From a0a4e5a84817f4fa8005f84fdb7a70deba2d998c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Jul 2026 17:49:24 +0200 Subject: [PATCH 01/33] chore(deps-dev): bump xdeployer from 3.1.6 to 3.1.25 (#3955) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- packages/core/package.json | 2 +- yarn.lock | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/core/package.json b/packages/core/package.json index 33cf5f3b98..98da0a3d05 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -91,7 +91,7 @@ "typechain": "^8.3.2", "typescript": "^5.8.3", "typescript-eslint": "^8.57.0", - "xdeployer": "3.1.6" + "xdeployer": "3.1.25" }, "peerDependencies": { "ethers": "~6.17.0" diff --git a/yarn.lock b/yarn.lock index 005b000181..54fd236315 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5380,7 +5380,7 @@ __metadata: typechain: "npm:^8.3.2" typescript: "npm:^5.8.3" typescript-eslint: "npm:^8.57.0" - xdeployer: "npm:3.1.6" + xdeployer: "npm:3.1.25" peerDependencies: ethers: ~6.17.0 languageName: unknown @@ -32768,14 +32768,14 @@ __metadata: languageName: node linkType: hard -"xdeployer@npm:3.1.6": - version: 3.1.6 - resolution: "xdeployer@npm:3.1.6" +"xdeployer@npm:3.1.25": + version: 3.1.25 + resolution: "xdeployer@npm:3.1.25" peerDependencies: - "@nomicfoundation/hardhat-ethers": ^3.0.8 - ethers: ^6.13.4 - hardhat: ^2.22.15 - checksum: 10c0/bc3609666600174db4a9e50bb09b2171bcbe63408180c3f9388d4edc6d183e5cf077fb2a7fc9c17e98df01a3ac8f25091e609dfbf600cf2fd17e5af0aa36d888 + "@nomicfoundation/hardhat-ethers": ^3.1.3 + ethers: ^6.17.0 + hardhat: ^2.28.6 + checksum: 10c0/7da6f7c7893fc8e4a0d2a16cb2c1e298f87a3295dac70662c8159330ef7c9a7d5d046448cc12e5bc65a535e7aaef55c0a21d4b7fb57bcfc287875483cfae74b4 languageName: node linkType: hard From 40b86e58cee257f8cb1503b075f4efc1ebe87f9c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Jul 2026 17:50:03 +0200 Subject: [PATCH 02/33] chore(deps): bump cache-manager from 7.2.8 to 7.2.9 (#3957) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- packages/apps/dashboard/server/package.json | 2 +- packages/apps/human-app/server/package.json | 2 +- yarn.lock | 49 ++++++++++++--------- 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/packages/apps/dashboard/server/package.json b/packages/apps/dashboard/server/package.json index d6f2b10fac..625172509e 100644 --- a/packages/apps/dashboard/server/package.json +++ b/packages/apps/dashboard/server/package.json @@ -35,7 +35,7 @@ "@nestjs/schedule": "^6.1.3", "@nestjs/swagger": "^11.2.5", "axios": "^1.3.1", - "cache-manager": "7.2.8", + "cache-manager": "7.2.9", "class-transformer": "^0.5.1", "class-validator": "0.14.1", "dayjs": "^1.11.20", diff --git a/packages/apps/human-app/server/package.json b/packages/apps/human-app/server/package.json index d2d2bcc737..9f167e01b2 100644 --- a/packages/apps/human-app/server/package.json +++ b/packages/apps/human-app/server/package.json @@ -40,7 +40,7 @@ "@nestjs/terminus": "^11.1.1", "@types/passport-jwt": "^4.0.1", "axios": "^1.7.2", - "cache-manager": "7.2.8", + "cache-manager": "7.2.9", "class-transformer": "^0.5.1", "class-validator": "0.14.1", "ethers": "^6.17.0", diff --git a/yarn.lock b/yarn.lock index 54fd236315..5b310388ef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -177,7 +177,7 @@ __metadata: "@types/jest": "npm:30.0.0" "@types/node": "npm:22.10.5" axios: "npm:^1.3.1" - cache-manager: "npm:7.2.8" + cache-manager: "npm:7.2.9" class-transformer: "npm:^0.5.1" class-validator: "npm:0.14.1" dayjs: "npm:^1.11.20" @@ -517,7 +517,7 @@ __metadata: "@types/passport": "npm:^1" "@types/passport-jwt": "npm:^4.0.1" axios: "npm:^1.7.2" - cache-manager: "npm:7.2.8" + cache-manager: "npm:7.2.9" class-transformer: "npm:^0.5.1" class-validator: "npm:0.14.1" eslint: "npm:^10.1.0" @@ -3182,13 +3182,13 @@ __metadata: languageName: node linkType: hard -"@cacheable/utils@npm:^2.3.3": - version: 2.3.3 - resolution: "@cacheable/utils@npm:2.3.3" +"@cacheable/utils@npm:^2.5.0": + version: 2.5.0 + resolution: "@cacheable/utils@npm:2.5.0" dependencies: - hashery: "npm:^1.3.0" - keyv: "npm:^5.5.5" - checksum: 10c0/aa6198dcbd799055465efcaa9c91b11266218bd674bc889665efe7a230ecbce17fda2502aed51bd65062f20ad3af464841a72a93e8609d579535736526e3988c + hashery: "npm:^1.5.1" + keyv: "npm:^5.6.0" + checksum: 10c0/99e901accd71eeb0bce91484d6c66d7ef2c731b541561eb5dc9ea7fed78bdc0b65e5dd2a80edde50191143bcfc5f238fc4742475b32e82d43b43eea224038e35 languageName: node linkType: hard @@ -16174,13 +16174,13 @@ __metadata: languageName: node linkType: hard -"cache-manager@npm:7.2.8": - version: 7.2.8 - resolution: "cache-manager@npm:7.2.8" +"cache-manager@npm:7.2.9": + version: 7.2.9 + resolution: "cache-manager@npm:7.2.9" dependencies: - "@cacheable/utils": "npm:^2.3.3" - keyv: "npm:^5.5.5" - checksum: 10c0/d620f8489cbdd549574c5b42ce27eb5a99841af059b1ed0ffcceaa897e7f5093aff68186e1af306d125685f4e565ae96da2c3e632bb23b45938bdd5a01d5b7f3 + "@cacheable/utils": "npm:^2.5.0" + keyv: "npm:^5.6.0" + checksum: 10c0/b4146edb102c7f49f9eb804c48ffb370405594e36f3e391093c35f5589b25fcd51cb33291589e453882745b60d669f7be21411c86864746d74ef9287ef238af8 languageName: node linkType: hard @@ -21427,12 +21427,12 @@ __metadata: languageName: node linkType: hard -"hashery@npm:^1.3.0": - version: 1.4.0 - resolution: "hashery@npm:1.4.0" +"hashery@npm:^1.5.1": + version: 1.5.1 + resolution: "hashery@npm:1.5.1" dependencies: - hookified: "npm:^1.14.0" - checksum: 10c0/34e0c72f7eac78676ee81f7b4f8263cbc591d2eb66229c3fd8812d006362a43436038b07e07580d6cfa512954d674a01a045e0d4c6968cc13c1d817d638bfcbf + hookified: "npm:^1.15.0" + checksum: 10c0/ab4225b655a7b0d05df99b1a59d5b3a51fe433f82422ca25e6f3f4c4ddd30adb49ebd38e0047ef9bded93319c1e9fc857e16aa382e554929c871cb77d39fc463 languageName: node linkType: hard @@ -21516,13 +21516,20 @@ __metadata: languageName: node linkType: hard -"hookified@npm:^1.13.0, hookified@npm:^1.14.0": +"hookified@npm:^1.13.0": version: 1.15.0 resolution: "hookified@npm:1.15.0" checksum: 10c0/bb8e2b34d6e6c1a00fd946ebbb3988fd826ac1c7ae103507d3402ab94defdb09d1fafb37cec6eae48e60ba56217ef89b803b885ccf4156c149e499d05a7741ec languageName: node linkType: hard +"hookified@npm:^1.15.0": + version: 1.15.1 + resolution: "hookified@npm:1.15.1" + checksum: 10c0/6b691374fa97ae57169fb29f90e723499fda5e85494654fbe55c4768b3ccbf3e14c0adc8d0f365f32c503b60d7c06f907781f5966c03d41c423575eb5e16860c + languageName: node + linkType: hard + "hosted-git-info@npm:^2.1.4": version: 2.8.9 resolution: "hosted-git-info@npm:2.8.9" @@ -23771,7 +23778,7 @@ __metadata: languageName: node linkType: hard -"keyv@npm:^5.5.5": +"keyv@npm:^5.5.5, keyv@npm:^5.6.0": version: 5.6.0 resolution: "keyv@npm:5.6.0" dependencies: From 103188611327fa0a0fa7985a2a30ffe39e4d4fa1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Jul 2026 10:16:40 +0200 Subject: [PATCH 03/33] chore(deps): bump lodash and @types/lodash (#3958) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- packages/apps/dashboard/server/package.json | 2 +- packages/apps/human-app/frontend/package.json | 4 +-- packages/apps/human-app/server/package.json | 4 +-- .../reputation-oracle/server/package.json | 4 +-- yarn.lock | 30 ++++++++++++++----- 5 files changed, 29 insertions(+), 15 deletions(-) diff --git a/packages/apps/dashboard/server/package.json b/packages/apps/dashboard/server/package.json index 625172509e..ee87594ed1 100644 --- a/packages/apps/dashboard/server/package.json +++ b/packages/apps/dashboard/server/package.json @@ -42,7 +42,7 @@ "ethers": "~6.17.0", "joi": "^17.13.3", "keyv": "^5.5.5", - "lodash": "^4.17.21", + "lodash": "^4.18.1", "minio": "8.0.7", "reflect-metadata": "^0.2.2", "rxjs": "^7.2.0" diff --git a/packages/apps/human-app/frontend/package.json b/packages/apps/human-app/frontend/package.json index 79b2befa5c..a9fb3a8fd3 100644 --- a/packages/apps/human-app/frontend/package.json +++ b/packages/apps/human-app/frontend/package.json @@ -38,7 +38,7 @@ "ethers": "^6.17.0", "i18next": "^25.8.0", "jwt-decode": "^4.0.0", - "lodash": "^4.17.21", + "lodash": "^4.18.1", "material-react-table": "3.0.1", "mui-image": "^1.0.7", "notistack": "^3.0.1", @@ -62,7 +62,7 @@ "@eslint/js": "^10.0.1", "@tanstack/eslint-plugin-query": "^5.60.1", "@tanstack/react-query-devtools": "^5.59.16", - "@types/lodash": "^4.17.12", + "@types/lodash": "^4.17.24", "@types/mui-image": "^1.0.5", "@types/node": "^22.10.5", "@types/prop-types": "^15", diff --git a/packages/apps/human-app/server/package.json b/packages/apps/human-app/server/package.json index 9f167e01b2..f24ab46afb 100644 --- a/packages/apps/human-app/server/package.json +++ b/packages/apps/human-app/server/package.json @@ -48,7 +48,7 @@ "jsonwebtoken": "^9.0.3", "jwt-decode": "^4.0.0", "keyv": "^5.5.5", - "lodash": "^4.17.21", + "lodash": "^4.18.1", "passport": "^0.7.0", "passport-jwt": "^4.0.1", "reflect-metadata": "^0.2.2", @@ -62,7 +62,7 @@ "@types/express": "^5.0.6", "@types/jest": "30.0.0", "@types/jsonwebtoken": "^9.0.7", - "@types/lodash": "^4.17.14", + "@types/lodash": "^4.17.24", "@types/node": "22.10.5", "@types/passport": "^1", "eslint": "^10.1.0", diff --git a/packages/apps/reputation-oracle/server/package.json b/packages/apps/reputation-oracle/server/package.json index d2a311c636..1f9b9c82d1 100644 --- a/packages/apps/reputation-oracle/server/package.json +++ b/packages/apps/reputation-oracle/server/package.json @@ -59,7 +59,7 @@ "helmet": "^8.1.0", "joi": "^17.13.3", "json-stable-stringify": "^1.2.1", - "lodash": "^4.17.21", + "lodash": "^4.18.1", "minio": "8.0.7", "passport": "^0.7.0", "passport-jwt": "^4.0.1", @@ -81,7 +81,7 @@ "@types/bcrypt": "^6.0.0", "@types/express": "^5.0.6", "@types/jest": "30.0.0", - "@types/lodash": "^4.17.14", + "@types/lodash": "^4.17.24", "@types/node": "22.10.5", "@types/zxcvbn": "4.4.5", "eslint": "^10.1.0", diff --git a/yarn.lock b/yarn.lock index 5b310388ef..764fbd5f54 100644 --- a/yarn.lock +++ b/yarn.lock @@ -190,7 +190,7 @@ __metadata: jest: "npm:^29.7.0" joi: "npm:^17.13.3" keyv: "npm:^5.5.5" - lodash: "npm:^4.17.21" + lodash: "npm:^4.18.1" minio: "npm:8.0.7" prettier: "npm:^3.8.1" reflect-metadata: "npm:^0.2.2" @@ -435,7 +435,7 @@ __metadata: "@tanstack/eslint-plugin-query": "npm:^5.60.1" "@tanstack/react-query": "npm:^5.91.3" "@tanstack/react-query-devtools": "npm:^5.59.16" - "@types/lodash": "npm:^4.17.12" + "@types/lodash": "npm:^4.17.24" "@types/mui-image": "npm:^1.0.5" "@types/node": "npm:^22.10.5" "@types/prop-types": "npm:^15" @@ -457,7 +457,7 @@ __metadata: i18next: "npm:^25.8.0" jsdom: "npm:^29.1.1" jwt-decode: "npm:^4.0.0" - lodash: "npm:^4.17.21" + lodash: "npm:^4.18.1" material-react-table: "npm:3.0.1" mui-image: "npm:^1.0.7" notistack: "npm:^3.0.1" @@ -512,7 +512,7 @@ __metadata: "@types/express": "npm:^5.0.6" "@types/jest": "npm:30.0.0" "@types/jsonwebtoken": "npm:^9.0.7" - "@types/lodash": "npm:^4.17.14" + "@types/lodash": "npm:^4.17.24" "@types/node": "npm:22.10.5" "@types/passport": "npm:^1" "@types/passport-jwt": "npm:^4.0.1" @@ -531,7 +531,7 @@ __metadata: jsonwebtoken: "npm:^9.0.3" jwt-decode: "npm:^4.0.0" keyv: "npm:^5.5.5" - lodash: "npm:^4.17.21" + lodash: "npm:^4.18.1" nock: "npm:^14.0.11" passport: "npm:^0.7.0" passport-jwt: "npm:^4.0.1" @@ -715,7 +715,7 @@ __metadata: "@types/bcrypt": "npm:^6.0.0" "@types/express": "npm:^5.0.6" "@types/jest": "npm:30.0.0" - "@types/lodash": "npm:^4.17.14" + "@types/lodash": "npm:^4.17.24" "@types/node": "npm:22.10.5" "@types/passport-jwt": "npm:^4.0.1" "@types/zxcvbn": "npm:4.4.5" @@ -736,7 +736,7 @@ __metadata: jest: "npm:^29.7.0" joi: "npm:^17.13.3" json-stable-stringify: "npm:^1.2.1" - lodash: "npm:^4.17.21" + lodash: "npm:^4.18.1" minio: "npm:8.0.7" nock: "npm:^14.0.11" passport: "npm:^0.7.0" @@ -12325,13 +12325,20 @@ __metadata: languageName: node linkType: hard -"@types/lodash@npm:^4.17.12, @types/lodash@npm:^4.17.14, @types/lodash@npm:^4.17.20": +"@types/lodash@npm:^4.17.20": version: 4.17.20 resolution: "@types/lodash@npm:4.17.20" checksum: 10c0/98cdd0faae22cbb8079a01a3bb65aa8f8c41143367486c1cbf5adc83f16c9272a2a5d2c1f541f61d0d73da543c16ee1d21cf2ef86cb93cd0cc0ac3bced6dd88f languageName: node linkType: hard +"@types/lodash@npm:^4.17.24": + version: 4.17.24 + resolution: "@types/lodash@npm:4.17.24" + checksum: 10c0/b72f60d4daacdad1fa643edb3faba204c02a01eb1ac00a83ff73496a6d236fc55e459c06106e8ced42277dba932d087d8fc090f8de4ef590d3f91e6d6f7ce85a + languageName: node + linkType: hard + "@types/long@npm:^4.0.0": version: 4.0.2 resolution: "@types/long@npm:4.0.2" @@ -24230,6 +24237,13 @@ __metadata: languageName: node linkType: hard +"lodash@npm:^4.18.1": + version: 4.18.1 + resolution: "lodash@npm:4.18.1" + checksum: 10c0/757228fc68805c59789e82185135cf85f05d0b2d3d54631d680ca79ec21944ec8314d4533639a14b8bcfbd97a517e78960933041a5af17ecb693ec6eecb99a27 + languageName: node + linkType: hard + "log-symbols@npm:^3.0.0": version: 3.0.0 resolution: "log-symbols@npm:3.0.0" From f194556a1948a8d4cc89773a06ce4deda4587d43 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Jul 2026 12:07:39 +0200 Subject: [PATCH 04/33] chore(deps): bump @nestjs/common from 11.1.12 to 11.1.27 (#3956) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: portuu3 <> --- packages/apps/dashboard/server/package.json | 2 +- .../src/common/config/cache-factory.config.ts | 2 +- .../exchange-oracle/server/package.json | 2 +- .../fortune/recording-oracle/package.json | 2 +- packages/apps/human-app/server/package.json | 2 +- .../apps/job-launcher/server/package.json | 2 +- .../reputation-oracle/server/package.json | 2 +- yarn.lock | 30 +++++++++---------- 8 files changed, 22 insertions(+), 22 deletions(-) diff --git a/packages/apps/dashboard/server/package.json b/packages/apps/dashboard/server/package.json index ee87594ed1..d18d0ed3a1 100644 --- a/packages/apps/dashboard/server/package.json +++ b/packages/apps/dashboard/server/package.json @@ -27,7 +27,7 @@ "@keyv/redis": "^5.1.5", "@nestjs/axios": "^4.0.1", "@nestjs/cache-manager": "^3.1.0", - "@nestjs/common": "^11.1.12", + "@nestjs/common": "^11.1.27", "@nestjs/config": "^4.0.2", "@nestjs/core": "^11.1.12", "@nestjs/mapped-types": "^2.1.1", diff --git a/packages/apps/dashboard/server/src/common/config/cache-factory.config.ts b/packages/apps/dashboard/server/src/common/config/cache-factory.config.ts index f7c6350826..049a763aed 100644 --- a/packages/apps/dashboard/server/src/common/config/cache-factory.config.ts +++ b/packages/apps/dashboard/server/src/common/config/cache-factory.config.ts @@ -1,4 +1,4 @@ -import { CacheModuleAsyncOptions } from '@nestjs/common/cache'; +import { CacheModuleAsyncOptions } from '@nestjs/cache-manager'; import { ConfigModule } from '@nestjs/config'; import * as _ from 'lodash'; diff --git a/packages/apps/fortune/exchange-oracle/server/package.json b/packages/apps/fortune/exchange-oracle/server/package.json index cc725d61fa..3ee2d456da 100644 --- a/packages/apps/fortune/exchange-oracle/server/package.json +++ b/packages/apps/fortune/exchange-oracle/server/package.json @@ -33,7 +33,7 @@ "@human-protocol/logger": "workspace:*", "@human-protocol/sdk": "workspace:*", "@nestjs/axios": "^4.0.1", - "@nestjs/common": "^11.1.12", + "@nestjs/common": "^11.1.27", "@nestjs/config": "^4.0.2", "@nestjs/core": "^11.1.12", "@nestjs/passport": "^11.0.5", diff --git a/packages/apps/fortune/recording-oracle/package.json b/packages/apps/fortune/recording-oracle/package.json index aa930343df..8e4aa52d58 100644 --- a/packages/apps/fortune/recording-oracle/package.json +++ b/packages/apps/fortune/recording-oracle/package.json @@ -26,7 +26,7 @@ "@human-protocol/logger": "workspace:*", "@human-protocol/sdk": "workspace:*", "@nestjs/axios": "^4.0.1", - "@nestjs/common": "^11.1.12", + "@nestjs/common": "^11.1.27", "@nestjs/config": "^4.0.2", "@nestjs/core": "^11.1.12", "@nestjs/platform-express": "^11.1.12", diff --git a/packages/apps/human-app/server/package.json b/packages/apps/human-app/server/package.json index f24ab46afb..91752e1a3e 100644 --- a/packages/apps/human-app/server/package.json +++ b/packages/apps/human-app/server/package.json @@ -30,7 +30,7 @@ "@keyv/redis": "^5.1.5", "@nestjs/axios": "^4.0.1", "@nestjs/cache-manager": "^3.1.0", - "@nestjs/common": "^11.1.12", + "@nestjs/common": "^11.1.27", "@nestjs/config": "^4.0.2", "@nestjs/core": "^11.1.12", "@nestjs/passport": "^11.0.5", diff --git a/packages/apps/job-launcher/server/package.json b/packages/apps/job-launcher/server/package.json index 60c15209a6..44b7e9b8c8 100644 --- a/packages/apps/job-launcher/server/package.json +++ b/packages/apps/job-launcher/server/package.json @@ -35,7 +35,7 @@ "@human-protocol/logger": "workspace:*", "@human-protocol/sdk": "workspace:*", "@nestjs/axios": "^4.0.1", - "@nestjs/common": "^11.1.12", + "@nestjs/common": "^11.1.27", "@nestjs/config": "^4.0.2", "@nestjs/core": "^11.1.12", "@nestjs/jwt": "^11.0.2", diff --git a/packages/apps/reputation-oracle/server/package.json b/packages/apps/reputation-oracle/server/package.json index 1f9b9c82d1..6a4eef6904 100644 --- a/packages/apps/reputation-oracle/server/package.json +++ b/packages/apps/reputation-oracle/server/package.json @@ -34,7 +34,7 @@ "@human-protocol/logger": "workspace:*", "@human-protocol/sdk": "workspace:*", "@nestjs/axios": "^4.0.1", - "@nestjs/common": "^11.1.12", + "@nestjs/common": "^11.1.27", "@nestjs/config": "^4.0.2", "@nestjs/core": "^11.1.12", "@nestjs/jwt": "^11.0.2", diff --git a/yarn.lock b/yarn.lock index 764fbd5f54..1c92a2ea4f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -164,7 +164,7 @@ __metadata: "@nestjs/axios": "npm:^4.0.1" "@nestjs/cache-manager": "npm:^3.1.0" "@nestjs/cli": "npm:^11.0.16" - "@nestjs/common": "npm:^11.1.12" + "@nestjs/common": "npm:^11.1.27" "@nestjs/config": "npm:^4.0.2" "@nestjs/core": "npm:^11.1.12" "@nestjs/mapped-types": "npm:^2.1.1" @@ -318,7 +318,7 @@ __metadata: "@human-protocol/sdk": "workspace:*" "@nestjs/axios": "npm:^4.0.1" "@nestjs/cli": "npm:^11.0.16" - "@nestjs/common": "npm:^11.1.12" + "@nestjs/common": "npm:^11.1.27" "@nestjs/config": "npm:^4.0.2" "@nestjs/core": "npm:^11.1.12" "@nestjs/passport": "npm:^11.0.5" @@ -378,7 +378,7 @@ __metadata: "@human-protocol/sdk": "workspace:*" "@nestjs/axios": "npm:^4.0.1" "@nestjs/cli": "npm:^11.0.16" - "@nestjs/common": "npm:^11.1.12" + "@nestjs/common": "npm:^11.1.27" "@nestjs/config": "npm:^4.0.2" "@nestjs/core": "npm:^11.1.12" "@nestjs/platform-express": "npm:^11.1.12" @@ -499,7 +499,7 @@ __metadata: "@nestjs/axios": "npm:^4.0.1" "@nestjs/cache-manager": "npm:^3.1.0" "@nestjs/cli": "npm:^11.0.16" - "@nestjs/common": "npm:^11.1.12" + "@nestjs/common": "npm:^11.1.27" "@nestjs/config": "npm:^4.0.2" "@nestjs/core": "npm:^11.1.12" "@nestjs/passport": "npm:^11.0.5" @@ -622,7 +622,7 @@ __metadata: "@human-protocol/sdk": "workspace:*" "@nestjs/axios": "npm:^4.0.1" "@nestjs/cli": "npm:^11.0.16" - "@nestjs/common": "npm:^11.1.12" + "@nestjs/common": "npm:^11.1.27" "@nestjs/config": "npm:^4.0.2" "@nestjs/core": "npm:^11.1.12" "@nestjs/jwt": "npm:^11.0.2" @@ -696,7 +696,7 @@ __metadata: "@human-protocol/sdk": "workspace:*" "@nestjs/axios": "npm:^4.0.1" "@nestjs/cli": "npm:^11.0.16" - "@nestjs/common": "npm:^11.1.12" + "@nestjs/common": "npm:^11.1.27" "@nestjs/config": "npm:^4.0.2" "@nestjs/core": "npm:^11.1.12" "@nestjs/jwt": "npm:^11.0.2" @@ -7828,11 +7828,11 @@ __metadata: languageName: node linkType: hard -"@nestjs/common@npm:^11.1.12": - version: 11.1.12 - resolution: "@nestjs/common@npm:11.1.12" +"@nestjs/common@npm:^11.1.27": + version: 11.1.27 + resolution: "@nestjs/common@npm:11.1.27" dependencies: - file-type: "npm:21.3.0" + file-type: "npm:21.3.4" iterare: "npm:1.2.1" load-esm: "npm:1.0.3" tslib: "npm:2.8.1" @@ -7847,7 +7847,7 @@ __metadata: optional: true class-validator: optional: true - checksum: 10c0/2ab28286ba7a3cdef74c11f9578f859e24d96828de5c271374cba2abc92c64b923bdcb46aa119d617bcac0557159c85ddf70aa30d773363ef4f57456c7cef100 + checksum: 10c0/c8c9c4ae913f302d76007ad9488c2dbf895df48373f3d9a475e7444232bd2b0d2d499557548fec48b3c38c399422456a475f8e23f79b14f3e7e46f8866d97ec0 languageName: node linkType: hard @@ -20132,15 +20132,15 @@ __metadata: languageName: node linkType: hard -"file-type@npm:21.3.0": - version: 21.3.0 - resolution: "file-type@npm:21.3.0" +"file-type@npm:21.3.4": + version: 21.3.4 + resolution: "file-type@npm:21.3.4" dependencies: "@tokenizer/inflate": "npm:^0.4.1" strtok3: "npm:^10.3.4" token-types: "npm:^6.1.1" uint8array-extras: "npm:^1.4.0" - checksum: 10c0/1b1fa909e6063044a6da1d2ea348ee4d747ed9286382d3f0d4d6532c11fb2ea9f2e7e67b2bc7d745d1bc937e05dee1aa8cb912c64250933bcb393a3744f4e284 + checksum: 10c0/6f15e7538c5d73f9308d2e897365d253a6647a6751bb1b0d85c78aebc02b8976afb7c6c9b3759687a064b1b3d60246e5504746b8f11e38b0d5a1b339087e00d2 languageName: node linkType: hard From 8b14c3f14920b04aa0c8ddccede0d5e57d52a657 Mon Sep 17 00:00:00 2001 From: KirillKirill Date: Tue, 14 Jul 2026 14:03:52 +0300 Subject: [PATCH 05/33] [Human App] Remove Staking Info leftovers (#3969) --- packages/apps/human-app/frontend/src/main.tsx | 44 ++- .../src/modules/auth/context/auth-context.tsx | 1 - .../worker/hooks/use-exchange-api-keys.ts | 58 ---- .../src/modules/worker/hooks/use-staking.ts | 11 - .../hooks/use-available-jobs-filter-modal.tsx | 6 +- .../src/modules/worker/jobs/jobs.page.tsx | 16 +- .../hooks/use-my-jobs-filter-modal.tsx | 6 +- .../profile/components/add-api-key-modal.tsx | 252 ---------------- .../profile/components/api-key-data.tsx | 105 ------- .../components/delete-api-key-modal.tsx | 118 -------- .../profile/components/edit-api-key-modal.tsx | 280 ------------------ .../worker/profile/components/index.ts | 6 - .../profile/components/staking-info.tsx | 225 -------------- .../profile/hooks/use-api-key-modals.tsx | 52 ---- .../worker/profile/views/profile.page.tsx | 11 - .../worker/providers/require-stake.tsx | 30 -- .../services/exchangeApiKeys.service.ts | 46 --- .../worker/services/staking.service.ts | 16 - .../drawer-menu-items-worker.tsx | 11 +- .../human-app/frontend/src/router/router.tsx | 37 +-- .../frontend/src/shared/i18n/en.json | 42 --- .../shared/providers/ui-config-provider.tsx | 44 --- .../src/shared/services/ui-config.service.ts | 2 - .../apps/human-app/server/src/app.module.ts | 8 - .../common/config/gateway-config.service.ts | 30 -- .../server/src/common/enums/http-method.ts | 1 - .../enums/reputation-oracle-endpoints.ts | 6 - .../src/common/guards/strategy/jwt.http.ts | 2 - .../src/common/utils/jwt-token.model.ts | 2 - .../reputation-oracle.gateway.ts | 81 ----- .../reputation-oracle.mapper.profile.ts | 13 - packages/apps/human-app/server/src/main.ts | 2 +- .../exchange-api-keys.controller.ts | 83 ------ .../exchange-api-keys.mapper.profile.ts | 20 -- .../exchange-api-keys.module.ts | 13 - .../exchange-api-keys.service.ts | 28 -- .../model/exchange-api-keys.model.ts | 44 --- .../spec/exchange-api-keys.controller.spec.ts | 96 ------ .../spec/exchange-api-keys.fixtures.ts | 45 --- .../spec/exchange-api-keys.service.mock.ts | 14 - .../spec/exchange-api-keys.service.spec.ts | 89 ------ .../job-assignment.controller.ts | 24 -- .../spec/job-assignment.controller.spec.ts | 55 ---- .../jobs-discovery.controller.ts | 11 - .../spec/jobs-discovery.controller.spec.ts | 18 +- .../modules/staking/model/staking.model.ts | 20 -- .../staking/spec/staking.controller.spec.ts | 50 ---- .../modules/staking/spec/staking.fixtures.ts | 11 - .../staking/spec/staking.service.mock.ts | 9 - .../staking/spec/staking.service.spec.ts | 55 ---- .../src/modules/staking/staking.controller.ts | 25 -- .../src/modules/staking/staking.module.ts | 12 - .../src/modules/staking/staking.service.ts | 19 -- .../ui-configuration.controller.spec.ts | 20 +- .../ui-configuration.controller.ts | 8 +- .../ui-configuration/ui-configuration.dto.ts | 11 - .../ui-configuration.module.ts | 2 - .../server/src/app.module.ts | 4 - .../server/src/common/constants/index.ts | 17 -- .../server/src/config/config.module.ts | 3 - .../server/src/config/env-schema.ts | 15 - .../server/src/config/index.ts | 1 - .../src/config/staking-config.service.ts | 43 --- .../server/src/database/database.module.ts | 2 - .../1783955400433-dropExchangeApiKeys.ts | 19 ++ .../server/src/modules/auth/auth.module.ts | 8 +- .../src/modules/auth/auth.service.spec.ts | 139 --------- .../server/src/modules/auth/auth.service.ts | 45 --- .../exchange-api-key.entity.ts | 24 -- .../exchange-api-keys.controller.ts | 136 --------- .../exchange-api-keys.dto.ts | 48 --- .../exchange-api-keys.error-filter.ts | 54 ---- .../exchange-api-keys.errors.ts | 19 -- .../exchange-api-keys.module.ts | 17 -- .../exchange-api-keys.repository.ts | 30 -- .../exchange-api-keys.service.spec.ts | 217 -------------- .../exchange-api-keys.service.ts | 101 ------- .../exchange-api-keys/fixtures/index.ts | 25 -- .../src/modules/exchange-api-keys/index.ts | 8 - .../server/src/modules/exchange/errors.ts | 15 - .../exchange/exchange-client.factory.ts | 31 -- .../src/modules/exchange/exchange.module.ts | 9 - .../src/modules/exchange/fixtures/exchange.ts | 32 -- .../src/modules/exchange/fixtures/index.ts | 1 - .../exchange/gate-exchange.client.spec.ts | 224 -------------- .../modules/exchange/gate-exchange.client.ts | 148 --------- .../server/src/modules/exchange/index.ts | 3 - .../exchange/mexc-exchange.client.spec.ts | 196 ------------ .../modules/exchange/mexc-exchange.client.ts | 101 ------- .../server/src/modules/exchange/types.ts | 16 - .../server/src/modules/exchange/utils.ts | 27 -- .../server/src/modules/staking/index.ts | 3 - .../src/modules/staking/staking.controller.ts | 39 --- .../server/src/modules/staking/staking.dto.ts | 23 -- .../modules/staking/staking.error-filter.ts | 34 --- .../src/modules/staking/staking.module.ts | 17 -- .../modules/staking/staking.service.spec.ts | 205 ------------- .../src/modules/staking/staking.service.ts | 110 ------- .../server/src/modules/staking/types.ts | 11 - .../server/src/utils/stake.ts | 6 - 100 files changed, 78 insertions(+), 4494 deletions(-) delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/hooks/use-exchange-api-keys.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/hooks/use-staking.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/profile/components/add-api-key-modal.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/profile/components/api-key-data.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/profile/components/delete-api-key-modal.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/profile/components/edit-api-key-modal.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/profile/components/staking-info.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/profile/hooks/use-api-key-modals.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/providers/require-stake.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/services/exchangeApiKeys.service.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/services/staking.service.ts delete mode 100644 packages/apps/human-app/frontend/src/shared/providers/ui-config-provider.tsx delete mode 100644 packages/apps/human-app/server/src/modules/exchange-api-keys/exchange-api-keys.controller.ts delete mode 100644 packages/apps/human-app/server/src/modules/exchange-api-keys/exchange-api-keys.mapper.profile.ts delete mode 100644 packages/apps/human-app/server/src/modules/exchange-api-keys/exchange-api-keys.module.ts delete mode 100644 packages/apps/human-app/server/src/modules/exchange-api-keys/exchange-api-keys.service.ts delete mode 100644 packages/apps/human-app/server/src/modules/exchange-api-keys/model/exchange-api-keys.model.ts delete mode 100644 packages/apps/human-app/server/src/modules/exchange-api-keys/spec/exchange-api-keys.controller.spec.ts delete mode 100644 packages/apps/human-app/server/src/modules/exchange-api-keys/spec/exchange-api-keys.fixtures.ts delete mode 100644 packages/apps/human-app/server/src/modules/exchange-api-keys/spec/exchange-api-keys.service.mock.ts delete mode 100644 packages/apps/human-app/server/src/modules/exchange-api-keys/spec/exchange-api-keys.service.spec.ts delete mode 100644 packages/apps/human-app/server/src/modules/staking/model/staking.model.ts delete mode 100644 packages/apps/human-app/server/src/modules/staking/spec/staking.controller.spec.ts delete mode 100644 packages/apps/human-app/server/src/modules/staking/spec/staking.fixtures.ts delete mode 100644 packages/apps/human-app/server/src/modules/staking/spec/staking.service.mock.ts delete mode 100644 packages/apps/human-app/server/src/modules/staking/spec/staking.service.spec.ts delete mode 100644 packages/apps/human-app/server/src/modules/staking/staking.controller.ts delete mode 100644 packages/apps/human-app/server/src/modules/staking/staking.module.ts delete mode 100644 packages/apps/human-app/server/src/modules/staking/staking.service.ts delete mode 100644 packages/apps/reputation-oracle/server/src/config/staking-config.service.ts create mode 100644 packages/apps/reputation-oracle/server/src/database/migrations/1783955400433-dropExchangeApiKeys.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-key.entity.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.controller.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.dto.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.error-filter.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.errors.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.module.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.repository.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.service.spec.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.service.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/fixtures/index.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/index.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/exchange/errors.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/exchange/exchange-client.factory.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/exchange/exchange.module.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/exchange/fixtures/exchange.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/exchange/fixtures/index.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/exchange/gate-exchange.client.spec.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/exchange/gate-exchange.client.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/exchange/index.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/exchange/mexc-exchange.client.spec.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/exchange/mexc-exchange.client.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/exchange/types.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/exchange/utils.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/staking/index.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/staking/staking.controller.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/staking/staking.dto.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/staking/staking.error-filter.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/staking/staking.module.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/staking/staking.service.spec.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/staking/staking.service.ts delete mode 100644 packages/apps/reputation-oracle/server/src/modules/staking/types.ts delete mode 100644 packages/apps/reputation-oracle/server/src/utils/stake.ts diff --git a/packages/apps/human-app/frontend/src/main.tsx b/packages/apps/human-app/frontend/src/main.tsx index bf9aaa190f..ccf792a2b6 100644 --- a/packages/apps/human-app/frontend/src/main.tsx +++ b/packages/apps/human-app/frontend/src/main.tsx @@ -23,7 +23,6 @@ import { HomePageStateProvider } from '@/shared/contexts/homepage-state'; import { NotificationProvider } from '@/shared/providers/notifications-provider'; import { ModalProvider } from './shared/contexts/modal-context'; import { GlobalModal } from './shared/components/ui/modal/global-modal'; -import { UiConfigProvider } from './shared/providers/ui-config-provider'; const root = document.getElementById('root'); if (!root) throw Error('root element is undefined'); @@ -40,30 +39,25 @@ createRoot(root).render( - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/packages/apps/human-app/frontend/src/modules/auth/context/auth-context.tsx b/packages/apps/human-app/frontend/src/modules/auth/context/auth-context.tsx index 13b9001fed..2b2478b5f4 100644 --- a/packages/apps/human-app/frontend/src/modules/auth/context/auth-context.tsx +++ b/packages/apps/human-app/frontend/src/modules/auth/context/auth-context.tsx @@ -11,7 +11,6 @@ const userDataSchema = z.object({ user_id: z.number(), reputation_network: z.string(), exp: z.number(), - is_stake_eligible: z.boolean(), }); export type UserData = z.infer; diff --git a/packages/apps/human-app/frontend/src/modules/worker/hooks/use-exchange-api-keys.ts b/packages/apps/human-app/frontend/src/modules/worker/hooks/use-exchange-api-keys.ts deleted file mode 100644 index c958791ca7..0000000000 --- a/packages/apps/human-app/frontend/src/modules/worker/hooks/use-exchange-api-keys.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; -import { - deleteExchangeApiKeys, - enrollExchangeApiKeys, - getExchangeApiKeys, - getSupportedExchanges, -} from '../services/exchangeApiKeys.service'; - -function useGetSupportedExchanges() { - return useQuery({ - queryKey: ['supported-exchanges'], - queryFn: () => getSupportedExchanges(), - }); -} - -function useGetExchangeApiKeys() { - return useQuery({ - queryKey: ['exchange-api-keys'], - queryFn: () => getExchangeApiKeys(), - }); -} - -function useEnrollExchangeApiKeys() { - const queryClient = useQueryClient(); - - return useMutation({ - mutationKey: ['enroll-exchange-api-keys'], - mutationFn: (data: { - exchange: string; - apiKey: string; - secretKey: string; - }) => enrollExchangeApiKeys(data), - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['exchange-api-keys'] }); - queryClient.invalidateQueries({ queryKey: ['staking-summary'] }); - }, - }); -} - -function useDeleteExchangeApiKeys() { - const queryClient = useQueryClient(); - - return useMutation({ - mutationKey: ['delete-exchange-api-keys'], - mutationFn: () => deleteExchangeApiKeys(), - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['exchange-api-keys'] }); - queryClient.invalidateQueries({ queryKey: ['staking-summary'] }); - }, - }); -} - -export { - useGetSupportedExchanges, - useDeleteExchangeApiKeys, - useGetExchangeApiKeys, - useEnrollExchangeApiKeys, -}; diff --git a/packages/apps/human-app/frontend/src/modules/worker/hooks/use-staking.ts b/packages/apps/human-app/frontend/src/modules/worker/hooks/use-staking.ts deleted file mode 100644 index 1556c072d6..0000000000 --- a/packages/apps/human-app/frontend/src/modules/worker/hooks/use-staking.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; -import { getStakingSummary } from '../services/staking.service'; - -function useGetStakingSummary() { - return useQuery({ - queryKey: ['staking-summary'], - queryFn: () => getStakingSummary(), - }); -} - -export { useGetStakingSummary }; diff --git a/packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/hooks/use-available-jobs-filter-modal.tsx b/packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/hooks/use-available-jobs-filter-modal.tsx index 6ce55c5c48..f90e919961 100644 --- a/packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/hooks/use-available-jobs-filter-modal.tsx +++ b/packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/hooks/use-available-jobs-filter-modal.tsx @@ -1,17 +1,17 @@ import { useModal } from '@/shared/contexts/modal-context'; -import { useUiConfig } from '@/shared/providers/ui-config-provider'; +import { useGetUiConfig } from '@/shared/hooks'; import { AvailableJobsFilterModal } from '../available-jobs-filter-modal'; export function useAvailableJobsFilterModal() { const { openModal, closeModal } = useModal(); - const { uiConfig } = useUiConfig(); + const { data: uiConfigData } = useGetUiConfig(); return { openModal: () => { openModal({ content: ( ), diff --git a/packages/apps/human-app/frontend/src/modules/worker/jobs/jobs.page.tsx b/packages/apps/human-app/frontend/src/modules/worker/jobs/jobs.page.tsx index 21364ccedf..5e65b627ae 100644 --- a/packages/apps/human-app/frontend/src/modules/worker/jobs/jobs.page.tsx +++ b/packages/apps/human-app/frontend/src/modules/worker/jobs/jobs.page.tsx @@ -7,7 +7,7 @@ import { useIsMobile } from '@/shared/hooks/use-is-mobile'; import { useColorMode } from '@/shared/contexts/color-mode'; import { NoRecords } from '@/shared/components/ui/no-records'; import { PageCardLoader } from '@/shared/components/ui/page-card'; -import { useUiConfig } from '@/shared/providers/ui-config-provider'; +import { useGetUiConfig } from '@/shared/hooks'; import { useGetOracles } from '../hooks'; import { useGetOraclesNotifications } from '../hooks/use-get-oracles-notifications'; import { TabPanel } from './components'; @@ -30,15 +30,19 @@ export function JobsPage() { error, } = useGetOracles(); - const { uiConfig, isUiConfigLoading, isUiConfigError } = useUiConfig(); + const { + data: uiConfigData, + isPending: isPendingUiConfig, + isError: isErrorUiConfig, + } = useGetUiConfig(); const { address: oracle_address } = useParams<{ address: string }>(); const { t } = useTranslation(); const [activeTab, setActiveTab] = useState(0); const isMobile = useIsMobile(); - const isError = isErrorGetOracles || isUiConfigError; - const isPending = isPendingGetOracles || isUiConfigLoading; + const isError = isErrorGetOracles || isErrorUiConfig; + const isPending = isPendingGetOracles || isPendingUiConfig; const { onError } = useGetOraclesNotifications(); const handleTabChange = (_event: React.SyntheticEvent, newValue: number) => { @@ -115,7 +119,7 @@ export function JobsPage() { ) : ( )} @@ -124,7 +128,7 @@ export function JobsPage() { ) : ( )} diff --git a/packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/hooks/use-my-jobs-filter-modal.tsx b/packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/hooks/use-my-jobs-filter-modal.tsx index a41ca0c491..40a0c9c1be 100644 --- a/packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/hooks/use-my-jobs-filter-modal.tsx +++ b/packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/hooks/use-my-jobs-filter-modal.tsx @@ -1,17 +1,17 @@ import { useModal } from '@/shared/contexts/modal-context'; +import { useGetUiConfig } from '@/shared/hooks'; import { MyJobsFilterModal } from '../components/mobile/my-jobs-filter-modal'; -import { useUiConfig } from '@/shared/providers/ui-config-provider'; export function useMyJobFilterModal() { const { openModal, closeModal } = useModal(); - const { uiConfig } = useUiConfig(); + const { data: uiConfigData } = useGetUiConfig(); return { openModal: () => { openModal({ content: ( ), diff --git a/packages/apps/human-app/frontend/src/modules/worker/profile/components/add-api-key-modal.tsx b/packages/apps/human-app/frontend/src/modules/worker/profile/components/add-api-key-modal.tsx deleted file mode 100644 index f3b1ee6954..0000000000 --- a/packages/apps/human-app/frontend/src/modules/worker/profile/components/add-api-key-modal.tsx +++ /dev/null @@ -1,252 +0,0 @@ -import { zodResolver } from '@hookform/resolvers/zod'; -import { - Autocomplete, - Box, - FormControl, - FormHelperText, - Stack, - TextField, - Typography, -} from '@mui/material'; -import { Controller, useForm } from 'react-hook-form'; -import { useTranslation } from 'react-i18next'; -import { z } from 'zod'; -import { Button } from '@/shared/components/ui/button'; -import { useIsMobile } from '@/shared/hooks'; -import { - useEnrollExchangeApiKeys, - useGetSupportedExchanges, -} from '../../hooks/use-exchange-api-keys'; -import { ModalError, ModalLoading, ModalSuccess } from './modal-states'; -import { useEffect } from 'react'; - -interface AddApiKeyModalProps { - onClose: () => void; - disableClose: (disable: boolean) => void; -} - -export function AddApiKeyModal({ onClose, disableClose }: AddApiKeyModalProps) { - const { t } = useTranslation(); - const { - mutate: enrollExchangeApiKey, - reset: resetMutation, - error, - isSuccess, - isPending, - isError, - isIdle, - } = useEnrollExchangeApiKeys(); - const isMobile = useIsMobile(); - const { data: supportedExchanges } = useGetSupportedExchanges(); - - useEffect(() => { - disableClose(isPending); - }, [isPending, disableClose]); - - const { - control, - handleSubmit, - formState: { errors }, - reset, - } = useForm({ - defaultValues: { - exchange: '', - apiKey: '', - secretKey: '', - }, - resolver: zodResolver( - z.object({ - exchange: z.string().min(1, t('validation.required')), - apiKey: z.string().trim().min(1, t('validation.required')), - secretKey: z.string().trim().min(1, t('validation.required')), - }) - ), - }); - - useEffect(() => { - return () => { - reset(); - resetMutation(); - }; - }, [reset, resetMutation]); - - const onSubmit = (data: { - exchange: string; - apiKey: string; - secretKey: string; - }) => { - enrollExchangeApiKey(data); - }; - - return ( -
- - - {isMobile - ? t('worker.profile.apiKeyData.connectApiKey') - : t('worker.profile.apiKeyData.connectYourApiKey')} - - {isPending && } - {isIdle && ( - <> - - {t('worker.profile.apiKeyData.modalDescription')} - - - - ( - exchange.name) || - [] - } - getOptionLabel={(option) => { - const exchange = supportedExchanges?.find( - (exchange) => exchange.name === option - ); - return exchange?.display_name || option || ''; - }} - renderInput={(params) => ( - - )} - renderOption={(props, option) => { - const exchange = supportedExchanges?.find( - (exchange) => exchange.name === option - ); - return ( - - - {exchange?.display_name || exchange?.name} - - - ); - }} - {...field} - onChange={(_, value) => field.onChange(value)} - /> - )} - /> - {errors.exchange && ( - - {errors.exchange.message} - - )} - - - ( - - )} - /> - {errors.apiKey && ( - {errors.apiKey.message} - )} - - - - ( - - )} - /> - {errors.secretKey && ( - - {errors.secretKey.message} - - )} - - - )} - {isSuccess && ( - - - {t('worker.profile.apiKeyData.connectSuccess')} - - - )} - {isError && ( - - )} - {isIdle && ( - - )} - {(isPending || isSuccess) && ( - - )} - {isError && ( - - )} - - {t('worker.profile.apiKeyData.modalFooterAgreement')} - - -
- ); -} diff --git a/packages/apps/human-app/frontend/src/modules/worker/profile/components/api-key-data.tsx b/packages/apps/human-app/frontend/src/modules/worker/profile/components/api-key-data.tsx deleted file mode 100644 index a6fa175b58..0000000000 --- a/packages/apps/human-app/frontend/src/modules/worker/profile/components/api-key-data.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import { IconButton, Stack, Typography } from '@mui/material'; -import { useTranslation } from 'react-i18next'; -import { Chip } from '@/shared/components/ui/chip'; -import { CustomTextField, CustomTextFieldDark } from './custom-text-field'; -import { useColorMode } from '@/shared/contexts/color-mode'; -import { DeleteIcon, EditIcon } from '@/shared/components/ui/icons'; -import { - useDeleteApiKeyModal, - useEditApiKeyModal, -} from '../hooks/use-api-key-modals'; -import { useGetExchangeApiKeys } from '../../hooks/use-exchange-api-keys'; - -export function ApiKeyData({ - stakingExchangeError, -}: { - stakingExchangeError?: string; -}) { - const { isDarkMode } = useColorMode(); - const { t } = useTranslation(); - const { openModal: openEditApiKeyModal } = useEditApiKeyModal(); - const { openModal: openDeleteApiKeyModal } = useDeleteApiKeyModal(); - const { data: exchangeApiKeyData, isError: isExchangeApiKeyError } = - useGetExchangeApiKeys(); - - const textField = isDarkMode ? ( - - ) : ( - - ); - - return ( - - - - {t('worker.profile.apiKeyData.apiKey')} - - - - - {textField} - {exchangeApiKeyData?.exchange_name && ( - - - openEditApiKeyModal(exchangeApiKeyData.exchange_name) - } - > - - - - - - - )} - - - ); -} diff --git a/packages/apps/human-app/frontend/src/modules/worker/profile/components/delete-api-key-modal.tsx b/packages/apps/human-app/frontend/src/modules/worker/profile/components/delete-api-key-modal.tsx deleted file mode 100644 index 6a75d44423..0000000000 --- a/packages/apps/human-app/frontend/src/modules/worker/profile/components/delete-api-key-modal.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import { Stack, Typography } from '@mui/material'; -import { useTranslation } from 'react-i18next'; -import { Button } from '@/shared/components/ui/button'; -import { useIsMobile } from '@/shared/hooks'; -import { useDeleteExchangeApiKeys } from '../../hooks/use-exchange-api-keys'; -import { useEffect } from 'react'; -import { ModalError, ModalSuccess, ModalLoading } from './modal-states'; - -interface DeleteApiKeyModalProps { - onClose: () => void; - disableClose: (disable: boolean) => void; -} - -export function DeleteApiKeyModal({ - onClose, - disableClose, -}: DeleteApiKeyModalProps) { - const { t } = useTranslation(); - const { - mutate: deleteExchangeApiKey, - reset: resetMutation, - isSuccess, - isError, - isPending, - isIdle, - } = useDeleteExchangeApiKeys(); - const isMobile = useIsMobile(); - - const handleDeleteExchangeApiKey = () => { - deleteExchangeApiKey(); - }; - - useEffect(() => { - disableClose(isPending); - }, [isPending, disableClose]); - - useEffect(() => { - return () => { - resetMutation(); - }; - }, [resetMutation]); - - return ( - - - {t('worker.profile.apiKeyData.deleteApiKey')} - - {isPending && } - {isIdle && ( - <> - - {t('worker.profile.apiKeyData.deleteApiKeyConfirmation')} - - - {t('worker.profile.apiKeyData.deleteApiKeyDescription')} - - - )} - {isSuccess && ( - - - {t('worker.profile.apiKeyData.deleteKeySuccess')} - - - )} - {isError && ( - - )} - {isIdle && ( - - - - - )} - {(isPending || isSuccess) && ( - - )} - {isError && ( - - )} - - ); -} diff --git a/packages/apps/human-app/frontend/src/modules/worker/profile/components/edit-api-key-modal.tsx b/packages/apps/human-app/frontend/src/modules/worker/profile/components/edit-api-key-modal.tsx deleted file mode 100644 index 9141eb9b02..0000000000 --- a/packages/apps/human-app/frontend/src/modules/worker/profile/components/edit-api-key-modal.tsx +++ /dev/null @@ -1,280 +0,0 @@ -import { zodResolver } from '@hookform/resolvers/zod'; -import { - Autocomplete, - Box, - FormControl, - FormHelperText, - Stack, - TextField, - Typography, -} from '@mui/material'; -import { Controller, useForm } from 'react-hook-form'; -import { useTranslation } from 'react-i18next'; -import { z } from 'zod'; -import { Button } from '@/shared/components/ui/button'; -import { useIsMobile } from '@/shared/hooks'; -import { useEffect } from 'react'; -import { - useEnrollExchangeApiKeys, - useGetSupportedExchanges, -} from '../../hooks/use-exchange-api-keys'; -import { ModalError, ModalLoading, ModalSuccess } from './modal-states'; - -interface EditApiKeyModalProps { - exchangeName: string; - onClose: () => void; - disableClose: (disable: boolean) => void; -} - -export function EditApiKeyModal({ - onClose, - exchangeName, - disableClose, -}: EditApiKeyModalProps) { - const { t } = useTranslation(); - const isMobile = useIsMobile(); - const { - mutate: postExchangeApiKey, - reset: resetMutation, - error, - isSuccess, - isError, - isPending, - isIdle, - } = useEnrollExchangeApiKeys(); - const { data: supportedExchanges } = useGetSupportedExchanges(); - - const { - control, - handleSubmit, - formState: { errors }, - reset, - } = useForm({ - defaultValues: { - exchange: '', - apiKey: '', - secretKey: '', - }, - resolver: zodResolver( - z.object({ - exchange: z.string().min(1, t('validation.required')), - apiKey: z.string().trim().min(1, t('validation.required')), - secretKey: z.string().trim().min(1, t('validation.required')), - }) - ), - }); - - useEffect(() => { - if (exchangeName && supportedExchanges) { - reset({ - exchange: exchangeName, - apiKey: '', - secretKey: '', - }); - } - }, [exchangeName, reset, supportedExchanges]); - - useEffect(() => { - disableClose(isPending); - }, [isPending, disableClose]); - - useEffect(() => { - return () => { - reset(); - resetMutation(); - }; - }, [reset, resetMutation]); - - const onSubmit = (data: { - exchange: string; - apiKey: string; - secretKey: string; - }) => { - postExchangeApiKey(data); - }; - - return ( -
- - - {t('worker.profile.apiKeyData.editApiKey')} - - {isPending && } - {isIdle && ( - <> - - {t('worker.profile.apiKeyData.modalDescription')} - - - - ( - exchange.name) || - [] - } - getOptionLabel={(option) => { - const exchange = supportedExchanges?.find( - (exchange) => exchange.name === option - ); - return exchange?.display_name || option || ''; - }} - renderInput={(params) => ( - - )} - renderOption={(props, option) => { - const exchange = supportedExchanges?.find( - (exchange) => exchange.name === option - ); - return ( - - - {exchange?.display_name || exchange?.name} - - - ); - }} - {...field} - onChange={(_, value) => field.onChange(value)} - /> - )} - /> - {errors.exchange && ( - - {errors.exchange.message} - - )} - - - ( - - )} - /> - {errors.apiKey && ( - {errors.apiKey.message} - )} - - - - ( - - )} - /> - {errors.secretKey && ( - - {errors.secretKey.message} - - )} - - - )} - {isSuccess && ( - - - {t('worker.profile.apiKeyData.editSuccess')} - - - )} - {isError && ( - - )} - {isIdle && ( - - - - - )} - {(isPending || isSuccess) && ( - - )} - {isError && ( - - )} - -
- ); -} diff --git a/packages/apps/human-app/frontend/src/modules/worker/profile/components/index.ts b/packages/apps/human-app/frontend/src/modules/worker/profile/components/index.ts index 7df62f04b8..7b2eadb361 100644 --- a/packages/apps/human-app/frontend/src/modules/worker/profile/components/index.ts +++ b/packages/apps/human-app/frontend/src/modules/worker/profile/components/index.ts @@ -2,9 +2,3 @@ export * from './wallet-connect-done'; export * from './profile-data'; export * from './identity-verification-control'; export * from './wallet-connection-control'; -export * from './staking-info'; -export * from './api-key-data'; -export * from './custom-text-field'; -export * from './add-api-key-modal'; -export * from './edit-api-key-modal'; -export * from './delete-api-key-modal'; diff --git a/packages/apps/human-app/frontend/src/modules/worker/profile/components/staking-info.tsx b/packages/apps/human-app/frontend/src/modules/worker/profile/components/staking-info.tsx deleted file mode 100644 index 889d26aaae..0000000000 --- a/packages/apps/human-app/frontend/src/modules/worker/profile/components/staking-info.tsx +++ /dev/null @@ -1,225 +0,0 @@ -import { - Button, - IconButton, - Link, - Skeleton, - Stack, - Typography, -} from '@mui/material'; -import { useTranslation } from 'react-i18next'; -import { Chip } from '@/shared/components/ui/chip'; -import { env } from '@/shared/env'; -import { useAddApiKeyModal } from '../hooks/use-api-key-modals'; -import { ApiKeyData } from './'; -import { useGetStakingSummary } from '../../hooks/use-staking'; -import { RefreshIcon } from '@/shared/components/ui/icons'; -import { useGetExchangeApiKeys } from '../../hooks/use-exchange-api-keys'; -import { useAuthenticatedUser } from '@/modules/auth/hooks/use-authenticated-user'; -import { useEffect, useRef, useState } from 'react'; -import { useAccessTokenRefresh } from '@/api/hooks/use-access-token-refresh'; -import { colorPalette } from '@/shared/styles/color-palette'; -import { useGetUiConfig } from '@/shared/hooks/use-get-ui-config'; -import { - TopNotificationType, - useNotification, -} from '@/shared/hooks/use-notification'; - -export function StakingInfo() { - const [isPromptExpanded, setIsPromptExpanded] = useState(false); - const tokenRefreshLock = useRef(false); - - const { user, updateUserData } = useAuthenticatedUser(); - const { refreshAccessTokenAsync } = useAccessTokenRefresh(); - const { t } = useTranslation(); - const { showNotification } = useNotification(); - - const { openModal: openAddApiKeyModal } = useAddApiKeyModal(); - const { data: exchangeApiKeyData, isLoading: isExchangeApiKeyLoading } = - useGetExchangeApiKeys(); - const { - data: stakingSummary, - isLoading, - isError, - refetch, - isRefetching, - } = useGetStakingSummary(); - const { data: uiConfig, isLoading: isUiConfigLoading } = useGetUiConfig(); - - const isConnectButtonDisabled = - !!exchangeApiKeyData?.exchange_name || isExchangeApiKeyLoading; - - const stakedAmount = - Number(stakingSummary?.on_chain_stake || 0) + - Number(stakingSummary?.exchange_stake || 0); - - const isStaked = - isLoading || isError || isUiConfigLoading - ? false - : stakedAmount >= Number(uiConfig?.minThreshold || '0'); - - useEffect(() => { - const stakingSummaryError = - stakingSummary?.on_chain_error || stakingSummary?.exchange_error; - if (stakingSummaryError && !isLoading && !isRefetching) { - showNotification({ - type: TopNotificationType.WARNING, - message: stakingSummaryError, - }); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ - isLoading, - isRefetching, - stakingSummary?.on_chain_error, - stakingSummary?.exchange_error, - ]); - - useEffect(() => { - if (isRefetching || isLoading) return; - - if (isStaked !== user.is_stake_eligible) { - if (!tokenRefreshLock.current) { - tokenRefreshLock.current = true; - updateUserData({ is_stake_eligible: isStaked }); - void refreshAccessTokenAsync({ authType: 'web2' }); - } - } else { - tokenRefreshLock.current = false; - } - }, [ - isStaked, - user.is_stake_eligible, - refreshAccessTokenAsync, - isRefetching, - isLoading, - updateUserData, - ]); - - const handleRefreshStakingInfo = () => { - if (isRefetching || isLoading) return; - tokenRefreshLock.current = false; - refetch(); - }; - - return ( - - - - {t('worker.profile.stakingInfo.stakeHmt')} - - {isLoading || isRefetching ? ( - - ) : ( - - )} - - - {isPromptExpanded - ? t('worker.profile.stakingInfo.prompt', { - amount: uiConfig?.minThreshold, - }) - : t('worker.profile.stakingInfo.promptShort')}{' '} - {isPromptExpanded && ( - <> -
- - {t('worker.profile.stakingInfo.howToCreateApiKeys')} - -
- - )} - -
- - - {t('worker.profile.stakingInfo.stakedAmount')} - - svg > path': { - fill: - isRefetching || isLoading - ? colorPalette.button.disabled - : 'primary.main', - }, - }} - onClick={handleRefreshStakingInfo} - > - - - - {isLoading || isRefetching ? ( - - ) : ( - - {stakedAmount} HMT - - )} - - - - - -
- ); -} diff --git a/packages/apps/human-app/frontend/src/modules/worker/profile/hooks/use-api-key-modals.tsx b/packages/apps/human-app/frontend/src/modules/worker/profile/hooks/use-api-key-modals.tsx deleted file mode 100644 index 5d7db03586..0000000000 --- a/packages/apps/human-app/frontend/src/modules/worker/profile/hooks/use-api-key-modals.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { useModal } from '@/shared/contexts/modal-context'; -import { - AddApiKeyModal, - EditApiKeyModal, - DeleteApiKeyModal, -} from '../components'; - -export function useAddApiKeyModal() { - const { openModal, closeModal, setDisableClose } = useModal(); - - return { - openModal: () => - openModal({ - content: ( - - ), - }), - }; -} - -export function useEditApiKeyModal() { - const { openModal, closeModal, setDisableClose } = useModal(); - - return { - openModal: (exchangeName: string) => - openModal({ - content: ( - - ), - }), - }; -} - -export function useDeleteApiKeyModal() { - const { openModal, closeModal, setDisableClose } = useModal(); - - return { - openModal: () => - openModal({ - content: ( - - ), - }), - }; -} diff --git a/packages/apps/human-app/frontend/src/modules/worker/profile/views/profile.page.tsx b/packages/apps/human-app/frontend/src/modules/worker/profile/views/profile.page.tsx index 3fa42e64b9..d79116a913 100644 --- a/packages/apps/human-app/frontend/src/modules/worker/profile/views/profile.page.tsx +++ b/packages/apps/human-app/frontend/src/modules/worker/profile/views/profile.page.tsx @@ -12,10 +12,7 @@ import { ProfileData, IdentityVerificationControl, WalletConnectionControl, - StakingInfo, } from '../components'; -import { PageCardLoader } from '@/shared/components/ui/page-card/page-card-loader'; -import { useUiConfig } from '@/shared/providers/ui-config-provider'; export function WorkerProfilePage() { const { user } = useAuthenticatedUser(); @@ -23,7 +20,6 @@ export function WorkerProfilePage() { const { isConnected, initializing, web3ProviderMutation } = useWalletConnect(); const { showNotification } = useNotification(); - const { uiConfig, isUiConfigLoading } = useUiConfig(); useEffect(() => { if (initializing) return; @@ -50,10 +46,6 @@ export function WorkerProfilePage() { showNotification, ]); - if (isUiConfigLoading) { - return ; - } - return ( - {!!user.wallet_address && uiConfig?.stakingEligibilityEnabled && ( - - )} ); diff --git a/packages/apps/human-app/frontend/src/modules/worker/providers/require-stake.tsx b/packages/apps/human-app/frontend/src/modules/worker/providers/require-stake.tsx deleted file mode 100644 index 83802a5467..0000000000 --- a/packages/apps/human-app/frontend/src/modules/worker/providers/require-stake.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import type { ReactNode } from 'react'; -import { useAuthenticatedUser } from '@/modules/auth/hooks/use-authenticated-user'; -import { routerPaths } from '@/router/router-paths'; -import { protectedRoutes } from '@/router/routes'; -import { useUiConfig } from '@/shared/providers/ui-config-provider'; -import { Navigate, useLocation, matchPath } from 'react-router-dom'; - -const stakeProtectedPaths = protectedRoutes - .map((route) => route.routerProps.path) - .filter((path) => path !== routerPaths.worker.profile); - -export function RequireStake({ children }: Readonly<{ children: ReactNode }>) { - const { user } = useAuthenticatedUser(); - const location = useLocation(); - const { uiConfig } = useUiConfig(); - - const isStakeProtectedRoute = stakeProtectedPaths.some( - (path) => path && matchPath(path, location.pathname) - ); - - if ( - uiConfig?.stakingEligibilityEnabled && - !user?.is_stake_eligible && - isStakeProtectedRoute - ) { - return ; - } - - return children; -} diff --git a/packages/apps/human-app/frontend/src/modules/worker/services/exchangeApiKeys.service.ts b/packages/apps/human-app/frontend/src/modules/worker/services/exchangeApiKeys.service.ts deleted file mode 100644 index 41db9404e2..0000000000 --- a/packages/apps/human-app/frontend/src/modules/worker/services/exchangeApiKeys.service.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { authorizedHumanAppApiClient } from '@/api'; - -interface ExchangeApiKey { - api_key: string; - exchange_name: string; -} - -interface Exchange { - name: string; - display_name: string; -} - -async function getSupportedExchanges(): Promise { - const response = await authorizedHumanAppApiClient.get( - '/exchange-api-keys/supported-exchanges' - ); - return response || []; -} - -async function getExchangeApiKeys(): Promise { - const response = - await authorizedHumanAppApiClient.get('/exchange-api-keys'); - return response || null; -} - -async function enrollExchangeApiKeys(data: { - exchange: string; - apiKey: string; - secretKey: string; -}): Promise { - const { exchange, ...body } = data; - await authorizedHumanAppApiClient.post(`/exchange-api-keys/${exchange}`, { - body, - }); -} - -async function deleteExchangeApiKeys(): Promise { - await authorizedHumanAppApiClient.delete('/exchange-api-keys'); -} - -export { - enrollExchangeApiKeys, - getExchangeApiKeys, - deleteExchangeApiKeys, - getSupportedExchanges, -}; diff --git a/packages/apps/human-app/frontend/src/modules/worker/services/staking.service.ts b/packages/apps/human-app/frontend/src/modules/worker/services/staking.service.ts deleted file mode 100644 index d4a38a65b3..0000000000 --- a/packages/apps/human-app/frontend/src/modules/worker/services/staking.service.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { authorizedHumanAppApiClient } from '@/api'; - -interface StakeSummary { - exchange_stake: string; - exchange_error?: string; - on_chain_stake: string; - on_chain_error?: string; -} - -async function getStakingSummary(): Promise { - const response = - await authorizedHumanAppApiClient.get('/staking/summary'); - return response || null; -} - -export { getStakingSummary }; diff --git a/packages/apps/human-app/frontend/src/router/components/drawer-menu-items/drawer-menu-items-worker.tsx b/packages/apps/human-app/frontend/src/router/components/drawer-menu-items/drawer-menu-items-worker.tsx index 5c39359e16..427bba124b 100644 --- a/packages/apps/human-app/frontend/src/router/components/drawer-menu-items/drawer-menu-items-worker.tsx +++ b/packages/apps/human-app/frontend/src/router/components/drawer-menu-items/drawer-menu-items-worker.tsx @@ -9,21 +9,14 @@ import type { UserData } from '@/modules/auth/context/auth-context'; import { routerPaths } from '@/router/router-paths'; import { KycStatus } from '@/modules/worker/profile/types'; import { type MenuItem } from '../layout/protected'; -import { UiConfig } from '@/shared/services/ui-config.service'; -export const workerDrawerTopMenuItems = ( - user: UserData | null, - uiConfig: UiConfig | undefined -): MenuItem[] => { +export const workerDrawerTopMenuItems = (user: UserData | null): MenuItem[] => { return [ { label: t('components.DrawerNavigation.jobs'), icon: , link: routerPaths.worker.jobsDiscovery, - disabled: - !user?.wallet_address || - (uiConfig?.stakingEligibilityEnabled && !user?.is_stake_eligible) || - user.kyc_status !== KycStatus.APPROVED, + disabled: !user?.wallet_address || user.kyc_status !== KycStatus.APPROVED, }, ]; }; diff --git a/packages/apps/human-app/frontend/src/router/router.tsx b/packages/apps/human-app/frontend/src/router/router.tsx index 0d27ce4c46..b22c8052d8 100644 --- a/packages/apps/human-app/frontend/src/router/router.tsx +++ b/packages/apps/human-app/frontend/src/router/router.tsx @@ -20,12 +20,9 @@ import { workerDrawerBottomMenuItems, workerDrawerTopMenuItems, } from './components'; -import { RequireStake } from '@/modules/worker/providers/require-stake'; -import { useUiConfig } from '@/shared/providers/ui-config-provider'; export function Router() { const { user } = useAuth(); - const { uiConfig } = useUiConfig(); const handleSignOut = () => { browserAuthProvider.signOut({ @@ -60,24 +57,22 @@ export function Router() { - - ( - - )} - renderHCaptchaStatisticsDrawer={(isOpen) => ( - - )} - renderGovernanceBanner - /> - + ( + + )} + renderHCaptchaStatisticsDrawer={(isOpen) => ( + + )} + renderGovernanceBanner + /> } key={routerProps.path} diff --git a/packages/apps/human-app/frontend/src/shared/i18n/en.json b/packages/apps/human-app/frontend/src/shared/i18n/en.json index d5619012e9..127b9c1d4e 100644 --- a/packages/apps/human-app/frontend/src/shared/i18n/en.json +++ b/packages/apps/human-app/frontend/src/shared/i18n/en.json @@ -226,48 +226,6 @@ "review": "Under Review", "expired": "Expired", "abandoned": "Abandoned" - }, - "stakingStatusValues": { - "staked": "Staked", - "error": "Error", - "notStaked": "Not Staked" - }, - "stakingInfo": { - "promptShort": "Before you can start earning on the HUMAN App, you'll need to stake HMT.", - "prompt": "Before you can start earning on the HUMAN App, you’ll need to stake HMT. You can stake directly on our Staking Dashboard, or connect your API key having minimum balance of {{amount}} HMT in your exchange account to stake automatically via API KEY.", - "stakeHmt": "Stake HMT", - "stakingInfoValue": "Staking Info Value", - "stakedAmount": "Staked amount", - "readMore": "Read more", - "readLess": "Read less", - "howToCreateApiKeys": "How to create API keys?" - }, - "apiKeyData": { - "apiKey": "API KEY", - "exchange": "Exchange", - "apiSecret": "API Secret", - "apiKeyConnected": "Connected", - "apiKeyNotConnected": "Not connected", - "cancel": "Cancel", - "error": "Error", - "close": "Close", - "edit": "Edit", - "tryAgain": "Try Again", - "connectYourApiKey": "Connect your API KEY", - "connectApiKey": "Connect API KEY", - "connectSuccess": "You have successfully connected your API key", - "connectError": "Failed to connect API key.", - "editSuccess": "You have successfully edited your API key", - "editError": "Failed to edit API key.", - "deleteKeySuccess": "You have successfully deleted your API key", - "deleteKeyError": "Failed to delete API key.", - "modalDescription": "To stake HMT using your exchange balance, connect your exchange account by adding your API key and secret. Your credentials are encrypted and securely stored.", - "modalFooterAgreement": "By connecting your API KEY, you agree to HUMAN Protocol Terms of Service and consent to its Privacy Policy.", - "deleteApiKey": "Delete API KEY", - "deleteApiKeyConfirmation": "Are you sure you want to delete your API key?", - "deleteApiKeyDescription": "You can only solve jobs in the HUMAN App if you have staked HMT.", - "editApiKey": "Edit API KEY", - "saveChanges": "Save Changes" } }, "oraclesTable": { diff --git a/packages/apps/human-app/frontend/src/shared/providers/ui-config-provider.tsx b/packages/apps/human-app/frontend/src/shared/providers/ui-config-provider.tsx deleted file mode 100644 index 5f23cd7d49..0000000000 --- a/packages/apps/human-app/frontend/src/shared/providers/ui-config-provider.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import React, { createContext, useContext, useMemo } from 'react'; -import { useGetUiConfig } from '../hooks/use-get-ui-config'; -import { UiConfig } from '../services/ui-config.service'; - -interface UiConfigContextType { - uiConfig: UiConfig | undefined; - isUiConfigLoading: boolean; - isUiConfigError: boolean; - error: Error | null; -} - -const UiConfigContext = createContext( - undefined -); - -export function UiConfigProvider({ - children, -}: Readonly<{ children: React.ReactNode }>) { - const { data, isLoading, error, isError } = useGetUiConfig(); - - const contextValue = useMemo( - () => ({ - uiConfig: data, - isUiConfigLoading: isLoading, - isUiConfigError: isError, - error, - }), - [data, isLoading, isError, error] - ); - - return ( - - {children} - - ); -} - -export const useUiConfig = () => { - const context = useContext(UiConfigContext); - if (!context) { - throw new Error('useUiConfig must be used within a UiConfigProvider'); - } - return context; -}; diff --git a/packages/apps/human-app/frontend/src/shared/services/ui-config.service.ts b/packages/apps/human-app/frontend/src/shared/services/ui-config.service.ts index 5103cc92c3..0fadf37eaf 100644 --- a/packages/apps/human-app/frontend/src/shared/services/ui-config.service.ts +++ b/packages/apps/human-app/frontend/src/shared/services/ui-config.service.ts @@ -7,8 +7,6 @@ const apiPaths = { const uiConfigSchema = z.object({ chainIdsEnabled: z.array(z.number()), - stakingEligibilityEnabled: z.boolean().prefault(false), - minThreshold: z.string(), }); export type UiConfig = z.infer; diff --git a/packages/apps/human-app/server/src/app.module.ts b/packages/apps/human-app/server/src/app.module.ts index 6de9bbd087..529154b0ed 100644 --- a/packages/apps/human-app/server/src/app.module.ts +++ b/packages/apps/human-app/server/src/app.module.ts @@ -58,10 +58,6 @@ import { OperatorController } from './modules/user-operator/operator.controller' import { OperatorModule } from './modules/user-operator/operator.module'; import { WorkerController } from './modules/user-worker/worker.controller'; import { WorkerModule } from './modules/user-worker/worker.module'; -import { ExchangeApiKeysModule } from './modules/exchange-api-keys/exchange-api-keys.module'; -import { ExchangeApiKeysController } from './modules/exchange-api-keys/exchange-api-keys.controller'; -import { StakingController } from './modules/staking/staking.controller'; -import { StakingModule } from './modules/staking/staking.module'; const JOI_BOOLEAN_STRING_SCHEMA = Joi.string().valid('true', 'false'); @@ -151,8 +147,6 @@ const JOI_BOOLEAN_STRING_SCHEMA = Joi.string().valid('true', 'false'); NDAModule, AbuseModule, GovernanceModule, - ExchangeApiKeysModule, - StakingModule, ], controllers: [ AppController, @@ -168,8 +162,6 @@ const JOI_BOOLEAN_STRING_SCHEMA = Joi.string().valid('true', 'false'); NDAController, AbuseController, GovernanceController, - ExchangeApiKeysController, - StakingController, ], exports: [HttpModule], providers: [ diff --git a/packages/apps/human-app/server/src/common/config/gateway-config.service.ts b/packages/apps/human-app/server/src/common/config/gateway-config.service.ts index 0dbbb0c2cb..7f7c548fb2 100644 --- a/packages/apps/human-app/server/src/common/config/gateway-config.service.ts +++ b/packages/apps/human-app/server/src/common/config/gateway-config.service.ts @@ -141,36 +141,6 @@ export class GatewayConfigService { method: HttpMethod.GET, headers: this.JSON_HEADER, }, - [ReputationOracleEndpoints.EXCHANGE_API_KEYS_ENROLL]: { - endpoint: '/exchange-api-keys', - method: HttpMethod.POST, - headers: this.JSON_HEADER, - }, - [ReputationOracleEndpoints.EXCHANGE_API_KEYS_DELETE]: { - endpoint: '/exchange-api-keys', - method: HttpMethod.DELETE, - headers: this.JSON_HEADER, - }, - [ReputationOracleEndpoints.EXCHANGE_API_KEYS_RETRIEVE]: { - endpoint: '/exchange-api-keys', - method: HttpMethod.GET, - headers: this.JSON_HEADER, - }, - [ReputationOracleEndpoints.EXCHANGE_API_KEYS_SUPPORTED_EXCHANGES]: { - endpoint: '/exchange-api-keys/supported', - method: HttpMethod.GET, - headers: this.JSON_HEADER, - }, - [ReputationOracleEndpoints.STAKE_SUMMARY]: { - endpoint: '/staking/summary', - method: HttpMethod.GET, - headers: this.JSON_HEADER, - }, - [ReputationOracleEndpoints.STAKE_CONFIG]: { - endpoint: '/staking/config', - method: HttpMethod.GET, - headers: this.JSON_HEADER, - }, } as Record, }, [ExternalApiName.HCAPTCHA_LABELING_STATS]: { diff --git a/packages/apps/human-app/server/src/common/enums/http-method.ts b/packages/apps/human-app/server/src/common/enums/http-method.ts index 4dfcef38b9..5a3bbf6de1 100644 --- a/packages/apps/human-app/server/src/common/enums/http-method.ts +++ b/packages/apps/human-app/server/src/common/enums/http-method.ts @@ -1,5 +1,4 @@ export enum HttpMethod { GET = 'GET', POST = 'POST', - DELETE = 'DELETE', } diff --git a/packages/apps/human-app/server/src/common/enums/reputation-oracle-endpoints.ts b/packages/apps/human-app/server/src/common/enums/reputation-oracle-endpoints.ts index 63cc216389..bedd90d15d 100644 --- a/packages/apps/human-app/server/src/common/enums/reputation-oracle-endpoints.ts +++ b/packages/apps/human-app/server/src/common/enums/reputation-oracle-endpoints.ts @@ -22,12 +22,6 @@ export enum ReputationOracleEndpoints { SIGN_NDA = 'sign_nda', REPORT_ABUSE = 'report_abuse', GET_ABUSE_REPORTS = 'get_abuse_reports', - EXCHANGE_API_KEYS_ENROLL = 'exchange_api_keys_enroll', - EXCHANGE_API_KEYS_DELETE = 'exchange_api_keys_delete', - EXCHANGE_API_KEYS_RETRIEVE = 'exchange_api_keys_retrieve', - EXCHANGE_API_KEYS_SUPPORTED_EXCHANGES = 'exchange_api_keys_supported_exchanges', - STAKE_SUMMARY = 'stake_summary', - STAKE_CONFIG = 'stake_config', } export enum HCaptchaLabelingStatsEndpoints { USER_STATS = 'user_stats', diff --git a/packages/apps/human-app/server/src/common/guards/strategy/jwt.http.ts b/packages/apps/human-app/server/src/common/guards/strategy/jwt.http.ts index 5d79c29c28..1a06cd60ee 100644 --- a/packages/apps/human-app/server/src/common/guards/strategy/jwt.http.ts +++ b/packages/apps/human-app/server/src/common/guards/strategy/jwt.http.ts @@ -44,7 +44,6 @@ export class JwtHttpStrategy extends PassportStrategy(Strategy, 'jwt-http') { status: string; wallet_address: string; reputation_network: string; - is_stake_eligible?: boolean; qualifications?: string[]; site_key?: string; email?: string; @@ -59,7 +58,6 @@ export class JwtHttpStrategy extends PassportStrategy(Strategy, 'jwt-http') { wallet_address: payload.wallet_address, status: payload.status, reputation_network: payload.reputation_network, - is_stake_eligible: payload.is_stake_eligible, qualifications: payload.qualifications, site_key: payload.site_key, email: payload.email, diff --git a/packages/apps/human-app/server/src/common/utils/jwt-token.model.ts b/packages/apps/human-app/server/src/common/utils/jwt-token.model.ts index a0175c642d..85da60b3c1 100644 --- a/packages/apps/human-app/server/src/common/utils/jwt-token.model.ts +++ b/packages/apps/human-app/server/src/common/utils/jwt-token.model.ts @@ -10,8 +10,6 @@ export class JwtUserData { @AutoMap() reputation_network: string; @AutoMap() - is_stake_eligible?: boolean; - @AutoMap() email?: string; @AutoMap() qualifications?: string[]; diff --git a/packages/apps/human-app/server/src/integrations/reputation-oracle/reputation-oracle.gateway.ts b/packages/apps/human-app/server/src/integrations/reputation-oracle/reputation-oracle.gateway.ts index 618833409a..03094bb53f 100644 --- a/packages/apps/human-app/server/src/integrations/reputation-oracle/reputation-oracle.gateway.ts +++ b/packages/apps/human-app/server/src/integrations/reputation-oracle/reputation-oracle.gateway.ts @@ -95,17 +95,6 @@ import { ReportAbuseParams, ReportedAbuseResponse, } from '../../modules/abuse/model/abuse.model'; -import { HttpMethod } from '../../common/enums/http-method'; -import { - EnrollExchangeApiKeysCommand, - EnrollExchangeApiKeysData, - RetrieveExchangeApiKeysResponse, - SupportedExchangeResponse, -} from '../../modules/exchange-api-keys/model/exchange-api-keys.model'; -import { - StakeConfigResponse, - StakeSummaryResponse, -} from '../../modules/staking/model/staking.model'; @Injectable() export class ReputationOracleGateway { @@ -148,76 +137,6 @@ export class ReputationOracleGateway { return response.data as T; } - async enrollExchangeApiKeys( - command: EnrollExchangeApiKeysCommand, - ): Promise<{ id: number }> { - const enrollExchangeApiKeysData = this.mapper.map( - command, - EnrollExchangeApiKeysCommand, - EnrollExchangeApiKeysData, - ); - const options = this.getEndpointOptions( - ReputationOracleEndpoints.EXCHANGE_API_KEYS_ENROLL, - enrollExchangeApiKeysData, - command.token, - ); - options.url = `${options.url}/${command.exchangeName}`; - return this.handleRequestToReputationOracle<{ id: number }>(options); - } - - async deleteExchangeApiKeys(token: string) { - const options = this.getEndpointOptions( - ReputationOracleEndpoints.EXCHANGE_API_KEYS_DELETE, - undefined, - token, - ); - options.method = HttpMethod.DELETE; - return this.handleRequestToReputationOracle(options); - } - - async retrieveExchangeApiKeys( - token: string, - ): Promise { - const options = this.getEndpointOptions( - ReputationOracleEndpoints.EXCHANGE_API_KEYS_RETRIEVE, - undefined, - token, - ); - return this.handleRequestToReputationOracle( - options, - ); - } - - async getStakeSummary(token: string): Promise { - const options = this.getEndpointOptions( - ReputationOracleEndpoints.STAKE_SUMMARY, - undefined, - token, - ); - return this.handleRequestToReputationOracle(options); - } - - async getStakeConfig(): Promise { - const options = this.getEndpointOptions( - ReputationOracleEndpoints.STAKE_CONFIG, - undefined, - ); - return this.handleRequestToReputationOracle(options); - } - - async supportedExchanges( - token: string, - ): Promise { - const options = this.getEndpointOptions( - ReputationOracleEndpoints.EXCHANGE_API_KEYS_SUPPORTED_EXCHANGES, - undefined, - token, - ); - return this.handleRequestToReputationOracle( - options, - ); - } - async sendWorkerSignup(command: SignupWorkerCommand): Promise { const signupWorkerData = this.mapper.map( command, diff --git a/packages/apps/human-app/server/src/integrations/reputation-oracle/reputation-oracle.mapper.profile.ts b/packages/apps/human-app/server/src/integrations/reputation-oracle/reputation-oracle.mapper.profile.ts index 3488762b01..1c147e2833 100644 --- a/packages/apps/human-app/server/src/integrations/reputation-oracle/reputation-oracle.mapper.profile.ts +++ b/packages/apps/human-app/server/src/integrations/reputation-oracle/reputation-oracle.mapper.profile.ts @@ -62,10 +62,6 @@ import { ReportAbuseData, ReportAbuseParams, } from '../../modules/abuse/model/abuse.model'; -import { - EnrollExchangeApiKeysCommand, - EnrollExchangeApiKeysData, -} from '../../modules/exchange-api-keys/model/exchange-api-keys.model'; @Injectable() export class ReputationOracleProfile extends AutomapperProfile { @@ -170,15 +166,6 @@ export class ReputationOracleProfile extends AutomapperProfile { destination: new SnakeCaseNamingConvention(), }), ); - createMap( - mapper, - EnrollExchangeApiKeysCommand, - EnrollExchangeApiKeysData, - namingConventions({ - source: new CamelCaseNamingConvention(), - destination: new SnakeCaseNamingConvention(), - }), - ); }; } } diff --git a/packages/apps/human-app/server/src/main.ts b/packages/apps/human-app/server/src/main.ts index d2cdacde04..330c60d253 100644 --- a/packages/apps/human-app/server/src/main.ts +++ b/packages/apps/human-app/server/src/main.ts @@ -19,7 +19,7 @@ async function bootstrap() { if (envConfigService.isCorsEnabled) { app.enableCors({ origin: envConfigService.corsEnabledOrigin, - methods: ['GET', 'POST', 'OPTIONS', 'PUT', 'DELETE'], + methods: ['GET', 'POST', 'OPTIONS', 'PUT'], allowedHeaders: envConfigService.corsAllowedHeaders, }); } diff --git a/packages/apps/human-app/server/src/modules/exchange-api-keys/exchange-api-keys.controller.ts b/packages/apps/human-app/server/src/modules/exchange-api-keys/exchange-api-keys.controller.ts deleted file mode 100644 index efb605dfa9..0000000000 --- a/packages/apps/human-app/server/src/modules/exchange-api-keys/exchange-api-keys.controller.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { - Body, - Controller, - Delete, - Get, - HttpCode, - Param, - Post, - Request, -} from '@nestjs/common'; -import { - ApiBearerAuth, - ApiBody, - ApiOperation, - ApiResponse, - ApiTags, -} from '@nestjs/swagger'; -import { RequestWithUser } from '../../common/interfaces/jwt'; -import { ExchangeApiKeysService } from '../../modules/exchange-api-keys/exchange-api-keys.service'; -import { InjectMapper } from '@automapper/nestjs'; -import { Mapper } from '@automapper/core'; -import { - EnrollExchangeApiKeysCommand, - EnrollExchangeApiKeysDto, - RetrieveExchangeApiKeysResponse, - SupportedExchangeResponse, -} from './model/exchange-api-keys.model'; - -@ApiTags('Exchange-Api-Keys') -@ApiBearerAuth() -@Controller('/exchange-api-keys') -export class ExchangeApiKeysController { - constructor( - private readonly service: ExchangeApiKeysService, - @InjectMapper() private readonly mapper: Mapper, - ) {} - - @ApiOperation({ summary: 'Enroll API keys for exchange' }) - @ApiBody({ type: EnrollExchangeApiKeysDto }) - @ApiResponse({ status: 200, description: 'Exchange API keys enrolled' }) - @HttpCode(200) - @Post('/:exchange_name') - async enroll( - @Param('exchange_name') exchangeName: string, - @Body() dto: EnrollExchangeApiKeysDto, - @Request() req: RequestWithUser, - ): Promise<{ id: number }> { - const command = this.mapper.map( - dto, - EnrollExchangeApiKeysDto, - EnrollExchangeApiKeysCommand, - ); - command.token = req.token; - command.exchangeName = exchangeName; - return this.service.enroll(command); - } - - @ApiOperation({ summary: 'Delete API keys for exchange' }) - @ApiResponse({ status: 204, description: 'Exchange API keys deleted' }) - @HttpCode(204) - @Delete('/') - async delete(@Request() req: RequestWithUser): Promise { - await this.service.delete(req.token); - } - - @ApiOperation({ - summary: 'Retrieve API keys for exchange', - }) - @Get('/') - async retrieve( - @Request() req: RequestWithUser, - ): Promise { - return this.service.retrieve(req.token); - } - - @ApiOperation({ summary: 'Get supported exchanges' }) - @Get('/supported-exchanges') - async getSupportedExchanges( - @Request() req: RequestWithUser, - ): Promise { - return this.service.getSupportedExchanges(req.token); - } -} diff --git a/packages/apps/human-app/server/src/modules/exchange-api-keys/exchange-api-keys.mapper.profile.ts b/packages/apps/human-app/server/src/modules/exchange-api-keys/exchange-api-keys.mapper.profile.ts deleted file mode 100644 index 5f65c8f475..0000000000 --- a/packages/apps/human-app/server/src/modules/exchange-api-keys/exchange-api-keys.mapper.profile.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Mapper, createMap } from '@automapper/core'; -import { AutomapperProfile, InjectMapper } from '@automapper/nestjs'; -import { Injectable } from '@nestjs/common'; -import { - EnrollExchangeApiKeysCommand, - EnrollExchangeApiKeysDto, -} from './model/exchange-api-keys.model'; - -@Injectable() -export class ExchangeApiKeysProfile extends AutomapperProfile { - constructor(@InjectMapper() mapper: Mapper) { - super(mapper); - } - - override get profile() { - return (mapper: Mapper) => { - createMap(mapper, EnrollExchangeApiKeysDto, EnrollExchangeApiKeysCommand); - }; - } -} diff --git a/packages/apps/human-app/server/src/modules/exchange-api-keys/exchange-api-keys.module.ts b/packages/apps/human-app/server/src/modules/exchange-api-keys/exchange-api-keys.module.ts deleted file mode 100644 index 3b6d627810..0000000000 --- a/packages/apps/human-app/server/src/modules/exchange-api-keys/exchange-api-keys.module.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Module } from '@nestjs/common'; -import { ExchangeApiKeysController } from '../../modules/exchange-api-keys/exchange-api-keys.controller'; -import { ExchangeApiKeysService } from '../../modules/exchange-api-keys/exchange-api-keys.service'; -import { ReputationOracleModule } from '../../integrations/reputation-oracle/reputation-oracle.module'; -import { ExchangeApiKeysProfile } from './exchange-api-keys.mapper.profile'; - -@Module({ - imports: [ReputationOracleModule], - controllers: [ExchangeApiKeysController], - providers: [ExchangeApiKeysService, ExchangeApiKeysProfile], - exports: [ExchangeApiKeysService], -}) -export class ExchangeApiKeysModule {} diff --git a/packages/apps/human-app/server/src/modules/exchange-api-keys/exchange-api-keys.service.ts b/packages/apps/human-app/server/src/modules/exchange-api-keys/exchange-api-keys.service.ts deleted file mode 100644 index 712335441b..0000000000 --- a/packages/apps/human-app/server/src/modules/exchange-api-keys/exchange-api-keys.service.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { ReputationOracleGateway } from '../../integrations/reputation-oracle/reputation-oracle.gateway'; -import { - EnrollExchangeApiKeysCommand, - RetrieveExchangeApiKeysResponse, - SupportedExchangeResponse, -} from './model/exchange-api-keys.model'; - -@Injectable() -export class ExchangeApiKeysService { - constructor(private readonly reputationOracle: ReputationOracleGateway) {} - - enroll(command: EnrollExchangeApiKeysCommand): Promise<{ id: number }> { - return this.reputationOracle.enrollExchangeApiKeys(command); - } - - delete(token: string): Promise { - return this.reputationOracle.deleteExchangeApiKeys(token); - } - - retrieve(token: string): Promise { - return this.reputationOracle.retrieveExchangeApiKeys(token); - } - - getSupportedExchanges(token: string): Promise { - return this.reputationOracle.supportedExchanges(token); - } -} diff --git a/packages/apps/human-app/server/src/modules/exchange-api-keys/model/exchange-api-keys.model.ts b/packages/apps/human-app/server/src/modules/exchange-api-keys/model/exchange-api-keys.model.ts deleted file mode 100644 index f07c049e26..0000000000 --- a/packages/apps/human-app/server/src/modules/exchange-api-keys/model/exchange-api-keys.model.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { AutoMap } from '@automapper/classes'; -import { ApiProperty } from '@nestjs/swagger'; -import { IsString } from 'class-validator'; - -export class EnrollExchangeApiKeysDto { - @AutoMap() - @IsString() - @ApiProperty() - apiKey: string; - - @AutoMap() - @IsString() - @ApiProperty() - secretKey: string; -} - -export class EnrollExchangeApiKeysCommand { - @AutoMap() - apiKey: string; - @AutoMap() - secretKey: string; - token: string; - exchangeName: string; -} - -export class EnrollExchangeApiKeysData { - @AutoMap() - apiKey: string; - @AutoMap() - secretKey: string; -} - -export class RetrieveExchangeApiKeysResponse { - apiKey: string; - exchangeName: string; -} - -export class SupportedExchangeResponse { - @ApiProperty() - name: string; - - @ApiProperty() - displayName: string; -} diff --git a/packages/apps/human-app/server/src/modules/exchange-api-keys/spec/exchange-api-keys.controller.spec.ts b/packages/apps/human-app/server/src/modules/exchange-api-keys/spec/exchange-api-keys.controller.spec.ts deleted file mode 100644 index e298642428..0000000000 --- a/packages/apps/human-app/server/src/modules/exchange-api-keys/spec/exchange-api-keys.controller.spec.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { classes } from '@automapper/classes'; -import { AutomapperModule } from '@automapper/nestjs'; -import { Test, TestingModule } from '@nestjs/testing'; -import { RequestWithUser } from '../../../common/interfaces/jwt'; -import { ExchangeApiKeysController } from '../exchange-api-keys.controller'; -import { ExchangeApiKeysService } from '../exchange-api-keys.service'; -import { - enrollExchangeApiKeysCommandFixture, - enrollExchangeApiKeysDtoFixture, - enrollExchangeApiKeysResponseFixture, - EXCHANGE_NAME, - retrieveExchangeApiKeysResponseFixture, - TOKEN, -} from './exchange-api-keys.fixtures'; -import { exchangeApiKeysServiceMock } from './exchange-api-keys.service.mock'; -import { ExchangeApiKeysProfile } from '../exchange-api-keys.mapper.profile'; - -describe('ExchangeApiKeysController', () => { - let controller: ExchangeApiKeysController; - let service: ExchangeApiKeysService; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [ExchangeApiKeysController], - imports: [ - AutomapperModule.forRoot({ - strategyInitializer: classes(), - }), - ], - providers: [ - ExchangeApiKeysService, - ExchangeApiKeysProfile, - { - provide: ExchangeApiKeysService, - useValue: exchangeApiKeysServiceMock, - }, - ], - }) - .overrideProvider(ExchangeApiKeysService) - .useValue(exchangeApiKeysServiceMock) - .compile(); - - controller = module.get( - ExchangeApiKeysController, - ); - service = module.get(ExchangeApiKeysService); - }); - - it('should be defined', () => { - expect(controller).toBeDefined(); - }); - - describe('enroll', () => { - it('should call service.enroll with mapped command and return id', async () => { - const req: RequestWithUser = { token: TOKEN } as RequestWithUser; - const result = await controller.enroll( - EXCHANGE_NAME, - enrollExchangeApiKeysDtoFixture, - req, - ); - expect(service.enroll).toHaveBeenCalledWith( - enrollExchangeApiKeysCommandFixture, - ); - expect(result).toEqual(enrollExchangeApiKeysResponseFixture); - }); - }); - - describe('delete', () => { - it('should call service.delete with token', async () => { - const req: RequestWithUser = { token: TOKEN } as RequestWithUser; - const result = await controller.delete(req); - expect(service.delete).toHaveBeenCalledWith(TOKEN); - expect(result).toEqual(undefined); - }); - }); - - describe('retrieve', () => { - it('should call service.retrieve with token and return response', async () => { - const req: RequestWithUser = { token: TOKEN } as RequestWithUser; - const result = await controller.retrieve(req); - expect(service.retrieve).toHaveBeenCalledWith(TOKEN); - expect(result).toEqual(retrieveExchangeApiKeysResponseFixture); - }); - }); - - describe('getSupportedExchanges', () => { - it('should call service.getSupportedExchanges with token and return response', async () => { - const req: RequestWithUser = { token: TOKEN } as RequestWithUser; - const result = await controller.getSupportedExchanges(req); - expect(service.getSupportedExchanges).toHaveBeenCalledWith(TOKEN); - expect(result).toEqual( - exchangeApiKeysServiceMock.getSupportedExchanges(TOKEN), - ); - }); - }); -}); diff --git a/packages/apps/human-app/server/src/modules/exchange-api-keys/spec/exchange-api-keys.fixtures.ts b/packages/apps/human-app/server/src/modules/exchange-api-keys/spec/exchange-api-keys.fixtures.ts deleted file mode 100644 index 8cfda1ab77..0000000000 --- a/packages/apps/human-app/server/src/modules/exchange-api-keys/spec/exchange-api-keys.fixtures.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { - EnrollExchangeApiKeysCommand, - EnrollExchangeApiKeysDto, - RetrieveExchangeApiKeysResponse, -} from '../model/exchange-api-keys.model'; - -export const EXCHANGE_NAME = 'mexc'; -export const TOKEN = 'test_user_token'; -export const API_KEY = 'test_api_key'; -export const API_SECRET = 'test_api_secret'; -export const ID = 123; - -export const enrollExchangeApiKeysDtoFixture: EnrollExchangeApiKeysDto = { - apiKey: API_KEY, - secretKey: API_SECRET, -}; - -export const enrollExchangeApiKeysCommandFixture: EnrollExchangeApiKeysCommand = - { - apiKey: API_KEY, - secretKey: API_SECRET, - token: TOKEN, - exchangeName: EXCHANGE_NAME, - }; - -export const enrollExchangeApiKeysResponseFixture = { - id: ID, -}; - -export const retrieveExchangeApiKeysResponseFixture: RetrieveExchangeApiKeysResponse = - { - apiKey: API_KEY, - exchangeName: EXCHANGE_NAME, - }; - -export const supportedExchangesResponseFixture = [ - { - name: 'mexc', - displayName: 'MEXC Global', - }, - { - name: 'gate', - displayName: 'Gate', - }, -]; diff --git a/packages/apps/human-app/server/src/modules/exchange-api-keys/spec/exchange-api-keys.service.mock.ts b/packages/apps/human-app/server/src/modules/exchange-api-keys/spec/exchange-api-keys.service.mock.ts deleted file mode 100644 index 357e2142d0..0000000000 --- a/packages/apps/human-app/server/src/modules/exchange-api-keys/spec/exchange-api-keys.service.mock.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { - enrollExchangeApiKeysResponseFixture, - retrieveExchangeApiKeysResponseFixture, - supportedExchangesResponseFixture, -} from './exchange-api-keys.fixtures'; - -export const exchangeApiKeysServiceMock = { - enroll: jest.fn().mockReturnValue(enrollExchangeApiKeysResponseFixture), - delete: jest.fn().mockResolvedValue(undefined), - retrieve: jest.fn().mockReturnValue(retrieveExchangeApiKeysResponseFixture), - getSupportedExchanges: jest - .fn() - .mockReturnValue(supportedExchangesResponseFixture), -}; diff --git a/packages/apps/human-app/server/src/modules/exchange-api-keys/spec/exchange-api-keys.service.spec.ts b/packages/apps/human-app/server/src/modules/exchange-api-keys/spec/exchange-api-keys.service.spec.ts deleted file mode 100644 index f29868a395..0000000000 --- a/packages/apps/human-app/server/src/modules/exchange-api-keys/spec/exchange-api-keys.service.spec.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { ReputationOracleGateway } from '../../../integrations/reputation-oracle/reputation-oracle.gateway'; -import { ExchangeApiKeysService } from '../exchange-api-keys.service'; -import { - enrollExchangeApiKeysCommandFixture, - enrollExchangeApiKeysResponseFixture, - retrieveExchangeApiKeysResponseFixture, - supportedExchangesResponseFixture, - TOKEN, -} from './exchange-api-keys.fixtures'; - -describe('ExchangeApiKeysService', () => { - let service: ExchangeApiKeysService; - let reputationOracleMock: Partial; - - beforeEach(async () => { - reputationOracleMock = { - enrollExchangeApiKeys: jest.fn(), - deleteExchangeApiKeys: jest.fn(), - retrieveExchangeApiKeys: jest.fn(), - getStakeSummary: jest.fn(), - supportedExchanges: jest.fn(), - }; - - const module: TestingModule = await Test.createTestingModule({ - providers: [ - ExchangeApiKeysService, - { provide: ReputationOracleGateway, useValue: reputationOracleMock }, - ], - }).compile(); - - service = module.get(ExchangeApiKeysService); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); - - describe('enroll', () => { - it('should enroll exchange API keys and return id', async () => { - ( - reputationOracleMock.enrollExchangeApiKeys as jest.Mock - ).mockResolvedValue(enrollExchangeApiKeysResponseFixture); - const result = await service.enroll(enrollExchangeApiKeysCommandFixture); - expect(reputationOracleMock.enrollExchangeApiKeys).toHaveBeenCalledWith( - enrollExchangeApiKeysCommandFixture, - ); - expect(result).toEqual(enrollExchangeApiKeysResponseFixture); - }); - }); - - describe('delete', () => { - it('should delete exchange API keys', async () => { - ( - reputationOracleMock.deleteExchangeApiKeys as jest.Mock - ).mockResolvedValue(undefined); - await service.delete(TOKEN); - expect(reputationOracleMock.deleteExchangeApiKeys).toHaveBeenCalledWith( - TOKEN, - ); - }); - }); - - describe('retrieve', () => { - it('should retrieve exchange API keys', async () => { - ( - reputationOracleMock.retrieveExchangeApiKeys as jest.Mock - ).mockResolvedValue(retrieveExchangeApiKeysResponseFixture); - const result = await service.retrieve(TOKEN); - expect(reputationOracleMock.retrieveExchangeApiKeys).toHaveBeenCalledWith( - TOKEN, - ); - expect(result).toEqual(retrieveExchangeApiKeysResponseFixture); - }); - }); - - describe('getSupportedExchanges', () => { - it('should retrieve supported exchanges', async () => { - (reputationOracleMock.supportedExchanges as jest.Mock).mockResolvedValue( - supportedExchangesResponseFixture, - ); - const result = await service.getSupportedExchanges(TOKEN); - expect(reputationOracleMock.supportedExchanges).toHaveBeenCalledWith( - TOKEN, - ); - expect(result).toEqual(supportedExchangesResponseFixture); - }); - }); -}); diff --git a/packages/apps/human-app/server/src/modules/job-assignment/job-assignment.controller.ts b/packages/apps/human-app/server/src/modules/job-assignment/job-assignment.controller.ts index 79e3a48663..56f6661b91 100644 --- a/packages/apps/human-app/server/src/modules/job-assignment/job-assignment.controller.ts +++ b/packages/apps/human-app/server/src/modules/job-assignment/job-assignment.controller.ts @@ -8,7 +8,6 @@ import { Post, Query, Request, - ForbiddenException, } from '@nestjs/common'; import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger'; import { RequestWithUser } from '../../common/interfaces/jwt'; @@ -43,11 +42,6 @@ export class JobAssignmentController { @Body() jobAssignmentDto: JobAssignmentDto, @Request() req: RequestWithUser, ): Promise { - // Require stake eligibility - if (!req.user?.is_stake_eligible) { - throw new ForbiddenException('Stake requirement not met'); - } - const jobAssignmentCommand = this.mapper.map( jobAssignmentDto, JobAssignmentDto, @@ -65,16 +59,6 @@ export class JobAssignmentController { @Query() jobsAssignmentParamsDto: JobsFetchParamsDto, @Request() req: RequestWithUser, ): Promise { - // Require stake eligibility - if (!req.user?.is_stake_eligible) { - return { - page: 0, - page_size: 1, - total_pages: 1, - total_results: 0, - results: [], - }; - } const jobsAssignmentParamsCommand = this.mapper.map( jobsAssignmentParamsDto, JobsFetchParamsDto, @@ -94,10 +78,6 @@ export class JobAssignmentController { @Body() dto: ResignJobDto, @Request() req: RequestWithUser, ) { - // Require stake eligibility - if (!req.user?.is_stake_eligible) { - throw new ForbiddenException('Stake requirement not met'); - } const command = this.mapper.map(dto, ResignJobDto, ResignJobCommand); command.token = req.token; return this.service.resignJob(command); @@ -112,10 +92,6 @@ export class JobAssignmentController { @Body() dto: RefreshJobDto, @Request() req: RequestWithUser, ) { - // Require stake eligibility - if (!req.user?.is_stake_eligible) { - throw new ForbiddenException('Stake requirement not met'); - } const command = new JobsFetchParamsCommand(); command.oracleAddress = dto.oracle_address; command.token = req.token; diff --git a/packages/apps/human-app/server/src/modules/job-assignment/spec/job-assignment.controller.spec.ts b/packages/apps/human-app/server/src/modules/job-assignment/spec/job-assignment.controller.spec.ts index f810cce1ca..ae69ce4e12 100644 --- a/packages/apps/human-app/server/src/modules/job-assignment/spec/job-assignment.controller.spec.ts +++ b/packages/apps/human-app/server/src/modules/job-assignment/spec/job-assignment.controller.spec.ts @@ -26,7 +26,6 @@ import { TOKEN, } from './job-assignment.fixtures'; import { jobAssignmentServiceMock } from './job-assignment.service.mock'; -import { ForbiddenException } from '@nestjs/common'; const httpServiceMock = { request: jest.fn().mockImplementation((options) => { @@ -78,7 +77,6 @@ describe('JobAssignmentController', () => { const command: JobAssignmentCommand = jobAssignmentCommandFixture; await controller.assignJob(dto, { token: jobAssignmentToken, - user: { is_stake_eligible: true }, } as RequestWithUser); expect(jobAssignmentService.processJobAssignment).toHaveBeenCalledWith( command, @@ -90,85 +88,32 @@ describe('JobAssignmentController', () => { const command: JobAssignmentCommand = jobAssignmentCommandFixture; const result = await controller.assignJob(dto, { token: jobAssignmentToken, - user: { is_stake_eligible: true }, } as RequestWithUser); expect(result).toEqual( jobAssignmentServiceMock.processJobAssignment(command), ); }); - it('should throw ForbiddenException if user is not stake eligible in assignJob', async () => { - const dto: JobAssignmentDto = jobAssignmentDtoFixture; - await expect( - controller.assignJob(dto, { - token: jobAssignmentToken, - user: { is_stake_eligible: false }, - } as RequestWithUser), - ).rejects.toThrow(new ForbiddenException('Stake requirement not met')); - }); - it('should call service processGetAssignedJobs method with proper fields set', async () => { const dto: JobsFetchParamsDto = jobsFetchParamsDtoFixture; const command: JobsFetchParamsCommand = jobsFetchParamsCommandFixture; await controller.getAssignedJobs(dto, { token: jobAssignmentToken, - user: { is_stake_eligible: true }, } as RequestWithUser); expect(jobAssignmentService.processGetAssignedJobs).toHaveBeenCalledWith( command, ); }); - it('should return empty results if user is not stake eligible in getAssignedJobs', async () => { - const dto: JobsFetchParamsDto = jobsFetchParamsDtoFixture; - const result = await controller.getAssignedJobs(dto, { - token: jobAssignmentToken, - user: { is_stake_eligible: false }, - } as RequestWithUser); - expect(result).toEqual({ - page: 0, - page_size: 1, - total_pages: 1, - total_results: 0, - results: [], - }); - }); - it('should call service refreshAssigments method with proper fields set', async () => { const dto: RefreshJobDto = refreshJobDtoFixture; await controller.refreshAssigments(dto, { token: jobAssignmentToken, - user: { is_stake_eligible: true }, } as RequestWithUser); expect(jobAssignmentService.updateAssignmentsCache).toHaveBeenCalledWith({ oracleAddress: EXCHANGE_ORACLE_ADDRESS, token: TOKEN, }); }); - - it('should throw ForbiddenException if user is not stake eligible in refreshAssigments', async () => { - const dto: RefreshJobDto = refreshJobDtoFixture; - await expect( - controller.refreshAssigments(dto, { - token: jobAssignmentToken, - user: { is_stake_eligible: false }, - } as RequestWithUser), - ).rejects.toThrow(new ForbiddenException('Stake requirement not met')); - }); - }); - - describe('resignAssigment', () => { - it('should throw ForbiddenException if user is not stake eligible in resignAssigment', async () => { - const dto = { assignment_id: '1' }; - await expect( - controller.resignAssigment( - dto as any, - { - token: jobAssignmentToken, - user: { is_stake_eligible: false }, - } as RequestWithUser, - ), - ).rejects.toThrow(new ForbiddenException('Stake requirement not met')); - }); }); }); diff --git a/packages/apps/human-app/server/src/modules/jobs-discovery/jobs-discovery.controller.ts b/packages/apps/human-app/server/src/modules/jobs-discovery/jobs-discovery.controller.ts index d2908c1c28..50650861b6 100644 --- a/packages/apps/human-app/server/src/modules/jobs-discovery/jobs-discovery.controller.ts +++ b/packages/apps/human-app/server/src/modules/jobs-discovery/jobs-discovery.controller.ts @@ -49,17 +49,6 @@ export class JobsDiscoveryController { ); } - // Require stake eligibility - if (!req.user?.is_stake_eligible) { - return { - page: 0, - page_size: 1, - total_pages: 1, - total_results: 0, - results: [], - }; - } - const jobsDiscoveryParamsCommand: JobsDiscoveryParamsCommand = this.mapper.map( jobsDiscoveryParamsDto, diff --git a/packages/apps/human-app/server/src/modules/jobs-discovery/spec/jobs-discovery.controller.spec.ts b/packages/apps/human-app/server/src/modules/jobs-discovery/spec/jobs-discovery.controller.spec.ts index 9b73a31176..c1780290c0 100644 --- a/packages/apps/human-app/server/src/modules/jobs-discovery/spec/jobs-discovery.controller.spec.ts +++ b/packages/apps/human-app/server/src/modules/jobs-discovery/spec/jobs-discovery.controller.spec.ts @@ -14,7 +14,6 @@ import { dtoFixture, jobsDiscoveryParamsCommandFixture, responseFixture, - jobDiscoveryToken, } from './jobs-discovery.fixtures'; import { jobsDiscoveryServiceMock } from './jobs-discovery.service.mock'; @@ -74,7 +73,7 @@ describe('JobsDiscoveryController', () => { const dto = dtoFixture; const command = jobsDiscoveryParamsCommandFixture; await controller.getJobs(dto, { - user: { qualifications: [], is_stake_eligible: true }, + user: { qualifications: [] }, token: command.token, } as any); command.data.qualifications = []; @@ -93,20 +92,5 @@ describe('JobsDiscoveryController', () => { ); (configServiceMock as any).jobsDiscoveryFlag = true; }); - - it('should return empty results if user is not stake eligible', async () => { - const dto = dtoFixture; - const result = await controller.getJobs(dto, { - user: { qualifications: [], is_stake_eligible: false }, - token: jobDiscoveryToken, - } as any); - expect(result).toEqual({ - page: 0, - page_size: 1, - total_pages: 1, - total_results: 0, - results: [], - }); - }); }); }); diff --git a/packages/apps/human-app/server/src/modules/staking/model/staking.model.ts b/packages/apps/human-app/server/src/modules/staking/model/staking.model.ts deleted file mode 100644 index a6b6f9d95b..0000000000 --- a/packages/apps/human-app/server/src/modules/staking/model/staking.model.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; - -export class StakeSummaryResponse { - @ApiProperty() - exchange_stake: number; - - @ApiProperty({ name: 'on_chain_stake' }) - on_chain_stake: number; - - @ApiPropertyOptional() - exchange_error?: string | null; - - @ApiPropertyOptional() - on_chain_error?: string | null; -} - -export class StakeConfigResponse { - min_threshold: number; - eligibility_enabled: boolean; -} diff --git a/packages/apps/human-app/server/src/modules/staking/spec/staking.controller.spec.ts b/packages/apps/human-app/server/src/modules/staking/spec/staking.controller.spec.ts deleted file mode 100644 index f92224d522..0000000000 --- a/packages/apps/human-app/server/src/modules/staking/spec/staking.controller.spec.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { classes } from '@automapper/classes'; -import { AutomapperModule } from '@automapper/nestjs'; -import { Test, TestingModule } from '@nestjs/testing'; -import { RequestWithUser } from '../../../common/interfaces/jwt'; -import { TOKEN } from './staking.fixtures'; -import { StakingService } from '../staking.service'; -import { StakingController } from '../staking.controller'; -import { stakingServiceMock } from './staking.service.mock'; - -describe('StakingController', () => { - let controller: StakingController; - let service: StakingService; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [StakingController], - imports: [ - AutomapperModule.forRoot({ - strategyInitializer: classes(), - }), - ], - providers: [ - StakingService, - { - provide: StakingService, - useValue: stakingServiceMock, - }, - ], - }) - .overrideProvider(StakingService) - .useValue(stakingServiceMock) - .compile(); - - controller = module.get(StakingController); - service = module.get(StakingService); - }); - - it('should be defined', () => { - expect(controller).toBeDefined(); - }); - - describe('getStakeSummary', () => { - it('should call service.getStakeSummary with token and return response', async () => { - const req: RequestWithUser = { token: TOKEN } as RequestWithUser; - const result = await controller.getStakeSummary(req); - expect(service.getStakeSummary).toHaveBeenCalledWith(TOKEN); - expect(result).toEqual(stakingServiceMock.getStakeSummary(TOKEN)); - }); - }); -}); diff --git a/packages/apps/human-app/server/src/modules/staking/spec/staking.fixtures.ts b/packages/apps/human-app/server/src/modules/staking/spec/staking.fixtures.ts deleted file mode 100644 index 93699eef96..0000000000 --- a/packages/apps/human-app/server/src/modules/staking/spec/staking.fixtures.ts +++ /dev/null @@ -1,11 +0,0 @@ -export const TOKEN = 'test_user_token'; - -export const stakeSummaryResponseFixture = { - exchange_stake: '1000', - on_chain_stake: '500', -}; - -export const stakeConfigResponseFixture = { - min_threshold: '1000', - eligibility_enabled: true, -}; diff --git a/packages/apps/human-app/server/src/modules/staking/spec/staking.service.mock.ts b/packages/apps/human-app/server/src/modules/staking/spec/staking.service.mock.ts deleted file mode 100644 index 582f931236..0000000000 --- a/packages/apps/human-app/server/src/modules/staking/spec/staking.service.mock.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { - stakeConfigResponseFixture, - stakeSummaryResponseFixture, -} from './staking.fixtures'; - -export const stakingServiceMock = { - getStakeSummary: jest.fn().mockReturnValue(stakeSummaryResponseFixture), - getStakeConfig: jest.fn().mockReturnValue(stakeConfigResponseFixture), -}; diff --git a/packages/apps/human-app/server/src/modules/staking/spec/staking.service.spec.ts b/packages/apps/human-app/server/src/modules/staking/spec/staking.service.spec.ts deleted file mode 100644 index ad97851205..0000000000 --- a/packages/apps/human-app/server/src/modules/staking/spec/staking.service.spec.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { ReputationOracleGateway } from '../../../integrations/reputation-oracle/reputation-oracle.gateway'; -import { StakingService } from '../staking.service'; -import { - stakeConfigResponseFixture, - stakeSummaryResponseFixture, - TOKEN, -} from './staking.fixtures'; - -describe('StakingService', () => { - let service: StakingService; - let reputationOracleMock: Partial; - - beforeEach(async () => { - reputationOracleMock = { - getStakeSummary: jest.fn(), - getStakeConfig: jest.fn(), - }; - - const module: TestingModule = await Test.createTestingModule({ - providers: [ - StakingService, - { provide: ReputationOracleGateway, useValue: reputationOracleMock }, - ], - }).compile(); - - service = module.get(StakingService); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); - - describe('getStakeSummary', () => { - it('should retrieve stake summary', async () => { - (reputationOracleMock.getStakeSummary as jest.Mock).mockResolvedValue( - stakeSummaryResponseFixture, - ); - const result = await service.getStakeSummary(TOKEN); - expect(reputationOracleMock.getStakeSummary).toHaveBeenCalledWith(TOKEN); - expect(result).toEqual(stakeSummaryResponseFixture); - }); - }); - - describe('getStakeConfig', () => { - it('should retrieve stake config', async () => { - (reputationOracleMock.getStakeConfig as jest.Mock).mockResolvedValue( - stakeConfigResponseFixture, - ); - const result = await service.getStakeConfig(); - expect(reputationOracleMock.getStakeConfig).toHaveBeenCalledWith(); - expect(result).toEqual(stakeConfigResponseFixture); - }); - }); -}); diff --git a/packages/apps/human-app/server/src/modules/staking/staking.controller.ts b/packages/apps/human-app/server/src/modules/staking/staking.controller.ts deleted file mode 100644 index f8bcdae90f..0000000000 --- a/packages/apps/human-app/server/src/modules/staking/staking.controller.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Mapper } from '@automapper/core'; -import { InjectMapper } from '@automapper/nestjs'; -import { Controller, Get, Request } from '@nestjs/common'; -import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger'; -import { RequestWithUser } from '../../common/interfaces/jwt'; -import { StakingService } from './staking.service'; -import { StakeSummaryResponse } from './model/staking.model'; - -@ApiTags('Staking') -@ApiBearerAuth() -@Controller('/staking') -export class StakingController { - constructor( - private readonly service: StakingService, - @InjectMapper() private readonly mapper: Mapper, - ) {} - - @ApiOperation({ summary: 'Get exchange API keys stake summary' }) - @Get('/summary') - async getStakeSummary( - @Request() req: RequestWithUser, - ): Promise { - return this.service.getStakeSummary(req.token); - } -} diff --git a/packages/apps/human-app/server/src/modules/staking/staking.module.ts b/packages/apps/human-app/server/src/modules/staking/staking.module.ts deleted file mode 100644 index 49bc184eda..0000000000 --- a/packages/apps/human-app/server/src/modules/staking/staking.module.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Module } from '@nestjs/common'; -import { StakingController } from './staking.controller'; -import { StakingService } from './staking.service'; -import { ReputationOracleModule } from '../../integrations/reputation-oracle/reputation-oracle.module'; - -@Module({ - imports: [ReputationOracleModule], - controllers: [StakingController], - providers: [StakingService], - exports: [StakingService], -}) -export class StakingModule {} diff --git a/packages/apps/human-app/server/src/modules/staking/staking.service.ts b/packages/apps/human-app/server/src/modules/staking/staking.service.ts deleted file mode 100644 index 820c8f9361..0000000000 --- a/packages/apps/human-app/server/src/modules/staking/staking.service.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { ReputationOracleGateway } from '../../integrations/reputation-oracle/reputation-oracle.gateway'; -import { - StakeConfigResponse, - StakeSummaryResponse, -} from './model/staking.model'; - -@Injectable() -export class StakingService { - constructor(private readonly reputationOracle: ReputationOracleGateway) {} - - getStakeSummary(token: string): Promise { - return this.reputationOracle.getStakeSummary(token); - } - - getStakeConfig(): Promise { - return this.reputationOracle.getStakeConfig(); - } -} diff --git a/packages/apps/human-app/server/src/modules/ui-configuration/ui-configuration.controller.spec.ts b/packages/apps/human-app/server/src/modules/ui-configuration/ui-configuration.controller.spec.ts index c8df57939b..24b68667fc 100644 --- a/packages/apps/human-app/server/src/modules/ui-configuration/ui-configuration.controller.spec.ts +++ b/packages/apps/human-app/server/src/modules/ui-configuration/ui-configuration.controller.spec.ts @@ -3,20 +3,14 @@ import { ConfigModule } from '@nestjs/config'; import { Test, TestingModule } from '@nestjs/testing'; import { EnvironmentConfigService } from '../../common/config/environment-config.service'; -import { StakingService } from '../staking/staking.service'; import { UiConfigurationController } from './ui-configuration.controller'; process.env.CHAIN_IDS_ENABLED = '80002,11155111'; describe('UiConfigurationController', () => { let controller: UiConfigurationController; - let stakingServiceMock: Pick, 'getStakeConfig'>; beforeAll(async () => { - stakingServiceMock = { - getStakeConfig: jest.fn(), - }; - const module: TestingModule = await Test.createTestingModule({ imports: [ ConfigModule.forRoot({ @@ -24,13 +18,7 @@ describe('UiConfigurationController', () => { isGlobal: true, }), ], - providers: [ - EnvironmentConfigService, - { - provide: StakingService, - useValue: stakingServiceMock, - }, - ], + providers: [EnvironmentConfigService], controllers: [UiConfigurationController], }).compile(); @@ -40,16 +28,10 @@ describe('UiConfigurationController', () => { }); it('should return proper config', async () => { - stakingServiceMock.getStakeConfig.mockResolvedValueOnce({ - eligibility_enabled: true, - min_threshold: Math.random(), - }); - const result = await controller.getConfig(); expect(result.chainIdsEnabled).toEqual([ ChainId.POLYGON_AMOY, ChainId.SEPOLIA, ]); - expect(result.stakingEligibilityEnabled).toBe(true); }); }); diff --git a/packages/apps/human-app/server/src/modules/ui-configuration/ui-configuration.controller.ts b/packages/apps/human-app/server/src/modules/ui-configuration/ui-configuration.controller.ts index 0c4107eb01..0ed982fe27 100644 --- a/packages/apps/human-app/server/src/modules/ui-configuration/ui-configuration.controller.ts +++ b/packages/apps/human-app/server/src/modules/ui-configuration/ui-configuration.controller.ts @@ -3,7 +3,6 @@ import { ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger'; import { EnvironmentConfigService } from '../../common/config/environment-config.service'; import { Public } from '../../common/decorators'; import { UiConfigResponseDto } from './ui-configuration.dto'; -import { StakingService } from '../staking/staking.service'; @Controller() @Public() @@ -11,7 +10,6 @@ import { StakingService } from '../staking/staking.service'; export class UiConfigurationController { constructor( private readonly environmentConfigService: EnvironmentConfigService, - private readonly stakingService: StakingService, ) {} @ApiOperation({ summary: 'Retrieve UI configuration' }) @@ -19,15 +17,11 @@ export class UiConfigurationController { type: UiConfigResponseDto, description: 'UI Configuration object', }) - @Header('Cache-Control', 'public, max-age=600') + @Header('Cache-Control', 'public, max-age=3600') @Get('/ui-config') public async getConfig(): Promise { - const stakingRequirementConfig = await this.stakingService.getStakeConfig(); - return { chainIdsEnabled: this.environmentConfigService.chainIdsEnabled, - stakingEligibilityEnabled: stakingRequirementConfig.eligibility_enabled, - minThreshold: stakingRequirementConfig.min_threshold, }; } } diff --git a/packages/apps/human-app/server/src/modules/ui-configuration/ui-configuration.dto.ts b/packages/apps/human-app/server/src/modules/ui-configuration/ui-configuration.dto.ts index 6633c8cf49..864757461b 100644 --- a/packages/apps/human-app/server/src/modules/ui-configuration/ui-configuration.dto.ts +++ b/packages/apps/human-app/server/src/modules/ui-configuration/ui-configuration.dto.ts @@ -9,15 +9,4 @@ export class UiConfigResponseDto { enumName: 'ChainId', }) chainIdsEnabled: ChainId[]; - - @ApiProperty({ - description: - 'Indicated if stake eligibility check enabled on app & oracles', - }) - stakingEligibilityEnabled: boolean; - - @ApiProperty({ - description: 'Minimum staking threshold required for eligibility', - }) - minThreshold: number; } diff --git a/packages/apps/human-app/server/src/modules/ui-configuration/ui-configuration.module.ts b/packages/apps/human-app/server/src/modules/ui-configuration/ui-configuration.module.ts index 2e99816674..d14d2d39bd 100644 --- a/packages/apps/human-app/server/src/modules/ui-configuration/ui-configuration.module.ts +++ b/packages/apps/human-app/server/src/modules/ui-configuration/ui-configuration.module.ts @@ -1,9 +1,7 @@ import { Module } from '@nestjs/common'; import { UiConfigurationController } from './ui-configuration.controller'; -import { StakingModule } from '../staking/staking.module'; @Module({ - imports: [StakingModule], controllers: [UiConfigurationController], }) export class UiConfigurationModule {} diff --git a/packages/apps/reputation-oracle/server/src/app.module.ts b/packages/apps/reputation-oracle/server/src/app.module.ts index a57b33c078..a064f1b5c9 100644 --- a/packages/apps/reputation-oracle/server/src/app.module.ts +++ b/packages/apps/reputation-oracle/server/src/app.module.ts @@ -14,13 +14,11 @@ import { AbuseModule } from './modules/abuse'; import { AuthModule } from './modules/auth'; import { CronJobModule } from './modules/cron-job'; import { EscrowCompletionModule } from './modules/escrow-completion'; -import { ExchangeApiKeysModule } from './modules/exchange-api-keys'; import { HealthModule } from './modules/health'; import { KycModule } from './modules/kyc'; import { NDAModule } from './modules/nda'; import { QualificationModule } from './modules/qualification'; import { ReputationModule } from './modules/reputation'; -import { StakingModule } from './modules/staking'; import { UserModule } from './modules/user'; import { IncomingWebhookModule, @@ -74,8 +72,6 @@ import Environment from './utils/environment'; CronJobModule, UserModule, NDAModule, - ExchangeApiKeysModule, - StakingModule, EscrowCompletionModule, HealthModule, KycModule, diff --git a/packages/apps/reputation-oracle/server/src/common/constants/index.ts b/packages/apps/reputation-oracle/server/src/common/constants/index.ts index 02d82593be..1bacfb11fd 100644 --- a/packages/apps/reputation-oracle/server/src/common/constants/index.ts +++ b/packages/apps/reputation-oracle/server/src/common/constants/index.ts @@ -12,20 +12,3 @@ export const RESEND_EMAIL_VERIFICATION_PATH = export const LOGOUT_PATH = '/auth/logout'; export const BACKOFF_INTERVAL_SECONDS = 120; - -export enum SupportedExchange { - MEXC = 'mexc', - GATE = 'gate', -} - -export type SupportedExchangeInfo = { - name: SupportedExchange; - displayName: string; -}; - -export const SUPPORTED_EXCHANGES_INFO: readonly SupportedExchangeInfo[] = [ - { name: SupportedExchange.MEXC, displayName: 'MEXC' }, - { name: SupportedExchange.GATE, displayName: 'Gate' }, -] as const; - -export const DEFAULT_TIMEOUT_MS = 5000; diff --git a/packages/apps/reputation-oracle/server/src/config/config.module.ts b/packages/apps/reputation-oracle/server/src/config/config.module.ts index 1adb75e47f..a06e59563c 100644 --- a/packages/apps/reputation-oracle/server/src/config/config.module.ts +++ b/packages/apps/reputation-oracle/server/src/config/config.module.ts @@ -13,7 +13,6 @@ import { ReputationConfigService } from './reputation-config.service'; import { S3ConfigService } from './s3-config.service'; import { ServerConfigService } from './server-config.service'; import { SlackConfigService } from './slack-config.service'; -import { StakingConfigService } from './staking-config.service'; import { Web3ConfigService } from './web3-config.service'; @Global() @@ -29,7 +28,6 @@ import { Web3ConfigService } from './web3-config.service'; NDAConfigService, PGPConfigService, ReputationConfigService, - StakingConfigService, S3ConfigService, ServerConfigService, SlackConfigService, @@ -45,7 +43,6 @@ import { Web3ConfigService } from './web3-config.service'; NDAConfigService, PGPConfigService, ReputationConfigService, - StakingConfigService, S3ConfigService, ServerConfigService, SlackConfigService, diff --git a/packages/apps/reputation-oracle/server/src/config/env-schema.ts b/packages/apps/reputation-oracle/server/src/config/env-schema.ts index c2a55a98d8..66eed695c5 100644 --- a/packages/apps/reputation-oracle/server/src/config/env-schema.ts +++ b/packages/apps/reputation-oracle/server/src/config/env-schema.ts @@ -82,21 +82,6 @@ export const envValidator = Joi.object({ KYC_BASE_URL: Joi.string().uri({ scheme: ['http', 'https'] }), // Human App HUMAN_APP_SECRET_KEY: Joi.string().required(), - // Staking configuration - STAKING_ASSET: Joi.string().description( - 'Asset symbol to check for staking (default HMT)', - ), - STAKING_MIN_THRESHOLD: Joi.number() - .min(0) - .description('Minimum asset amount to qualify as staked'), - STAKING_TIMEOUT_MS: Joi.number() - .integer() - .min(100) - .description('HTTP timeout for exchange staking checks in ms'), - STAKING_ELIGIBILITY_ENABLED: Joi.string() - .valid('true', 'false') - .default('false') - .description('Enable or disable staking eligibility checks'), // Slack notifications ABUSE_SLACK_WEBHOOK_URL: Joi.string() .uri({ scheme: ['http', 'https'] }) diff --git a/packages/apps/reputation-oracle/server/src/config/index.ts b/packages/apps/reputation-oracle/server/src/config/index.ts index 5d1318cd56..358c303f52 100644 --- a/packages/apps/reputation-oracle/server/src/config/index.ts +++ b/packages/apps/reputation-oracle/server/src/config/index.ts @@ -9,7 +9,6 @@ export { KycConfigService } from './kyc-config.service'; export { NDAConfigService } from './nda-config.service'; export { PGPConfigService } from './pgp-config.service'; export { ReputationConfigService } from './reputation-config.service'; -export { StakingConfigService } from './staking-config.service'; export { S3ConfigService } from './s3-config.service'; export { ServerConfigService } from './server-config.service'; export { Web3ConfigService, Web3Network } from './web3-config.service'; diff --git a/packages/apps/reputation-oracle/server/src/config/staking-config.service.ts b/packages/apps/reputation-oracle/server/src/config/staking-config.service.ts deleted file mode 100644 index 174d3ed5d1..0000000000 --- a/packages/apps/reputation-oracle/server/src/config/staking-config.service.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { ConfigService } from '@nestjs/config'; - -@Injectable() -export class StakingConfigService { - constructor(private readonly configService: ConfigService) {} - - /** - * Default asset symbol to check for staking eligibility. - * Default: 'HMT' - */ - get asset(): string { - return this.configService.get('STAKING_ASSET', 'HMT'); - } - - /** - * Minimum threshold (asset units) required for staking eligibility. - * Default: 1000 - */ - get minThreshold(): number { - return Number(this.configService.get('STAKING_MIN_THRESHOLD')) || 1000; - } - - /** - * Optional per-exchange HTTP timeout, in milliseconds. - * Default: 2000 - */ - get timeoutMs(): number { - return Number(this.configService.get('STAKING_TIMEOUT_MS')) || 2000; - } - - /** - * Feature flag to enable/disable staking eligibility enforcement. - * When disabled, eligibility will be treated as true unconditionally. - * Default: false - */ - get eligibilityEnabled(): boolean { - return ( - this.configService.get('STAKING_ELIGIBILITY_ENABLED', 'false') === - 'true' - ); - } -} diff --git a/packages/apps/reputation-oracle/server/src/database/database.module.ts b/packages/apps/reputation-oracle/server/src/database/database.module.ts index c8bb6dc8f3..093c5d7abf 100644 --- a/packages/apps/reputation-oracle/server/src/database/database.module.ts +++ b/packages/apps/reputation-oracle/server/src/database/database.module.ts @@ -13,7 +13,6 @@ import { TokenEntity } from '@/modules/auth/token.entity'; import { CronJobEntity } from '@/modules/cron-job/cron-job.entity'; import { EscrowCompletionEntity } from '@/modules/escrow-completion/escrow-completion.entity'; import { EscrowPayoutsBatchEntity } from '@/modules/escrow-completion/escrow-payouts-batch.entity'; -import { ExchangeApiKeyEntity } from '@/modules/exchange-api-keys'; import { KycEntity } from '@/modules/kyc/kyc.entity'; import { QualificationEntity } from '@/modules/qualification/qualification.entity'; import { UserQualificationEntity } from '@/modules/qualification/user-qualification.entity'; @@ -72,7 +71,6 @@ import { TypeOrmLoggerModule, TypeOrmLoggerService } from './typeorm'; OutgoingWebhookEntity, EscrowCompletionEntity, EscrowPayoutsBatchEntity, - ExchangeApiKeyEntity, ReputationEntity, TokenEntity, UserEntity, diff --git a/packages/apps/reputation-oracle/server/src/database/migrations/1783955400433-dropExchangeApiKeys.ts b/packages/apps/reputation-oracle/server/src/database/migrations/1783955400433-dropExchangeApiKeys.ts new file mode 100644 index 0000000000..c369ba619d --- /dev/null +++ b/packages/apps/reputation-oracle/server/src/database/migrations/1783955400433-dropExchangeApiKeys.ts @@ -0,0 +1,19 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class DropExchangeApiKeys1783955400433 implements MigrationInterface { + name = 'DropExchangeApiKeys1783955400433'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "hmt"."exchange_api_keys" DROP CONSTRAINT "FK_96ee74195b058a1b55afc49f673"`, + ); + await queryRunner.query( + `DROP INDEX "hmt"."IDX_96ee74195b058a1b55afc49f67"`, + ); + await queryRunner.query(`DROP TABLE "hmt"."exchange_api_keys"`); + } + + public async down(_queryRunner: QueryRunner): Promise { + // noop + } +} diff --git a/packages/apps/reputation-oracle/server/src/modules/auth/auth.module.ts b/packages/apps/reputation-oracle/server/src/modules/auth/auth.module.ts index bcb7cd27c6..f613211882 100644 --- a/packages/apps/reputation-oracle/server/src/modules/auth/auth.module.ts +++ b/packages/apps/reputation-oracle/server/src/modules/auth/auth.module.ts @@ -4,10 +4,8 @@ import { JwtModule } from '@nestjs/jwt'; import { AuthConfigService } from '@/config'; import { HCaptchaModule } from '@/integrations/hcaptcha'; import { EmailModule } from '@/modules/email'; -import { ExchangeModule } from '@/modules/exchange'; -import { ExchangeApiKeysModule } from '@/modules/exchange-api-keys'; -import { StakingModule } from '@/modules/staking'; import { UserModule } from '@/modules/user'; +import { Web3Module } from '@/modules/web3'; import { AuthController } from './auth.controller'; import { AuthService } from './auth.service'; @@ -27,10 +25,8 @@ import { TokenRepository } from './token.repository'; }, }), }), + Web3Module, HCaptchaModule, - ExchangeModule, - ExchangeApiKeysModule, - StakingModule, EmailModule, ], providers: [JwtHttpStrategy, AuthService, TokenRepository], diff --git a/packages/apps/reputation-oracle/server/src/modules/auth/auth.service.spec.ts b/packages/apps/reputation-oracle/server/src/modules/auth/auth.service.spec.ts index 3eebd54bb9..0de059e6bc 100644 --- a/packages/apps/reputation-oracle/server/src/modules/auth/auth.service.spec.ts +++ b/packages/apps/reputation-oracle/server/src/modules/auth/auth.service.spec.ts @@ -11,12 +11,10 @@ import { SignatureType, UserStatus, UserRole } from '@/common/enums'; import { AuthConfigService, NDAConfigService, - StakingConfigService, ServerConfigService, Web3ConfigService, } from '@/config'; import { EmailAction, EmailService } from '@/modules/email'; -import { StakingService } from '@/modules/staking'; import { SiteKeyRepository } from '@/modules/user'; import { UserEntity, UserRepository, UserService } from '@/modules/user'; import { generateOperator, generateWorkerUser } from '@/modules/user/fixtures'; @@ -43,12 +41,6 @@ const mockAuthConfigService: Omit = { forgotPasswordExpiresIn: 86400000, humanAppSecretKey: faker.string.alphanumeric({ length: 42 }), }; -const mockStakingConfigService: Omit = { - eligibilityEnabled: true, - minThreshold: 100, - asset: 'ETH', - timeoutMs: 2000, -}; const mockEmailService = createMock(); @@ -64,7 +56,6 @@ const mockSiteKeyRepository = createMock(); const mockTokenRepository = createMock(); const mockUserRepository = createMock(); const mockUserService = createMock(); -const mockStakingService = createMock(); describe('AuthService', () => { let service: AuthService; @@ -94,8 +85,6 @@ describe('AuthService', () => { { provide: UserRepository, useValue: mockUserRepository }, { provide: UserService, useValue: mockUserService }, { provide: Web3ConfigService, useValue: mockWeb3ConfigService }, - { provide: StakingService, useValue: mockStakingService }, - { provide: StakingConfigService, useValue: mockStakingConfigService }, ], }).compile(); @@ -635,7 +624,6 @@ describe('AuthService', () => { wallet_address: user.evmAddress, role: user.role, kyc_status: user.kyc?.status, - is_stake_eligible: true, nda_signed: user.ndaSignedUrl === mockNdaConfigService.latestNdaUrl, reputation_network: mockWeb3ConfigService.operatorAddress, qualifications: user.userQualifications @@ -645,11 +633,6 @@ describe('AuthService', () => { : [], }; - const spyOncheckStakeEligible = jest - // eslint-disable-next-line @typescript-eslint/no-explicit-any - .spyOn(service as any, 'checkStakeEligible') - .mockImplementation(); - spyOncheckStakeEligible.mockResolvedValueOnce(true); const spyOnGenerateTokens = jest .spyOn(service, 'generateTokens') .mockImplementation(); @@ -666,132 +649,10 @@ describe('AuthService', () => { expectedJwtPayload, ); - expect(spyOncheckStakeEligible).toHaveBeenCalledTimes(1); - - spyOncheckStakeEligible.mockRestore(); spyOnGenerateTokens.mockRestore(); }); }); - describe('checkStakeEligible', () => { - it('returns true when feature flag disabled', async () => { - const user = generateWorkerUser(); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (mockStakingConfigService as any).eligibilityEnabled = false; - - const result = await service['checkStakeEligible'](user); - - expect(result).toBe(true); - expect( - mockStakingService.getExchangeStakedBalance, - ).not.toHaveBeenCalled(); - expect(mockStakingService.getOnChainStakedBalance).not.toHaveBeenCalled(); - }); - - it('returns true when exchange balance meets threshold (no on-chain call)', async () => { - const user = generateWorkerUser(); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (mockStakingConfigService as any).eligibilityEnabled = true; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (mockStakingConfigService as any).minThreshold = 1000; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (mockStakingConfigService as any).asset = 'HMT'; - - mockStakingService.getExchangeStakedBalance.mockResolvedValueOnce(1500); - - const result = await service['checkStakeEligible'](user); - - expect(result).toBe(true); - expect(mockStakingService.getExchangeStakedBalance).toHaveBeenCalledWith( - user.id, - ); - expect(mockStakingService.getOnChainStakedBalance).not.toHaveBeenCalled(); - }); - - it('returns true when exchange balance below threshold but on-chain makes up the difference', async () => { - const user = generateWorkerUser({ - privateKey: generateEthWallet().privateKey, - }); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (mockStakingConfigService as any).eligibilityEnabled = true; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (mockStakingConfigService as any).minThreshold = 1000; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (mockStakingConfigService as any).asset = 'HMT'; - - mockStakingService.getExchangeStakedBalance.mockResolvedValueOnce(400); - mockStakingService.getOnChainStakedBalance.mockResolvedValueOnce(600); - - const result = await service['checkStakeEligible'](user); - - expect(result).toBe(true); - expect(mockStakingService.getExchangeStakedBalance).toHaveBeenCalledWith( - user.id, - ); - expect(mockStakingService.getOnChainStakedBalance).toHaveBeenCalledTimes( - 1, - ); - expect(mockStakingService.getOnChainStakedBalance).toHaveBeenCalledWith( - user.evmAddress, - ); - }); - - it('returns false when no exchange keys and on-chain stake below threshold', async () => { - const user = generateWorkerUser({ - privateKey: generateEthWallet().privateKey, - }); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (mockStakingConfigService as any).eligibilityEnabled = true; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (mockStakingConfigService as any).minThreshold = 1000; - - mockStakingService.getExchangeStakedBalance.mockResolvedValueOnce(0); - mockStakingService.getOnChainStakedBalance.mockResolvedValueOnce(500); - - const result = await service['checkStakeEligible'](user); - - expect(result).toBe(false); - expect(mockStakingService.getExchangeStakedBalance).toHaveBeenCalledWith( - user.id, - ); - expect(mockStakingService.getOnChainStakedBalance).toHaveBeenCalledTimes( - 1, - ); - }); - - it('continues on exchange error and returns based on on-chain stake', async () => { - const user = generateWorkerUser({ - privateKey: generateEthWallet().privateKey, - }); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (mockStakingConfigService as any).eligibilityEnabled = true; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (mockStakingConfigService as any).minThreshold = 1000; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (mockStakingConfigService as any).asset = 'HMT'; - - mockStakingService.getExchangeStakedBalance.mockRejectedValueOnce( - new Error('network'), - ); - mockStakingService.getOnChainStakedBalance.mockResolvedValueOnce(1200); - - const result = await service['checkStakeEligible'](user); - - expect(result).toBe(true); - expect(mockStakingService.getExchangeStakedBalance).toHaveBeenCalledWith( - user.id, - ); - expect(mockStakingService.getOnChainStakedBalance).toHaveBeenCalledTimes( - 1, - ); - }); - }); - describe('web3Auth', () => { it('should generate jwt payload for operator', async () => { const operator = generateOperator(); diff --git a/packages/apps/reputation-oracle/server/src/modules/auth/auth.service.ts b/packages/apps/reputation-oracle/server/src/modules/auth/auth.service.ts index e32d92f809..09fb00c925 100644 --- a/packages/apps/reputation-oracle/server/src/modules/auth/auth.service.ts +++ b/packages/apps/reputation-oracle/server/src/modules/auth/auth.service.ts @@ -7,12 +7,10 @@ import { AuthConfigService, NDAConfigService, ServerConfigService, - StakingConfigService, Web3ConfigService, } from '@/config'; import logger from '@/logger'; import { EmailAction, EmailService } from '@/modules/email'; -import { StakingService } from '@/modules/staking'; import { OperatorStatus, SiteKeyRepository, @@ -58,8 +56,6 @@ export class AuthService { private readonly userRepository: UserRepository, private readonly userService: UserService, private readonly web3ConfigService: Web3ConfigService, - private readonly stakingService: StakingService, - private readonly stakingConfigService: StakingConfigService, ) {} async signup(email: string, password: string): Promise { @@ -233,8 +229,6 @@ export class AuthService { hCaptchaSiteKey = hCaptchaSiteKeys[0].siteKey; } - const stakeEligible = await this.checkStakeEligible(userEntity); - const jwtPayload = { email: userEntity.email, status: userEntity.status, @@ -244,7 +238,6 @@ export class AuthService { kyc_status: userEntity.kyc?.status, nda_signed: userEntity.ndaSignedUrl === this.ndaConfigService.latestNdaUrl, - is_stake_eligible: stakeEligible, reputation_network: this.web3ConfigService.operatorAddress, qualifications: userEntity.userQualifications ? userEntity.userQualifications.map( @@ -257,44 +250,6 @@ export class AuthService { return this.generateTokens(userEntity.id, jwtPayload); } - private async checkStakeEligible( - userEntity: Web2UserEntity | UserEntity, - ): Promise { - if (!this.stakingConfigService.eligibilityEnabled) return true; - - let inspectedStakeAmount = 0; - - try { - const exchangeBalance = - await this.stakingService.getExchangeStakedBalance(userEntity.id); - inspectedStakeAmount += exchangeBalance; - } catch (err) { - this.logger.warn('Failed to query exchange balance; continuing', { - userId: userEntity.id, - error: err, - }); - } - - if ( - inspectedStakeAmount < this.stakingConfigService.minThreshold && - userEntity.evmAddress - ) { - try { - const onChainStake = await this.stakingService.getOnChainStakedBalance( - userEntity.evmAddress, - ); - inspectedStakeAmount += onChainStake; - } catch (err) { - this.logger.warn('Failed to query on-chain stake; continuing', { - userId: userEntity.id, - error: err, - }); - } - } - - return inspectedStakeAmount >= this.stakingConfigService.minThreshold; - } - async web3Auth(userEntity: OperatorUserEntity): Promise { /** * NOTE diff --git a/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-key.entity.ts b/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-key.entity.ts deleted file mode 100644 index 5a9252614e..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-key.entity.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Column, Entity, Index, ManyToOne } from 'typeorm'; - -import { DATABASE_SCHEMA_NAME } from '@/common/constants'; -import { BaseEntity } from '@/database'; -import type { UserEntity } from '@/modules/user'; - -@Entity({ schema: DATABASE_SCHEMA_NAME, name: 'exchange_api_keys' }) -@Index(['userId'], { unique: true }) -export class ExchangeApiKeyEntity extends BaseEntity { - @Column('varchar', { length: 20 }) - exchangeName: string; - - @Column('varchar', { length: 1000 }) - apiKey: string; - - @Column('varchar', { length: 10000 }) - secretKey: string; - - @ManyToOne('UserEntity', { persistence: false, onDelete: 'CASCADE' }) - user?: UserEntity; - - @Column() - userId: number; -} diff --git a/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.controller.ts b/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.controller.ts deleted file mode 100644 index df34ad7f2c..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.controller.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { - Body, - Controller, - Delete, - ForbiddenException, - Get, - HttpCode, - Param, - Post, - Req, - UseFilters, -} from '@nestjs/common'; -import { - ApiBearerAuth, - ApiBody, - ApiOperation, - ApiResponse, - ApiTags, -} from '@nestjs/swagger'; - -import type { RequestWithUser } from '@/common/types'; -import Environment from '@/utils/environment'; - -import { - EnrollExchangeApiKeysDto, - EnrollExchangeApiKeysResponseDto, - EnrolledApiKeyDto, - ExchangeNameParamDto, - SupportedExchangeDto, -} from './exchange-api-keys.dto'; -import { ExchangeApiKeysControllerErrorsFilter } from './exchange-api-keys.error-filter'; -import { ExchangeApiKeyNotFoundError } from './exchange-api-keys.errors'; -import { ExchangeApiKeysRepository } from './exchange-api-keys.repository'; -import { ExchangeApiKeysService } from './exchange-api-keys.service'; - -@ApiTags('Exchange API Keys') -@ApiBearerAuth() -@UseFilters(ExchangeApiKeysControllerErrorsFilter) -@Controller('exchange-api-keys') -export class ExchangeApiKeysController { - constructor( - private readonly exchangeApiKeysService: ExchangeApiKeysService, - private readonly exchangeApiKeysRepository: ExchangeApiKeysRepository, - ) {} - - @ApiOperation({ - summary: 'Retrieve enrolled exchange with api key', - description: 'Returns the enrolled api key for exchange w/o secret key', - }) - @ApiResponse({ - status: 200, - type: EnrolledApiKeyDto, - }) - @Get('/') - async retrieveEnrolledApiKeys( - @Req() request: RequestWithUser, - ): Promise { - const userId = request.user.id; - - const apiKey = await this.exchangeApiKeysService.retrieve(userId); - if (!apiKey) { - return null; - } - - return { - exchangeName: apiKey.exchangeName, - apiKey: apiKey.apiKey, - }; - } - - @ApiOperation({ - summary: 'Enroll API keys for exchange', - description: - 'Enrolls API keys for provided exchange. If keys already exist for exchange - updates them', - }) - @ApiResponse({ - status: 200, - description: 'Exchange API keys enrolled', - type: EnrollExchangeApiKeysResponseDto, - }) - @ApiBody({ type: EnrollExchangeApiKeysDto }) - @HttpCode(200) - @Post('/:exchange_name') - async enroll( - @Req() request: RequestWithUser, - @Param() params: ExchangeNameParamDto, - @Body() data: EnrollExchangeApiKeysDto, - ): Promise { - const key = await this.exchangeApiKeysService.enroll({ - userId: request.user.id, - exchangeName: params.exchangeName, - apiKey: data.apiKey, - secretKey: data.secretKey, - }); - - return { id: key.id }; - } - - @ApiOperation({ - summary: 'Delete API keys', - }) - @ApiResponse({ - status: 204, - description: 'Exchange API keys deleted', - }) - @HttpCode(204) - @Delete('/') - async delete(@Req() request: RequestWithUser): Promise { - await this.exchangeApiKeysRepository.deleteByUser(request.user.id); - } - - @ApiOperation({ - summary: 'Retreive API keys for exchange', - description: - 'This functionality is purely for dev solely and works only in non-production environments', - }) - @Get('/exchange') - async retrieve(@Req() request: RequestWithUser): Promise { - if (!Environment.isDevelopment()) { - throw new ForbiddenException(); - } - - const apiKey = await this.exchangeApiKeysService.retrieve(request.user.id); - if (!apiKey) { - throw new ExchangeApiKeyNotFoundError(request.user.id); - } - return apiKey; - } - - @ApiOperation({ summary: 'List supported exchanges' }) - @ApiResponse({ status: 200, type: SupportedExchangeDto, isArray: true }) - @Get('/supported') - async getSupportedExchanges(): Promise { - return this.exchangeApiKeysService.getSupportedExchanges(); - } -} diff --git a/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.dto.ts b/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.dto.ts deleted file mode 100644 index e9546e80d8..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.dto.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { IsEnum, IsNotEmpty, IsString, MaxLength } from 'class-validator'; - -import { SupportedExchange } from '@/common/constants'; - -export class EnrollExchangeApiKeysDto { - @ApiProperty({ name: 'api_key' }) - @IsString() - @IsNotEmpty() - @MaxLength(200) - apiKey: string; - - @ApiProperty({ name: 'secret_key' }) - @IsString() - @IsNotEmpty() - @MaxLength(5000) - secretKey: string; -} - -export class ExchangeNameParamDto { - @ApiProperty({ - name: 'exchange_name', - enum: SupportedExchange, - }) - @IsEnum(SupportedExchange) - exchangeName: SupportedExchange; -} - -export class EnrollExchangeApiKeysResponseDto { - @ApiProperty() - id: number; -} - -export class EnrolledApiKeyDto { - @ApiProperty({ name: 'exchange_name' }) - exchangeName: string; - - @ApiProperty({ name: 'api_key' }) - apiKey: string; -} - -export class SupportedExchangeDto { - @ApiProperty({ name: 'name' }) - name: string; - - @ApiProperty({ name: 'display_name' }) - displayName: string; -} diff --git a/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.error-filter.ts b/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.error-filter.ts deleted file mode 100644 index d4d629d673..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.error-filter.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { - ExceptionFilter, - Catch, - ArgumentsHost, - HttpStatus, -} from '@nestjs/common'; -import { Request, Response } from 'express'; - -import logger from '@/logger'; -import { UserNotFoundError } from '@/modules/user'; - -import { - ExchangeApiKeyNotFoundError, - IncompleteKeySuppliedError, - KeyAuthorizationError, -} from './exchange-api-keys.errors'; -import { ExchangeApiClientError } from '../exchange/errors'; - -@Catch( - UserNotFoundError, - IncompleteKeySuppliedError, - KeyAuthorizationError, - ExchangeApiKeyNotFoundError, -) -export class ExchangeApiKeysControllerErrorsFilter implements ExceptionFilter { - private readonly logger = logger.child({ - context: ExchangeApiKeysControllerErrorsFilter.name, - }); - - catch(exception: Error, host: ArgumentsHost) { - const ctx = host.switchToHttp(); - const response = ctx.getResponse(); - const request = ctx.getRequest(); - let status = HttpStatus.INTERNAL_SERVER_ERROR; - - if ( - exception instanceof UserNotFoundError || - exception instanceof IncompleteKeySuppliedError || - exception instanceof KeyAuthorizationError - ) { - status = HttpStatus.UNPROCESSABLE_ENTITY; - } else if (exception instanceof ExchangeApiClientError) { - status = HttpStatus.SERVICE_UNAVAILABLE; - } else if (exception instanceof ExchangeApiKeyNotFoundError) { - status = HttpStatus.NOT_FOUND; - } - - return response.status(status).json({ - message: exception.message, - timestamp: new Date().toISOString(), - path: request.url, - }); - } -} diff --git a/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.errors.ts b/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.errors.ts deleted file mode 100644 index b16190ddd2..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.errors.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { BaseError } from '@/common/errors/base'; - -export class ExchangeApiKeyNotFoundError extends BaseError { - constructor(readonly userId: number) { - super('Exchange API key not found'); - } -} - -export class IncompleteKeySuppliedError extends BaseError { - constructor(readonly exchangeName: string) { - super('Incomplete credentials supplied for exchange'); - } -} - -export class KeyAuthorizationError extends BaseError { - constructor(readonly exchangeName: string) { - super("Provided API key can't be authorized on exchange"); - } -} diff --git a/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.module.ts b/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.module.ts deleted file mode 100644 index 5d7a416588..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.module.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { EncryptionModule } from '@/modules/encryption'; -import { ExchangeModule } from '@/modules/exchange/exchange.module'; -import { UserModule } from '@/modules/user'; - -import { ExchangeApiKeysController } from './exchange-api-keys.controller'; -import { ExchangeApiKeysRepository } from './exchange-api-keys.repository'; -import { ExchangeApiKeysService } from './exchange-api-keys.service'; - -@Module({ - imports: [ExchangeModule, EncryptionModule, UserModule], - providers: [ExchangeApiKeysRepository, ExchangeApiKeysService], - controllers: [ExchangeApiKeysController], - exports: [ExchangeApiKeysRepository, ExchangeApiKeysService], -}) -export class ExchangeApiKeysModule {} diff --git a/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.repository.ts b/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.repository.ts deleted file mode 100644 index ea0d264915..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.repository.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { DataSource } from 'typeorm'; - -import { BaseRepository } from '@/database'; - -import { ExchangeApiKeyEntity } from './exchange-api-key.entity'; - -@Injectable() -export class ExchangeApiKeysRepository extends BaseRepository { - constructor(dataSource: DataSource) { - super(ExchangeApiKeyEntity, dataSource); - } - - async findOneByUserId(userId: number): Promise { - if (!userId) { - throw new Error('Invalid arguments'); - } - return this.findOne({ - where: { userId }, - }); - } - - async deleteByUser(userId: number): Promise { - if (!userId) { - throw new Error('userId is required'); - } - - await this.delete({ userId }); - } -} diff --git a/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.service.spec.ts b/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.service.spec.ts deleted file mode 100644 index 082d28dc67..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.service.spec.ts +++ /dev/null @@ -1,217 +0,0 @@ -import { createMock } from '@golevelup/ts-jest'; -import { Test, TestingModule } from '@nestjs/testing'; - -import { SUPPORTED_EXCHANGES_INFO } from '@/common/constants'; -import { EncryptionConfigService } from '@/config/encryption-config.service'; -import { AesEncryptionService } from '@/modules/encryption/aes-encryption.service'; -import { mockEncryptionConfigService } from '@/modules/encryption/fixtures'; -import { ExchangeClientFactory } from '@/modules/exchange/exchange-client.factory'; - -// eslint-disable-next-line import-x/order -import { ExchangeApiKeysService } from './exchange-api-keys.service'; -import { UserEntity, UserNotFoundError, UserRepository } from '@/modules/user'; - -import { ExchangeApiKeyEntity } from './exchange-api-key.entity'; -import { KeyAuthorizationError } from './exchange-api-keys.errors'; -import { ExchangeApiKeysRepository } from './exchange-api-keys.repository'; -import { - generateExchangeApiKey, - generateExchangeApiKeysData, -} from './fixtures'; -import { ExchangeClient } from '../exchange/types'; - -const mockUserRepository = createMock(); -const mockExchangeApiKeysRepository = createMock(); -const mockExchangeClient = createMock(); -const mockExchangeClientFactory = { - create: jest.fn().mockReturnValue(mockExchangeClient), -}; - -describe('ExchangeApiKeysService', () => { - let exchangeApiKeysService: ExchangeApiKeysService; - let aesEncryptionService: AesEncryptionService; - - beforeAll(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [ - ExchangeApiKeysService, - AesEncryptionService, - { provide: UserRepository, useValue: mockUserRepository }, - { - provide: ExchangeApiKeysRepository, - useValue: mockExchangeApiKeysRepository, - }, - { - provide: EncryptionConfigService, - useValue: mockEncryptionConfigService, - }, - { - provide: ExchangeClientFactory, - useValue: mockExchangeClientFactory, - }, - ], - }).compile(); - - exchangeApiKeysService = module.get( - ExchangeApiKeysService, - ); - aesEncryptionService = - module.get(AesEncryptionService); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - it('should be defined', () => { - expect(exchangeApiKeysService).toBeDefined(); - }); - - describe('enroll', () => { - it.each([ - Object.assign(generateExchangeApiKeysData(), { userId: '' }), - Object.assign(generateExchangeApiKeysData(), { apiKey: '' }), - Object.assign(generateExchangeApiKeysData(), { secretKey: '' }), - ])('should throw if required param is missing [%#]', async (input) => { - let thrownError; - try { - await exchangeApiKeysService.enroll(input); - } catch (error) { - thrownError = error; - } - - expect(thrownError.constructor).toBe(Error); - expect(thrownError.message).toBe('Invalid arguments'); - }); - - it('should throw if provided keys do not have required access', async () => { - mockExchangeApiKeysRepository.findOneByUserId.mockResolvedValueOnce(null); - mockExchangeClient.checkRequiredAccess.mockResolvedValueOnce(false); - - const input = generateExchangeApiKeysData(); - - let thrownError; - try { - await exchangeApiKeysService.enroll(input); - } catch (error) { - thrownError = error; - } - - expect(thrownError).toBeInstanceOf(KeyAuthorizationError); - expect(thrownError.exchangeName).toBe(input.exchangeName); - }); - - it('should overwrite existing keys if user already has active ones', async () => { - const input = generateExchangeApiKeysData(); - const existingKey = generateExchangeApiKey(); - mockExchangeApiKeysRepository.findOneByUserId.mockResolvedValueOnce( - existingKey, - ); - mockExchangeClient.checkRequiredAccess.mockResolvedValueOnce(true); - mockUserRepository.findOneById.mockResolvedValueOnce({ - id: input.userId, - } as UserEntity); - mockExchangeApiKeysRepository.updateOne.mockImplementation( - async (entity) => entity, - ); - - const updatedEntity = await exchangeApiKeysService.enroll(input); - - expect(mockExchangeApiKeysRepository.updateOne).toHaveBeenCalledWith( - existingKey, - ); - const [decryptedApiKey, decryptedSecretKey] = await Promise.all([ - aesEncryptionService.decrypt(updatedEntity.apiKey), - aesEncryptionService.decrypt(updatedEntity.secretKey), - ]); - expect(decryptedApiKey.toString()).toBe(input.apiKey); - expect(decryptedSecretKey.toString()).toBe(input.secretKey); - }); - - it('should throw if user not exists', async () => { - mockExchangeApiKeysRepository.findOneByUserId.mockResolvedValueOnce(null); - mockExchangeClient.checkRequiredAccess.mockResolvedValueOnce(true); - - mockUserRepository.findOneById.mockResolvedValueOnce(null); - - const input = generateExchangeApiKeysData(); - - let thrownError; - try { - await exchangeApiKeysService.enroll(input); - } catch (error) { - thrownError = error; - } - - expect(thrownError).toBeInstanceOf(UserNotFoundError); - }); - - it('should insert encrypted keys if data is valid', async () => { - mockExchangeApiKeysRepository.findOneByUserId.mockResolvedValueOnce(null); - mockExchangeClient.checkRequiredAccess.mockResolvedValueOnce(true); - mockUserRepository.findOneById.mockResolvedValueOnce({ - id: 1, - } as UserEntity); - - const input = generateExchangeApiKeysData(); - - const entity = await exchangeApiKeysService.enroll(input); - - expect(entity.userId).toBe(input.userId); - expect(entity.exchangeName).toBe(input.exchangeName); - expect(entity.apiKey).not.toBe(input.apiKey); - expect(entity.secretKey).not.toBe(input.secretKey); - - const [decryptedApiKey, decryptedSecretKey] = await Promise.all([ - aesEncryptionService.decrypt(entity.apiKey), - aesEncryptionService.decrypt(entity.secretKey), - ]); - - expect(decryptedApiKey.toString()).toBe(input.apiKey); - expect(decryptedSecretKey.toString()).toBe(input.secretKey); - }); - }); - - describe('retrieve', () => { - it('should return null if key not found for the user', async () => { - const { userId } = generateExchangeApiKeysData(); - mockExchangeApiKeysRepository.findOneByUserId.mockResolvedValueOnce(null); - - const result = await exchangeApiKeysService.retrieve(userId); - expect(result).toBeNull(); - }); - - it('should return decrypted keys', async () => { - const { userId, exchangeName, apiKey, secretKey } = - generateExchangeApiKeysData(); - - const [encryptedApiKey, encryptedSecretKey] = await Promise.all([ - aesEncryptionService.encrypt(Buffer.from(apiKey)), - aesEncryptionService.encrypt(Buffer.from(secretKey)), - ]); - mockExchangeApiKeysRepository.findOneByUserId.mockResolvedValueOnce({ - exchangeName, - apiKey: encryptedApiKey, - secretKey: encryptedSecretKey, - } as ExchangeApiKeyEntity); - - const result = await exchangeApiKeysService.retrieve(userId); - - expect(result).not.toBeNull(); - expect(result!.apiKey).toBe(apiKey); - expect(result!.secretKey).toBe(secretKey); - expect( - mockExchangeApiKeysRepository.findOneByUserId, - ).toHaveBeenCalledWith(userId); - }); - }); - - describe('getSupportedExchanges', () => { - it('returns a copy of supported exchanges constant', () => { - const result = exchangeApiKeysService.getSupportedExchanges(); - - expect(result).toEqual(SUPPORTED_EXCHANGES_INFO); - expect(result).not.toBe(SUPPORTED_EXCHANGES_INFO); - }); - }); -}); diff --git a/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.service.ts b/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.service.ts deleted file mode 100644 index c59b852fdc..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/exchange-api-keys.service.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -import { - SUPPORTED_EXCHANGES_INFO, - SupportedExchange, - type SupportedExchangeInfo, -} from '@/common/constants'; -import { AesEncryptionService } from '@/modules/encryption/aes-encryption.service'; -import { ExchangeClientFactory } from '@/modules/exchange/exchange-client.factory'; -import { UserNotFoundError, UserRepository } from '@/modules/user'; - -import { ExchangeApiKeyEntity } from './exchange-api-key.entity'; -import { KeyAuthorizationError } from './exchange-api-keys.errors'; -import { ExchangeApiKeysRepository } from './exchange-api-keys.repository'; - -@Injectable() -export class ExchangeApiKeysService { - constructor( - private readonly aesEncryptionService: AesEncryptionService, - private readonly exchangeApiKeysRepository: ExchangeApiKeysRepository, - private readonly exchangeClientFactory: ExchangeClientFactory, - private readonly userRepository: UserRepository, - ) {} - - async enroll(input: { - userId: number; - exchangeName: SupportedExchange; - apiKey: string; - secretKey: string; - }): Promise { - const { userId, exchangeName, apiKey, secretKey } = input; - - if (!userId || !apiKey || !secretKey) { - throw new Error('Invalid arguments'); - } - - const currentKeys = - await this.exchangeApiKeysRepository.findOneByUserId(userId); - - const client = await this.exchangeClientFactory.create(exchangeName, { - apiKey, - secretKey, - }); - const hasRequiredAccess = await client.checkRequiredAccess(); - if (!hasRequiredAccess) { - throw new KeyAuthorizationError(exchangeName); - } - - const user = await this.userRepository.findOneById(userId); - if (!user) { - throw new UserNotFoundError(userId); - } - - const [encryptedApiKey, encryptedSecretKey] = await Promise.all([ - this.aesEncryptionService.encrypt(Buffer.from(apiKey)), - this.aesEncryptionService.encrypt(Buffer.from(secretKey)), - ]); - if (currentKeys) { - currentKeys.exchangeName = exchangeName; - currentKeys.apiKey = encryptedApiKey; - currentKeys.secretKey = encryptedSecretKey; - - return this.exchangeApiKeysRepository.updateOne(currentKeys); - } - - const enrolledKey = new ExchangeApiKeyEntity(); - enrolledKey.userId = userId; - enrolledKey.exchangeName = exchangeName; - enrolledKey.apiKey = encryptedApiKey; - enrolledKey.secretKey = encryptedSecretKey; - await this.exchangeApiKeysRepository.createUnique(enrolledKey); - - return enrolledKey; - } - - async retrieve(userId: number): Promise<{ - exchangeName: string; - apiKey: string; - secretKey: string; - } | null> { - const entity = await this.exchangeApiKeysRepository.findOneByUserId(userId); - if (!entity) { - return null; - } - - const [decryptedApiKey, decryptedSecretKey] = await Promise.all([ - this.aesEncryptionService.decrypt(entity.apiKey), - this.aesEncryptionService.decrypt(entity.secretKey), - ]); - - return { - exchangeName: entity.exchangeName, - apiKey: decryptedApiKey.toString(), - secretKey: decryptedSecretKey.toString(), - }; - } - - getSupportedExchanges(): SupportedExchangeInfo[] { - return SUPPORTED_EXCHANGES_INFO.map((exchange) => ({ ...exchange })); - } -} diff --git a/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/fixtures/index.ts b/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/fixtures/index.ts deleted file mode 100644 index 8597aa47fc..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/fixtures/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { faker } from '@faker-js/faker'; - -import { generateExchangeName } from '@/modules/exchange/fixtures'; - -import { ExchangeApiKeyEntity } from '../exchange-api-key.entity'; - -export function generateExchangeApiKeysData() { - return { - userId: faker.number.int(), - exchangeName: generateExchangeName(), - apiKey: faker.string.sample(), - secretKey: faker.string.sample(), - }; -} - -export function generateExchangeApiKey(): ExchangeApiKeyEntity { - const entity = { - id: faker.number.int(), - ...generateExchangeApiKeysData(), - createdAt: faker.date.recent(), - updatedAt: new Date(), - }; - - return entity as ExchangeApiKeyEntity; -} diff --git a/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/index.ts b/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/index.ts deleted file mode 100644 index 2736f37d6b..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/exchange-api-keys/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -export { ExchangeApiKeysModule } from './exchange-api-keys.module'; -export { ExchangeApiKeyEntity } from './exchange-api-key.entity'; -export { ExchangeApiKeysRepository } from './exchange-api-keys.repository'; -export { ExchangeApiKeysService } from './exchange-api-keys.service'; -export { - ExchangeApiKeyNotFoundError, - KeyAuthorizationError, -} from './exchange-api-keys.errors'; diff --git a/packages/apps/reputation-oracle/server/src/modules/exchange/errors.ts b/packages/apps/reputation-oracle/server/src/modules/exchange/errors.ts deleted file mode 100644 index d529464ffa..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/exchange/errors.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { BaseError } from '@/common/errors/base'; - -export class ExchangeApiClientError extends BaseError {} - -export class ExchangeProviderResponseError extends BaseError { - constructor(exchange: string, status: number, detail?: string) { - const exchangeLabel = `${exchange.toUpperCase()} API`; - const fallback = status ? `status ${status}` : 'an error'; - super( - detail - ? `${exchangeLabel} error: ${detail}` - : `${exchangeLabel} responded with ${fallback}`, - ); - } -} diff --git a/packages/apps/reputation-oracle/server/src/modules/exchange/exchange-client.factory.ts b/packages/apps/reputation-oracle/server/src/modules/exchange/exchange-client.factory.ts deleted file mode 100644 index 035c2b0ef2..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/exchange/exchange-client.factory.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -import type { SupportedExchange } from '@/common/constants'; - -import { GateExchangeClient } from './gate-exchange.client'; -import { MexcExchangeClient } from './mexc-exchange.client'; -import type { - ExchangeClient, - ExchangeClientCredentials, - ExchangeClientOptions, -} from './types'; - -@Injectable() -export class ExchangeClientFactory { - async create( - exchange: SupportedExchange, - creds: ExchangeClientCredentials, - options?: ExchangeClientOptions, - ): Promise { - switch (exchange) { - case 'mexc': { - return new MexcExchangeClient(creds, options); - } - case 'gate': { - return new GateExchangeClient(creds, options); - } - default: - throw new Error(`Unsupported exchange: ${exchange}`); - } - } -} diff --git a/packages/apps/reputation-oracle/server/src/modules/exchange/exchange.module.ts b/packages/apps/reputation-oracle/server/src/modules/exchange/exchange.module.ts deleted file mode 100644 index ddc664fdc8..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/exchange/exchange.module.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { ExchangeClientFactory } from './exchange-client.factory'; - -@Module({ - providers: [ExchangeClientFactory], - exports: [ExchangeClientFactory], -}) -export class ExchangeModule {} diff --git a/packages/apps/reputation-oracle/server/src/modules/exchange/fixtures/exchange.ts b/packages/apps/reputation-oracle/server/src/modules/exchange/fixtures/exchange.ts deleted file mode 100644 index bca953a18b..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/exchange/fixtures/exchange.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { faker } from '@faker-js/faker'; - -import { SupportedExchange } from '@/common/constants'; - -export function generateGateAccountBalance(tokens: string[] = []) { - if (tokens.length === 0) { - throw new Error('At least one token must be specified'); - } - return tokens.map((token) => ({ - currency: token, - available: faker.finance.amount(), - locked: faker.finance.amount(), - freeze: faker.finance.amount(), - })); -} - -export function generateMexcAccountBalance(tokens: string[] = []) { - if (tokens.length === 0) { - throw new Error('At least one token must be specified'); - } - return { - balances: tokens.map((token) => ({ - asset: token, - free: faker.finance.amount(), - locked: faker.finance.amount(), - })), - }; -} - -export function generateExchangeName() { - return faker.helpers.enumValue(SupportedExchange); -} diff --git a/packages/apps/reputation-oracle/server/src/modules/exchange/fixtures/index.ts b/packages/apps/reputation-oracle/server/src/modules/exchange/fixtures/index.ts deleted file mode 100644 index 40165d35a9..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/exchange/fixtures/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './exchange'; diff --git a/packages/apps/reputation-oracle/server/src/modules/exchange/gate-exchange.client.spec.ts b/packages/apps/reputation-oracle/server/src/modules/exchange/gate-exchange.client.spec.ts deleted file mode 100644 index 9b7b60d150..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/exchange/gate-exchange.client.spec.ts +++ /dev/null @@ -1,224 +0,0 @@ -jest.mock('@/logger'); - -import crypto from 'crypto'; - -import { faker } from '@faker-js/faker'; -import nock from 'nock'; - -import { - ExchangeApiClientError, - ExchangeProviderResponseError, -} from './errors'; -import { generateGateAccountBalance } from './fixtures'; -import { - DEVELOP_GATE_API_BASE_URL, - GateExchangeClient, -} from './gate-exchange.client'; - -describe('GateExchangeClient', () => { - afterAll(() => { - nock.restore(); - }); - - afterEach(() => { - jest.resetAllMocks(); - nock.cleanAll(); - }); - - describe('signGateRequest', () => { - it('returns the expected signature for known input', () => { - const apiKey = faker.string.sample(); - const secretKey = faker.string.sample(); - const method = faker.string.sample(); - const path = faker.string.sample(); - const query = faker.string.sample(); - const body = faker.string.sample(); - const now = faker.number.int(); - - const client = new GateExchangeClient({ apiKey, secretKey }); - - jest.useFakeTimers({ now }); - const { signature, timestamp } = client['signGateRequest']( - method, - path, - query, - body, - ); - jest.useRealTimers(); - - const bodyHash = crypto - .createHash('sha512') - .update(body ?? '') - .digest('hex'); - const payload = [ - method, - path, - query, - bodyHash, - String(Math.floor(now / 1000)), - ].join('\n'); - const expectedSignature = crypto - .createHmac('sha512', secretKey) - .update(payload) - .digest('hex'); - - expect(timestamp).toBe(String(Math.floor(now / 1000))); - expect(signature).toBe(expectedSignature); - }); - }); - - describe('constructor', () => { - it('throws if credentials are missing', () => { - expect( - () => new GateExchangeClient({ apiKey: '', secretKey: '' }), - ).toThrow(ExchangeApiClientError); - }); - - it('sets fields correctly', () => { - const apiKey = faker.string.sample(); - const secretKey = faker.string.sample(); - const timeoutMs = faker.number.int(); - const client = new GateExchangeClient( - { apiKey, secretKey }, - { timeoutMs: timeoutMs }, - ); - expect(client).toBeDefined(); - expect(client['apiKey']).toBe(apiKey); - expect(client['secretKey']).toBe(secretKey); - expect(client['timeoutMs']).toBe(timeoutMs); - }); - }); - - describe('checkRequiredAccess', () => { - const path = '/spot/accounts'; - - it('returns true if fetch is ok', async () => { - const apiKey = faker.string.sample(); - const secretKey = faker.string.sample(); - const client = new GateExchangeClient({ apiKey, secretKey }); - const scope = nock(DEVELOP_GATE_API_BASE_URL) - .get(path) - .query(true) - .reply(200); - const result = await client.checkRequiredAccess(); - scope.done(); - expect(result).toBe(true); - }); - - it('returns false if fetch is not ok', async () => { - const apiKey = faker.string.sample(); - const secretKey = faker.string.sample(); - const client = new GateExchangeClient({ apiKey, secretKey }); - const scope = nock(DEVELOP_GATE_API_BASE_URL) - .get(path) - .query(true) - .reply(403); - const result = await client.checkRequiredAccess(); - scope.done(); - expect(result).toBe(false); - }); - - it('throws ExchangeApiClientError on fetch error', async () => { - const apiKey = faker.string.sample(); - const secretKey = faker.string.sample(); - const client = new GateExchangeClient({ apiKey, secretKey }); - const scope = nock(DEVELOP_GATE_API_BASE_URL) - .get(path) - .query(true) - .replyWithError('network error'); - let thrownError; - try { - await client.checkRequiredAccess(); - } catch (error) { - thrownError = error; - } - - scope.done(); - - expect(thrownError).toBeInstanceOf(ExchangeApiClientError); - expect((thrownError as Error).message).toBe( - 'Failed to make request for exchange', - ); - }); - }); - - describe('getAccountBalance', () => { - const path = '/spot/accounts'; - - it('throws ExchangeProviderResponseError with response body if fetch not ok', async () => { - const apiKey = faker.string.sample(); - const secretKey = faker.string.sample(); - const asset = faker.finance.currencyCode(); - const client = new GateExchangeClient({ apiKey, secretKey }); - const errorPayload = { message: 'forbidden' }; - const scope = nock(DEVELOP_GATE_API_BASE_URL) - .get(path) - .query(true) - .reply(403, errorPayload); - - const balancePromise = client.getAccountBalance(asset); - await expect(balancePromise).rejects.toThrow( - ExchangeProviderResponseError, - ); - - scope.done(); - }); - - it('returns 0 if asset not found', async () => { - const apiKey = faker.string.sample(); - const secretKey = faker.string.sample(); - const asset = faker.finance.currencyCode(); - const client = new GateExchangeClient({ apiKey, secretKey }); - const scope = nock(DEVELOP_GATE_API_BASE_URL) - .get(path) - .query(true) - .reply(200, generateGateAccountBalance(['OTHER'])); - const result = await client.getAccountBalance(asset); - scope.done(); - expect(result).toBe(0); - }); - - it('returns sum of available and locked if asset found', async () => { - const apiKey = faker.string.sample(); - const secretKey = faker.string.sample(); - const asset = faker.finance.currencyCode(); - const client = new GateExchangeClient({ apiKey, secretKey }); - const balanceFixture = generateGateAccountBalance([asset]); - const scope = nock(DEVELOP_GATE_API_BASE_URL) - .get(path) - .query(true) - .reply(200, balanceFixture); - - const result = await client.getAccountBalance(asset); - scope.done(); - expect(result).toBe( - parseFloat(balanceFixture[0].available) + - parseFloat(balanceFixture[0].locked), - ); - }); - - it('throws ExchangeApiClientError on fetch error', async () => { - const apiKey = faker.string.sample(); - const secretKey = faker.string.sample(); - const asset = faker.finance.currencyCode(); - const client = new GateExchangeClient({ apiKey, secretKey }); - const scope = nock(DEVELOP_GATE_API_BASE_URL) - .get(path) - .query(true) - .replyWithError('network error'); - let thrownError; - try { - await client.getAccountBalance(asset); - } catch (error) { - thrownError = error; - } - - scope.done(); - - expect(thrownError).toBeInstanceOf(ExchangeApiClientError); - expect((thrownError as Error).message).toBe( - 'Failed to make request for exchange', - ); - }); - }); -}); diff --git a/packages/apps/reputation-oracle/server/src/modules/exchange/gate-exchange.client.ts b/packages/apps/reputation-oracle/server/src/modules/exchange/gate-exchange.client.ts deleted file mode 100644 index ad50394dea..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/exchange/gate-exchange.client.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { createHash, createHmac } from 'node:crypto'; - -import { SupportedExchange } from '@/common/constants'; -import logger from '@/logger'; -import Environment from '@/utils/environment'; - -import { - ExchangeApiClientError, - ExchangeProviderResponseError, -} from './errors'; -import type { - ExchangeClient, - ExchangeClientCredentials, - ExchangeClientOptions, -} from './types'; -import { fetchWithHandling } from './utils'; - -export const GATE_API_BASE_URL = 'https://api.gateio.ws/api/v4'; -export const DEVELOP_GATE_API_BASE_URL = - 'https://api-testnet.gateapi.io/api/v4'; - -export class GateExchangeClient implements ExchangeClient { - readonly id = SupportedExchange.GATE; - private readonly apiKey: string; - private readonly secretKey: string; - private readonly timeoutMs?: number; - private readonly apiBaseUrl = Environment.isDevelopment() - ? DEVELOP_GATE_API_BASE_URL - : GATE_API_BASE_URL; - private readonly logger = logger.child({ - context: GateExchangeClient.name, - exchange: this.id, - }); - - constructor( - creds: ExchangeClientCredentials, - options?: ExchangeClientOptions, - ) { - if (!creds?.apiKey || !creds?.secretKey) { - throw new ExchangeApiClientError('Incomplete credentials for Gate'); - } - this.apiKey = creds.apiKey; - this.secretKey = creds.secretKey; - this.timeoutMs = options?.timeoutMs; - } - - async checkRequiredAccess(): Promise { - const method = 'GET'; - const path = '/spot/accounts'; - const query = ''; - const body = ''; - const { signature, timestamp } = this.signGateRequest( - method, - `/api/v4${path}`, - query, - body, - ); - - const res = await fetchWithHandling( - `${this.apiBaseUrl}${path}`, - { - KEY: this.apiKey, - SIGN: signature, - Timestamp: timestamp, - Accept: 'application/json', - }, - this.logger, - this.timeoutMs, - ); - - if (res.ok) return true; - return false; - } - - async getAccountBalance(asset: string): Promise { - const method = 'GET'; - const path = '/spot/accounts'; - const query = `currency=${encodeURIComponent(asset)}`; - const body = ''; - const requestPath = `/api/v4${path}`; - const { signature, timestamp } = this.signGateRequest( - method, - requestPath, - query, - body, - ); - const url = `${this.apiBaseUrl}${path}?${query}`; - - const res = await fetchWithHandling( - url, - { - KEY: this.apiKey, - SIGN: signature, - Timestamp: timestamp, - Accept: 'application/json', - }, - this.logger, - this.timeoutMs, - ); - - if (!res.ok) { - const errorBody = await res.json(); - throw new ExchangeProviderResponseError( - this.id, - res.status, - errorBody.message as string, - ); - } - - const data = (await res.json()) as Array<{ - currency: string; - available: string; - locked?: string; - freeze?: string; - }>; - - const normalize = (item: { - currency: string; - available: string; - locked?: string; - freeze?: string; - }) => { - const free = parseFloat(item.available) || 0; - const locked = parseFloat(item.locked ?? item.freeze ?? '0') || 0; - return free + locked; - }; - - const entry = data.find((d) => d.currency === asset); - return entry ? normalize(entry) : 0; - } - - private signGateRequest( - method: string, - path: string, - query: string, - body: string, - ): { signature: string; timestamp: string } { - const timestamp = String(Math.floor(Date.now() / 1000)); - const bodyHash = createHash('sha512') - .update(body ?? '') - .digest('hex'); - const payload = [method, path, query, bodyHash, timestamp].join('\n'); - const signature = createHmac('sha512', this.secretKey) - .update(payload) - .digest('hex'); - return { signature, timestamp }; - } -} diff --git a/packages/apps/reputation-oracle/server/src/modules/exchange/index.ts b/packages/apps/reputation-oracle/server/src/modules/exchange/index.ts deleted file mode 100644 index 3a0424a866..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/exchange/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { ExchangeModule } from './exchange.module'; -export { ExchangeClientFactory } from './exchange-client.factory'; -export * from './types'; diff --git a/packages/apps/reputation-oracle/server/src/modules/exchange/mexc-exchange.client.spec.ts b/packages/apps/reputation-oracle/server/src/modules/exchange/mexc-exchange.client.spec.ts deleted file mode 100644 index 5b91f88d3b..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/exchange/mexc-exchange.client.spec.ts +++ /dev/null @@ -1,196 +0,0 @@ -jest.mock('@/logger'); - -import { createHmac } from 'crypto'; - -import { faker } from '@faker-js/faker'; -import nock from 'nock'; - -import { - ExchangeApiClientError, - ExchangeProviderResponseError, -} from './errors'; -import { generateMexcAccountBalance } from './fixtures'; -import { MexcExchangeClient, MEXC_API_BASE_URL } from './mexc-exchange.client'; - -describe('MexcExchangeClient', () => { - afterAll(() => { - nock.restore(); - }); - - afterEach(() => { - jest.resetAllMocks(); - nock.cleanAll(); - }); - - describe('constructor', () => { - it('throws if credentials are missing', () => { - expect( - () => new MexcExchangeClient({ apiKey: '', secretKey: '' }), - ).toThrow(ExchangeApiClientError); - }); - - it('sets fields correctly', () => { - const apiKey = faker.string.sample(); - const secretKey = faker.string.sample(); - const timeoutMs = faker.number.int(); - - const client = new MexcExchangeClient( - { apiKey, secretKey }, - { timeoutMs: timeoutMs }, - ); - - expect(client).toBeDefined(); - expect(client['apiKey']).toBe(apiKey); - expect(client['secretKey']).toBe(secretKey); - expect(client['timeoutMs']).toBe(timeoutMs); - }); - }); - - describe('signQuery', () => { - it('getSignedQuery returns correct structure and signature', () => { - const apiKey = faker.string.sample(); - const secretKey = faker.string.sample(); - const client = new MexcExchangeClient({ apiKey, secretKey }); - - const now = Date.now(); - jest.useFakeTimers({ now }); - const result = client['getSignedQuery'](); - jest.useRealTimers(); - - expect(result).toHaveProperty('query'); - expect(result).toHaveProperty('signature'); - expect(result.query).toBe(`timestamp=${now}&recvWindow=5000`); - - const expectedSignature = createHmac('sha256', secretKey) - .update(result.query) - .digest('hex'); - expect(result.signature).toBe(expectedSignature); - }); - }); - - describe('checkRequiredAccess', () => { - const path = '/account'; - - it('returns true if fetch is ok', async () => { - const apiKey = faker.string.sample(); - const secretKey = faker.string.sample(); - const client = new MexcExchangeClient({ apiKey, secretKey }); - const scope = nock(MEXC_API_BASE_URL).get(path).query(true).reply(200); - const result = await client.checkRequiredAccess(); - scope.done(); - expect(result).toBe(true); - }); - - it('returns false if fetch is not ok', async () => { - const apiKey = faker.string.sample(); - const secretKey = faker.string.sample(); - const client = new MexcExchangeClient({ apiKey, secretKey }); - const scope = nock(MEXC_API_BASE_URL).get(path).query(true).reply(403); - const result = await client.checkRequiredAccess(); - scope.done(); - expect(result).toBe(false); - }); - - it('throws ExchangeApiClientError on fetch error', async () => { - const apiKey = faker.string.sample(); - const secretKey = faker.string.sample(); - const client = new MexcExchangeClient({ apiKey, secretKey }); - const scope = nock(MEXC_API_BASE_URL) - .get(path) - .query(true) - .replyWithError('network error'); - let thrownError: unknown; - try { - await client.checkRequiredAccess(); - } catch (error) { - thrownError = error; - } - - scope.done(); - - expect(thrownError).toBeInstanceOf(ExchangeApiClientError); - expect((thrownError as Error).message).toBe( - 'Failed to make request for exchange', - ); - }); - }); - - describe('getAccountBalance', () => { - const path = '/account'; - - it('throws ExchangeProviderResponseError with response detail if fetch not ok', async () => { - const apiKey = faker.string.sample(); - const secretKey = faker.string.sample(); - const asset = faker.finance.currencyCode(); - const client = new MexcExchangeClient({ apiKey, secretKey }); - const errorPayload = { msg: 'forbidden' }; - const scope = nock(MEXC_API_BASE_URL) - .get(path) - .query(true) - .reply(400, errorPayload); - - const balancePromise = client.getAccountBalance(asset); - await expect(balancePromise).rejects.toThrow( - ExchangeProviderResponseError, - ); - - scope.done(); - }); - - it('returns 0 if asset not found', async () => { - const apiKey = faker.string.sample(); - const secretKey = faker.string.sample(); - const asset = faker.finance.currencyCode(); - const client = new MexcExchangeClient({ apiKey, secretKey }); - const scope = nock(MEXC_API_BASE_URL) - .get(path) - .query(true) - .reply(200, generateMexcAccountBalance(['OTHER'])); - const result = await client.getAccountBalance(asset); - scope.done(); - expect(result).toBe(0); - }); - - it('returns sum of free and locked if asset found', async () => { - const apiKey = faker.string.sample(); - const secretKey = faker.string.sample(); - const asset = faker.finance.currencyCode(); - const client = new MexcExchangeClient({ apiKey, secretKey }); - const balanceFixture = generateMexcAccountBalance([asset]); - const scope = nock(MEXC_API_BASE_URL) - .get(path) - .query(true) - .reply(200, balanceFixture); - const result = await client.getAccountBalance(asset); - scope.done(); - expect(result).toBe( - parseFloat(balanceFixture.balances[0].free) + - parseFloat(balanceFixture.balances[0].locked), - ); - }); - - it('throws ExchangeApiClientError on fetch error', async () => { - const apiKey = faker.string.sample(); - const secretKey = faker.string.sample(); - const asset = faker.finance.currencyCode(); - const client = new MexcExchangeClient({ apiKey, secretKey }); - const scope = nock(MEXC_API_BASE_URL) - .get(path) - .query(true) - .replyWithError('network error'); - let thrownError: unknown; - try { - await client.getAccountBalance(asset); - } catch (error) { - thrownError = error; - } - - scope.done(); - - expect(thrownError).toBeInstanceOf(ExchangeApiClientError); - expect((thrownError as Error).message).toBe( - 'Failed to make request for exchange', - ); - }); - }); -}); diff --git a/packages/apps/reputation-oracle/server/src/modules/exchange/mexc-exchange.client.ts b/packages/apps/reputation-oracle/server/src/modules/exchange/mexc-exchange.client.ts deleted file mode 100644 index 9c3b0d4460..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/exchange/mexc-exchange.client.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { createHmac } from 'node:crypto'; - -import { SupportedExchange } from '@/common/constants'; -import logger from '@/logger'; - -import { - ExchangeApiClientError, - ExchangeProviderResponseError, -} from './errors'; -import type { - ExchangeClient, - ExchangeClientCredentials, - ExchangeClientOptions, -} from './types'; -import { fetchWithHandling } from './utils'; - -export const MEXC_API_BASE_URL = 'https://api.mexc.com/api/v3'; - -export class MexcExchangeClient implements ExchangeClient { - readonly id = SupportedExchange.MEXC; - private readonly apiKey: string; - private readonly secretKey: string; - private readonly timeoutMs?: number; - private readonly logger = logger.child({ - context: MexcExchangeClient.name, - exchange: this.id, - }); - readonly recvWindow = 5000; - - constructor( - creds: ExchangeClientCredentials, - options?: ExchangeClientOptions, - ) { - if (!creds?.apiKey || !creds?.secretKey) { - throw new ExchangeApiClientError('Incomplete credentials for MEXC'); - } - this.apiKey = creds.apiKey; - this.secretKey = creds.secretKey; - this.timeoutMs = options?.timeoutMs; - } - - private signQuery(query: string): string { - return createHmac('sha256', this.secretKey).update(query).digest('hex'); - } - - async checkRequiredAccess(): Promise { - const path = '/account'; - const { query, signature } = this.getSignedQuery(); - const url = `${MEXC_API_BASE_URL}${path}?${query}&signature=${signature}`; - - const res = await fetchWithHandling( - url, - { 'X-MEXC-APIKEY': this.apiKey }, - this.logger, - this.timeoutMs, - ); - if (res.ok) return true; - return false; - } - - async getAccountBalance(asset: string): Promise { - const path = '/account'; - const { query, signature } = this.getSignedQuery(); - const url = `${MEXC_API_BASE_URL}${path}?${query}&signature=${signature}`; - - const res = await fetchWithHandling( - url, - { 'X-MEXC-APIKEY': this.apiKey }, - this.logger, - this.timeoutMs, - ); - if (!res.ok) { - const errorBody = await res.json(); - throw new ExchangeProviderResponseError( - this.id, - res.status, - errorBody.msg as string, - ); - } - const data = (await res.json()) as { - balances?: Array<{ asset: string; free: string; locked: string }>; - }; - const balances = data.balances || []; - const entry = balances.find((b) => b.asset === asset); - if (!entry) return 0; - const total = - (parseFloat(entry.free || '0') || 0) + - (parseFloat(entry.locked || '0') || 0); - return total; - } - - private getSignedQuery(): { - query: string; - signature: string; - } { - const timestamp = Date.now(); - const query = `timestamp=${timestamp}&recvWindow=${this.recvWindow}`; - const signature = this.signQuery(query); - return { query, signature }; - } -} diff --git a/packages/apps/reputation-oracle/server/src/modules/exchange/types.ts b/packages/apps/reputation-oracle/server/src/modules/exchange/types.ts deleted file mode 100644 index 1fd5cfa68b..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/exchange/types.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { SupportedExchange } from '@/common/constants'; - -export interface ExchangeClientCredentials { - apiKey: string; - secretKey: string; -} - -export interface ExchangeClientOptions { - timeoutMs?: number; -} - -export interface ExchangeClient { - readonly id: SupportedExchange; - checkRequiredAccess(): Promise; - getAccountBalance(asset: string): Promise; -} diff --git a/packages/apps/reputation-oracle/server/src/modules/exchange/utils.ts b/packages/apps/reputation-oracle/server/src/modules/exchange/utils.ts deleted file mode 100644 index 8a2fd42fdc..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/exchange/utils.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { DEFAULT_TIMEOUT_MS } from '@/common/constants'; -import Logger from '@/logger'; - -import { ExchangeApiClientError } from './errors'; - -export async function fetchWithHandling( - url: string, - headers: HeadersInit, - logger: typeof Logger, - timeoutMs?: number, -): Promise { - try { - const res = await fetch(url, { - method: 'GET', - headers, - signal: AbortSignal.timeout(timeoutMs || DEFAULT_TIMEOUT_MS), - }); - return res; - } catch (error) { - const message: string = `Failed to make request for exchange`; - logger.error(message, { - url, - error, - }); - throw new ExchangeApiClientError(message); - } -} diff --git a/packages/apps/reputation-oracle/server/src/modules/staking/index.ts b/packages/apps/reputation-oracle/server/src/modules/staking/index.ts deleted file mode 100644 index fc1296365f..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/staking/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { StakingModule } from './staking.module'; -export { StakingService } from './staking.service'; -export type { StakeSummaryData } from './types'; diff --git a/packages/apps/reputation-oracle/server/src/modules/staking/staking.controller.ts b/packages/apps/reputation-oracle/server/src/modules/staking/staking.controller.ts deleted file mode 100644 index c4f711281d..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/staking/staking.controller.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Controller, Get, Req, UseFilters } from '@nestjs/common'; -import { - ApiBearerAuth, - ApiOperation, - ApiResponse, - ApiTags, -} from '@nestjs/swagger'; - -import { Public } from '@/common/decorators'; -import type { RequestWithUser } from '@/common/types'; - -import { StakeConfigResponseDto, StakeSummaryResponseDto } from './staking.dto'; -import { StakingControllerErrorsFilter } from './staking.error-filter'; -import { StakingService } from './staking.service'; - -@ApiTags('Staking') -@UseFilters(StakingControllerErrorsFilter) -@Controller('staking') -export class StakingController { - constructor(private readonly stakingService: StakingService) {} - - @ApiBearerAuth() - @ApiOperation({ summary: 'Retrieve aggregated staking info' }) - @ApiResponse({ status: 200, type: StakeSummaryResponseDto }) - @Get('/summary') - async getStakeSummary( - @Req() request: RequestWithUser, - ): Promise { - return this.stakingService.getStakeSummary(request.user.id); - } - - @Public() - @ApiOperation({ summary: 'Retrieve staking configuration' }) - @ApiResponse({ status: 200, type: StakeConfigResponseDto }) - @Get('/config') - async getStakeConfig(): Promise { - return this.stakingService.getStakeConfig(); - } -} diff --git a/packages/apps/reputation-oracle/server/src/modules/staking/staking.dto.ts b/packages/apps/reputation-oracle/server/src/modules/staking/staking.dto.ts deleted file mode 100644 index 114430a9da..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/staking/staking.dto.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; - -export class StakeSummaryResponseDto { - @ApiProperty({ name: 'exchange_stake' }) - exchangeStake: string; - - @ApiProperty({ name: 'on_chain_stake' }) - onChainStake: string; - - @ApiPropertyOptional({ name: 'exchange_error' }) - exchangeError?: string; - - @ApiPropertyOptional({ name: 'on_chain_error' }) - onChainError?: string; -} - -export class StakeConfigResponseDto { - @ApiProperty({ name: 'min_threshold' }) - minThreshold: string; - - @ApiProperty({ name: 'eligibility_enabled' }) - eligibilityEnabled: boolean; -} diff --git a/packages/apps/reputation-oracle/server/src/modules/staking/staking.error-filter.ts b/packages/apps/reputation-oracle/server/src/modules/staking/staking.error-filter.ts deleted file mode 100644 index af660d4d70..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/staking/staking.error-filter.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { - ArgumentsHost, - Catch, - ExceptionFilter, - HttpStatus, -} from '@nestjs/common'; -import { Request, Response } from 'express'; - -import logger from '@/logger'; -import { UserNotFoundError } from '@/modules/user'; - -@Catch(UserNotFoundError) -export class StakingControllerErrorsFilter implements ExceptionFilter { - private readonly logger = logger.child({ - context: StakingControllerErrorsFilter.name, - }); - - catch(exception: Error, host: ArgumentsHost) { - const ctx = host.switchToHttp(); - const response = ctx.getResponse(); - const request = ctx.getRequest(); - let status = HttpStatus.INTERNAL_SERVER_ERROR; - - if (exception instanceof UserNotFoundError) { - status = HttpStatus.UNPROCESSABLE_ENTITY; - } - - return response.status(status).json({ - message: exception.message, - timestamp: new Date().toISOString(), - path: request.url, - }); - } -} diff --git a/packages/apps/reputation-oracle/server/src/modules/staking/staking.module.ts b/packages/apps/reputation-oracle/server/src/modules/staking/staking.module.ts deleted file mode 100644 index a28244e510..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/staking/staking.module.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { ExchangeModule } from '@/modules/exchange/exchange.module'; -import { ExchangeApiKeysModule } from '@/modules/exchange-api-keys'; -import { UserModule } from '@/modules/user'; -import { Web3Module } from '@/modules/web3'; - -import { StakingController } from './staking.controller'; -import { StakingService } from './staking.service'; - -@Module({ - imports: [ExchangeApiKeysModule, ExchangeModule, UserModule, Web3Module], - providers: [StakingService], - controllers: [StakingController], - exports: [StakingService], -}) -export class StakingModule {} diff --git a/packages/apps/reputation-oracle/server/src/modules/staking/staking.service.spec.ts b/packages/apps/reputation-oracle/server/src/modules/staking/staking.service.spec.ts deleted file mode 100644 index 7657803a1a..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/staking/staking.service.spec.ts +++ /dev/null @@ -1,205 +0,0 @@ -jest.mock('@human-protocol/sdk'); - -import { faker } from '@faker-js/faker'; -import { createMock } from '@golevelup/ts-jest'; -import { StakingClient } from '@human-protocol/sdk'; -import { Test, TestingModule } from '@nestjs/testing'; -import { ethers } from 'ethers'; - -import { SupportedExchange } from '@/common/constants'; -import { StakingConfigService, Web3ConfigService } from '@/config'; -import { type ExchangeClient, ExchangeClientFactory } from '@/modules/exchange'; -import { ExchangeApiKeysService } from '@/modules/exchange-api-keys'; -import { UserEntity, UserNotFoundError, UserRepository } from '@/modules/user'; -import { WalletWithProvider, Web3Service } from '@/modules/web3'; -import { mockWeb3ConfigService } from '@/modules/web3/fixtures'; - -import { StakingService } from './staking.service'; - -const mockExchangeApiKeysService = createMock(); -const mockExchangeClientFactory = { - create: jest.fn(), -}; -const mockExchangeClient = createMock(); -const mockUserRepository = createMock(); -const mockWeb3Service = createMock(); -const mockStakingConfigService: Omit = { - eligibilityEnabled: true, - minThreshold: faker.number.int({ min: 1, max: 1000 }), - asset: 'HMT', - timeoutMs: faker.number.int({ min: 1000, max: 10000 }), -}; -const mockedStakingClient = jest.mocked(StakingClient); - -describe('StakingService', () => { - let stakingService: StakingService; - - beforeAll(async () => { - mockExchangeClientFactory.create.mockResolvedValue(mockExchangeClient); - mockExchangeClient.getAccountBalance.mockReset(); - mockWeb3Service.getSigner.mockReturnValue({ - provider: {}, - } as never); - - const module: TestingModule = await Test.createTestingModule({ - providers: [ - StakingService, - { - provide: ExchangeApiKeysService, - useValue: mockExchangeApiKeysService, - }, - { - provide: ExchangeClientFactory, - useValue: mockExchangeClientFactory, - }, - { provide: UserRepository, useValue: mockUserRepository }, - { provide: Web3Service, useValue: mockWeb3Service }, - { provide: StakingConfigService, useValue: mockStakingConfigService }, - { provide: Web3ConfigService, useValue: mockWeb3ConfigService }, - ], - }).compile(); - - stakingService = module.get(StakingService); - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - describe('getExchangeStakedBalance', () => { - const userId = faker.number.int(); - it('returns 0 when user has no exchange keys', async () => { - mockExchangeApiKeysService.retrieve.mockResolvedValueOnce(null); - - await expect( - stakingService.getExchangeStakedBalance(userId), - ).resolves.toBe(0); - }); - - it('returns balance fetched from exchange client', async () => { - const keys = { - exchangeName: SupportedExchange.GATE, - apiKey: faker.string.sample(), - secretKey: faker.string.sample(), - }; - const balance = faker.number.int(); - mockExchangeApiKeysService.retrieve.mockResolvedValueOnce(keys); - mockExchangeClient.getAccountBalance.mockResolvedValueOnce(balance); - - const result = await stakingService.getExchangeStakedBalance(userId); - expect(mockExchangeClientFactory.create).toHaveBeenCalledWith( - keys.exchangeName, - { - apiKey: keys.apiKey, - secretKey: keys.secretKey, - }, - { timeoutMs: mockStakingConfigService.timeoutMs }, - ); - expect(mockExchangeClient.getAccountBalance).toHaveBeenCalledWith( - mockStakingConfigService.asset, - ); - expect(result).toBe(balance); - }); - }); - - describe('getStakeSummary', () => { - const user = { - id: faker.number.int(), - evmAddress: faker.finance.ethereumAddress(), - }; - const onChainStake = faker.number.int(); - const exchangeStake = faker.number.int(); - let spyOnGetExchangeStakedBalance: jest.SpyInstance; - let spyOnGetOnChainStakedBalance: jest.SpyInstance; - - beforeAll(() => { - spyOnGetExchangeStakedBalance = jest - .spyOn(stakingService, 'getExchangeStakedBalance') - .mockImplementation(); - spyOnGetOnChainStakedBalance = jest - .spyOn(stakingService, 'getOnChainStakedBalance') - .mockImplementation(); - }); - - afterAll(() => { - spyOnGetExchangeStakedBalance.mockRestore(); - spyOnGetOnChainStakedBalance.mockRestore(); - }); - - it('throws when user is not found', async () => { - mockUserRepository.findOneById.mockResolvedValueOnce(null); - - await expect( - stakingService.getStakeSummary(user.id), - ).rejects.toBeInstanceOf(UserNotFoundError); - }); - - it('returns aggregated exchange and on-chain stakes', async () => { - mockUserRepository.findOneById.mockResolvedValueOnce(user as UserEntity); - spyOnGetExchangeStakedBalance.mockResolvedValueOnce(exchangeStake); - spyOnGetOnChainStakedBalance.mockResolvedValueOnce(onChainStake); - - const result = await stakingService.getStakeSummary(user.id); - - expect(spyOnGetExchangeStakedBalance).toHaveBeenCalledWith(user.id); - expect(spyOnGetOnChainStakedBalance).toHaveBeenCalledWith( - user.evmAddress, - ); - expect(result).toEqual({ - exchangeStake: exchangeStake.toString(), - onChainStake: onChainStake.toString(), - }); - }); - - it('skips on-chain lookup when user has no address', async () => { - mockUserRepository.findOneById.mockResolvedValueOnce({ - ...user, - evmAddress: null, - } as UserEntity); - spyOnGetExchangeStakedBalance.mockResolvedValueOnce(exchangeStake); - - const result = await stakingService.getStakeSummary(user.id); - - expect(spyOnGetOnChainStakedBalance).not.toHaveBeenCalled(); - expect(result).toEqual({ - exchangeStake: exchangeStake.toString(), - onChainStake: '0', - }); - }); - }); - - describe('getOnChainStakedBalance', () => { - it('returns total staked balance', async () => { - const address = faker.finance.ethereumAddress(); - const stakedAmount = ethers.toBigInt( - faker.number.int({ min: 500, max: 1000000 }), - ); - const mockProvider = {}; - mockWeb3Service.getSigner.mockReturnValueOnce({ - provider: mockProvider, - } as WalletWithProvider); - - const getStakerInfoMock = jest.fn().mockResolvedValue({ stakedAmount }); - mockedStakingClient.build.mockResolvedValueOnce({ - getStakerInfo: getStakerInfoMock, - } as unknown as StakingClient); - - const result = await stakingService.getOnChainStakedBalance(address); - - expect(mockedStakingClient.build).toHaveBeenCalledWith(mockProvider); - expect(getStakerInfoMock).toHaveBeenCalledWith(address); - expect(result).toBe(Number(ethers.formatEther(stakedAmount))); - }); - }); - - describe('getStakeConfig', () => { - it('returns current staking configuration', async () => { - const result = await stakingService.getStakeConfig(); - - expect(result).toEqual({ - minThreshold: mockStakingConfigService.minThreshold.toString(), - eligibilityEnabled: mockStakingConfigService.eligibilityEnabled, - }); - }); - }); -}); diff --git a/packages/apps/reputation-oracle/server/src/modules/staking/staking.service.ts b/packages/apps/reputation-oracle/server/src/modules/staking/staking.service.ts deleted file mode 100644 index 4103b91e91..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/staking/staking.service.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { StakingClient } from '@human-protocol/sdk'; -import { Injectable } from '@nestjs/common'; -import { ethers } from 'ethers'; - -import { SupportedExchange } from '@/common/constants'; -import { StakingConfigService, Web3ConfigService } from '@/config'; -import logger from '@/logger'; -import { ExchangeClientFactory } from '@/modules/exchange/exchange-client.factory'; -import { ExchangeApiKeysService } from '@/modules/exchange-api-keys'; -import { UserNotFoundError, UserRepository } from '@/modules/user'; -import { Web3Service } from '@/modules/web3'; -import { formatStake } from '@/utils/stake'; - -import { StakeConfigData, StakeSummaryData } from './types'; - -@Injectable() -export class StakingService { - private readonly logger = logger.child({ - context: StakingService.name, - }); - - constructor( - private readonly exchangeApiKeysService: ExchangeApiKeysService, - private readonly exchangeClientFactory: ExchangeClientFactory, - private readonly userRepository: UserRepository, - private readonly web3Service: Web3Service, - private readonly stakingConfigService: StakingConfigService, - private readonly web3ConfigService: Web3ConfigService, - ) {} - - async getExchangeStakedBalance(userId: number): Promise { - const apiKeys = await this.exchangeApiKeysService.retrieve(userId); - if (!apiKeys) { - return 0; - } - - const client = await this.exchangeClientFactory.create( - apiKeys.exchangeName as SupportedExchange, - { - apiKey: apiKeys.apiKey, - secretKey: apiKeys.secretKey, - }, - { timeoutMs: this.stakingConfigService.timeoutMs }, - ); - - return client.getAccountBalance(this.stakingConfigService.asset); - } - - async getOnChainStakedBalance(address: string): Promise { - const chainId = this.web3ConfigService.reputationNetworkChainId; - const provider = this.web3Service.getSigner(chainId).provider; - - const stakingClient = await StakingClient.build(provider); - const stakerInfo = await stakingClient.getStakerInfo(address); - - return Number(ethers.formatEther(stakerInfo.stakedAmount ?? 0n)); - } - - async getStakeSummary(userId: number): Promise { - const user = await this.userRepository.findOneById(userId); - if (!user) { - throw new UserNotFoundError(userId); - } - - const summary: StakeSummaryData = { - exchangeStake: '0', - onChainStake: '0', - }; - - try { - summary.exchangeStake = formatStake( - await this.getExchangeStakedBalance(userId), - ); - } catch (error) { - summary.exchangeError = error.message - ? error.message - : 'Unable to fetch exchange stake'; - this.logger.warn('Failed to retrieve exchange stake', { - userId, - error, - }); - } - - if (user.evmAddress) { - try { - summary.onChainStake = formatStake( - await this.getOnChainStakedBalance(user.evmAddress), - ); - } catch (error) { - summary.onChainError = error.message - ? error.message - : 'Unable to fetch on-chain stake'; - this.logger.warn('Failed to retrieve on-chain stake', { - userId, - evmAddress: user.evmAddress, - error, - }); - } - } - - return summary; - } - - async getStakeConfig(): Promise { - return { - minThreshold: this.stakingConfigService.minThreshold.toString(), - eligibilityEnabled: this.stakingConfigService.eligibilityEnabled, - }; - } -} diff --git a/packages/apps/reputation-oracle/server/src/modules/staking/types.ts b/packages/apps/reputation-oracle/server/src/modules/staking/types.ts deleted file mode 100644 index fcf1e16436..0000000000 --- a/packages/apps/reputation-oracle/server/src/modules/staking/types.ts +++ /dev/null @@ -1,11 +0,0 @@ -export type StakeSummaryData = { - exchangeStake: string; - onChainStake: string; - exchangeError?: string; - onChainError?: string; -}; - -export type StakeConfigData = { - minThreshold: string; - eligibilityEnabled: boolean; -}; diff --git a/packages/apps/reputation-oracle/server/src/utils/stake.ts b/packages/apps/reputation-oracle/server/src/utils/stake.ts deleted file mode 100644 index 49988b7c22..0000000000 --- a/packages/apps/reputation-oracle/server/src/utils/stake.ts +++ /dev/null @@ -1,6 +0,0 @@ -const stakeFormatter = new Intl.NumberFormat(undefined, { - maximumFractionDigits: 18, - notation: 'standard', - useGrouping: false, -}); -export const formatStake = (value: number) => stakeFormatter.format(value); From 899098e66b88c5a99a1401737b242969d153feb9 Mon Sep 17 00:00:00 2001 From: KirillKirill Date: Tue, 14 Jul 2026 14:31:53 +0300 Subject: [PATCH 06/33] [Human App Frontend] Bump MUI to v9 (#3961) --- docker-setup/Makefile | 4 +- packages/apps/human-app/frontend/package.json | 9 +- packages/apps/human-app/frontend/src/main.tsx | 2 - .../components/governance-banner.tsx | 72 +++--- .../choose-sign-up-account-type.tsx | 2 +- .../homepage/components/logo-section.tsx | 50 ++-- .../homepage/components/operator-sign-up.tsx | 60 ++--- .../modules/homepage/components/welcome.tsx | 10 +- .../homepage/components/worker-sign-up.tsx | 64 ++--- .../src/modules/homepage/views/home.page.tsx | 2 +- .../profile/components/operator-info.tsx | 6 +- .../profile/components/operator-stats.tsx | 8 +- .../modules/operator/profile/profile.page.tsx | 6 +- .../modules/signin/worker/sign-in-form.tsx | 15 +- .../components/add-keys/add-keys-form.tsx | 14 +- .../add-keys/edit-existing-keys-form.tsx | 7 +- .../add-keys/existing-keys-form.tsx | 14 +- .../components/add-keys/existing-keys.tsx | 26 +-- .../operator/components/add-stake/buttons.tsx | 8 +- .../components/add-stake/stake-form.tsx | 6 +- .../signup/operator/views/add-stake.page.tsx | 10 +- .../views/edit-existing-keys-success.page.tsx | 2 +- .../worker/views/sign-up-worker.page.tsx | 4 +- .../email-verification-success-message.tsx | 2 +- .../resend-verification-email-form.tsx | 8 +- .../components/user-stats-details.tsx | 31 ++- .../components/user-stats-drawer.tsx | 6 +- .../hcaptcha-labeling/enable-labeler.page.tsx | 13 +- .../hcaptcha-labeling.page.tsx | 15 +- .../components/oracles-table-item-mobile.tsx | 14 +- .../components/oracles-table.tsx | 2 +- .../jobs-discovery/jobs-discovery.page.tsx | 34 ++- .../available-jobs-filter-modal.tsx | 9 +- .../mobile/available-jobs-list-mobile.tsx | 29 ++- ...ailable-jobs-reward-amount-sort-mobile.tsx | 2 +- .../components/escrow-address-search-form.tsx | 16 +- .../jobs/components/report-abuse-modal.tsx | 32 +-- .../worker/jobs/components/reward-amount.tsx | 6 +- .../worker/jobs/components/sorting.tsx | 4 +- .../src/modules/worker/jobs/jobs.page.tsx | 6 +- .../components/desktop/status-chip.tsx | 2 +- .../mobile/my-jobs-expires-at-sort-mobile.tsx | 2 +- .../mobile/my-jobs-filter-modal.tsx | 9 +- .../components/mobile/my-jobs-list-mobile.tsx | 25 +- .../my-jobs-reward-amount-sort-mobile.tsx | 2 +- .../oracle-registration/registration-form.tsx | 2 +- .../oracle-registration/registration.page.tsx | 6 +- .../identity-verification-control.tsx | 2 +- .../profile/components/modal-states.tsx | 41 ++-- .../profile/components/profile-data.tsx | 5 +- .../components/wallet-connect-done.tsx | 56 ++--- .../worker/profile/views/profile.page.tsx | 2 +- .../reset-password-success.page.tsx | 2 +- .../reset-password/reset-password.page.tsx | 2 +- .../send-reset-link-success.page.tsx | 18 +- .../send-reset-link/send-reset-link.page.tsx | 2 +- .../frontend/src/router/components/footer.tsx | 94 ++++---- .../protected/bottom-menu-items-list.tsx | 9 +- .../layout/protected/drawer-navigation.tsx | 7 +- .../components/layout/protected/layout.tsx | 41 ++-- .../components/layout/protected/navbar.tsx | 8 +- .../layout/protected/page-header.tsx | 76 +++--- .../layout/protected/top-menu-items-list.tsx | 30 +-- .../components/layout/unprotected/layout.tsx | 18 +- .../components/layout/unprotected/navbar.tsx | 2 +- .../shared/components/data-entry/checkbox.tsx | 2 +- .../shared/components/data-entry/input.tsx | 23 +- .../data-entry/password/password.tsx | 50 ++-- .../components/hcaptcha/h-captcha-form.tsx | 2 +- .../src/shared/components/ui/chip.tsx | 6 +- .../components/ui/empty-placeholder.tsx | 2 +- .../components/ui/modal/global-modal.tsx | 12 +- .../shared/components/ui/optional-text.tsx | 2 +- .../components/ui/page-card/page-card.tsx | 40 ++-- .../ui/profile/profile-list-item.tsx | 17 +- .../shared/components/ui/success-label.tsx | 2 +- .../src/shared/components/ui/table-button.tsx | 6 +- .../components/ui/table/table-header-cell.tsx | 2 +- .../ui/table/table-header-menu/filtering.tsx | 16 +- .../ui/table/table-header-menu/sorting.tsx | 14 +- .../components/ui/text-header-with-icon.tsx | 2 +- .../frontend/src/shared/styles/dark-theme.ts | 1 - .../frontend/src/shared/styles/theme.ts | 1 - .../frontend/src/shared/styles/typography.ts | 1 + .../apps/human-app/frontend/tsconfig.json | 1 - yarn.lock | 219 +++++++++++++++--- 86 files changed, 848 insertions(+), 666 deletions(-) diff --git a/docker-setup/Makefile b/docker-setup/Makefile index 724723d377..39d57fd2e6 100644 --- a/docker-setup/Makefile +++ b/docker-setup/Makefile @@ -16,15 +16,15 @@ infra-up: check-env-file infra-stop: @docker compose --env-file .env.compose.local stop postgres redis minio minio-client +# TODO: Revisit compose-native parallel builds once Docker Compose v5 parallel limits are reliable again. build-services: check-env-file - @# TODO: Revisit compose-native parallel builds once Docker Compose v5 parallel limits are reliable again. @docker compose --env-file .env.compose.local config --services | \ xargs -n $(DOCKER_PARALLEL) docker compose --env-file .env.compose.local build @docker compose --env-file .env.compose.local up --no-start +# TODO: Revisit compose-native parallel builds once Docker Compose v5 parallel limits are reliable again. services-up: check-env-file @service_names="$(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS))"; \ - @# TODO: Revisit compose-native parallel builds once Docker Compose v5 parallel limits are reliable again. if [ -n "$$service_names" ]; then \ printf '%s\n' $$service_names | xargs -n $(DOCKER_PARALLEL) docker compose --env-file .env.compose.local up -d; \ else \ diff --git a/packages/apps/human-app/frontend/package.json b/packages/apps/human-app/frontend/package.json index a9fb3a8fd3..f3c078cde3 100644 --- a/packages/apps/human-app/frontend/package.json +++ b/packages/apps/human-app/frontend/package.json @@ -25,9 +25,8 @@ "@hcaptcha/react-hcaptcha": "^1.14.0", "@hookform/resolvers": "^5.1.0", "@human-protocol/sdk": "workspace:*", - "@mui/icons-material": "^7.3.8", - "@mui/material": "^5.16.7", - "@mui/system": "^9.0.1", + "@mui/icons-material": "^9.2.0", + "@mui/material": "^9.2.0", "@mui/x-date-pickers": "^9.2.0", "@reown/appkit": "^1.8.20", "@reown/appkit-adapter-wagmi": "^1.8.20", @@ -40,7 +39,6 @@ "jwt-decode": "^4.0.0", "lodash": "^4.18.1", "material-react-table": "3.0.1", - "mui-image": "^1.0.7", "notistack": "^3.0.1", "prop-types": "^15.8.1", "query-string": "^9.0.0", @@ -63,7 +61,6 @@ "@tanstack/eslint-plugin-query": "^5.60.1", "@tanstack/react-query-devtools": "^5.59.16", "@types/lodash": "^4.17.24", - "@types/mui-image": "^1.0.5", "@types/node": "^22.10.5", "@types/prop-types": "^15", "@types/react": "^19.2.15", @@ -80,7 +77,7 @@ "husky": "^9.1.6", "jsdom": "^29.1.1", "prettier": "^3.8.1", - "typescript": "^5.6.3", + "typescript": "^6.0.2", "typescript-eslint": "^8.57.0", "vite": "^6.2.4", "vitest": "^4.0.18" diff --git a/packages/apps/human-app/frontend/src/main.tsx b/packages/apps/human-app/frontend/src/main.tsx index ccf792a2b6..b50351ca33 100644 --- a/packages/apps/human-app/frontend/src/main.tsx +++ b/packages/apps/human-app/frontend/src/main.tsx @@ -7,12 +7,10 @@ import CssBaseline from '@mui/material/CssBaseline'; import { BrowserRouter } from 'react-router-dom'; import { AuthProvider } from '@/modules/auth/context/auth-context'; import { Router } from '@/router/router'; -import '@fontsource/inter'; import '@fontsource/inter/400.css'; import '@fontsource/inter/500.css'; import '@fontsource/inter/600.css'; import '@fontsource/inter/800.css'; -import '@fontsource/roboto'; import '@fontsource/roboto/400.css'; import '@fontsource/roboto/500.css'; import { WalletConnectProvider } from '@/shared/contexts/wallet-connect'; diff --git a/packages/apps/human-app/frontend/src/modules/governance-banner/components/governance-banner.tsx b/packages/apps/human-app/frontend/src/modules/governance-banner/components/governance-banner.tsx index a1096e1d3d..a72404c85f 100644 --- a/packages/apps/human-app/frontend/src/modules/governance-banner/components/governance-banner.tsx +++ b/packages/apps/human-app/frontend/src/modules/governance-banner/components/governance-banner.tsx @@ -17,6 +17,7 @@ function getProposalStatus(proposal: ProposalResponse): ProposalStatus { if (voteStart <= now && now < voteEnd) return 'active'; return 'pending'; } + export function GovernanceBanner() { const { t } = useTranslation(); const { data: proposal, isLoading, isError } = useProposalQuery(); @@ -53,45 +54,49 @@ export function GovernanceBanner() { return ( {/* Left side: Countdown & "X votes" */} - + - + {status === 'pending' ? t('governance.timeToStart', 'Voting starts in') : t('governance.timeToReveal', 'Time to reveal vote')} : - + {timeRemaining} {status === 'active' && ( {totalVotes} {t('governance.votes', 'votes')} @@ -100,19 +105,24 @@ export function GovernanceBanner() { {/* Right side: "More details" link */} {t('governance.moreDetails', 'More details')} → diff --git a/packages/apps/human-app/frontend/src/modules/homepage/components/choose-sign-up-account-type.tsx b/packages/apps/human-app/frontend/src/modules/homepage/components/choose-sign-up-account-type.tsx index a0c2415e16..bb7ebfe479 100644 --- a/packages/apps/human-app/frontend/src/modules/homepage/components/choose-sign-up-account-type.tsx +++ b/packages/apps/human-app/frontend/src/modules/homepage/components/choose-sign-up-account-type.tsx @@ -27,7 +27,7 @@ export function ChooseSignUpAccountType() { title={{t('homepage.welcome')} 👋} > - + {t('homepage.howWillUse')} diff --git a/packages/apps/human-app/frontend/src/modules/homepage/components/logo-section.tsx b/packages/apps/human-app/frontend/src/modules/homepage/components/logo-section.tsx index 6116bb99a3..d8666f3fac 100644 --- a/packages/apps/human-app/frontend/src/modules/homepage/components/logo-section.tsx +++ b/packages/apps/human-app/frontend/src/modules/homepage/components/logo-section.tsx @@ -15,55 +15,65 @@ export function LogoSection() { const isMobile = useIsMobile('lg'); return ( - + {isMobile ? ( ) : ( - + - + - + )} {logoTextSplit[0]} - + {logoTextSplit[1]} {t('homepage.completeJobs')} diff --git a/packages/apps/human-app/frontend/src/modules/homepage/components/operator-sign-up.tsx b/packages/apps/human-app/frontend/src/modules/homepage/components/operator-sign-up.tsx index 7ec945c879..488b5d88d5 100644 --- a/packages/apps/human-app/frontend/src/modules/homepage/components/operator-sign-up.tsx +++ b/packages/apps/human-app/frontend/src/modules/homepage/components/operator-sign-up.tsx @@ -1,35 +1,38 @@ -import { Grid, Typography, List, ListItemText, Button } from '@mui/material'; +import { + Grid, + Typography, + List, + ListItemText, + Button, + Stack, +} from '@mui/material'; import { useTranslation } from 'react-i18next'; import { Link } from 'react-router-dom'; import { routerPaths } from '@/router/router-paths'; import { useColorMode } from '@/shared/contexts/color-mode'; -import { useIsMobile } from '@/shared/hooks/use-is-mobile'; import { onlyDarkModeColor } from '@/shared/styles/dark-color-palette'; export function OperatorSignUp() { const { colorPalette, isDarkMode } = useColorMode(); const { t } = useTranslation(); - const isMobile = useIsMobile('lg'); return ( -
+ {t('homepage.joinAsOperator')} @@ -37,45 +40,48 @@ export function OperatorSignUp() { sx={{ listStyleType: 'disc', listStylePosition: 'inside', - paddingLeft: '0.5rem', + pl: 1, }} > -
+ diff --git a/packages/apps/human-app/frontend/src/modules/homepage/components/welcome.tsx b/packages/apps/human-app/frontend/src/modules/homepage/components/welcome.tsx index 2737034284..c6ba4099bb 100644 --- a/packages/apps/human-app/frontend/src/modules/homepage/components/welcome.tsx +++ b/packages/apps/human-app/frontend/src/modules/homepage/components/welcome.tsx @@ -1,6 +1,5 @@ import { Grid } from '@mui/material'; import { useEffect } from 'react'; -import { useIsMobile } from '@/shared/hooks/use-is-mobile'; import { useColorMode } from '@/shared/contexts/color-mode'; import { useBackgroundContext } from '@/shared/contexts/background'; import { SignInSection } from './sign-in-section'; @@ -9,7 +8,6 @@ import { LogoSection } from './logo-section'; export function Welcome() { const { isDarkMode } = useColorMode(); const { setWhiteBackground } = useBackgroundContext(); - const isMobile = useIsMobile('lg'); useEffect(() => { if (!isDarkMode) { @@ -20,13 +18,13 @@ export function Welcome() { return ( - + - + diff --git a/packages/apps/human-app/frontend/src/modules/homepage/components/worker-sign-up.tsx b/packages/apps/human-app/frontend/src/modules/homepage/components/worker-sign-up.tsx index 8ec2dcab12..7fe567bce4 100644 --- a/packages/apps/human-app/frontend/src/modules/homepage/components/worker-sign-up.tsx +++ b/packages/apps/human-app/frontend/src/modules/homepage/components/worker-sign-up.tsx @@ -1,24 +1,23 @@ -import { Grid, Typography, List, ListItemText, Button } from '@mui/material'; +import { + Grid, + Typography, + List, + ListItemText, + Button, + Stack, +} from '@mui/material'; import { useTranslation } from 'react-i18next'; import { Link } from 'react-router-dom'; import { routerPaths } from '@/router/router-paths'; import { useColorMode } from '@/shared/contexts/color-mode'; -import { useIsMobile } from '@/shared/hooks/use-is-mobile'; import { onlyDarkModeColor } from '@/shared/styles/dark-color-palette'; export function WorkerSignUp() { const { colorPalette, isDarkMode } = useColorMode(); const { t } = useTranslation(); - const isMobile = useIsMobile('lg'); return ( - + -
+ {t('homepage.iWantToEarn')} @@ -42,45 +41,48 @@ export function WorkerSignUp() { sx={{ listStyleType: 'disc', listStylePosition: 'inside', - paddingLeft: '0.5rem', + pl: '0.5rem', }} > -
+ diff --git a/packages/apps/human-app/frontend/src/modules/homepage/views/home.page.tsx b/packages/apps/human-app/frontend/src/modules/homepage/views/home.page.tsx index 7176f2fa77..35ba3e9221 100644 --- a/packages/apps/human-app/frontend/src/modules/homepage/views/home.page.tsx +++ b/packages/apps/human-app/frontend/src/modules/homepage/views/home.page.tsx @@ -34,7 +34,7 @@ export function HomePage() { })(); return ( - + {t('operator.profile.about.header')} - + ) { - const isMobile = useIsMobile('lg'); const { colorPalette } = useColorMode(); const { t } = useTranslation(); @@ -22,21 +20,21 @@ export function OperatorStats({ width: '100%', display: 'flex', flexDirection: 'column', - padding: isMobile ? '20px' : '40px', + padding: { xs: 2.5, md: 5 }, borderRadius: '20px', }} > {t('operator.profile.statistics.header')} - + - + - + diff --git a/packages/apps/human-app/frontend/src/modules/signin/worker/sign-in-form.tsx b/packages/apps/human-app/frontend/src/modules/signin/worker/sign-in-form.tsx index 5aeca3562a..f08174d2cd 100644 --- a/packages/apps/human-app/frontend/src/modules/signin/worker/sign-in-form.tsx +++ b/packages/apps/human-app/frontend/src/modules/signin/worker/sign-in-form.tsx @@ -1,5 +1,5 @@ import { FormProvider, useForm } from 'react-hook-form'; -import { Box, Grid, Typography } from '@mui/material'; +import { Box, Grid, Link as MuiLink, Typography } from '@mui/material'; import { zodResolver } from '@hookform/resolvers/zod'; import { useTranslation } from 'react-i18next'; import { Link } from 'react-router-dom'; @@ -44,7 +44,7 @@ export function SignInForm({ return (
- + - + - {t('worker.signInForm.forgotPassword')} - + diff --git a/packages/apps/human-app/frontend/src/modules/signup/operator/components/add-keys/add-keys-form.tsx b/packages/apps/human-app/frontend/src/modules/signup/operator/components/add-keys/add-keys-form.tsx index 84491fee32..fd45b334c5 100644 --- a/packages/apps/human-app/frontend/src/modules/signup/operator/components/add-keys/add-keys-form.tsx +++ b/packages/apps/human-app/frontend/src/modules/signup/operator/components/add-keys/add-keys-form.tsx @@ -1,4 +1,4 @@ -import { Grid } from '@mui/material'; +import { Grid, Stack } from '@mui/material'; import { t } from 'i18next'; import { Link } from 'react-router-dom'; import { routerPaths } from '@/router/router-paths'; @@ -27,13 +27,11 @@ export function AddKeysForm({ }); return ( - -
+ {hasSomeNotEmptyKeys ? : null} @@ -47,7 +45,7 @@ export function AddKeysForm({ {t('operator.addKeysPage.skipBtn')} ) : null} -
+
); } diff --git a/packages/apps/human-app/frontend/src/modules/signup/operator/components/add-keys/edit-existing-keys-form.tsx b/packages/apps/human-app/frontend/src/modules/signup/operator/components/add-keys/edit-existing-keys-form.tsx index 7ef7b929f3..20914684fd 100644 --- a/packages/apps/human-app/frontend/src/modules/signup/operator/components/add-keys/edit-existing-keys-form.tsx +++ b/packages/apps/human-app/frontend/src/modules/signup/operator/components/add-keys/edit-existing-keys-form.tsx @@ -107,9 +107,9 @@ export function EditExistingKeysForm({ {noChangesError ? (
{noChangesError} @@ -117,7 +117,10 @@ export function EditExistingKeysForm({ ) : null}
diff --git a/packages/apps/human-app/frontend/src/modules/signup/operator/components/add-keys/existing-keys-form.tsx b/packages/apps/human-app/frontend/src/modules/signup/operator/components/add-keys/existing-keys-form.tsx index d7b0687727..b78d59326b 100644 --- a/packages/apps/human-app/frontend/src/modules/signup/operator/components/add-keys/existing-keys-form.tsx +++ b/packages/apps/human-app/frontend/src/modules/signup/operator/components/add-keys/existing-keys-form.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { Grid } from '@mui/material'; +import { Grid, Stack } from '@mui/material'; import { zodResolver } from '@hookform/resolvers/zod'; import { FormProvider, useForm } from 'react-hook-form'; import type { GetEthKVStoreValuesSuccessResponse } from '@/modules/operator/hooks/use-get-keys'; @@ -31,13 +31,11 @@ export function ExistingKeysForm({ useResetMutationErrors(existingKeysMethods.watch, existingKeysMutation.reset); return ( - -
+ @@ -66,7 +64,7 @@ export function ExistingKeysForm({ )} -
+
); } diff --git a/packages/apps/human-app/frontend/src/modules/signup/operator/components/add-keys/existing-keys.tsx b/packages/apps/human-app/frontend/src/modules/signup/operator/components/add-keys/existing-keys.tsx index 1eb854a9fc..272bdb3083 100644 --- a/packages/apps/human-app/frontend/src/modules/signup/operator/components/add-keys/existing-keys.tsx +++ b/packages/apps/human-app/frontend/src/modules/signup/operator/components/add-keys/existing-keys.tsx @@ -18,7 +18,7 @@ const existingKeysConfig: Record< (values: GetEthKVStoreValuesSuccessResponse) => React.ReactElement > = { [EthKVStoreKeys.Fee]: ({ fee }) => ( - + {t('operator.addKeysPage.existingKeys.fee')} @@ -30,38 +30,38 @@ const existingKeysConfig: Record< ), [EthKVStoreKeys.PublicKey]: ({ public_key }) => ( - - + + {t('operator.addKeysPage.existingKeys.publicKey')} - + ), [EthKVStoreKeys.Url]: ({ url }) => ( - - + + {t('operator.addKeysPage.existingKeys.url')} - + ), [EthKVStoreKeys.WebhookUrl]: ({ webhook_url }) => ( - + {t('operator.addKeysPage.existingKeys.webhookUrl')} - + ), [EthKVStoreKeys.Role]: ({ role }) => ( - + {t('operator.addKeysPage.existingKeys.role')}
{role ? : }
@@ -69,7 +69,7 @@ const existingKeysConfig: Record< ), [EthKVStoreKeys.JobTypes]: ({ job_types }) => ( - + {t('operator.addKeysPage.existingKeys.jobType')}
{job_types ? : }
@@ -94,7 +94,7 @@ export function ExistingKeys({ ); return ( - + {t('operator.addKeysPage.existingKeys.title')} @@ -111,7 +111,7 @@ export function ExistingKeys({ startIcon={} variant="contained" > - + {t('operator.addKeysPage.existingKeys.editBtn')} diff --git a/packages/apps/human-app/frontend/src/modules/signup/operator/components/add-stake/buttons.tsx b/packages/apps/human-app/frontend/src/modules/signup/operator/components/add-stake/buttons.tsx index b3a4b84a83..4a677bdaf8 100644 --- a/packages/apps/human-app/frontend/src/modules/signup/operator/components/add-stake/buttons.tsx +++ b/packages/apps/human-app/frontend/src/modules/signup/operator/components/add-stake/buttons.tsx @@ -16,9 +16,9 @@ export function Buttons({ return ( diff --git a/packages/apps/human-app/frontend/src/modules/worker/hcaptcha-labeling/hcaptcha-labeling.page.tsx b/packages/apps/human-app/frontend/src/modules/worker/hcaptcha-labeling/hcaptcha-labeling.page.tsx index 3efadc29da..232f127f4d 100644 --- a/packages/apps/human-app/frontend/src/modules/worker/hcaptcha-labeling/hcaptcha-labeling.page.tsx +++ b/packages/apps/human-app/frontend/src/modules/worker/hcaptcha-labeling/hcaptcha-labeling.page.tsx @@ -4,7 +4,6 @@ import { Paper, Typography } from '@mui/material'; import { t } from 'i18next'; import { Navigate, useNavigate } from 'react-router-dom'; import { useRef } from 'react'; -import { useIsMobile } from '@/shared/hooks/use-is-mobile'; import { env } from '@/shared/env'; import { breakpoints } from '@/shared/styles/breakpoints'; import { Counter } from '@/shared/components/ui/counter'; @@ -67,7 +66,6 @@ export function HcaptchaLabelingPage() { error: dailyHmtSpentError, } = useDailyHmtSpent(); - const isMobile = useIsMobile(); const navigate = useNavigate(); const canSolveCaptcha = @@ -102,17 +100,14 @@ export function HcaptchaLabelingPage() { return ( @@ -155,11 +150,11 @@ export function HcaptchaLabelingPage() { /> ) : ( - + {t('worker.hcaptchaLabeling.noJobs')} - + { diff --git a/packages/apps/human-app/frontend/src/modules/worker/jobs-discovery/components/oracles-table-item-mobile.tsx b/packages/apps/human-app/frontend/src/modules/worker/jobs-discovery/components/oracles-table-item-mobile.tsx index 085b952125..730f41db79 100644 --- a/packages/apps/human-app/frontend/src/modules/worker/jobs-discovery/components/oracles-table-item-mobile.tsx +++ b/packages/apps/human-app/frontend/src/modules/worker/jobs-discovery/components/oracles-table-item-mobile.tsx @@ -1,4 +1,4 @@ -import { Grid, Paper, type SxProps, Typography } from '@mui/material'; +import { Stack, Paper, type SxProps, Typography } from '@mui/material'; import { t } from 'i18next'; import { Chips } from '@/shared/components/ui/chips'; import { TableButton } from '@/shared/components/ui/table-button'; @@ -14,13 +14,13 @@ interface OraclesTableItemMobileProps { } const styles: SxProps = { - px: '16px', - py: '32px', - marginBottom: '20px', + px: 2, + py: 4, + mb: 2.5, borderRadius: '20px', display: 'flex', flexDirection: 'column', - gap: '1rem', + gap: 2, boxShadow: 'none', }; @@ -32,7 +32,7 @@ export function OraclesTableItemMobile({ return ( - + @@ -46,7 +46,7 @@ export function OraclesTableItemMobile({ )} /> - + { diff --git a/packages/apps/human-app/frontend/src/modules/worker/jobs-discovery/components/oracles-table.tsx b/packages/apps/human-app/frontend/src/modules/worker/jobs-discovery/components/oracles-table.tsx index abb5fe312c..9e19e8af0e 100644 --- a/packages/apps/human-app/frontend/src/modules/worker/jobs-discovery/components/oracles-table.tsx +++ b/packages/apps/human-app/frontend/src/modules/worker/jobs-discovery/components/oracles-table.tsx @@ -51,7 +51,7 @@ export function OraclesTable() { } return isMobile ? ( - + {oraclesData.map((oracle) => ( - - - - - - - + + + + + + ); } diff --git a/packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/available-jobs-filter-modal.tsx b/packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/available-jobs-filter-modal.tsx index 087a512020..f66e008a16 100644 --- a/packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/available-jobs-filter-modal.tsx +++ b/packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/available-jobs-filter-modal.tsx @@ -43,16 +43,15 @@ export function AvailableJobsFilterModal({ variant="persistent" > {t('worker.jobs.network')} - + @@ -112,7 +111,7 @@ export function AvailableJobsFilterModal({ {t('worker.jobs.jobType')} - + diff --git a/packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/components/mobile/available-jobs-list-mobile.tsx b/packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/components/mobile/available-jobs-list-mobile.tsx index 0ece918fc8..da1da55a87 100644 --- a/packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/components/mobile/available-jobs-list-mobile.tsx +++ b/packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/components/mobile/available-jobs-list-mobile.tsx @@ -40,34 +40,34 @@ export function AvailableJobsListMobile() { }, [resetFilterParams]); return ( - + {isTableError && ( {getErrorMessageForError(tableError)} )} {tableStatus === 'pending' && ( - + )} - {allPages.map((d) => ( - - + + {d.job_description} - + @@ -93,22 +92,22 @@ export function AvailableJobsListMobile() { /> - + {getNetworkName(d.chain_id)} - + - + { setPageParams(filterParams.page + 1, filterParams.page_size); void fetchNextPage(); }} - variant="outlined" > {t('worker.jobs.next')} diff --git a/packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/components/mobile/available-jobs-reward-amount-sort-mobile.tsx b/packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/components/mobile/available-jobs-reward-amount-sort-mobile.tsx index 5aa9807f7f..3f78e5fec9 100644 --- a/packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/components/mobile/available-jobs-reward-amount-sort-mobile.tsx +++ b/packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/components/mobile/available-jobs-reward-amount-sort-mobile.tsx @@ -12,7 +12,7 @@ export function AvailableJobsRewardAmountSortMobile() { return ( + {t('worker.jobs.rewardAmount')} } diff --git a/packages/apps/human-app/frontend/src/modules/worker/jobs/components/escrow-address-search-form.tsx b/packages/apps/human-app/frontend/src/modules/worker/jobs/components/escrow-address-search-form.tsx index 77cebcfca9..472dbc17ca 100644 --- a/packages/apps/human-app/frontend/src/modules/worker/jobs/components/escrow-address-search-form.tsx +++ b/packages/apps/human-app/frontend/src/modules/worker/jobs/components/escrow-address-search-form.tsx @@ -73,16 +73,18 @@ export function EscrowAddressSearchForm({ > - - - ), - }} fullWidth label={label} name="searchValue" + slotProps={{ + input: { + startAdornment: ( + + + + ), + }, + }} onChange={(e) => { methods.setValue('searchValue', e.target.value); }} diff --git a/packages/apps/human-app/frontend/src/modules/worker/jobs/components/report-abuse-modal.tsx b/packages/apps/human-app/frontend/src/modules/worker/jobs/components/report-abuse-modal.tsx index 7db3ca047b..5cbfa52622 100644 --- a/packages/apps/human-app/frontend/src/modules/worker/jobs/components/report-abuse-modal.tsx +++ b/packages/apps/human-app/frontend/src/modules/worker/jobs/components/report-abuse-modal.tsx @@ -45,24 +45,23 @@ function ErrorState({ error }: { error: string }) { const errorColor = colorPalette.error.main; return ( - + {isAbuseError ? ( <> {t('worker.reportAbuse.modalHeaderAlreadyReportedError')} - + {t('worker.reportAbuse.modalParagraphAlreadyReportedError')} ) : ( - + {t('worker.reportAbuse.modalUnknownError')} )} @@ -73,11 +72,11 @@ function ErrorState({ error }: { error: string }) { function SuccessState() { const { t } = useTranslation(); return ( - + - + {t('worker.reportAbuse.modalSuccessHeader')} @@ -129,17 +128,22 @@ export function ReportAbuseModal({ return ( - + {t('worker.reportAbuse.modalHeader')} {isIdleOrLoading && ( <> - + {t('worker.reportAbuse.modalParagraph')} @@ -162,7 +166,7 @@ export function ReportAbuseModal({ {isPending && } {isError && } {isSuccess && } - + - + diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/table/table-header-cell.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/table/table-header-cell.tsx index b6730efb98..a0dfa345b0 100644 --- a/packages/apps/human-app/frontend/src/shared/components/ui/table/table-header-cell.tsx +++ b/packages/apps/human-app/frontend/src/shared/components/ui/table/table-header-cell.tsx @@ -1,6 +1,6 @@ import React, { useState } from 'react'; import Popover from '@mui/material/Popover'; -import type { TableCellBaseProps } from '@mui/material/TableCell/TableCell'; +import type { TableCellBaseProps } from '@mui/material/TableCell'; import { type IconType, TextHeaderWithIcon } from '../text-header-with-icon'; type CommonProps = TableCellBaseProps & { diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/table/table-header-menu/filtering.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/table/table-header-menu/filtering.tsx index 32023a5d48..ed71180808 100644 --- a/packages/apps/human-app/frontend/src/shared/components/ui/table/table-header-menu/filtering.tsx +++ b/packages/apps/human-app/frontend/src/shared/components/ui/table/table-header-menu/filtering.tsx @@ -34,9 +34,8 @@ export function Filtering({ {showTitle ? ( {t('components.table.filter')} @@ -54,15 +53,18 @@ export function Filtering({ } setFiltering(option); }} - sx={{ paddingLeft: 0, ':hover': { background: 'none' } }} + sx={{ pl: 0, ':hover': { background: 'none' } }} /> - + {name} @@ -74,11 +76,11 @@ export function Filtering({ { clear(); }} - variant="buttonMedium" > {t('components.table.clearBtn')} diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/table/table-header-menu/sorting.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/table/table-header-menu/sorting.tsx index 5d5749b639..835197d3fd 100644 --- a/packages/apps/human-app/frontend/src/shared/components/ui/table/table-header-menu/sorting.tsx +++ b/packages/apps/human-app/frontend/src/shared/components/ui/table/table-header-menu/sorting.tsx @@ -15,9 +15,8 @@ export function Sorting({ sortingOptions, clear }: SortingMenuProps) { return ( {t('components.table.sort')} @@ -30,7 +29,10 @@ export function Sorting({ sortingOptions, clear }: SortingMenuProps) { }} sx={{ padding: '0.2rem 0.5rem', cursor: 'pointer' }} > - + {label} @@ -39,9 +41,11 @@ export function Sorting({ sortingOptions, clear }: SortingMenuProps) { { + clear(); + }} > {t('components.table.clearBtn')} diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/text-header-with-icon.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/text-header-with-icon.tsx index 0af093146e..57a2d2b727 100644 --- a/packages/apps/human-app/frontend/src/shared/components/ui/text-header-with-icon.tsx +++ b/packages/apps/human-app/frontend/src/shared/components/ui/text-header-with-icon.tsx @@ -1,4 +1,4 @@ -import Grid from '@mui/material/Grid/Grid'; +import { Grid } from '@mui/material'; import { FiltersIcon } from '@/shared/components/ui/icons'; export type IconType = 'filter'; diff --git a/packages/apps/human-app/frontend/src/shared/styles/dark-theme.ts b/packages/apps/human-app/frontend/src/shared/styles/dark-theme.ts index 0158695420..56a635b86c 100644 --- a/packages/apps/human-app/frontend/src/shared/styles/dark-theme.ts +++ b/packages/apps/human-app/frontend/src/shared/styles/dark-theme.ts @@ -20,7 +20,6 @@ export const darkTheme: ThemeOptions = { defaultProps: { variant: 'body1', color: darkColorPalette.text.primary, - fontFamily: 'Inter', variantMapping: { subtitle1: 'p', subtitle2: 'p', diff --git a/packages/apps/human-app/frontend/src/shared/styles/theme.ts b/packages/apps/human-app/frontend/src/shared/styles/theme.ts index 44a04ae421..b655c57dc4 100644 --- a/packages/apps/human-app/frontend/src/shared/styles/theme.ts +++ b/packages/apps/human-app/frontend/src/shared/styles/theme.ts @@ -9,7 +9,6 @@ export const theme: ThemeOptions = { defaultProps: { variant: 'body1', color: colorPalette.primary.main, - fontFamily: 'Inter', variantMapping: { subtitle1: 'p', subtitle2: 'p', diff --git a/packages/apps/human-app/frontend/src/shared/styles/typography.ts b/packages/apps/human-app/frontend/src/shared/styles/typography.ts index 6f940bcf59..6d53f178e9 100644 --- a/packages/apps/human-app/frontend/src/shared/styles/typography.ts +++ b/packages/apps/human-app/frontend/src/shared/styles/typography.ts @@ -73,6 +73,7 @@ declare module '@mui/material/styles' { } export const typography: ThemeOptions['typography'] = { + fontFamily: 'Inter', h1: { fontSize: 80, fontWeight: 800, diff --git a/packages/apps/human-app/frontend/tsconfig.json b/packages/apps/human-app/frontend/tsconfig.json index f58b6f497d..ff07c5d0da 100644 --- a/packages/apps/human-app/frontend/tsconfig.json +++ b/packages/apps/human-app/frontend/tsconfig.json @@ -20,7 +20,6 @@ "noUnusedParameters": true, "noFallthroughCasesInSwitch": true, /* Absolute paths */ - "baseUrl": ".", "paths": { "@/*": ["./src/*"] } diff --git a/yarn.lock b/yarn.lock index 1c92a2ea4f..8243482728 100644 --- a/yarn.lock +++ b/yarn.lock @@ -425,9 +425,8 @@ __metadata: "@hcaptcha/react-hcaptcha": "npm:^1.14.0" "@hookform/resolvers": "npm:^5.1.0" "@human-protocol/sdk": "workspace:*" - "@mui/icons-material": "npm:^7.3.8" - "@mui/material": "npm:^5.16.7" - "@mui/system": "npm:^9.0.1" + "@mui/icons-material": "npm:^9.2.0" + "@mui/material": "npm:^9.2.0" "@mui/x-date-pickers": "npm:^9.2.0" "@reown/appkit": "npm:^1.8.20" "@reown/appkit-adapter-wagmi": "npm:^1.8.20" @@ -436,7 +435,6 @@ __metadata: "@tanstack/react-query": "npm:^5.91.3" "@tanstack/react-query-devtools": "npm:^5.59.16" "@types/lodash": "npm:^4.17.24" - "@types/mui-image": "npm:^1.0.5" "@types/node": "npm:^22.10.5" "@types/prop-types": "npm:^15" "@types/react": "npm:^19.2.15" @@ -459,7 +457,6 @@ __metadata: jwt-decode: "npm:^4.0.0" lodash: "npm:^4.18.1" material-react-table: "npm:3.0.1" - mui-image: "npm:^1.0.7" notistack: "npm:^3.0.1" prettier: "npm:^3.8.1" prop-types: "npm:^15.8.1" @@ -472,7 +469,7 @@ __metadata: react-number-format: "npm:^5.4.5" react-router-dom: "npm:^7.18.0" serve: "npm:^14.2.6" - typescript: "npm:^5.6.3" + typescript: "npm:^6.0.2" typescript-eslint: "npm:^8.57.0" viem: "npm:^2.52.2" vite: "npm:^6.2.4" @@ -7034,6 +7031,13 @@ __metadata: languageName: node linkType: hard +"@mui/core-downloads-tracker@npm:^9.2.0": + version: 9.2.0 + resolution: "@mui/core-downloads-tracker@npm:9.2.0" + checksum: 10c0/644d5e78c9a305b4520889348649b6f89ced9ef1c5a60720b58d5fd4e743d703cd53249405cf236d60d2ccca1bd7813c59451acd02afcb04e24bc3c1439917a7 + languageName: node + linkType: hard + "@mui/icons-material@npm:^7.3.8": version: 7.3.8 resolution: "@mui/icons-material@npm:7.3.8" @@ -7050,6 +7054,22 @@ __metadata: languageName: node linkType: hard +"@mui/icons-material@npm:^9.2.0": + version: 9.2.0 + resolution: "@mui/icons-material@npm:9.2.0" + dependencies: + "@babel/runtime": "npm:^7.29.2" + peerDependencies: + "@mui/material": ^9.2.0 + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/7fc499bdb1018f90c028983da136810ec7d0a9a9ecc7b40773d9c2d8c5d76c4c765d3859de2d9e3cccd9b0c44961d9a17417fbda9a68874f2bff5a471e1bd62f + languageName: node + linkType: hard + "@mui/lab@npm:^7.0.0-beta.17": version: 7.0.0-beta.17 resolution: "@mui/lab@npm:7.0.0-beta.17" @@ -7150,6 +7170,42 @@ __metadata: languageName: node linkType: hard +"@mui/material@npm:^9.2.0": + version: 9.2.0 + resolution: "@mui/material@npm:9.2.0" + dependencies: + "@babel/runtime": "npm:^7.29.2" + "@mui/core-downloads-tracker": "npm:^9.2.0" + "@mui/system": "npm:^9.2.0" + "@mui/types": "npm:^9.1.1" + "@mui/utils": "npm:^9.2.0" + "@popperjs/core": "npm:^2.11.8" + "@types/react-transition-group": "npm:^4.4.12" + clsx: "npm:^2.1.1" + csstype: "npm:^3.2.3" + prop-types: "npm:^15.8.1" + react-is: "npm:^19.2.6" + react-transition-group: "npm:^4.4.5" + peerDependencies: + "@emotion/react": ^11.5.0 + "@emotion/styled": ^11.3.0 + "@mui/material-pigment-css": ^9.2.0 + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@emotion/react": + optional: true + "@emotion/styled": + optional: true + "@mui/material-pigment-css": + optional: true + "@types/react": + optional: true + checksum: 10c0/058b10cd15b9d5c8b1d0a95200603e207f456ab7a52616e00e552e96a43be8081206486b4d7beea540e66f28e1b232cc8d75333a68d7bb0748dbdefbf11190da + languageName: node + linkType: hard + "@mui/private-theming@npm:^5.17.1": version: 5.17.1 resolution: "@mui/private-theming@npm:5.17.1" @@ -7218,6 +7274,23 @@ __metadata: languageName: node linkType: hard +"@mui/private-theming@npm:^9.2.0": + version: 9.2.0 + resolution: "@mui/private-theming@npm:9.2.0" + dependencies: + "@babel/runtime": "npm:^7.29.2" + "@mui/utils": "npm:^9.2.0" + prop-types: "npm:^15.8.1" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/534fbf18f53ee641b09fd72c839adeec23975b4bca399493183b01a539c085de2e998ce914b148481d12d4e92f8ccbaf5aad139e7878c131cdcc6e70298d2f1f + languageName: node + linkType: hard + "@mui/styled-engine-sc@npm:9.0.1": version: 9.0.1 resolution: "@mui/styled-engine-sc@npm:9.0.1" @@ -7324,6 +7397,29 @@ __metadata: languageName: node linkType: hard +"@mui/styled-engine@npm:^9.1.1": + version: 9.1.1 + resolution: "@mui/styled-engine@npm:9.1.1" + dependencies: + "@babel/runtime": "npm:^7.29.2" + "@emotion/cache": "npm:^11.14.0" + "@emotion/serialize": "npm:^1.3.3" + "@emotion/sheet": "npm:^1.4.0" + csstype: "npm:^3.2.3" + prop-types: "npm:^15.8.1" + peerDependencies: + "@emotion/react": ^11.4.1 + "@emotion/styled": ^11.3.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@emotion/react": + optional: true + "@emotion/styled": + optional: true + checksum: 10c0/250bb2a94ac3399a3a9c2ba81871419100fed51b823b87a935215c50781aace3022585697039898073964e661e749abd9e30a6a241ce7567ad5eec47ef082467 + languageName: node + linkType: hard + "@mui/system@npm:^5.18.0": version: 5.18.0 resolution: "@mui/system@npm:5.18.0" @@ -7436,6 +7532,34 @@ __metadata: languageName: node linkType: hard +"@mui/system@npm:^9.2.0": + version: 9.2.0 + resolution: "@mui/system@npm:9.2.0" + dependencies: + "@babel/runtime": "npm:^7.29.2" + "@mui/private-theming": "npm:^9.2.0" + "@mui/styled-engine": "npm:^9.1.1" + "@mui/types": "npm:^9.1.1" + "@mui/utils": "npm:^9.2.0" + clsx: "npm:^2.1.1" + csstype: "npm:^3.2.3" + prop-types: "npm:^15.8.1" + peerDependencies: + "@emotion/react": ^11.5.0 + "@emotion/styled": ^11.3.0 + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@emotion/react": + optional: true + "@emotion/styled": + optional: true + "@types/react": + optional: true + checksum: 10c0/ff7edecadfbd6a746ba8a401b68a32ddf0439d5caeeef27ebdd4a305ceb0d8c532276d03d2965c6cac75a4a80c7be7903830309b509839722ac8f0799aae6276 + languageName: node + linkType: hard + "@mui/types@npm:^7.4.12, @mui/types@npm:^7.4.6": version: 7.4.12 resolution: "@mui/types@npm:7.4.12" @@ -7478,6 +7602,20 @@ __metadata: languageName: node linkType: hard +"@mui/types@npm:^9.1.1": + version: 9.1.1 + resolution: "@mui/types@npm:9.1.1" + dependencies: + "@babel/runtime": "npm:^7.29.2" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/83cb89cafba0c55c909a8a89bd165550a71f92a67bbd191823b6ec304e5f59b43438052fecc4f69cc27e4e557c6bce3d5a073b9f5d5787d62d8cdc055e479905 + languageName: node + linkType: hard + "@mui/types@npm:~7.2.15": version: 7.2.24 resolution: "@mui/types@npm:7.2.24" @@ -7590,6 +7728,26 @@ __metadata: languageName: node linkType: hard +"@mui/utils@npm:^9.2.0": + version: 9.2.0 + resolution: "@mui/utils@npm:9.2.0" + dependencies: + "@babel/runtime": "npm:^7.29.2" + "@mui/types": "npm:^9.1.1" + "@types/prop-types": "npm:^15.7.15" + clsx: "npm:^2.1.1" + prop-types: "npm:^15.8.1" + react-is: "npm:^19.2.6" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/fb2a0b7f0bd24e0027f218743d03eb69d1067dfb4faccbe0483580dee5a0c6023c8b1e4611bc9810d704a01d06f2da699912f8080deccef8ae2460b5ab928170 + languageName: node + linkType: hard + "@mui/x-data-grid@npm:^8.7.0": version: 8.16.0 resolution: "@mui/x-data-grid@npm:8.16.0" @@ -12381,15 +12539,6 @@ __metadata: languageName: node linkType: hard -"@types/mui-image@npm:^1.0.5": - version: 1.0.5 - resolution: "@types/mui-image@npm:1.0.5" - dependencies: - "@types/react": "npm:*" - checksum: 10c0/ac81f6e290571a7534271464203d6ab92d997ebb266c35b7611adbcc12c3ee5a0f65d67e072f234f3689cc38903e8c94d785fc164ca987f19e6b33b51083daed - languageName: node - linkType: hard - "@types/node@npm:*, @types/node@npm:>=13.7.0, @types/node@npm:>=18, @types/node@npm:>=18.0.0, @types/node@npm:>=8.1.0": version: 24.10.0 resolution: "@types/node@npm:24.10.0" @@ -25088,19 +25237,6 @@ __metadata: languageName: node linkType: hard -"mui-image@npm:^1.0.7": - version: 1.0.9 - resolution: "mui-image@npm:1.0.9" - peerDependencies: - "@emotion/react": ^11.4.1 - "@emotion/styled": ^11.3.0 - "@mui/material": ^5.0.1 || ^6.0.0 || ^7.0.0 - prop-types: ^15.7.2 - react: ^17.0.2 || ^18.0.0 || ^19.0.0 - checksum: 10c0/ad17200a32c3633776ee8351d2071ee7e38faaf41b2e1c26673cab75a2a1f6a94d6d2939d34ec65ba9b088fc34d55b56798afd71e9753818e2079306992ce3d1 - languageName: node - linkType: hard - "multer@npm:2.0.2": version: 2.0.2 resolution: "multer@npm:2.0.2" @@ -27578,6 +27714,13 @@ __metadata: languageName: node linkType: hard +"react-is@npm:^19.2.6": + version: 19.2.7 + resolution: "react-is@npm:19.2.7" + checksum: 10c0/419fe54d5bd7fdf5414a5bb7bd9a1e0e36f9fae28ffb4cb73290fbe342bde15d8584a90d1db62547f6aa03018dce517b178a041abb522136cd4b4b51b4e94c83 + languageName: node + linkType: hard + "react-loading-skeleton@npm:^3.3.1": version: 3.5.0 resolution: "react-loading-skeleton@npm:3.5.0" @@ -30949,6 +31092,16 @@ __metadata: languageName: node linkType: hard +"typescript@npm:^6.0.2": + version: 6.0.3 + resolution: "typescript@npm:6.0.3" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/4a25ff5045b984370f48f196b3a0120779b1b343d40b9a68d114ea5e5fff099809b2bb777576991a63a5cd59cf7bffd96ff6fe10afcefbcb8bd6fb96ad4b6606 + languageName: node + linkType: hard + "typescript@patch:typescript@npm%3A5.9.3#optional!builtin, typescript@patch:typescript@npm%3A^5.5.4#optional!builtin, typescript@patch:typescript@npm%3A^5.6.3#optional!builtin, typescript@patch:typescript@npm%3A^5.8.3#optional!builtin, typescript@patch:typescript@npm%3A^5.9.2#optional!builtin": version: 5.9.3 resolution: "typescript@patch:typescript@npm%3A5.9.3#optional!builtin::version=5.9.3&hash=5786d5" @@ -30959,6 +31112,16 @@ __metadata: languageName: node linkType: hard +"typescript@patch:typescript@npm%3A^6.0.2#optional!builtin": + version: 6.0.3 + resolution: "typescript@patch:typescript@npm%3A6.0.3#optional!builtin::version=6.0.3&hash=5786d5" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/2f25c74e65663c248fa1ade2b8459d9ce5372ff9dad07067310f132966ebec1d93f6c42f0baf77a6b6a7a91460463f708e6887013aaade22111037457c6b25df + languageName: node + linkType: hard + "typical@npm:^4.0.0": version: 4.0.0 resolution: "typical@npm:4.0.0" From f34ccbb6970b7124d040cf1a91c556ef9dc5afb2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 14:42:10 +0300 Subject: [PATCH 07/33] chore(deps): bump @mui/x-date-pickers from 9.2.0 to 9.9.0 (#3965) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- packages/apps/dashboard/client/package.json | 2 +- packages/apps/human-app/frontend/package.json | 2 +- .../apps/job-launcher/client/package.json | 2 +- yarn.lock | 135 ++++++++++-------- 4 files changed, 81 insertions(+), 60 deletions(-) diff --git a/packages/apps/dashboard/client/package.json b/packages/apps/dashboard/client/package.json index 884bd43dbf..aa3feed6df 100644 --- a/packages/apps/dashboard/client/package.json +++ b/packages/apps/dashboard/client/package.json @@ -25,7 +25,7 @@ "@mui/styled-engine-sc": "9.0.1", "@mui/system": "^9.0.1", "@mui/x-data-grid": "^8.7.0", - "@mui/x-date-pickers": "^9.2.0", + "@mui/x-date-pickers": "^9.9.0", "@tanstack/react-query": "^5.91.3", "@types/react-router-dom": "^5.3.3", "@types/recharts": "^1.8.29", diff --git a/packages/apps/human-app/frontend/package.json b/packages/apps/human-app/frontend/package.json index f3c078cde3..d386d29404 100644 --- a/packages/apps/human-app/frontend/package.json +++ b/packages/apps/human-app/frontend/package.json @@ -27,7 +27,7 @@ "@human-protocol/sdk": "workspace:*", "@mui/icons-material": "^9.2.0", "@mui/material": "^9.2.0", - "@mui/x-date-pickers": "^9.2.0", + "@mui/x-date-pickers": "^9.9.0", "@reown/appkit": "^1.8.20", "@reown/appkit-adapter-wagmi": "^1.8.20", "@synaps-io/verify-sdk": "^4.0.45", diff --git a/packages/apps/job-launcher/client/package.json b/packages/apps/job-launcher/client/package.json index 3e466458ca..51dc5a854c 100644 --- a/packages/apps/job-launcher/client/package.json +++ b/packages/apps/job-launcher/client/package.json @@ -13,7 +13,7 @@ "@mui/lab": "^7.0.0-beta.17", "@mui/material": "^5.16.7", "@mui/system": "^9.0.1", - "@mui/x-date-pickers": "^9.2.0", + "@mui/x-date-pickers": "^9.9.0", "@reduxjs/toolkit": "^2.5.0", "@stripe/react-stripe-js": "^3.0.0", "@stripe/stripe-js": "^9.6.0", diff --git a/yarn.lock b/yarn.lock index 8243482728..a4c0e50ac9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -112,7 +112,7 @@ __metadata: "@mui/styled-engine-sc": "npm:9.0.1" "@mui/system": "npm:^9.0.1" "@mui/x-data-grid": "npm:^8.7.0" - "@mui/x-date-pickers": "npm:^9.2.0" + "@mui/x-date-pickers": "npm:^9.9.0" "@tanstack/react-query": "npm:^5.91.3" "@types/react": "npm:^19.2.15" "@types/react-dom": "npm:^19.2.3" @@ -427,7 +427,7 @@ __metadata: "@human-protocol/sdk": "workspace:*" "@mui/icons-material": "npm:^9.2.0" "@mui/material": "npm:^9.2.0" - "@mui/x-date-pickers": "npm:^9.2.0" + "@mui/x-date-pickers": "npm:^9.9.0" "@reown/appkit": "npm:^1.8.20" "@reown/appkit-adapter-wagmi": "npm:^1.8.20" "@synaps-io/verify-sdk": "npm:^4.0.45" @@ -558,7 +558,7 @@ __metadata: "@mui/lab": "npm:^7.0.0-beta.17" "@mui/material": "npm:^5.16.7" "@mui/system": "npm:^9.0.1" - "@mui/x-date-pickers": "npm:^9.2.0" + "@mui/x-date-pickers": "npm:^9.9.0" "@reduxjs/toolkit": "npm:^2.5.0" "@stripe/react-stripe-js": "npm:^3.0.0" "@stripe/stripe-js": "npm:^9.6.0" @@ -3058,6 +3058,13 @@ __metadata: languageName: node linkType: hard +"@babel/runtime@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/runtime@npm:7.29.7" + checksum: 10c0/ca11572f7146b21e0bde6a9ed4bb6a89eafbee5f0944c7eb54d0d8a2dac962c33638a1d611e14faa71dfbb92b4b5f9236232208568a6b7d5c6f3f39ddb91771e + languageName: node + linkType: hard + "@babel/template@npm:^7.27.1, @babel/template@npm:^7.27.2, @babel/template@npm:^7.3.3": version: 7.27.2 resolution: "@babel/template@npm:7.27.2" @@ -3147,6 +3154,25 @@ __metadata: languageName: node linkType: hard +"@base-ui/utils@npm:^0.3.0": + version: 0.3.1 + resolution: "@base-ui/utils@npm:0.3.1" + dependencies: + "@babel/runtime": "npm:^7.29.2" + "@floating-ui/utils": "npm:^0.2.11" + reselect: "npm:^5.2.0" + use-sync-external-store: "npm:^1.6.0" + peerDependencies: + "@types/react": ^17 || ^18 || ^19 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/4de858c3e2c8a4486a549d51c5e887bba6921e5a7f8db54439ba558feaf1656c3592a873928aee8a1711ee9210be3a65ca43b26713e97f649695ed2fa8c3af2c + languageName: node + linkType: hard + "@bcoe/v8-coverage@npm:^0.2.3": version: 0.2.3 resolution: "@bcoe/v8-coverage@npm:0.2.3" @@ -4764,6 +4790,13 @@ __metadata: languageName: node linkType: hard +"@floating-ui/utils@npm:^0.2.11": + version: 0.2.12 + resolution: "@floating-ui/utils@npm:0.2.12" + checksum: 10c0/bb910b90d56991a62011afaf5f8e0c4b7fb6dab69403f4dd17fbd6eb25560b28d533dff9791f270b4f459852e9006a1077b5d73cbedb5e34d9424afc6a828314 + languageName: node + linkType: hard + "@fontsource/inter@npm:^5.0.17": version: 5.2.8 resolution: "@fontsource/inter@npm:5.2.8" @@ -7628,46 +7661,6 @@ __metadata: languageName: node linkType: hard -"@mui/utils@npm:9.0.0": - version: 9.0.0 - resolution: "@mui/utils@npm:9.0.0" - dependencies: - "@babel/runtime": "npm:^7.29.2" - "@mui/types": "npm:^9.0.0" - "@types/prop-types": "npm:^15.7.15" - clsx: "npm:^2.1.1" - prop-types: "npm:^15.8.1" - react-is: "npm:^19.2.4" - peerDependencies: - "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 - react: ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/139ccbdc418dce45070def89f3644b9a42b4eef9a98e74338f83e0f74b715f484a047163708746bf18713da88aa0d8a9e4d0c3df51c93337e492dcebc953fde5 - languageName: node - linkType: hard - -"@mui/utils@npm:9.0.1, @mui/utils@npm:^9.0.1": - version: 9.0.1 - resolution: "@mui/utils@npm:9.0.1" - dependencies: - "@babel/runtime": "npm:^7.29.2" - "@mui/types": "npm:^9.0.0" - "@types/prop-types": "npm:^15.7.15" - clsx: "npm:^2.1.1" - prop-types: "npm:^15.8.1" - react-is: "npm:^19.2.4" - peerDependencies: - "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 - react: ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/be6d3c6ce7e5767a7d01583ff8780222f1bafa2f5ee8c549e3a25e7e283ba9fb7cb8c95d39ddbd9a57820722f5cfb5f5322cd37c580290d44d0f6e3a464cf23d - languageName: node - linkType: hard - "@mui/utils@npm:^5.17.1": version: 5.17.1 resolution: "@mui/utils@npm:5.17.1" @@ -7728,6 +7721,26 @@ __metadata: languageName: node linkType: hard +"@mui/utils@npm:^9.0.1": + version: 9.0.1 + resolution: "@mui/utils@npm:9.0.1" + dependencies: + "@babel/runtime": "npm:^7.29.2" + "@mui/types": "npm:^9.0.0" + "@types/prop-types": "npm:^15.7.15" + clsx: "npm:^2.1.1" + prop-types: "npm:^15.8.1" + react-is: "npm:^19.2.4" + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/be6d3c6ce7e5767a7d01583ff8780222f1bafa2f5ee8c549e3a25e7e283ba9fb7cb8c95d39ddbd9a57820722f5cfb5f5322cd37c580290d44d0f6e3a464cf23d + languageName: node + linkType: hard + "@mui/utils@npm:^9.2.0": version: 9.2.0 resolution: "@mui/utils@npm:9.2.0" @@ -7775,13 +7788,13 @@ __metadata: languageName: node linkType: hard -"@mui/x-date-pickers@npm:^9.2.0": - version: 9.2.0 - resolution: "@mui/x-date-pickers@npm:9.2.0" +"@mui/x-date-pickers@npm:^9.9.0": + version: 9.9.0 + resolution: "@mui/x-date-pickers@npm:9.9.0" dependencies: - "@babel/runtime": "npm:^7.29.2" - "@mui/utils": "npm:9.0.1" - "@mui/x-internals": "npm:^9.1.0" + "@babel/runtime": "npm:^7.29.7" + "@mui/utils": "npm:^9.2.0" + "@mui/x-internals": "npm:^9.9.0" "@types/react-transition-group": "npm:^4.4.12" clsx: "npm:^2.1.1" prop-types: "npm:^15.8.1" @@ -7819,7 +7832,7 @@ __metadata: optional: true moment-jalaali: optional: true - checksum: 10c0/12a4dc4fe2f10be399cffc51bd1b42a76d91e5703d86caf034116e8bc5f1f7e03dc04eddb674e27c48140fe947218db6d1cf8cea0393a85fb8b10be2d8890948 + checksum: 10c0/3df060eb893c6d478239e89e3975ebfcb5b46c92161db52538896445eddaa7d21de436364fa1b21656b28830e76621b222b15a314861e908872a6a730b79c11b languageName: node linkType: hard @@ -7837,17 +7850,18 @@ __metadata: languageName: node linkType: hard -"@mui/x-internals@npm:^9.1.0": - version: 9.1.0 - resolution: "@mui/x-internals@npm:9.1.0" +"@mui/x-internals@npm:^9.9.0": + version: 9.9.0 + resolution: "@mui/x-internals@npm:9.9.0" dependencies: - "@babel/runtime": "npm:^7.29.2" - "@mui/utils": "npm:9.0.0" - reselect: "npm:^5.1.1" + "@babel/runtime": "npm:^7.29.7" + "@base-ui/utils": "npm:^0.3.0" + "@mui/utils": "npm:^9.2.0" + reselect: "npm:^5.2.0" use-sync-external-store: "npm:^1.6.0" peerDependencies: react: ^17.0.0 || ^18.0.0 || ^19.0.0 - checksum: 10c0/3494fb8794b11e3d10e17310dcfb4affa95e73be00908b6e27f6016f13569bd643bc41b02ac032e7bd2dbbe44c8ba211a348fff4110548d7af6450650814eb3e + checksum: 10c0/c14390446850d9437e8bda012c6d72bdfccc8f1b63b4ef17a4b44ed3174998e40456313cb910be31852681915387ed28a5fee3456b7eaf8e0294bd78aadf6e55 languageName: node linkType: hard @@ -28201,6 +28215,13 @@ __metadata: languageName: node linkType: hard +"reselect@npm:^5.2.0": + version: 5.2.0 + resolution: "reselect@npm:5.2.0" + checksum: 10c0/d0a8497e404b25a769fe792eacae88b9b576c30870450cd243d76ec9427d91a59c4a2cc00d824d283448b444c4c698a8f961d771c8ae39c759313afb31950e2e + languageName: node + linkType: hard + "resize-observer-polyfill@npm:^1.5.1": version: 1.5.1 resolution: "resize-observer-polyfill@npm:1.5.1" From 790ca6ec4bd332286636448bd66f1bde32d4d4b4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 14:47:16 +0300 Subject: [PATCH 08/33] chore(deps): bump @tanstack/query-sync-storage-persister from 5.90.8 to 5.101.2 (#3962) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../exchange-oracle/client/package.json | 2 +- .../apps/job-launcher/client/package.json | 2 +- packages/apps/staking/package.json | 2 +- yarn.lock | 34 ++++++++++++++----- 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/packages/apps/fortune/exchange-oracle/client/package.json b/packages/apps/fortune/exchange-oracle/client/package.json index 7d2542af36..da0d840e1c 100644 --- a/packages/apps/fortune/exchange-oracle/client/package.json +++ b/packages/apps/fortune/exchange-oracle/client/package.json @@ -32,7 +32,7 @@ "@human-protocol/sdk": "workspace:^", "@mui/icons-material": "^7.3.8", "@mui/material": "^5.16.7", - "@tanstack/query-sync-storage-persister": "^5.68.0", + "@tanstack/query-sync-storage-persister": "^5.101.2", "@tanstack/react-query": "^5.91.3", "@tanstack/react-query-persist-client": "^5.80.7", "axios": "^1.7.2", diff --git a/packages/apps/job-launcher/client/package.json b/packages/apps/job-launcher/client/package.json index 51dc5a854c..91958fc9c3 100644 --- a/packages/apps/job-launcher/client/package.json +++ b/packages/apps/job-launcher/client/package.json @@ -17,7 +17,7 @@ "@reduxjs/toolkit": "^2.5.0", "@stripe/react-stripe-js": "^3.0.0", "@stripe/stripe-js": "^9.6.0", - "@tanstack/query-sync-storage-persister": "^5.68.0", + "@tanstack/query-sync-storage-persister": "^5.101.2", "@tanstack/react-query": "^5.91.3", "@tanstack/react-query-persist-client": "^5.80.7", "axios": "^1.1.3", diff --git a/packages/apps/staking/package.json b/packages/apps/staking/package.json index 7215d70c41..60c3eed8cc 100644 --- a/packages/apps/staking/package.json +++ b/packages/apps/staking/package.json @@ -34,7 +34,7 @@ "@mui/icons-material": "^7.3.8", "@mui/material": "^5.16.7", "@mui/x-data-grid": "^8.7.0", - "@tanstack/query-sync-storage-persister": "^5.68.0", + "@tanstack/query-sync-storage-persister": "^5.101.2", "@tanstack/react-query": "^5.91.3", "@tanstack/react-query-persist-client": "^5.80.7", "axios": "^1.7.2", diff --git a/yarn.lock b/yarn.lock index a4c0e50ac9..abf0966e3a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -281,7 +281,7 @@ __metadata: "@human-protocol/sdk": "workspace:^" "@mui/icons-material": "npm:^7.3.8" "@mui/material": "npm:^5.16.7" - "@tanstack/query-sync-storage-persister": "npm:^5.68.0" + "@tanstack/query-sync-storage-persister": "npm:^5.101.2" "@tanstack/react-query": "npm:^5.91.3" "@tanstack/react-query-persist-client": "npm:^5.80.7" "@types/react": "npm:^19.2.15" @@ -562,7 +562,7 @@ __metadata: "@reduxjs/toolkit": "npm:^2.5.0" "@stripe/react-stripe-js": "npm:^3.0.0" "@stripe/stripe-js": "npm:^9.6.0" - "@tanstack/query-sync-storage-persister": "npm:^5.68.0" + "@tanstack/query-sync-storage-persister": "npm:^5.101.2" "@tanstack/react-query": "npm:^5.91.3" "@tanstack/react-query-persist-client": "npm:^5.80.7" "@types/file-saver": "npm:^2.0.7" @@ -766,7 +766,7 @@ __metadata: "@mui/icons-material": "npm:^7.3.8" "@mui/material": "npm:^5.16.7" "@mui/x-data-grid": "npm:^8.7.0" - "@tanstack/query-sync-storage-persister": "npm:^5.68.0" + "@tanstack/query-sync-storage-persister": "npm:^5.101.2" "@tanstack/react-query": "npm:^5.91.3" "@tanstack/react-query-persist-client": "npm:^5.80.7" "@types/react": "npm:^19.2.15" @@ -11770,6 +11770,13 @@ __metadata: languageName: node linkType: hard +"@tanstack/query-core@npm:5.101.2": + version: 5.101.2 + resolution: "@tanstack/query-core@npm:5.101.2" + checksum: 10c0/c3288757bfd563ca35cee21bf6ed0edb2f4425a8c92f75d84dcb36a0580a59e48bd97fcdbbc7c8d8e95a4c40376edfc5772b14665b85d183079a0ba7e17793b2 + languageName: node + linkType: hard + "@tanstack/query-core@npm:5.90.6": version: 5.90.6 resolution: "@tanstack/query-core@npm:5.90.6" @@ -11791,6 +11798,15 @@ __metadata: languageName: node linkType: hard +"@tanstack/query-persist-client-core@npm:5.101.2": + version: 5.101.2 + resolution: "@tanstack/query-persist-client-core@npm:5.101.2" + dependencies: + "@tanstack/query-core": "npm:5.101.2" + checksum: 10c0/a57f9046a19cebc21ce30c367eca679b5063e6a357f2395bb06e5858c8e6e1df68cae33a148a16b6d33e037a30e9bb0b13eae3d9e0b8d484de8221d3a3189437 + languageName: node + linkType: hard + "@tanstack/query-persist-client-core@npm:5.91.5": version: 5.91.5 resolution: "@tanstack/query-persist-client-core@npm:5.91.5" @@ -11800,13 +11816,13 @@ __metadata: languageName: node linkType: hard -"@tanstack/query-sync-storage-persister@npm:^5.68.0": - version: 5.90.8 - resolution: "@tanstack/query-sync-storage-persister@npm:5.90.8" +"@tanstack/query-sync-storage-persister@npm:^5.101.2": + version: 5.101.2 + resolution: "@tanstack/query-sync-storage-persister@npm:5.101.2" dependencies: - "@tanstack/query-core": "npm:5.90.6" - "@tanstack/query-persist-client-core": "npm:5.91.5" - checksum: 10c0/523d550049047fe4fcaa3838e96219da865a1e1d89dd33d95da246aea6b5d1795882399c0da8157b63364f119b50bcdf19e64230bd55014df21df24808466902 + "@tanstack/query-core": "npm:5.101.2" + "@tanstack/query-persist-client-core": "npm:5.101.2" + checksum: 10c0/885a575ed71b4238608d71c8db1a81c82c5762581a2c02dea063cc210e7cda4526b21a3faa3dae7cb885343b017f38db17bdb44f26939b1cbe3cd42a6553f7fb languageName: node linkType: hard From 4b0a8a7409330f5105d02ce9a02a1884c626d4b6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 14:56:59 +0300 Subject: [PATCH 09/33] chore(deps): bump styled-components from 6.3.11 to 6.4.3 (#3963) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- packages/apps/dashboard/client/package.json | 2 +- yarn.lock | 50 ++++++--------------- 2 files changed, 14 insertions(+), 38 deletions(-) diff --git a/packages/apps/dashboard/client/package.json b/packages/apps/dashboard/client/package.json index aa3feed6df..3bce3eff8e 100644 --- a/packages/apps/dashboard/client/package.json +++ b/packages/apps/dashboard/client/package.json @@ -38,7 +38,7 @@ "react-router-dom": "^7.18.0", "recharts": "^2.13.0-alpha.4", "simplebar-react": "^3.3.2", - "styled-components": "^6.3.11", + "styled-components": "^6.4.3", "swiper": "^11.1.3", "use-debounce": "^10.1.0", "vite-plugin-node-polyfills": "^0.25.0", diff --git a/yarn.lock b/yarn.lock index abf0966e3a..61582849b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -138,7 +138,7 @@ __metadata: recharts: "npm:^2.13.0-alpha.4" sass: "npm:^1.89.2" simplebar-react: "npm:^3.3.2" - styled-components: "npm:^6.3.11" + styled-components: "npm:^6.4.3" swiper: "npm:^11.1.3" terser: "npm:^5.36.0" typescript: "npm:^5.6.3" @@ -3737,7 +3737,7 @@ __metadata: languageName: node linkType: hard -"@emotion/unitless@npm:0.10.0, @emotion/unitless@npm:^0.10.0": +"@emotion/unitless@npm:^0.10.0": version: 0.10.0 resolution: "@emotion/unitless@npm:0.10.0" checksum: 10c0/150943192727b7650eb9a6851a98034ddb58a8b6958b37546080f794696141c3760966ac695ab9af97efe10178690987aee4791f9f0ad1ff76783cdca83c1d49 @@ -12852,13 +12852,6 @@ __metadata: languageName: node linkType: hard -"@types/stylis@npm:4.2.7": - version: 4.2.7 - resolution: "@types/stylis@npm:4.2.7" - checksum: 10c0/01a9679addb3f63951a9c09729564e2205581f2db40875a28b25cc461efc52ba17a711cc50cdb5e7d3a67c5f2cd60580e078c8a69b8df7b67699d89060d2a977 - languageName: node - linkType: hard - "@types/tough-cookie@npm:*": version: 4.0.5 resolution: "@types/tough-cookie@npm:4.0.5" @@ -25337,7 +25330,7 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.3.11, nanoid@npm:^3.3.7": +"nanoid@npm:^3.3.11": version: 3.3.11 resolution: "nanoid@npm:3.3.11" bin: @@ -27031,17 +27024,6 @@ __metadata: languageName: node linkType: hard -"postcss@npm:8.4.49": - version: 8.4.49 - resolution: "postcss@npm:8.4.49" - dependencies: - nanoid: "npm:^3.3.7" - picocolors: "npm:^1.1.1" - source-map-js: "npm:^1.2.1" - checksum: 10c0/f1b3f17aaf36d136f59ec373459f18129908235e65dbdc3aee5eef8eba0756106f52de5ec4682e29a2eab53eb25170e7e871b3e4b52a8f1de3d344a514306be3 - languageName: node - linkType: hard - "postcss@npm:^8.5.3, postcss@npm:^8.5.6": version: 8.5.6 resolution: "postcss@npm:8.5.6" @@ -29032,13 +29014,6 @@ __metadata: languageName: node linkType: hard -"shallowequal@npm:1.1.0": - version: 1.1.0 - resolution: "shallowequal@npm:1.1.0" - checksum: 10c0/b926efb51cd0f47aa9bc061add788a4a650550bbe50647962113a4579b60af2abe7b62f9b02314acc6f97151d4cf87033a2b15fc20852fae306d1a095215396c - languageName: node - linkType: hard - "shebang-command@npm:^2.0.0": version: 2.0.0 resolution: "shebang-command@npm:2.0.0" @@ -29994,26 +29969,27 @@ __metadata: languageName: node linkType: hard -"styled-components@npm:^6.3.11": - version: 6.3.11 - resolution: "styled-components@npm:6.3.11" +"styled-components@npm:^6.4.3": + version: 6.4.3 + resolution: "styled-components@npm:6.4.3" dependencies: "@emotion/is-prop-valid": "npm:1.4.0" - "@emotion/unitless": "npm:0.10.0" - "@types/stylis": "npm:4.2.7" css-to-react-native: "npm:3.2.0" csstype: "npm:3.2.3" - postcss: "npm:8.4.49" - shallowequal: "npm:1.1.0" stylis: "npm:4.3.6" - tslib: "npm:2.8.1" peerDependencies: + css-to-react-native: ">= 3.2.0" react: ">= 16.8.0" react-dom: ">= 16.8.0" + react-native: ">= 0.68.0" peerDependenciesMeta: + css-to-react-native: + optional: true react-dom: optional: true - checksum: 10c0/26e9e6205b9cebb3db56cd1ffcd43d8b7cb0d2801cdd6cea7d361b11ac32a8de24a88279e6138816c6d922099dccd6a08a0a6aeacf08f2281095151169640595 + react-native: + optional: true + checksum: 10c0/158514feb0a502dfa7f95610a8270faa56be2572c12902b7bf5c2855bf9fdd5d76a5909d67dcbecf627ee40511f4161f8016b23f9fef22c14f7911337359647c languageName: node linkType: hard From 65742fae8c34f864c5e6761b133d12b4fe567d05 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 15:07:03 +0300 Subject: [PATCH 10/33] chore(deps): bump react-router-dom from 7.18.0 to 7.18.1 (#3964) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- packages/apps/dashboard/client/package.json | 2 +- packages/apps/faucet/client/package.json | 2 +- .../exchange-oracle/client/package.json | 2 +- packages/apps/human-app/frontend/package.json | 2 +- .../apps/job-launcher/client/package.json | 2 +- packages/apps/staking/package.json | 2 +- yarn.lock | 30 +++++++++---------- 7 files changed, 21 insertions(+), 21 deletions(-) diff --git a/packages/apps/dashboard/client/package.json b/packages/apps/dashboard/client/package.json index 3bce3eff8e..54c43c6c7c 100644 --- a/packages/apps/dashboard/client/package.json +++ b/packages/apps/dashboard/client/package.json @@ -35,7 +35,7 @@ "react": "^19.2.6", "react-dom": "^19.2.6", "react-number-format": "^5.4.5", - "react-router-dom": "^7.18.0", + "react-router-dom": "^7.18.1", "recharts": "^2.13.0-alpha.4", "simplebar-react": "^3.3.2", "styled-components": "^6.4.3", diff --git a/packages/apps/faucet/client/package.json b/packages/apps/faucet/client/package.json index b24b6c5666..620c0f82a3 100644 --- a/packages/apps/faucet/client/package.json +++ b/packages/apps/faucet/client/package.json @@ -26,7 +26,7 @@ "react": "^19.2.6", "react-dom": "^19.2.6", "react-loading-skeleton": "^3.3.1", - "react-router-dom": "^7.18.0", + "react-router-dom": "^7.18.1", "serve": "^14.2.6", "viem": "^2.52.2" }, diff --git a/packages/apps/fortune/exchange-oracle/client/package.json b/packages/apps/fortune/exchange-oracle/client/package.json index da0d840e1c..80351990c1 100644 --- a/packages/apps/fortune/exchange-oracle/client/package.json +++ b/packages/apps/fortune/exchange-oracle/client/package.json @@ -39,7 +39,7 @@ "ethers": "^6.17.0", "react": "^19.2.6", "react-dom": "^19.2.6", - "react-router-dom": "^7.18.0", + "react-router-dom": "^7.18.1", "serve": "^14.2.6", "viem": "^2.52.2", "wagmi": "^3.6.15" diff --git a/packages/apps/human-app/frontend/package.json b/packages/apps/human-app/frontend/package.json index d386d29404..2c41645461 100644 --- a/packages/apps/human-app/frontend/package.json +++ b/packages/apps/human-app/frontend/package.json @@ -48,7 +48,7 @@ "react-i18next": "^15.1.0", "react-imask": "^7.4.0", "react-number-format": "^5.4.5", - "react-router-dom": "^7.18.0", + "react-router-dom": "^7.18.1", "serve": "^14.2.6", "viem": "^2.52.2", "vite-plugin-svgr": "^4.2.0", diff --git a/packages/apps/job-launcher/client/package.json b/packages/apps/job-launcher/client/package.json index 91958fc9c3..aa022bb8bf 100644 --- a/packages/apps/job-launcher/client/package.json +++ b/packages/apps/job-launcher/client/package.json @@ -31,7 +31,7 @@ "react": "^19.2.6", "react-dom": "^19.2.6", "react-redux": "^9.1.0", - "react-router-dom": "^7.18.0", + "react-router-dom": "^7.18.1", "recharts": "^2.7.2", "serve": "^14.2.6", "swr": "^2.4.1", diff --git a/packages/apps/staking/package.json b/packages/apps/staking/package.json index 60c3eed8cc..9ea828c49b 100644 --- a/packages/apps/staking/package.json +++ b/packages/apps/staking/package.json @@ -41,7 +41,7 @@ "ethers": "^6.17.0", "react": "^19.2.6", "react-dom": "^19.2.6", - "react-router-dom": "^7.18.0", + "react-router-dom": "^7.18.1", "serve": "^14.2.6", "simplebar-react": "^3.3.2", "viem": "^2.52.2", diff --git a/yarn.lock b/yarn.lock index 61582849b4..79f52d1a19 100644 --- a/yarn.lock +++ b/yarn.lock @@ -134,7 +134,7 @@ __metadata: react: "npm:^19.2.6" react-dom: "npm:^19.2.6" react-number-format: "npm:^5.4.5" - react-router-dom: "npm:^7.18.0" + react-router-dom: "npm:^7.18.1" recharts: "npm:^2.13.0-alpha.4" sass: "npm:^1.89.2" simplebar-react: "npm:^3.3.2" @@ -229,7 +229,7 @@ __metadata: react: "npm:^19.2.6" react-dom: "npm:^19.2.6" react-loading-skeleton: "npm:^3.3.1" - react-router-dom: "npm:^7.18.0" + react-router-dom: "npm:^7.18.1" serve: "npm:^14.2.6" typescript: "npm:^5.8.3" typescript-eslint: "npm:^8.57.0" @@ -297,7 +297,7 @@ __metadata: prettier: "npm:^3.8.1" react: "npm:^19.2.6" react-dom: "npm:^19.2.6" - react-router-dom: "npm:^7.18.0" + react-router-dom: "npm:^7.18.1" serve: "npm:^14.2.6" typescript: "npm:^5.6.3" typescript-eslint: "npm:^8.57.0" @@ -467,7 +467,7 @@ __metadata: react-i18next: "npm:^15.1.0" react-imask: "npm:^7.4.0" react-number-format: "npm:^5.4.5" - react-router-dom: "npm:^7.18.0" + react-router-dom: "npm:^7.18.1" serve: "npm:^14.2.6" typescript: "npm:^6.0.2" typescript-eslint: "npm:^8.57.0" @@ -590,7 +590,7 @@ __metadata: react: "npm:^19.2.6" react-dom: "npm:^19.2.6" react-redux: "npm:^9.1.0" - react-router-dom: "npm:^7.18.0" + react-router-dom: "npm:^7.18.1" recharts: "npm:^2.7.2" resize-observer-polyfill: "npm:^1.5.1" serve: "npm:^14.2.6" @@ -782,7 +782,7 @@ __metadata: prettier: "npm:^3.8.1" react: "npm:^19.2.6" react-dom: "npm:^19.2.6" - react-router-dom: "npm:^7.18.0" + react-router-dom: "npm:^7.18.1" sass: "npm:^1.89.2" serve: "npm:^14.2.6" simplebar-react: "npm:^3.3.2" @@ -27787,21 +27787,21 @@ __metadata: languageName: node linkType: hard -"react-router-dom@npm:^7.18.0": - version: 7.18.0 - resolution: "react-router-dom@npm:7.18.0" +"react-router-dom@npm:^7.18.1": + version: 7.18.1 + resolution: "react-router-dom@npm:7.18.1" dependencies: - react-router: "npm:7.18.0" + react-router: "npm:7.18.1" peerDependencies: react: ">=18" react-dom: ">=18" - checksum: 10c0/035303f4d14680bf5356ab20e40889fc7bac281f59399c34b8fd0ed884e2f8e9e1b17ce7e668cad5e8bc1b428fe32a33d97509947568a23f4271e0392501304c + checksum: 10c0/5efb99f2f09cecf445788f3459a8f5ff952ed85061f2d40f8de25fdd6e2ce6aeea8e40e4bacad470ea42a45d0460feb6fb59c62f14d87720b43d5c96cd9b2cb6 languageName: node linkType: hard -"react-router@npm:7.18.0": - version: 7.18.0 - resolution: "react-router@npm:7.18.0" +"react-router@npm:7.18.1": + version: 7.18.1 + resolution: "react-router@npm:7.18.1" dependencies: cookie: "npm:^1.0.1" set-cookie-parser: "npm:^2.6.0" @@ -27811,7 +27811,7 @@ __metadata: peerDependenciesMeta: react-dom: optional: true - checksum: 10c0/7ab6c6dc7efdc14092486d63f55b04f9e3ef269fdec8c695a513f69e55d02a9beab8f637a13396952815d85accf16e7db2d65d9cbb68def13c349be82ceb5aee + checksum: 10c0/1a559de58d656bad5565f2232e4f4fab7e9f5282dfaf95bc24f195a06e7e85b281077fe5c21ed3ff527e3d90d930447e0d0bb0f0713950d2a56ad0f0377a7d09 languageName: node linkType: hard From b60b89aa337f3dd27d4537756abc860ab7ba1f01 Mon Sep 17 00:00:00 2001 From: Maxim Zhiltsov Date: Tue, 14 Jul 2026 15:57:34 +0300 Subject: [PATCH 11/33] Bump CVAT oracle deps, improve container structure and test performance (#3967) --- .../ci-lint-cvat-recording-oracle.yaml | 2 +- .../ci-test-cvat-exchange-oracle.yaml | 2 +- .../ci-test-cvat-recording-oracle.yaml | 2 +- .../examples/cvat/exchange-oracle/Dockerfile | 2 +- .../examples/cvat/exchange-oracle/README.md | 47 ++++- .../cvat/exchange-oracle/alembic/env.py | 10 +- .../examples/cvat/exchange-oracle/debug.py | 3 +- .../docker-compose.test.head.dev.yml | 7 + .../docker-compose.test.head.yml | 35 ++++ .../exchange-oracle/docker-compose.test.yml | 35 ---- .../{test.Dockerfile => test.ci.Dockerfile} | 2 +- .../dockerfiles/test.dev.Dockerfile | 22 +++ .../examples/cvat/exchange-oracle/poetry.lock | 84 +------- .../cvat/exchange-oracle/pyproject.toml | 4 +- .../cvat/exchange-oracle/src/chain/escrow.py | 23 ++- .../src/core/tasks/skeletons_from_boxes.py | 2 +- .../src/endpoints/serializers.py | 30 ++- .../cvat/exchange-oracle/tests/conftest.py | 65 +++--- .../tests/integration/chain/test_escrow.py | 11 +- .../tests/integration/chain/test_kvstore.py | 3 +- ...test_process_reputation_oracle_webhooks.py | 24 +-- .../examples/cvat/recording-oracle/Dockerfile | 4 +- .../examples/cvat/recording-oracle/README.md | 44 ++++- .../cvat/recording-oracle/alembic/env.py | 6 +- .../examples/cvat/recording-oracle/debug.py | 3 +- .../docker-compose.test.head.dev.yml | 7 + .../docker-compose.test.head.yml | 37 ++++ .../recording-oracle/docker-compose.test.yml | 53 +---- .../dockerfiles/blockchain-node.Dockerfile | 21 -- .../{test.Dockerfile => test.ci.Dockerfile} | 4 +- .../dockerfiles/test.dev.Dockerfile | 22 +++ .../cvat/recording-oracle/poetry.lock | 127 +----------- .../cvat/recording-oracle/pyproject.toml | 7 +- .../cvat/recording-oracle/src/chain/escrow.py | 23 ++- .../src/core/tasks/skeletons_from_boxes.py | 2 +- .../cvat/recording-oracle/tests/conftest.py | 35 +++- .../tests/integration/chain/test_escrow.py | 187 ++++++++---------- .../tests/integration/chain/test_kvstore.py | 3 +- .../test_process_exchange_oracle_webhooks.py | 35 ++-- ...test_process_reputation_oracle_webhooks.py | 21 +- .../tests/utils/setup_escrow.py | 68 ------- .../tests/utils/setup_kvstore.py | 22 --- 42 files changed, 502 insertions(+), 644 deletions(-) create mode 100644 packages/examples/cvat/exchange-oracle/docker-compose.test.head.dev.yml create mode 100644 packages/examples/cvat/exchange-oracle/docker-compose.test.head.yml rename packages/examples/cvat/exchange-oracle/dockerfiles/{test.Dockerfile => test.ci.Dockerfile} (90%) create mode 100644 packages/examples/cvat/exchange-oracle/dockerfiles/test.dev.Dockerfile create mode 100644 packages/examples/cvat/recording-oracle/docker-compose.test.head.dev.yml create mode 100644 packages/examples/cvat/recording-oracle/docker-compose.test.head.yml delete mode 100644 packages/examples/cvat/recording-oracle/dockerfiles/blockchain-node.Dockerfile rename packages/examples/cvat/recording-oracle/dockerfiles/{test.Dockerfile => test.ci.Dockerfile} (78%) create mode 100644 packages/examples/cvat/recording-oracle/dockerfiles/test.dev.Dockerfile delete mode 100644 packages/examples/cvat/recording-oracle/tests/utils/setup_escrow.py delete mode 100644 packages/examples/cvat/recording-oracle/tests/utils/setup_kvstore.py diff --git a/.github/workflows/ci-lint-cvat-recording-oracle.yaml b/.github/workflows/ci-lint-cvat-recording-oracle.yaml index 046a857d0b..baa61a0dae 100644 --- a/.github/workflows/ci-lint-cvat-recording-oracle.yaml +++ b/.github/workflows/ci-lint-cvat-recording-oracle.yaml @@ -29,5 +29,5 @@ jobs: python-version: '3.10' cache: 'poetry' cache-dependency-path: ${{ env.WORKING_DIR }}/poetry.lock - - run: poetry install --no-root --only lint + - run: poetry install --no-root --only dev - run: poetry run pre-commit run --all-files diff --git a/.github/workflows/ci-test-cvat-exchange-oracle.yaml b/.github/workflows/ci-test-cvat-exchange-oracle.yaml index 8ec4a147ba..8f49f2b7f4 100644 --- a/.github/workflows/ci-test-cvat-exchange-oracle.yaml +++ b/.github/workflows/ci-test-cvat-exchange-oracle.yaml @@ -15,4 +15,4 @@ jobs: - uses: actions/checkout@v7 - name: CVAT Exchange Oracle tests working-directory: ./packages/examples/cvat/exchange-oracle - run: docker compose -f docker-compose.test.yml up --attach test --exit-code-from test + run: docker compose -f docker-compose.test.yml -f docker-compose.test.head.yml up --attach test --exit-code-from test diff --git a/.github/workflows/ci-test-cvat-recording-oracle.yaml b/.github/workflows/ci-test-cvat-recording-oracle.yaml index bf975f3ce1..944e079de2 100644 --- a/.github/workflows/ci-test-cvat-recording-oracle.yaml +++ b/.github/workflows/ci-test-cvat-recording-oracle.yaml @@ -15,4 +15,4 @@ jobs: - uses: actions/checkout@v7 - name: CVAT Recording Oracle tests working-directory: ./packages/examples/cvat/recording-oracle - run: docker compose -f docker-compose.test.yml up --attach test --exit-code-from test + run: docker compose -f docker-compose.test.yml -f docker-compose.test.head.yml up --attach test --exit-code-from test diff --git a/packages/examples/cvat/exchange-oracle/Dockerfile b/packages/examples/cvat/exchange-oracle/Dockerfile index 69e547480d..48a5b31fc8 100644 --- a/packages/examples/cvat/exchange-oracle/Dockerfile +++ b/packages/examples/cvat/exchange-oracle/Dockerfile @@ -6,7 +6,7 @@ RUN apt-get update -y && \ apt-get install -y jq ffmpeg libsm6 libxext6 && \ rm -rf /var/lib/apt/lists/* -RUN pip install --no-cache poetry +RUN pip install --no-cache 'poetry==1.8.5' COPY pyproject.toml poetry.lock ./ diff --git a/packages/examples/cvat/exchange-oracle/README.md b/packages/examples/cvat/exchange-oracle/README.md index d6d91ce62b..b1bcb63f6e 100644 --- a/packages/examples/cvat/exchange-oracle/README.md +++ b/packages/examples/cvat/exchange-oracle/README.md @@ -71,8 +71,47 @@ Available at `/docs` route ### Tests -To run tests +#### "oneshot" run + +A single command to build, run, and tear down the test suite: + +```sh +docker compose -p "test" \ + -f docker-compose.test.yml \ + -f docker-compose.test.head.yml \ + up --build test --attach test --exit-code-from test; \ + docker compose -p "test" \ + -f docker-compose.test.yml \ + -f docker-compose.test.head.yml \ + down +``` + +Use this option for CI and for clean single time test runs. + +#### Running separate elements + +Dev builds require faster iteration and some components may require more control. The following +commands allow running just the services, build, tear down, and run the test suite: + ```sh -docker compose -p "test" -f docker-compose.test.yml up --build test --attach test --exit-code-from test; \ - docker compose -p "test" -f docker-compose.test.yml down -``` \ No newline at end of file +# run services +docker compose -p "test" \ + -f docker-compose.test.yml \ + up -d --build + +# run the tests +docker compose -p "test" \ + -f docker-compose.test.yml \ + -f docker-compose.test.head.yml \ + -f docker-compose.test.head.dev.yml \ + up --build test --attach test --exit-code-from test + +# tear down +docker compose -p "test" \ + -f docker-compose.test.yml \ + -f docker-compose.test.head.yml \ + -f docker-compose.test.head.dev.yml \ + down +``` + +The dev setup mounts the local directory to speed the things up. diff --git a/packages/examples/cvat/exchange-oracle/alembic/env.py b/packages/examples/cvat/exchange-oracle/alembic/env.py index ac430d2eda..b642b5942c 100644 --- a/packages/examples/cvat/exchange-oracle/alembic/env.py +++ b/packages/examples/cvat/exchange-oracle/alembic/env.py @@ -12,17 +12,19 @@ config.set_main_option("sqlalchemy.url", Config.postgres_config.connection_url()) # Interpret the config file for Python logging. -# This line sets up loggers basically. if config.config_file_name is not None: - fileConfig(config.config_file_name) + fileConfig( + config.config_file_name, + disable_existing_loggers=config.attributes.get("disable_existing_loggers", True), + ) + +from src.db import Base # noqa: E402 # add your model's MetaData object here # for 'autogenerate' support # from myapp import mymodel # target_metadata = mymodel.Base.metadata -from src.db import Base # noqa: E402 - target_metadata = Base.metadata # other values from the config, defined by the needs of env.py, diff --git a/packages/examples/cvat/exchange-oracle/debug.py b/packages/examples/cvat/exchange-oracle/debug.py index f11128dd65..4b89982d89 100644 --- a/packages/examples/cvat/exchange-oracle/debug.py +++ b/packages/examples/cvat/exchange-oracle/debug.py @@ -94,10 +94,11 @@ def patched_get_escrow(chain_id: int, escrow_address: str) -> EscrowData: count=1, factory_address="", launcher="", + job_requester_id="", status="Pending", token="HMT", # noqa: S106 total_funded_amount=10, - created_at=datetime.datetime(2023, 1, 1, tzinfo=datetime.timezone.utc), + created_at=int(datetime.datetime(2023, 1, 1, tzinfo=datetime.timezone.utc).timestamp()), manifest=(f"http://{Config.storage_config.endpoint_url}/manifests/{manifest_file}"), ) diff --git a/packages/examples/cvat/exchange-oracle/docker-compose.test.head.dev.yml b/packages/examples/cvat/exchange-oracle/docker-compose.test.head.dev.yml new file mode 100644 index 0000000000..e50efbbe73 --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/docker-compose.test.head.dev.yml @@ -0,0 +1,7 @@ +services: + test: + build: + context: ./ + dockerfile: dockerfiles/test.dev.Dockerfile + volumes: + - "./:/app:ro" diff --git a/packages/examples/cvat/exchange-oracle/docker-compose.test.head.yml b/packages/examples/cvat/exchange-oracle/docker-compose.test.head.yml new file mode 100644 index 0000000000..b885070446 --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/docker-compose.test.head.yml @@ -0,0 +1,35 @@ +services: + test: + build: + context: ./ + dockerfile: dockerfiles/test.ci.Dockerfile + environment: + SQLALCHEMY_SILENCE_UBER_WARNING: 1 + ENVIRONMENT: 'test' + PG_PORT: 5432 + PG_HOST: 'postgres' + PG_USER: 'test' + PG_PASSWORD: 'test' + PG_DB: 'exchange_oracle_test' + WEB3_HTTP_PROVIDER_URI: 'http://blockchain-node:8545' + STORAGE_ENDPOINT_URL: 'host.docker.internal:9000' + STORAGE_ACCESS_KEY: 'dev' + STORAGE_SECRET_KEY: 'devdevdev' + STORAGE_RESULTS_BUCKET_NAME: 'results' + STORAGE_USE_SSL: 'False' + STORAGE_PROVIDER: 'aws' + ENABLE_CUSTOM_CLOUD_HOST: 'Yes' + REDIS_HOST: 'redis' + depends_on: + postgres: + condition: service_started + redis: + condition: service_started + minio-mc: + condition: service_completed_successfully + # Used to reference localhost since minio:9000 is rejected by the SDK URL validator + extra_hosts: + - "host.docker.internal:host-gateway" + networks: + - test-network + tty: true diff --git a/packages/examples/cvat/exchange-oracle/docker-compose.test.yml b/packages/examples/cvat/exchange-oracle/docker-compose.test.yml index f6a1ad6e3d..216ac36132 100644 --- a/packages/examples/cvat/exchange-oracle/docker-compose.test.yml +++ b/packages/examples/cvat/exchange-oracle/docker-compose.test.yml @@ -64,41 +64,6 @@ services: networks: - test-network - test: - build: - context: ./ - dockerfile: dockerfiles/test.Dockerfile - environment: - SQLALCHEMY_SILENCE_UBER_WARNING: 1 - ENVIRONMENT: 'test' - PG_PORT: 5432 - PG_HOST: 'postgres' - PG_USER: 'test' - PG_PASSWORD: 'test' - PG_DB: 'exchange_oracle_test' - WEB3_HTTP_PROVIDER_URI: 'http://blockchain-node:8545' - STORAGE_ENDPOINT_URL: 'host.docker.internal:9000' - STORAGE_ACCESS_KEY: 'dev' - STORAGE_SECRET_KEY: 'devdevdev' - STORAGE_RESULTS_BUCKET_NAME: 'results' - STORAGE_USE_SSL: 'False' - STORAGE_PROVIDER: 'aws' - ENABLE_CUSTOM_CLOUD_HOST: 'Yes' - REDIS_HOST: 'redis' - depends_on: - postgres: - condition: service_started - redis: - condition: service_started - minio-mc: - condition: service_completed_successfully - # Used to reference localhost since minio:9000 is rejected by the SDK URL validator - extra_hosts: - - "host.docker.internal:host-gateway" - networks: - - test-network - tty: true - networks: test-network: driver: bridge \ No newline at end of file diff --git a/packages/examples/cvat/exchange-oracle/dockerfiles/test.Dockerfile b/packages/examples/cvat/exchange-oracle/dockerfiles/test.ci.Dockerfile similarity index 90% rename from packages/examples/cvat/exchange-oracle/dockerfiles/test.Dockerfile rename to packages/examples/cvat/exchange-oracle/dockerfiles/test.ci.Dockerfile index eaa436f5d0..bbce75ef27 100644 --- a/packages/examples/cvat/exchange-oracle/dockerfiles/test.Dockerfile +++ b/packages/examples/cvat/exchange-oracle/dockerfiles/test.ci.Dockerfile @@ -6,7 +6,7 @@ RUN apt-get update -y && \ apt-get install -y jq ffmpeg libsm6 libxext6 && \ rm -rf /var/lib/apt/lists/* -RUN pip install --no-cache poetry +RUN pip install --no-cache 'poetry==1.8.5' COPY pyproject.toml poetry.lock ./ diff --git a/packages/examples/cvat/exchange-oracle/dockerfiles/test.dev.Dockerfile b/packages/examples/cvat/exchange-oracle/dockerfiles/test.dev.Dockerfile new file mode 100644 index 0000000000..94cdf9cf62 --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/dockerfiles/test.dev.Dockerfile @@ -0,0 +1,22 @@ +# Local dev test image: only dependencies are baked in; the source tree is bind-mounted at +# runtime by docker-compose.test.head.dev.yml. Skipping the source COPY keeps rebuilds fast when +# iterating locally. For CI / clean self-contained runs, use test.ci.Dockerfile instead. +FROM python:3.10 + +WORKDIR /app + +RUN apt-get update -y && \ + apt-get install -y jq ffmpeg libsm6 libxext6 && \ + rm -rf /var/lib/apt/lists/* + +RUN pip install --no-cache 'poetry==1.8.5' + +COPY pyproject.toml poetry.lock ./ + +RUN --mount=type=cache,target=/root/.cache \ + poetry config virtualenvs.create false && \ + poetry install --no-interaction --no-ansi --no-root + +RUN python -m pip uninstall -y poetry pip + +CMD ["pytest"] diff --git a/packages/examples/cvat/exchange-oracle/poetry.lock b/packages/examples/cvat/exchange-oracle/poetry.lock index 5f65733022..720a2f24dd 100644 --- a/packages/examples/cvat/exchange-oracle/poetry.lock +++ b/packages/examples/cvat/exchange-oracle/poetry.lock @@ -228,63 +228,6 @@ tornado = ["tornado (>=4.3)"] twisted = ["twisted"] zookeeper = ["kazoo"] -[[package]] -name = "argon2-cffi" -version = "23.1.0" -description = "Argon2 for Python" -optional = false -python-versions = ">=3.7" -files = [ - {file = "argon2_cffi-23.1.0-py3-none-any.whl", hash = "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea"}, - {file = "argon2_cffi-23.1.0.tar.gz", hash = "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08"}, -] - -[package.dependencies] -argon2-cffi-bindings = "*" - -[package.extras] -dev = ["argon2-cffi[tests,typing]", "tox (>4)"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-copybutton", "sphinx-notfound-page"] -tests = ["hypothesis", "pytest"] -typing = ["mypy"] - -[[package]] -name = "argon2-cffi-bindings" -version = "21.2.0" -description = "Low-level CFFI bindings for Argon2" -optional = false -python-versions = ">=3.6" -files = [ - {file = "argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f"}, - {file = "argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93"}, - {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194"}, - {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f"}, - {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5"}, - {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351"}, - {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7"}, - {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583"}, - {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d"}, - {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670"}, - {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb"}, - {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a"}, -] - -[package.dependencies] -cffi = ">=1.0.1" - -[package.extras] -dev = ["cogapp", "pre-commit", "pytest", "wheel"] -tests = ["pytest"] - [[package]] name = "async-timeout" version = "4.0.3" @@ -2128,20 +2071,19 @@ socks = ["socksio (==1.*)"] [[package]] name = "human-protocol-sdk" -version = "4.3.0" +version = "7.3.1" description = "A python library to launch escrow contracts to the HUMAN network." optional = false python-versions = "*" files = [ - {file = "human_protocol_sdk-4.3.0-py3-none-any.whl", hash = "sha256:498276ba47157615df7e914374fcb51f788e1892e2c169432deb2055108da525"}, - {file = "human_protocol_sdk-4.3.0.tar.gz", hash = "sha256:a1d172899c79c67d9b4266854252e02ae17f157bf1744710843e376c98c95738"}, + {file = "human_protocol_sdk-7.3.1-py3-none-any.whl", hash = "sha256:b3a410b6526f2742dad76cf866a2f6b35406631395df83e913cffa58bcc6a4db"}, + {file = "human_protocol_sdk-7.3.1.tar.gz", hash = "sha256:2df38610d2d4714373d7d0f7e30f7ca218b19746d849b2aa3a3bd0b3b2dfbdd4"}, ] [package.dependencies] aiohttp = "<4.0.0" cryptography = "*" eth-typing = "*" -minio = "*" pgpy = "*" validators = "*" web3 = "*" @@ -2590,24 +2532,6 @@ files = [ {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, ] -[[package]] -name = "minio" -version = "7.2.15" -description = "MinIO Python SDK for Amazon S3 Compatible Cloud Storage" -optional = false -python-versions = ">=3.9" -files = [ - {file = "minio-7.2.15-py3-none-any.whl", hash = "sha256:c06ef7a43e5d67107067f77b6c07ebdd68733e5aa7eed03076472410ca19d876"}, - {file = "minio-7.2.15.tar.gz", hash = "sha256:5247df5d4dca7bfa4c9b20093acd5ad43e82d8710ceb059d79c6eea970f49f79"}, -] - -[package.dependencies] -argon2-cffi = "*" -certifi = "*" -pycryptodome = "*" -typing-extensions = "*" -urllib3 = "*" - [[package]] name = "msgpack" version = "1.1.0" @@ -5070,4 +4994,4 @@ propcache = ">=0.2.0" [metadata] lock-version = "2.0" python-versions = "^3.10,<3.13" -content-hash = "d4b0b2cd3671d6e118b5fe545fe3ec2e69e9345bf321443ebf7f34368c085ab4" +content-hash = "84f9ce0ad56ffab8a5101eba4d9102f9df7d27d3663fdc08aaeafa49f7f467ab" diff --git a/packages/examples/cvat/exchange-oracle/pyproject.toml b/packages/examples/cvat/exchange-oracle/pyproject.toml index 7ca5e23a21..428e3a87f4 100644 --- a/packages/examples/cvat/exchange-oracle/pyproject.toml +++ b/packages/examples/cvat/exchange-oracle/pyproject.toml @@ -15,7 +15,6 @@ psycopg2 = "^2.9.6" sqlalchemy-utils = "^0.41.1" alembic = "^1.11.1" httpx = "^0.24.1" -pytest = "^7.2.2" cvat-sdk = "2.37.0" sqlalchemy = "^2.0.16" apscheduler = "^3.10.1" @@ -35,12 +34,13 @@ starlette = ">=0.40.0" # avoid the vulnerability with multipart/form-data cryptography = "<44.0.0" # human-protocol-sdk -> pgpy dep requires cryptography < 45 aiocache = {extras = ["msgpack", "redis"], version = "^0.12.3"} # convenient api for redis (async) cachelib = "^0.13.0" # convenient api for redis (sync) -human-protocol-sdk = "^4.3.0" +human-protocol-sdk = "^7.3.1" [tool.poetry.group.dev.dependencies] pre-commit = "^3.0.4" ruff = "^0.6.0" +pytest = "^7.2.2" pytest-mock = "^3.14.0" [tool.ruff] diff --git a/packages/examples/cvat/exchange-oracle/src/chain/escrow.py b/packages/examples/cvat/exchange-oracle/src/chain/escrow.py index cae6250c8c..df4deed4ad 100644 --- a/packages/examples/cvat/exchange-oracle/src/chain/escrow.py +++ b/packages/examples/cvat/exchange-oracle/src/chain/escrow.py @@ -1,10 +1,11 @@ import json from functools import partial +import httpx from human_protocol_sdk.constants import ChainId, Status from human_protocol_sdk.encryption import Encryption, EncryptionUtils from human_protocol_sdk.escrow import EscrowData, EscrowUtils -from human_protocol_sdk.storage import StorageUtils +from human_protocol_sdk.utils import validate_url from src.chain.web3 import get_token_symbol from src.core.config import Config @@ -12,6 +13,24 @@ from src.services.cache import Cache +class ManifestNotAvailableError(Exception): + """Raised when the escrow manifest cannot be retrieved.""" + + +def _get_manifest_content(manifest: str) -> str: + if validate_url(manifest): + try: + response = httpx.get(manifest, follow_redirects=True) + response.raise_for_status() + except Exception as e: + raise ManifestNotAvailableError( + f"failed to download manifest from {manifest}: {e}" + ) from e + return response.text + + return manifest + + def get_escrow(chain_id: int, escrow_address: str) -> EscrowData: escrow = EscrowUtils.get_escrow(ChainId(chain_id), escrow_address) if not escrow: @@ -48,7 +67,7 @@ def validate_escrow( def download_manifest(chain_id: int, escrow_address: str) -> dict: escrow = get_escrow(chain_id, escrow_address) - manifest_content = StorageUtils.download_file_from_url(escrow.manifest).decode("utf-8") + manifest_content = _get_manifest_content(escrow.manifest) if EncryptionUtils.is_encrypted(manifest_content): encryption = Encryption( diff --git a/packages/examples/cvat/exchange-oracle/src/core/tasks/skeletons_from_boxes.py b/packages/examples/cvat/exchange-oracle/src/core/tasks/skeletons_from_boxes.py index 7459b904cb..0809d65316 100644 --- a/packages/examples/cvat/exchange-oracle/src/core/tasks/skeletons_from_boxes.py +++ b/packages/examples/cvat/exchange-oracle/src/core/tasks/skeletons_from_boxes.py @@ -29,7 +29,7 @@ class RoiInfo: # RoI is centered on the bbox center # Coordinates can be out of image boundaries. - # In this case RoI includes extra margins to be centered on bbox center + # In this case RoI includes extra margins to be centered on bbox center. roi_x: int roi_y: int roi_w: int diff --git a/packages/examples/cvat/exchange-oracle/src/endpoints/serializers.py b/packages/examples/cvat/exchange-oracle/src/endpoints/serializers.py index 219d40af40..05b01ffb80 100644 --- a/packages/examples/cvat/exchange-oracle/src/endpoints/serializers.py +++ b/packages/examples/cvat/exchange-oracle/src/endpoints/serializers.py @@ -1,16 +1,18 @@ from contextlib import ExitStack, suppress -from typing import Literal -from human_protocol_sdk.storage import StorageFileNotFoundError from sqlalchemy.orm import Session import src.services.cvat as cvat_service -from src.chain.escrow import get_escrow_fund_token_symbol, get_escrow_manifest -from src.core.manifest import TaskManifest +from src.chain.escrow import ( + ManifestNotAvailableError, + get_escrow_fund_token_symbol, + get_escrow_manifest, +) +from src.core.manifest import parse_manifest from src.core.types import AssignmentStatuses, ProjectStatuses from src.db import SessionLocal from src.schemas import exchange as service_api -from src.utils.assignments import compose_assignment_url, parse_manifest +from src.utils.assignments import compose_assignment_url PROJECT_COMPLETED_STATUSES = { ProjectStatuses.recorded, @@ -21,7 +23,6 @@ def serialize_job( project: str | cvat_service.Project, *, - manifest: None | TaskManifest | Literal[False] = None, session: Session | None = None, ) -> service_api.JobResponse: with ExitStack() as es: @@ -37,11 +38,8 @@ def serialize_job( f"or a cvat_service.Project instance, not {project!r}" ) - if manifest is None: - with suppress(StorageFileNotFoundError): - manifest = parse_manifest( - get_escrow_manifest(project.chain_id, project.escrow_address) - ) + with suppress(ManifestNotAvailableError): + manifest = parse_manifest(get_escrow_manifest(project.chain_id, project.escrow_address)) if project.status == ProjectStatuses.canceled: api_status = service_api.JobStatuses.canceled @@ -63,7 +61,7 @@ def serialize_job( reward_token=reward_token, created_at=project.created_at, updated_at=project.updated_at, - qualifications=manifest.annotation.qualifications, + qualifications=manifest.annotation.qualifications if manifest else [], ) @@ -78,7 +76,6 @@ def serialize_assignment( assignment: str | cvat_service.Assignment, *, project: None | str | cvat_service.Project = None, - manifest: None | TaskManifest | Literal[False] = None, session: Session | None = None, ) -> service_api.AssignmentResponse: with ExitStack() as es: @@ -104,11 +101,8 @@ def serialize_assignment( f"or a cvat_service.Project instance, not {project!r}" ) - if manifest is None: - with suppress(StorageFileNotFoundError): - manifest = parse_manifest( - get_escrow_manifest(project.chain_id, project.escrow_address) - ) + with suppress(ManifestNotAvailableError): + manifest = parse_manifest(get_escrow_manifest(project.chain_id, project.escrow_address)) assignment_status_mapping = { AssignmentStatuses.created: service_api.AssignmentStatuses.active, diff --git a/packages/examples/cvat/exchange-oracle/tests/conftest.py b/packages/examples/cvat/exchange-oracle/tests/conftest.py index 058049d12d..c2b92ac0ed 100644 --- a/packages/examples/cvat/exchange-oracle/tests/conftest.py +++ b/packages/examples/cvat/exchange-oracle/tests/conftest.py @@ -8,16 +8,19 @@ import pytest from fastapi.testclient import TestClient -from sqlalchemy import TextClause, text +from sqlalchemy import TextClause, inspect, text from sqlalchemy.orm import Session from sqlalchemy_utils import create_database, database_exists, drop_database from alembic import command as alembic_command from alembic.config import Config from src import app -from src.db import SessionLocal, engine +from src.db import Base, SessionLocal, engine alembic_config = Config(Path(__file__).parent.parent / "alembic.ini") +# Don't let Alembic's fileConfig() disable the app's loggers when migrations run in-process, +# otherwise swallowed cron/webhook handler errors are hidden from the pytest report. +alembic_config.attributes["disable_existing_loggers"] = False @dataclass @@ -49,39 +52,49 @@ def setup_db(alembic) -> None: if database_exists(engine.url): drop_database(engine.url) create_database(engine.url) - yield # Run the test cases - # Upgrade to the latest version after all tests are done, - # this helps with inspection of the latest schema. - with engine.connect() as connection: - connection.execute(alembic.upgrade) - - -@pytest.fixture(autouse=True) -def init_db(alembic) -> None: - """ - Runs the recorded Alembic upgrade and downgrade SQL for each test. - This ensures correctness of alembic migrations. - """ + # Apply the schema once for the whole session. Per-test resets only truncate the DB. try: with engine.connect() as connection: + # Validate the migration round-trip once + connection.execute(alembic.upgrade) + connection.execute(alembic.downgrade) + connection.execute(alembic.upgrade) except Exception as e: raise RuntimeError( - "Failed to upgrade migrations, `alembic upgrade head` would fail." - " inspect the cause error and change migrations accordingly." + "Alembic migrations must upgrade and downgrade cleanly " + "(`alembic upgrade head` / `alembic downgrade base`). Fix the migrations." ) from e - yield # Run the test case + # The per-test cleanup only DELETEs rows; it does not reset sequences. Guard that assumption so + # that a future migration adding a serial/identity column fails loudly here rather than silently + # leaking sequence state (e.g. auto-increment ids) across tests. + sequences = inspect(engine).get_sequence_names() + assert not sequences, ( + f"Found DB sequences {sequences}: the per-test cleanup DELETEs rows without resetting " + "sequences, so ids would leak between tests. Reset them per test (e.g. TRUNCATE ... " + "RESTART IDENTITY, or ALTER SEQUENCE) and update the cleanup." + ) + + +# Clear every table between tests. DELETE in reverse dependency order is dramatically faster than +# TRUNCATE on this schema: TRUNCATE does per-table file truncation + fsync (~270ms for all tables), +# while DELETE on already-empty tables is ~0. No table uses an autoincrement primary key, so there +# are no sequences to reset (guarded in setup_db). Each DELETE is a single SQL expression. +_CLEANUP_SQL = text( + ";\n".join( + str(table.delete().compile(dialect=engine.dialect)) + for table in reversed(Base.metadata.sorted_tables) + ) +) - try: - with engine.connect() as connection: - connection.execute(alembic.downgrade) - except Exception as e: - raise RuntimeError( - "Failed to downgrade migrations, `alembic downgrade head:base` would fail." - " inspect the cause error and change migrations accordingly." - ) from e + +@pytest.fixture(autouse=True) +def init_db() -> None: + """Reset the database to an empty, migrated schema before each test.""" + with engine.begin() as connection: + connection.execute(_CLEANUP_SQL) @pytest.fixture(scope="module") diff --git a/packages/examples/cvat/exchange-oracle/tests/integration/chain/test_escrow.py b/packages/examples/cvat/exchange-oracle/tests/integration/chain/test_escrow.py index c2569a6861..d1b68d29ed 100644 --- a/packages/examples/cvat/exchange-oracle/tests/integration/chain/test_escrow.py +++ b/packages/examples/cvat/exchange-oracle/tests/integration/chain/test_escrow.py @@ -43,10 +43,11 @@ def setUp(self): count=0, factory_address=FACTORY_ADDRESS, launcher=JOB_LAUNCHER_ADDRESS, + job_requester_id=JOB_LAUNCHER_ADDRESS, status=Status.Pending.name, token=TOKEN_ADDRESS, total_funded_amount=1000, - created_at="", + created_at="0", recording_oracle=RECORDING_ORACLE_ADDRESS, exchange_oracle=EXCHANGE_ORACLE_ADDRESS, reputation_oracle=REPUTATION_ORACLE_ADDRESS, @@ -83,9 +84,9 @@ def test_validate_escrow_without_funds(self): def test_get_escrow_manifest(self): with ( patch("src.chain.escrow.EscrowUtils.get_escrow") as mock_function, - patch("src.chain.escrow.StorageUtils.download_file_from_url") as mock_download, + patch("src.chain.escrow._get_manifest_content") as mock_download, ): - mock_download.return_value = json.dumps({"title": "test"}).encode() + mock_download.return_value = json.dumps({"title": "test"}) mock_function.return_value = self.escrow_data manifest = get_escrow_manifest(chain_id, escrow_address) assert isinstance(manifest, dict) @@ -94,7 +95,7 @@ def test_get_escrow_manifest(self): def test_get_encrypted_escrow_manifest(self): with ( patch("src.chain.escrow.EscrowUtils.get_escrow") as mock_function, - patch("src.chain.escrow.StorageUtils.download_file_from_url") as mock_download, + patch("src.chain.escrow._get_manifest_content") as mock_download, patch("src.core.config.Config.encryption_config.pgp_private_key", PGP_PRIVATE_KEY1), patch("src.core.config.Config.encryption_config.pgp_passphrase", PGP_PASSPHRASE), patch( @@ -112,7 +113,7 @@ def test_get_encrypted_escrow_manifest(self): ) assert encrypted_manifest != original_manifest - mock_download.return_value = encrypted_manifest.encode() + mock_download.return_value = encrypted_manifest downloaded_manifest_content = get_escrow_manifest(chain_id, escrow_address) assert downloaded_manifest_content == original_manifest_content diff --git a/packages/examples/cvat/exchange-oracle/tests/integration/chain/test_kvstore.py b/packages/examples/cvat/exchange-oracle/tests/integration/chain/test_kvstore.py index 86438fbedb..8c65f49917 100644 --- a/packages/examples/cvat/exchange-oracle/tests/integration/chain/test_kvstore.py +++ b/packages/examples/cvat/exchange-oracle/tests/integration/chain/test_kvstore.py @@ -40,10 +40,11 @@ def setup(self): count=0, factory_address=FACTORY_ADDRESS, launcher=JOB_LAUNCHER_ADDRESS, + job_requester_id=JOB_LAUNCHER_ADDRESS, status=Status.Pending.name, token=TOKEN_ADDRESS, total_funded_amount=1000, - created_at="", + created_at="0", recording_oracle=RECORDING_ORACLE_ADDRESS, reputation_oracle=REPUTATION_ORACLE_ADDRESS, ) diff --git a/packages/examples/cvat/exchange-oracle/tests/integration/cron/test_process_reputation_oracle_webhooks.py b/packages/examples/cvat/exchange-oracle/tests/integration/cron/test_process_reputation_oracle_webhooks.py index 1638fbcaba..380ed680b6 100644 --- a/packages/examples/cvat/exchange-oracle/tests/integration/cron/test_process_reputation_oracle_webhooks.py +++ b/packages/examples/cvat/exchange-oracle/tests/integration/cron/test_process_reputation_oracle_webhooks.py @@ -144,10 +144,10 @@ def test_process_incoming_reputation_oracle_webhook_escrow_completed( mocker.call(prefix=compose_data_bucket_prefix(escrow_address, chain_id)), mocker.call(prefix=compose_results_bucket_prefix(escrow_address, chain_id)), ] - assert delete_project_mock.mock_calls == [ - mocker.call(project1.cvat_id), - mocker.call(project2.cvat_id), - ] + assert {c.args[0] for c in delete_project_mock.mock_calls} == { + project1.cvat_id, + project2.cvat_id, + } assert delete_cloudstorage_mock.mock_calls == [mocker.call(1)] outgoing_webhooks = list( @@ -197,10 +197,10 @@ def test_process_incoming_reputation_oracle_webhooks_escrow_completed_exceptions mocker.call(prefix=compose_data_bucket_prefix(escrow_address, chain_id)), mocker.call(prefix=compose_results_bucket_prefix(escrow_address, chain_id)), ] - assert delete_project_mock.mock_calls == [ - mocker.call(project1.cvat_id), - mocker.call(project2.cvat_id), - ] + assert {c.args[0] for c in delete_project_mock.mock_calls} == { + project1.cvat_id, + project2.cvat_id, + } assert delete_cloudstorage_mock.mock_calls == [mocker.call(1)] outgoing_webhooks = list( @@ -229,10 +229,10 @@ def test_process_incoming_reputation_oracle_webhooks_escrow_completed_exceptions mocker.call(prefix=compose_data_bucket_prefix(escrow_address, chain_id)), mocker.call(prefix=compose_results_bucket_prefix(escrow_address, chain_id)), ] - assert delete_project_mock.mock_calls == [ - mocker.call(project1.cvat_id), - mocker.call(project2.cvat_id), - ] + assert {c.args[0] for c in delete_project_mock.mock_calls} == { + project1.cvat_id, + project2.cvat_id, + } outgoing_webhooks = list( session.scalars( diff --git a/packages/examples/cvat/recording-oracle/Dockerfile b/packages/examples/cvat/recording-oracle/Dockerfile index 69e547480d..bdc0dd597c 100644 --- a/packages/examples/cvat/recording-oracle/Dockerfile +++ b/packages/examples/cvat/recording-oracle/Dockerfile @@ -3,10 +3,10 @@ FROM python:3.10 WORKDIR /app RUN apt-get update -y && \ - apt-get install -y jq ffmpeg libsm6 libxext6 && \ + apt-get install -y jq libgl1 libsm6 libxext6 && \ rm -rf /var/lib/apt/lists/* -RUN pip install --no-cache poetry +RUN pip install --no-cache 'poetry==1.8.5' COPY pyproject.toml poetry.lock ./ diff --git a/packages/examples/cvat/recording-oracle/README.md b/packages/examples/cvat/recording-oracle/README.md index 6b412f5081..77bee0b36d 100644 --- a/packages/examples/cvat/recording-oracle/README.md +++ b/packages/examples/cvat/recording-oracle/README.md @@ -68,8 +68,46 @@ Available at `/docs` route ### Tests -To run tests +#### "oneshot" run + +A single command to build, run, and tear down the test suite: + ```sh -docker compose -p "test" -f docker-compose.test.yml up --build test --attach test --exit-code-from test; \ - docker compose -p "test" -f docker-compose.test.yml down +docker compose -p "test" \ + -f docker-compose.test.yml \ + -f docker-compose.test.head.yml \ + up --build test --attach test --exit-code-from test; \ + docker compose -p "test" \ + -f docker-compose.test.yml \ + -f docker-compose.test.head.yml down ``` + +Use this option for CI and for clean single time test runs. + +#### Running separate elements + +Dev builds require faster iteration and some components may require more control. The following +commands allow running just the services, build, tear down, and run the test suite: + +```sh +# run services +docker compose -p "test" \ + -f docker-compose.test.yml \ + up -d --build + +# run the tests +docker compose -p "test" \ + -f docker-compose.test.yml \ + -f docker-compose.test.head.yml \ + -f docker-compose.test.head.dev.yml \ + up --build test --attach test --exit-code-from test + +# tear down +docker compose -p "test" \ + -f docker-compose.test.yml \ + -f docker-compose.test.head.yml \ + -f docker-compose.test.head.dev.yml \ + down +``` + +The dev setup mounts the local directory to speed the things up. diff --git a/packages/examples/cvat/recording-oracle/alembic/env.py b/packages/examples/cvat/recording-oracle/alembic/env.py index 1e85b134f0..fde70d21e7 100644 --- a/packages/examples/cvat/recording-oracle/alembic/env.py +++ b/packages/examples/cvat/recording-oracle/alembic/env.py @@ -12,9 +12,11 @@ config.set_main_option("sqlalchemy.url", Config.postgres_config.connection_url()) # Interpret the config file for Python logging. -# This line sets up loggers basically. if config.config_file_name is not None: - fileConfig(config.config_file_name) + fileConfig( + config.config_file_name, + disable_existing_loggers=config.attributes.get("disable_existing_loggers", True), + ) from src.db import Base # noqa: E402 diff --git a/packages/examples/cvat/recording-oracle/debug.py b/packages/examples/cvat/recording-oracle/debug.py index 4a8d40a42c..37c00dbd9a 100644 --- a/packages/examples/cvat/recording-oracle/debug.py +++ b/packages/examples/cvat/recording-oracle/debug.py @@ -58,10 +58,11 @@ def patched_get_escrow(chain_id: int, escrow_address: str) -> EscrowData: count=1, factory_address="", launcher="", + job_requester_id="", status="Pending", token="HMT", # noqa: S106 total_funded_amount=10, - created_at=datetime.datetime(2023, 1, 1, tzinfo=datetime.timezone.utc), + created_at=int(datetime.datetime(2023, 1, 1, tzinfo=datetime.timezone.utc).timestamp()), manifest=(f"http://{Config.storage_config.endpoint_url}/manifests/{manifest_file}"), ) diff --git a/packages/examples/cvat/recording-oracle/docker-compose.test.head.dev.yml b/packages/examples/cvat/recording-oracle/docker-compose.test.head.dev.yml new file mode 100644 index 0000000000..e50efbbe73 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/docker-compose.test.head.dev.yml @@ -0,0 +1,7 @@ +services: + test: + build: + context: ./ + dockerfile: dockerfiles/test.dev.Dockerfile + volumes: + - "./:/app:ro" diff --git a/packages/examples/cvat/recording-oracle/docker-compose.test.head.yml b/packages/examples/cvat/recording-oracle/docker-compose.test.head.yml new file mode 100644 index 0000000000..044c537d3b --- /dev/null +++ b/packages/examples/cvat/recording-oracle/docker-compose.test.head.yml @@ -0,0 +1,37 @@ +services: + test: + build: + context: ./ + dockerfile: dockerfiles/test.ci.Dockerfile + environment: + SQLALCHEMY_SILENCE_UBER_WARNING: 1 + ENVIRONMENT: 'test' + PG_PORT: 5432 + PG_HOST: 'postgres' + PG_USER: 'test' + PG_PASSWORD: 'test' + PG_DB: 'recording_oracle_test' + WEB3_HTTP_PROVIDER_URI: 'http://localhost:8545' + STORAGE_ENDPOINT_URL: 'host.docker.internal:9000' + STORAGE_ACCESS_KEY: 'dev' + STORAGE_SECRET_KEY: 'devdevdev' + STORAGE_RESULTS_BUCKET_NAME: 'results' + STORAGE_PROVIDER: 'aws' + STORAGE_USE_SSL: False + EXCHANGE_ORACLE_STORAGE_ENDPOINT_URL: 'host.docker.internal:9000' + EXCHANGE_ORACLE_STORAGE_ACCESS_KEY: 'dev' + EXCHANGE_ORACLE_STORAGE_SECRET_KEY: 'devdevdev' + EXCHANGE_ORACLE_STORAGE_RESULTS_BUCKET_NAME: 'results' + EXCHANGE_ORACLE_STORAGE_USE_SSL: False + EXCHANGE_ORACLE_STORAGE_PROVIDER: 'aws' + depends_on: + postgres: + condition: service_started + minio-mc: + condition: service_completed_successfully + # Used to reference localhost since minio:9000 is rejected by the SDK URL validator. + extra_hosts: + - "host.docker.internal:host-gateway" + networks: + - test-network + tty: true diff --git a/packages/examples/cvat/recording-oracle/docker-compose.test.yml b/packages/examples/cvat/recording-oracle/docker-compose.test.yml index 2d7ca3d412..82c78ff286 100644 --- a/packages/examples/cvat/recording-oracle/docker-compose.test.yml +++ b/packages/examples/cvat/recording-oracle/docker-compose.test.yml @@ -11,18 +11,6 @@ services: networks: - test-network - blockchain-node: - build: - context: ../../../../ - dockerfile: docker-setup/Dockerfile.core - healthcheck: - test: yarn local:readiness - interval: 15s - timeout: 30s - retries: 0 - networks: - - test-network - minio: container_name: minio image: minio/minio:RELEASE.2022-05-26T05-48-41Z @@ -58,45 +46,6 @@ services: networks: - test-network - test: - build: - context: ./ - dockerfile: dockerfiles/test.Dockerfile - environment: - SQLALCHEMY_SILENCE_UBER_WARNING: 1 - ENVIRONMENT: 'test' - PG_PORT: 5432 - PG_HOST: 'postgres' - PG_USER: 'test' - PG_PASSWORD: 'test' - PG_DB: 'recording_oracle_test' - WEB3_HTTP_PROVIDER_URI: 'http://blockchain-node:8545' - STORAGE_ENDPOINT_URL: 'host.docker.internal:9000' - STORAGE_ACCESS_KEY: 'dev' - STORAGE_SECRET_KEY: 'devdevdev' - STORAGE_RESULTS_BUCKET_NAME: 'results' - STORAGE_PROVIDER: 'aws' - STORAGE_USE_SSL: False - EXCHANGE_ORACLE_STORAGE_ENDPOINT_URL: 'host.docker.internal:9000' - EXCHANGE_ORACLE_STORAGE_ACCESS_KEY: 'dev' - EXCHANGE_ORACLE_STORAGE_SECRET_KEY: 'devdevdev' - EXCHANGE_ORACLE_STORAGE_RESULTS_BUCKET_NAME: 'results' - EXCHANGE_ORACLE_STORAGE_USE_SSL: False - EXCHANGE_ORACLE_STORAGE_PROVIDER: 'aws' - depends_on: - postgres: - condition: service_started - blockchain-node: - condition: service_healthy - minio-mc: - condition: service_completed_successfully - # Used to reference localhost since minio:9000 is rejected by the SDK URL validator. - extra_hosts: - - "host.docker.internal:host-gateway" - networks: - - test-network - tty: true - networks: test-network: - driver: bridge \ No newline at end of file + driver: bridge diff --git a/packages/examples/cvat/recording-oracle/dockerfiles/blockchain-node.Dockerfile b/packages/examples/cvat/recording-oracle/dockerfiles/blockchain-node.Dockerfile deleted file mode 100644 index a4f747cc28..0000000000 --- a/packages/examples/cvat/recording-oracle/dockerfiles/blockchain-node.Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -# TODO: make this shared and part of local setup -FROM node:24.13-slim - -# curl is needed for healthcheck -RUN apt-get update && apt-get install -y curl - -WORKDIR /usr/src/app - -# Copy expected yarn dist -COPY .yarn ./.yarn -COPY .yarnrc.yml ./ -# Copy files for deps installation -COPY package.json yarn.lock ./ - -COPY tsconfig.base.json ./ -COPY packages/core ./packages/core -RUN yarn workspace @human-protocol/core install -RUN yarn workspace @human-protocol/core build - -EXPOSE 8545 -CMD yarn workspace @human-protocol/core local diff --git a/packages/examples/cvat/recording-oracle/dockerfiles/test.Dockerfile b/packages/examples/cvat/recording-oracle/dockerfiles/test.ci.Dockerfile similarity index 78% rename from packages/examples/cvat/recording-oracle/dockerfiles/test.Dockerfile rename to packages/examples/cvat/recording-oracle/dockerfiles/test.ci.Dockerfile index eaa436f5d0..1c39e52f2a 100644 --- a/packages/examples/cvat/recording-oracle/dockerfiles/test.Dockerfile +++ b/packages/examples/cvat/recording-oracle/dockerfiles/test.ci.Dockerfile @@ -3,10 +3,10 @@ FROM python:3.10 WORKDIR /app RUN apt-get update -y && \ - apt-get install -y jq ffmpeg libsm6 libxext6 && \ + apt-get install -y jq libgl1 libsm6 libxext6 && \ rm -rf /var/lib/apt/lists/* -RUN pip install --no-cache poetry +RUN pip install --no-cache 'poetry==1.8.5' COPY pyproject.toml poetry.lock ./ diff --git a/packages/examples/cvat/recording-oracle/dockerfiles/test.dev.Dockerfile b/packages/examples/cvat/recording-oracle/dockerfiles/test.dev.Dockerfile new file mode 100644 index 0000000000..fe1143c473 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/dockerfiles/test.dev.Dockerfile @@ -0,0 +1,22 @@ +# Local dev test image: only dependencies are baked in; the source tree is bind-mounted at +# runtime by docker-compose.test.head.dev.yml. Skipping the source COPY keeps rebuilds fast when +# iterating locally. For CI / clean self-contained runs, use test.ci.Dockerfile instead. +FROM python:3.10 + +WORKDIR /app + +RUN apt-get update -y && \ + apt-get install -y jq libgl1 libsm6 libxext6 && \ + rm -rf /var/lib/apt/lists/* + +RUN pip install --no-cache 'poetry==1.8.5' + +COPY pyproject.toml poetry.lock ./ + +RUN --mount=type=cache,target=/root/.cache \ + poetry config virtualenvs.create false && \ + poetry install --no-interaction --no-ansi --no-root + +RUN python -m pip uninstall -y poetry pip + +CMD ["pytest"] diff --git a/packages/examples/cvat/recording-oracle/poetry.lock b/packages/examples/cvat/recording-oracle/poetry.lock index a6883c0a02..d467345a9f 100644 --- a/packages/examples/cvat/recording-oracle/poetry.lock +++ b/packages/examples/cvat/recording-oracle/poetry.lock @@ -208,63 +208,6 @@ tornado = ["tornado (>=4.3)"] twisted = ["twisted"] zookeeper = ["kazoo"] -[[package]] -name = "argon2-cffi" -version = "23.1.0" -description = "Argon2 for Python" -optional = false -python-versions = ">=3.7" -files = [ - {file = "argon2_cffi-23.1.0-py3-none-any.whl", hash = "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea"}, - {file = "argon2_cffi-23.1.0.tar.gz", hash = "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08"}, -] - -[package.dependencies] -argon2-cffi-bindings = "*" - -[package.extras] -dev = ["argon2-cffi[tests,typing]", "tox (>4)"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-copybutton", "sphinx-notfound-page"] -tests = ["hypothesis", "pytest"] -typing = ["mypy"] - -[[package]] -name = "argon2-cffi-bindings" -version = "21.2.0" -description = "Low-level CFFI bindings for Argon2" -optional = false -python-versions = ">=3.6" -files = [ - {file = "argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082"}, - {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f"}, - {file = "argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93"}, - {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194"}, - {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f"}, - {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5"}, - {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351"}, - {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7"}, - {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583"}, - {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d"}, - {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670"}, - {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb"}, - {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a"}, -] - -[package.dependencies] -cffi = ">=1.0.1" - -[package.extras] -dev = ["cogapp", "pre-commit", "pytest", "wheel"] -tests = ["pytest"] - [[package]] name = "async-timeout" version = "5.0.1" @@ -2031,20 +1974,19 @@ socks = ["socksio (==1.*)"] [[package]] name = "human-protocol-sdk" -version = "4.3.0" +version = "7.3.1" description = "A python library to launch escrow contracts to the HUMAN network." optional = false python-versions = "*" files = [ - {file = "human_protocol_sdk-4.3.0-py3-none-any.whl", hash = "sha256:498276ba47157615df7e914374fcb51f788e1892e2c169432deb2055108da525"}, - {file = "human_protocol_sdk-4.3.0.tar.gz", hash = "sha256:a1d172899c79c67d9b4266854252e02ae17f157bf1744710843e376c98c95738"}, + {file = "human_protocol_sdk-7.3.1-py3-none-any.whl", hash = "sha256:b3a410b6526f2742dad76cf866a2f6b35406631395df83e913cffa58bcc6a4db"}, + {file = "human_protocol_sdk-7.3.1.tar.gz", hash = "sha256:2df38610d2d4714373d7d0f7e30f7ca218b19746d849b2aa3a3bd0b3b2dfbdd4"}, ] [package.dependencies] aiohttp = "<4.0.0" cryptography = "*" eth-typing = "*" -minio = "*" pgpy = "*" validators = "*" web3 = "*" @@ -2052,38 +1994,6 @@ web3 = "*" [package.extras] agreement = ["numpy", "pyerf"] -[[package]] -name = "hypothesis" -version = "6.97.3" -description = "A library for property-based testing" -optional = false -python-versions = ">=3.8" -files = [ - {file = "hypothesis-6.97.3-py3-none-any.whl", hash = "sha256:6256d768ec866426bfce6ed78418c6e3e43119a0dbece2e0229a1ae5929ae53d"}, - {file = "hypothesis-6.97.3.tar.gz", hash = "sha256:00216ddadaee17ba73451e262f973970a97d34fd75ec34ef57510147264c34d1"}, -] - -[package.dependencies] -attrs = ">=22.2.0" -exceptiongroup = {version = ">=1.0.0", markers = "python_version < \"3.11\""} -sortedcontainers = ">=2.1.0,<3.0.0" - -[package.extras] -all = ["backports.zoneinfo (>=0.2.1)", "black (>=19.10b0)", "click (>=7.0)", "django (>=3.2)", "dpcontracts (>=0.4)", "lark (>=0.10.1)", "libcst (>=0.3.16)", "numpy (>=1.17.3)", "pandas (>=1.1)", "pytest (>=4.6)", "python-dateutil (>=1.4)", "pytz (>=2014.1)", "redis (>=3.0.0)", "rich (>=9.0.0)", "tzdata (>=2023.4)"] -cli = ["black (>=19.10b0)", "click (>=7.0)", "rich (>=9.0.0)"] -codemods = ["libcst (>=0.3.16)"] -dateutil = ["python-dateutil (>=1.4)"] -django = ["django (>=3.2)"] -dpcontracts = ["dpcontracts (>=0.4)"] -ghostwriter = ["black (>=19.10b0)"] -lark = ["lark (>=0.10.1)"] -numpy = ["numpy (>=1.17.3)"] -pandas = ["pandas (>=1.1)"] -pytest = ["pytest (>=4.6)"] -pytz = ["pytz (>=2014.1)"] -redis = ["redis (>=3.0.0)"] -zoneinfo = ["backports.zoneinfo (>=0.2.1)", "tzdata (>=2023.4)"] - [[package]] name = "identify" version = "2.5.33" @@ -2525,24 +2435,6 @@ files = [ {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, ] -[[package]] -name = "minio" -version = "7.2.15" -description = "MinIO Python SDK for Amazon S3 Compatible Cloud Storage" -optional = false -python-versions = ">=3.9" -files = [ - {file = "minio-7.2.15-py3-none-any.whl", hash = "sha256:c06ef7a43e5d67107067f77b6c07ebdd68733e5aa7eed03076472410ca19d876"}, - {file = "minio-7.2.15.tar.gz", hash = "sha256:5247df5d4dca7bfa4c9b20093acd5ad43e82d8710ceb059d79c6eea970f49f79"}, -] - -[package.dependencies] -argon2-cffi = "*" -certifi = "*" -pycryptodome = "*" -typing-extensions = "*" -urllib3 = "*" - [[package]] name = "multidict" version = "6.1.0" @@ -4043,17 +3935,6 @@ files = [ {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, ] -[[package]] -name = "sortedcontainers" -version = "2.4.0" -description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" -optional = false -python-versions = "*" -files = [ - {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, - {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, -] - [[package]] name = "sqlalchemy" version = "2.0.25" @@ -4755,4 +4636,4 @@ propcache = ">=0.2.0" [metadata] lock-version = "2.0" python-versions = "^3.10, <3.13" -content-hash = "82157c082fb82718a5e092b999f14d3c18ca27a2acfb198101e5dcae6c94e42a" +content-hash = "7b255d62870b43bd42bf9b686e94e5dbbda9929f4a503d6b5e6e91c8ca2627f4" diff --git a/packages/examples/cvat/recording-oracle/pyproject.toml b/packages/examples/cvat/recording-oracle/pyproject.toml index e332a910e5..b51dab8f05 100644 --- a/packages/examples/cvat/recording-oracle/pyproject.toml +++ b/packages/examples/cvat/recording-oracle/pyproject.toml @@ -14,7 +14,6 @@ python-dotenv = "^1.0.0" SQLAlchemy = "^2.0.17" psycopg2 = "^2.9.6" APScheduler = "^3.10.1" -pytest = "^7.4.0" alembic = "^1.11.1" pydantic = ">=2.6.1,<2.7.0" httpx = "^0.24.1" @@ -26,12 +25,10 @@ hexbytes = ">=1.2.0" # required for to_0x_hex() function starlette = ">=0.40.0" # avoid the vulnerability with multipart/form-data cvat-sdk = "2.37.0" cryptography = "<44.0.0" # human-protocol-sdk -> pgpy dep requires cryptography < 45 -human-protocol-sdk = "^4.3.0" +human-protocol-sdk = "^7.3.1" [tool.poetry.group.dev.dependencies] -hypothesis = "^6.82.6" - -[tool.poetry.group.lint.dependencies] +pytest = "^7.4.0" pre-commit = "^3.3.3" ruff = "^0.6.0" diff --git a/packages/examples/cvat/recording-oracle/src/chain/escrow.py b/packages/examples/cvat/recording-oracle/src/chain/escrow.py index bd21e2ff18..e0955548a7 100644 --- a/packages/examples/cvat/recording-oracle/src/chain/escrow.py +++ b/packages/examples/cvat/recording-oracle/src/chain/escrow.py @@ -1,15 +1,34 @@ import json +import httpx from human_protocol_sdk.constants import ChainId, Status from human_protocol_sdk.encryption import Encryption, EncryptionUtils from human_protocol_sdk.escrow import EscrowClient, EscrowData, EscrowUtils -from human_protocol_sdk.storage import StorageUtils +from human_protocol_sdk.utils import validate_url from src.chain.web3 import get_web3 from src.core.config import Config from src.core.types import OracleWebhookTypes +class ManifestNotAvailableError(Exception): + """Raised when the escrow manifest cannot be retrieved.""" + + +def _get_manifest_content(manifest: str) -> str: + if validate_url(manifest): + try: + response = httpx.get(manifest, follow_redirects=True) + response.raise_for_status() + except Exception as e: + raise ManifestNotAvailableError( + f"failed to download manifest from {manifest}: {e}" + ) from e + return response.text + + return manifest + + def get_escrow(chain_id: int, escrow_address: str) -> EscrowData: escrow = EscrowUtils.get_escrow(ChainId(chain_id), escrow_address) if not escrow: @@ -46,7 +65,7 @@ def validate_escrow( def get_escrow_manifest(chain_id: int, escrow_address: str) -> dict: escrow = get_escrow(chain_id, escrow_address) - manifest_content = StorageUtils.download_file_from_url(escrow.manifest).decode("utf-8") + manifest_content = _get_manifest_content(escrow.manifest) if EncryptionUtils.is_encrypted(manifest_content): encryption = Encryption( diff --git a/packages/examples/cvat/recording-oracle/src/core/tasks/skeletons_from_boxes.py b/packages/examples/cvat/recording-oracle/src/core/tasks/skeletons_from_boxes.py index fb5f09b418..f380a3874f 100644 --- a/packages/examples/cvat/recording-oracle/src/core/tasks/skeletons_from_boxes.py +++ b/packages/examples/cvat/recording-oracle/src/core/tasks/skeletons_from_boxes.py @@ -22,7 +22,7 @@ class RoiInfo: # RoI is centered on the bbox center # Coordinates can be out of image boundaries. - # In this case RoI includes extra margins to be centered on bbox center + # In this case RoI includes extra margins to be centered on bbox center. roi_x: int roi_y: int roi_w: int diff --git a/packages/examples/cvat/recording-oracle/tests/conftest.py b/packages/examples/cvat/recording-oracle/tests/conftest.py index 306d4f3368..32972c10f8 100644 --- a/packages/examples/cvat/recording-oracle/tests/conftest.py +++ b/packages/examples/cvat/recording-oracle/tests/conftest.py @@ -2,17 +2,48 @@ import pytest from fastapi.testclient import TestClient +from sqlalchemy import inspect, text from sqlalchemy.orm import Session from src import app from src.db import Base, SessionLocal, engine -@pytest.fixture(autouse=True) -def db(): +@pytest.fixture(scope="session", autouse=True) +def _create_schema() -> None: + """Create the schema once for the whole session; per-test cleanup only clears data (below).""" Base.metadata.drop_all(bind=engine) Base.metadata.create_all(bind=engine) + # The per-test cleanup only DELETEs rows; it does not reset sequences. Guard that assumption so + # a future model adding a serial/identity column fails loudly here rather than silently leaking + # sequence state (e.g. auto-increment ids) across tests. + sequences = inspect(engine).get_sequence_names() + assert not sequences, ( + f"Found DB sequences {sequences}: the per-test cleanup DELETEs rows without resetting " + "sequences, so ids would leak between tests. Reset them per test (e.g. TRUNCATE ... " + "RESTART IDENTITY, or ALTER SEQUENCE) and update the cleanup." + ) + + +# Clear every table between tests. DELETE in reverse dependency order is ~0 on empty tables, versus +# recreating the whole schema (drop_all + create_all, ~140ms) on every test. No autoincrement PKs, +# so there are no sequences to reset (guarded in _create_schema). Each DELETE is a single SQL +# expression. +_CLEANUP_SQL = text( + ";\n".join( + str(table.delete().compile(dialect=engine.dialect)) + for table in reversed(Base.metadata.sorted_tables) + ) +) + + +@pytest.fixture(autouse=True) +def db(_create_schema) -> None: + """Reset the database to an empty schema before each test.""" + with engine.begin() as connection: + connection.execute(_CLEANUP_SQL) + @pytest.fixture(scope="module") def client() -> Generator: diff --git a/packages/examples/cvat/recording-oracle/tests/integration/chain/test_escrow.py b/packages/examples/cvat/recording-oracle/tests/integration/chain/test_escrow.py index a06702b6ac..742c7addb6 100644 --- a/packages/examples/cvat/recording-oracle/tests/integration/chain/test_escrow.py +++ b/packages/examples/cvat/recording-oracle/tests/integration/chain/test_escrow.py @@ -3,123 +3,113 @@ from unittest.mock import MagicMock, patch import pytest +from human_protocol_sdk.constants import ChainId, Status from human_protocol_sdk.encryption import EncryptionUtils -from human_protocol_sdk.escrow import EscrowClientError -from web3 import Web3 -from web3.middleware import SignAndSendRawMiddlewareBuilder -from web3.providers.rpc import HTTPProvider +from human_protocol_sdk.escrow import EscrowClientError, EscrowData from src.chain.escrow import ( get_escrow_manifest, store_results, validate_escrow, ) -from src.core.config import Config from tests.utils.constants import ( - DEFAULT_GAS_PAYER_PRIV, DEFAULT_HASH, DEFAULT_MANIFEST_URL, + ESCROW_ADDRESS, + EXCHANGE_ORACLE_ADDRESS, + FACTORY_ADDRESS, + JOB_LAUNCHER_ADDRESS, PGP_PASSPHRASE, PGP_PRIVATE_KEY1, PGP_PUBLIC_KEY1, PGP_PUBLIC_KEY2, + RECORDING_ORACLE_ADDRESS, REPUTATION_ORACLE_ADDRESS, + TOKEN_ADDRESS, ) -from tests.utils.setup_escrow import ( - amount, - bulk_payout, - create_escrow, - fund_escrow, - get_intermediate_results_url, - setup_escrow, -) + +escrow_address = ESCROW_ADDRESS +chain_id = ChainId.LOCALHOST.value class ServiceIntegrationTest(unittest.TestCase): def setUp(self): - self.w3 = Web3(HTTPProvider()) - - # Set default gas payer - self.gas_payer = self.w3.eth.account.from_key(DEFAULT_GAS_PAYER_PRIV) - self.w3.middleware_onion.inject( - SignAndSendRawMiddlewareBuilder.build(DEFAULT_GAS_PAYER_PRIV), - "SignAndSendRawMiddlewareBuilder", - layer=0, + self.escrow_data = EscrowData( + chain_id=ChainId.LOCALHOST.name, + id=1, + address=escrow_address, + amount_paid=100, + balance=100, + count=0, + factory_address=FACTORY_ADDRESS, + launcher=JOB_LAUNCHER_ADDRESS, + job_requester_id=JOB_LAUNCHER_ADDRESS, + status=Status.Pending.name, + token=TOKEN_ADDRESS, + total_funded_amount=1000, + created_at="0", + manifest=DEFAULT_MANIFEST_URL, + recording_oracle=RECORDING_ORACLE_ADDRESS, + exchange_oracle=EXCHANGE_ORACLE_ADDRESS, + reputation_oracle=REPUTATION_ORACLE_ADDRESS, ) - self.w3.eth.default_account = self.gas_payer.address - self.network_config = Config.localhost - self.escrow_address = create_escrow(self.w3) - fund_escrow(self.w3, self.escrow_address) - setup_escrow(self.w3, self.escrow_address) + def test_validate_escrow(self): + with patch("src.chain.escrow.EscrowUtils.get_escrow") as mock_function: + mock_function.return_value = self.escrow_data + assert validate_escrow(chain_id, escrow_address) is None - def escrow(self, status: str = "Pending", balance: float = amount): - mock_escrow = MagicMock() - mock_escrow.status = status - mock_escrow.balance = balance - mock_escrow.reputation_oracle = REPUTATION_ORACLE_ADDRESS - mock_escrow.manifest = "http://s3.amazonaws.com" - return mock_escrow + def test_validate_escrow_invalid_address(self): + with pytest.raises(EscrowClientError, match="Invalid escrow address: invalid_address"): + validate_escrow(chain_id, "invalid_address") - def test_validate_escrow(self): - with patch("src.chain.escrow.get_escrow") as mock_get_escrow: - mock_get_escrow.return_value = self.escrow("Pending", amount) - # should not throw an exception - validate_escrow(self.network_config.chain_id, self.escrow_address) + def test_validate_escrow_invalid_status(self): + with patch("src.chain.escrow.EscrowUtils.get_escrow") as mock_function: + self.escrow_data.status = Status.Partial.name + mock_function.return_value = self.escrow_data + with pytest.raises( + ValueError, + match=r"Escrow is not in any of the accepted states \(Pending\)", + ): + validate_escrow(chain_id, escrow_address) def test_validate_escrow_without_funds(self): - with patch("src.chain.escrow.get_escrow") as mock_get_escrow: - mock_get_escrow.return_value = self.escrow("Pending", 0) - + with patch("src.chain.escrow.EscrowUtils.get_escrow") as mock_function: + self.escrow_data.balance = 0 + mock_function.return_value = self.escrow_data with pytest.raises(ValueError, match="Escrow doesn't have funds"): - validate_escrow(-1, "", allow_no_funds=False) + validate_escrow(chain_id, escrow_address) - # should not throw an exception - validate_escrow(self.network_config.chain_id, self.escrow_address, allow_no_funds=True) - - def test_validate_escrow_invalid_status(self): - escrow_address = create_escrow(self.w3) - fund_escrow(self.w3, escrow_address) - setup_escrow(self.w3, escrow_address) - bulk_payout( - self.w3, - escrow_address, - self.gas_payer.address, - Web3.to_wei(50, "milliether"), - ) - with patch("src.chain.escrow.get_escrow") as mock_get_escrow: - mock_get_escrow.return_value = self.escrow("Partial", 0.95) - - with pytest.raises(ValueError, match="Escrow is not in any of the accepted states"): - validate_escrow(self.w3.eth.chain_id, escrow_address) + assert validate_escrow(chain_id, escrow_address, allow_no_funds=True) is None def test_get_escrow_manifest(self): with ( - patch("src.chain.escrow.get_escrow") as mock_get_escrow, - patch("src.chain.escrow.StorageUtils.download_file_from_url") as mock_download, + patch("src.chain.escrow.EscrowUtils.get_escrow") as mock_function, + patch("src.chain.escrow._get_manifest_content") as mock_download, ): - mock_download.return_value = json.dumps({"title": "test"}).encode() - - mock_get_escrow.return_value = self.escrow() - manifest = get_escrow_manifest(self.network_config.chain_id, self.escrow_address) + mock_download.return_value = json.dumps({"title": "test"}) + mock_function.return_value = self.escrow_data + manifest = get_escrow_manifest(chain_id, escrow_address) assert isinstance(manifest, dict) assert manifest is not None + def test_get_escrow_manifest_invalid_address(self): + with pytest.raises(EscrowClientError, match="Invalid escrow address: invalid_address"): + get_escrow_manifest(chain_id, "invalid_address") + def test_get_encrypted_escrow_manifest(self): with ( patch("src.chain.escrow.EscrowUtils.get_escrow") as mock_function, - patch("src.chain.escrow.StorageUtils.download_file_from_url") as mock_download, + patch("src.chain.escrow._get_manifest_content") as mock_download, patch("src.core.config.Config.encryption_config.pgp_private_key", PGP_PRIVATE_KEY1), patch("src.core.config.Config.encryption_config.pgp_passphrase", PGP_PASSPHRASE), patch( "src.core.config.Config.encryption_config.pgp_public_key_url", "http:///some-url" ), ): - mock_function.return_value = self.escrow() - original_manifest_content = { - "title": "test", - } + mock_function.return_value = self.escrow_data + original_manifest_content = {"title": "test"} original_manifest = json.dumps(original_manifest_content) encrypted_manifest = EncryptionUtils.encrypt( @@ -127,39 +117,36 @@ def test_get_encrypted_escrow_manifest(self): ) assert encrypted_manifest != original_manifest - mock_download.return_value = encrypted_manifest.encode() - downloaded_manifest_content = get_escrow_manifest( - self.network_config.chain_id, self.escrow_address - ) + mock_download.return_value = encrypted_manifest + downloaded_manifest_content = get_escrow_manifest(chain_id, escrow_address) assert downloaded_manifest_content == original_manifest_content def test_store_results(self): - escrow_address = create_escrow(self.w3) - fund_escrow(self.w3, escrow_address) - setup_escrow(self.w3, escrow_address) - with patch("src.chain.escrow.get_web3") as mock_function: - mock_function.return_value = self.w3 - results = store_results( - self.w3.eth.chain_id, escrow_address, DEFAULT_MANIFEST_URL, DEFAULT_HASH + with ( + patch("src.chain.escrow.get_web3"), + patch("src.chain.escrow.EscrowClient") as mock_client_cls, + ): + assert ( + store_results(chain_id, escrow_address, DEFAULT_MANIFEST_URL, DEFAULT_HASH) is None + ) + mock_client_cls.return_value.store_results.assert_called_once_with( + escrow_address, DEFAULT_MANIFEST_URL, DEFAULT_HASH ) - assert results is None - intermediate_results_url = get_intermediate_results_url(self.w3, escrow_address) - assert intermediate_results_url == DEFAULT_MANIFEST_URL def test_store_results_invalid_url(self): - escrow_address = create_escrow(self.w3) - fund_escrow(self.w3, escrow_address) - setup_escrow(self.w3, escrow_address) - with patch("src.chain.escrow.get_web3") as mock_function: - mock_function.return_value = self.w3 - with pytest.raises(EscrowClientError, match="Invalid URL: invalid_url"): - store_results(self.w3.eth.chain_id, escrow_address, "invalid_url", DEFAULT_HASH) + w3 = MagicMock() + w3.eth.chain_id = chain_id + with ( + patch("src.chain.escrow.get_web3", return_value=w3), + pytest.raises(EscrowClientError, match="Invalid URL: invalid_url"), + ): + store_results(chain_id, escrow_address, "invalid_url", DEFAULT_HASH) def test_store_results_invalid_hash(self): - escrow_address = create_escrow(self.w3) - fund_escrow(self.w3, escrow_address) - setup_escrow(self.w3, escrow_address) - with patch("src.chain.escrow.get_web3") as mock_function: - mock_function.return_value = self.w3 - with pytest.raises(EscrowClientError, match="Invalid empty hash"): - store_results(self.w3.eth.chain_id, escrow_address, DEFAULT_MANIFEST_URL, "") + w3 = MagicMock() + w3.eth.chain_id = chain_id + with ( + patch("src.chain.escrow.get_web3", return_value=w3), + pytest.raises(EscrowClientError, match="Invalid empty hash"), + ): + store_results(chain_id, escrow_address, DEFAULT_MANIFEST_URL, "") diff --git a/packages/examples/cvat/recording-oracle/tests/integration/chain/test_kvstore.py b/packages/examples/cvat/recording-oracle/tests/integration/chain/test_kvstore.py index a8ffa538ff..ee0756ff02 100644 --- a/packages/examples/cvat/recording-oracle/tests/integration/chain/test_kvstore.py +++ b/packages/examples/cvat/recording-oracle/tests/integration/chain/test_kvstore.py @@ -39,10 +39,11 @@ def setup(self): count=0, factory_address=FACTORY_ADDRESS, launcher=JOB_LAUNCHER_ADDRESS, + job_requester_id=JOB_LAUNCHER_ADDRESS, status=Status.Pending.name, token=TOKEN_ADDRESS, total_funded_amount=1000, - created_at="", + created_at="0", manifest=DEFAULT_MANIFEST_URL, exchange_oracle=EXCHANGE_ORACLE_ADDRESS, reputation_oracle=REPUTATION_ORACLE_ADDRESS, diff --git a/packages/examples/cvat/recording-oracle/tests/integration/cron/test_process_exchange_oracle_webhooks.py b/packages/examples/cvat/recording-oracle/tests/integration/cron/test_process_exchange_oracle_webhooks.py index 50e2d18705..81dfa6fe95 100644 --- a/packages/examples/cvat/recording-oracle/tests/integration/cron/test_process_exchange_oracle_webhooks.py +++ b/packages/examples/cvat/recording-oracle/tests/integration/cron/test_process_exchange_oracle_webhooks.py @@ -4,11 +4,7 @@ from unittest.mock import MagicMock, call, patch from sqlalchemy.sql import select -from web3 import Web3 -from web3.middleware import SignAndSendRawMiddlewareBuilder -from web3.providers.rpc import HTTPProvider -from src.core.config import Config from src.core.storage import compose_data_bucket_prefix, compose_results_bucket_prefix from src.core.types import ( ExchangeOracleEventTypes, @@ -26,22 +22,12 @@ from src.services.cloud import StorageClient from src.services.webhook import OracleWebhookDirectionTags -from tests.utils.constants import DEFAULT_GAS_PAYER_PRIV, ESCROW_ADDRESS, SIGNATURE -from tests.utils.setup_escrow import create_escrow, fund_escrow, setup_escrow +from tests.utils.constants import ESCROW_ADDRESS, SIGNATURE class ServiceIntegrationTest(unittest.TestCase): def setUp(self): self.session = SessionLocal() - self.w3 = Web3(HTTPProvider(Config.localhost.rpc_api)) - - self.gas_payer = self.w3.eth.account.from_key(DEFAULT_GAS_PAYER_PRIV) - self.w3.middleware_onion.inject( - SignAndSendRawMiddlewareBuilder.build(DEFAULT_GAS_PAYER_PRIV), - "SignAndSendRawMiddlewareBuilder", - layer=0, - ) - self.w3.eth.default_account = self.gas_payer.address def tearDown(self): self.session.close() @@ -60,9 +46,7 @@ def make_webhook(self, escrow_address, event_type=ExchangeOracleEventTypes.job_f ) def test_process_exchange_oracle_webhook(self): - escrow_address = create_escrow(self.w3) - fund_escrow(self.w3, escrow_address) - setup_escrow(self.w3, escrow_address) + escrow_address = ESCROW_ADDRESS webhook = self.make_webhook(escrow_address) self.session.add(webhook) @@ -175,7 +159,7 @@ def test_process_recording_oracle_webhooks_invalid_escrow_address(self): assert updated_webhook.attempts == 1 def test_process_recording_oracle_webhooks_invalid_escrow_balance(self): - escrow_address = create_escrow(self.w3) + escrow_address = ESCROW_ADDRESS webhook = self.make_webhook(escrow_address) @@ -195,16 +179,21 @@ def test_process_recording_oracle_webhooks_invalid_escrow_balance(self): assert updated_webhook.attempts == 1 def test_process_job_launcher_webhooks_invalid_manifest_url(self): - escrow_address = create_escrow(self.w3) - fund_escrow(self.w3, escrow_address) - setup_escrow(self.w3, escrow_address, manifest="http://localhost/invalid/url") + escrow_address = ESCROW_ADDRESS webhook = self.make_webhook(escrow_address) self.session.add(webhook) self.session.commit() - process_incoming_exchange_oracle_webhooks() + with ( + patch("src.crons.process_exchange_oracle_webhooks.validate_escrow"), + patch( + "src.crons.process_exchange_oracle_webhooks.validate_results", + side_effect=Exception("failed to download manifest"), + ), + ): + process_incoming_exchange_oracle_webhooks() updated_webhook = ( self.session.execute(select(Webhook).where(Webhook.id == webhook.id)).scalars().first() diff --git a/packages/examples/cvat/recording-oracle/tests/integration/cron/test_process_reputation_oracle_webhooks.py b/packages/examples/cvat/recording-oracle/tests/integration/cron/test_process_reputation_oracle_webhooks.py index 254016415f..11bdf6cd7e 100644 --- a/packages/examples/cvat/recording-oracle/tests/integration/cron/test_process_reputation_oracle_webhooks.py +++ b/packages/examples/cvat/recording-oracle/tests/integration/cron/test_process_reputation_oracle_webhooks.py @@ -3,9 +3,6 @@ from unittest.mock import MagicMock, patch from sqlalchemy.sql import select -from web3 import Web3 -from web3.middleware import SignAndSendRawMiddlewareBuilder -from web3.providers.rpc import HTTPProvider from src.core.types import ( Networks, @@ -18,23 +15,12 @@ from src.models.webhook import Webhook from src.services.webhook import OracleWebhookDirectionTags -from tests.utils.constants import DEFAULT_GAS_PAYER_PRIV, SIGNATURE -from tests.utils.setup_escrow import create_escrow -from tests.utils.setup_kvstore import store_kvstore_value +from tests.utils.constants import ESCROW_ADDRESS, SIGNATURE class ServiceIntegrationTest(unittest.TestCase): def setUp(self): self.session = SessionLocal() - self.w3 = Web3(HTTPProvider()) - - self.gas_payer = self.w3.eth.account.from_key(DEFAULT_GAS_PAYER_PRIV) - self.w3.middleware_onion.inject( - SignAndSendRawMiddlewareBuilder.build(DEFAULT_GAS_PAYER_PRIV), - "SignAndSendRawMiddlewareBuilder", - layer=0, - ) - self.w3.eth.default_account = self.gas_payer.address def tearDown(self): self.session.close() @@ -67,8 +53,7 @@ def test_process_reputation_oracle_webhooks(self): mock_get_repo_url.return_value = expected_url chain_id = Networks.localhost.value - escrow_address = create_escrow(self.w3) - store_kvstore_value("webhook_url", expected_url) + escrow_address = ESCROW_ADDRESS event_data = {} mock_signature.return_value = (None, SIGNATURE) @@ -122,7 +107,7 @@ def test_process_reputation_oracle_webhooks_invalid_reputation_oracle_url(self): ) as mock_get_repo_url: mock_get_repo_url.return_value = "https://not.a.real/url/existing.somewhere" - webhook = self.get_webhook(create_escrow(self.w3), Networks.localhost.value, {}) + webhook = self.get_webhook(ESCROW_ADDRESS, Networks.localhost.value, {}) self.session.add(webhook) self.session.commit() process_outgoing_reputation_oracle_webhooks() diff --git a/packages/examples/cvat/recording-oracle/tests/utils/setup_escrow.py b/packages/examples/cvat/recording-oracle/tests/utils/setup_escrow.py deleted file mode 100644 index f289738487..0000000000 --- a/packages/examples/cvat/recording-oracle/tests/utils/setup_escrow.py +++ /dev/null @@ -1,68 +0,0 @@ -from decimal import Decimal - -from human_protocol_sdk.constants import NETWORKS, ChainId -from human_protocol_sdk.escrow import EscrowClient, EscrowConfig -from human_protocol_sdk.staking import StakingClient -from web3 import Web3 - -from tests.utils.constants import ( - DEFAULT_HASH, - DEFAULT_MANIFEST_URL, - EXCHANGE_ORACLE_ADDRESS, - EXCHANGE_ORACLE_FEE, - JOB_REQUESTER_ID, - RECORDING_ORACLE_ADDRESS, - RECORDING_ORACLE_FEE, - REPUTATION_ORACLE_ADDRESS, - REPUTATION_ORACLE_FEE, -) - -amount = Web3.to_wei(1, "ether") - - -def create_escrow(web3: Web3): - staking_client = StakingClient(web3) - escrow_client = EscrowClient(web3) - staking_client.approve_stake(amount) - staking_client.stake(amount) - return escrow_client.create_escrow( - token_address=NETWORKS[ChainId.LOCALHOST]["hmt_address"], - trusted_handlers=[web3.eth.default_account], - job_requester_id=JOB_REQUESTER_ID, - ) - - -def setup_escrow(web3: Web3, escrow_address: str, *, manifest: str = DEFAULT_MANIFEST_URL): - escrow_client = EscrowClient(web3) - escrow_client.setup( - escrow_address=escrow_address, - escrow_config=EscrowConfig( - exchange_oracle_address=EXCHANGE_ORACLE_ADDRESS, - exchange_oracle_fee=EXCHANGE_ORACLE_FEE, - recording_oracle_address=RECORDING_ORACLE_ADDRESS, - recording_oracle_fee=RECORDING_ORACLE_FEE, - reputation_oracle_address=REPUTATION_ORACLE_ADDRESS, - reputation_oracle_fee=REPUTATION_ORACLE_FEE, - manifest=manifest, - hash=DEFAULT_HASH, - ), - ) - - -def fund_escrow(web3: Web3, escrow_address: str): - escrow_client = EscrowClient(web3) - escrow_client.fund(escrow_address, amount) - - -def bulk_payout(web3: Web3, escrow_address: str, recipient: str, amount: Decimal): - escrow_client = EscrowClient(web3) - escrow_client.bulk_payout( - escrow_address, [recipient], [amount], DEFAULT_MANIFEST_URL, DEFAULT_HASH, 1 - ) - - -def get_intermediate_results_url(web3: Web3, escrow_address: str): - escrow_client = EscrowClient(web3) - return ( - escrow_client._get_escrow_contract(escrow_address).functions.intermediateResultsUrl().call() - ) diff --git a/packages/examples/cvat/recording-oracle/tests/utils/setup_kvstore.py b/packages/examples/cvat/recording-oracle/tests/utils/setup_kvstore.py deleted file mode 100644 index ec9bd88a70..0000000000 --- a/packages/examples/cvat/recording-oracle/tests/utils/setup_kvstore.py +++ /dev/null @@ -1,22 +0,0 @@ -from human_protocol_sdk.kvstore import KVStoreClient -from web3 import HTTPProvider, Web3 -from web3.middleware import SignAndSendRawMiddlewareBuilder - -from tests.utils.constants import REPUTATION_ORACLE_PRIV - -amount = Web3.to_wei(1, "ether") - - -def store_kvstore_value(key: str, value: str): - w3 = Web3(HTTPProvider()) - - # Set default gas payer - reputation_oracle = w3.eth.account.from_key(REPUTATION_ORACLE_PRIV) - w3.middleware_onion.inject( - SignAndSendRawMiddlewareBuilder.build(REPUTATION_ORACLE_PRIV), - "SignAndSendRawMiddlewareBuilder", - layer=0, - ) - w3.eth.default_account = reputation_oracle.address - kvstore_client = KVStoreClient(w3) - kvstore_client.set(key, value) From 438aaca9b629cf3dd51877ddd23bb211c2a80c8d Mon Sep 17 00:00:00 2001 From: Maxim Zhiltsov Date: Fri, 17 Jul 2026 17:28:26 +0300 Subject: [PATCH 12/33] [CVAT] Bump oracle deps (#3973) --- .../examples/cvat/exchange-oracle/.gitignore | 2 + .../examples/cvat/exchange-oracle/README.md | 32 +- .../examples/cvat/exchange-oracle/alembic.ini | 4 + .../cvat/exchange-oracle/alembic/env.py | 6 +- ..._project_assignment_bounty_9884511c7077.py | 30 + .../cvat/exchange-oracle/bin/start_debug.sh | 2 +- .../cvat/exchange-oracle/bin/start_dev.sh | 2 +- .../cvat/exchange-oracle/bin/start_prod.sh | 2 +- .../exchange-oracle/docker-compose.dev.yml | 10 +- .../docker-compose.test.head.yml | 3 +- .../exchange-oracle/docker-compose.test.yml | 17 +- .../examples/cvat/exchange-oracle/poetry.lock | 7575 ++++++++++------- .../cvat/exchange-oracle/pyproject.toml | 51 +- .../cvat/exchange-oracle/src/__init__.py | 36 - .../unit/helpers => src/apps}/__init__.py | 0 .../src/apps/exchange_oracle.py | 36 + .../cvat/exchange-oracle/src/chain/escrow.py | 4 +- .../cvat/exchange-oracle/src/core/config.py | 4 +- .../src/core/manifest/__init__.py | 38 + .../exchange-oracle/src/core/manifest/base.py | 6 + .../src/core/manifest/shared.py} | 91 +- .../exchange-oracle/src/core/manifest/v1.py | 83 + .../exchange-oracle/src/core/manifest/v2.py | 170 + .../src/core/tasks/__init__.py | 7 + .../tasks/audio_transcription/__init__.py | 0 .../core/tasks/audio_transcription/meta.py | 252 + .../core/tasks/audio_transcription/spec.py | 170 + .../src/core/tasks/boxes_from_points.py | 2 +- .../src/core/tasks/cvat_formats.py | 22 + .../exchange-oracle/src/core/tasks/errors.py | 2 + .../src/core/tasks/skeletons_from_boxes.py | 6 +- .../exchange-oracle/src/core/tasks/types.py | 13 + .../cvat/exchange-oracle/src/core/types.py | 39 +- .../exchange-oracle/src/crons/_cron_job.py | 2 +- .../src/crons/cvat/state_trackers.py | 2 +- .../src/crons/webhooks/_common.py | 4 +- .../src/crons/webhooks/job_launcher.py | 5 +- .../src/crons/webhooks/recording_oracle.py | 2 +- .../exchange-oracle/src/cvat/api_calls.py | 50 +- .../cvat/exchange-oracle/src/db/__init__.py | 3 +- .../exchange-oracle/src/endpoints/__init__.py | 2 +- .../src/endpoints/authentication.py | 19 +- .../exchange-oracle/src/endpoints/exchange.py | 3 +- .../src/endpoints/filtering.py | 9 +- .../src/endpoints/pagination.py | 12 +- .../src/endpoints/serializers.py | 32 +- .../src/endpoints/throttling.py | 2 +- .../src/entrypoints/__init__.py | 0 .../{ => src/entrypoints}/debug.py | 59 +- .../{ => src/entrypoints}/run.py | 2 +- .../src/handlers/completed_escrows.py | 347 - .../src/handlers/job_completion/__init__.py | 3 + .../src/handlers/job_completion/handlers.py | 79 + .../job_completion/validators/__init__.py | 0 .../job_completion/validators/audio.py | 50 + .../job_completion/validators/base.py | 81 + .../job_completion/validators/factory.py | 42 + .../src/handlers/job_creation.py | 3060 ------- .../src/handlers/job_creation/__init__.py | 3 + .../job_creation/builders/__init__.py | 0 .../job_creation/builders/audio/__init__.py | 0 .../builders/audio/transcription.py | 814 ++ .../handlers/job_creation/builders/factory.py | 49 + .../job_creation/builders/vision/__init__.py | 0 .../job_creation/builders/vision/base.py | 155 + .../job_creation/builders/vision/basic.py | 345 + .../builders/vision/boxes_from_points.py | 1153 +++ .../builders/vision/skeletons_from_boxes.py | 1418 +++ .../src/handlers/job_creation/exceptions.py | 55 + .../src/handlers/job_creation/handlers.py | 17 + .../src/handlers/job_creation/utils.py | 103 + .../src/handlers/job_export/__init__.py | 3 + .../src/handlers/job_export/downloading.py | 117 + .../handlers/job_export/exporters/__init__.py | 0 .../handlers/job_export/exporters/audio.py | 144 + .../src/handlers/job_export/exporters/base.py | 70 + .../handlers/job_export/exporters/factory.py | 54 + .../exporters/vision.py} | 271 +- .../src/handlers/job_export/handlers.py | 39 + .../src/handlers/job_export/results.py | 82 + .../exchange-oracle/src/models/__init__.py | 27 + .../cvat/exchange-oracle/src/models/cvat.py | 3 +- .../exchange-oracle/src/schemas/exchange.py | 9 +- .../src/services/cloud/types.py | 8 +- .../cvat/exchange-oracle/src/services/cvat.py | 17 +- .../exchange-oracle/src/services/exchange.py | 20 +- .../exchange-oracle/src/services/webhook.py | 17 +- .../exchange-oracle/src/utils/annotations.py | 2 +- .../exchange-oracle/src/utils/assignments.py | 30 +- .../cvat/exchange-oracle/src/utils/audio.py | 124 + .../cvat/exchange-oracle/src/utils/enums.py | 7 + .../tests/api/test_cvat_webhook_api.py | 17 +- .../tests/api/test_exchange_api.py | 37 +- .../cloud/manifests/audio_manifest.json | 28 + .../cloud/manifests/manifest-v1.json} | 0 .../datasets/gt_annotations_coco.zip | Bin .../annotations/instances_default.json | 0 .../tests/{utils => assets}/datasets/img1.jpg | Bin .../{utils => assets}/datasets/img10.jpg | Bin .../{utils => assets}/datasets/img11.jpg | Bin .../{utils => assets}/datasets/img12.jpg | Bin .../{utils => assets}/datasets/img13.jpg | Bin .../tests/{utils => assets}/datasets/img2.jpg | Bin .../tests/{utils => assets}/datasets/img3.jpg | Bin .../tests/{utils => assets}/datasets/img4.jpg | Bin .../tests/{utils => assets}/datasets/img5.jpg | Bin .../tests/{utils => assets}/datasets/img6.jpg | Bin .../tests/{utils => assets}/datasets/img7.jpg | Bin .../tests/{utils => assets}/datasets/img8.jpg | Bin .../tests/{utils => assets}/datasets/img9.jpg | Bin .../utils/gen_audio_validation_fixture.py | 152 + .../cvat/exchange-oracle/tests/conftest.py | 4 +- .../tests/integration/chain/test_web3.py | 9 +- .../test_track_completed_escrows.py | 87 +- .../test_track_completed_projects.py | 3 +- .../test_track_completed_tasks.py | 3 +- .../test_track_task_creation.py | 2 +- .../test_process_job_launcher_webhooks.py | 30 +- .../test_process_recording_oracle_webhooks.py | 4 +- ...test_process_reputation_oracle_webhooks.py | 2 +- .../tests/integration/services/test_cvat.py | 156 +- .../integration/services/test_exchange.py | 32 +- .../integration/services/test_webhook.py | 10 +- .../unit/helpers/predefined_annotations.py | 36 - .../tests/unit/test_audio_task_creation.py | 268 + .../tests/utils/audio_transcription.py | 108 + .../exchange-oracle/tests/utils/constants.py | 2 +- .../exchange-oracle/tests/utils/db_helper.py | 3 +- .../exchange-oracle/tests/utils/setup_cvat.py | 10 +- .../examples/cvat/recording-oracle/.gitignore | 1 + .../recording-oracle/.pre-commit-config.yaml | 4 +- .../examples/cvat/recording-oracle/Dockerfile | 2 + .../examples/cvat/recording-oracle/README.md | 33 +- .../cvat/recording-oracle/alembic.ini | 4 + .../cvat/recording-oracle/alembic/env.py | 6 +- .../cvat/recording-oracle/bin/start_debug.sh | 2 +- .../cvat/recording-oracle/bin/start_dev.sh | 2 +- .../docker-compose.test.head.yml | 4 +- .../recording-oracle/docker-compose.test.yml | 16 +- .../dockerfiles/test.ci.Dockerfile | 2 + .../dockerfiles/test.dev.Dockerfile | 2 + .../recording-oracle/libs/audio_qe/LICENSE | 21 + .../recording-oracle/libs/audio_qe/README.md | 67 + .../libs/audio_qe/audio_qe/__init__.py | 102 + .../libs/audio_qe/audio_qe/config.py | 90 + .../libs/audio_qe/audio_qe/data.py | 84 + .../audio_qe/audio_qe/interval_matching.py | 215 + .../libs/audio_qe/audio_qe/normalization.py | 553 ++ .../libs/audio_qe/audio_qe/pipeline.py | 24 + .../libs/audio_qe/audio_qe/reports.py | 165 + .../audio_qe/transcription_matching.py | 1116 +++ .../libs/audio_qe/pyproject.toml | 18 + .../cvat/recording-oracle/poetry.lock | 6996 ++++++++------- .../cvat/recording-oracle/pyproject.toml | 42 +- .../cvat/recording-oracle/src/chain/escrow.py | 4 +- .../src/core/manifest/__init__.py | 38 + .../src/core/manifest/base.py | 6 + .../src/core/manifest/shared.py} | 91 +- .../recording-oracle/src/core/manifest/v1.py | 83 + .../recording-oracle/src/core/manifest/v2.py | 170 + .../src/core/tasks/__init__.py | 7 + .../tasks/audio_transcription/__init__.py | 0 .../core/tasks/audio_transcription/meta.py | 252 + .../core/tasks/audio_transcription/spec.py | 170 + .../src/core/tasks/cvat_formats.py | 22 + .../recording-oracle/src/core/tasks/errors.py | 2 + .../recording-oracle/src/core/tasks/types.py | 11 + .../cvat/recording-oracle/src/core/types.py | 23 +- .../src/core/validation_errors.py | 2 +- .../cvat/recording-oracle/src/crons/_utils.py | 16 +- .../recording-oracle/src/cvat/api_calls.py | 2 +- .../src/endpoints/__init__.py | 2 +- .../recording-oracle/src/endpoints/webhook.py | 4 +- .../src/entrypoints/__init__.py | 0 .../{ => src/entrypoints}/debug.py | 3 +- .../{ => src/entrypoints}/run.py | 0 .../src/handlers/completion/__init__.py | 3 + .../src/handlers/completion/final_results.py | 109 + .../{completion.py => completion/handlers.py} | 57 +- .../completion/task_exporters/__init__.py | 0 .../completion/task_exporters/audio.py | 73 + .../completion/task_exporters/base.py | 49 + .../completion/task_exporters/factory.py | 40 + .../completion/task_exporters/image.py | 190 + .../src/handlers/validation/__init__.py | 10 + .../src/handlers/validation/common.py | 66 + .../{validation.py => validation/handlers.py} | 32 +- .../intermediate_results.py} | 529 +- .../src/handlers/validation/meta.py | 18 + .../validation/quality_checkers/__init__.py | 0 .../validation/quality_checkers/audio.py | 338 + .../validation/quality_checkers/base.py | 60 + .../validation/quality_checkers/factory.py | 42 + .../validation/quality_checkers/image.py | 125 + .../recording-oracle/src/models/__init__.py | 10 + .../src/services/cloud/types.py | 8 +- .../recording-oracle/src/services/webhook.py | 17 +- .../recording-oracle/src/utils/annotations.py | 2 +- .../cvat/recording-oracle/src/utils/enums.py | 7 + .../cloud/audio_validation/assignments.json | 1 + .../assets/cloud/audio_validation/gt.tsv | 7 + .../cloud/audio_validation/manifest.json | 28 + .../cloud/audio_validation/task_clips.json | 1 + .../cloud/manifests/manifest-v1.json} | 0 .../tests/integration/chain/test_web3.py | 9 +- ...test_process_reputation_oracle_webhooks.py | 2 +- .../integration/endpoints/test_webhook.py | 7 +- .../services/test_validation_service.py | 169 +- .../recording-oracle/tests/unit/__init__.py | 0 .../tests/unit/test_audio_validation.py | 162 + .../tests/utils/audio_transcription.py | 108 + .../recording-oracle/tests/utils/constants.py | 2 +- .../recording-oracle/tests/utils/helpers.py | 4 +- .../tests/utils/intermediate-results.json | 29 - .../utils/recording_oracle_dummy_input.json | 321 - 215 files changed, 20443 insertions(+), 11417 deletions(-) create mode 100644 packages/examples/cvat/exchange-oracle/alembic/versions/1784115076_add_project_assignment_bounty_9884511c7077.py rename packages/examples/cvat/exchange-oracle/{tests/unit/helpers => src/apps}/__init__.py (100%) create mode 100644 packages/examples/cvat/exchange-oracle/src/apps/exchange_oracle.py create mode 100644 packages/examples/cvat/exchange-oracle/src/core/manifest/__init__.py create mode 100644 packages/examples/cvat/exchange-oracle/src/core/manifest/base.py rename packages/examples/cvat/{recording-oracle/src/core/manifest.py => exchange-oracle/src/core/manifest/shared.py} (50%) create mode 100644 packages/examples/cvat/exchange-oracle/src/core/manifest/v1.py create mode 100644 packages/examples/cvat/exchange-oracle/src/core/manifest/v2.py create mode 100644 packages/examples/cvat/exchange-oracle/src/core/tasks/audio_transcription/__init__.py create mode 100644 packages/examples/cvat/exchange-oracle/src/core/tasks/audio_transcription/meta.py create mode 100644 packages/examples/cvat/exchange-oracle/src/core/tasks/audio_transcription/spec.py create mode 100644 packages/examples/cvat/exchange-oracle/src/core/tasks/cvat_formats.py create mode 100644 packages/examples/cvat/exchange-oracle/src/core/tasks/errors.py create mode 100644 packages/examples/cvat/exchange-oracle/src/core/tasks/types.py create mode 100644 packages/examples/cvat/exchange-oracle/src/entrypoints/__init__.py rename packages/examples/cvat/exchange-oracle/{ => src/entrypoints}/debug.py (85%) rename packages/examples/cvat/exchange-oracle/{ => src/entrypoints}/run.py (89%) delete mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/completed_escrows.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_completion/__init__.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_completion/handlers.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_completion/validators/__init__.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_completion/validators/audio.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_completion/validators/base.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_completion/validators/factory.py delete mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_creation.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_creation/__init__.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/__init__.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/audio/__init__.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/audio/transcription.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/factory.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/vision/__init__.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/vision/base.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/vision/basic.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/vision/boxes_from_points.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/vision/skeletons_from_boxes.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_creation/exceptions.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_creation/handlers.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_creation/utils.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_export/__init__.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_export/downloading.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_export/exporters/__init__.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_export/exporters/audio.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_export/exporters/base.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_export/exporters/factory.py rename packages/examples/cvat/exchange-oracle/src/handlers/{job_export.py => job_export/exporters/vision.py} (74%) create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_export/handlers.py create mode 100644 packages/examples/cvat/exchange-oracle/src/handlers/job_export/results.py create mode 100644 packages/examples/cvat/exchange-oracle/src/utils/audio.py create mode 100644 packages/examples/cvat/exchange-oracle/tests/assets/cloud/manifests/audio_manifest.json rename packages/examples/cvat/exchange-oracle/tests/{utils/manifest.json => assets/cloud/manifests/manifest-v1.json} (100%) rename packages/examples/cvat/exchange-oracle/tests/{utils => assets}/datasets/gt_annotations_coco.zip (100%) rename packages/examples/cvat/exchange-oracle/tests/{utils => assets}/datasets/gt_annotations_coco/annotations/instances_default.json (100%) rename packages/examples/cvat/exchange-oracle/tests/{utils => assets}/datasets/img1.jpg (100%) rename packages/examples/cvat/exchange-oracle/tests/{utils => assets}/datasets/img10.jpg (100%) rename packages/examples/cvat/exchange-oracle/tests/{utils => assets}/datasets/img11.jpg (100%) rename packages/examples/cvat/exchange-oracle/tests/{utils => assets}/datasets/img12.jpg (100%) rename packages/examples/cvat/exchange-oracle/tests/{utils => assets}/datasets/img13.jpg (100%) rename packages/examples/cvat/exchange-oracle/tests/{utils => assets}/datasets/img2.jpg (100%) rename packages/examples/cvat/exchange-oracle/tests/{utils => assets}/datasets/img3.jpg (100%) rename packages/examples/cvat/exchange-oracle/tests/{utils => assets}/datasets/img4.jpg (100%) rename packages/examples/cvat/exchange-oracle/tests/{utils => assets}/datasets/img5.jpg (100%) rename packages/examples/cvat/exchange-oracle/tests/{utils => assets}/datasets/img6.jpg (100%) rename packages/examples/cvat/exchange-oracle/tests/{utils => assets}/datasets/img7.jpg (100%) rename packages/examples/cvat/exchange-oracle/tests/{utils => assets}/datasets/img8.jpg (100%) rename packages/examples/cvat/exchange-oracle/tests/{utils => assets}/datasets/img9.jpg (100%) create mode 100644 packages/examples/cvat/exchange-oracle/tests/assets/utils/gen_audio_validation_fixture.py delete mode 100644 packages/examples/cvat/exchange-oracle/tests/unit/helpers/predefined_annotations.py create mode 100644 packages/examples/cvat/exchange-oracle/tests/unit/test_audio_task_creation.py create mode 100644 packages/examples/cvat/exchange-oracle/tests/utils/audio_transcription.py create mode 100644 packages/examples/cvat/recording-oracle/libs/audio_qe/LICENSE create mode 100644 packages/examples/cvat/recording-oracle/libs/audio_qe/README.md create mode 100644 packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/__init__.py create mode 100644 packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/config.py create mode 100644 packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/data.py create mode 100644 packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/interval_matching.py create mode 100644 packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/normalization.py create mode 100644 packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/pipeline.py create mode 100644 packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/reports.py create mode 100644 packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/transcription_matching.py create mode 100644 packages/examples/cvat/recording-oracle/libs/audio_qe/pyproject.toml create mode 100644 packages/examples/cvat/recording-oracle/src/core/manifest/__init__.py create mode 100644 packages/examples/cvat/recording-oracle/src/core/manifest/base.py rename packages/examples/cvat/{exchange-oracle/src/core/manifest.py => recording-oracle/src/core/manifest/shared.py} (50%) create mode 100644 packages/examples/cvat/recording-oracle/src/core/manifest/v1.py create mode 100644 packages/examples/cvat/recording-oracle/src/core/manifest/v2.py create mode 100644 packages/examples/cvat/recording-oracle/src/core/tasks/audio_transcription/__init__.py create mode 100644 packages/examples/cvat/recording-oracle/src/core/tasks/audio_transcription/meta.py create mode 100644 packages/examples/cvat/recording-oracle/src/core/tasks/audio_transcription/spec.py create mode 100644 packages/examples/cvat/recording-oracle/src/core/tasks/cvat_formats.py create mode 100644 packages/examples/cvat/recording-oracle/src/core/tasks/errors.py create mode 100644 packages/examples/cvat/recording-oracle/src/core/tasks/types.py create mode 100644 packages/examples/cvat/recording-oracle/src/entrypoints/__init__.py rename packages/examples/cvat/recording-oracle/{ => src/entrypoints}/debug.py (98%) rename packages/examples/cvat/recording-oracle/{ => src/entrypoints}/run.py (100%) create mode 100644 packages/examples/cvat/recording-oracle/src/handlers/completion/__init__.py create mode 100644 packages/examples/cvat/recording-oracle/src/handlers/completion/final_results.py rename packages/examples/cvat/recording-oracle/src/handlers/{completion.py => completion/handlers.py} (72%) create mode 100644 packages/examples/cvat/recording-oracle/src/handlers/completion/task_exporters/__init__.py create mode 100644 packages/examples/cvat/recording-oracle/src/handlers/completion/task_exporters/audio.py create mode 100644 packages/examples/cvat/recording-oracle/src/handlers/completion/task_exporters/base.py create mode 100644 packages/examples/cvat/recording-oracle/src/handlers/completion/task_exporters/factory.py create mode 100644 packages/examples/cvat/recording-oracle/src/handlers/completion/task_exporters/image.py create mode 100644 packages/examples/cvat/recording-oracle/src/handlers/validation/__init__.py create mode 100644 packages/examples/cvat/recording-oracle/src/handlers/validation/common.py rename packages/examples/cvat/recording-oracle/src/handlers/{validation.py => validation/handlers.py} (83%) rename packages/examples/cvat/recording-oracle/src/handlers/{process_intermediate_results.py => validation/intermediate_results.py} (53%) create mode 100644 packages/examples/cvat/recording-oracle/src/handlers/validation/meta.py create mode 100644 packages/examples/cvat/recording-oracle/src/handlers/validation/quality_checkers/__init__.py create mode 100644 packages/examples/cvat/recording-oracle/src/handlers/validation/quality_checkers/audio.py create mode 100644 packages/examples/cvat/recording-oracle/src/handlers/validation/quality_checkers/base.py create mode 100644 packages/examples/cvat/recording-oracle/src/handlers/validation/quality_checkers/factory.py create mode 100644 packages/examples/cvat/recording-oracle/src/handlers/validation/quality_checkers/image.py create mode 100644 packages/examples/cvat/recording-oracle/tests/assets/cloud/audio_validation/assignments.json create mode 100644 packages/examples/cvat/recording-oracle/tests/assets/cloud/audio_validation/gt.tsv create mode 100644 packages/examples/cvat/recording-oracle/tests/assets/cloud/audio_validation/manifest.json create mode 100644 packages/examples/cvat/recording-oracle/tests/assets/cloud/audio_validation/task_clips.json rename packages/examples/cvat/recording-oracle/tests/{utils/manifest.json => assets/cloud/manifests/manifest-v1.json} (100%) create mode 100644 packages/examples/cvat/recording-oracle/tests/unit/__init__.py create mode 100644 packages/examples/cvat/recording-oracle/tests/unit/test_audio_validation.py create mode 100644 packages/examples/cvat/recording-oracle/tests/utils/audio_transcription.py delete mode 100644 packages/examples/cvat/recording-oracle/tests/utils/intermediate-results.json delete mode 100644 packages/examples/cvat/recording-oracle/tests/utils/recording_oracle_dummy_input.json diff --git a/packages/examples/cvat/exchange-oracle/.gitignore b/packages/examples/cvat/exchange-oracle/.gitignore index 12f5b4f876..bc7f61aa0e 100644 --- a/packages/examples/cvat/exchange-oracle/.gitignore +++ b/packages/examples/cvat/exchange-oracle/.gitignore @@ -1,3 +1,5 @@ +/.venv + # Byte-compiled / optimized / DLL files __pycache__/ .pytest_cache diff --git a/packages/examples/cvat/exchange-oracle/README.md b/packages/examples/cvat/exchange-oracle/README.md index b1bcb63f6e..9c8fc45ecd 100644 --- a/packages/examples/cvat/exchange-oracle/README.md +++ b/packages/examples/cvat/exchange-oracle/README.md @@ -4,7 +4,7 @@ Prerequisites: ``` -1. poetry shell +1. poetry config virtualenvs.in-project true # create .venv inside the project so editors/debuggers pick it up 2. poetry install 3. pre-commit install 4. Make sure you have postgres-devel packages installed on your OS. It is required for psycopg2 build phase. @@ -30,13 +30,13 @@ docker compose -f docker-compose.dev.yml up -d ./bin/start_debug.sh ``` -When running service from `./bin/start_debug.sh` (`debug.py`), simplified development flow is available: +When running service from `./bin/start_debug.sh` (`src/entrypoints/debug.py`), simplified development flow is available: - When JWT token is required, simple JSON can be used instead of JWT token. - When webhook signature is required, `{oracle_name}:unique_string` can be used - You can upload manifest.json to minio `manifests` bucket and use its filename as an escrow_address -### Environemt +### Environment Env example file: [.env.example](https://github.com/humanprotocol/human-protocol/blob/feat/cvat/exchange-oracle/packages/examples/cvat/exchange-oracle/src/.env.example) Config: [config file](https://github.com/humanprotocol/human-protocol/blob/feat/cvat/exchange-oracle/packages/examples/cvat/exchange-oracle/src/config.py) @@ -76,11 +76,11 @@ Available at `/docs` route A single command to build, run, and tear down the test suite: ```sh -docker compose -p "test" \ +docker compose -p eo-test \ -f docker-compose.test.yml \ -f docker-compose.test.head.yml \ up --build test --attach test --exit-code-from test; \ - docker compose -p "test" \ + docker compose -p eo-test \ -f docker-compose.test.yml \ -f docker-compose.test.head.yml \ down @@ -95,19 +95,19 @@ commands allow running just the services, build, tear down, and run the test sui ```sh # run services -docker compose -p "test" \ +docker compose -p eo-test \ -f docker-compose.test.yml \ up -d --build # run the tests -docker compose -p "test" \ +docker compose -p eo-test \ -f docker-compose.test.yml \ -f docker-compose.test.head.yml \ -f docker-compose.test.head.dev.yml \ up --build test --attach test --exit-code-from test # tear down -docker compose -p "test" \ +docker compose -p eo-test \ -f docker-compose.test.yml \ -f docker-compose.test.head.yml \ -f docker-compose.test.head.dev.yml \ @@ -115,3 +115,19 @@ docker compose -p "test" \ ``` The dev setup mounts the local directory to speed the things up. + +#### Regenerating the test fixtures + +Recording Oracle tests run against the fixtures produced by the Exchange Oracle implementation. +Regenerate them whenever the builder output layout or the shared task setups change. + +```sh +docker compose -p eo-test \ + -f docker-compose.test.yml \ + -f docker-compose.test.head.yml \ + -f docker-compose.test.head.dev.yml \ + run --rm \ + -v "$(pwd)/../recording-oracle/tests/assets/cloud/audio_validation:/out" \ + test sh -c "alembic upgrade head && PYTHONPATH=. \ + python tests/assets/utils/gen_audio_validation_fixture.py /out" +``` diff --git a/packages/examples/cvat/exchange-oracle/alembic.ini b/packages/examples/cvat/exchange-oracle/alembic.ini index 086270a85c..f957f9ca9f 100644 --- a/packages/examples/cvat/exchange-oracle/alembic.ini +++ b/packages/examples/cvat/exchange-oracle/alembic.ini @@ -15,6 +15,10 @@ file_template = %%(epoch)d_%%(slug)s_%%(rev)s # defaults to the current working directory. prepend_sys_path = . +# path separator (os = os.pathsep) used to split prepend_sys_path and version_locations; +# the unified key introduced in alembic 1.16, replacing version_path_separator. +path_separator = os + # timezone to use when rendering the date within the migration file # as well as the filename. # If specified, requires the python-dateutil library that can be diff --git a/packages/examples/cvat/exchange-oracle/alembic/env.py b/packages/examples/cvat/exchange-oracle/alembic/env.py index b642b5942c..0af4210614 100644 --- a/packages/examples/cvat/exchange-oracle/alembic/env.py +++ b/packages/examples/cvat/exchange-oracle/alembic/env.py @@ -18,13 +18,9 @@ disable_existing_loggers=config.attributes.get("disable_existing_loggers", True), ) +import src.models # noqa: E402, F401 (registers all models on Base.metadata for autogenerate) from src.db import Base # noqa: E402 -# add your model's MetaData object here -# for 'autogenerate' support -# from myapp import mymodel -# target_metadata = mymodel.Base.metadata - target_metadata = Base.metadata # other values from the config, defined by the needs of env.py, diff --git a/packages/examples/cvat/exchange-oracle/alembic/versions/1784115076_add_project_assignment_bounty_9884511c7077.py b/packages/examples/cvat/exchange-oracle/alembic/versions/1784115076_add_project_assignment_bounty_9884511c7077.py new file mode 100644 index 0000000000..0caf69311e --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/alembic/versions/1784115076_add_project_assignment_bounty_9884511c7077.py @@ -0,0 +1,30 @@ +""" +add project assignment_bounty + +Revision ID: 9884511c7077 +Revises: 216af22b5590 +Create Date: 2026-07-15 14:31:16.493245 + +""" + +import sqlalchemy as sa + +from alembic import op + +# revision identifiers, used by Alembic. +revision = "9884511c7077" +down_revision = "216af22b5590" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column("projects", sa.Column("assignment_bounty", sa.String(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column("projects", "assignment_bounty") + # ### end Alembic commands ### diff --git a/packages/examples/cvat/exchange-oracle/bin/start_debug.sh b/packages/examples/cvat/exchange-oracle/bin/start_debug.sh index ff93f4765c..a7d31fdc4f 100755 --- a/packages/examples/cvat/exchange-oracle/bin/start_debug.sh +++ b/packages/examples/cvat/exchange-oracle/bin/start_debug.sh @@ -1,4 +1,4 @@ export ENVIRONMENT=development alembic upgrade head -python debug.py \ No newline at end of file +python -m src.entrypoints.debug \ No newline at end of file diff --git a/packages/examples/cvat/exchange-oracle/bin/start_dev.sh b/packages/examples/cvat/exchange-oracle/bin/start_dev.sh index 64f2bd6fe1..66f642002c 100755 --- a/packages/examples/cvat/exchange-oracle/bin/start_dev.sh +++ b/packages/examples/cvat/exchange-oracle/bin/start_dev.sh @@ -1,4 +1,4 @@ export ENVIRONMENT=development alembic upgrade head -python run.py \ No newline at end of file +python -m src.entrypoints.run \ No newline at end of file diff --git a/packages/examples/cvat/exchange-oracle/bin/start_prod.sh b/packages/examples/cvat/exchange-oracle/bin/start_prod.sh index 01e23572e6..bd5322ceb1 100755 --- a/packages/examples/cvat/exchange-oracle/bin/start_prod.sh +++ b/packages/examples/cvat/exchange-oracle/bin/start_prod.sh @@ -1,4 +1,4 @@ export ENVIRONMENT=production alembic upgrade head -python run.py \ No newline at end of file +python -m src.entrypoints.run \ No newline at end of file diff --git a/packages/examples/cvat/exchange-oracle/docker-compose.dev.yml b/packages/examples/cvat/exchange-oracle/docker-compose.dev.yml index 065297be48..bb39bc98f1 100644 --- a/packages/examples/cvat/exchange-oracle/docker-compose.dev.yml +++ b/packages/examples/cvat/exchange-oracle/docker-compose.dev.yml @@ -32,11 +32,11 @@ services: ports: - 6380:6379 networks: - - test-network + - oracle-network minio: container_name: minio - image: minio/minio:RELEASE.2022-05-26T05-48-41Z + image: minio/minio:RELEASE.2025-09-07T16-13-09Z environment: MINIO_ROOT_USER: dev MINIO_ROOT_PASSWORD: devdevdev @@ -54,7 +54,7 @@ services: timeout: 5s retries: 3 networks: - - test-network + - oracle-network - cvat-human-bridge minio-mc: @@ -78,7 +78,7 @@ services: /usr/bin/mc anonymous set public myminio/launcher; " networks: - - test-network + - oracle-network volumes: postgres: @@ -86,7 +86,7 @@ volumes: minio: networks: - test-network: + oracle-network: cvat-human-bridge: name: cvat-human-bridge external: true diff --git a/packages/examples/cvat/exchange-oracle/docker-compose.test.head.yml b/packages/examples/cvat/exchange-oracle/docker-compose.test.head.yml index b885070446..825d84fa01 100644 --- a/packages/examples/cvat/exchange-oracle/docker-compose.test.head.yml +++ b/packages/examples/cvat/exchange-oracle/docker-compose.test.head.yml @@ -15,11 +15,12 @@ services: STORAGE_ENDPOINT_URL: 'host.docker.internal:9000' STORAGE_ACCESS_KEY: 'dev' STORAGE_SECRET_KEY: 'devdevdev' - STORAGE_RESULTS_BUCKET_NAME: 'results' + STORAGE_BUCKET_NAME: 'excor-data' STORAGE_USE_SSL: 'False' STORAGE_PROVIDER: 'aws' ENABLE_CUSTOM_CLOUD_HOST: 'Yes' REDIS_HOST: 'redis' + REDIS_PORT: 6379 depends_on: postgres: condition: service_started diff --git a/packages/examples/cvat/exchange-oracle/docker-compose.test.yml b/packages/examples/cvat/exchange-oracle/docker-compose.test.yml index 216ac36132..eb25d129b0 100644 --- a/packages/examples/cvat/exchange-oracle/docker-compose.test.yml +++ b/packages/examples/cvat/exchange-oracle/docker-compose.test.yml @@ -9,8 +9,6 @@ services: PGDATA: '/var/lib/postgresql/data/pgdata' networks: - test-network - ports: - - 5432:5432 redis: container_name: oracle-redis @@ -21,14 +19,12 @@ services: "--save", "60", "100", "--appendonly", "yes", ] - ports: - - 6379:6379 networks: - test-network minio: container_name: minio - image: minio/minio:RELEASE.2022-05-26T05-48-41Z + image: minio/minio:RELEASE.2025-09-07T16-13-09Z ports: - 9001:9001 - 9000:9000 @@ -36,10 +32,11 @@ services: MINIO_ROOT_USER: dev MINIO_ROOT_PASSWORD: devdevdev volumes: - - ./tests/utils/manifest.json:/tmp/manifests/manifest.json + # Each subdirectory under the shared assets dir seeds a same-named bucket. + - ./tests/assets/cloud:/tmp/cloud:ro entrypoint: 'sh' command: - -c "mkdir -p /data/manifests && cp /tmp/manifests/manifest.json /data/manifests/manifest.json && minio server /data --console-address ':9001'" + -c "mkdir -p /data && cp -r /tmp/cloud/. /data/ && minio server /data --console-address ':9001'" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] interval: 5s @@ -57,9 +54,11 @@ services: entrypoint: > /bin/sh -c " /usr/bin/mc config host add myminio http://minio:9000 dev devdevdev; + /usr/bin/mc mb -p myminio/datasets myminio/manifests myminio/excor-data myminio/recor-data; + /usr/bin/mc anonymous set public myminio/datasets; /usr/bin/mc anonymous set public myminio/manifests; - /usr/bin/mc mb myminio/results; - /usr/bin/mc anonymous set public myminio/results; + /usr/bin/mc anonymous set public myminio/excor-data; + /usr/bin/mc anonymous set public myminio/recor-data; " networks: - test-network diff --git a/packages/examples/cvat/exchange-oracle/poetry.lock b/packages/examples/cvat/exchange-oracle/poetry.lock index 720a2f24dd..13e2f3a12d 100644 --- a/packages/examples/cvat/exchange-oracle/poetry.lock +++ b/packages/examples/cvat/exchange-oracle/poetry.lock @@ -22,150 +22,202 @@ redis = ["redis (>=4.2.0)"] [[package]] name = "aiohappyeyeballs" -version = "2.4.6" +version = "2.7.1" description = "Happy Eyeballs for asyncio" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" files = [ - {file = "aiohappyeyeballs-2.4.6-py3-none-any.whl", hash = "sha256:147ec992cf873d74f5062644332c539fcd42956dc69453fe5204195e560517e1"}, - {file = "aiohappyeyeballs-2.4.6.tar.gz", hash = "sha256:9b05052f9042985d32ecbe4b59a77ae19c006a78f1344d7fdad69d28ded3d0b0"}, + {file = "aiohappyeyeballs-2.7.1-py3-none-any.whl", hash = "sha256:9243213661e29250eb41368e5daa826fc017156c3b8a11440826b2e3ed376472"}, + {file = "aiohappyeyeballs-2.7.1.tar.gz", hash = "sha256:065665c041c42a5938ed220bdcd7230f22527fbec085e1853d2402c8a3615d9d"}, ] [[package]] name = "aiohttp" -version = "3.11.12" +version = "3.14.1" description = "Async http client/server framework (asyncio)" optional = false -python-versions = ">=3.9" -files = [ - {file = "aiohttp-3.11.12-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:aa8a8caca81c0a3e765f19c6953416c58e2f4cc1b84829af01dd1c771bb2f91f"}, - {file = "aiohttp-3.11.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:84ede78acde96ca57f6cf8ccb8a13fbaf569f6011b9a52f870c662d4dc8cd854"}, - {file = "aiohttp-3.11.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:584096938a001378484aa4ee54e05dc79c7b9dd933e271c744a97b3b6f644957"}, - {file = "aiohttp-3.11.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:392432a2dde22b86f70dd4a0e9671a349446c93965f261dbaecfaf28813e5c42"}, - {file = "aiohttp-3.11.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:88d385b8e7f3a870146bf5ea31786ef7463e99eb59e31db56e2315535d811f55"}, - {file = "aiohttp-3.11.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b10a47e5390c4b30a0d58ee12581003be52eedd506862ab7f97da7a66805befb"}, - {file = "aiohttp-3.11.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b5263dcede17b6b0c41ef0c3ccce847d82a7da98709e75cf7efde3e9e3b5cae"}, - {file = "aiohttp-3.11.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50c5c7b8aa5443304c55c262c5693b108c35a3b61ef961f1e782dd52a2f559c7"}, - {file = "aiohttp-3.11.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d1c031a7572f62f66f1257db37ddab4cb98bfaf9b9434a3b4840bf3560f5e788"}, - {file = "aiohttp-3.11.12-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:7e44eba534381dd2687be50cbd5f2daded21575242ecfdaf86bbeecbc38dae8e"}, - {file = "aiohttp-3.11.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:145a73850926018ec1681e734cedcf2716d6a8697d90da11284043b745c286d5"}, - {file = "aiohttp-3.11.12-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:2c311e2f63e42c1bf86361d11e2c4a59f25d9e7aabdbdf53dc38b885c5435cdb"}, - {file = "aiohttp-3.11.12-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ea756b5a7bac046d202a9a3889b9a92219f885481d78cd318db85b15cc0b7bcf"}, - {file = "aiohttp-3.11.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:526c900397f3bbc2db9cb360ce9c35134c908961cdd0ac25b1ae6ffcaa2507ff"}, - {file = "aiohttp-3.11.12-cp310-cp310-win32.whl", hash = "sha256:b8d3bb96c147b39c02d3db086899679f31958c5d81c494ef0fc9ef5bb1359b3d"}, - {file = "aiohttp-3.11.12-cp310-cp310-win_amd64.whl", hash = "sha256:7fe3d65279bfbee8de0fb4f8c17fc4e893eed2dba21b2f680e930cc2b09075c5"}, - {file = "aiohttp-3.11.12-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:87a2e00bf17da098d90d4145375f1d985a81605267e7f9377ff94e55c5d769eb"}, - {file = "aiohttp-3.11.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b34508f1cd928ce915ed09682d11307ba4b37d0708d1f28e5774c07a7674cac9"}, - {file = "aiohttp-3.11.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:936d8a4f0f7081327014742cd51d320296b56aa6d324461a13724ab05f4b2933"}, - {file = "aiohttp-3.11.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2de1378f72def7dfb5dbd73d86c19eda0ea7b0a6873910cc37d57e80f10d64e1"}, - {file = "aiohttp-3.11.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9d45dbb3aaec05cf01525ee1a7ac72de46a8c425cb75c003acd29f76b1ffe94"}, - {file = "aiohttp-3.11.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:930ffa1925393381e1e0a9b82137fa7b34c92a019b521cf9f41263976666a0d6"}, - {file = "aiohttp-3.11.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8340def6737118f5429a5df4e88f440746b791f8f1c4ce4ad8a595f42c980bd5"}, - {file = "aiohttp-3.11.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4016e383f91f2814e48ed61e6bda7d24c4d7f2402c75dd28f7e1027ae44ea204"}, - {file = "aiohttp-3.11.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3c0600bcc1adfaaac321422d615939ef300df81e165f6522ad096b73439c0f58"}, - {file = "aiohttp-3.11.12-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:0450ada317a65383b7cce9576096150fdb97396dcfe559109b403c7242faffef"}, - {file = "aiohttp-3.11.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:850ff6155371fd802a280f8d369d4e15d69434651b844bde566ce97ee2277420"}, - {file = "aiohttp-3.11.12-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:8fd12d0f989c6099e7b0f30dc6e0d1e05499f3337461f0b2b0dadea6c64b89df"}, - {file = "aiohttp-3.11.12-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:76719dd521c20a58a6c256d058547b3a9595d1d885b830013366e27011ffe804"}, - {file = "aiohttp-3.11.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:97fe431f2ed646a3b56142fc81d238abcbaff08548d6912acb0b19a0cadc146b"}, - {file = "aiohttp-3.11.12-cp311-cp311-win32.whl", hash = "sha256:e10c440d142fa8b32cfdb194caf60ceeceb3e49807072e0dc3a8887ea80e8c16"}, - {file = "aiohttp-3.11.12-cp311-cp311-win_amd64.whl", hash = "sha256:246067ba0cf5560cf42e775069c5d80a8989d14a7ded21af529a4e10e3e0f0e6"}, - {file = "aiohttp-3.11.12-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e392804a38353900c3fd8b7cacbea5132888f7129f8e241915e90b85f00e3250"}, - {file = "aiohttp-3.11.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8fa1510b96c08aaad49303ab11f8803787c99222288f310a62f493faf883ede1"}, - {file = "aiohttp-3.11.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:dc065a4285307607df3f3686363e7f8bdd0d8ab35f12226362a847731516e42c"}, - {file = "aiohttp-3.11.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddb31f8474695cd61fc9455c644fc1606c164b93bff2490390d90464b4655df"}, - {file = "aiohttp-3.11.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9dec0000d2d8621d8015c293e24589d46fa218637d820894cb7356c77eca3259"}, - {file = "aiohttp-3.11.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3552fe98e90fdf5918c04769f338a87fa4f00f3b28830ea9b78b1bdc6140e0d"}, - {file = "aiohttp-3.11.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6dfe7f984f28a8ae94ff3a7953cd9678550dbd2a1f9bda5dd9c5ae627744c78e"}, - {file = "aiohttp-3.11.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a481a574af914b6e84624412666cbfbe531a05667ca197804ecc19c97b8ab1b0"}, - {file = "aiohttp-3.11.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1987770fb4887560363b0e1a9b75aa303e447433c41284d3af2840a2f226d6e0"}, - {file = "aiohttp-3.11.12-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a4ac6a0f0f6402854adca4e3259a623f5c82ec3f0c049374133bcb243132baf9"}, - {file = "aiohttp-3.11.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c96a43822f1f9f69cc5c3706af33239489a6294be486a0447fb71380070d4d5f"}, - {file = "aiohttp-3.11.12-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a5e69046f83c0d3cb8f0d5bd9b8838271b1bc898e01562a04398e160953e8eb9"}, - {file = "aiohttp-3.11.12-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:68d54234c8d76d8ef74744f9f9fc6324f1508129e23da8883771cdbb5818cbef"}, - {file = "aiohttp-3.11.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c9fd9dcf9c91affe71654ef77426f5cf8489305e1c66ed4816f5a21874b094b9"}, - {file = "aiohttp-3.11.12-cp312-cp312-win32.whl", hash = "sha256:0ed49efcd0dc1611378beadbd97beb5d9ca8fe48579fc04a6ed0844072261b6a"}, - {file = "aiohttp-3.11.12-cp312-cp312-win_amd64.whl", hash = "sha256:54775858c7f2f214476773ce785a19ee81d1294a6bedc5cc17225355aab74802"}, - {file = "aiohttp-3.11.12-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:413ad794dccb19453e2b97c2375f2ca3cdf34dc50d18cc2693bd5aed7d16f4b9"}, - {file = "aiohttp-3.11.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4a93d28ed4b4b39e6f46fd240896c29b686b75e39cc6992692e3922ff6982b4c"}, - {file = "aiohttp-3.11.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d589264dbba3b16e8951b6f145d1e6b883094075283dafcab4cdd564a9e353a0"}, - {file = "aiohttp-3.11.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5148ca8955affdfeb864aca158ecae11030e952b25b3ae15d4e2b5ba299bad2"}, - {file = "aiohttp-3.11.12-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:525410e0790aab036492eeea913858989c4cb070ff373ec3bc322d700bdf47c1"}, - {file = "aiohttp-3.11.12-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bd8695be2c80b665ae3f05cb584093a1e59c35ecb7d794d1edd96e8cc9201d7"}, - {file = "aiohttp-3.11.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0203433121484b32646a5f5ea93ae86f3d9559d7243f07e8c0eab5ff8e3f70e"}, - {file = "aiohttp-3.11.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40cd36749a1035c34ba8d8aaf221b91ca3d111532e5ccb5fa8c3703ab1b967ed"}, - {file = "aiohttp-3.11.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a7442662afebbf7b4c6d28cb7aab9e9ce3a5df055fc4116cc7228192ad6cb484"}, - {file = "aiohttp-3.11.12-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:8a2fb742ef378284a50766e985804bd6adb5adb5aa781100b09befdbfa757b65"}, - {file = "aiohttp-3.11.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2cee3b117a8d13ab98b38d5b6bdcd040cfb4181068d05ce0c474ec9db5f3c5bb"}, - {file = "aiohttp-3.11.12-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f6a19bcab7fbd8f8649d6595624856635159a6527861b9cdc3447af288a00c00"}, - {file = "aiohttp-3.11.12-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e4cecdb52aaa9994fbed6b81d4568427b6002f0a91c322697a4bfcc2b2363f5a"}, - {file = "aiohttp-3.11.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:30f546358dfa0953db92ba620101fefc81574f87b2346556b90b5f3ef16e55ce"}, - {file = "aiohttp-3.11.12-cp313-cp313-win32.whl", hash = "sha256:ce1bb21fc7d753b5f8a5d5a4bae99566386b15e716ebdb410154c16c91494d7f"}, - {file = "aiohttp-3.11.12-cp313-cp313-win_amd64.whl", hash = "sha256:f7914ab70d2ee8ab91c13e5402122edbc77821c66d2758abb53aabe87f013287"}, - {file = "aiohttp-3.11.12-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7c3623053b85b4296cd3925eeb725e386644fd5bc67250b3bb08b0f144803e7b"}, - {file = "aiohttp-3.11.12-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:67453e603cea8e85ed566b2700efa1f6916aefbc0c9fcb2e86aaffc08ec38e78"}, - {file = "aiohttp-3.11.12-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6130459189e61baac5a88c10019b21e1f0c6d00ebc770e9ce269475650ff7f73"}, - {file = "aiohttp-3.11.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9060addfa4ff753b09392efe41e6af06ea5dd257829199747b9f15bfad819460"}, - {file = "aiohttp-3.11.12-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34245498eeb9ae54c687a07ad7f160053911b5745e186afe2d0c0f2898a1ab8a"}, - {file = "aiohttp-3.11.12-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8dc0fba9a74b471c45ca1a3cb6e6913ebfae416678d90529d188886278e7f3f6"}, - {file = "aiohttp-3.11.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a478aa11b328983c4444dacb947d4513cb371cd323f3845e53caeda6be5589d5"}, - {file = "aiohttp-3.11.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c160a04283c8c6f55b5bf6d4cad59bb9c5b9c9cd08903841b25f1f7109ef1259"}, - {file = "aiohttp-3.11.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:edb69b9589324bdc40961cdf0657815df674f1743a8d5ad9ab56a99e4833cfdd"}, - {file = "aiohttp-3.11.12-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:4ee84c2a22a809c4f868153b178fe59e71423e1f3d6a8cd416134bb231fbf6d3"}, - {file = "aiohttp-3.11.12-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:bf4480a5438f80e0f1539e15a7eb8b5f97a26fe087e9828e2c0ec2be119a9f72"}, - {file = "aiohttp-3.11.12-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:e6b2732ef3bafc759f653a98881b5b9cdef0716d98f013d376ee8dfd7285abf1"}, - {file = "aiohttp-3.11.12-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f752e80606b132140883bb262a457c475d219d7163d996dc9072434ffb0784c4"}, - {file = "aiohttp-3.11.12-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ab3247d58b393bda5b1c8f31c9edece7162fc13265334217785518dd770792b8"}, - {file = "aiohttp-3.11.12-cp39-cp39-win32.whl", hash = "sha256:0d5176f310a7fe6f65608213cc74f4228e4f4ce9fd10bcb2bb6da8fc66991462"}, - {file = "aiohttp-3.11.12-cp39-cp39-win_amd64.whl", hash = "sha256:74bd573dde27e58c760d9ca8615c41a57e719bff315c9adb6f2a4281a28e8798"}, - {file = "aiohttp-3.11.12.tar.gz", hash = "sha256:7603ca26d75b1b86160ce1bbe2787a0b706e592af5b2504e12caa88a217767b0"}, +python-versions = ">=3.10" +files = [ + {file = "aiohttp-3.14.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8f6bb621e5863cfe8fe5ff5468002d200ec31f30f1280b259dc505b02595099e"}, + {file = "aiohttp-3.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4f7215cb3933784f79ed20e5f050e15984f390424339b22375d5a53c933a0491"}, + {file = "aiohttp-3.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d9d4e294455b23a68c9b8f042d0e8e377a265bcb15332753695f6e5b6819e0ce"}, + {file = "aiohttp-3.14.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b238af795833d5731d049d82bc84b768ae6f8f97f0495963b3ed9935c5901cc3"}, + {file = "aiohttp-3.14.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e4e5e0ae56914ecdbf446493addefc0159053dd53962cef37d7839f37f73d505"}, + {file = "aiohttp-3.14.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:092e4ce3619a7c6dee52a6bdabda973d9b34b66781f840ce93c7e0cec30cf521"}, + {file = "aiohttp-3.14.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bb33777ea21e8b7ecde0e6fc84f598be0a1192eab1a63bc746d75aa75d38e7bd"}, + {file = "aiohttp-3.14.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23119f8fd4f5d16902ed459b63b100bcd269628075162bddac56cc7b5273b3fb"}, + {file = "aiohttp-3.14.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:57fc6745a4b7d0f5a9eb4f40a69718be6c0bc1b8368cc9fe89e90118719f4f42"}, + {file = "aiohttp-3.14.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6fd35beba67c4183b09375c5fff9accb47524191a244a99f95fd4472f5402c2b"}, + {file = "aiohttp-3.14.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:672b9d65f42eb877f5c3f234a4547e4e1a226ca8c2eed879bb34670a0ce51192"}, + {file = "aiohttp-3.14.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:24ba13339fed9251d9b1a1bec8c7ab84c0d1675d79d33501e11f94f8b9a84e05"}, + {file = "aiohttp-3.14.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:94da27378da0610e341c4d30de29a191672683cc82b8f9556e8f7c7212a020fe"}, + {file = "aiohttp-3.14.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:52cdac9432d8b4a719f35094a818d95adcae0f0b4fe9b9b921909e0c87de9e7d"}, + {file = "aiohttp-3.14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:672ac254412a24d0d0cf00a9e6c238877e4be5e5fa2d188832c1244f45f31966"}, + {file = "aiohttp-3.14.1-cp310-cp310-win32.whl", hash = "sha256:2fe3607e71acc6ebb0ec8e492a247bf7a291226192dc0084236dfc12478916f6"}, + {file = "aiohttp-3.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:30099eda75a53c32efb0920e9c33c195314d2cc1c680fbfd30894932ac5f27df"}, + {file = "aiohttp-3.14.1-cp310-cp310-win_arm64.whl", hash = "sha256:5a837f49d901f9e368651b676912bff1104ed8c1a83b280bcd7b29adccef5c9c"}, + {file = "aiohttp-3.14.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:aa00140699487bd435fde4342d85c94cb256b7cd3a5b9c3396c67f19922afda2"}, + {file = "aiohttp-3.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1c1af67559445498b502030c35c59db59966f47041ca9de5b4e707f86bd10b5f"}, + {file = "aiohttp-3.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d44ec478e713ee7f29b439f7eb8dc2b9d4079e11ae114d2c2ac3d5daf30516c8"}, + {file = "aiohttp-3.14.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d3b1a184a9a8f548a6b73f1e26b96b052193e4b3175ed7342aaf1151a1f00a04"}, + {file = "aiohttp-3.14.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5f2504bc0322437c9a1ff6d3333ca56c7477b727c995f036b976ae17b98372c8"}, + {file = "aiohttp-3.14.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:73f05ea02013e02512c3bf42714f1208c57168c779cc6fe23516e4543089d0a6"}, + {file = "aiohttp-3.14.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:797457503c2d426bee06eef808d07b31ede30b65e054444e7de64cad0061b7af"}, + {file = "aiohttp-3.14.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b821a1f7dedf7e37450654e620038ac3b2e81e8fa6ea269337e97101978ec730"}, + {file = "aiohttp-3.14.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4cd96b5ba05d67ed0cf00b5b405c8cd99586d8e3481e8ee0a831057591af7621"}, + {file = "aiohttp-3.14.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d459b98a932296c6f0e94f87511a0b1b90a8a02c30a50e60a297619cd5a58ee"}, + {file = "aiohttp-3.14.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:764457a7be60825fb770a644852ff717bcbb5042f189f2bd16df61a81b3f6573"}, + {file = "aiohttp-3.14.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f7a16ef45b081454ef844502d87a848876c490c4cb5c650c230f6ec79ed2c1e7"}, + {file = "aiohttp-3.14.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2fbc3ed048b3475b9f0cbcb9978e9d2d3511acd91ead203af26ed9f0056004cf"}, + {file = "aiohttp-3.14.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bedb0cd073cc2dc035e30aeb99444389d3cd2113afe4ef9fcd23d439f5bade85"}, + {file = "aiohttp-3.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b6feea921016eb3d4e04d65fc4e9ca402d1a3801f562aef94989f54694917af3"}, + {file = "aiohttp-3.14.1-cp311-cp311-win32.whl", hash = "sha256:313701e488100074ce99850404ee36e741abf6330179fec908a1944ecf570126"}, + {file = "aiohttp-3.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:03ab4530fdcb3a543a122ba4b65ac9919da9fe9f78a03d328a6e38ff962f7aa5"}, + {file = "aiohttp-3.14.1-cp311-cp311-win_arm64.whl", hash = "sha256:486f7d16ed54c39c2cbd7ca71fd8ba2b8bb7860df65bd7b6ed640bab96a38a8b"}, + {file = "aiohttp-3.14.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d35143e27778b4bb0fb189562d7f275bff79c62ab8e98459717c0ea617ff2480"}, + {file = "aiohttp-3.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bcfb80a2cc36fba2534e5e5b5264dc7ae6fcd9bf15256da3e53d2f499e6fa29d"}, + {file = "aiohttp-3.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27fd7c91e51729b4f7e1577865fa6d34c9adccbc39aabe9000285b48af9f0ec2"}, + {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:64c567bf9eaf664280116a8688f63016e6b32db2505908e2bdaca1b6438142f2"}, + {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f5e6ff2bdbb8f4cd3fbe41f99e25bbcd58e3bf9f13d3dd31a11e7917251cc77a"}, + {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2f73e01dc37122325caf079982621262f96d74823c179038a82fddfc50359264"}, + {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bb2c0c80d431c0d03f2c7dbf125150fedd4f0de17366a7ca33f7ccb822391842"}, + {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3e6fc1a85fa7194a1a7d19f44e8609180f4a8eb5fa4c7ed8b4355f080fad235c"}, + {file = "aiohttp-3.14.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:686b6c0d3911ec387b444ddf5dc62fb7f7c0a7d5186a7861626496a5ab4aff95"}, + {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c6fa4dc7ad6f8109c70bb1499e589f76b0b792baf39f9b017eb92c8a81d0a199"}, + {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:87a5eea1b2a5e21e1ebdbb33ad4165359189327e63fc4e4894693e7f821ac817"}, + {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1c1421eb01d4fd608d88cc8290211d177a58532b55ad94076fb349c5bf467f0a"}, + {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:34b257ec41345c1e8f2df68fa908a7952f5de932723871eb633ecbbff396c9a4"}, + {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:de538791a80e5d862addbc183f70f0158ac9b9bb872bb147f1fd2a683691e087"}, + {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f71173be42d3241d428f760122febb748de0623f44308a6f120d0dd9ec572e3"}, + {file = "aiohttp-3.14.1-cp312-cp312-win32.whl", hash = "sha256:ec8dc383ee57ea3e883477dcca3f11b65d58199f1080acaf4cd6ad9a99698be4"}, + {file = "aiohttp-3.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:2aa92c87868cd13674989f9ee83e5f9f7ea4237589b728048e1f0c8f6caa3271"}, + {file = "aiohttp-3.14.1-cp312-cp312-win_arm64.whl", hash = "sha256:2c840c90759922cb5e6dda94596e079a30fb5a5ba548e7e0dc00574703940847"}, + {file = "aiohttp-3.14.1-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:b3a03285a7f9c7b016324574a6d92a1c895da6b978cb8f1deee3ac72bc6da178"}, + {file = "aiohttp-3.14.1-cp313-cp313-android_21_x86_64.whl", hash = "sha256:2a73f487ab8ef5abbb24b7aa9b73e98eaba9e9e031804ff2416f02eca315ccaf"}, + {file = "aiohttp-3.14.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:915fbb7b41b115192259f8c9ae58f3ddc444d2b5579917270211858e606a4afd"}, + {file = "aiohttp-3.14.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:7fb4bdf95b0561a79f259f9d28fbc109728c5ee7f27aff6391f0ca703a329abe"}, + {file = "aiohttp-3.14.1-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:1b9748363260121d2927704f5d4fc498150669ca3ae93625986ee89c8f80dcd4"}, + {file = "aiohttp-3.14.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:86a6dab78b0e43e2897a3bbe15745aa60dc5423ca437b7b0b164c069bf91b876"}, + {file = "aiohttp-3.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4dfd6e47d3c44c2279907607f73a4240b88c69eb8b90da7e2441a8045dfd21da"}, + {file = "aiohttp-3.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:317acd9f8602858dc7d59679812c376c7f0b97bcbbf16e0d6237f54141d8a8a6"}, + {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd869c427324e5cb15195793de951295710db28be7d818247f3097b4ab5d4b96"}, + {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:93b032b5ec3255473c143627d21a69ac74ae12f7f33974cb587c564d11b1066f"}, + {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f234b4deb12f3ad59127e037bc57c40c21e45b45282df7d3a55a0f409f595296"}, + {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9af6779bfb46abf124068327abcdf9ce95c9ef8287a3e8da76ccf2d0f16c28fa"}, + {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:faccab372e66bc76d5731525e7f1143c922271725b9d38c9f97edcc66266b451"}, + {file = "aiohttp-3.14.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f380468b09d2a81633ee863b0ec5648d364bd17bb8ecfb8c2f387f7ac1faf42c"}, + {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:97e704dcd26271f5bda3fa07c3ce0fb76d6d3f8659f4baa1a24442cc9ba177ca"}, + {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:269b76ac5394092b95bc4a098f4fc6c191c083c3bd12775d1e30e663132f6a09"}, + {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c0b3e614340c889d575451696374c9d17affd54cd607ca0babed8f8c37b9397"}, + {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:5663ee9257cfa1add7253a7da3035a02f31b6600ec48261585e1800a81533080"}, + {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:603a2c834142172ffddc054067f5ec0ca65d57a0aa98a71bc81952573208e345"}, + {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cb21957bb8aca671c1765e32f58164cf0c50e6bf41c0bbbd16da20732ecaf588"}, + {file = "aiohttp-3.14.1-cp313-cp313-win32.whl", hash = "sha256:e509a55f681e6158c20f70f102f9cf61fb20fbc382272bc6d94b7343f2582780"}, + {file = "aiohttp-3.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:1ac8531b638959718e18c2207fbfe297819875da46a740b29dfa29beba64355a"}, + {file = "aiohttp-3.14.1-cp313-cp313-win_arm64.whl", hash = "sha256:250d14af67f6b6a1a4a811049b1afa69d61d617fca6bf33149b3ab1a6dbcf7b8"}, + {file = "aiohttp-3.14.1-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:7c106c26852ca1c2047c6b80384f17100b4e439af276f21ef3d4e2f450ae7e15"}, + {file = "aiohttp-3.14.1-cp314-cp314-android_24_x86_64.whl", hash = "sha256:20205f7f5ade7aaec9f4b500549bbc071b046453aed72f9c06dcab87896a83e8"}, + {file = "aiohttp-3.14.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:62a759436b29e677181a9e76bab8b8f689a29cb9c535f45f7c48c9c830d3f8c3"}, + {file = "aiohttp-3.14.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:2964cbf553df4d7a57348da44d961d871895fc1ee4e8c322b2a95612c7b17fba"}, + {file = "aiohttp-3.14.1-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:237651caadc3a59badd39319c54642b5299e9cc98a3a194310e55d5bb9f5e397"}, + {file = "aiohttp-3.14.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:896e12dfdbbab9d8f7e16d2b28c6769a60126fa92095d1ebf9473d02593a2448"}, + {file = "aiohttp-3.14.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d03f281ed22579314ba00821ce20115a7c0ac430660b4cc05704a3f818b3e004"}, + {file = "aiohttp-3.14.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:07eabb979d236335fed927e137a928c9adfb7df3b9ec7aa31726f133a62be983"}, + {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4fe1f1087cbadb280b5e1bb054a4f00d1423c74d6626c5e48400d871d34ecefe"}, + {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:367a9314fdc79dab0fac96e216cb41dd73c85bdca85306ce8999118ba7e0f333"}, + {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a24f677ebe83749039e7bdf862ff0bbb16818ae4193d4ef96505e269375bcce0"}, + {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c83afe0ba876be7e943d2e0ba645809ad441575d2840c895c21ee5de93b9377a"}, + {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:634e385930fb6d2d479cf3aa66515955863b77a5e3c2b5894ca259a25b308602"}, + {file = "aiohttp-3.14.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eeea07c4397bbc57719c4eed8f9c284874d4f175f9b6d57f7a1546b976d455ca"}, + {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:335c0cc3e3545ce98dcb9cfcb836f40c3411f43fa03dab757597d80c89af8a35"}, + {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:ae6be797afdef264e8a84864a85b196ca06045586481b3df8a967322fd2fa844"}, + {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:8560b4d712474335d08907db7973f71912d3a9a8f1dee992ec06b5d2fe359496"}, + {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7edd08e0a5deb1e8564a2fcd8f4561014a3f05252334671bbf55ddd47db0e5"}, + {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:b6ff7fcee63287ae57b5df3e4f5957ce032122802509246dec1a5bcc55904c95"}, + {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6ffbb2f4ec1ceaff7e07d43922954da26b223d188bf30658e561b98e23089444"}, + {file = "aiohttp-3.14.1-cp314-cp314-win32.whl", hash = "sha256:a9875b46d910cff3ea2f5962f9d266b465459fe634e22556ab9bd6fc1192eea0"}, + {file = "aiohttp-3.14.1-cp314-cp314-win_amd64.whl", hash = "sha256:af8b4b81a960eeaf1234971ac3cd0ba5901f3cd42eae42a46b4d089a8b492719"}, + {file = "aiohttp-3.14.1-cp314-cp314-win_arm64.whl", hash = "sha256:cf4491381b1b57425c315a56a439251b1bdac07b2275f19a8c44bc57744532ec"}, + {file = "aiohttp-3.14.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:819c054312f1af92947e6a55883d1b66feefab11531a7fc45e0fb9b63880b5c2"}, + {file = "aiohttp-3.14.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:10ee9c1753a8f706345b22496c79fbddb5be0599e0823f3738b1534058e25340"}, + {file = "aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1601cc37baf5750ccacae618ec2daf020769581695550e3b654a911f859c563d"}, + {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4d6e0ac9da31c9c04c84e1c0182ad8d6df35965a85cae29cd71d089621b3ae94"}, + {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9e8f2d660c350b3d0e259c7a7e3d9b7fc8b41210cbcc3d4a7076ff0a5e5c2fdc"}, + {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4691802dda97be727f79d86818acaad7eb8e9252626a1d6b519fedbb92d5e251"}, + {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c389c482a7e9b9dc3ee2701ac46c4125297a3818875b9c305ddb603c04828fd1"}, + {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fc0cacab7ba4e56f0f81c82a98c09bed2f39c940107b03a34b168bdf7597edd3"}, + {file = "aiohttp-3.14.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:979ed4717f59b8bb12e3963378fa285d93d367e15bcd66c721311826d3c44a6c"}, + {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:38e1e7daaea81df51c952e18483f323d878499a1e2bfe564790e0f9701d6f203"}, + {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:4132e72c608fe9fecb8f409113567605915b83e9bdd3ea56538d2f9cd35002f1"}, + {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:eefd9cc9b6d4a2db5f00a26bc3e4f9acf71926a6ec557cd56c9c6f27c290b665"}, + {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:b165790117eea512d7f3fb22f1f6dad3d55a7189571993eb015591c1401276d1"}, + {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:ed09c7eb1c391271c2ed0314a51903e72a3acb653d5ccfc264cdf3ef11f8269d"}, + {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:99abd37084b82f5830c635fddd0b4993b9742a66eb746dacf433c8590e8f9e3c"}, + {file = "aiohttp-3.14.1-cp314-cp314t-win32.whl", hash = "sha256:47ddf841cdecc810749921d25606dee45857d12d2ad5ddb7b5bd7eab12e4b365"}, + {file = "aiohttp-3.14.1-cp314-cp314t-win_amd64.whl", hash = "sha256:5e78b522b7a6e27e0b25d19b247b75039ac4c94f99823e3c9e53ae1603a9f7e9"}, + {file = "aiohttp-3.14.1-cp314-cp314t-win_arm64.whl", hash = "sha256:90d53f1609c29ccc2193945ef732428382a28f78d0456ae4d3daf0d48b74f0f6"}, + {file = "aiohttp-3.14.1.tar.gz", hash = "sha256:307f2cff90a764d329e77040603fa032db89c5c24fdad50c4c15334cba744035"}, ] [package.dependencies] -aiohappyeyeballs = ">=2.3.0" -aiosignal = ">=1.1.2" +aiohappyeyeballs = ">=2.5.0" +aiosignal = ">=1.4.0" async-timeout = {version = ">=4.0,<6.0", markers = "python_version < \"3.11\""} attrs = ">=17.3.0" frozenlist = ">=1.1.1" multidict = ">=4.5,<7.0" propcache = ">=0.2.0" +typing_extensions = {version = ">=4.4", markers = "python_version < \"3.13\""} yarl = ">=1.17.0,<2.0" [package.extras] -speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] +speedups = ["Brotli (>=1.2)", "aiodns (>=3.3.0)", "backports.zstd", "brotlicffi (>=1.2)"] [[package]] name = "aiosignal" -version = "1.3.2" +version = "1.4.0" description = "aiosignal: a list of registered asynchronous callbacks" optional = false python-versions = ">=3.9" files = [ - {file = "aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5"}, - {file = "aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54"}, + {file = "aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e"}, + {file = "aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7"}, ] [package.dependencies] frozenlist = ">=1.1.0" +typing-extensions = {version = ">=4.2", markers = "python_version < \"3.13\""} [[package]] name = "alembic" -version = "1.13.1" +version = "1.18.5" description = "A database migration tool for SQLAlchemy." optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "alembic-1.13.1-py3-none-any.whl", hash = "sha256:2edcc97bed0bd3272611ce3a98d98279e9c209e7186e43e75bbb1b2bdfdbcc43"}, - {file = "alembic-1.13.1.tar.gz", hash = "sha256:4932c8558bf68f2ee92b9bbcb8218671c627064d5b08939437af6d77dc05e595"}, + {file = "alembic-1.18.5-py3-none-any.whl", hash = "sha256:06d8ba9d04558022f5395e9317de03d270f3dced49cee01f89fe7a13c26f14bc"}, + {file = "alembic-1.18.5.tar.gz", hash = "sha256:1554982221dd17e9a749b53902407578eb305e453f71999e8c7f0a48389fff8e"}, ] [package.dependencies] Mako = "*" -SQLAlchemy = ">=1.3.0" -typing-extensions = ">=4" +SQLAlchemy = ">=1.4.23" +tomli = {version = "*", markers = "python_version < \"3.11\""} +typing-extensions = ">=4.12" [package.extras] -tz = ["backports.zoneinfo"] +tz = ["tzdata"] + +[[package]] +name = "annotated-doc" +version = "0.0.4" +description = "Document parameters, class attributes, return types, and variables inline, with Annotated." +optional = false +python-versions = ">=3.8" +files = [ + {file = "annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320"}, + {file = "annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4"}, +] [[package]] name = "annotated-types" @@ -180,584 +232,545 @@ files = [ [[package]] name = "anyio" -version = "4.2.0" -description = "High level compatibility layer for multiple asynchronous event loop implementations" +version = "4.14.2" +description = "High-level concurrency and networking framework on top of asyncio or Trio" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "anyio-4.2.0-py3-none-any.whl", hash = "sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee"}, - {file = "anyio-4.2.0.tar.gz", hash = "sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f"}, + {file = "anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494"}, + {file = "anyio-4.14.2.tar.gz", hash = "sha256:cfa139f3ed1a23ee8f88a145ddb5ac7605b8bbfd8592baacd7ce3d8bb4313c7f"}, ] [package.dependencies] exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} idna = ">=2.8" -sniffio = ">=1.1" -typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} +typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] -doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] -trio = ["trio (>=0.23)"] +trio = ["trio (>=0.32.0)"] [[package]] name = "apscheduler" -version = "3.10.4" +version = "3.11.3" description = "In-process task scheduler with Cron-like capabilities" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "APScheduler-3.10.4-py3-none-any.whl", hash = "sha256:fb91e8a768632a4756a585f79ec834e0e27aad5860bac7eaa523d9ccefd87661"}, - {file = "APScheduler-3.10.4.tar.gz", hash = "sha256:e6df071b27d9be898e486bc7940a7be50b4af2e9da7c08f0744a96d4bd4cef4a"}, + {file = "apscheduler-3.11.3-py3-none-any.whl", hash = "sha256:bbeb2ec02d23d3c06a6c07ed7f0f3939ada6680eb121fae809a69bb42c537a30"}, + {file = "apscheduler-3.11.3.tar.gz", hash = "sha256:cd2fcc9330039a81a5893472ad49facf23a6d5604cbe1d918c835c6de7834d5a"}, ] [package.dependencies] -pytz = "*" -six = ">=1.4.0" -tzlocal = ">=2.0,<3.dev0 || >=4.dev0" +tzlocal = ">=3.0" [package.extras] -doc = ["sphinx", "sphinx-rtd-theme"] +doc = ["packaging", "sphinx", "sphinx-rtd-theme (>=1.3.0)"] +etcd = ["etcd3", "protobuf (<=3.21.0)"] gevent = ["gevent"] mongodb = ["pymongo (>=3.0)"] redis = ["redis (>=3.0)"] rethinkdb = ["rethinkdb (>=2.4.0)"] sqlalchemy = ["sqlalchemy (>=1.4)"] -testing = ["pytest", "pytest-asyncio", "pytest-cov", "pytest-tornado5"] +test = ["APScheduler[etcd,mongodb,redis,rethinkdb,sqlalchemy,tornado,zookeeper]", "PySide6", "anyio (>=4.5.2)", "gevent", "pytest", "pytest-timeout", "pytz", "twisted"] tornado = ["tornado (>=4.3)"] twisted = ["twisted"] zookeeper = ["kazoo"] [[package]] name = "async-timeout" -version = "4.0.3" +version = "5.0.1" description = "Timeout context manager for asyncio programs" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, - {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, + {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"}, + {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"}, ] [[package]] name = "attrs" -version = "23.2.0" +version = "26.1.0" description = "Classes Without Boilerplate" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" 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-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309"}, + {file = "attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32"}, ] -[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]"] - [[package]] name = "bitarray" -version = "3.1.0" +version = "3.9.0" description = "efficient arrays of booleans -- C extension" optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "bitarray-3.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3c1fad6456993f604726dcb21d1f003430988d5138f858d79e5b8682f56dfad6"}, - {file = "bitarray-3.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0dc0f28340929fffa17fbd3eca5bfae5c1827f3000c0bd9312999d8c5b1464a0"}, - {file = "bitarray-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84de57891a80944e259956fd72bd542290b76c063182f0e85ce5380c49cfcfb6"}, - {file = "bitarray-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b3f4be402e7c611a0a7048f3d042b9e4d697ca6f721d08098118d1ae8bb8a69c"}, - {file = "bitarray-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eabaee3c7d411f6ed48f92752e61a409530a0ebf65498bd408432800a804e0b8"}, - {file = "bitarray-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cb6c270c49d6779af97586a955977493146626ae34710a4c1ec84cb0115f4d4"}, - {file = "bitarray-3.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:481a00d710c7811b38563f6fe22da20be2e6f722196f68873e12d23f4fdf82c1"}, - {file = "bitarray-3.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b81bbefe9d205af66a15a3097f8b66f29fe767fa9cb5dd5a7881f53d2505c2d5"}, - {file = "bitarray-3.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:506df7b12e1380f56cfa20b9c203518afe585f0b86e850a96e3691cf0175e4c0"}, - {file = "bitarray-3.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:43ec740770723de6c99f0a858807ef905664f31cf254e0b803f3dd2797537d7a"}, - {file = "bitarray-3.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:4deac3da54c3df136d6615a2410d5a6170353b4d08142273266296c376fb1889"}, - {file = "bitarray-3.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c58cbd0cc9f6347fffa36a6870fac695cd6e98c39fcfd8002d44a70fba03cd8c"}, - {file = "bitarray-3.1.0-cp310-cp310-win32.whl", hash = "sha256:e092a5c4cc9ae6bc757bc1fee8894cd0275f0a0689c8f57555b00e198cdbcecc"}, - {file = "bitarray-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:453395201790f16b22092c25bed6ecf3bafee7f36db840d4cfc07cd9b6f9628f"}, - {file = "bitarray-3.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a1cb97bdc51e3db8def039607ca42d12c6e55fb134a8d211cca2fcf0a7b3a986"}, - {file = "bitarray-3.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:92d8130efa6bebd4903b70f6d98832aabbd78c1031bc64c7c9d4e39b9db3bfa6"}, - {file = "bitarray-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37a9559ab050618902f8b8055c5b0b78dfc2a7974656fddee26b033ec56945f7"}, - {file = "bitarray-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2c57a4e8f0d9eb5cef7c83c8a4fd8bf06c35d641fc3cb24bf9511adb54e2d8a"}, - {file = "bitarray-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d9bcaa1764d0d302050a31b0f6879ea20e3900b2e73b4ea647ab570950c2062b"}, - {file = "bitarray-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:769184a57abfdfc24c37bb5d0f3836ffe65c7c5cdbeec431766520cd246a27c6"}, - {file = "bitarray-3.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8f247387bb58b8c626088be2fa4ca5869fb12638b45acd29fab21aee48529560"}, - {file = "bitarray-3.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1303604e4069699cef3e969f31d6c3e8e5a0bc637569d90b3647469eff91dc7b"}, - {file = "bitarray-3.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f238c2eb7a0a6a50537e5d182edb629901af94746854108483f0b11b0e3d1a78"}, - {file = "bitarray-3.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e43a96b9b63348d9e5cca70fc31b5d0f07a420a70ef89b376aa4148b87d24b39"}, - {file = "bitarray-3.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5255fb9e4e4879adea5fb61cbde347767d346e29822a51ca21816f28340f4cdb"}, - {file = "bitarray-3.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:68bab51a827abc6f037ea76bb374ec28804a47b51716f9eb3f7da3d754bc8431"}, - {file = "bitarray-3.1.0-cp311-cp311-win32.whl", hash = "sha256:7ff061c714ff62357ff3be23d96c73944ad9181b8b21d49c29ed82fb2fb0efa4"}, - {file = "bitarray-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:b2f8aed62de760be852e0dee0ad507e0fe17fc12f83b36cc0bfe4900e0a0e915"}, - {file = "bitarray-3.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4c298fefda9dfe2ef24aee8fe48acc3a1a063b266791a814330c6932248785c4"}, - {file = "bitarray-3.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e9211fb3a109ba76cb8bd0f76645d256f8a46e733693de22d0d7857941603cee"}, - {file = "bitarray-3.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b6bfe0a618301f0afed9004b8230a413ad399b58fef50a744a623461b96d8e3"}, - {file = "bitarray-3.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2db21d733e06d0d5b86fd3c848a84b8930e71250542aa7602e2c048b96fce163"}, - {file = "bitarray-3.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3807c38b37a500583eafd4ae866d2a051834acd4e11cd8557af9cf5379fa7e21"}, - {file = "bitarray-3.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcd15f43e846bfdaac8e5420006eba2d6adce29b6336492cf9d651e4a313ea86"}, - {file = "bitarray-3.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc2266e15f02d3192d1c2d29a790a4eccb230e23de0de6136815b32f9cdd5b4d"}, - {file = "bitarray-3.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:54a6a8525bc66228ed9cc69d562979319ef151dba2ed302bf7a21c7e124c137b"}, - {file = "bitarray-3.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ffb6b3a6efdabe6a4f3042b16a68499711a7835e950847a5643f60a43de3335f"}, - {file = "bitarray-3.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:430302c3ca7ed0dbb629db87e24a3be082851d71777787d4c8ad424624363780"}, - {file = "bitarray-3.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:d4277999453fa63e96ed8a31698c9ac64ee5f38bd5c63205d69d9b73780fa152"}, - {file = "bitarray-3.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f8fab5053ff281954718dc56c44ee7d1462ccc7e296b84da504b72b01c6c0c41"}, - {file = "bitarray-3.1.0-cp312-cp312-win32.whl", hash = "sha256:598072dbe456cc57270c6f34fa6b9aafd56bb5291e0d14f8509c1522f6d77f32"}, - {file = "bitarray-3.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:4fed8491a77f9fa5303bf6a24a76fcafbf1b496bb22d72b213b673ef8ce6e201"}, - {file = "bitarray-3.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ea4a888e45fdabc89705837b10030a990ec4879d14fccc3b9450ab56ca9d7ec"}, - {file = "bitarray-3.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2695c23b9857105631e9d4f8ebbcc8a4e55c6c9f31bc80d9e5e018e377d650d8"}, - {file = "bitarray-3.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:577a1ffc6318cdcbf91e8492596004bb1572ce3c703aa42c16c8ac1188625b8d"}, - {file = "bitarray-3.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1221d5d1255a74397f938ff822d8df4b0cc416b74e5659d21c3fe5f3d06590a1"}, - {file = "bitarray-3.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91e9309912700ab085cf78d162ad0bf0d3de35e5e084868400672b4ce3befbb0"}, - {file = "bitarray-3.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8c319f77118bac6aded58a0d2f172ac1b06e00bfa5391033848864e39bfd771"}, - {file = "bitarray-3.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:08004c22af11a234a73a8edf744524fb67e89ab4c80791f647c522687ddcb4b9"}, - {file = "bitarray-3.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:afb4d8876fff11cced4377f055498fd3c179e6e2bf7165fd055dabc494005252"}, - {file = "bitarray-3.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7c228c78bd20f2a46a2f3f2e349292c604ae26210dad56afe4b64ea65f72db75"}, - {file = "bitarray-3.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:139115998ffcffd8b883e1f21ced6f1d96947c5ace51f9656ceccedea5765557"}, - {file = "bitarray-3.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7e3ade382c9a5d5d77635041dd2aaa4e59326c8f62e1fb33ce28ddaeaa6ae7b6"}, - {file = "bitarray-3.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5efdb6403d206068d434caf9deb7ab936732c06e5617a63e213c94ac750303f4"}, - {file = "bitarray-3.1.0-cp313-cp313-win32.whl", hash = "sha256:69721fef0427a7f56ed7eef16ff9ddec96c64cee4d7abb5e7511c9aedebafc0f"}, - {file = "bitarray-3.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:34d75765b5c558e7bffa247493412831c6edb5c40e639a6ac94999bc6f40a6c8"}, - {file = "bitarray-3.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6b85d01d8cf30937d9f55d2029a0f7575e9b559d606e6fff17bb79c2830e0afb"}, - {file = "bitarray-3.1.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:acdac94fa2853e74503248b4079a30f3c09ab993f1b2a393fd88071824bdb0de"}, - {file = "bitarray-3.1.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f851a69521240418fc1ab6b313ef5ef6533e451a46184077b1f5e410441c7d9a"}, - {file = "bitarray-3.1.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf6be47880210416d3cd2405fd9a5f28b8fd1896b77acf729024f64b4ecd2676"}, - {file = "bitarray-3.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf4d0759d431953324de2ab251b954123bd4dfa83c990370814a88306f1ffc53"}, - {file = "bitarray-3.1.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a0e1e3836468b62c079a69dbbfcdb8f0abb8dc8540f5cfca48147a8178cc95ea"}, - {file = "bitarray-3.1.0-cp36-cp36m-musllinux_1_2_aarch64.whl", hash = "sha256:0b380164b3b2ff5aa833ee2cf00855645308f14694546ca02beca6b9069e3c75"}, - {file = "bitarray-3.1.0-cp36-cp36m-musllinux_1_2_i686.whl", hash = "sha256:de8ce30fb9e9d2fa063abf8f9443d7bdf77b5de52a5cffbfd007f6150e6bee96"}, - {file = "bitarray-3.1.0-cp36-cp36m-musllinux_1_2_ppc64le.whl", hash = "sha256:72b0f7cbc5c0bf008fde06b7777474a942cc0aa9c743dafc583a1dc430a07122"}, - {file = "bitarray-3.1.0-cp36-cp36m-musllinux_1_2_s390x.whl", hash = "sha256:ccd384e435d9c540c7e54c9149abbf462691e8a6c9287448d44da9f22230e09b"}, - {file = "bitarray-3.1.0-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:37d8da058472b2fedd27903781d5ea27264cde11dcb81a3237724427de83f241"}, - {file = "bitarray-3.1.0-cp36-cp36m-win32.whl", hash = "sha256:f78e2a4fd88b6fa383f44ca866cf6b5e1c0370de7ace7a0b4af7b3f11d806558"}, - {file = "bitarray-3.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:a394cfcd6d9f7fac71429df8e8c4b93b1f0db3ef7a06eb84d9f69d901b862ee4"}, - {file = "bitarray-3.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:756da43ac44b1cbf576a02b3e9710fa24f14823b38df95868ea8a3fea840c725"}, - {file = "bitarray-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:638026c90fb135f0014a47bc5e9d5ed8acff8bbc3283f05e811e9f84a1f32a0e"}, - {file = "bitarray-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f90b57ea9aa9c6159c4a9110e8f787194583ede08b6ff5a6ea36c17b8973b75"}, - {file = "bitarray-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:93cb9b8e2cda9006d489bfa8e7f4fe5680860b6ff45fa9081a6554a9e661fa97"}, - {file = "bitarray-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2225ce0383a2e6950865f178513d8939c89782e909cbcfe4dd7c4f572b1e5a1"}, - {file = "bitarray-3.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bf22a95774a3d04200605bef8f436867df3ec87a13033fc482cce7ce17f62644"}, - {file = "bitarray-3.1.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:226297bb0a9f6636c3b74cfa39a1feec7fbd26c6b59fd9d5b78c4066a87aa571"}, - {file = "bitarray-3.1.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f4c28344774fadb554489f3a8c7a9c75237a85996a8a6d5d91ffa781bdd7b1ff"}, - {file = "bitarray-3.1.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:ce05239a8422ca3ebb1f00cf3577a1d255f07f7dd4c2ab20e8e009da393b86f3"}, - {file = "bitarray-3.1.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:9ce0f80904644ddbdad42eb1eb3945c19bc274b8b0e0844c7f7b9effafd279d0"}, - {file = "bitarray-3.1.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:c467bf00939b162144862d167dd55a651e44c256805f25e44edbd547fc0b0922"}, - {file = "bitarray-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:90b714bc59a9dd11d1bba0d68dd395a3e51f275c8547e9b68af561763a61196e"}, - {file = "bitarray-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4cbbe82edbe2f93f2598042d208caa87969025537ddce34cf647e4da6c4f6af4"}, - {file = "bitarray-3.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:34dd123c69a7f8520c20b45351df1d169429b9e636425c3c8278fdde80151fe6"}, - {file = "bitarray-3.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:03ae745110d4e343d78f5c3836058d510222b17469b1eb64362cdba7cbdfa26a"}, - {file = "bitarray-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfef13ba01363e185f3c7ffd8dc84c109a2be7da4d035b289c8f8a94b02c8183"}, - {file = "bitarray-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:798a71af5e1cded785dabc2f03bf65cd021a7e0ea54d8874a49cbb64669694e2"}, - {file = "bitarray-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d5eb9d2389c76469c4f10d636a79bcd13142d863a5d07a962738ae55fa60dfa"}, - {file = "bitarray-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a0a9c6a9fe679cd48204c719329de0ce72dede6f8e862744adcaf85b1d0c4c6"}, - {file = "bitarray-3.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a97cb1a6cf3538ecda5ce537111f246f468919ca38ff6cfe188f99ee3353c8f2"}, - {file = "bitarray-3.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6d49b0748e9aa0b3bcec4074675405d6a1b19288fb0e8ad8bc6db95c66840747"}, - {file = "bitarray-3.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:b57959f7538b93cb058aa8c467cfd8b82c0af88a2168a4f382ff77e3a90274ee"}, - {file = "bitarray-3.1.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:752e2de8b0094d56a6e98516609f4d2b9a2027d1a9038de3f021a7d1d13d0599"}, - {file = "bitarray-3.1.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:5b90b46cc73fc2db871985ae93132c7945f264aea6000348a124ba84b48af980"}, - {file = "bitarray-3.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:491d5c5b34b00c971be98b36736e090c847b0e2904a1b097a32bb02226fb11ba"}, - {file = "bitarray-3.1.0-cp38-cp38-win32.whl", hash = "sha256:515d954219d9b81b6442ab270cb8142100f32eac06f00f0c588da6c1416c9a1f"}, - {file = "bitarray-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:40c3f234b515aa8cfce0adc1df2b9c3b45e4307f8b756c9f3069cbc3effb5acb"}, - {file = "bitarray-3.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6fdd73f8f563b1f0d106c09949bd90b1104464b5cd148c02b7dae4e3efdb1dcd"}, - {file = "bitarray-3.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0c609504ce985754867a91db78fb1d5110df589447233badb5a1d453fb2e1714"}, - {file = "bitarray-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff398a6850da105e5cf13e4297f1bd181d90c16a4db9ce20e0608e1edf9c81b0"}, - {file = "bitarray-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:39f32b9c1b03f2c2cec002513ef91a9818cf85e8da94069e430d71256c0b858c"}, - {file = "bitarray-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9d6e940dfefe604ecbd77849b107319c73f51dfb24ae18c80710dad9bdb59244"}, - {file = "bitarray-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19c3a7f80b286bd4df0fcbddbe97fd8b48028c0497678ee1f0bab820978295bd"}, - {file = "bitarray-3.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47b6cbbecd24d3b943cef3e704dbf9b510dec310251e1c279d10105cb40a33d8"}, - {file = "bitarray-3.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ab0063f8264cae001fc24238bf8b90a424be25b952951b749b647fd615011428"}, - {file = "bitarray-3.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:86544ffdf8d0cb7271acb5c3a560f4c7850f4c11057cc9c9acdadbea125aa68a"}, - {file = "bitarray-3.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:56ce6219922715fa8f9c65a40a504d4a5e64504ed7c4f3fac64071117559ef33"}, - {file = "bitarray-3.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:56fac415c19689b327f22ca6c02ffa908009f21aab931230d292d5239de40094"}, - {file = "bitarray-3.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e47bee13f43dfc5c5c3661e70b350a5dd37f62f25e196c9a20f504ca02774ac6"}, - {file = "bitarray-3.1.0-cp39-cp39-win32.whl", hash = "sha256:df4ea0d3035298716550b20396d831bc5871efbba7f9cc8e84eabd0906c0163e"}, - {file = "bitarray-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:7c96ecf342bf6093523477cf1eacd958df5206564aef347d3d2d8d4541a1c6a0"}, - {file = "bitarray-3.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c0790bbbe08b141d6a93061e68d1954c86374ca4982e5586becdf7dc0d61e95c"}, - {file = "bitarray-3.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:dde6268797d6e3f0639b1a5048eee5e42aa63fd00c4477741f9a5b1720f1aa8f"}, - {file = "bitarray-3.1.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea7791224248fe8ad6f5533877f94850b5636cf957f245a2f4854da21d0be766"}, - {file = "bitarray-3.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea7319e68ad1cb081dd7d1b2fe1242c12fe8f9ee3c78812db010b18e9753f7bb"}, - {file = "bitarray-3.1.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3aab1395cd4a23b1815f87120e59e1a66a5f3e92cbe42e4653b9fae1320e0eeb"}, - {file = "bitarray-3.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:729ede2a88c0b379080606f2dd6ff4b4fc1798683f1fb244d79e929b298784c4"}, - {file = "bitarray-3.1.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fe0998dfa82776c17c262b20c2ff735f310aed4c85dcc2614ed389815a6bb4ef"}, - {file = "bitarray-3.1.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19f7b08cabfeed0190fbfcf7aad2cd71bb6934f319bd9f195b138616ebc56edf"}, - {file = "bitarray-3.1.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ba0aede899cd78952977db93cf24f5845163efbe85e4220de95298976d3c54b"}, - {file = "bitarray-3.1.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6370b01839750fcb3aea8639344fb3898f73dac42abe344bc5e39669b93fe110"}, - {file = "bitarray-3.1.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:37901e3b417ae482858c29be7b963ef1e6cf0ac16f03f4852295aee1aa77ac18"}, - {file = "bitarray-3.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7eb06912a72f5728864808a68abc1e247bc24c9983a1f3e400f9954245715fac"}, - {file = "bitarray-3.1.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:b9fe9c40c13c0c796bee8d6416185c59f270eb9d22dfb7f6b1cadd0d8be3b4c8"}, - {file = "bitarray-3.1.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44b93406e302f1077c9b4c4b990a40a7afbebab66e4579dce2b06d7f55d8e7c7"}, - {file = "bitarray-3.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:984803aa15421f3bade7c05fd44ab6acdcebe16b646f3201f5ccf1a111ba7661"}, - {file = "bitarray-3.1.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d39a36b6b95889a4cbc1d3083053cebe3315c13ff9a8760c14a3fe9cd8a102b1"}, - {file = "bitarray-3.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:41282599c51e26bc491a3d1471a785a0158c529a2e99757a353a708a9df66655"}, - {file = "bitarray-3.1.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4653e4cab6001a97c6689a4bfe3517128a74656eaa5df22f6ce01fd9b264db30"}, - {file = "bitarray-3.1.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:8d6ef7906263c12a27361ec06e89180a01f8ac57ffa0e1cdf7953948505fea4e"}, - {file = "bitarray-3.1.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:868e0a4fc33333b9cfaa9a0c6b847ce64e7d2064162c2183608244a649487d0a"}, - {file = "bitarray-3.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c64123ae24065478a17d2c6ed08e7e9ea6131be054326a01c9b13f5e36ac1a95"}, - {file = "bitarray-3.1.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6dcceb74c288777e86dbf2497e0bfc444aecf1e710e8a030ea4dba13600ac066"}, - {file = "bitarray-3.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:244897669375d345fe67cd5c0701ec5ea81991a9193fa8cfa4bcb55277375eff"}, - {file = "bitarray-3.1.0.tar.gz", hash = "sha256:71757171a45eac58782861c49137ba3bed0da489155311857f69f4e9baf81fa4"}, + {file = "bitarray-3.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:af7906ffe12fa285014c85a89c165c8f1e6fd485438f08be84e7107d0acdd804"}, + {file = "bitarray-3.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dd5b6d915c21ab53d3f9e32c44335fd1fbcd948589634aba87926432c8897446"}, + {file = "bitarray-3.9.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:89d0e3de109ebc26d713c8c0ca7868d2ca8a2ad812a7dab587a6f4c7b3cf6908"}, + {file = "bitarray-3.9.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2f3c3252914a837a610f25f12a6bf88406fdfadba4de60dad75c20db93fb6b60"}, + {file = "bitarray-3.9.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:dc79aa810daabc3c5eb5f29b8425390e65dac04f02ddc84809eeaef7fc6569dc"}, + {file = "bitarray-3.9.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ae003034bcaba92e534e7237fc6b03e8b4c161ac2e4707155321ea2d9b2d1557"}, + {file = "bitarray-3.9.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8705d00a47326174f606e26d141faba6c0ca7b494f0989bc93d92b1b2527cb49"}, + {file = "bitarray-3.9.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:2ccc1f0f10167e118e965f5b56577445dcdf38bae43e6fdf802c124e518fee8c"}, + {file = "bitarray-3.9.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:bf4b4f57d37e27208298365abf7ee102e2137b29c82cf2f2b996efc08a960202"}, + {file = "bitarray-3.9.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d81d8f90603eaa4de9ae6342fa656e549aa4b510e2d7cde9d7f43d2482600818"}, + {file = "bitarray-3.9.0-cp310-cp310-win32.whl", hash = "sha256:5de49c9dbe5d60f704242ae5ccc35aafb161e61b229e3536b01b6dba58fde4c0"}, + {file = "bitarray-3.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:8863e0461ebed5ff39bfbc73ff9caac78f78834549c727b5f539f1bd3e80849c"}, + {file = "bitarray-3.9.0-cp310-cp310-win_arm64.whl", hash = "sha256:f3509e45507abf43dc584b30de1c9b1adcd5949a7307488ab5df8d9c2bc03181"}, + {file = "bitarray-3.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d66b965ab369284c187c38c9cd5d6e638e863db856ee244c739ad5ec07769645"}, + {file = "bitarray-3.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c019a95da22eca2793dd80db95758ff82cfc17f8813fd6a926cca5fd93b1bd7f"}, + {file = "bitarray-3.9.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b9d16a362f454abe9ef7d362fb9260b0a7945e64a53d35effb10c7fd64da415"}, + {file = "bitarray-3.9.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8f118e3f43a01d7326c30d95eafda951e0823596f1659f4a5a54ab032341d5f4"}, + {file = "bitarray-3.9.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bc6db5b0d52ab31136da48d2913aad14e5ba3bfd5522d75c4d9bda2700c66768"}, + {file = "bitarray-3.9.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:19b6cbca02cdfb27a6fb6e0d4f9170a53da2c37fce70bc5afa6d58aab6d1f1af"}, + {file = "bitarray-3.9.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9c45b31ddef2d4f50224cb5cbe1ac0af4909555340fdf88e65da5c9c7e912cb3"}, + {file = "bitarray-3.9.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:cc9cc3025e9453239843d1c4431c5aca700bec246e9071596b8240193e91af2f"}, + {file = "bitarray-3.9.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e79e4c283ed834b0587b0fde21ced22251a569255b338de1e466d901c8d07d5e"}, + {file = "bitarray-3.9.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4e52b54a8e639da6e80ddeaca9aa3ca324ca20bdcd4cd51f6070ca4b334113a1"}, + {file = "bitarray-3.9.0-cp311-cp311-win32.whl", hash = "sha256:b664bd8174795df4f0353c9ff3d997f5ae764285753c785bf6aa0afab75a357a"}, + {file = "bitarray-3.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:eb5e65d4c2da36446a4592f50e0393a0255e832bdd5d519391a216728cface15"}, + {file = "bitarray-3.9.0-cp311-cp311-win_arm64.whl", hash = "sha256:2d7b0167098b7a423e8b8fcd2d4291aa99b97589e53b6b182c0b456a79a78cd5"}, + {file = "bitarray-3.9.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:541890dd453021a6f8155e7d091a6589652f703832a41c959eb139b487b67ad2"}, + {file = "bitarray-3.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c5f11802751285f982a333192f1336ce94017eedb6ea5f8e05039484ca00b24d"}, + {file = "bitarray-3.9.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1acbb40c630d0429d5a7e8879896f43ddb998625d380d94664239dae9bb4978d"}, + {file = "bitarray-3.9.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e55a6e8e5c14546a90db3c5c93d68dc73c8d86ed19556aa58cd6d558286ae620"}, + {file = "bitarray-3.9.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1f2d47d0f451f42c328544e9a8968d168e452934eef218e6e68e5b14b6711a3a"}, + {file = "bitarray-3.9.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:353430288ff7e2a97029dea750d3095bf85089f8d7757dff52b46d71c0b635ff"}, + {file = "bitarray-3.9.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:63e934aecbad62ed3b591877b7f4ce2c9b7b28376ef70448cb657338911350c1"}, + {file = "bitarray-3.9.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6272808ed86948389e3fb6723474691f4dd3475ccbd2f8b1232feec517b2c394"}, + {file = "bitarray-3.9.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2c0aceb582baabb97612647193fd6160f9766250b7d1f034d1be7d5f2b2d88ca"}, + {file = "bitarray-3.9.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6e3fe6fc6bf914e1a538e955c1260f64ccb174136ac798811f2a5f904e437def"}, + {file = "bitarray-3.9.0-cp312-cp312-win32.whl", hash = "sha256:7ad4eb391e138958b69d9f1521e45e537ad4a66eba9ba90bb4a99ada6fa1fc90"}, + {file = "bitarray-3.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:71070085c168cb5cb0972c09c9f36995a34fab2807c15f2f64f0dee6014f1008"}, + {file = "bitarray-3.9.0-cp312-cp312-win_arm64.whl", hash = "sha256:3075370a7aaec476b0f3ce501f83cfa1797fa722619f7f130981403978b1ad89"}, + {file = "bitarray-3.9.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:62e5a7520f3d2b632438f94c9b9bddf1b2c0e9154e69c8c62e32accf680b3fdc"}, + {file = "bitarray-3.9.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:867994fb56cbfe40c77b1c5d0527e4d6ef4141b3ea2aca2aa02bd89ca08ae2d2"}, + {file = "bitarray-3.9.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:255090e32993dc0b10cd29ad49e21cd7349ed9cdb44d61ad970b4a698b7bd1e7"}, + {file = "bitarray-3.9.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:21facaa003c1a6487eaada863fc93059ee2f542a9ca589f7c5716a1e4ceddfd0"}, + {file = "bitarray-3.9.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c5636104b949b937ef47bcc700665befc2f5a1e906036cba6fdb978501adca11"}, + {file = "bitarray-3.9.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:17e721ed7695257f5f0a8147633f96a60b5ac13735c73d29b2409d1b5a484062"}, + {file = "bitarray-3.9.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:68f66a71bcfbedd1144b8d21b54fa77e32f90067fc3e49abc0a479392697c3cd"}, + {file = "bitarray-3.9.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e780526164e5c4051cf8618e73ecaf0c900c7c3ea2cdd99558b486e47cbe28c9"}, + {file = "bitarray-3.9.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f6abac81451d0d0ce5ee553b9c7e6b9de165642ffe949c1379e6f553f482066e"}, + {file = "bitarray-3.9.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:db0a55d52d9056187670e8e7e525a2aa5f4a74a4459e9455aa68c0198b4ac2fc"}, + {file = "bitarray-3.9.0-cp313-cp313-win32.whl", hash = "sha256:e5799c01e961273136d95ade2164c689714bdfcdc443f9e2568b45df620248d2"}, + {file = "bitarray-3.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:eba091b89bfaf931709e09b8bc564101c7c834d2978019784dd97e017e84d060"}, + {file = "bitarray-3.9.0-cp313-cp313-win_arm64.whl", hash = "sha256:c13cb765f5dd30eefec0046cde1c2eee11b76cd749b045e54f1aa0a15057d219"}, + {file = "bitarray-3.9.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:988ab837bb55951dbddb8b26db0d4a2e9eb3fd2bcf1dfd29ab96b046ff96dd2a"}, + {file = "bitarray-3.9.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d3d27fa77487455de1a3aa6b593dd23eeb5971357b96453daf60307e7a623188"}, + {file = "bitarray-3.9.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4213db72d8ee547df486dce28cde286346bc7a01f8e22fdeea1f8f0c18d1c9eb"}, + {file = "bitarray-3.9.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:212559f1a69c89cdd4ebd487f1581818b67939a3ac157a32f26ab29d29414b84"}, + {file = "bitarray-3.9.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:080e8530a7b56ba843bdad6c4cf9887506944be180222e6691d7aee13f977868"}, + {file = "bitarray-3.9.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05dc8db96a184eeb4e9d51f558602fa51eaa651790aa5d50f7fd2c5306e1bc16"}, + {file = "bitarray-3.9.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:64ccb1873db36d71c90de7611f3bfcad5cae889293bfe81c28d5c0eefa1065d3"}, + {file = "bitarray-3.9.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:eea7a98b277e6a19cdf2e74908a534826f552d7a0d75c17b8fc6f4d886653695"}, + {file = "bitarray-3.9.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:1608a8f62d17323f4b7a92dd731fff8e30562f8a18bab4758aba5fb1d7df9d78"}, + {file = "bitarray-3.9.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:21ab3b432cc4d73fdac310bd500bc54473116c85107acecb27b9d6805ff8b48b"}, + {file = "bitarray-3.9.0-cp314-cp314-win32.whl", hash = "sha256:a1774b7f06b2d705cc0332245b71e18c6f0ddaf6925cce2d0b8eaa30c58b5164"}, + {file = "bitarray-3.9.0-cp314-cp314-win_amd64.whl", hash = "sha256:fc8c5da04dfce44a9446d3e2348924252b72db98a22d1576b2ce66f34dc7fb99"}, + {file = "bitarray-3.9.0-cp314-cp314-win_arm64.whl", hash = "sha256:784d4180c38a0db82fa4a0c7ac54e92cbb9137b0336f7d5f9f433179fab0e56a"}, + {file = "bitarray-3.9.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:737230129bae3649dedfccc4b20040b76805c8a5ff9b3c7f0564775850bcdf58"}, + {file = "bitarray-3.9.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:caaecd574c5ea9c3168654779c0633b08a4c346fe97b38c2896d7846dcfd85cb"}, + {file = "bitarray-3.9.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b3123de3aee13dad947e4e30e1f580cb78fa24c2d103fd5a11e429ea2d55dc0f"}, + {file = "bitarray-3.9.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:513007e9a05ab9247ff5bba5c5bd43557fc40c8fe80fd50be3570760ef449601"}, + {file = "bitarray-3.9.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c9fac669b0c19362b69818eb04358d912ffdaf2b6ee039e4f358271ba8095dc"}, + {file = "bitarray-3.9.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24cbd77670da7e6fe2218b2905a88ecaafd456017673cc7b47b06caf47ff0d77"}, + {file = "bitarray-3.9.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:918a29d788a5a29001dcf20b25da00c0cda6998861d1346358a0a1611dcf2be7"}, + {file = "bitarray-3.9.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:496d8ae6fbc1f870a04d40148ff6daa1357c94543498de5c33612d5969aed074"}, + {file = "bitarray-3.9.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:52b8690da0334d0d1b0907a5011dc08415d0514468296233dd2296b50be2dcc8"}, + {file = "bitarray-3.9.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:41807c5be6b3c0730d2472fd5973d44e22498c610f60a3c00aefe41bb3caa2e2"}, + {file = "bitarray-3.9.0-cp314-cp314t-win32.whl", hash = "sha256:81c12f37cd31e254be3a12454e2933d5668d811ecfc5bbf7cd6f9c54cb5fda60"}, + {file = "bitarray-3.9.0-cp314-cp314t-win_amd64.whl", hash = "sha256:feec62af25b9d81c5013280e44d512a2991784c3f9969fde3ca7327016cc1ab0"}, + {file = "bitarray-3.9.0-cp314-cp314t-win_arm64.whl", hash = "sha256:6334497cd63bf03c5a7c8b58b2b701a3d9aca692e3d82c722a577fe97f7d085f"}, + {file = "bitarray-3.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a3e61827396b12ca67ec7752fef1ca5791cdc019c273bc3c1eb66912b5e8161e"}, + {file = "bitarray-3.9.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6f71689369b38d21ab8d1800f1e6cdbaeeb40c0384bafbd2aa062ba181b96e0c"}, + {file = "bitarray-3.9.0-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:535191f9f5250f044f701461a0a5e86028383c7531cd6554858a402fd8af34a4"}, + {file = "bitarray-3.9.0-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:df8451534b06c8c64801a317d7e4f91889cadaf0a02b74dd2f1cb4955f3fbd46"}, + {file = "bitarray-3.9.0-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:dcd69e150af52ce706ad436b6350c6783ce111aee33e6114806c56933c0c05a0"}, + {file = "bitarray-3.9.0-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2a055a3d80e113d644bc067a40787e6bbce216f896b8767136700fb35522718c"}, + {file = "bitarray-3.9.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:0e95b101a31f3655ac37548a0b3239fdcde87e745881c3ccef7192e2711e9e41"}, + {file = "bitarray-3.9.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:af29f1c1b47e68b921099cfb7744a9e875d79087b6d15fbed918559d8629794f"}, + {file = "bitarray-3.9.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:8fd928a528300f6b9e69d5e00145ceb81e81009749950cdc2f5f7ab7e704de85"}, + {file = "bitarray-3.9.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:3edab70dd2b35240526d3fa0ece098335758173a5ab3582970069ac2dd2f7d6e"}, + {file = "bitarray-3.9.0-cp38-cp38-win32.whl", hash = "sha256:e0dc39f7d0df33c390793716180cb1f1b0adbd5f9701d0adaa608b1ec8867d6e"}, + {file = "bitarray-3.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:2faf64e69dcb308efa0cfa2618552a05c0197e2ee5858facfa47678e5a571fd9"}, + {file = "bitarray-3.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1f5c17c55630255ece343964306070d713559e4f32cd6c394235b64ece6e1b34"}, + {file = "bitarray-3.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8c999433dbe25b3fe8514f1deb2552c9d8d0bdc2b7d7c66c81234894f3254e05"}, + {file = "bitarray-3.9.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:27571ac93c8dbf9bc5f3594257a1d3f2591da08a91fb972083cee334d5828f4a"}, + {file = "bitarray-3.9.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:43569be23ff90190ce7b1b05c2c5072a5ee8d3d09fb076a4ac0a846043179758"}, + {file = "bitarray-3.9.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c16e0377c0a96cdc8eb072e3e31cedfec0dc29fd7d2bb58d63f796771578d49d"}, + {file = "bitarray-3.9.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a6e7134f857a3ab0fe52a6b84b387e31ee2a7c5af77945172221978deda8c7e7"}, + {file = "bitarray-3.9.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f3a90ff32822d70fedf93bd9c057ae88176372fb478c2c376c5257eacfecf27c"}, + {file = "bitarray-3.9.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:2f2749855f3a60ab8d7250f9b549cc7ce77883fb52a7ccac82cdab322f92e305"}, + {file = "bitarray-3.9.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:0e0099dc02f63383c06602e9c73fe0d347d760c7ba23940328e9075cabedc71f"}, + {file = "bitarray-3.9.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0eb630289dad8930a4ad8a634a03a962545c1015b0d90425e1b36a900fc36277"}, + {file = "bitarray-3.9.0-cp39-cp39-win32.whl", hash = "sha256:83943314d6605f7cdc9272937f91f5d9a3446a927cfae89e77502611dfb37d5d"}, + {file = "bitarray-3.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:56315f6d8f967555999d00920ada3712a60af17c4862853162cc837ce7fd635c"}, + {file = "bitarray-3.9.0-cp39-cp39-win_arm64.whl", hash = "sha256:e9d0dfc81d27b44045bdda606dda40452c53e19e2755f56407dfa393980e91c5"}, + {file = "bitarray-3.9.0.tar.gz", hash = "sha256:af5f91e61d868c8f457f66cd726ef31d69264f71edbaccd70fdbb13548c1d652"}, ] [[package]] name = "boto3" -version = "1.34.30" +version = "1.43.50" description = "The AWS SDK for Python" optional = false -python-versions = ">= 3.8" +python-versions = ">=3.10" files = [ - {file = "boto3-1.34.30-py3-none-any.whl", hash = "sha256:cd6173380768faaecf6236dbdcec15d8d032cbb162ce354fdb111056a74fc298"}, - {file = "boto3-1.34.30.tar.gz", hash = "sha256:9e1476ce2b26437881a0381bf2daa54de619ac74ab4bd74278668acda6004a64"}, + {file = "boto3-1.43.50-py3-none-any.whl", hash = "sha256:779eb5cfa8bd1d615f36051465f8182860219eef78b4ab8ca2c666bb56702325"}, + {file = "boto3-1.43.50.tar.gz", hash = "sha256:a6865b9cd1d15511f6aad89cef964105acecff2160a3e29ae53c10d9821416af"}, ] [package.dependencies] -botocore = ">=1.34.30,<1.35.0" +botocore = ">=1.43.50,<1.44.0" jmespath = ">=0.7.1,<2.0.0" -s3transfer = ">=0.10.0,<0.11.0" +s3transfer = ">=0.19.0,<0.20.0" [package.extras] crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.34.30" +version = "1.43.50" description = "Low-level, data-driven core of boto 3." optional = false -python-versions = ">= 3.8" +python-versions = ">=3.10" files = [ - {file = "botocore-1.34.30-py3-none-any.whl", hash = "sha256:caf82d91c2ff61235284a07ffdfba006873e0752e00896052f901a37720cefa4"}, - {file = "botocore-1.34.30.tar.gz", hash = "sha256:e071a9766e7fc2221ca42ec01dfc54368a7518610787342ea622f6edc57f7891"}, + {file = "botocore-1.43.50-py3-none-any.whl", hash = "sha256:4a57a1e0dd4a8be855c29183fc0e029c18e9ec84cd4ac172869f3e800f972528"}, + {file = "botocore-1.43.50.tar.gz", hash = "sha256:7b07c423c44b1ab3815af103f11fa28ea317e28dda1335718a02ecde371a25e9"}, ] [package.dependencies] jmespath = ">=0.7.1,<2.0.0" python-dateutil = ">=2.1,<3.0.0" -urllib3 = {version = ">=1.25.4,<2.1", markers = "python_version >= \"3.10\""} +urllib3 = ">=1.25.4,<2.2.0 || >2.2.0,<3" [package.extras] -crt = ["awscrt (==0.19.19)"] +crt = ["awscrt (==0.32.2)"] [[package]] name = "cachelib" -version = "0.13.0" +version = "0.14.0" description = "A collection of cache libraries in the same API interface." optional = false python-versions = ">=3.8" files = [ - {file = "cachelib-0.13.0-py3-none-any.whl", hash = "sha256:8c8019e53b6302967d4e8329a504acf75e7bc46130291d30188a6e4e58162516"}, - {file = "cachelib-0.13.0.tar.gz", hash = "sha256:209d8996e3c57595bee274ff97116d1d73c4980b2fd9a34c7846cd07fd2e1a48"}, -] - -[[package]] -name = "cachetools" -version = "5.3.2" -description = "Extensible memoizing collections and decorators" -optional = false -python-versions = ">=3.7" -files = [ - {file = "cachetools-5.3.2-py3-none-any.whl", hash = "sha256:861f35a13a451f94e301ce2bec7cac63e881232ccce7ed67fab9b5df4d3beaa1"}, - {file = "cachetools-5.3.2.tar.gz", hash = "sha256:086ee420196f7b2ab9ca2db2520aca326318b68fe5ba8bc4d49cca91add450f2"}, + {file = "cachelib-0.14.0-py3-none-any.whl", hash = "sha256:4671000b032baa8fac47ad19850f4f522785cee764b4e04c5cfe8955a18d67de"}, + {file = "cachelib-0.14.0.tar.gz", hash = "sha256:73fedcadd0ba818fb2bb9f3c7cd5fcc2a71e86286f1842f55f28d500faee17f1"}, ] [[package]] name = "certifi" -version = "2023.11.17" +version = "2026.6.17" description = "Python package for providing Mozilla's CA Bundle." optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, - {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, + {file = "certifi-2026.6.17-py3-none-any.whl", hash = "sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db"}, + {file = "certifi-2026.6.17.tar.gz", hash = "sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432"}, ] [[package]] name = "cffi" -version = "1.16.0" +version = "2.1.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"}, +python-versions = ">=3.10" +files = [ + {file = "cffi-2.1.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:b65f590ef2a44640f9a05dbb548a429b4ade77913ce683ac8b1480777658a6c0"}, + {file = "cffi-2.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164bff1657b2a74f0b6d54e11c9b375bc97b931f2ca9c43fcf875838da1570dd"}, + {file = "cffi-2.1.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:c941bb58d5a6e1c3892d86e42927ed6c180302f07e6d395d08c416e594b98b46"}, + {file = "cffi-2.1.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a016194dbe13d14ee9556e734b772d8d67b947092b268d757fd4290e3ba2dfc2"}, + {file = "cffi-2.1.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:03e9810d18c646077e501f661b682fbf5dee4676048527ca3cffe66faa9960dd"}, + {file = "cffi-2.1.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:19c54ac121cad98450b4896fa9a43ee0180d57bc4bc911a33db6cab1efab6cd3"}, + {file = "cffi-2.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d433a51f1870e43a13b6732f92aaf540ff77c2015097c78556f75a2d6c030e0"}, + {file = "cffi-2.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3d7f118b5adbfdfead90c25822690b02bc8074fba949bb7858bec4ebd55adb43"}, + {file = "cffi-2.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c5f5df567f6eb216de69be06ce55c8b714090fae02b18a3b40da8163b8c5fa9c"}, + {file = "cffi-2.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:11b3fb55f4f8ad92274ed26705f65d8f91457de71f5380061eb6d125a768fecd"}, + {file = "cffi-2.1.0-cp310-cp310-win32.whl", hash = "sha256:9d72af0cf10a76a600a9690078fe31c63b9588c8e86bf9fd353f713c84b5db0f"}, + {file = "cffi-2.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb62edb5bb52cca65fab91a63afa7561607120d26090a7e8fda6fb9f064726da"}, + {file = "cffi-2.1.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:02cb7ff33ded4f1532476731f89ede53e2e488a8e6205515a82144246ffa7dcc"}, + {file = "cffi-2.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f5bce581e6b8c235e566a14768a943b172ada3ed73537bb0c0be1edee312d4e7"}, + {file = "cffi-2.1.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:30b65779d598c370374fefabf138d456fd6f3216bfa7bedfab1ba82025b0cd93"}, + {file = "cffi-2.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88023dfe18799507b73f1dbb0d14326a17465de1bc9c9c7655c22845e9ddc3a2"}, + {file = "cffi-2.1.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:0a96b74cda968eebbad56d973efe5098974f0a9fb323865bf99ea1fd24e3e64c"}, + {file = "cffi-2.1.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:a5781494d4d400a3f47f8f1da94b324f6e6b440a53387774002890a2a2f4b50f"}, + {file = "cffi-2.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aa7a1b53a2a4452ada2d1b5dade9960b2522f1e61293a811a077439e39029565"}, + {file = "cffi-2.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9d8272c0e483b024e1b9ad029821470ed8ec65631dbd90217469da0e7cd89f1c"}, + {file = "cffi-2.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7762faa47e8ff7eb80bd261d9a7d8eea2d8baa69de5e95b70c1f338bbe712f02"}, + {file = "cffi-2.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:89095c1968b4ba8285840e131bf2891b09ae137fe2146905acae0354fbce1b5e"}, + {file = "cffi-2.1.0-cp311-cp311-win32.whl", hash = "sha256:64c753a0f87a256020004f37a1c8c02c480e725f910f0b2a0f3f07debd1b2479"}, + {file = "cffi-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:4f26194e3d95e06501b942642855aed4f953d55e95d7d01b7c4483db3ecff458"}, + {file = "cffi-2.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:35aaea0c7ee0e58a5cd8c2fd1a48fdf7ece0d2699b7ecdda08194e9ce5dd9b3d"}, + {file = "cffi-2.1.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:df2b82571a1b30f58a87bf4e5a9e78d2b1eff6c6ce8fd3aa3757221f93f0863f"}, + {file = "cffi-2.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78474632761faa0fb96f30b1c928c84ebcf68713cbb80d15bab09dfe61640fde"}, + {file = "cffi-2.1.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:5972433ad71a9e46516584ef60a0fda12d9dc459938d1539c3ddecf9bdc1368d"}, + {file = "cffi-2.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b6422532152adf4e59b110cb2808cee7a033800952f5c036b4af047ee43199e7"}, + {file = "cffi-2.1.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:46b1c8db8f6122420f32d02fffb924c2fe9bc772d228c7c711748fff56aabb2b"}, + {file = "cffi-2.1.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9fafc5aa2e2a39aaf7f8cc0c1f044a9b07fca12e558dca53a3cc5c654ad67a7"}, + {file = "cffi-2.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1e9f50d192a3e525b15a75ab5114e442d83d657b7ec29182a991bc9a88fd3a66"}, + {file = "cffi-2.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:98fff996e983a36d3aa2eca83af40c5821202e7e6f32d13ae94e3d2286f10cfe"}, + {file = "cffi-2.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:379de10ce1ba048b1448599d1b37b24caee16309d1ac98d3982fc997f768700b"}, + {file = "cffi-2.1.0-cp312-cp312-win32.whl", hash = "sha256:9b8f0f26ca4e7513c534d351eca551947d053fac438f2a04ac96d882909b0d3a"}, + {file = "cffi-2.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:c97f080ea627e2863524c5af3836e2270b5f5dfff1f104392b959f8df0c5d384"}, + {file = "cffi-2.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:6d194185eabd279f1c05ebe3504265ddfc5ad2b58d0714f7db9f01da592e9eb6"}, + {file = "cffi-2.1.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:10537b1df4967ca26d21e5072d7d54188354483b91dc75058968d3f0cf13fbda"}, + {file = "cffi-2.1.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:a95b05f9baf29b91171b3a8bd2020b028835243e7b0ff6bb23e2a3c228518b1b"}, + {file = "cffi-2.1.0-cp313-cp313-macosx_10_15_x86_64.whl", hash = "sha256:15faec4adfff450819f3aee0e2e02c812de6edb88203aa58807955db2003472a"}, + {file = "cffi-2.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:716ff8ec22f20b4d988b12884086bcef0fc99737043e503f7a3935a6be99b1ea"}, + {file = "cffi-2.1.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:63960549e4f8dc41e31accb97b975abaecfc44c03e396c093a6436763c2ea7db"}, + {file = "cffi-2.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ff067a8d8d880e7809e4ac88eb009bb848870115317b306666502ccad30b147f"}, + {file = "cffi-2.1.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:3b926723c13eba9f81d2ef3820d63aeceec3b2d4639906047bf675cb8a7a500d"}, + {file = "cffi-2.1.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:47ff3a8bfd8cb9da1af7524b965127095055654c177fcfc7578debcb015eecd0"}, + {file = "cffi-2.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:799416bae98336e400981ff6e532d67d5c709cfb30afb79865a1315f94b0e224"}, + {file = "cffi-2.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:961be50688f7fba2fa65f63712d3b9b341a22311f5253460ce933f52f0de1c8c"}, + {file = "cffi-2.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bf5c6cf48238b0eb4c086978c492ad1cbc22373fc5b2d7353b3a598ce6db887a"}, + {file = "cffi-2.1.0-cp313-cp313-win32.whl", hash = "sha256:db3eb7d46527159a878ec3460e9d40615bc25ba337d477db681aea6e4f05c5d2"}, + {file = "cffi-2.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:8e74a6135550c4748af665b1b1118b6aab33b1fc6a16f9aff630af107c3b4512"}, + {file = "cffi-2.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:2282cd5e38aa8accd03e99d1256af8411c84cdbee6a89d841b563fdbd1f3e50f"}, + {file = "cffi-2.1.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:d2117334c3af3bdcb9a88522b844a2bdb5efdc4f71c6c822df55486ae1c3347a"}, + {file = "cffi-2.1.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:702c436735fbe99d59ada02a1f65cfc0d31c0ee8b7290912f8fbc5cd1e4b16c3"}, + {file = "cffi-2.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1ff3456eab0d889592d1936d6125bbfbc7ae4d3354a700f8bd80450a66445d4d"}, + {file = "cffi-2.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c4165821e131d6d4ca444347c2b694e2311bcfa3fe5a861cc72968f28867beac"}, + {file = "cffi-2.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:276f20fffd7b396e12516ba8edf9509210ac248cbbc5acbc39cd512f9f59ebe6"}, + {file = "cffi-2.1.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7d5980a3433d4b71a5e120f9dd551403d7824e31e2e67124fe2769c404c06913"}, + {file = "cffi-2.1.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:6ca4919c6e4f89aa99c42510b42cf54596892c00b3f9077f6bdd1505e24b9c8d"}, + {file = "cffi-2.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d53d10f7da99ae46f7373b9150393e9c5eab9b224909982b43832668de4779f5"}, + {file = "cffi-2.1.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c351efb95e832a853a29361675f33a7ce53de1a109cd73fd47af0712213aa4ce"}, + {file = "cffi-2.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:dbf7c7a88e2bac086f06d14577332760bdeecc42bdec8ac4077f6260557d9326"}, + {file = "cffi-2.1.0-cp314-cp314-win32.whl", hash = "sha256:1854b724d00f6654c742097d5387569021be12d3a0f770eae1df8f8acfcc6acd"}, + {file = "cffi-2.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:1b96bfe2c4bd825681b7d311ad6d9b7280a091f43e8f63da5729638083cd3bfb"}, + {file = "cffi-2.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:7d28dff1db6764108bc30788d85d61c876beff416d9a49cb9dd7c5a9f34f5804"}, + {file = "cffi-2.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:7ea6b3e2c4250ff1de21c630fe72d0f63eb95c2c32ffbf64a358cf4a8836d714"}, + {file = "cffi-2.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6af371f3767faeffc6ac1ef57cdfd25844403e9d3f476c5537caee499de96376"}, + {file = "cffi-2.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb4e8997a49aa2c08a3e43c9045d224448b8941d88e7ac163c7d383e560cbf98"}, + {file = "cffi-2.1.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:bf01d8c84cbea96b944c73b22182e6c7c432b3475632b8111dbfdc95ddad6e13"}, + {file = "cffi-2.1.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:33eb1ad83ebe8f313e0df035c406227d55a79456704a863fad9842136af5ad7d"}, + {file = "cffi-2.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ac0f1a2d0cfa7eea3f2aaf006ab6e70e8feeb16b75d65b7e5939982ca2f11056"}, + {file = "cffi-2.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c16914df9fb7f500e440e6875fa23ff5e0b31db01fa9c06af98d59a91f0dc2e4"}, + {file = "cffi-2.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5ecbd0499275d57506d397eebe1981cee87b47fcd9ef5c22cab7ed7644a39a94"}, + {file = "cffi-2.1.0-cp314-cp314t-win32.whl", hash = "sha256:7d034dcffa09e9a46c93fa3a3be402096cb5354ac6e41ab8e5cc9cd8b642ad76"}, + {file = "cffi-2.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0582a58f3051372229ca8e7f5f589f9e5632678208d8636fea3676711fdf7fe5"}, + {file = "cffi-2.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:510aeeeac94811b138077451da1fb18b308a5feab47dd2b603af55804155e1c8"}, + {file = "cffi-2.1.0-cp315-cp315-ios_13_0_arm64_iphoneos.whl", hash = "sha256:2e9dabb9abcb7ad15938c7196ad5c1718a4e6d33cc79b4c0209bdb64c4a54a5c"}, + {file = "cffi-2.1.0-cp315-cp315-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:37f525a7e7e50c017fdebe58b787be310ad59357ae43a053943a6e1a6c526001"}, + {file = "cffi-2.1.0-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:95f2954c2c9473d892eca6e0409f3568b37ab62a8eedb122461f73cc273476e3"}, + {file = "cffi-2.1.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:cdf2448aab5f661c9315308ec8b93f4e8a1a67a3c733f8631067a2b67d5913dc"}, + {file = "cffi-2.1.0-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:90bec57cf82089383bd06a605b3eb8daebf7e5a668520beaf6e327a83a947699"}, + {file = "cffi-2.1.0-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6274dcb2d15cef48daa73ed1be5a40d501d74dccd0cd6db364776d12cb6ba022"}, + {file = "cffi-2.1.0-cp315-cp315-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:2b71d409cccee78310ab5dec549aed052aaea483346e282c7b02362596e01bb0"}, + {file = "cffi-2.1.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7d3538f9c0e50670f4deb93dbb696576e60590369cae2faf7de681e597a8a1f1"}, + {file = "cffi-2.1.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:8f9ec95b8a043d3dfbc74d9abc6f7baf524dd27a8dc160b0a32ff9cdab650c28"}, + {file = "cffi-2.1.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:af5e2915d41fe6c961694d7bfdc8562942638200f3ce2765dfb8b745cf997629"}, + {file = "cffi-2.1.0-cp315-cp315-win32.whl", hash = "sha256:0a42c688d19fca6e095a53c6a6e2295a5b050a8b289f109adab02a9e61a25de6"}, + {file = "cffi-2.1.0-cp315-cp315-win_amd64.whl", hash = "sha256:bccbbb5ee76a61f9d99b5bf3846a51d7fca4b6a732fe46f89295610edaf41853"}, + {file = "cffi-2.1.0-cp315-cp315-win_arm64.whl", hash = "sha256:8d35c139744adb3e727cd51b1a18324bbe44b8bd41bf8322bca4d41289f48eda"}, + {file = "cffi-2.1.0-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:f9912624a0c0b834b7520d7769b3644453aabc0a7e1c839da7359f050750e9bc"}, + {file = "cffi-2.1.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:df92f2aba50eb4d96718b68ef76f2e57a57b54f2fa62333496d16c6d585a85ca"}, + {file = "cffi-2.1.0-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0520e1f4c35f44e209cbbb421b67eec42e6a157f59444dfb6058874ff3610e5d"}, + {file = "cffi-2.1.0-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:3681e031db29958a7502f5c0c9d6bbc4c36cb20f7b104086fa642d1799631ff8"}, + {file = "cffi-2.1.0-cp315-cp315t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:762f99479dcb369f60ab9017ad4ab97a36a1dd7c1ee5a3b15db0f4b8659120cd"}, + {file = "cffi-2.1.0-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0611e7ebf90573a535ebdc33ae9da222d037853983e13359f580fab781ca017f"}, + {file = "cffi-2.1.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:86cf8755a791f72c85dc287128cc62d4f24d392e3f1e15837245623f4a33cccc"}, + {file = "cffi-2.1.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:ba00f661f8ba35d075c937174e27c2c421cec3942fd2e0ea3e66996757c0fdd9"}, + {file = "cffi-2.1.0-cp315-cp315t-win32.whl", hash = "sha256:cb96698e3c7413d906ce83f8ffd245ec1bd94707541f299d0ce4d6b0193e982b"}, + {file = "cffi-2.1.0-cp315-cp315t-win_amd64.whl", hash = "sha256:f146d154428a2523f9cc7936c02353c2459b8f6cf07d3cd1ee1c0a611109c5d5"}, + {file = "cffi-2.1.0-cp315-cp315t-win_arm64.whl", hash = "sha256:cbb7640ce37159548d2147b5b8c241f962143d4c71231431820783f4dc78f210"}, + {file = "cffi-2.1.0.tar.gz", hash = "sha256:efc1cdd798b1aaf39b4610bba7aad28c9bea9b910f25c784ccf9ec1fa719d1f9"}, ] [package.dependencies] -pycparser = "*" +pycparser = {version = "*", markers = "implementation_name != \"PyPy\""} [[package]] name = "cfgv" -version = "3.4.0" +version = "3.5.0" description = "Validate configuration and produce human readable error messages." optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, - {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, + {file = "cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0"}, + {file = "cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132"}, ] [[package]] name = "charset-normalizer" -version = "3.3.2" +version = "3.4.9" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false -python-versions = ">=3.7.0" -files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +python-versions = ">=3.7" +files = [ + {file = "charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd6280cf040f233bd7d3407b743b4b4c74f70e8e1c4199cb112a62c941c0772a"}, + {file = "charset_normalizer-3.4.9-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa99adc8f081b475a12843953db36831eaf83ec33eb46a90629ca6a5de45a616"}, + {file = "charset_normalizer-3.4.9-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c1225416b463483160e4af85d5fc3a9690ccb53fd4b1865a6437825f5ede3209"}, + {file = "charset_normalizer-3.4.9-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:16d10d789dd9bcca1173c95af82c58433122564b7bc39385124be735a35cbe99"}, + {file = "charset_normalizer-3.4.9-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9bb41182d93ea91f60b4bc8fbf4c820c69ef8a12ab2d917f3f1834f1acad07e8"}, + {file = "charset_normalizer-3.4.9-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:bcf74c1df76758a395bf0af608c04c82257523f55c9868b334f06270d0f2112b"}, + {file = "charset_normalizer-3.4.9-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b5314963fce9b0b12743891de876e724997864ee22aa496f903f426c7e2fa5b2"}, + {file = "charset_normalizer-3.4.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e9701d0049d92c16703a42771b98d560b95248949f23f8cf7b4eddd201814fb9"}, + {file = "charset_normalizer-3.4.9-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:65a7ff3f705e57d392f7261b6d0550fe137c3019477431f1c355e0db0a7d3e15"}, + {file = "charset_normalizer-3.4.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79580094b00d1789d1f93ea55bc43cb2f611910c72235b7657f3482ddcc1b22d"}, + {file = "charset_normalizer-3.4.9-cp310-cp310-win32.whl", hash = "sha256:432786d3561e69aeeae6c7e8648964ce0ad05736120135601f87ac26b9c83381"}, + {file = "charset_normalizer-3.4.9-cp310-cp310-win_amd64.whl", hash = "sha256:8c041122946b7ba21bb32c45b1aa57b1be35527690aeb3c5c234521085632eee"}, + {file = "charset_normalizer-3.4.9-cp310-cp310-win_arm64.whl", hash = "sha256:375b83ed0aecfce76c16d198fbc21f3b11b337d68662bea0a995046682a11419"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0e94703ec9684807f20cfb5eed95c70f67f2a8f21ad620146d7b5a13677b93e5"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a441ea71902098ffe78c5abe6c494f44160b4af614ed16c3d9a3b1d17fd8ee2"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:304b13570067b2547562e308af560b3963857b1fa90bd6afd978130130fe2d6a"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4773092f8019072343a7447203308b176e10199920eb02d6195e81bbb3274c29"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:04ce310cb89c15df659582aee80a0603788732a5e017d5bd5c81158106ce249c"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:c0323c9daef75ef2e5083624b4585018a0c9d5e3b40f607eed81a311270b934b"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:871ff67ea1aad4dfd91736464934d56b32dac49f9fbe16cddba36198a7b3a0db"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:67830fc78e67501f47bb950471b2dcb9b35b140084429318e862895a8e89c993"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:3d92613ec25e43b05f042302531ec0f00b8445190e43325880cbd6ab7c2581da"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:280081916dc341820640489a66e4696049401ef1cf6dd672f672e70ad915aca3"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-win32.whl", hash = "sha256:ac351b3b8014eead140e77e9717e2992c6bbe30b63bc3422422eb84865412e3d"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-win_amd64.whl", hash = "sha256:6366a16e1a25018694d6a5d784d09b046edc9eac40ea2b54065c3052672516a1"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-win_arm64.whl", hash = "sha256:1d22856ffbe153a602df38e4a5464f0b748a54002e0d69ac6d2ad0a197cc99ec"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:45b0cc4e3556cd875e09102988d1ab8356c998b596c9fced84547c8138b487a0"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b2aff1c7b3884512b9512c3eaadd9bab39fb45042ffaaa1dd08ff2b9f8109d9"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9104ed0bd76a429d46f9ec0dbc9b08ad1d2dcdf2b00a5a0daa1c145329b35b44"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7b86a2b16095d250c6f58b3d9b2eee6f4147754344f3dab0922f7c9bf7d226c9"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e226f6218febc71f6c1fc2fafb91c226f75bdc1d8fb12d66823716e891608fd"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:90c44bc373b7687f6948b693cceaea1348ae0975d7474746559494468e3c1d84"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cdef90ae47919cae358d8ab15797a800ed41da7aba5d72419fb510729e2ed4b"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:60f44ade2cf573dad7a277e6f8ca9a51a21dda572b13bd7d8539bb3cd5dbedde"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a1786910334ed46ab1dd73222f2cd1e05c2c3bb39f6dddb4f8b36fc382058a39"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:03d07803992c6c7bbc976327f34b18b6160327fc81cb82c9d504720ac0be3b62"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-win32.whl", hash = "sha256:78841cccf1af7b40f6f716338d50c0902dbe88d9f800b3c973b7a9a0a693a642"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-win_amd64.whl", hash = "sha256:4b3dac63058cc36820b0dd072f89898604e2d39686fe05321729d00d8ac185a0"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-win_arm64.whl", hash = "sha256:78fa18e436a1a0e58dbd7e02fc4473f3f32cceb12df9dfca542d075961c307d2"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:440eede837960000d74978f0eba527be106b5b9aee0daf779d395276ed0b0614"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21e764fd1e70b6a3e205a0e46f3051701f98a8cb3fad66eeb80e48bb502f8698"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e4fd89cc178bced6ad29cb3e6dd4aa63fa5017c3524dbd0b25998fb64a87cc8b"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bd47ba7fc3ca94896759ea0109775132d3e7ab921fbf54038e1bab2e46c313c9"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:84fd18bcc17526fc2b3c1af7d2b9217d32c9c04448c16ec693b9b4f1985c3d33"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:5b10cd92fc5c498b35a8635df6d5a100207f88b63a4dc1de7ef9a548e1e2cd63"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a4fbdde9dd4a9ce5fd52c2b3a347bb50cc89483ef783f1cb00d408c13f7a96c0"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:416c229f77e5ea25b3dfd4b582f8d73d7e43c22320302b9ab128a2d3a0b38efe"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:75286256590a6320cf106a0d28970d3560aad9ee09aa7b34fb40524792436d35"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:69b157c5d3292bcd443faca052f3096f637f1e074b98212a933c074ae23dc3b8"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-win32.whl", hash = "sha256:51307f5c71007673a2bf8232ad973483d281e74cb99c8c5a990af1eefa6277d9"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-win_amd64.whl", hash = "sha256:fe2c7201c642b7c308f1675355ad7ff7b66acfe3541625efe5a3ad38f29d6115"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-win_arm64.whl", hash = "sha256:611057cc5d5c0afc743ba8be6bd828c17e0aaa8643f9d0a9b9bb7dea80eb8012"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:0327fcd59a935777d83410750c50600ee9571af2846f71ce40f25b13da1ef380"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a79d9f4d8001473a30c163556b3c3bfebec837495a412dde78b51672f6134f9"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:33bdcc2a32c0a0e861f60841a512c8acc658c87c2ac59d89e3a46dacf7d866e4"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f840ed6d8ecba8255df8c42b87fadeda98ddfc6eeec05e2dc66e26d46dd6f58a"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c25fe15c70c59eb7c5ce8c06a1f3fa1da0ecc5ea1e7a5922c40fd2fa9b0d5046"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:f7fb7d750cfa0a070d2c24e831fd3481019a60dd317ea2b39acbcebc08b6ed81"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4d1c96a7a18b9690a4d46df09e3e3382406ae3213727cd1019ebade1c4a81917"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a4cfde78a9f2880208d16a93b795726a3017d5977e08d1e162a7a31322479c41"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d4d6fcde76f94f5cb9e43e9e9a61f16dacefd228cbbf6f1a09bd9b219a92f1a1"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:898f0e9068ca27d37f8e83a5b962821df851532e6c4a7d615c1c033f9da6eedf"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-win32.whl", hash = "sha256:c1c948747b03be832dceed96ca815cef7360de9aa19d37c730f8e3f6101aca48"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-win_amd64.whl", hash = "sha256:16b65ea0f2465b6fb52aa22de5eca612aa964ddfec00a912e26f4656cbef890b"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-win_arm64.whl", hash = "sha256:40a126142a56b2dfc0aacbad1de8310cbf60da7656db0e6b16eebd48e3e93519"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:609b3ba8fcc0fb5ab7af00719d0fb6ad0cb518e48e7712d12fd68f1327951198"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51447e9aa2684679af07ca5021c3db526e0284347ebf4ffcec1154c3350cfe32"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cc1b0fff8ead343dae06305f954eb8468ba0ec1a97881f42489d198e4ce3c632"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fa36ec09ef71d158186bc79e359ff5fdd6e7996fe8ab638f00d6b93139ba4fcf"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:df115d4d83168fdf2cae48ef1ff6d1cb4c466364e30861b37121de0f3bf1b990"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:f86c6358749bd4fda175388691e3ba8c46e24c5347d0afd20f9b7edfc9faf07d"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:32286a2c8d167e897177b673176c1e3e00d4057caf5d2b64eef9a3666b03018e"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:83aed2c10721ddd90f68140685391b50811a880af20654c59af6b6c66c40513c"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cd6c3d4b783c556fa00bf540854e42f135e2f256abd29669fcd0da0f2dec79c2"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ee2f2a527e3c1a6e6411eb4209642e138b544a2d72fe5d0d76daf77b24063534"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-win32.whl", hash = "sha256:0d861473f743244d349b50f850d10eb87aeb22bbdcc8e64f79273c94af5a8226"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-win_amd64.whl", hash = "sha256:9b8e0f3107e2200b76f6054de99016eac3ee6762713587b36baaa7e4bd2ae177"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-win_arm64.whl", hash = "sha256:19ac87f93086ce37b86e098888555c4b4bc48102279bae3350098c0ed664b501"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:253a4a220747e8b5faf57ec320c4f5efb0cef05f647420bf267143ec15dba10a"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:68ce9f4d6b26d5ccbf7fd4459bf75f74a0a146677ebba80597df60cbdb20e6f4"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:58150c9f9b9a552505912d182ccdf26f6396fb6094816ceebcbb20eecabaed94"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:df7276909358e5635ae203673ab7e509ddd224225a8d6b0790bf13eb2bde1cc5"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3c09a49d6cde137258beb3d551994a2927fd35ad5cf96aed573f61bbd67c5f84"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-manylinux_2_31_armv7l.whl", hash = "sha256:231ddcbb35e2ff8973e1365db41fe0572662893b99a05deb183b68ad4c0c8bd4"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:920079c3f7456fa213e0829ed2073aaa727fd39d889ead5b4f35d0de5460d04f"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0fa1aec2d32bcc03c8fa0f6f1712caad1adc38509f31142112e5c9daf5b9c833"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:ad41ba96094304aa090f5a30cb6e4fb3b3f1c264c523394b4c39bbacc4dc92ba"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:43b9e366a31fdd1c87d0eb08f579b4a82b723ea54338f040d6b4e518a026ea29"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-win32.whl", hash = "sha256:93d59d504b230e83c7a843251681959a0b6a9cd76f6e146ce1b8a80eb8739af9"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-win_amd64.whl", hash = "sha256:ddf4af30b417d9fe16481e9b81c27ab2a7cde1ff7ba3e85653b02db7d145dc7b"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-win_arm64.whl", hash = "sha256:476743fe6dfe14a2da12e3ac79125dc84a3b2cf8094369a47a1529b0cd8549fe"}, + {file = "charset_normalizer-3.4.9-py3-none-any.whl", hash = "sha256:68e5f26a1ad57ded6d1cfb85331d1c1a195314756471d97758c48498bb4dcdf5"}, + {file = "charset_normalizer-3.4.9.tar.gz", hash = "sha256:673611bbd43f0810bec0b0f028ddeaaa501190339cac411f347ac76917c3ae7b"}, ] [[package]] name = "ckzg" -version = "2.0.1" +version = "2.1.8" description = "Python bindings for C-KZG-4844" optional = false python-versions = "*" files = [ - {file = "ckzg-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b7f9ba6d215f8981c5545f952aac84875bd564a63da02fb22a3d1321662ecdc0"}, - {file = "ckzg-2.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8fdec3ff96399acba9baeef9e1b0b5258c08f73245780e6c69f7b73def5e8d0a"}, - {file = "ckzg-2.0.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1644369af9900a9f109d417d6760693edf134118f3100d0c68f56667de775b80"}, - {file = "ckzg-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0a2146f122d489ac7e67ae0c0743f8d0db1718e6aeed8f05717340594fe07dd"}, - {file = "ckzg-2.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:979841be50f2782b447762db38e9bc927ae251f6ca86c54a26561a52068ee779"}, - {file = "ckzg-2.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4516d86647ee4e8ea9470f4adf68fbebb6dc1bdedff7d9592c2504fe53145908"}, - {file = "ckzg-2.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:91866fc58a29b4829201efd9ffadfac3ffeca6359254a54a360ff6a189c34bf5"}, - {file = "ckzg-2.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ed35508dac059b2c0a7994383bc7a92eaf35d0b9ce790016819e2619e0f4b8a9"}, - {file = "ckzg-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:449c4fe38017351eca362106420eeb2d28d50b7e54aa8668b3af29a8ab780132"}, - {file = "ckzg-2.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:260608a22e2f2cadcd31f4495832d45d6460438c38faba9761b92df885a99d88"}, - {file = "ckzg-2.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e1015f99c50215098751b07d7e459ba9a2790d3692ca81552eed29996128e90d"}, - {file = "ckzg-2.0.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dd350d97554c161dc5b8c7b32c2dc8e659632c374f60e2669fb3c9b5b294827"}, - {file = "ckzg-2.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eec7724fa8dc4ae95757efe4a87e7b2d4b880cb348c72ce7355fc0c4f64bc298"}, - {file = "ckzg-2.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3fa0f4398fa67fb71f0a2b34a652cc89e6e0e6af1340b0dc771db1a5f3e089c"}, - {file = "ckzg-2.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f865a0297aabeeb638187a46f7df445763360417b9df4dea60560d512c2cda09"}, - {file = "ckzg-2.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b6ec738350771dbf5974fb70cc8bbb20a4df784af770f7e655922adc08a2171"}, - {file = "ckzg-2.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9b4b669fc77edeb16adc182efc32b3737b36f741a2e33a170d40619e8b171a94"}, - {file = "ckzg-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:decb97f4a17c7338b2130dcc4b045df4cc0e7785ece872c764b554c7c73a99ff"}, - {file = "ckzg-2.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:285cf3121b8a8c5609c5b706314f68d2ba2784ab02c5bb7487c6ae1714ecb27f"}, - {file = "ckzg-2.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f927bc41c2551b0ef0056a649a7ebed29d9665680a10795f4cee5002c69ddb7"}, - {file = "ckzg-2.0.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fd9fb690c88919f30c9f3ab7cc46a7ecd734d5ff4c9ccea383c119b9b7cc4da"}, - {file = "ckzg-2.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fabc3bd41b306d1c7025d561c3281a007c2aca8ceaf998582dc3894904d9c73e"}, - {file = "ckzg-2.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2eb50c53efdb9c34f762bd0c8006cf79bc92a9daf47aa6b541e496988484124f"}, - {file = "ckzg-2.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7960cc62f959403293fb53a3c2404778369ae7cefc6d7f202e5e00567cf98c4b"}, - {file = "ckzg-2.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d721bcd492294c70eca39da0b0a433c29b6a571dbac2f7084bab06334904af06"}, - {file = "ckzg-2.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dde2391d025b5033ef0eeacf62b11ecfe446aea25682b5f547a907766ad0a8cb"}, - {file = "ckzg-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fab8859d9420f6f7df4e094ee3639bc49d18c8dab0df81bee825e2363dd67a09"}, - {file = "ckzg-2.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9747d92883199d4f8f3a3d7018134745fddcf692dfe67115434e4b32609ea785"}, - {file = "ckzg-2.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b2cf58fb9e165da97f0ffe9f4a6efb73992645fac8e0fa223a6cc7ec486a434a"}, - {file = "ckzg-2.0.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d25d006899d76bb8c9d3e8b27981dd6b66a78f9826e33c1bf981af6577a69a19"}, - {file = "ckzg-2.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a04bf0b32f04f5ea5e4b8518e292d3321bc05596fde95f9c3b4f504e5e4bc780"}, - {file = "ckzg-2.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d0cf3dccd72376bff10e1833641cc9d642f34f60ca63972626d9dfcfdc8e77f"}, - {file = "ckzg-2.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:770809c7e93087470cc524724419b0f85590edb033c7c73ba94aef70b36ca18b"}, - {file = "ckzg-2.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e31b59b8124148d5e21f7e41b35532d7af98260c44a77c3917958adece84296d"}, - {file = "ckzg-2.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:174f0c356df644d6e349ce03b7284d83dbec859e11ca5d1b1b3bace8b8fbc65d"}, - {file = "ckzg-2.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:30e375cd45142e56b5dbfdec05ce4deb2368d7f7dedfc7408ba37d5639af05ff"}, - {file = "ckzg-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:abdee71958b214730a8341b16bdd413d0fab1b1a2504fbdb7b0ef2aeee9f9d22"}, - {file = "ckzg-2.0.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b4442667058db791325fe231f22e4fc7aaa3495d535d75af5595bc5f4f86036"}, - {file = "ckzg-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c3c9aa9d4477ad52f3561b717e776c1a8a442d9d8b06600c7d8a2857d1ecf05"}, - {file = "ckzg-2.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68e0a9cde35f11e80b4e560d22990f2f29dd200a95d3141acde137cb6c883f9a"}, - {file = "ckzg-2.0.1-cp36-cp36m-musllinux_1_2_aarch64.whl", hash = "sha256:4508a089e53330866d3360000d76483400eeab5f8057b8e1f3e344ce2cc0097b"}, - {file = "ckzg-2.0.1-cp36-cp36m-musllinux_1_2_i686.whl", hash = "sha256:828cecee16ec576dcf4386beac4eedfd058fd32ee90827f2282e7156a53600be"}, - {file = "ckzg-2.0.1-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:bd437ec1dfb4f5609979328b5f465a74307f45d46d24234868c67d44da96903b"}, - {file = "ckzg-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:70406b10acf68469ac62110047044a6c1a998f5d5fcd6e27cb3ec2d5760d0490"}, - {file = "ckzg-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2f53fba88febac17e82a96eb83dc38ecf4b28abcdd15c0246534c358bd3b26c4"}, - {file = "ckzg-2.0.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be8e0d5015e7755af4ddaab9ae1a4084f72c84b2cbb53628f4366aeed46cc380"}, - {file = "ckzg-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:261414121091042d29f28fc319d7c9a7f950f91f8bf54c010b581ee6a0499473"}, - {file = "ckzg-2.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:524e1e66edd2be2c38b660824aa7b5d4525b41b30ac029d80738a8eee491aeb5"}, - {file = "ckzg-2.0.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:4a12a1d8ef8f475d9f0af9a538e1674057e007806cb1204bb269ea00d9f8c1e5"}, - {file = "ckzg-2.0.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:4cc4bb5f62417a58065deeaf124e178cb1787ef3228e6032600d1e0a2775765b"}, - {file = "ckzg-2.0.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:e7b015f5615bcb82fa0d935481a209fc1dcd9308fb52fb1a7e5400108df67a94"}, - {file = "ckzg-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:0518933ff3b9550f9dd60d833cdb74e8e97cc1cc58f0560b706916606dfd47d0"}, - {file = "ckzg-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ac0bca0795990076cde1930ecec307379b5303e34367c6e6e8a16bdba5a7ba5"}, - {file = "ckzg-2.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8086d23a41020ede312843bda7ea4ee0c9831265379027904106f99f2f8ed469"}, - {file = "ckzg-2.0.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:31d1b141d41fa51aeac9440c936b812e885aef5719adfbd3a27550d8dc433997"}, - {file = "ckzg-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60a58e4d8cb91bad669ca111b7ccdd05c32de6787fdb571bb599625b043ad75b"}, - {file = "ckzg-2.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:633e143385622d7a43fcb5c4f400ec5ec15df0b1c74ab7d6449a41a7abed24ad"}, - {file = "ckzg-2.0.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:4876313614ea01f9a0039b5ca2c754340ba40aa8405f8756912d90ae55718011"}, - {file = "ckzg-2.0.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:19c86c8102200484074afac06b3946b457ba9915636de187f63854522be2e3bd"}, - {file = "ckzg-2.0.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:564abf27878f129781e1df4d33b1c4e264e5b25f89c1bdf95b7d6256e4bceb6c"}, - {file = "ckzg-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:bc2da29bb970d3f5de04fb60797dbb4490c010ffc683cbc6016349dd6fa60d14"}, - {file = "ckzg-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9c1869671140ae7e698520b678b594ebd26fb59ef476711403541597d7d32c01"}, - {file = "ckzg-2.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1dd2aec2c61e8cc2ec815900f6768c6fe74b8fd29810e79b57c4150c6db32fb6"}, - {file = "ckzg-2.0.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9632ef17285dbdd3fcd9780f599c266da736d9b2897decc4ea02ba8690bdf72"}, - {file = "ckzg-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5747d7926873e3af0f6af5fca666feb0097d06cab525950e2664a6fbcb90165d"}, - {file = "ckzg-2.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75484ffb78aaebaeb3a30f1194a9143b904312b0f365fc4101e58e1bf5f89f66"}, - {file = "ckzg-2.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:b2f72bc861b8bee9bac3314c58586d1ab2d23530f932a8f0a8562c8a4a6a45f9"}, - {file = "ckzg-2.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6f85e5802fea5b77f52fc3a14c8dec18a3f2b7c7070c811a4608940834f563cc"}, - {file = "ckzg-2.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:583a0b6b531a16974676439b23e7defb3dfe9732f18d13d2316152019c538af1"}, - {file = "ckzg-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:fafb9ac36b3398f8091d40773d9a450e5f74883dad8ca4ee22d472e7a231ef4d"}, - {file = "ckzg-2.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a12e96f20dce35e5222f898a5c8355054ef7c5ee038eeb97dbb694640b57577b"}, - {file = "ckzg-2.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:4e0ebc55253addaa24dd2cd871bbe3b8f57855f32b5f74e70bf2cb76b6f7da54"}, - {file = "ckzg-2.0.1-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8f917a7bf363a3735db30559e1ed63cf1ccf414234433ba687fa72c007abd756"}, - {file = "ckzg-2.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30f08c984286853271d4adae219e9ba87275a15047dbaa262ab8dd6c01be97b0"}, - {file = "ckzg-2.0.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4fa1ea4888417e1f109fd5e57965788fb7f53b674329b937a65604a3c1ca1d03"}, - {file = "ckzg-2.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0b249914aeaf05cabc71c5c3797e3d6c126cb2c64192b7eb6755ef6aa5ab2f11"}, - {file = "ckzg-2.0.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a038e26baf650e1c733dcaa066ec948e75556b0c485e8c790c9a758875c71a93"}, - {file = "ckzg-2.0.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d6deb2c822122bdd32b555fa3b9216c86a355f24a2cc6a46b9b5743b412b60c"}, - {file = "ckzg-2.0.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50f6f2fbceba9ece3fbc1d2613a246f4e6ec4d787f542859e70c358928c0e4a1"}, - {file = "ckzg-2.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33ca40ef30129e2347bff3c95ad093403a0d5703476705ab92c92fbffe89bd5a"}, - {file = "ckzg-2.0.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:700b989c2f7089edc8fac6dfbd1b4677e85b966216ebedee8eb5e7894765c188"}, - {file = "ckzg-2.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f11933c007c3df02446a81957ac6e2488058b969e2eff5357c98ab569a0c7999"}, - {file = "ckzg-2.0.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:3dbc9580eccecbd485f22e48f6044c48cbe6d838a7b7514cce179c085c65a960"}, - {file = "ckzg-2.0.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad6eb83f343fea6dd9a13fd1bce87b9cd26abeeb72f0674a62d26e40fe0b8aca"}, - {file = "ckzg-2.0.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:269f82b992facbd20461310cf5784551c77d11017b7d4b85d741d70359be6794"}, - {file = "ckzg-2.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:895d67cfd43130652e1ae39b90465b392d9a72c7c7e6f250eaf14689bfda6351"}, - {file = "ckzg-2.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:369cf1aeaf336c31f2050a7f54ae21cf46f4b2db23ebb013fff621144ab361bb"}, - {file = "ckzg-2.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:24fda2637598a467e7b11ff664805ee7fdf4f6c7b0c043d6d0a6ccb69b5681ee"}, - {file = "ckzg-2.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ea27baabe5b22b92901c428768eacf93b992ac7681f93768ab24818ad26ccfed"}, - {file = "ckzg-2.0.1-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a33f71e382020f2bc4ead2bd6881a9bd3811d929f272da239ac01ad615a00802"}, - {file = "ckzg-2.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:926507c569727bb4c851a1eea702c5e902267de96e06ce2d685019f973f72968"}, - {file = "ckzg-2.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f5f29518b0a4555d8f2a28559209bd1d4080547aa629ff9ee51799346573b3f"}, - {file = "ckzg-2.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4595db84ce63c227e4448de0f7b39d3043e3477d78394ff651708c37fee6c486"}, - {file = "ckzg-2.0.1.tar.gz", hash = "sha256:62c5adc381637affa7e1df465c57750b356a761b8a3164c3106589b02532b9c9"}, + {file = "ckzg-2.1.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8dc23b189b5e061b5a2fcf609b6dc1f62098dd72cf9116e4721f995eb144b0ee"}, + {file = "ckzg-2.1.8-cp310-cp310-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:71e0e6d84a268c23c29d546a7ef4720a9d2aea597efe4def75205b6ef436900c"}, + {file = "ckzg-2.1.8-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8ccabbd5aea9cf98ae5301ec8b16119720d93f8f155a567e041e2f16b1fafc87"}, + {file = "ckzg-2.1.8-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a1dee4ec1d8e6702e6008a4d489638027cd640b5d9e5adca48a8c16aa193c6c7"}, + {file = "ckzg-2.1.8-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:697f5c4016a9f091bdf7e646be0d71e625b5106a9f78c6ab53e93e5f425aa513"}, + {file = "ckzg-2.1.8-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:50f6281f5c55240f1be254041e0c06d6348c91e21fccd0ed108151f880b6d087"}, + {file = "ckzg-2.1.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9371ac89c420beb6f6d236ce808c7990174dc21bde61032c39235982e4e65697"}, + {file = "ckzg-2.1.8-cp310-cp310-win_amd64.whl", hash = "sha256:c1f0f8e7a14bb4348f3ecaee92d929df3428be1f706034c961e11239d398bcdb"}, + {file = "ckzg-2.1.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:adb4868ec73547d040d8551538dc00ebc3822a758a7fb2b762735e097556c13b"}, + {file = "ckzg-2.1.8-cp311-cp311-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:5e42a07899e62cf8888bdefe1fa200e3248190953bacc1d872e13825b0b91a7f"}, + {file = "ckzg-2.1.8-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:369af9ec31248a942f2b249bee9f60dccfe6c8ac944095ad26c8083c9df04186"}, + {file = "ckzg-2.1.8-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dac8202240347c4af5cee9a3ebc62560ae629c8bac2b1ee313fa57cf1c9e4f0a"}, + {file = "ckzg-2.1.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:eff52513b32bc83e3b978cae991289cc932d801b6c08aa002d29e44a4290b2f0"}, + {file = "ckzg-2.1.8-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:23bef3d98c905152f4ff497a6243b6a14e916deef2d8a1d342175be90f6e6425"}, + {file = "ckzg-2.1.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:40e6e33672e474331519b7d07b8c8e0cbec3d817b6341e00fa728a94141fa8e8"}, + {file = "ckzg-2.1.8-cp311-cp311-win_amd64.whl", hash = "sha256:b84d698c81569381a3dd18a9848f8fca03273ae62045494cee5669a885697d8d"}, + {file = "ckzg-2.1.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:98abe138d79886e3e1fbbaf05cdf0702a4351f242ad1a8b4802343c7ba149faa"}, + {file = "ckzg-2.1.8-cp312-cp312-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:2fe01dad7c968bcdf3c063c5192bc7d7d59f66358afb5c99554e5ce2435a95aa"}, + {file = "ckzg-2.1.8-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9bdb7f51ee3cf8e45451bee8c6dce975fddadfe231174d8de9c27a3aa27741b8"}, + {file = "ckzg-2.1.8-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10339d23e36b8a0a4e6fda7f6c72d6b2fd4e1506f7b64a661ba8c706ee33f335"}, + {file = "ckzg-2.1.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a4456c9027f2edcb50a2279d6035ca971a511d8b0025e6659ff407b87ad841ba"}, + {file = "ckzg-2.1.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:88cbec7e2010f64988c249ebb5679b73ccae1c536f4c130d4708bf7b06a8cd69"}, + {file = "ckzg-2.1.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a4d2581df10bdfaec00fec6daefdeaa438e66582364e1d1b705710e9d749fc47"}, + {file = "ckzg-2.1.8-cp312-cp312-win_amd64.whl", hash = "sha256:a30f2b980929e898f0b28aa6bf9ae35e7afd5884e354376ad3744669b7cacf3e"}, + {file = "ckzg-2.1.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:26ed4c4d3acbfdb4bfdf1ab1029219657d4565e1c63d36f2695cdfdb5ec0b569"}, + {file = "ckzg-2.1.8-cp313-cp313-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:a6899908ca3a41e6d2aa19973b398de101a6d64b5189894077ea09a3f508d3fd"}, + {file = "ckzg-2.1.8-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3db1ca21685d567eea668925c9f85ebd723db41d24bbecaa2f78d8256e1ba9c6"}, + {file = "ckzg-2.1.8-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f27d7d16be9debf173369248ff06e97fc45826bfb0a743519b49b38539ab6c7"}, + {file = "ckzg-2.1.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dadf0cd0c3c19611e8a1188a2a10316b88fbae56d806f75a67cbe846b8b7ec86"}, + {file = "ckzg-2.1.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cde13789188b7bac6d5bee308532a7bd60ab5c2feeccdef2f1da41be761c7e04"}, + {file = "ckzg-2.1.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1f2737534458547ba8ce89663f833041925b104f7906f17b2338d1b36e6c7c4d"}, + {file = "ckzg-2.1.8-cp313-cp313-win_amd64.whl", hash = "sha256:10b483ad6937878f03d556d120a43d323dcb3891eb83313aa71087b54559594b"}, + {file = "ckzg-2.1.8-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2f3e4a3ae1ff3ec811b6d2aac7a246524f72a750af95fe7a01550cdd68677d6f"}, + {file = "ckzg-2.1.8-cp314-cp314-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:9afe50a28d8d6f130797f0861d4753f76294d983f1e6ead9c17dfa14f8118ad4"}, + {file = "ckzg-2.1.8-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:da197eef7014997b976ae7bc6e0ad42c02a9faa3a4221d6699e8b777761422f1"}, + {file = "ckzg-2.1.8-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fef164b9a0c7ed57935bf78bd23e701ba82efcca180e9b29814a94928a2d5880"}, + {file = "ckzg-2.1.8-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c56f588a57d419ac314880931122796e4331be395368c8887ca3ade5c27f539c"}, + {file = "ckzg-2.1.8-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:37eecbce59271040dfab736db490a28c0e59f189b404e5820e65531dadf84ddb"}, + {file = "ckzg-2.1.8-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:acc5d33e42ac852fec08ad1991020a958e2534ac6af346a83f579b553bd0bdfd"}, + {file = "ckzg-2.1.8-cp314-cp314-win_amd64.whl", hash = "sha256:5eb3b5327dd0cbaaa6551e01a42af9780e998640c57236e460830bf9a6e6f9b4"}, + {file = "ckzg-2.1.8-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:dbd7021cdc5616df5902ec04876b9af25d17facc39851b4d6630c9c2b209e30a"}, + {file = "ckzg-2.1.8-cp314-cp314t-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:5ecbcd887fa97988ddfc3ac4d1951367fa4f6bb25a6f72d449550ea4be45b938"}, + {file = "ckzg-2.1.8-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaeaed98d7be94f7c215373f90cd06536237d6ec08d48d2be74c630e03edf73c"}, + {file = "ckzg-2.1.8-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1030903bf9989957b73fe30a96516e75a8bc27efb65e1b6e9d3507447bfee06"}, + {file = "ckzg-2.1.8-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ff48587f541b625dd0e471ecc866cf91462100a4429e3c21cf4f099e7dff9150"}, + {file = "ckzg-2.1.8-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:0580e8a1780d44a85c6edaa44e30a6a85565ad26593becb320d7353bc05e8627"}, + {file = "ckzg-2.1.8-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:bc8a259bc3cc321413c3c8eb0789cbe35919f4f4bb32946b0e1a484d4303629c"}, + {file = "ckzg-2.1.8-cp314-cp314t-win_amd64.whl", hash = "sha256:f41377a2a63330df64ae6f7cd806a288b21c52aa346151fd8f0551b9e0742289"}, + {file = "ckzg-2.1.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c4ec8234a72cebe419330e13d580048fec25e63d9526a0a9bf65ed134b6ffa9a"}, + {file = "ckzg-2.1.8-cp39-cp39-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:036b8de43a07340609a3a4445d4da542cb9487c58dc0752c2d419c7be1f3dbdb"}, + {file = "ckzg-2.1.8-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9290e8d128921f1906ffa8e6229a878a9e967ea9937697bf90c894fe523e9d11"}, + {file = "ckzg-2.1.8-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ad90fe4e55aea73e3df744b97043c43cd3227725c3f8715fbae07b4eb0acbab0"}, + {file = "ckzg-2.1.8-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8d511e410956aa2fcde7d19f40cefcc166fa84ef3387b3c96083e3798bd21a44"}, + {file = "ckzg-2.1.8-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e523457f3a463214e2ae8aa37f8b35d519e1a51d772734d381dd090cf7391b5c"}, + {file = "ckzg-2.1.8-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:70b67a92373b834e910bc527d538c170757ebc70bc8f99beedbfd64d1913dc80"}, + {file = "ckzg-2.1.8-cp39-cp39-win_amd64.whl", hash = "sha256:d2e709e9701d6085d79cf5d2ed12d373beffae1d93d61b0387055a14818973c0"}, + {file = "ckzg-2.1.8.tar.gz", hash = "sha256:d7bef6b425dca6995457fc59fc5b30211d9b28cbbeee0e7a7bef1372e13f29ca"}, ] [[package]] name = "click" -version = "8.1.7" +version = "8.4.2" description = "Composable command line interface toolkit" optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, + {file = "click-8.4.2-py3-none-any.whl", hash = "sha256:e6f9f66136c816745b9d65817da91d61d957fb16e02e4dcd0552553c5a197b76"}, + {file = "click-8.4.2.tar.gz", hash = "sha256:9a6cea6e60b17ebe0a44c5cc636d94f09bd66142c1cd7d8b4cd731c4917a15f6"}, ] [package.dependencies] @@ -776,66 +789,79 @@ files = [ [[package]] name = "contourpy" -version = "1.2.0" +version = "1.3.2" description = "Python library for calculating contours of 2D quadrilateral grids" optional = false -python-versions = ">=3.9" -files = [ - {file = "contourpy-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0274c1cb63625972c0c007ab14dd9ba9e199c36ae1a231ce45d725cbcbfd10a8"}, - {file = "contourpy-1.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ab459a1cbbf18e8698399c595a01f6dcc5c138220ca3ea9e7e6126232d102bb4"}, - {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fdd887f17c2f4572ce548461e4f96396681212d858cae7bd52ba3310bc6f00f"}, - {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d16edfc3fc09968e09ddffada434b3bf989bf4911535e04eada58469873e28e"}, - {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c203f617abc0dde5792beb586f827021069fb6d403d7f4d5c2b543d87edceb9"}, - {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b69303ceb2e4d4f146bf82fda78891ef7bcd80c41bf16bfca3d0d7eb545448aa"}, - {file = "contourpy-1.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:884c3f9d42d7218304bc74a8a7693d172685c84bd7ab2bab1ee567b769696df9"}, - {file = "contourpy-1.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4a1b1208102be6e851f20066bf0e7a96b7d48a07c9b0cfe6d0d4545c2f6cadab"}, - {file = "contourpy-1.2.0-cp310-cp310-win32.whl", hash = "sha256:34b9071c040d6fe45d9826cbbe3727d20d83f1b6110d219b83eb0e2a01d79488"}, - {file = "contourpy-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:bd2f1ae63998da104f16a8b788f685e55d65760cd1929518fd94cd682bf03e41"}, - {file = "contourpy-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dd10c26b4eadae44783c45ad6655220426f971c61d9b239e6f7b16d5cdaaa727"}, - {file = "contourpy-1.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5c6b28956b7b232ae801406e529ad7b350d3f09a4fde958dfdf3c0520cdde0dd"}, - {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebeac59e9e1eb4b84940d076d9f9a6cec0064e241818bcb6e32124cc5c3e377a"}, - {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:139d8d2e1c1dd52d78682f505e980f592ba53c9f73bd6be102233e358b401063"}, - {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e9dc350fb4c58adc64df3e0703ab076f60aac06e67d48b3848c23647ae4310e"}, - {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18fc2b4ed8e4a8fe849d18dce4bd3c7ea637758c6343a1f2bae1e9bd4c9f4686"}, - {file = "contourpy-1.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:16a7380e943a6d52472096cb7ad5264ecee36ed60888e2a3d3814991a0107286"}, - {file = "contourpy-1.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8d8faf05be5ec8e02a4d86f616fc2a0322ff4a4ce26c0f09d9f7fb5330a35c95"}, - {file = "contourpy-1.2.0-cp311-cp311-win32.whl", hash = "sha256:67b7f17679fa62ec82b7e3e611c43a016b887bd64fb933b3ae8638583006c6d6"}, - {file = "contourpy-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:99ad97258985328b4f207a5e777c1b44a83bfe7cf1f87b99f9c11d4ee477c4de"}, - {file = "contourpy-1.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:575bcaf957a25d1194903a10bc9f316c136c19f24e0985a2b9b5608bdf5dbfe0"}, - {file = "contourpy-1.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9e6c93b5b2dbcedad20a2f18ec22cae47da0d705d454308063421a3b290d9ea4"}, - {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:464b423bc2a009088f19bdf1f232299e8b6917963e2b7e1d277da5041f33a779"}, - {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:68ce4788b7d93e47f84edd3f1f95acdcd142ae60bc0e5493bfd120683d2d4316"}, - {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d7d1f8871998cdff5d2ff6a087e5e1780139abe2838e85b0b46b7ae6cc25399"}, - {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e739530c662a8d6d42c37c2ed52a6f0932c2d4a3e8c1f90692ad0ce1274abe0"}, - {file = "contourpy-1.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:247b9d16535acaa766d03037d8e8fb20866d054d3c7fbf6fd1f993f11fc60ca0"}, - {file = "contourpy-1.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:461e3ae84cd90b30f8d533f07d87c00379644205b1d33a5ea03381edc4b69431"}, - {file = "contourpy-1.2.0-cp312-cp312-win32.whl", hash = "sha256:1c2559d6cffc94890b0529ea7eeecc20d6fadc1539273aa27faf503eb4656d8f"}, - {file = "contourpy-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:491b1917afdd8638a05b611a56d46587d5a632cabead889a5440f7c638bc6ed9"}, - {file = "contourpy-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5fd1810973a375ca0e097dee059c407913ba35723b111df75671a1976efa04bc"}, - {file = "contourpy-1.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:999c71939aad2780f003979b25ac5b8f2df651dac7b38fb8ce6c46ba5abe6ae9"}, - {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7caf9b241464c404613512d5594a6e2ff0cc9cb5615c9475cc1d9b514218ae8"}, - {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:266270c6f6608340f6c9836a0fb9b367be61dde0c9a9a18d5ece97774105ff3e"}, - {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbd50d0a0539ae2e96e537553aff6d02c10ed165ef40c65b0e27e744a0f10af8"}, - {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11f8d2554e52f459918f7b8e6aa20ec2a3bce35ce95c1f0ef4ba36fbda306df5"}, - {file = "contourpy-1.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ce96dd400486e80ac7d195b2d800b03e3e6a787e2a522bfb83755938465a819e"}, - {file = "contourpy-1.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6d3364b999c62f539cd403f8123ae426da946e142312a514162adb2addd8d808"}, - {file = "contourpy-1.2.0-cp39-cp39-win32.whl", hash = "sha256:1c88dfb9e0c77612febebb6ac69d44a8d81e3dc60f993215425b62c1161353f4"}, - {file = "contourpy-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:78e6ad33cf2e2e80c5dfaaa0beec3d61face0fb650557100ee36db808bfa6843"}, - {file = "contourpy-1.2.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:be16975d94c320432657ad2402f6760990cb640c161ae6da1363051805fa8108"}, - {file = "contourpy-1.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b95a225d4948b26a28c08307a60ac00fb8671b14f2047fc5476613252a129776"}, - {file = "contourpy-1.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0d7e03c0f9a4f90dc18d4e77e9ef4ec7b7bbb437f7f675be8e530d65ae6ef956"}, - {file = "contourpy-1.2.0.tar.gz", hash = "sha256:171f311cb758de7da13fc53af221ae47a5877be5a0843a9fe150818c51ed276a"}, +python-versions = ">=3.10" +files = [ + {file = "contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934"}, + {file = "contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989"}, + {file = "contourpy-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9be002b31c558d1ddf1b9b415b162c603405414bacd6932d031c5b5a8b757f0d"}, + {file = "contourpy-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8d2e74acbcba3bfdb6d9d8384cdc4f9260cae86ed9beee8bd5f54fee49a430b9"}, + {file = "contourpy-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e259bced5549ac64410162adc973c5e2fb77f04df4a439d00b478e57a0e65512"}, + {file = "contourpy-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad687a04bc802cbe8b9c399c07162a3c35e227e2daccf1668eb1f278cb698631"}, + {file = "contourpy-1.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cdd22595308f53ef2f891040ab2b93d79192513ffccbd7fe19be7aa773a5e09f"}, + {file = "contourpy-1.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4f54d6a2defe9f257327b0f243612dd051cc43825587520b1bf74a31e2f6ef2"}, + {file = "contourpy-1.3.2-cp310-cp310-win32.whl", hash = "sha256:f939a054192ddc596e031e50bb13b657ce318cf13d264f095ce9db7dc6ae81c0"}, + {file = "contourpy-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c440093bbc8fc21c637c03bafcbef95ccd963bc6e0514ad887932c18ca2a759a"}, + {file = "contourpy-1.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a37a2fb93d4df3fc4c0e363ea4d16f83195fc09c891bc8ce072b9d084853445"}, + {file = "contourpy-1.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b7cd50c38f500bbcc9b6a46643a40e0913673f869315d8e70de0438817cb7773"}, + {file = "contourpy-1.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6658ccc7251a4433eebd89ed2672c2ed96fba367fd25ca9512aa92a4b46c4f1"}, + {file = "contourpy-1.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:70771a461aaeb335df14deb6c97439973d253ae70660ca085eec25241137ef43"}, + {file = "contourpy-1.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65a887a6e8c4cd0897507d814b14c54a8c2e2aa4ac9f7686292f9769fcf9a6ab"}, + {file = "contourpy-1.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3859783aefa2b8355697f16642695a5b9792e7a46ab86da1118a4a23a51a33d7"}, + {file = "contourpy-1.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:eab0f6db315fa4d70f1d8ab514e527f0366ec021ff853d7ed6a2d33605cf4b83"}, + {file = "contourpy-1.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d91a3ccc7fea94ca0acab82ceb77f396d50a1f67412efe4c526f5d20264e6ecd"}, + {file = "contourpy-1.3.2-cp311-cp311-win32.whl", hash = "sha256:1c48188778d4d2f3d48e4643fb15d8608b1d01e4b4d6b0548d9b336c28fc9b6f"}, + {file = "contourpy-1.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:5ebac872ba09cb8f2131c46b8739a7ff71de28a24c869bcad554477eb089a878"}, + {file = "contourpy-1.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4caf2bcd2969402bf77edc4cb6034c7dd7c0803213b3523f111eb7460a51b8d2"}, + {file = "contourpy-1.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:82199cb78276249796419fe36b7386bd8d2cc3f28b3bc19fe2454fe2e26c4c15"}, + {file = "contourpy-1.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:106fab697af11456fcba3e352ad50effe493a90f893fca6c2ca5c033820cea92"}, + {file = "contourpy-1.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d14f12932a8d620e307f715857107b1d1845cc44fdb5da2bc8e850f5ceba9f87"}, + {file = "contourpy-1.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:532fd26e715560721bb0d5fc7610fce279b3699b018600ab999d1be895b09415"}, + {file = "contourpy-1.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b383144cf2d2c29f01a1e8170f50dacf0eac02d64139dcd709a8ac4eb3cfe"}, + {file = "contourpy-1.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c49f73e61f1f774650a55d221803b101d966ca0c5a2d6d5e4320ec3997489441"}, + {file = "contourpy-1.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3d80b2c0300583228ac98d0a927a1ba6a2ba6b8a742463c564f1d419ee5b211e"}, + {file = "contourpy-1.3.2-cp312-cp312-win32.whl", hash = "sha256:90df94c89a91b7362e1142cbee7568f86514412ab8a2c0d0fca72d7e91b62912"}, + {file = "contourpy-1.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:8c942a01d9163e2e5cfb05cb66110121b8d07ad438a17f9e766317bcb62abf73"}, + {file = "contourpy-1.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:de39db2604ae755316cb5967728f4bea92685884b1e767b7c24e983ef5f771cb"}, + {file = "contourpy-1.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3f9e896f447c5c8618f1edb2bafa9a4030f22a575ec418ad70611450720b5b08"}, + {file = "contourpy-1.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71e2bd4a1c4188f5c2b8d274da78faab884b59df20df63c34f74aa1813c4427c"}, + {file = "contourpy-1.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de425af81b6cea33101ae95ece1f696af39446db9682a0b56daaa48cfc29f38f"}, + {file = "contourpy-1.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:977e98a0e0480d3fe292246417239d2d45435904afd6d7332d8455981c408b85"}, + {file = "contourpy-1.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:434f0adf84911c924519d2b08fc10491dd282b20bdd3fa8f60fd816ea0b48841"}, + {file = "contourpy-1.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c66c4906cdbc50e9cba65978823e6e00b45682eb09adbb78c9775b74eb222422"}, + {file = "contourpy-1.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8b7fc0cd78ba2f4695fd0a6ad81a19e7e3ab825c31b577f384aa9d7817dc3bef"}, + {file = "contourpy-1.3.2-cp313-cp313-win32.whl", hash = "sha256:15ce6ab60957ca74cff444fe66d9045c1fd3e92c8936894ebd1f3eef2fff075f"}, + {file = "contourpy-1.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e1578f7eafce927b168752ed7e22646dad6cd9bca673c60bff55889fa236ebf9"}, + {file = "contourpy-1.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0475b1f6604896bc7c53bb070e355e9321e1bc0d381735421a2d2068ec56531f"}, + {file = "contourpy-1.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c85bb486e9be652314bb5b9e2e3b0d1b2e643d5eec4992c0fbe8ac71775da739"}, + {file = "contourpy-1.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:745b57db7758f3ffc05a10254edd3182a2a83402a89c00957a8e8a22f5582823"}, + {file = "contourpy-1.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:970e9173dbd7eba9b4e01aab19215a48ee5dd3f43cef736eebde064a171f89a5"}, + {file = "contourpy-1.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6c4639a9c22230276b7bffb6a850dfc8258a2521305e1faefe804d006b2e532"}, + {file = "contourpy-1.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc829960f34ba36aad4302e78eabf3ef16a3a100863f0d4eeddf30e8a485a03b"}, + {file = "contourpy-1.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d32530b534e986374fc19eaa77fcb87e8a99e5431499949b828312bdcd20ac52"}, + {file = "contourpy-1.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e298e7e70cf4eb179cc1077be1c725b5fd131ebc81181bf0c03525c8abc297fd"}, + {file = "contourpy-1.3.2-cp313-cp313t-win32.whl", hash = "sha256:d0e589ae0d55204991450bb5c23f571c64fe43adaa53f93fc902a84c96f52fe1"}, + {file = "contourpy-1.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:78e9253c3de756b3f6a5174d024c4835acd59eb3f8e2ca13e775dbffe1558f69"}, + {file = "contourpy-1.3.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fd93cc7f3139b6dd7aab2f26a90dde0aa9fc264dbf70f6740d498a70b860b82c"}, + {file = "contourpy-1.3.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:107ba8a6a7eec58bb475329e6d3b95deba9440667c4d62b9b6063942b61d7f16"}, + {file = "contourpy-1.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ded1706ed0c1049224531b81128efbd5084598f18d8a2d9efae833edbd2b40ad"}, + {file = "contourpy-1.3.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5f5964cdad279256c084b69c3f412b7801e15356b16efa9d78aa974041903da0"}, + {file = "contourpy-1.3.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49b65a95d642d4efa8f64ba12558fcb83407e58a2dfba9d796d77b63ccfcaff5"}, + {file = "contourpy-1.3.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8c5acb8dddb0752bf252e01a3035b21443158910ac16a3b0d20e7fed7d534ce5"}, + {file = "contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54"}, ] [package.dependencies] -numpy = ">=1.20,<2.0" +numpy = ">=1.23" [package.extras] bokeh = ["bokeh", "selenium"] docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] -mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.6.1)", "types-Pillow"] +mypy = ["bokeh", "contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.15.0)", "types-Pillow"] test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] -test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] +test-no-images = ["pytest", "pytest-cov", "pytest-rerunfailures", "pytest-xdist", "wurlitzer"] [[package]] name = "cryptography" @@ -888,13 +914,13 @@ test-randomorder = ["pytest-randomly"] [[package]] name = "cvat-sdk" -version = "2.37.0" -description = "CVAT REST API" +version = "2.70.0" +description = "Software Development Kit for CVAT" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" files = [ - {file = "cvat_sdk-2.37.0-py3-none-any.whl", hash = "sha256:faa94cfd6678089814179a8da828761dfa3daf08eb752490ee85551a1045dac5"}, - {file = "cvat_sdk-2.37.0.tar.gz", hash = "sha256:e990908a473c499eb6d7b84f7f2e640ea729ef027d4c4cc32a5a925752532689"}, + {file = "cvat_sdk-2.70.0-py3-none-any.whl", hash = "sha256:6098b01bda86433d96e177cfce5e28dce2c19f7c0bd3b0e814b8d7e45b8e1a46"}, + {file = "cvat_sdk-2.70.0.tar.gz", hash = "sha256:4d9304bd8334b05b5e5504466cedf1f538a667f5274544398dec78bba4b47e83"}, ] [package.dependencies] @@ -903,9 +929,7 @@ packaging = ">=21.3" Pillow = ">=10.3.0" platformdirs = ">=2.1.0" python_dateutil = ">=2.5.3" -setuptools = ">=21.0.0" tqdm = ">=4.64.0" -tuspy = "0.2.5" typing_extensions = ">=4.2.0" urllib3 = ">=1.25.3" @@ -930,118 +954,192 @@ tests = ["pytest", "pytest-cov", "pytest-xdist"] [[package]] name = "cytoolz" -version = "1.0.1" +version = "1.1.0" description = "Cython implementation of Toolz: High performance functional utilities" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "cytoolz-1.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cec9af61f71fc3853eb5dca3d42eb07d1f48a4599fa502cbe92adde85f74b042"}, - {file = "cytoolz-1.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:140bbd649dbda01e91add7642149a5987a7c3ccc251f2263de894b89f50b6608"}, - {file = "cytoolz-1.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e90124bdc42ff58b88cdea1d24a6bc5f776414a314cc4d94f25c88badb3a16d1"}, - {file = "cytoolz-1.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e74801b751e28f7c5cc3ad264c123954a051f546f2fdfe089f5aa7a12ccfa6da"}, - {file = "cytoolz-1.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:582dad4545ddfb5127494ef23f3fa4855f1673a35d50c66f7638e9fb49805089"}, - {file = "cytoolz-1.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd7bd0618e16efe03bd12f19c2a26a27e6e6b75d7105adb7be1cd2a53fa755d8"}, - {file = "cytoolz-1.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d74cca6acf1c4af58b2e4a89cc565ed61c5e201de2e434748c93e5a0f5c541a5"}, - {file = "cytoolz-1.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:823a3763828d8d457f542b2a45d75d6b4ced5e470b5c7cf2ed66a02f508ed442"}, - {file = "cytoolz-1.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:51633a14e6844c61db1d68c1ffd077cf949f5c99c60ed5f1e265b9e2966f1b52"}, - {file = "cytoolz-1.0.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f3ec9b01c45348f1d0d712507d54c2bfd69c62fbd7c9ef555c9d8298693c2432"}, - {file = "cytoolz-1.0.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1855022b712a9c7a5bce354517ab4727a38095f81e2d23d3eabaf1daeb6a3b3c"}, - {file = "cytoolz-1.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9930f7288c4866a1dc1cc87174f0c6ff4cad1671eb1f6306808aa6c445857d78"}, - {file = "cytoolz-1.0.1-cp310-cp310-win32.whl", hash = "sha256:a9baad795d72fadc3445ccd0f122abfdbdf94269157e6d6d4835636dad318804"}, - {file = "cytoolz-1.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:ad95b386a84e18e1f6136f6d343d2509d4c3aae9f5a536f3dc96808fcc56a8cf"}, - {file = "cytoolz-1.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2d958d4f04d9d7018e5c1850790d9d8e68b31c9a2deebca74b903706fdddd2b6"}, - {file = "cytoolz-1.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0f445b8b731fc0ecb1865b8e68a070084eb95d735d04f5b6c851db2daf3048ab"}, - {file = "cytoolz-1.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f546a96460a7e28eb2ec439f4664fa646c9b3e51c6ebad9a59d3922bbe65e30"}, - {file = "cytoolz-1.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0317681dd065532d21836f860b0563b199ee716f55d0c1f10de3ce7100c78a3b"}, - {file = "cytoolz-1.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0c0ef52febd5a7821a3fd8d10f21d460d1a3d2992f724ba9c91fbd7a96745d41"}, - {file = "cytoolz-1.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5ebaf419acf2de73b643cf96108702b8aef8e825cf4f63209ceb078d5fbbbfd"}, - {file = "cytoolz-1.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f7f04eeb4088947585c92d6185a618b25ad4a0f8f66ea30c8db83cf94a425e3"}, - {file = "cytoolz-1.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f61928803bb501c17914b82d457c6f50fe838b173fb40d39c38d5961185bd6c7"}, - {file = "cytoolz-1.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d2960cb4fa01ccb985ad1280db41f90dc97a80b397af970a15d5a5de403c8c61"}, - {file = "cytoolz-1.0.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b2b407cc3e9defa8df5eb46644f6f136586f70ba49eba96f43de67b9a0984fd3"}, - {file = "cytoolz-1.0.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:8245f929144d4d3bd7b972c9593300195c6cea246b81b4c46053c48b3f044580"}, - {file = "cytoolz-1.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e37385db03af65763933befe89fa70faf25301effc3b0485fec1c15d4ce4f052"}, - {file = "cytoolz-1.0.1-cp311-cp311-win32.whl", hash = "sha256:50f9c530f83e3e574fc95c264c3350adde8145f4f8fc8099f65f00cc595e5ead"}, - {file = "cytoolz-1.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:b7f6b617454b4326af7bd3c7c49b0fc80767f134eb9fd6449917a058d17a0e3c"}, - {file = "cytoolz-1.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fcb8f7d0d65db1269022e7e0428471edee8c937bc288ebdcb72f13eaa67c2fe4"}, - {file = "cytoolz-1.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:207d4e4b445e087e65556196ff472ff134370d9a275d591724142e255f384662"}, - {file = "cytoolz-1.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21cdf6bac6fd843f3b20280a66fd8df20dea4c58eb7214a2cd8957ec176f0bb3"}, - {file = "cytoolz-1.0.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a55ec098036c0dea9f3bdc021f8acd9d105a945227d0811589f0573f21c9ce1"}, - {file = "cytoolz-1.0.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a13ab79ff4ce202e03ab646a2134696988b554b6dc4b71451e948403db1331d8"}, - {file = "cytoolz-1.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e2d944799026e1ff08a83241f1027a2d9276c41f7a74224cd98b7df6e03957d"}, - {file = "cytoolz-1.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88ba85834cd523b91fdf10325e1e6d71c798de36ea9bdc187ca7bd146420de6f"}, - {file = "cytoolz-1.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a750b1af7e8bf6727f588940b690d69e25dc47cce5ce467925a76561317eaf7"}, - {file = "cytoolz-1.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:44a71870f7eae31d263d08b87da7c2bf1176f78892ed8bdade2c2850478cb126"}, - {file = "cytoolz-1.0.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c8231b9abbd8e368e036f4cc2e16902c9482d4cf9e02a6147ed0e9a3cd4a9ab0"}, - {file = "cytoolz-1.0.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:aa87599ccc755de5a096a4d6c34984de6cd9dc928a0c5eaa7607457317aeaf9b"}, - {file = "cytoolz-1.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:67cd16537df51baabde3baa770ab7b8d16839c4d21219d5b96ac59fb012ebd2d"}, - {file = "cytoolz-1.0.1-cp312-cp312-win32.whl", hash = "sha256:fb988c333f05ee30ad4693fe4da55d95ec0bb05775d2b60191236493ea2e01f9"}, - {file = "cytoolz-1.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:8f89c48d8e5aec55ffd566a8ec858706d70ed0c6a50228eca30986bfa5b4da8b"}, - {file = "cytoolz-1.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6944bb93b287032a4c5ca6879b69bcd07df46f3079cf8393958cf0b0454f50c0"}, - {file = "cytoolz-1.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e027260fd2fc5cb041277158ac294fc13dca640714527219f702fb459a59823a"}, - {file = "cytoolz-1.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88662c0e07250d26f5af9bc95911e6137e124a5c1ec2ce4a5d74de96718ab242"}, - {file = "cytoolz-1.0.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:309dffa78b0961b4c0cf55674b828fbbc793cf2d816277a5c8293c0c16155296"}, - {file = "cytoolz-1.0.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:edb34246e6eb40343c5860fc51b24937698e4fa1ee415917a73ad772a9a1746b"}, - {file = "cytoolz-1.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a54da7a8e4348a18d45d4d5bc84af6c716d7f131113a4f1cc45569d37edff1b"}, - {file = "cytoolz-1.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:241c679c3b1913c0f7259cf1d9639bed5084c86d0051641d537a0980548aa266"}, - {file = "cytoolz-1.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5bfc860251a8f280ac79696fc3343cfc3a7c30b94199e0240b6c9e5b6b01a2a5"}, - {file = "cytoolz-1.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c8edd1547014050c1bdad3ff85d25c82bd1c2a3c96830c6181521eb78b9a42b3"}, - {file = "cytoolz-1.0.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b349bf6162e8de215403d7f35f8a9b4b1853dc2a48e6e1a609a5b1a16868b296"}, - {file = "cytoolz-1.0.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1b18b35256219b6c3dd0fa037741b85d0bea39c552eab0775816e85a52834140"}, - {file = "cytoolz-1.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:738b2350f340ff8af883eb301054eb724997f795d20d90daec7911c389d61581"}, - {file = "cytoolz-1.0.1-cp313-cp313-win32.whl", hash = "sha256:9cbd9c103df54fcca42be55ef40e7baea624ac30ee0b8bf1149f21146d1078d9"}, - {file = "cytoolz-1.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:90e577e08d3a4308186d9e1ec06876d4756b1e8164b92971c69739ea17e15297"}, - {file = "cytoolz-1.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f3a509e4ac8e711703c368476b9bbce921fcef6ebb87fa3501525f7000e44185"}, - {file = "cytoolz-1.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a7eecab6373e933dfbf4fdc0601d8fd7614f8de76793912a103b5fccf98170cd"}, - {file = "cytoolz-1.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e55ed62087f6e3e30917b5f55350c3b6be6470b849c6566018419cd159d2cebc"}, - {file = "cytoolz-1.0.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43de33d99a4ccc07234cecd81f385456b55b0ea9c39c9eebf42f024c313728a5"}, - {file = "cytoolz-1.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:139bed875828e1727018aa0982aa140e055cbafccb7fd89faf45cbb4f2a21514"}, - {file = "cytoolz-1.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22c12671194b518aa8ce2f4422bd5064f25ab57f410ba0b78705d0a219f4a97a"}, - {file = "cytoolz-1.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79888f2f7dc25709cd5d37b032a8833741e6a3692c8823be181d542b5999128e"}, - {file = "cytoolz-1.0.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:51628b4eb41fa25bd428f8f7b5b74fbb05f3ae65fbd265019a0dd1ded4fdf12a"}, - {file = "cytoolz-1.0.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:1db9eb7179285403d2fb56ba1ff6ec35a44921b5e2fa5ca19d69f3f9f0285ea5"}, - {file = "cytoolz-1.0.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:08ab7efae08e55812340bfd1b3f09f63848fe291675e2105eab1aa5327d3a16e"}, - {file = "cytoolz-1.0.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:e5fdc5264f884e7c0a1711a81dff112708a64b9c8561654ee578bfdccec6be09"}, - {file = "cytoolz-1.0.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:90d6a2e6ab891043ee655ec99d5e77455a9bee9e1131bdfcfb745edde81200dd"}, - {file = "cytoolz-1.0.1-cp38-cp38-win32.whl", hash = "sha256:08946e083faa5147751b34fbf78ab931f149ef758af5c1092932b459e18dcf5c"}, - {file = "cytoolz-1.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:a91b4e10a9c03796c0dc93e47ebe25bb41ecc6fafc3cf5197c603cf767a3d44d"}, - {file = "cytoolz-1.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:980c323e626ba298b77ae62871b2de7c50b9d7219e2ddf706f52dd34b8be7349"}, - {file = "cytoolz-1.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:45f6fa1b512bc2a0f2de5123db932df06c7f69d12874fe06d67772b2828e2c8b"}, - {file = "cytoolz-1.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f93f42d9100c415155ad1f71b0de362541afd4ac95e3153467c4c79972521b6b"}, - {file = "cytoolz-1.0.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a76d20dec9c090cdf4746255bbf06a762e8cc29b5c9c1d138c380bbdb3122ade"}, - {file = "cytoolz-1.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:239039585487c69aa50c5b78f6a422016297e9dea39755761202fb9f0530fe87"}, - {file = "cytoolz-1.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c28307640ca2ab57b9fbf0a834b9bf563958cd9e038378c3a559f45f13c3c541"}, - {file = "cytoolz-1.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:454880477bb901cee3a60f6324ec48c95d45acc7fecbaa9d49a5af737ded0595"}, - {file = "cytoolz-1.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:902115d1b1f360fd81e44def30ac309b8641661150fcbdde18ead446982ada6a"}, - {file = "cytoolz-1.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e68e6b38473a3a79cee431baa22be31cac39f7df1bf23eaa737eaff42e213883"}, - {file = "cytoolz-1.0.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:32fba3f63fcb76095b0a22f4bdcc22bc62a2bd2d28d58bf02fd21754c155a3ec"}, - {file = "cytoolz-1.0.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:0724ba4cf41eb40b6cf75250820ab069e44bdf4183ff78857aaf4f0061551075"}, - {file = "cytoolz-1.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c42420e0686f887040d5230420ed44f0e960ccbfa29a0d65a3acd9ca52459209"}, - {file = "cytoolz-1.0.1-cp39-cp39-win32.whl", hash = "sha256:4ba8b16358ea56b1fe8e637ec421e36580866f2e787910bac1cf0a6997424a34"}, - {file = "cytoolz-1.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:92d27f84bf44586853d9562bfa3610ecec000149d030f793b4cb614fd9da1813"}, - {file = "cytoolz-1.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:83d19d55738ad9c60763b94f3f6d3c6e4de979aeb8d76841c1401081e0e58d96"}, - {file = "cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f112a71fad6ea824578e6393765ce5c054603afe1471a5c753ff6c67fd872d10"}, - {file = "cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a515df8f8aa6e1eaaf397761a6e4aff2eef73b5f920aedf271416d5471ae5ee"}, - {file = "cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92c398e7b7023460bea2edffe5fcd0a76029580f06c3f6938ac3d198b47156f3"}, - {file = "cytoolz-1.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3237e56211e03b13df47435b2369f5df281e02b04ad80a948ebd199b7bc10a47"}, - {file = "cytoolz-1.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ba0d1da50aab1909b165f615ba1125c8b01fcc30d606c42a61c42ea0269b5e2c"}, - {file = "cytoolz-1.0.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25b6e8dec29aa5a390092d193abd673e027d2c0b50774ae816a31454286c45c7"}, - {file = "cytoolz-1.0.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:36cd6989ebb2f18fe9af8f13e3c61064b9f741a40d83dc5afeb0322338ad25f2"}, - {file = "cytoolz-1.0.1-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a47394f8ab7fca3201f40de61fdeea20a2baffb101485ae14901ea89c3f6c95d"}, - {file = "cytoolz-1.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d00ac423542af944302e034e618fb055a0c4e87ba704cd6a79eacfa6ac83a3c9"}, - {file = "cytoolz-1.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a5ca923d1fa632f7a4fb33c0766c6fba7f87141a055c305c3e47e256fb99c413"}, - {file = "cytoolz-1.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:058bf996bcae9aad3acaeeb937d42e0c77c081081e67e24e9578a6a353cb7fb2"}, - {file = "cytoolz-1.0.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:69e2a1f41a3dad94a17aef4a5cc003323359b9f0a9d63d4cc867cb5690a2551d"}, - {file = "cytoolz-1.0.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67daeeeadb012ec2b59d63cb29c4f2a2023b0c4957c3342d354b8bb44b209e9a"}, - {file = "cytoolz-1.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:54d3d36bbf0d4344d1afa22c58725d1668e30ff9de3a8f56b03db1a6da0acb11"}, - {file = "cytoolz-1.0.1.tar.gz", hash = "sha256:89cc3161b89e1bb3ed7636f74ed2e55984fd35516904fc878cae216e42b2c7d6"}, + {file = "cytoolz-1.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:72d7043a88ea5e61ba9d17ea0d1c1eff10f645d7edfcc4e56a31ef78be287644"}, + {file = "cytoolz-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d759e9ed421bacfeb456d47af8d734c057b9912b5f2441f95b27ca35e5efab07"}, + {file = "cytoolz-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fdb5be8fbcc0396141189022724155a4c1c93712ac4aef8c03829af0c2a816d7"}, + {file = "cytoolz-1.1.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c8c0a513dc89bc05cc72893609118815bced5ef201f1a317b4cc3423b3a0e750"}, + {file = "cytoolz-1.1.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce94db4f8ebe842c30c0ece42ff5de977c47859088c2c363dede5a68f6906484"}, + {file = "cytoolz-1.1.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b622d4f54e370c853ded94a668f94fe72c6d70e06ac102f17a2746661c27ab52"}, + {file = "cytoolz-1.1.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:375a65baa5a5b4ff6a0c5ff17e170cf23312e4c710755771ca966144c24216b5"}, + {file = "cytoolz-1.1.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c0d51bcdb3203a062a78f66bbe33db5e3123048e24a5f0e1402422d79df8ee2d"}, + {file = "cytoolz-1.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1010869529bb05dc9802b6d776a34ca1b6d48b9deec70ad5e2918ae175be5c2f"}, + {file = "cytoolz-1.1.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:11a8f2e83295bdb33f35454d6bafcb7845b03b5881dcaed66ecbd726c7f16772"}, + {file = "cytoolz-1.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0499c5e0a8e688ed367a2e51cc13792ae8f08226c15f7d168589fc44b9b9cada"}, + {file = "cytoolz-1.1.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:87d44e6033d4c5e95a7d39ba59b8e105ba1c29b1ccd1d215f26477cc1d64be39"}, + {file = "cytoolz-1.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a68cef396a7de237f7b97422a6a450dfb111722296ba217ba5b34551832f1f6e"}, + {file = "cytoolz-1.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:06ad4c95b258141f138a93ebfdc1d76ac087afc1a82f1401100a1f44b44ba656"}, + {file = "cytoolz-1.1.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:ada59a4b3c59d4ac7162e0ed08667ffa78abf48e975c8a9f9d5b9bc50720f4fd"}, + {file = "cytoolz-1.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:a8957bcaea1ba01327a9b219d2adb84144377684f51444253890dab500ca171f"}, + {file = "cytoolz-1.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6d8cdc299d67eb0f3b9ecdafeeb55eb3b7b7470e2d950ac34b05ed4c7a5572b8"}, + {file = "cytoolz-1.1.0-cp310-cp310-win32.whl", hash = "sha256:d8e08464c5cdea4f6df31e84b11ed6bfd79cedb99fbcbfdc15eb9361a6053c5a"}, + {file = "cytoolz-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:7e49922a7ed54262d41960bf3b835a7700327bf79cff1e9bfc73d79021132ff8"}, + {file = "cytoolz-1.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:943a662d2e72ffc4438d43ab5a1de8d852237775a423236594a3b3e381b8032c"}, + {file = "cytoolz-1.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:dba8e5a8c6e3c789d27b0eb5e7ce5ed7d032a7a9aae17ca4ba5147b871f6e327"}, + {file = "cytoolz-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:44b31c05addb0889167a720123b3b497b28dd86f8a0aeaf3ae4ffa11e2c85d55"}, + {file = "cytoolz-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:653cb18c4fc5d8a8cfce2bce650aabcbe82957cd0536827367d10810566d5294"}, + {file = "cytoolz-1.1.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:853a5b4806915020c890e1ce70cc056bbc1dd8bc44f2d74d555cccfd7aefba7d"}, + {file = "cytoolz-1.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7b44e9de86bea013fe84fd8c399d6016bbb96c37c5290769e5c99460b9c53e5"}, + {file = "cytoolz-1.1.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:098d628a801dc142e9740126be5624eb7aef1d732bc7a5719f60a2095547b485"}, + {file = "cytoolz-1.1.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:779ee4096ed7a82cffab89372ffc339631c285079dbf33dbe7aff1f6174985df"}, + {file = "cytoolz-1.1.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f2ce18dd99533d077e9712f9faa852f389f560351b1efd2f2bdb193a95eddde2"}, + {file = "cytoolz-1.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ac266a34437812cf841cecbfe19f355ab9c3dd1ef231afc60415d40ff12a76e4"}, + {file = "cytoolz-1.1.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1920b9b9c13d60d0bb6cd14594b3bce0870022eccb430618c37156da5f2b7a55"}, + {file = "cytoolz-1.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47caa376dafd2bdc29f8a250acf59c810ec9105cd6f7680b9a9d070aae8490ec"}, + {file = "cytoolz-1.1.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:5ab2c97d8aaa522b038cca9187b1153347af22309e7c998b14750c6fdec7b1cb"}, + {file = "cytoolz-1.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4bce006121b120e8b359244ee140bb0b1093908efc8b739db8dbaa3f8fb42139"}, + {file = "cytoolz-1.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7fc0f1e4e9bb384d26e73c6657bbc26abdae4ff66a95933c00f3d578be89181b"}, + {file = "cytoolz-1.1.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:dd3f894ff972da1994d06ac6157d74e40dda19eb31fe5e9b7863ca4278c3a167"}, + {file = "cytoolz-1.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0846f49cf8a4496bd42659040e68bd0484ce6af819709cae234938e039203ba0"}, + {file = "cytoolz-1.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:16a3af394ade1973226d64bb2f9eb3336adbdea03ed5b134c1bbec5a3b20028e"}, + {file = "cytoolz-1.1.0-cp311-cp311-win32.whl", hash = "sha256:b786c9c8aeab76cc2f76011e986f7321a23a56d985b77d14f155d5e5514ea781"}, + {file = "cytoolz-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:ebf06d1c5344fb22fee71bf664234733e55db72d74988f2ecb7294b05e4db30c"}, + {file = "cytoolz-1.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:b63f5f025fac893393b186e132e3e242de8ee7265d0cd3f5bdd4dda93f6616c9"}, + {file = "cytoolz-1.1.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:99f8e134c9be11649342853ec8c90837af4089fc8ff1e8f9a024a57d1fa08514"}, + {file = "cytoolz-1.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0a6f44cf9319c30feb9a50aa513d777ef51efec16f31c404409e7deb8063df64"}, + {file = "cytoolz-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:945580dc158c557172fca899a35a99a16fbcebf6db0c77cb6621084bc82189f9"}, + {file = "cytoolz-1.1.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:257905ec050d04f2f856854620d1e25556fd735064cebd81b460f54939b9f9d5"}, + {file = "cytoolz-1.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:82779049f352fb3ab5e8c993ab45edbb6e02efb1f17f0b50f4972c706cc51d76"}, + {file = "cytoolz-1.1.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7d3e405e435320e08c5a1633afaf285a392e2d9cef35c925d91e2a31dfd7a688"}, + {file = "cytoolz-1.1.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:923df8f5591e0d20543060c29909c149ab1963a7267037b39eee03a83dbc50a8"}, + {file = "cytoolz-1.1.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:25db9e4862f22ea0ae2e56c8bec9fc9fd756b655ae13e8c7b5625d7ed1c582d4"}, + {file = "cytoolz-1.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c7a98deb11ccd8e5d9f9441ef2ff3352aab52226a2b7d04756caaa53cd612363"}, + {file = "cytoolz-1.1.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dce4ee9fc99104bc77efdea80f32ca5a650cd653bcc8a1d984a931153d3d9b58"}, + {file = "cytoolz-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:80d6da158f7d20c15819701bbda1c041f0944ede2f564f5c739b1bc80a9ffb8b"}, + {file = "cytoolz-1.1.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:3b5c5a192abda123ad45ef716ec9082b4cf7d95e9ada8291c5c2cc5558be858b"}, + {file = "cytoolz-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5b399ce7d967b1cb6280250818b786be652aa8ddffd3c0bb5c48c6220d945ab5"}, + {file = "cytoolz-1.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e7e29a1a03f00b4322196cfe8e2c38da9a6c8d573566052c586df83aacc5663c"}, + {file = "cytoolz-1.1.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:5291b117d71652a817ec164e7011f18e6a51f8a352cc9a70ed5b976c51102fda"}, + {file = "cytoolz-1.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:8caef62f846a9011676c51bda9189ae394cdd6bb17f2946ecaedc23243268320"}, + {file = "cytoolz-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:de425c5a8e3be7bb3a195e19191d28d9eb3c2038046064a92edc4505033ec9cb"}, + {file = "cytoolz-1.1.0-cp312-cp312-win32.whl", hash = "sha256:296440a870e8d1f2e1d1edf98f60f1532b9d3ab8dfbd4b25ec08cd76311e79e5"}, + {file = "cytoolz-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:07156987f224c6dac59aa18fb8bf91e1412f5463961862716a3381bf429c8699"}, + {file = "cytoolz-1.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:23e616b38f5b3160c7bb45b0f84a8f3deb4bd26b29fb2dfc716f241c738e27b8"}, + {file = "cytoolz-1.1.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:76c9b58555300be6dde87a41faf1f97966d79b9a678b7a526fcff75d28ef4945"}, + {file = "cytoolz-1.1.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:d1d638b10d3144795655e9395566ce35807df09219fd7cacd9e6acbdef67946a"}, + {file = "cytoolz-1.1.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:26801c1a165e84786a99e03c9c9973356caaca002d66727b761fb1042878ef06"}, + {file = "cytoolz-1.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2a9a464542912d3272f6dccc5142df057c71c6a5cbd30439389a732df401afb7"}, + {file = "cytoolz-1.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ed6104fa942aa5784bf54f339563de637557e3443b105760bc4de8f16a7fc79b"}, + {file = "cytoolz-1.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56161f0ab60dc4159ec343509abaf809dc88e85c7e420e354442c62e3e7cbb77"}, + {file = "cytoolz-1.1.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:832bd36cc9123535f1945acf6921f8a2a15acc19cfe4065b1c9b985a28671886"}, + {file = "cytoolz-1.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1842636b6e034f229bf084c2bcdcfd36c8437e752eefd2c74ce9e2f10415cb6e"}, + {file = "cytoolz-1.1.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:823df012ab90d2f2a0f92fea453528539bf71ac1879e518524cd0c86aa6df7b9"}, + {file = "cytoolz-1.1.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2f1fcf9e7e7b3487883ff3f815abc35b89dcc45c4cf81c72b7ee457aa72d197b"}, + {file = "cytoolz-1.1.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4cdb3fa1772116827f263f25b0cdd44c663b6701346a56411960534a06c082de"}, + {file = "cytoolz-1.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d1b5c95041741b81430454db65183e133976f45ac3c03454cfa8147952568529"}, + {file = "cytoolz-1.1.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b2079fd9f1a65f4c61e6278c8a6d4f85edf30c606df8d5b32f1add88cbbe2286"}, + {file = "cytoolz-1.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a92a320d72bef1c7e2d4c6d875125cf57fc38be45feb3fac1bfa64ea401f54a4"}, + {file = "cytoolz-1.1.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:06d1c79aa51e6a92a90b0e456ebce2288f03dd6a76c7f582bfaa3eda7692e8a5"}, + {file = "cytoolz-1.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e1d7be25f6971e986a52b6d3a0da28e1941850985417c35528f6823aef2cfec5"}, + {file = "cytoolz-1.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:964b248edc31efc50a65e9eaa0c845718503823439d2fa5f8d2c7e974c2b5409"}, + {file = "cytoolz-1.1.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c9ff2b3c57c79b65cb5be14a18c6fd4a06d5036fb3f33e973a9f70e9ac13ca28"}, + {file = "cytoolz-1.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:22290b73086af600042d99f5ce52a43d4ad9872c382610413176e19fc1d4fd2d"}, + {file = "cytoolz-1.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a2ade74fccd080ea793382968913ee38d7a35c921df435bbf0a6aeecf0d17574"}, + {file = "cytoolz-1.1.0-cp313-cp313-win32.whl", hash = "sha256:db5dbcfda1c00e937426cbf9bdc63c24ebbc358c3263bfcbc1ab4a88dc52aa8e"}, + {file = "cytoolz-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:9e2d3fe3b45c3eb7233746f7aca37789be3dceec3e07dcc406d3e045ea0f7bdc"}, + {file = "cytoolz-1.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:32c559f95ff44a9ebcbd934acaa1e6dc8f3e6ffce4762a79a88528064873d6d5"}, + {file = "cytoolz-1.1.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:9e2cd93b28f667c5870a070ab2b8bb4397470a85c4b204f2454b0ad001cd1ca3"}, + {file = "cytoolz-1.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:f494124e141a9361f31d79875fe7ea459a3be2b9dadd90480427c0c52a0943d4"}, + {file = "cytoolz-1.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:53a3262bf221f19437ed544bf8c0e1980c81ac8e2a53d87a9bc075dba943d36f"}, + {file = "cytoolz-1.1.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:47663e57d3f3f124921f38055e86a1022d0844c444ede2e8f090d3bbf80deb65"}, + {file = "cytoolz-1.1.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a5a8755c4104ee4e3d5ba434c543b5f85fdee6a1f1df33d93f518294da793a60"}, + {file = "cytoolz-1.1.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4d96ff3d381423af1b105295f97de86d1db51732c9566eb37378bab6670c5010"}, + {file = "cytoolz-1.1.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0ec96b3d537cdf47d4e76ded199f7440715f4c71029b45445cff92c1248808c2"}, + {file = "cytoolz-1.1.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:208e2f2ef90a32b0acbff3303d90d89b13570a228d491d2e622a7883a3c68148"}, + {file = "cytoolz-1.1.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0d416a81bb0bd517558668e49d30a7475b5445f9bbafaab7dcf066f1e9adba36"}, + {file = "cytoolz-1.1.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f32e94c91ffe49af04835ee713ebd8e005c85ebe83e7e1fdcc00f27164c2d636"}, + {file = "cytoolz-1.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:15d0c6405efc040499c46df44056a5c382f551a7624a41cf3e4c84a96b988a15"}, + {file = "cytoolz-1.1.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:bf069c5381d757debae891401b88b3a346ba3a28ca45ba9251103b282463fad8"}, + {file = "cytoolz-1.1.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7d5cf15892e63411ec1bd67deff0e84317d974e6ab2cdfefdd4a7cea2989df66"}, + {file = "cytoolz-1.1.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:3e3872c21170f8341656f8692f8939e8800dcee6549ad2474d4c817bdefd62cd"}, + {file = "cytoolz-1.1.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:b9ddeff8e8fd65eb1fcefa61018100b2b627e759ea6ad275d2e2a93ffac147bf"}, + {file = "cytoolz-1.1.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:02feeeda93e1fa3b33414eb57c2b0aefd1db8f558dd33fdfcce664a0f86056e4"}, + {file = "cytoolz-1.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d08154ad45349162b6c37f12d5d1b2e6eef338e657b85e1621e4e6a4a69d64cb"}, + {file = "cytoolz-1.1.0-cp313-cp313t-win32.whl", hash = "sha256:10ae4718a056948d73ca3e1bb9ab1f95f897ec1e362f829b9d37cc29ab566c60"}, + {file = "cytoolz-1.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:1bb77bc6197e5cb19784b6a42bb0f8427e81737a630d9d7dda62ed31733f9e6c"}, + {file = "cytoolz-1.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:563dda652c6ff52d215704fbe6b491879b78d7bbbb3a9524ec8e763483cb459f"}, + {file = "cytoolz-1.1.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:d542cee7c7882d2a914a33dec4d3600416fb336734df979473249d4c53d207a1"}, + {file = "cytoolz-1.1.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:31922849b701b0f24bb62e56eb2488dcd3aa6ae3057694bd6b3b7c4c2bc27c2f"}, + {file = "cytoolz-1.1.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:e68308d32afd31943314735c1335e4ab5696110e96b405f6bdb8f2a8dc771a16"}, + {file = "cytoolz-1.1.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fc4bb48b3b866e1867f7c6411a4229e5b44be3989060663713e10efc24c9bd5f"}, + {file = "cytoolz-1.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:456f77207d1445025d7ef262b8370a05492dcb1490cb428b0f3bf1bd744a89b0"}, + {file = "cytoolz-1.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:174ebc71ebb20a9baeffce6ee07ee2cd913754325c93f99d767380d8317930f7"}, + {file = "cytoolz-1.1.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8b3604fef602bcd53415055a4f68468339192fd17be39e687ae24f476d23d56e"}, + {file = "cytoolz-1.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3604b959a01f64c366e7d10ec7634d5f5cfe10301e27a8f090f6eb3b2a628a18"}, + {file = "cytoolz-1.1.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6db2127a3c1bc2f59f08010d2ae53a760771a9de2f67423ad8d400e9ba4276e8"}, + {file = "cytoolz-1.1.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56584745ac647993a016a21bc76399113b7595e312f8d0a1b140c9fcf9b58a27"}, + {file = "cytoolz-1.1.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:db2c4c3a7f7bd7e03bb1a236a125c8feb86c75802f4ecda6ecfaf946610b2930"}, + {file = "cytoolz-1.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:48cb8a692111a285d2b9acd16d185428176bfbffa8a7c274308525fccd01dd42"}, + {file = "cytoolz-1.1.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d2f344ba5eb17dcf38ee37fdde726f69053f54927db8f8a1bed6ac61e5b1890d"}, + {file = "cytoolz-1.1.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:abf76b1c1abd031f098f293b6d90ee08bdaa45f8b5678430e331d991b82684b1"}, + {file = "cytoolz-1.1.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:ddf9a38a5b686091265ff45b53d142e44a538cd6c2e70610d3bc6be094219032"}, + {file = "cytoolz-1.1.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:946786755274f07bb2be0400f28adb31d7d85a7c7001873c0a8e24a503428fb3"}, + {file = "cytoolz-1.1.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:d5b8f78b9fed79cf185ad4ddec099abeef45951bdcb416c5835ba05f0a1242c7"}, + {file = "cytoolz-1.1.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:fccde6efefdbc02e676ccb352a2ccc8a8e929f59a1c6d3d60bb78e923a49ca44"}, + {file = "cytoolz-1.1.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:717b7775313da5f51b0fbf50d865aa9c39cb241bd4cb605df3cf2246d6567397"}, + {file = "cytoolz-1.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5158744a09d0e0e4a4f82225e3a3c4ebf38f9ae74467aaa905467270e52f2794"}, + {file = "cytoolz-1.1.0-cp314-cp314-win32.whl", hash = "sha256:1ed534bdbbf063b2bb28fca7d0f6723a3e5a72b086e7c7fe6d74ae8c3e4d00e2"}, + {file = "cytoolz-1.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:472c1c9a085f5ad973ec0ad7f0b9ba0969faea6f96c9e397f6293d386f3a25ec"}, + {file = "cytoolz-1.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:a7ad7ca3386fa86bd301be3fa36e7f0acb024f412f665937955acfc8eb42deff"}, + {file = "cytoolz-1.1.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:64b63ed4b71b1ba813300ad0f06b8aff19a12cf51116e0e4f1ed837cea4debcf"}, + {file = "cytoolz-1.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:a60ba6f2ed9eb0003a737e1ee1e9fa2258e749da6477946008d4324efa25149f"}, + {file = "cytoolz-1.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1aa58e2434d732241f7f051e6f17657e969a89971025e24578b5cbc6f1346485"}, + {file = "cytoolz-1.1.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6965af3fc7214645970e312deb9bd35a213a1eaabcfef4f39115e60bf2f76867"}, + {file = "cytoolz-1.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ddd2863f321d67527d3b67a93000a378ad6f967056f68c06467fe011278a6d0e"}, + {file = "cytoolz-1.1.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4e6b428e9eb5126053c2ae0efa62512ff4b38ed3951f4d0888ca7005d63e56f5"}, + {file = "cytoolz-1.1.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d758e5ef311d2671e0ae8c214c52e44617cf1e58bef8f022b547b9802a5a7f30"}, + {file = "cytoolz-1.1.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a95416eca473e6c1179b48d86adcf528b59c63ce78f4cb9934f2e413afa9b56b"}, + {file = "cytoolz-1.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:36c8ede93525cf11e2cc787b7156e5cecd7340193ef800b816a16f1404a8dc6d"}, + {file = "cytoolz-1.1.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c949755b6d8a649c5fbc888bc30915926f1b09fe42fea9f289e297c2f6ddd3"}, + {file = "cytoolz-1.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e1b6d37545816905a76d9ed59fa4e332f929e879f062a39ea0f6f620405cdc27"}, + {file = "cytoolz-1.1.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:05332112d4087904842b36954cd1d3fc0e463a2f4a7ef9477bd241427c593c3b"}, + {file = "cytoolz-1.1.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:31538ca2fad2d688cbd962ccc3f1da847329e2258a52940f10a2ac0719e526be"}, + {file = "cytoolz-1.1.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:747562aa70abf219ea16f07d50ac0157db856d447f7f498f592e097cbc77df0b"}, + {file = "cytoolz-1.1.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:3dc15c48b20c0f467e15e341e102896c8422dccf8efc6322def5c1b02f074629"}, + {file = "cytoolz-1.1.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:3c03137ee6103ba92d5d6ad6a510e86fded69cd67050bd8a1843f15283be17ac"}, + {file = "cytoolz-1.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:be8e298d88f88bd172b59912240558be3b7a04959375646e7fd4996401452941"}, + {file = "cytoolz-1.1.0-cp314-cp314t-win32.whl", hash = "sha256:3d407140f5604a89578285d4aac7b18b8eafa055cf776e781aabb89c48738fad"}, + {file = "cytoolz-1.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:56e5afb69eb6e1b3ffc34716ee5f92ffbdb5cb003b3a5ca4d4b0fe700e217162"}, + {file = "cytoolz-1.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:27b19b4a286b3ff52040efa42dbe403730aebe5fdfd2def704eb285e2125c63e"}, + {file = "cytoolz-1.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:08a63935c66488511b7b29b06233be0be5f4123622fc8fd488f28dc1b7e4c164"}, + {file = "cytoolz-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:93bd0afcc4cc05794507084afaefb161c3639f283ee629bd0e8654b5c0327ba8"}, + {file = "cytoolz-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8f3d4da470cfd5cf44f6d682c6eb01363066e0af53ebe111225e44a618f9453d"}, + {file = "cytoolz-1.1.0-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ba6c12d0e6a67399f4102b4980f4f1bebdbf226ed0a68e84617709d4009b4e71"}, + {file = "cytoolz-1.1.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b557071405b4aeeaa7cbec1a95d15d6c8f37622fe3f4b595311e0e226ce772c"}, + {file = "cytoolz-1.1.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:cdb406001474726a47fbe903f3aba0de86f5c0b9c9861f55c09c366368225ae0"}, + {file = "cytoolz-1.1.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b6072876ba56446d9ac29d349983677d6f44c6d1c6c1c6be44e66e377c57c767"}, + {file = "cytoolz-1.1.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8c3784c965c9a6822d315d099c3a85b0884ac648952815891c667b469116f1d0"}, + {file = "cytoolz-1.1.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cc537ad78981df1a827773069fd3b7774f4478db43f518b1616efaf87d7d8f9"}, + {file = "cytoolz-1.1.0-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:574ee9dfdc632db8bf9237f27f2a687d1a0b90d29d5e96cab2b21fd2b419c17d"}, + {file = "cytoolz-1.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6594efbaea72dc58b368b53e745ad902c8d8cc41286f00b3743ceac464d5ef3f"}, + {file = "cytoolz-1.1.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:7c849f9ddaf3c7faba938440f9c849235a2908b303063d49da3092a93acd695b"}, + {file = "cytoolz-1.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1fef0296fb3577d0a08ad9b70344ee418f728f1ec21a768ffe774437d67ac859"}, + {file = "cytoolz-1.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:1dce1e66fdf72cc474367bd7a7f2b90ec67bb8197dc3fe8ecd08f4ce3ab950a1"}, + {file = "cytoolz-1.1.0-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:202fe9975efaec0085cab14a6a6050418bc041f5316f2cf098c0cd2aced4c50e"}, + {file = "cytoolz-1.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:528349434601b9d55e65c6a495494de0001c9a06b431547fea4c60b5edc7d5b3"}, + {file = "cytoolz-1.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3e248cdbf2a54bafdadf4486ddd32e8352f816d3caa2014e44de99f8c525d4a8"}, + {file = "cytoolz-1.1.0-cp39-cp39-win32.whl", hash = "sha256:e63f2b70f4654648a5c6a176ae80897c0de6401f385540dce8e365019e800cfe"}, + {file = "cytoolz-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:f731c53ed29959f105ae622b62e39603c207ed8e8cb2a40cd4accb63d9f92901"}, + {file = "cytoolz-1.1.0-cp39-cp39-win_arm64.whl", hash = "sha256:5a2120bf9e6e8f25e1b32748424a5571e319ef03a995a8fde663fd2feec1a696"}, + {file = "cytoolz-1.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f32e93a55681d782fc6af939f6df36509d65122423cbc930be39b141064adff8"}, + {file = "cytoolz-1.1.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:5d9bc596751cbda8073e65be02ca11706f00029768fbbbc81e11a8c290bb41aa"}, + {file = "cytoolz-1.1.0-pp311-pypy311_pp73-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9b16660d01c3931951fab49db422c627897c38c1a1f0393a97582004019a4887"}, + {file = "cytoolz-1.1.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b7de5718e2113d4efccea3f06055758cdbc17388ecc3341ba4d1d812837d7c1a"}, + {file = "cytoolz-1.1.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a12a2a1a6bc44099491c05a12039efa08cc33a3d0f8c7b0566185e085e139283"}, + {file = "cytoolz-1.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:047defa7f5f9a32f82373dbc3957289562e8a3fa58ae02ec8e4dca4f43a33a21"}, + {file = "cytoolz-1.1.0.tar.gz", hash = "sha256:13a7bf254c3c0d28b12e2290b82aed0f0977a4c2a2bf84854fcdc7796a29f3b0"}, ] [package.dependencies] toolz = ">=0.8.0" [package.extras] -cython = ["cython"] +cython = ["cython (>=0.29)"] +test = ["pytest"] [[package]] name = "datumaro" @@ -1096,46 +1194,57 @@ files = [ {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, ] +[[package]] +name = "detect-installer" +version = "0.1.0" +description = "Detect how a Python package was installed and get the correct upgrade command" +optional = false +python-versions = ">=3.10" +files = [ + {file = "detect_installer-0.1.0-py3-none-any.whl", hash = "sha256:034fb20fd665c36e6ba52b8821525ea07fb4f7f938cac459df889fb33801528a"}, + {file = "detect_installer-0.1.0.tar.gz", hash = "sha256:00ad7ba0a36e3cf7d08a40d3643011746dbc112597c7d475cc91c416710ca4e7"}, +] + [[package]] name = "distlib" -version = "0.4.0" +version = "0.4.3" description = "Distribution utilities" optional = false python-versions = "*" files = [ - {file = "distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16"}, - {file = "distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d"}, + {file = "distlib-0.4.3-py2.py3-none-any.whl", hash = "sha256:4b0ce306c966eb73bc3a7b6abad017c556dadd92c44701562cd528ac7fde4d5b"}, + {file = "distlib-0.4.3.tar.gz", hash = "sha256:f152097224a0ae24be5a0f6bae1b9359af82133bce63f98a95f86cae1aede9ed"}, ] [[package]] name = "dnspython" -version = "2.7.0" +version = "2.8.0" description = "DNS toolkit" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" files = [ - {file = "dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86"}, - {file = "dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1"}, + {file = "dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af"}, + {file = "dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f"}, ] [package.extras] -dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "hypercorn (>=0.16.0)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "quart-trio (>=0.11.0)", "sphinx (>=7.2.0)", "sphinx-rtd-theme (>=2.0.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"] -dnssec = ["cryptography (>=43)"] -doh = ["h2 (>=4.1.0)", "httpcore (>=1.0.0)", "httpx (>=0.26.0)"] -doq = ["aioquic (>=1.0.0)"] -idna = ["idna (>=3.7)"] -trio = ["trio (>=0.23)"] +dev = ["black (>=25.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "hypercorn (>=0.17.0)", "mypy (>=1.17)", "pylint (>=3)", "pytest (>=8.4)", "pytest-cov (>=6.2.0)", "quart-trio (>=0.12.0)", "sphinx (>=8.2.0)", "sphinx-rtd-theme (>=3.0.0)", "twine (>=6.1.0)", "wheel (>=0.45.0)"] +dnssec = ["cryptography (>=45)"] +doh = ["h2 (>=4.2.0)", "httpcore (>=1.0.0)", "httpx (>=0.28.0)"] +doq = ["aioquic (>=1.2.0)"] +idna = ["idna (>=3.10)"] +trio = ["trio (>=0.30)"] wmi = ["wmi (>=1.5.1)"] [[package]] name = "email-validator" -version = "2.2.0" +version = "2.3.0" description = "A robust email address syntax and deliverability validation library." optional = false python-versions = ">=3.8" files = [ - {file = "email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631"}, - {file = "email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7"}, + {file = "email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4"}, + {file = "email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426"}, ] [package.dependencies] @@ -1166,13 +1275,13 @@ tools = ["hypothesis (>=6.22.0,<6.108.7)"] [[package]] name = "eth-account" -version = "0.13.5" +version = "0.13.7" description = "eth-account: Sign Ethereum transactions and messages with local private keys" optional = false python-versions = "<4,>=3.8" files = [ - {file = "eth_account-0.13.5-py3-none-any.whl", hash = "sha256:e43fd30c9a7fabb882b50e8c4c41d4486d2f3478ad97c66bb18cfcc872fdbec8"}, - {file = "eth_account-0.13.5.tar.gz", hash = "sha256:010c9ce5f3d2688106cf9bfeb711bb8eaf0154ea6f85325f54fecea85c2b3759"}, + {file = "eth_account-0.13.7-py3-none-any.whl", hash = "sha256:39727de8c94d004ff61d10da7587509c04d2dc7eac71e04830135300bdfc6d24"}, + {file = "eth_account-0.13.7.tar.gz", hash = "sha256:5853ecbcbb22e65411176f121f5f24b8afeeaf13492359d254b16d8b18c77a46"}, ] [package.dependencies] @@ -1194,20 +1303,20 @@ test = ["coverage", "hypothesis (>=6.22.0,<6.108.7)", "pytest (>=7.0.0)", "pytes [[package]] name = "eth-hash" -version = "0.7.1" +version = "0.8.0" description = "eth-hash: The Ethereum hashing function, keccak256, sometimes (erroneously) called sha3" optional = false -python-versions = "<4,>=3.8" +python-versions = "<4,>=3.10" files = [ - {file = "eth_hash-0.7.1-py3-none-any.whl", hash = "sha256:0fb1add2adf99ef28883fd6228eb447ef519ea72933535ad1a0b28c6f65f868a"}, - {file = "eth_hash-0.7.1.tar.gz", hash = "sha256:d2411a403a0b0a62e8247b4117932d900ffb4c8c64b15f92620547ca5ce46be5"}, + {file = "eth_hash-0.8.0-py3-none-any.whl", hash = "sha256:523718a51b369ab89866b929a5c93c52978cd866ea309192ad980dd8271f9fac"}, + {file = "eth_hash-0.8.0.tar.gz", hash = "sha256:b009752b620da2e9c7668014849d1f5fadbe4f138603f1871cc5d4ca706896b1"}, ] [package.dependencies] pycryptodome = {version = ">=3.6.6,<4", optional = true, markers = "extra == \"pycryptodome\""} [package.extras] -dev = ["build (>=0.9.0)", "bump_my_version (>=0.19.0)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)", "tox (>=4.0.0)", "twine", "wheel"] +dev = ["build (>=0.9.0)", "bump_my_version (>=0.19.0)", "ipython", "mypy (==1.18.2)", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)", "tox (>=4.0.0)", "twine", "wheel (>=0.38.1)"] docs = ["sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)"] pycryptodome = ["pycryptodome (>=3.6.6,<4)"] pysha3 = ["pysha3 (>=1.0.0,<2.0.0)", "safe-pysha3 (>=1.0.0)"] @@ -1236,13 +1345,13 @@ test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] [[package]] name = "eth-keys" -version = "0.6.1" +version = "0.7.0" description = "eth-keys: Common API for Ethereum key operations" optional = false python-versions = "<4,>=3.8" files = [ - {file = "eth_keys-0.6.1-py3-none-any.whl", hash = "sha256:7deae4cd56e862e099ec58b78176232b931c4ea5ecded2f50c7b1ccbc10c24cf"}, - {file = "eth_keys-0.6.1.tar.gz", hash = "sha256:a43e263cbcabfd62fa769168efc6c27b1f5603040e4de22bb84d12567e4fd962"}, + {file = "eth_keys-0.7.0-py3-none-any.whl", hash = "sha256:b0cdda8ffe8e5ba69c7c5ca33f153828edcace844f67aabd4542d7de38b159cf"}, + {file = "eth_keys-0.7.0.tar.gz", hash = "sha256:79d24fd876201df67741de3e3fefb3f4dbcbb6ace66e47e6fe662851a4547814"}, ] [package.dependencies] @@ -1250,8 +1359,8 @@ eth-typing = ">=3" eth-utils = ">=2" [package.extras] -coincurve = ["coincurve (>=12.0.0)"] -dev = ["asn1tools (>=0.146.2)", "build (>=0.9.0)", "bump_my_version (>=0.19.0)", "coincurve (>=12.0.0)", "eth-hash[pysha3]", "factory-boy (>=3.0.1)", "hypothesis (>=5.10.3)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "pyasn1 (>=0.4.5)", "pytest (>=7.0.0)", "towncrier (>=24,<25)", "tox (>=4.0.0)", "twine", "wheel"] +coincurve = ["coincurve (>=17.0.0)"] +dev = ["asn1tools (>=0.146.2)", "build (>=0.9.0)", "bump_my_version (>=0.19.0)", "coincurve (>=17.0.0)", "eth-hash[pysha3]", "factory-boy (>=3.0.1)", "hypothesis (>=5.10.3)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "pyasn1 (>=0.4.5)", "pytest (>=7.0.0)", "towncrier (>=24,<25)", "tox (>=4.0.0)", "twine", "wheel"] docs = ["towncrier (>=24,<25)"] test = ["asn1tools (>=0.146.2)", "eth-hash[pysha3]", "factory-boy (>=3.0.1)", "hypothesis (>=5.10.3)", "pyasn1 (>=0.4.5)", "pytest (>=7.0.0)"] @@ -1279,100 +1388,140 @@ test = ["eth-hash[pycryptodome]", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] [[package]] name = "eth-typing" -version = "5.2.0" +version = "6.0.0" description = "eth-typing: Common type annotations for ethereum python packages" optional = false -python-versions = "<4,>=3.8" +python-versions = "<4,>=3.10" files = [ - {file = "eth_typing-5.2.0-py3-none-any.whl", hash = "sha256:e1f424e97990fc3c6a1c05a7b0968caed4e20e9c99a4d5f4db3df418e25ddc80"}, - {file = "eth_typing-5.2.0.tar.gz", hash = "sha256:28685f7e2270ea0d209b75bdef76d8ecef27703e1a16399f6929820d05071c28"}, + {file = "eth_typing-6.0.0-py3-none-any.whl", hash = "sha256:ee74fb641eb36dd885e1c42c2a3055314efa532b3e71480816df70a94d35cfb9"}, + {file = "eth_typing-6.0.0.tar.gz", hash = "sha256:315dd460dc0b71c15a6cd51e3c0b70d237eec8771beb844144f3a1fb4adb2392"}, ] [package.dependencies] typing_extensions = ">=4.5.0" [package.extras] -dev = ["build (>=0.9.0)", "bump_my_version (>=0.19.0)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)", "tox (>=4.0.0)", "twine", "wheel"] +dev = ["build (>=0.9.0)", "bump_my_version (>=0.19.0)", "ipython", "mypy (==1.18.2)", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)", "tox (>=4.0.0)", "twine", "wheel (>=0.38.1)"] docs = ["sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)"] test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] [[package]] name = "eth-utils" -version = "5.2.0" +version = "6.0.0" description = "eth-utils: Common utility functions for python code that interacts with Ethereum" optional = false -python-versions = "<4,>=3.8" +python-versions = "<4,>=3.10" files = [ - {file = "eth_utils-5.2.0-py3-none-any.whl", hash = "sha256:4d43eeb6720e89a042ad5b28d4b2111630ae764f444b85cbafb708d7f076da10"}, - {file = "eth_utils-5.2.0.tar.gz", hash = "sha256:17e474eb654df6e18f20797b22c6caabb77415a996b3ba0f3cc8df3437463134"}, + {file = "eth_utils-6.0.0-py3-none-any.whl", hash = "sha256:63cf48ee32c45541cb5748751909a8345c470432fb6f0fed4bd7c53fd6400469"}, + {file = "eth_utils-6.0.0.tar.gz", hash = "sha256:eb54b2f82dd300d3142c49a89da195e823f5e5284d43203593f87c67bad92a96"}, ] [package.dependencies] cytoolz = {version = ">=0.10.1", markers = "implementation_name == \"cpython\""} eth-hash = ">=0.3.1" eth-typing = ">=5.0.0" +pydantic = ">=2.0.0,<3" toolz = {version = ">0.8.2", markers = "implementation_name == \"pypy\""} [package.extras] -dev = ["build (>=0.9.0)", "bump-my-version (>=0.19.0)", "eth-hash[pycryptodome]", "hypothesis (>=4.43.0)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=24,<25)", "tox (>=4.0.0)", "twine", "wheel"] -docs = ["sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=24,<25)"] -test = ["hypothesis (>=4.43.0)", "mypy (==1.10.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] +dev = ["build (>=0.9.0)", "bump_my_version (>=0.19.0)", "eth-hash[pycryptodome]", "hypothesis (>=4.43.0)", "ipython", "mypy (==1.18.2)", "mypy (==1.18.2)", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)", "tox (>=4.0.0)", "twine", "wheel (>=0.38.1)"] +docs = ["sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)"] +test = ["hypothesis (>=4.43.0)", "mypy (==1.18.2)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] [[package]] name = "exceptiongroup" -version = "1.2.0" +version = "1.3.1" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, - {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, + {file = "exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598"}, + {file = "exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219"}, ] +[package.dependencies] +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} + [package.extras] test = ["pytest (>=6)"] [[package]] name = "fastapi" -version = "0.115.4" +version = "0.136.3" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "fastapi-0.115.4-py3-none-any.whl", hash = "sha256:0b504a063ffb3cf96a5e27dc1bc32c80ca743a2528574f9cdc77daa2d31b4742"}, - {file = "fastapi-0.115.4.tar.gz", hash = "sha256:db653475586b091cb8b2fec2ac54a680ac6a158e07406e1abae31679e8826349"}, + {file = "fastapi-0.136.3-py3-none-any.whl", hash = "sha256:3d2a69bdf04b7e9f3afa292c3bc7a98816bbfafa10bc9b45f3f3700d2f761620"}, + {file = "fastapi-0.136.3.tar.gz", hash = "sha256:e487fae93ad408e6f47641ee4dfe389864fd7bec92e547ea8498fc13f43e83ab"}, ] [package.dependencies] +annotated-doc = ">=0.0.2" email-validator = {version = ">=2.0.0", optional = true, markers = "extra == \"standard\""} -fastapi-cli = {version = ">=0.0.5", extras = ["standard"], optional = true, markers = "extra == \"standard\""} -httpx = {version = ">=0.23.0", optional = true, markers = "extra == \"standard\""} -jinja2 = {version = ">=2.11.2", optional = true, markers = "extra == \"standard\""} -pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" -python-multipart = {version = ">=0.0.7", optional = true, markers = "extra == \"standard\""} -starlette = ">=0.40.0,<0.42.0" +fastapi-cli = {version = ">=0.0.8", extras = ["standard"], optional = true, markers = "extra == \"standard\""} +fastar = {version = ">=0.9.0", optional = true, markers = "extra == \"standard\""} +httpx = {version = ">=0.23.0,<1.0.0", optional = true, markers = "extra == \"standard\""} +jinja2 = {version = ">=3.1.5", optional = true, markers = "extra == \"standard\""} +pydantic = ">=2.9.0" +pydantic-extra-types = {version = ">=2.0.0", optional = true, markers = "extra == \"standard\""} +pydantic-settings = {version = ">=2.0.0", optional = true, markers = "extra == \"standard\""} +python-multipart = {version = ">=0.0.18", optional = true, markers = "extra == \"standard\""} +starlette = ">=0.46.0" typing-extensions = ">=4.8.0" +typing-inspection = ">=0.4.2" uvicorn = {version = ">=0.12.0", extras = ["standard"], optional = true, markers = "extra == \"standard\""} [package.extras] -all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] -standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "jinja2 (>=2.11.2)", "python-multipart (>=0.0.7)", "uvicorn[standard] (>=0.12.0)"] +all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=3.1.5)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "pyyaml (>=5.3.1)", "uvicorn[standard] (>=0.12.0)"] +standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "fastar (>=0.9.0)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"] +standard-no-fastapi-cloud-cli = ["email-validator (>=2.0.0)", "fastapi-cli[standard-no-fastapi-cloud-cli] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"] [[package]] name = "fastapi-cli" -version = "0.0.5" +version = "0.0.32" description = "Run and manage FastAPI apps from the command line with FastAPI CLI. 🚀" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "fastapi_cli-0.0.5-py3-none-any.whl", hash = "sha256:e94d847524648c748a5350673546bbf9bcaeb086b33c24f2e82e021436866a46"}, - {file = "fastapi_cli-0.0.5.tar.gz", hash = "sha256:d30e1239c6f46fcb95e606f02cdda59a1e2fa778a54b64686b3ff27f6211ff9f"}, + {file = "fastapi_cli-0.0.32-py3-none-any.whl", hash = "sha256:8dcc286fa32f01bbd3f65dd09cfd5a2540ed5f2230b77db7fd30978d6165f3c4"}, + {file = "fastapi_cli-0.0.32.tar.gz", hash = "sha256:38024d2345275e1b37ce8848727a580d84901b570e96b3256d9d36a9a5039424"}, ] [package.dependencies] -typer = ">=0.12.3" +fastapi-cloud-cli = {version = ">=0.1.1", optional = true, markers = "extra == \"standard\""} +rich-toolkit = ">=0.14.8" +tomli = {version = ">=2.0.0", markers = "python_version < \"3.11\""} +typer = ">=0.16.0" uvicorn = {version = ">=0.15.0", extras = ["standard"]} +[package.extras] +new = ["fastapi-new (>=0.0.2)"] +standard = ["fastapi-cloud-cli (>=0.1.1)", "uvicorn[standard] (>=0.15.0)"] +standard-no-fastapi-cloud-cli = ["uvicorn[standard] (>=0.15.0)"] + +[[package]] +name = "fastapi-cloud-cli" +version = "0.22.2" +description = "Deploy and manage FastAPI Cloud apps from the command line 🚀" +optional = false +python-versions = ">=3.10" +files = [ + {file = "fastapi_cloud_cli-0.22.2-py3-none-any.whl", hash = "sha256:37c6b05adb94a4c9f59916a559d041c565db36b5f3dddeed420bf0a51182c363"}, + {file = "fastapi_cloud_cli-0.22.2.tar.gz", hash = "sha256:7ec78c1fed58f578af5eb1fb54ec4b456eba4dc1eaca1c3a93cf499a7cbc7ab3"}, +] + +[package.dependencies] +detect-installer = ">=0.1.0" +fastar = ">=0.10.0" +httpx = ">=0.27.0" +pydantic = {version = ">=2.7.4", extras = ["email"], markers = "python_version < \"3.13\""} +rich-toolkit = ">=0.20.3" +rignore = ">=0.5.1" +sentry-sdk = ">=2.20.0" +typer = ">=0.16.0" +uvicorn = {version = ">=0.17.6", extras = ["standard"]} + [package.extras] standard = ["uvicorn[standard] (>=0.15.0)"] @@ -1413,661 +1562,910 @@ redis = ">=4.2.0rc1" [[package]] name = "fastapi-pagination" -version = "0.12.27" +version = "0.15.15" description = "FastAPI pagination" optional = false -python-versions = "<4.0,>=3.8" +python-versions = ">=3.10" files = [ - {file = "fastapi_pagination-0.12.27-py3-none-any.whl", hash = "sha256:b239d449a878cbd5d2d4939871f8f1c328bfe8ec67779475c628ce4416b1812d"}, - {file = "fastapi_pagination-0.12.27.tar.gz", hash = "sha256:3f9ad8dba85a4e784de55145e934e06b9c5bcdc8e49ad00efa0515d962cd8696"}, + {file = "fastapi_pagination-0.15.15-py3-none-any.whl", hash = "sha256:dc828d7cd15614c650c284bd2c3a98a8a2d9ce340508be3970dc8986908a02aa"}, + {file = "fastapi_pagination-0.15.15.tar.gz", hash = "sha256:d6e9e4bc4d6e20709dcabc11b16056cd5cd184c995ee214b0190f6b81426fa0c"}, ] [package.dependencies] +fastapi = ">=0.93.0" pydantic = ">=1.9.1" -typing-extensions = ">=4.8.0,<5.0.0" +typing-extensions = ">=4.8.0" [package.extras] -all = ["SQLAlchemy (>=1.3.20)", "asyncpg (>=0.24.0)", "beanie (>=1.25.0)", "bunnet (>=1.1.0,<2.0.0)", "databases (>=0.6.0)", "django (<5.0.0)", "mongoengine (>=0.23.1,<0.30.0)", "motor (>=2.5.1,<4.0.0)", "orm (>=0.3.1)", "ormar (>=0.11.2)", "piccolo (>=0.89,<0.122)", "pony (>=0.7.16,<0.8.0)", "scylla-driver (>=3.25.6,<4.0.0)", "sqlakeyset (>=2.0.1680321678,<3.0.0)", "sqlmodel (>=0.0.8,<0.0.15)", "tortoise-orm (>=0.16.18,!=0.21.0,<0.22.0)"] -asyncpg = ["SQLAlchemy (>=1.3.20)", "asyncpg (>=0.24.0)"] -beanie = ["beanie (>=1.25.0)"] -bunnet = ["bunnet (>=1.1.0,<2.0.0)"] +aiosqlite = ["aiosqlite (>=0.19.0,!=0.22.0,!=0.22.1)"] +asyncpg = ["asyncpg (>=0.24.0)", "sqlalchemy (>=1.3.20)"] +beanie = ["beanie (>=2.1.0)"] +bunnet = ["bunnet (>=1.1.0)"] databases = ["databases (>=0.6.0)"] -django = ["databases (>=0.6.0)", "django (<5.0.0)"] -mongoengine = ["mongoengine (>=0.23.1,<0.30.0)"] -motor = ["motor (>=2.5.1,<4.0.0)"] +django = ["databases (>=0.6.0)", "django (<6.0.0)"] +elasticsearch = ["elasticsearch-dsl (>=8.13.0)"] +firestore = ["google-cloud-firestore (>=2.19.0)"] +mongoengine = ["mongoengine (>=0.23.1)"] +motor = ["motor (>=3.6.0)"] +odmantic = ["odmantic (>=1.0.2)"] orm = ["databases (>=0.6.0)", "orm (>=0.3.1)"] -ormar = ["ormar (>=0.11.2)"] -piccolo = ["piccolo (>=0.89,<0.122)"] -scylla-driver = ["scylla-driver (>=3.25.6,<4.0.0)"] -sqlalchemy = ["SQLAlchemy (>=1.3.20)", "sqlakeyset (>=2.0.1680321678,<3.0.0)"] -sqlmodel = ["sqlakeyset (>=2.0.1680321678,<3.0.0)", "sqlmodel (>=0.0.8,<0.0.15)"] -tortoise = ["tortoise-orm (>=0.16.18,!=0.21.0,<0.22.0)"] +ormar = ["ormar (>=0.21.0)"] +peewee = ["aiosqlite (>=0.19.0,!=0.22.0,!=0.22.1)", "greenlet", "peewee (>=4.0)"] +peewee-sync = ["peewee (>=4.0)"] +piccolo = ["piccolo (>=0.89)"] +psycopg = ["psycopg[binary] (>=3.3.2)"] +scylla-driver = ["scylla-driver (>=3.25.6)"] +sqlalchemy = ["sqlakeyset (>=2.0.1680321678)", "sqlalchemy (>=1.3.20)"] +sqlmodel = ["sqlakeyset (>=2.0.1680321678)", "sqlmodel (>=0.0.22)"] +tortoise = ["tortoise-orm (>=0.22.0)"] [[package]] -name = "filelock" -version = "3.13.1" -description = "A platform independent file lock." +name = "fastar" +version = "0.11.0" +description = "High-level bindings for the Rust tar crate" optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, - {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, + {file = "fastar-0.11.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:e7c906ad371ca365591ebcb7630009923f3eceb20956814494d15591a78e9e46"}, + {file = "fastar-0.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6919497b35fa5bd978d2c26ee117cf1771b90ee5073f7518e44b9bc364b57715"}, + {file = "fastar-0.11.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:56b50206aeedd99e22b83289e6fb3ff8f7d7da4407d2419902e4716b4f90585a"}, + {file = "fastar-0.11.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a1811a69ae81d469720df0c8af3f84f834a93b5e4f8be0e0e8bde6a52fa11f2"}, + {file = "fastar-0.11.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:10486238c55589a3947c38f9cfb88a67d8a608eb8dddc722038237d0278a41d7"}, + {file = "fastar-0.11.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1555ef9992d368a6ec39092276990cef8d329c39a1d86ebd847eaa3b10efd472"}, + {file = "fastar-0.11.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b1f4aca0a9620b76988bbf6225cdea6678a392902444ca18bb8a51495b165a89"}, + {file = "fastar-0.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75beeecac7d11a666a6c4a0b7f7e80842ae5cf523f2f890b99c78fc82b403545"}, + {file = "fastar-0.11.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:a08cdf5d16daa401c65c9c7493a18db7dc515c52155a17071ec7098bb07da9d3"}, + {file = "fastar-0.11.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6e210375e5a7ba53586cbd6017aa417d2d2ceacbe8671682470281bd0a15e8ef"}, + {file = "fastar-0.11.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a2988eb2604b8e15670f355425e8c800e4dcd4edfbcbfe194397f8f17b7eb19e"}, + {file = "fastar-0.11.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:34abc857b46068fdf91d157bd0203bfd6791dc7a432d1ed180f5af6c2f5bcce9"}, + {file = "fastar-0.11.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0d884be84e37a01053776395441fc960031974e0265801ce574efc3d05e0cdaf"}, + {file = "fastar-0.11.0-cp310-cp310-win32.whl", hash = "sha256:c721c1ad758e3e4c2c1fd9e96911a0fa58c0a6be5668f1bcfd0b741e72c7cb63"}, + {file = "fastar-0.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:ba4180b7c3080f55f9035fdd7d8c39fe0e1485087a68ff615bb4784a10b8106b"}, + {file = "fastar-0.11.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b82fd6f996e65a86f67a6bd64dd22ef3e8ae2dcaed0ae3b550e71f7e1bbb1df5"}, + {file = "fastar-0.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27eed386fd0558e6daa29211111bbd7b740f7c7e881197f8a00ac7c0f3cdb1d7"}, + {file = "fastar-0.11.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a6931bebc1d8e95ddeef55732c195449e6b44ef33aa31b325505097ed3b4d6aa"}, + {file = "fastar-0.11.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:891f72ce42a5e28a74fbd4d5fbf1a3ac1a1163d13cbc200cbd005fb0fabc54bd"}, + {file = "fastar-0.11.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5b83c1f61f7017d6e1498568038f8745440cfc16ca2f697ec81bac83050108f6"}, + {file = "fastar-0.11.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db73a9b765a516e73983b25341e7b5e0189733878279e278b2295131b0e3a21e"}, + {file = "fastar-0.11.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:625827d52eb4e8fec942e0233f125ff8010fcf6a67c0a974a8e5f4666b771e3c"}, + {file = "fastar-0.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7f5fd8fa21ec0a88296a38dc5d7fc35efd3b26d46a17b8b7c73c5563925ca15"}, + {file = "fastar-0.11.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:8c15af91b8cd87ddf23ea55355ae513c1de3ab67178f26dad017c9e9c0af6096"}, + {file = "fastar-0.11.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:03a112395a8b0bff251423bd1564c012f0cc058ad8b6bd8fba96f3d7fc117e44"}, + {file = "fastar-0.11.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f2994bb8f5f8c11eb12beae1e6e77a907173c9819236b8a4c8f0573652ceccce"}, + {file = "fastar-0.11.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:dcf99e4b5973d842c7f19c776c3a83cdc0977d505edce6206438505c0456b517"}, + {file = "fastar-0.11.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:29c9c386dc0d5dda78845a8e6b1480d26ab861c1e0b68f42ae5735cb70ca07f1"}, + {file = "fastar-0.11.0-cp311-cp311-win32.whl", hash = "sha256:030b2580fc394f2c9b7890b6735810404e9b9ed5e0344db150b945965b5482b7"}, + {file = "fastar-0.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:83ab57ae067969cd0b483ac3b6dccc4b595fc77f5c820760998648d4c42822b5"}, + {file = "fastar-0.11.0-cp311-cp311-win_arm64.whl", hash = "sha256:27b1a4cee2298b704de8151d310462ee7335ed036011ca9aa6e784b30b6c73a9"}, + {file = "fastar-0.11.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3c51f1c2cdddbd1420d2897ace7738e36c65e17f6ae84e0bfe763f8d1068bb97"}, + {file = "fastar-0.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0d9d6b052baf5380baea866675dab6ccd04ec2460d12b1c46f10ce3f4ee6a820"}, + {file = "fastar-0.11.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:bd2f05666d4df7e14885b5c38fefd92a785917387513d33d837ff42ec143a22f"}, + {file = "fastar-0.11.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1e6e74aba1ae77ca4aedcaf1697cd413319f4c88a5ccbe5b42c709517c5097e"}, + {file = "fastar-0.11.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:38ef77fe940bbc9b37a98bd838727f844b11731cd39358a2640ff864fb385086"}, + {file = "fastar-0.11.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8955e61b32d6aff82c983217abf80933fd823b0e727586fc72f08043d996fd59"}, + {file = "fastar-0.11.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:483532442cdb08fbff0169510224eae0836f2f672cea6aacb52847d90fefdc46"}, + {file = "fastar-0.11.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef5a6071121e05d8287fc75bccb054bcbac8bb0501200a0c0a8feeace5303ea4"}, + {file = "fastar-0.11.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:e45e598af5afe8412197d4786efd6cf29be02e7d3d4f6a3461149eae5d7e94f1"}, + {file = "fastar-0.11.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2e160919b1c47ddb8538e7e8eb4cd527281b40f0bf75110a75993838ef61f286"}, + {file = "fastar-0.11.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:4bb4dc0fc8f7a6807febcebce8a2f3626ba4955a9263d81ecc630aad83be84c0"}, + {file = "fastar-0.11.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4ec95af56aa173f6e320e1183001bf108ba59beaf13edd1fc8200648db203588"}, + {file = "fastar-0.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:136cf342735464091c39dc3708168f9fdeb9ebea40b1ead937c61afaf46143d9"}, + {file = "fastar-0.11.0-cp312-cp312-win32.whl", hash = "sha256:35f23c11b556cc4d3704587faacbc0037f7bdf6c4525cd1d09c70bda4b1c6809"}, + {file = "fastar-0.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:920bc56c3c0b8a8ca492904941d1883c1c947c858cd93343356c29122a38f44c"}, + {file = "fastar-0.11.0-cp312-cp312-win_arm64.whl", hash = "sha256:395248faf89e8a6bd5dc1fd544c8465113b627cb6d7c8b296796b60ebea33593"}, + {file = "fastar-0.11.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:33f544b08b4541b678e53749b4552a44720d96761fb79c172b005b1089c443ed"}, + {file = "fastar-0.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:91c1c792447e4a642745f347ff9847c52af39633071c57ee67ed53c157fc3506"}, + {file = "fastar-0.11.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:881247e6b6eaea59fc6569f9b61447aa6b9fc2ee864e048b4643d69c52745805"}, + {file = "fastar-0.11.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:863b7929845c9fec92ef6c8d59579cf46af5136655e5342f8df5cebe46cab06c"}, + {file = "fastar-0.11.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:96b4a57df12bf3211662627a3ea29d62ecb314a2434a0d0843f9fc23e47536e5"}, + {file = "fastar-0.11.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ceef1c2c4df7b7b8ebd3f5d718bbf457b9bbdf25ce0bd07870211ec4fbd9aff4"}, + {file = "fastar-0.11.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8e545918441910a779659d4759ad0eef349e935fbdb4668a666d3681567eb05"}, + {file = "fastar-0.11.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28095bb8f821e85fc2764e1a55f03e5e2876dee2abe7cd0ee9420d929905d643"}, + {file = "fastar-0.11.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0fafb95ecbe70f666a5e9b35dd63974ccdc9bb3d99ccdbd4014a823ec3e659b5"}, + {file = "fastar-0.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:af48fed039b94016629dcdad1c95c90c486326dd068de2b0a4df419ee09b6821"}, + {file = "fastar-0.11.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:74cd96163f39b8638ab4e8d49708ca887959672a22871d8170d01f067319533b"}, + {file = "fastar-0.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4e8b993cb5613bab495ed482810bedc0986633fcb9a3b55c37ec88e0d6714f6a"}, + {file = "fastar-0.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dfe39d91fc28e37e06162d94afe01050220edb7df554acb5b702b5503e564816"}, + {file = "fastar-0.11.0-cp313-cp313-win32.whl", hash = "sha256:c5f63d4d99ff4bfb37c659982ec413358bdee747005348756cc50a04d412d989"}, + {file = "fastar-0.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:8690ed1928d31ded3ada308e1086525fb3871f5fa81e1b69601a3f7774004583"}, + {file = "fastar-0.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:d977ded9d98a0719a305e0a4d5ee811f1d3e856d853a50acb8ae833c3cd6d5d2"}, + {file = "fastar-0.11.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:71375bd6f03c2a43eb47bd949ea38ff45434917f9cdac79675c5b9f60de4fa73"}, + {file = "fastar-0.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:eddfd9cab16e19ae247fe44bf992cb403ccfe27d3931d6de29a4695d95ad386c"}, + {file = "fastar-0.11.0-cp314-cp314-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:7c371f1d4386c699018bb64eb2fa785feacf32785559049d2bb72fe4af023f53"}, + {file = "fastar-0.11.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cad7fa41e3e66554387481c1a09365e4638becd322904932674159d5f4046728"}, + {file = "fastar-0.11.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cf36652fa71b83761717c9899b98732498f8a2cb6327ff16bbf07f6be85c3437"}, + {file = "fastar-0.11.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f68ff8c17833053da4841720e95edde80ce45bb994b6b7d51418dddaac70ee47"}, + {file = "fastar-0.11.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4563ed37a12ea1cdc398af8571258d24b988bf342b7b3bf5451bd5891243280c"}, + {file = "fastar-0.11.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cee63c9875cba3b70dc44338c560facc5d6e763047dcc4a30501f9a68cf5f890"}, + {file = "fastar-0.11.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:bd76bfffae6d0a91f4ac4a612f721e7aec108db97dccdd120ae063cd66959f27"}, + {file = "fastar-0.11.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8f5b707501ec01c1bc0518f741f01d322e50c9adc19a451aa24f67a2316e9397"}, + {file = "fastar-0.11.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:37c0b5a88a657839aad98b0a6c9e4ac4c2c15d6b49c44ee3935c6b08e9d3e479"}, + {file = "fastar-0.11.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:6c55f536c62a6efb180c1af0d5182948bff576bbfe6276e8e1359c9c7d2215d8"}, + {file = "fastar-0.11.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3082eeca59e189b9039335862f4c2780c0c8871d656bfdf559db4414a105b251"}, + {file = "fastar-0.11.0-cp314-cp314-win32.whl", hash = "sha256:b201a0a4e29f9fec2a177e13154b8725ec65ab9f83bd6415483efaa2aa18344b"}, + {file = "fastar-0.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:868fddb26072a43e870a8819134b9f80ee602931be5a76e6fb873e04da343637"}, + {file = "fastar-0.11.0-cp314-cp314-win_arm64.whl", hash = "sha256:3db39c9cc42abb0c780a26b299f24dfbc8be455985e969e15336d70d7b2f833b"}, + {file = "fastar-0.11.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:49c3299dec5e125e7ebaa27545714da9c7391777366015427e0ae62d548b442b"}, + {file = "fastar-0.11.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3328ed1ed56d31f5198350b17dd60449b8d6b9d47abb4688bab6aef4450a165b"}, + {file = "fastar-0.11.0-cp314-cp314t-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:bd3eca3bbfec84a614bcb4143b4ad4f784d0895babc26cfc88436af88ca23c7a"}, + {file = "fastar-0.11.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff86a967acb0d621dd24063dda090daa67bf4993b9570e97fe156de88a9006ca"}, + {file = "fastar-0.11.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:86eaf7c0e985d93a7734168be2fb232b2a8cca53e41431c2782d7c12b12c03b1"}, + {file = "fastar-0.11.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91f07b0b8eb67e2f177733a1f884edad7dfb9f8977ffef15927b20cb9604027d"}, + {file = "fastar-0.11.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f85c896885eb4abf1a635d54dea22cac6ae48d04fc2ea26ae652fcf1febe1220"}, + {file = "fastar-0.11.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:075c07095c8de4b774ba8f28b9c0a02b1a2cd254da50cbe464dd3bb2432e9158"}, + {file = "fastar-0.11.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:07f028933820c65750baf3383b807ecce1cd9385cf00ce192b79d263ad6b856c"}, + {file = "fastar-0.11.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:039f875efa0f01fa43c20bf4e2fc7305489c61d0ac76eda991acfba7820a0e63"}, + {file = "fastar-0.11.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:fff12452a9a5c6814a012445f26365541cc3d99dcca61f09762e6a389f7a32ea"}, + {file = "fastar-0.11.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:2bf733e09f942b6fa876efe30a90508d1f4caef5630c00fb2a84fba355873712"}, + {file = "fastar-0.11.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d1531fa848fdd3677d2dce0a4b436ea64d9ae38fb8babe2ddbc180dd153cb7a3"}, + {file = "fastar-0.11.0-cp314-cp314t-win32.whl", hash = "sha256:5744551bc67c6fc6581cbd0e34a0fd6e2cd0bd30b43e94b1c3119cf35064b162"}, + {file = "fastar-0.11.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f4ce44e3b56c47cf38244b98d29f269b259740a580c47a2552efa5b96a5458fb"}, + {file = "fastar-0.11.0-cp314-cp314t-win_arm64.whl", hash = "sha256:76c1359314355eafbc6989f20fb1ad565a3d10200117923b9da765a17e2f6f11"}, + {file = "fastar-0.11.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:a2cbcd0dde5548a8b2fc37a24b4bd957daf168973e63ba6dd1cbc2279964631d"}, + {file = "fastar-0.11.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f7d361813a881fef5ab97945ae89ebda7f6fa5ef74ee75871047f88bb2eac471"}, + {file = "fastar-0.11.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6dac5916958156c067ee0f678b4af9a1918aeca80d3c9ac0f81a2dc7a9af0451"}, + {file = "fastar-0.11.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:207b01117a770c0720415c19a43177cc701d458db411f0a8e1c9003138121a9d"}, + {file = "fastar-0.11.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:096f52102b5401b2f60fdca6f417f9b2fae146c644846eda123fe42cbd392178"}, + {file = "fastar-0.11.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:492487d8d2209b71f5f768644a30fced192acf32af287c9ee219a6331ad08097"}, + {file = "fastar-0.11.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d20fbd0fae43453de998027b13646e3376e59077ef7e2c9fbde4e9d65a951e91"}, + {file = "fastar-0.11.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:353db755d840bb2ce4c54d3f889c4d4e17680a9c18e676ff558b45943d4af1bf"}, + {file = "fastar-0.11.0-cp38-cp38-manylinux_2_31_riscv64.whl", hash = "sha256:0881f68bead037eb2bb0e7832ba8bb3b014c67a9fcc1a085dd81f968c611c9da"}, + {file = "fastar-0.11.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:65b38e1a47e6f15585ecb02d7bec27d4cbf1b39d4e030a4159bfee32d275deeb"}, + {file = "fastar-0.11.0-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:9c6157c5df39f3283cfa0f1d0c466ce2cc9375a66d8d451eab5786574a7baa55"}, + {file = "fastar-0.11.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:a84b8d5457b9d378912fb9220548e8a816f35ec952decdc8df8bd5bdb1b28c66"}, + {file = "fastar-0.11.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aab189c0ff354bc246ea540187901daf8527a71e83c9a506a512e693c4bb68ad"}, + {file = "fastar-0.11.0-cp38-cp38-win32.whl", hash = "sha256:2f3da9d75b9aa2e936d410a81eef5303f3d97356748d7079545c32a23837292f"}, + {file = "fastar-0.11.0-cp38-cp38-win_amd64.whl", hash = "sha256:9d0bbd6a34eedd44aa72e7cd7fd9828b4e35fe212e4524a45299288544527991"}, + {file = "fastar-0.11.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:6ced901e08b81514d141b8820857d51be4b0cc881a58edc555fff21ce3b16d8e"}, + {file = "fastar-0.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9277b377ac7dce7d927baf8460ac59248769cd3f5099b547b329b8ecaf2ed3ae"}, + {file = "fastar-0.11.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cb0009f9dd263261be455f8f2a38c0814370ab4febb90adf33e6dc54740438f6"}, + {file = "fastar-0.11.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec9de5c99c01de7be04e332a57dda9dceb98f4b2424c5bea4d4b899732483219"}, + {file = "fastar-0.11.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:628073cfc782f383ef2fa3ce2598fff9ff344d74d7d1e8dd5cff31b7675be1e7"}, + {file = "fastar-0.11.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50194636d86af5317f8a3b4a7cfbb45c14efe2045c7a099b6760785470a57bc9"}, + {file = "fastar-0.11.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88f665ac38c976146fa1f87a9151e6ff3a3e7d423a52e88ab35e9d49da2f4b2f"}, + {file = "fastar-0.11.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78ee04e4b6f94a42b889040ab310f446fc477fd0e71ec3592c1d0e5446f24737"}, + {file = "fastar-0.11.0-cp39-cp39-manylinux_2_31_riscv64.whl", hash = "sha256:9177d62f253b3fa2f4304ffaddab5fc3063c13e2fd481c032631437a2850f99f"}, + {file = "fastar-0.11.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a5b4399806d77e5172b1a37a0a7954e220f84e388cdbfbf80bd1de90fed70aa4"}, + {file = "fastar-0.11.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:e74cbb513f32a5b4499d49fb7a436713cb7a66a3498b002ec1de933650afb447"}, + {file = "fastar-0.11.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:d95530421ef5ea46d37c38509932c52a5862480515f599f5b0eb2e951d04de1b"}, + {file = "fastar-0.11.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2ef4691d57ce8f55e4696235fa98cf86f3f00916e4571838ad2041d1334d6cb0"}, + {file = "fastar-0.11.0-cp39-cp39-win32.whl", hash = "sha256:f3a3dc706fd59fb3566f34597656bdfdabecb563fbefdc41441a85b431fe96cf"}, + {file = "fastar-0.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:1a08582519c2564ecb2d034f1be7a73ceb309c4891d01f4d19ce712c72420fa5"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1266d6a004f427b0d61bd6c7b544d84cc964691b2232c2f4d635a1b75f2f6d5e"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:298a827ec04ade43733f6ca960d0faec38706aa1494175869ea7ea17f5bad5d3"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8800e2387e463a0e5799416a1cbe72dd0fde7270a20e4bde684145e7878f6516"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7496def0a2befd82d429cb004ef7ca831585cc887947bd6b9abb68a5ef852b0b"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:878eaf15463eb572e3538af7ca3a8534e5e279cf8196db902d24e5725c4af86e"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0324ed1d1ef0186e1bbd843b17807d6d837d0906899d4c99378b02c5d86bdd9c"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bdf9bd863205590beaf8ef6e66f315310196632180dceaf674985d01a876cac3"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59af8dbb683b24b90fb5b506de080faeab0a17a908e6c2a5d93a97260ed75d7b"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:9f3df73a3c4292cfe15696cdf59cdb6c309ab59d30b34c733be13c6e32d9a264"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:aa3762cbb16e41a76b61f4a6914937a71aab3a7b6c2d82ca233bc686ebaf756b"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:a8c7bc8ac74cb359bb546b199288c83236372d094b402e557c197e85527495cd"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:587cbd060a2699c5f66281081395bb4657b2b1e0eef5c206b1aabf740019d670"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6a1c56957ac82408be37a3f63594bc83e0919e8760492a4475e542f9f1828778"}, + {file = "fastar-0.11.0.tar.gz", hash = "sha256:aa7f100f7313c03fdb20f1385927ba95671071ba308ad0c1763fef295e1895ce"}, ] -[package.extras] -docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] -typing = ["typing-extensions (>=4.8)"] +[[package]] +name = "filelock" +version = "3.30.2" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.10" +files = [ + {file = "filelock-3.30.2-py3-none-any.whl", hash = "sha256:a64b58f75048ec39589983e97f5117163f822261dcb6ba843e098f05aac9663f"}, + {file = "filelock-3.30.2.tar.gz", hash = "sha256:1ea7c857465c897a4a6e64c1aace28ff6b83f5bc66c1c06ea148efa65bc2ec5d"}, +] [[package]] name = "fonttools" -version = "4.47.2" +version = "4.63.0" description = "Tools to manipulate font files" optional = false -python-versions = ">=3.8" -files = [ - {file = "fonttools-4.47.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3b629108351d25512d4ea1a8393a2dba325b7b7d7308116b605ea3f8e1be88df"}, - {file = "fonttools-4.47.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c19044256c44fe299d9a73456aabee4b4d06c6b930287be93b533b4737d70aa1"}, - {file = "fonttools-4.47.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8be28c036b9f186e8c7eaf8a11b42373e7e4949f9e9f370202b9da4c4c3f56c"}, - {file = "fonttools-4.47.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f83a4daef6d2a202acb9bf572958f91cfde5b10c8ee7fb1d09a4c81e5d851fd8"}, - {file = "fonttools-4.47.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4a5a5318ba5365d992666ac4fe35365f93004109d18858a3e18ae46f67907670"}, - {file = "fonttools-4.47.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8f57ecd742545362a0f7186774b2d1c53423ed9ece67689c93a1055b236f638c"}, - {file = "fonttools-4.47.2-cp310-cp310-win32.whl", hash = "sha256:a1c154bb85dc9a4cf145250c88d112d88eb414bad81d4cb524d06258dea1bdc0"}, - {file = "fonttools-4.47.2-cp310-cp310-win_amd64.whl", hash = "sha256:3e2b95dce2ead58fb12524d0ca7d63a63459dd489e7e5838c3cd53557f8933e1"}, - {file = "fonttools-4.47.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:29495d6d109cdbabe73cfb6f419ce67080c3ef9ea1e08d5750240fd4b0c4763b"}, - {file = "fonttools-4.47.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0a1d313a415eaaba2b35d6cd33536560deeebd2ed758b9bfb89ab5d97dc5deac"}, - {file = "fonttools-4.47.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90f898cdd67f52f18049250a6474185ef6544c91f27a7bee70d87d77a8daf89c"}, - {file = "fonttools-4.47.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3480eeb52770ff75140fe7d9a2ec33fb67b07efea0ab5129c7e0c6a639c40c70"}, - {file = "fonttools-4.47.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0255dbc128fee75fb9be364806b940ed450dd6838672a150d501ee86523ac61e"}, - {file = "fonttools-4.47.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f791446ff297fd5f1e2247c188de53c1bfb9dd7f0549eba55b73a3c2087a2703"}, - {file = "fonttools-4.47.2-cp311-cp311-win32.whl", hash = "sha256:740947906590a878a4bde7dd748e85fefa4d470a268b964748403b3ab2aeed6c"}, - {file = "fonttools-4.47.2-cp311-cp311-win_amd64.whl", hash = "sha256:63fbed184979f09a65aa9c88b395ca539c94287ba3a364517698462e13e457c9"}, - {file = "fonttools-4.47.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4ec558c543609e71b2275c4894e93493f65d2f41c15fe1d089080c1d0bb4d635"}, - {file = "fonttools-4.47.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e040f905d542362e07e72e03612a6270c33d38281fd573160e1003e43718d68d"}, - {file = "fonttools-4.47.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6dd58cc03016b281bd2c74c84cdaa6bd3ce54c5a7f47478b7657b930ac3ed8eb"}, - {file = "fonttools-4.47.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32ab2e9702dff0dd4510c7bb958f265a8d3dd5c0e2547e7b5f7a3df4979abb07"}, - {file = "fonttools-4.47.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3a808f3c1d1df1f5bf39be869b6e0c263570cdafb5bdb2df66087733f566ea71"}, - {file = "fonttools-4.47.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ac71e2e201df041a2891067dc36256755b1229ae167edbdc419b16da78732c2f"}, - {file = "fonttools-4.47.2-cp312-cp312-win32.whl", hash = "sha256:69731e8bea0578b3c28fdb43dbf95b9386e2d49a399e9a4ad736b8e479b08085"}, - {file = "fonttools-4.47.2-cp312-cp312-win_amd64.whl", hash = "sha256:b3e1304e5f19ca861d86a72218ecce68f391646d85c851742d265787f55457a4"}, - {file = "fonttools-4.47.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:254d9a6f7be00212bf0c3159e0a420eb19c63793b2c05e049eb337f3023c5ecc"}, - {file = "fonttools-4.47.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eabae77a07c41ae0b35184894202305c3ad211a93b2eb53837c2a1143c8bc952"}, - {file = "fonttools-4.47.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a86a5ab2873ed2575d0fcdf1828143cfc6b977ac448e3dc616bb1e3d20efbafa"}, - {file = "fonttools-4.47.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13819db8445a0cec8c3ff5f243af6418ab19175072a9a92f6cc8ca7d1452754b"}, - {file = "fonttools-4.47.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4e743935139aa485fe3253fc33fe467eab6ea42583fa681223ea3f1a93dd01e6"}, - {file = "fonttools-4.47.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d49ce3ea7b7173faebc5664872243b40cf88814ca3eb135c4a3cdff66af71946"}, - {file = "fonttools-4.47.2-cp38-cp38-win32.whl", hash = "sha256:94208ea750e3f96e267f394d5588579bb64cc628e321dbb1d4243ffbc291b18b"}, - {file = "fonttools-4.47.2-cp38-cp38-win_amd64.whl", hash = "sha256:0f750037e02beb8b3569fbff701a572e62a685d2a0e840d75816592280e5feae"}, - {file = "fonttools-4.47.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3d71606c9321f6701642bd4746f99b6089e53d7e9817fc6b964e90d9c5f0ecc6"}, - {file = "fonttools-4.47.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:86e0427864c6c91cf77f16d1fb9bf1bbf7453e824589e8fb8461b6ee1144f506"}, - {file = "fonttools-4.47.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a00bd0e68e88987dcc047ea31c26d40a3c61185153b03457956a87e39d43c37"}, - {file = "fonttools-4.47.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5d77479fb885ef38a16a253a2f4096bc3d14e63a56d6246bfdb56365a12b20c"}, - {file = "fonttools-4.47.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5465df494f20a7d01712b072ae3ee9ad2887004701b95cb2cc6dcb9c2c97a899"}, - {file = "fonttools-4.47.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4c811d3c73b6abac275babb8aa439206288f56fdb2c6f8835e3d7b70de8937a7"}, - {file = "fonttools-4.47.2-cp39-cp39-win32.whl", hash = "sha256:5b60e3afa9635e3dfd3ace2757039593e3bd3cf128be0ddb7a1ff4ac45fa5a50"}, - {file = "fonttools-4.47.2-cp39-cp39-win_amd64.whl", hash = "sha256:7ee48bd9d6b7e8f66866c9090807e3a4a56cf43ffad48962725a190e0dd774c8"}, - {file = "fonttools-4.47.2-py3-none-any.whl", hash = "sha256:7eb7ad665258fba68fd22228a09f347469d95a97fb88198e133595947a20a184"}, - {file = "fonttools-4.47.2.tar.gz", hash = "sha256:7df26dd3650e98ca45f1e29883c96a0b9f5bb6af8d632a6a108bc744fa0bd9b3"}, +python-versions = ">=3.10" +files = [ + {file = "fonttools-4.63.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e3297a6a4059b4acc3a1e9a8b04741f240a80044eef08ebd32e8b5bcdddce75b"}, + {file = "fonttools-4.63.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b1cd75a03ad8cb5bc40c90bfde68c0c47de423aa19e5c0f362b43520645eea94"}, + {file = "fonttools-4.63.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0425b277a59cff3d80ca42162a8de360f318438a2ac83570842a678d826d579"}, + {file = "fonttools-4.63.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d7e5c9973aa04c95650c96e5f5ad865fbf42d62079163ecfab1e01cbc2504c22"}, + {file = "fonttools-4.63.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cb014d58140a38135f16064c74c652ed57aa0b75cbf8bb59cac821f7edb5334e"}, + {file = "fonttools-4.63.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:032038247a96c1690f9f31e377c389383c902531b085aa4e4dabd6f57f870e69"}, + {file = "fonttools-4.63.0-cp310-cp310-win32.whl", hash = "sha256:a8b33a82979e0a6a34ff435cc81317be1f95ec1ebb7a3a2d1c8a6a54f02ae44e"}, + {file = "fonttools-4.63.0-cp310-cp310-win_amd64.whl", hash = "sha256:0c18358a155d75034911c5ee397a5b44cd19dd325dbb8b35fb60bf421d6a72ac"}, + {file = "fonttools-4.63.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2b8ae05d9eacf6081414d759c0a352769ac28ce31280d6bb8e77b03f9e3c449f"}, + {file = "fonttools-4.63.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:79cdc9f567aec74a72918fd060283911406750cbc9fd28c1316023deb6ce31a9"}, + {file = "fonttools-4.63.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c14b4fd138c4bafcca294765c547914e1aa431ae1ca94ab99d8db08c958bd3b"}, + {file = "fonttools-4.63.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d76ac49f929aecaf82d83250b8347e099d7aecba0f4726c1d9b6df3b8bb5fe18"}, + {file = "fonttools-4.63.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dcf076a4474fe0d7367e5bbf5b052c7284fa1feca729c04176ce513521afd8a0"}, + {file = "fonttools-4.63.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7dd683fef0663e9f0f45cf541d788d24caa3ec9db50796b588e1757d8b3bc007"}, + {file = "fonttools-4.63.0-cp311-cp311-win32.whl", hash = "sha256:afefc1ed0a59785a7fb06ea7e1678e849c193e1e387db783579bc7b3056fcfcb"}, + {file = "fonttools-4.63.0-cp311-cp311-win_amd64.whl", hash = "sha256:063e08bd17bd5a90127a14123de0d6a952dbc847695fd98b63c043d58057f90c"}, + {file = "fonttools-4.63.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:37dd23e621e3b0aef1baa70a303b80aaf38449632cfc8fd2a55fb285bbccfc02"}, + {file = "fonttools-4.63.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a9faff9e0c1f76f9fd55899d2ce785832efebab37eb8ae13995853aef178bef0"}, + {file = "fonttools-4.63.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef3048ef05dbb552b89817713d9cac912e00d0fde4a3105c00d29e52e10c89af"}, + {file = "fonttools-4.63.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:58dc6bb86a78d782f00f9190ca02c119cf5bbe2807536e361e18d42019f877d8"}, + {file = "fonttools-4.63.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ee08ebfa58f6e1aeff5697ab9582105bb620008c1caafb681e4c557e7483027b"}, + {file = "fonttools-4.63.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:27fdc65af8da6f88b9c6121c47a464cbe359fcfff7ff6fc2d37a1f395d755b78"}, + {file = "fonttools-4.63.0-cp312-cp312-win32.whl", hash = "sha256:af2fd1664d00a397d75f806985ddb36282091c2131a73a6485c23b4a34722263"}, + {file = "fonttools-4.63.0-cp312-cp312-win_amd64.whl", hash = "sha256:59ac449f8cca9b4ffa08d2e7bbadad87ce710d69d1eda5c3c1ce579baa987272"}, + {file = "fonttools-4.63.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:cd7e9857e5e63738b9d9fd707bc1f59c8b09e5177726d23664db393c59bb08bd"}, + {file = "fonttools-4.63.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c2a2a42198b696a6f48fad91709afb55176e66a5e566131219dba372fb7f8c59"}, + {file = "fonttools-4.63.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e874792a8212b44583ea02189d9e693906b2f78b261f372f95d6c563210ac1d"}, + {file = "fonttools-4.63.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22135da48a348785c5e2d5d2d9d6bec5ed44adacbaeb9db12d9493bf6c6bfa68"}, + {file = "fonttools-4.63.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ccf41f2efdf56994d22d73bef4ced1052161958169428d06ba9724ea9e9a64be"}, + {file = "fonttools-4.63.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9ced0bd02ac751dd6319b0da88aaef24414e3b0dbc32bb4f24944821a3741a27"}, + {file = "fonttools-4.63.0-cp313-cp313-win32.whl", hash = "sha256:85be818f5506e8a7753153def2c9550178f0ecae6a47b5e0e8dbb23f7cc90380"}, + {file = "fonttools-4.63.0-cp313-cp313-win_amd64.whl", hash = "sha256:ba04cb5891d4c0c21b6da95eda8d7b090021508a294fff33464fc7d241e0856b"}, + {file = "fonttools-4.63.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fd1e3094f42d806d3d7c79162fc59e5910fcbe3a7360c385b8da969bc4493745"}, + {file = "fonttools-4.63.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:6e528da43bc3791085f8cb6141b1d13e459226790240340fcbb4625649238b03"}, + {file = "fonttools-4.63.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b2248c5decb223562f7902ff6325077a073f608ee8e33e88ad88db734eb9f49"}, + {file = "fonttools-4.63.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:308f957cdeaf8abe4e5f2f124902ef405448af92c90f80e302a3b771c2e6116b"}, + {file = "fonttools-4.63.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bf00f21eb5fb721dbaf73d1e9da6d02a1af7768f2ebcf9798be98beab8ba90f6"}, + {file = "fonttools-4.63.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c1aaa4b9c75798400ac043ce04d74e7830376c85095a5a6ed7cba2f17a266bf4"}, + {file = "fonttools-4.63.0-cp314-cp314-win32.whl", hash = "sha256:22693918177bd9ceabec4736d338045f357769416fc6b0b2508eefef75b08616"}, + {file = "fonttools-4.63.0-cp314-cp314-win_amd64.whl", hash = "sha256:7d782fac32985914c351556f68ac0855391572bcd87de50e05970d3cd4c96fc5"}, + {file = "fonttools-4.63.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:6db5140a60a5d731d21ec076745b40a310607731b0a565b50776393188649001"}, + {file = "fonttools-4.63.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:7d76edbff9014094dbf03bd2d074709dfa6ec7aba13d838c937a2b33d2d6a86e"}, + {file = "fonttools-4.63.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0eac00b9118c3c2f87d272e45341871c5b3066baa3c86897fa634a7c3fb59096"}, + {file = "fonttools-4.63.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:51394295f1a51de8b5f30bdb1e1b9a4231536c7064ef5c6e211eec19fa36036f"}, + {file = "fonttools-4.63.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9e12f105d2b6342c559c298afb674006bb2893afc7102dcf8a1b55b0486b4e40"}, + {file = "fonttools-4.63.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:796f27556dbe094c4824f75ca85267e4df776c79036c8441469a4df37038c196"}, + {file = "fonttools-4.63.0-cp314-cp314t-win32.whl", hash = "sha256:948428a275741f0b64b113c955425a953314f4b9ab9997f73a72c83e68e569c8"}, + {file = "fonttools-4.63.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6d4741eb179121cab9eea4cb2393d24492373a260d7945006358c08cfbf45419"}, + {file = "fonttools-4.63.0-py3-none-any.whl", hash = "sha256:445af2eab030a16b9171ea8bdda7ebf7d96bda2df88ee182a464252f6e05e20d"}, + {file = "fonttools-4.63.0.tar.gz", hash = "sha256:caeb583deeb5168e694b65cda8b4ee62abedfa66cf88488734466f2366b9c4e0"}, ] [package.extras] -all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] +all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.45.0)", "unicodedata2 (>=17.0.0)", "xattr", "zopfli (>=0.1.4)"] graphite = ["lz4 (>=1.7.4.2)"] interpolatable = ["munkres", "pycairo", "scipy"] -lxml = ["lxml (>=4.0,<5)"] +lxml = ["lxml (>=4.0)"] pathops = ["skia-pathops (>=0.5.0)"] plot = ["matplotlib"] -repacker = ["uharfbuzz (>=0.23.0)"] +repacker = ["uharfbuzz (>=0.45.0)"] symfont = ["sympy"] type1 = ["xattr"] -ufo = ["fs (>=2.2.0,<3)"] -unicode = ["unicodedata2 (>=15.1.0)"] +unicode = ["unicodedata2 (>=17.0.0)"] woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] [[package]] name = "frozenlist" -version = "1.5.0" +version = "1.8.0" description = "A list-like structure which implements collections.abc.MutableSequence" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a"}, - {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb"}, - {file = "frozenlist-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:15538c0cbf0e4fa11d1e3a71f823524b0c46299aed6e10ebb4c2089abd8c3bec"}, - {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e79225373c317ff1e35f210dd5f1344ff31066ba8067c307ab60254cd3a78ad5"}, - {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9272fa73ca71266702c4c3e2d4a28553ea03418e591e377a03b8e3659d94fa76"}, - {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:498524025a5b8ba81695761d78c8dd7382ac0b052f34e66939c42df860b8ff17"}, - {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:92b5278ed9d50fe610185ecd23c55d8b307d75ca18e94c0e7de328089ac5dcba"}, - {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f3c8c1dacd037df16e85227bac13cca58c30da836c6f936ba1df0c05d046d8d"}, - {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2ac49a9bedb996086057b75bf93538240538c6d9b38e57c82d51f75a73409d2"}, - {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e66cc454f97053b79c2ab09c17fbe3c825ea6b4de20baf1be28919460dd7877f"}, - {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3ba5f9a0dfed20337d3e966dc359784c9f96503674c2faf015f7fe8e96798c"}, - {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6321899477db90bdeb9299ac3627a6a53c7399c8cd58d25da094007402b039ab"}, - {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76e4753701248476e6286f2ef492af900ea67d9706a0155335a40ea21bf3b2f5"}, - {file = "frozenlist-1.5.0-cp310-cp310-win32.whl", hash = "sha256:977701c081c0241d0955c9586ffdd9ce44f7a7795df39b9151cd9a6fd0ce4cfb"}, - {file = "frozenlist-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:189f03b53e64144f90990d29a27ec4f7997d91ed3d01b51fa39d2dbe77540fd4"}, - {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fd74520371c3c4175142d02a976aee0b4cb4a7cc912a60586ffd8d5929979b30"}, - {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2f3f7a0fbc219fb4455264cae4d9f01ad41ae6ee8524500f381de64ffaa077d5"}, - {file = "frozenlist-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f47c9c9028f55a04ac254346e92977bf0f166c483c74b4232bee19a6697e4778"}, - {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0996c66760924da6e88922756d99b47512a71cfd45215f3570bf1e0b694c206a"}, - {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2fe128eb4edeabe11896cb6af88fca5346059f6c8d807e3b910069f39157869"}, - {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a8ea951bbb6cacd492e3948b8da8c502a3f814f5d20935aae74b5df2b19cf3d"}, - {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de537c11e4aa01d37db0d403b57bd6f0546e71a82347a97c6a9f0dcc532b3a45"}, - {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c2623347b933fcb9095841f1cc5d4ff0b278addd743e0e966cb3d460278840d"}, - {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cee6798eaf8b1416ef6909b06f7dc04b60755206bddc599f52232606e18179d3"}, - {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f5f9da7f5dbc00a604fe74aa02ae7c98bcede8a3b8b9666f9f86fc13993bc71a"}, - {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:90646abbc7a5d5c7c19461d2e3eeb76eb0b204919e6ece342feb6032c9325ae9"}, - {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bdac3c7d9b705d253b2ce370fde941836a5f8b3c5c2b8fd70940a3ea3af7f4f2"}, - {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03d33c2ddbc1816237a67f66336616416e2bbb6beb306e5f890f2eb22b959cdf"}, - {file = "frozenlist-1.5.0-cp311-cp311-win32.whl", hash = "sha256:237f6b23ee0f44066219dae14c70ae38a63f0440ce6750f868ee08775073f942"}, - {file = "frozenlist-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:0cc974cc93d32c42e7b0f6cf242a6bd941c57c61b618e78b6c0a96cb72788c1d"}, - {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:31115ba75889723431aa9a4e77d5f398f5cf976eea3bdf61749731f62d4a4a21"}, - {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7437601c4d89d070eac8323f121fcf25f88674627505334654fd027b091db09d"}, - {file = "frozenlist-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7948140d9f8ece1745be806f2bfdf390127cf1a763b925c4a805c603df5e697e"}, - {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feeb64bc9bcc6b45c6311c9e9b99406660a9c05ca8a5b30d14a78555088b0b3a"}, - {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:683173d371daad49cffb8309779e886e59c2f369430ad28fe715f66d08d4ab1a"}, - {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7d57d8f702221405a9d9b40f9da8ac2e4a1a8b5285aac6100f3393675f0a85ee"}, - {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c72000fbcc35b129cb09956836c7d7abf78ab5416595e4857d1cae8d6251a6"}, - {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e"}, - {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5d7f5a50342475962eb18b740f3beecc685a15b52c91f7d975257e13e029eca9"}, - {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:87f724d055eb4785d9be84e9ebf0f24e392ddfad00b3fe036e43f489fafc9039"}, - {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6e9080bb2fb195a046e5177f10d9d82b8a204c0736a97a153c2466127de87784"}, - {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b93d7aaa36c966fa42efcaf716e6b3900438632a626fb09c049f6a2f09fc631"}, - {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f"}, - {file = "frozenlist-1.5.0-cp312-cp312-win32.whl", hash = "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8"}, - {file = "frozenlist-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f"}, - {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953"}, - {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0"}, - {file = "frozenlist-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2"}, - {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f"}, - {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608"}, - {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b"}, - {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840"}, - {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439"}, - {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de"}, - {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641"}, - {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e"}, - {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9"}, - {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03"}, - {file = "frozenlist-1.5.0-cp313-cp313-win32.whl", hash = "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c"}, - {file = "frozenlist-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28"}, - {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:dd94994fc91a6177bfaafd7d9fd951bc8689b0a98168aa26b5f543868548d3ca"}, - {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0da8bbec082bf6bf18345b180958775363588678f64998c2b7609e34719b10"}, - {file = "frozenlist-1.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:73f2e31ea8dd7df61a359b731716018c2be196e5bb3b74ddba107f694fbd7604"}, - {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:828afae9f17e6de596825cf4228ff28fbdf6065974e5ac1410cecc22f699d2b3"}, - {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1577515d35ed5649d52ab4319db757bb881ce3b2b796d7283e6634d99ace307"}, - {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2150cc6305a2c2ab33299453e2968611dacb970d2283a14955923062c8d00b10"}, - {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a72b7a6e3cd2725eff67cd64c8f13335ee18fc3c7befc05aed043d24c7b9ccb9"}, - {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c16d2fa63e0800723139137d667e1056bee1a1cf7965153d2d104b62855e9b99"}, - {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:17dcc32fc7bda7ce5875435003220a457bcfa34ab7924a49a1c19f55b6ee185c"}, - {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:97160e245ea33d8609cd2b8fd997c850b56db147a304a262abc2b3be021a9171"}, - {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f1e6540b7fa044eee0bb5111ada694cf3dc15f2b0347ca125ee9ca984d5e9e6e"}, - {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:91d6c171862df0a6c61479d9724f22efb6109111017c87567cfeb7b5d1449fdf"}, - {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c1fac3e2ace2eb1052e9f7c7db480818371134410e1f5c55d65e8f3ac6d1407e"}, - {file = "frozenlist-1.5.0-cp38-cp38-win32.whl", hash = "sha256:b97f7b575ab4a8af9b7bc1d2ef7f29d3afee2226bd03ca3875c16451ad5a7723"}, - {file = "frozenlist-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:374ca2dabdccad8e2a76d40b1d037f5bd16824933bf7bcea3e59c891fd4a0923"}, - {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9bbcdfaf4af7ce002694a4e10a0159d5a8d20056a12b05b45cea944a4953f972"}, - {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1893f948bf6681733aaccf36c5232c231e3b5166d607c5fa77773611df6dc336"}, - {file = "frozenlist-1.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2b5e23253bb709ef57a8e95e6ae48daa9ac5f265637529e4ce6b003a37b2621f"}, - {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f253985bb515ecd89629db13cb58d702035ecd8cfbca7d7a7e29a0e6d39af5f"}, - {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04a5c6babd5e8fb7d3c871dc8b321166b80e41b637c31a995ed844a6139942b6"}, - {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9fe0f1c29ba24ba6ff6abf688cb0b7cf1efab6b6aa6adc55441773c252f7411"}, - {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:226d72559fa19babe2ccd920273e767c96a49b9d3d38badd7c91a0fdeda8ea08"}, - {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15b731db116ab3aedec558573c1a5eec78822b32292fe4f2f0345b7f697745c2"}, - {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:366d8f93e3edfe5a918c874702f78faac300209a4d5bf38352b2c1bdc07a766d"}, - {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1b96af8c582b94d381a1c1f51ffaedeb77c821c690ea5f01da3d70a487dd0a9b"}, - {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:c03eff4a41bd4e38415cbed054bbaff4a075b093e2394b6915dca34a40d1e38b"}, - {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:50cf5e7ee9b98f22bdecbabf3800ae78ddcc26e4a435515fc72d97903e8488e0"}, - {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1e76bfbc72353269c44e0bc2cfe171900fbf7f722ad74c9a7b638052afe6a00c"}, - {file = "frozenlist-1.5.0-cp39-cp39-win32.whl", hash = "sha256:666534d15ba8f0fda3f53969117383d5dc021266b3c1a42c9ec4855e4b58b9d3"}, - {file = "frozenlist-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:5c28f4b5dbef8a0d8aad0d4de24d1e9e981728628afaf4ea0792f5d0939372f0"}, - {file = "frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3"}, - {file = "frozenlist-1.5.0.tar.gz", hash = "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817"}, -] - -[[package]] -name = "future" -version = "0.18.3" -description = "Clean single-source support for Python 3 and 2" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -files = [ - {file = "future-0.18.3.tar.gz", hash = "sha256:34a17436ed1e96697a86f9de3d15a3b0be01d8bc8de9c1dffd59fb8234ed5307"}, + {file = "frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011"}, + {file = "frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565"}, + {file = "frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7"}, + {file = "frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a"}, + {file = "frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6"}, + {file = "frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e"}, + {file = "frozenlist-1.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09474e9831bc2b2199fad6da3c14c7b0fbdd377cce9d3d77131be28906cb7d84"}, + {file = "frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17c883ab0ab67200b5f964d2b9ed6b00971917d5d8a92df149dc2c9779208ee9"}, + {file = "frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa47e444b8ba08fffd1c18e8cdb9a75db1b6a27f17507522834ad13ed5922b93"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2552f44204b744fba866e573be4c1f9048d6a324dfe14475103fd51613eb1d1f"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e7c38f250991e48a9a73e6423db1bb9dd14e722a10f6b8bb8e16a0f55f695"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8585e3bb2cdea02fc88ffa245069c36555557ad3609e83be0ec71f54fd4abb52"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edee74874ce20a373d62dc28b0b18b93f645633c2943fd90ee9d898550770581"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c9a63152fe95756b85f31186bddf42e4c02c6321207fd6601a1c89ebac4fe567"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6db2185db9be0a04fecf2f241c70b63b1a242e2805be291855078f2b404dd6b"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f4be2e3d8bc8aabd566f8d5b8ba7ecc09249d74ba3c9ed52e54dc23a293f0b92"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c8d1634419f39ea6f5c427ea2f90ca85126b54b50837f31497f3bf38266e853d"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a7fa382a4a223773ed64242dbe1c9c326ec09457e6b8428efb4118c685c3dfd"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:11847b53d722050808926e785df837353bd4d75f1d494377e59b23594d834967"}, + {file = "frozenlist-1.8.0-cp311-cp311-win32.whl", hash = "sha256:27c6e8077956cf73eadd514be8fb04d77fc946a7fe9f7fe167648b0b9085cc25"}, + {file = "frozenlist-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac913f8403b36a2c8610bbfd25b8013488533e71e62b4b4adce9c86c8cea905b"}, + {file = "frozenlist-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:d4d3214a0f8394edfa3e303136d0575eece0745ff2b47bd2cb2e66dd92d4351a"}, + {file = "frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1"}, + {file = "frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b"}, + {file = "frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa"}, + {file = "frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf"}, + {file = "frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746"}, + {file = "frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd"}, + {file = "frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a"}, + {file = "frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7"}, + {file = "frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed"}, + {file = "frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496"}, + {file = "frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231"}, + {file = "frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62"}, + {file = "frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94"}, + {file = "frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c"}, + {file = "frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41"}, + {file = "frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b"}, + {file = "frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888"}, + {file = "frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042"}, + {file = "frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0"}, + {file = "frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f"}, + {file = "frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7"}, + {file = "frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806"}, + {file = "frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0"}, + {file = "frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b"}, + {file = "frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d"}, + {file = "frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed"}, + {file = "frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e"}, + {file = "frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df"}, + {file = "frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd"}, + {file = "frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79"}, + {file = "frozenlist-1.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d8b7138e5cd0647e4523d6685b0eac5d4be9a184ae9634492f25c6eb38c12a47"}, + {file = "frozenlist-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a6483e309ca809f1efd154b4d37dc6d9f61037d6c6a81c2dc7a15cb22c8c5dca"}, + {file = "frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1b9290cf81e95e93fdf90548ce9d3c1211cf574b8e3f4b3b7cb0537cf2227068"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:59a6a5876ca59d1b63af8cd5e7ffffb024c3dc1e9cf9301b21a2e76286505c95"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6dc4126390929823e2d2d9dc79ab4046ed74680360fc5f38b585c12c66cdf459"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:332db6b2563333c5671fecacd085141b5800cb866be16d5e3eb15a2086476675"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9ff15928d62a0b80bb875655c39bf517938c7d589554cbd2669be42d97c2cb61"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7bf6cdf8e07c8151fba6fe85735441240ec7f619f935a5205953d58009aef8c6"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:48e6d3f4ec5c7273dfe83ff27c91083c6c9065af655dc2684d2c200c94308bb5"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:1a7607e17ad33361677adcd1443edf6f5da0ce5e5377b798fba20fae194825f3"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3a935c3a4e89c733303a2d5a7c257ea44af3a56c8202df486b7f5de40f37e1"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:940d4a017dbfed9daf46a3b086e1d2167e7012ee297fef9e1c545c4d022f5178"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b9be22a69a014bc47e78072d0ecae716f5eb56c15238acca0f43d6eb8e4a5bda"}, + {file = "frozenlist-1.8.0-cp39-cp39-win32.whl", hash = "sha256:1aa77cb5697069af47472e39612976ed05343ff2e84a3dcf15437b232cbfd087"}, + {file = "frozenlist-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:7398c222d1d405e796970320036b1b563892b65809d9e5261487bb2c7f7b5c6a"}, + {file = "frozenlist-1.8.0-cp39-cp39-win_arm64.whl", hash = "sha256:b4f3b365f31c6cd4af24545ca0a244a53688cad8834e32f56831c4923b50a103"}, + {file = "frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d"}, + {file = "frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad"}, ] [[package]] name = "google-api-core" -version = "2.17.1" +version = "2.32.0" description = "Google API client core library" optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" files = [ - {file = "google-api-core-2.17.1.tar.gz", hash = "sha256:9df18a1f87ee0df0bc4eea2770ebc4228392d8cc4066655b320e2cfccb15db95"}, - {file = "google_api_core-2.17.1-py3-none-any.whl", hash = "sha256:610c5b90092c360736baccf17bd3efbcb30dd380e7a6dc28a71059edb8bd0d8e"}, + {file = "google_api_core-2.32.0-py3-none-any.whl", hash = "sha256:ae1f0d58a6c8869350bf469f8eb3092e7f8c494a942d9525494afb6c162b0904"}, + {file = "google_api_core-2.32.0.tar.gz", hash = "sha256:2b33aad226b19272458c46abfe5c5a38d9531ece0c44502129a1463ce83674ac"}, ] [package.dependencies] -google-auth = ">=2.14.1,<3.0.dev0" -googleapis-common-protos = ">=1.56.2,<2.0.dev0" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0" -requests = ">=2.18.0,<3.0.0.dev0" +google-auth = ">=2.14.1,<3.0.0" +googleapis-common-protos = ">=1.63.2,<2.0.0" +proto-plus = ">=1.24.0,<2.0.0" +protobuf = ">=5.29.6,<8.0.0" +requests = ">=2.33.0,<3.0.0" [package.extras] -grpc = ["grpcio (>=1.33.2,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "grpcio-status (>=1.33.2,<2.0.dev0)", "grpcio-status (>=1.49.1,<2.0.dev0)"] -grpcgcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] -grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] +async-rest = ["aiohttp (>=3.13.4)", "google-auth[aiohttp] (>=2.14.1,<3.0.0)"] +grpc = ["grpcio (>=1.41.0,<2.0.0)", "grpcio (>=1.49.1,<2.0.0)", "grpcio (>=1.75.1,<2.0.0)", "grpcio-status (>=1.41.0,<2.0.0)", "grpcio-status (>=1.49.1,<2.0.0)", "grpcio-status (>=1.75.1,<2.0.0)"] [[package]] name = "google-auth" -version = "2.28.0" +version = "2.56.0" description = "Google Authentication Library" optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" files = [ - {file = "google-auth-2.28.0.tar.gz", hash = "sha256:3cfc1b6e4e64797584fb53fc9bd0b7afa9b7c0dba2004fa7dcc9349e58cc3195"}, - {file = "google_auth-2.28.0-py2.py3-none-any.whl", hash = "sha256:7634d29dcd1e101f5226a23cbc4a0c6cda6394253bf80e281d9c5c6797869c53"}, + {file = "google_auth-2.56.0-py3-none-any.whl", hash = "sha256:6e88c10217e07a92bfd01cac8ee99e32ccfb08414c3102e6c5b8d58f37a0d1e0"}, + {file = "google_auth-2.56.0.tar.gz", hash = "sha256:f90fa030b569a92654b9d690665a073841df33d57487be53db583a9a0867a553"}, ] [package.dependencies] -cachetools = ">=2.0.0,<6.0" +cryptography = {version = ">=38.0.3", markers = "python_version < \"3.14\""} pyasn1-modules = ">=0.2.1" -rsa = ">=3.1.4,<5" [package.extras] -aiohttp = ["aiohttp (>=3.6.2,<4.0.0.dev0)", "requests (>=2.20.0,<3.0.0.dev0)"] -enterprise-cert = ["cryptography (==36.0.2)", "pyopenssl (==22.0.0)"] -pyopenssl = ["cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] +aiohttp = ["aiohttp (>=3.8.0,<4.0.0)", "aiohttp (>=3.9.0,<4.0.0)", "requests (>=2.30.0,<3.0.0)"] +cryptography = ["cryptography (>=38.0.3)", "cryptography (>=41.0.5)"] +enterprise-cert = ["cryptography (>=38.0.3)", "cryptography (>=41.0.5)"] +grpc = ["grpcio (>=1.59.0,<2.0.0)", "grpcio (>=1.75.1,<2.0.0)"] +pyjwt = ["pyjwt (>=2.0)"] +pyopenssl = ["cryptography (>=38.0.3)", "cryptography (>=41.0.5)"] reauth = ["pyu2f (>=0.1.5)"] -requests = ["requests (>=2.20.0,<3.0.0.dev0)"] +requests = ["requests (>=2.30.0,<3.0.0)"] +rsa = ["rsa (>=4.0.0,<5)"] +testing = ["aiohttp (>=3.8.0,<4.0.0)", "aiohttp (>=3.9.0,<4.0.0)", "aioresponses", "flask", "freezegun", "grpcio (>=1.59.0,<2.0.0)", "grpcio (>=1.75.1,<2.0.0)", "packaging (>=20.0)", "pyjwt (>=2.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-localserver", "pyu2f (>=0.1.5)", "requests (>=2.30.0,<3.0.0)", "responses", "urllib3 (>=1.26.15,<3.0.0)"] +urllib3 = ["packaging (>=20.0)", "urllib3 (>=1.26.15,<3.0.0)"] [[package]] name = "google-cloud-core" -version = "2.4.1" +version = "2.6.0" description = "Google Cloud API client core library" optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" files = [ - {file = "google-cloud-core-2.4.1.tar.gz", hash = "sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073"}, - {file = "google_cloud_core-2.4.1-py2.py3-none-any.whl", hash = "sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61"}, + {file = "google_cloud_core-2.6.0-py3-none-any.whl", hash = "sha256:6d63ac8e5eca6d9e4319d0a1e2265fadcd7f1049904378caecfa01cf52dd869e"}, + {file = "google_cloud_core-2.6.0.tar.gz", hash = "sha256:e76149739f90fac1fc6757c09f47eaccb3145b54adbd7759b0f7c4b235f46c83"}, ] [package.dependencies] -google-api-core = ">=1.31.6,<2.0.dev0 || >2.3.0,<3.0.0dev" -google-auth = ">=1.25.0,<3.0dev" +google-api-core = ">=2.11.0,<3.0.0" +google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0" [package.extras] -grpc = ["grpcio (>=1.38.0,<2.0dev)", "grpcio-status (>=1.38.0,<2.0.dev0)"] +grpc = ["grpcio (>=1.47.0,<2.0.0)", "grpcio (>=1.75.1,<2.0.0)", "grpcio-status (>=1.47.0,<2.0.0)"] [[package]] name = "google-cloud-storage" -version = "2.14.0" +version = "2.19.0" description = "Google Cloud Storage API client library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-storage-2.14.0.tar.gz", hash = "sha256:2d23fcf59b55e7b45336729c148bb1c464468c69d5efbaee30f7201dd90eb97e"}, - {file = "google_cloud_storage-2.14.0-py2.py3-none-any.whl", hash = "sha256:8641243bbf2a2042c16a6399551fbb13f062cbc9a2de38d6c0bb5426962e9dbd"}, + {file = "google_cloud_storage-2.19.0-py2.py3-none-any.whl", hash = "sha256:aeb971b5c29cf8ab98445082cbfe7b161a1f48ed275822f59ed3f1524ea54fba"}, + {file = "google_cloud_storage-2.19.0.tar.gz", hash = "sha256:cd05e9e7191ba6cb68934d8eb76054d9be4562aa89dbc4236feee4d7d51342b2"}, ] [package.dependencies] -google-api-core = ">=1.31.5,<2.0.dev0 || >2.3.0,<3.0.0dev" -google-auth = ">=2.23.3,<3.0dev" +google-api-core = ">=2.15.0,<3.0.0dev" +google-auth = ">=2.26.1,<3.0dev" google-cloud-core = ">=2.3.0,<3.0dev" google-crc32c = ">=1.0,<2.0dev" -google-resumable-media = ">=2.6.0" +google-resumable-media = ">=2.7.2" requests = ">=2.18.0,<3.0.0dev" [package.extras] -protobuf = ["protobuf (<5.0.0dev)"] +protobuf = ["protobuf (<6.0.0dev)"] +tracing = ["opentelemetry-api (>=1.1.0)"] [[package]] name = "google-crc32c" -version = "1.5.0" +version = "1.8.0" description = "A python wrapper of the C library 'Google CRC32C'" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "google-crc32c-1.5.0.tar.gz", hash = "sha256:89284716bc6a5a415d4eaa11b1726d2d60a0cd12aadf5439828353662ede9dd7"}, - {file = "google_crc32c-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:596d1f98fc70232fcb6590c439f43b350cb762fb5d61ce7b0e9db4539654cc13"}, - {file = "google_crc32c-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:be82c3c8cfb15b30f36768797a640e800513793d6ae1724aaaafe5bf86f8f346"}, - {file = "google_crc32c-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:461665ff58895f508e2866824a47bdee72497b091c730071f2b7575d5762ab65"}, - {file = "google_crc32c-1.5.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2096eddb4e7c7bdae4bd69ad364e55e07b8316653234a56552d9c988bd2d61b"}, - {file = "google_crc32c-1.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:116a7c3c616dd14a3de8c64a965828b197e5f2d121fedd2f8c5585c547e87b02"}, - {file = "google_crc32c-1.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5829b792bf5822fd0a6f6eb34c5f81dd074f01d570ed7f36aa101d6fc7a0a6e4"}, - {file = "google_crc32c-1.5.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:64e52e2b3970bd891309c113b54cf0e4384762c934d5ae56e283f9a0afcd953e"}, - {file = "google_crc32c-1.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:02ebb8bf46c13e36998aeaad1de9b48f4caf545e91d14041270d9dca767b780c"}, - {file = "google_crc32c-1.5.0-cp310-cp310-win32.whl", hash = "sha256:2e920d506ec85eb4ba50cd4228c2bec05642894d4c73c59b3a2fe20346bd00ee"}, - {file = "google_crc32c-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:07eb3c611ce363c51a933bf6bd7f8e3878a51d124acfc89452a75120bc436289"}, - {file = "google_crc32c-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cae0274952c079886567f3f4f685bcaf5708f0a23a5f5216fdab71f81a6c0273"}, - {file = "google_crc32c-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1034d91442ead5a95b5aaef90dbfaca8633b0247d1e41621d1e9f9db88c36298"}, - {file = "google_crc32c-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c42c70cd1d362284289c6273adda4c6af8039a8ae12dc451dcd61cdabb8ab57"}, - {file = "google_crc32c-1.5.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8485b340a6a9e76c62a7dce3c98e5f102c9219f4cfbf896a00cf48caf078d438"}, - {file = "google_crc32c-1.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77e2fd3057c9d78e225fa0a2160f96b64a824de17840351b26825b0848022906"}, - {file = "google_crc32c-1.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f583edb943cf2e09c60441b910d6a20b4d9d626c75a36c8fcac01a6c96c01183"}, - {file = "google_crc32c-1.5.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:a1fd716e7a01f8e717490fbe2e431d2905ab8aa598b9b12f8d10abebb36b04dd"}, - {file = "google_crc32c-1.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:72218785ce41b9cfd2fc1d6a017dc1ff7acfc4c17d01053265c41a2c0cc39b8c"}, - {file = "google_crc32c-1.5.0-cp311-cp311-win32.whl", hash = "sha256:66741ef4ee08ea0b2cc3c86916ab66b6aef03768525627fd6a1b34968b4e3709"}, - {file = "google_crc32c-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:ba1eb1843304b1e5537e1fca632fa894d6f6deca8d6389636ee5b4797affb968"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:98cb4d057f285bd80d8778ebc4fde6b4d509ac3f331758fb1528b733215443ae"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd8536e902db7e365f49e7d9029283403974ccf29b13fc7028b97e2295b33556"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19e0a019d2c4dcc5e598cd4a4bc7b008546b0358bd322537c74ad47a5386884f"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02c65b9817512edc6a4ae7c7e987fea799d2e0ee40c53ec573a692bee24de876"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6ac08d24c1f16bd2bf5eca8eaf8304812f44af5cfe5062006ec676e7e1d50afc"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3359fc442a743e870f4588fcf5dcbc1bf929df1fad8fb9905cd94e5edb02e84c"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e986b206dae4476f41bcec1faa057851f3889503a70e1bdb2378d406223994a"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:de06adc872bcd8c2a4e0dc51250e9e65ef2ca91be023b9d13ebd67c2ba552e1e"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-win32.whl", hash = "sha256:d3515f198eaa2f0ed49f8819d5732d70698c3fa37384146079b3799b97667a94"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:67b741654b851abafb7bc625b6d1cdd520a379074e64b6a128e3b688c3c04740"}, - {file = "google_crc32c-1.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c02ec1c5856179f171e032a31d6f8bf84e5a75c45c33b2e20a3de353b266ebd8"}, - {file = "google_crc32c-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:edfedb64740750e1a3b16152620220f51d58ff1b4abceb339ca92e934775c27a"}, - {file = "google_crc32c-1.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84e6e8cd997930fc66d5bb4fde61e2b62ba19d62b7abd7a69920406f9ecca946"}, - {file = "google_crc32c-1.5.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:024894d9d3cfbc5943f8f230e23950cd4906b2fe004c72e29b209420a1e6b05a"}, - {file = "google_crc32c-1.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:998679bf62b7fb599d2878aa3ed06b9ce688b8974893e7223c60db155f26bd8d"}, - {file = "google_crc32c-1.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:83c681c526a3439b5cf94f7420471705bbf96262f49a6fe546a6db5f687a3d4a"}, - {file = "google_crc32c-1.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4c6fdd4fccbec90cc8a01fc00773fcd5fa28db683c116ee3cb35cd5da9ef6c37"}, - {file = "google_crc32c-1.5.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5ae44e10a8e3407dbe138984f21e536583f2bba1be9491239f942c2464ac0894"}, - {file = "google_crc32c-1.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:37933ec6e693e51a5b07505bd05de57eee12f3e8c32b07da7e73669398e6630a"}, - {file = "google_crc32c-1.5.0-cp38-cp38-win32.whl", hash = "sha256:fe70e325aa68fa4b5edf7d1a4b6f691eb04bbccac0ace68e34820d283b5f80d4"}, - {file = "google_crc32c-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:74dea7751d98034887dbd821b7aae3e1d36eda111d6ca36c206c44478035709c"}, - {file = "google_crc32c-1.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c6c777a480337ac14f38564ac88ae82d4cd238bf293f0a22295b66eb89ffced7"}, - {file = "google_crc32c-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:759ce4851a4bb15ecabae28f4d2e18983c244eddd767f560165563bf9aefbc8d"}, - {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f13cae8cc389a440def0c8c52057f37359014ccbc9dc1f0827936bcd367c6100"}, - {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e560628513ed34759456a416bf86b54b2476c59144a9138165c9a1575801d0d9"}, - {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1674e4307fa3024fc897ca774e9c7562c957af85df55efe2988ed9056dc4e57"}, - {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:278d2ed7c16cfc075c91378c4f47924c0625f5fc84b2d50d921b18b7975bd210"}, - {file = "google_crc32c-1.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d5280312b9af0976231f9e317c20e4a61cd2f9629b7bfea6a693d1878a264ebd"}, - {file = "google_crc32c-1.5.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8b87e1a59c38f275c0e3676fc2ab6d59eccecfd460be267ac360cc31f7bcde96"}, - {file = "google_crc32c-1.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7c074fece789b5034b9b1404a1f8208fc2d4c6ce9decdd16e8220c5a793e6f61"}, - {file = "google_crc32c-1.5.0-cp39-cp39-win32.whl", hash = "sha256:7f57f14606cd1dd0f0de396e1e53824c371e9544a822648cd76c034d209b559c"}, - {file = "google_crc32c-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:a2355cba1f4ad8b6988a4ca3feed5bff33f6af2d7f134852cf279c2aebfde541"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f314013e7dcd5cf45ab1945d92e713eec788166262ae8deb2cfacd53def27325"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b747a674c20a67343cb61d43fdd9207ce5da6a99f629c6e2541aa0e89215bcd"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8f24ed114432de109aa9fd317278518a5af2d31ac2ea6b952b2f7782b43da091"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8667b48e7a7ef66afba2c81e1094ef526388d35b873966d8a9a447974ed9178"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:1c7abdac90433b09bad6c43a43af253e688c9cfc1c86d332aed13f9a7c7f65e2"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6f998db4e71b645350b9ac28a2167e6632c239963ca9da411523bb439c5c514d"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c99616c853bb585301df6de07ca2cadad344fd1ada6d62bb30aec05219c45d2"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ad40e31093a4af319dadf503b2467ccdc8f67c72e4bcba97f8c10cb078207b5"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd67cf24a553339d5062eff51013780a00d6f97a39ca062781d06b3a73b15462"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:398af5e3ba9cf768787eef45c803ff9614cc3e22a5b2f7d7ae116df8b11e3314"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b1f8133c9a275df5613a451e73f36c2aea4fe13c5c8997e22cf355ebd7bd0728"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ba053c5f50430a3fcfd36f75aff9caeba0440b2d076afdb79a318d6ca245f88"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:272d3892a1e1a2dbc39cc5cde96834c236d5327e2122d3aaa19f6614531bb6eb"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:635f5d4dd18758a1fbd1049a8e8d2fee4ffed124462d837d1a02a0e009c3ab31"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c672d99a345849301784604bfeaeba4db0c7aae50b95be04dd651fd2a7310b93"}, + {file = "google_crc32c-1.8.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:0470b8c3d73b5f4e3300165498e4cf25221c7eb37f1159e221d1825b6df8a7ff"}, + {file = "google_crc32c-1.8.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:119fcd90c57c89f30040b47c211acee231b25a45d225e3225294386f5d258288"}, + {file = "google_crc32c-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6f35aaffc8ccd81ba3162443fabb920e65b1f20ab1952a31b13173a67811467d"}, + {file = "google_crc32c-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:864abafe7d6e2c4c66395c1eb0fe12dc891879769b52a3d56499612ca93b6092"}, + {file = "google_crc32c-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:db3fe8eaf0612fc8b20fa21a5f25bd785bc3cd5be69f8f3412b0ac2ffd49e733"}, + {file = "google_crc32c-1.8.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:014a7e68d623e9a4222d663931febc3033c5c7c9730785727de2a81f87d5bab8"}, + {file = "google_crc32c-1.8.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:86cfc00fe45a0ac7359e5214a1704e51a99e757d0272554874f419f79838c5f7"}, + {file = "google_crc32c-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:19b40d637a54cb71e0829179f6cb41835f0fbd9e8eb60552152a8b52c36cbe15"}, + {file = "google_crc32c-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:17446feb05abddc187e5441a45971b8394ea4c1b6efd88ab0af393fd9e0a156a"}, + {file = "google_crc32c-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:71734788a88f551fbd6a97be9668a0020698e07b2bf5b3aa26a36c10cdfb27b2"}, + {file = "google_crc32c-1.8.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:4b8286b659c1335172e39563ab0a768b8015e88e08329fa5321f774275fc3113"}, + {file = "google_crc32c-1.8.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:2a3dc3318507de089c5384cc74d54318401410f82aa65b2d9cdde9d297aca7cb"}, + {file = "google_crc32c-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:14f87e04d613dfa218d6135e81b78272c3b904e2a7053b841481b38a7d901411"}, + {file = "google_crc32c-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cb5c869c2923d56cb0c8e6bcdd73c009c36ae39b652dbe46a05eb4ef0ad01454"}, + {file = "google_crc32c-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:3cc0c8912038065eafa603b238abf252e204accab2a704c63b9e14837a854962"}, + {file = "google_crc32c-1.8.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:3ebb04528e83b2634857f43f9bb8ef5b2bbe7f10f140daeb01b58f972d04736b"}, + {file = "google_crc32c-1.8.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:450dc98429d3e33ed2926fc99ee81001928d63460f8538f21a5d6060912a8e27"}, + {file = "google_crc32c-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3b9776774b24ba76831609ffbabce8cdf6fa2bd5e9df37b594221c7e333a81fa"}, + {file = "google_crc32c-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:89c17d53d75562edfff86679244830599ee0a48efc216200691de8b02ab6b2b8"}, + {file = "google_crc32c-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:57a50a9035b75643996fbf224d6661e386c7162d1dfdab9bc4ca790947d1007f"}, + {file = "google_crc32c-1.8.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:e6584b12cb06796d285d09e33f63309a09368b9d806a551d8036a4207ea43697"}, + {file = "google_crc32c-1.8.0-cp314-cp314-macosx_12_0_x86_64.whl", hash = "sha256:f4b51844ef67d6cf2e9425983274da75f18b1597bb2c998e1c0a0e8d46f8f651"}, + {file = "google_crc32c-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b0d1a7afc6e8e4635564ba8aa5c0548e3173e41b6384d7711a9123165f582de2"}, + {file = "google_crc32c-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b3f68782f3cbd1bce027e48768293072813469af6a61a86f6bb4977a4380f21"}, + {file = "google_crc32c-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:d511b3153e7011a27ab6ee6bb3a5404a55b994dc1a7322c0b87b29606d9790e2"}, + {file = "google_crc32c-1.8.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:ba6aba18daf4d36ad4412feede6221414692f44d17e5428bdd81ad3fc1eee5dc"}, + {file = "google_crc32c-1.8.0-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:87b0072c4ecc9505cfa16ee734b00cd7721d20a0f595be4d40d3d21b41f65ae2"}, + {file = "google_crc32c-1.8.0-cp39-cp39-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3d488e98b18809f5e322978d4506373599c0c13e6c5ad13e53bb44758e18d215"}, + {file = "google_crc32c-1.8.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:01f126a5cfddc378290de52095e2c7052be2ba7656a9f0caf4bcd1bfb1833f8a"}, + {file = "google_crc32c-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:61f58b28e0b21fcb249a8247ad0db2e64114e201e2e9b4200af020f3b6242c9f"}, + {file = "google_crc32c-1.8.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:87fa445064e7db928226b2e6f0d5304ab4cd0339e664a4e9a25029f384d9bb93"}, + {file = "google_crc32c-1.8.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f639065ea2042d5c034bf258a9f085eaa7af0cd250667c0635a3118e8f92c69c"}, + {file = "google_crc32c-1.8.0.tar.gz", hash = "sha256:a428e25fb7691024de47fecfbff7ff957214da51eddded0da0ae0e0f03a2cf79"}, ] -[package.extras] -testing = ["pytest"] - [[package]] name = "google-resumable-media" -version = "2.7.0" +version = "2.10.0" description = "Utilities for Google Media Downloads and Resumable Uploads" optional = false -python-versions = ">= 3.7" +python-versions = ">=3.10" files = [ - {file = "google-resumable-media-2.7.0.tar.gz", hash = "sha256:5f18f5fa9836f4b083162064a1c2c98c17239bfda9ca50ad970ccf905f3e625b"}, - {file = "google_resumable_media-2.7.0-py2.py3-none-any.whl", hash = "sha256:79543cfe433b63fd81c0844b7803aba1bb8950b47bedf7d980c38fa123937e08"}, + {file = "google_resumable_media-2.10.0-py3-none-any.whl", hash = "sha256:88152884bee37b2bf36a0ab81ad8c7fd12212c9803dd981d77c1b35b02d34e7c"}, + {file = "google_resumable_media-2.10.0.tar.gz", hash = "sha256:e324bc9d0fdae4c52a08ae90456edc4e71ece858399e1217ac0eb3a51d6bc6ee"}, ] [package.dependencies] -google-crc32c = ">=1.0,<2.0dev" +google-crc32c = ">=1.0.0,<2.0.0" [package.extras] -aiohttp = ["aiohttp (>=3.6.2,<4.0.0dev)", "google-auth (>=1.22.0,<2.0dev)"] -requests = ["requests (>=2.18.0,<3.0.0dev)"] +aiohttp = ["aiohttp (>=3.6.2,<4.0.0)", "google-auth (>=1.22.0,<2.0.0)"] +requests = ["requests (>=2.18.0,<3.0.0)"] [[package]] name = "googleapis-common-protos" -version = "1.62.0" +version = "1.75.0" description = "Common protobufs used in Google APIs" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "googleapis-common-protos-1.62.0.tar.gz", hash = "sha256:83f0ece9f94e5672cced82f592d2a5edf527a96ed1794f0bab36d5735c996277"}, - {file = "googleapis_common_protos-1.62.0-py2.py3-none-any.whl", hash = "sha256:4750113612205514f9f6aa4cb00d523a94f3e8c06c5ad2fee466387dc4875f07"}, + {file = "googleapis_common_protos-1.75.0-py3-none-any.whl", hash = "sha256:961ed60399c457ceb0ee8f285a84c870aabc9c6a832b9d37bb281b5bebde43ed"}, + {file = "googleapis_common_protos-1.75.0.tar.gz", hash = "sha256:53a062ff3c32552fbd62c11fe23768b78e4ddf0494d5e5fd97d3f4689c75fbbd"}, ] [package.dependencies] -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0" +protobuf = ">=4.25.8,<8.0.0" [package.extras] -grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] +grpc = ["grpcio (>=1.44.0,<2.0.0)"] [[package]] name = "greenlet" -version = "3.0.3" +version = "3.5.3" description = "Lightweight in-process concurrent programming" optional = false -python-versions = ">=3.7" -files = [ - {file = "greenlet-3.0.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405"}, - {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f"}, - {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb"}, - {file = "greenlet-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9"}, - {file = "greenlet-3.0.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22"}, - {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3"}, - {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d"}, - {file = "greenlet-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728"}, - {file = "greenlet-3.0.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf"}, - {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305"}, - {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6"}, - {file = "greenlet-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2"}, - {file = "greenlet-3.0.3-cp37-cp37m-macosx_11_0_universal2.whl", hash = "sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41"}, - {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7"}, - {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6"}, - {file = "greenlet-3.0.3-cp37-cp37m-win32.whl", hash = "sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d"}, - {file = "greenlet-3.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67"}, - {file = "greenlet-3.0.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4"}, - {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5"}, - {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da"}, - {file = "greenlet-3.0.3-cp38-cp38-win32.whl", hash = "sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3"}, - {file = "greenlet-3.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf"}, - {file = "greenlet-3.0.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b"}, - {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6"}, - {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113"}, - {file = "greenlet-3.0.3-cp39-cp39-win32.whl", hash = "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e"}, - {file = "greenlet-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067"}, - {file = "greenlet-3.0.3.tar.gz", hash = "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491"}, +python-versions = ">=3.10" +files = [ + {file = "greenlet-3.5.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:c180d22d325fb613956b443c3c6f4406eb70e6defc70d3974da2a7b59e06f48c"}, + {file = "greenlet-3.5.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:483d08c11181c83a6ce1a7a61df0f624a208ec40817a3bb2302714592eee4f04"}, + {file = "greenlet-3.5.3-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1dae6e0091eae084317e411f047f0b7cb241c6db570f7c45fd6b900a274914ce"}, + {file = "greenlet-3.5.3-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0f6ff50ff8dbd51fae9b37f4101648b04ea0df19b3f50ab2beb5061e7716a5c8"}, + {file = "greenlet-3.5.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9bcd2d72ccd70a1ec68ba6ef93e7fbb4420ef9997dabc7010d893bd4015e0bec"}, + {file = "greenlet-3.5.3-cp310-cp310-manylinux_2_39_riscv64.whl", hash = "sha256:37bf9c538f5ae6e63d643f88dec37c0c83bdf0e2ebc62961dedcf458822f7b71"}, + {file = "greenlet-3.5.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:73f152c895e09907e0dbe24f6c2db37beb085cd63db91c3825a0fcd0064124a8"}, + {file = "greenlet-3.5.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8bdb43e1a1d1873721acab2be99c5befd4d2044ddfd52e4d610801019880a702"}, + {file = "greenlet-3.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:0909f9355a9f24845d3299f3112e266a06afb68302041989fd26bd68894933db"}, + {file = "greenlet-3.5.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:aca9b4ce85b152b5524ef7d88170efdff80dc0032aa8b75f9aaf7f3479ea95b4"}, + {file = "greenlet-3.5.3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f71be4920368fe1fabeeaa53d1e3548337e2b223d9565f8ad5e392a75ba23fc"}, + {file = "greenlet-3.5.3-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d77e67f65f98449e3fb83f795b5d0a8437aead2f874ca89c96576caf4be3af6"}, + {file = "greenlet-3.5.3-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e18619ba655ac05d78d80fc83cac4ba892bd6927b99e3b8237aee861aaacc8bb"}, + {file = "greenlet-3.5.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8540f1e6205bd13ca0ce685581037219ca54a1b41a0a15d228c6c9b8ad5903d7"}, + {file = "greenlet-3.5.3-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:d27c0c653a60d9535f690226474a5cc1036a8b0d7b57504d1c4f89c44a07a80c"}, + {file = "greenlet-3.5.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7ef56fe650f50575bf843acde967b9c567687f3c22340941a899b7bc56e956a8"}, + {file = "greenlet-3.5.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5121af01cf911e70056c00d4b46d5e9b5d1415550038573d744138bacb59e6b8"}, + {file = "greenlet-3.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:0f41e4a05a3c0cb31b17023eff28dd111e1d16bf7d7d00406cd7df23f31398a7"}, + {file = "greenlet-3.5.3-cp311-cp311-win_arm64.whl", hash = "sha256:ec6f1af59f6b5f3fc9678e2ea062d8377d22ac644f7844cb7a292910cf12ff44"}, + {file = "greenlet-3.5.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:719757059f5a53fd0dde23f78cffeafcdd97b21c850ddb7ca684a3c1a1f122e2"}, + {file = "greenlet-3.5.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:efa9f765dd09f9d0cdac651ffdf631ee59ec5dc6ee7a73e0c012ba9c52fbdf5b"}, + {file = "greenlet-3.5.3-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7faba15ac005376e02a0384504e0243be3370ce010296a44a820feb342b505ab"}, + {file = "greenlet-3.5.3-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5795cd1101371140551c645f2d408b8d3c01a5a29cf8a9bce6e759c983682d23"}, + {file = "greenlet-3.5.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:87142215824be6ac05e2e8e2786eec307ccbc27c36723c3881959df654af6861"}, + {file = "greenlet-3.5.3-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:af4923b3096e26a36d7e9cf24ab88083a20f97d191e3b97f253731ce9b41b28c"}, + {file = "greenlet-3.5.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:215275b1b49320987352e6c1b054acca0064f965a2c66992bed9a6f7d913f149"}, + {file = "greenlet-3.5.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6b1b0eed82364b0e32c4ea0f221452d33e6bb17ae094d9f72aed9851812747ea"}, + {file = "greenlet-3.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:cde8adafa2365676f74a979744629589999093bc86e2484214f58e61df08902c"}, + {file = "greenlet-3.5.3-cp312-cp312-win_arm64.whl", hash = "sha256:c4e7b79d83805475f0102008843f6eb45fd3bb0b2e88c774adab5fbaab27117d"}, + {file = "greenlet-3.5.3-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:c8d87c2134d871df96ecdea9cec7cbaab286dadab0f56476e57aaf9e8ac11550"}, + {file = "greenlet-3.5.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2d185dd1621757e70c3861cceffd5317ab4e7ed7eb09c82994828468527ade5"}, + {file = "greenlet-3.5.3-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1c514a468149bf8fbbab874188a3535cd8a48a3e353eb53a3d424296f8dbacd3"}, + {file = "greenlet-3.5.3-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9ad04dd75458c6300b047c61b8639092433d205a25a14e310d6582a480efcca1"}, + {file = "greenlet-3.5.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:915f887cf2682b66419b879423a2e072634aa7b7dce6f3ada4957cfced3f1e9a"}, + {file = "greenlet-3.5.3-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:afaabdd554cd7ae9bbb3ca070b0d7fdfd207dbf1d16865f7233837709d354bda"}, + {file = "greenlet-3.5.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:766cfd421c13e450feb340cd472a3ed9957d438727b7b4593ad7c76c5d2b0deb"}, + {file = "greenlet-3.5.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2ecda9ec22edf38fa389369eaed8c3d37c05f3c54e69f69438dbb2cc1de1458b"}, + {file = "greenlet-3.5.3-cp313-cp313-win_amd64.whl", hash = "sha256:c82304750f057167ff60d188df1d0cc1764ce9567eadf03e6a7443bcedd0b30b"}, + {file = "greenlet-3.5.3-cp313-cp313-win_arm64.whl", hash = "sha256:dc133a1569ee667b2a6ef56ce551084aeefd87a5acbc4736d336d1e2edc6cfc4"}, + {file = "greenlet-3.5.3-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:fd2e02fa07485778536a036222d616ab957b1d533f36b3ed98ce725d9c9d3117"}, + {file = "greenlet-3.5.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df0a0628d1597eb0897b62f55d1343f772405fd25f3b2a796c76874b0c2e22e8"}, + {file = "greenlet-3.5.3-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ebd933a6adabc298bab47731a130fe6bfb888bd934eee37810f151159544540d"}, + {file = "greenlet-3.5.3-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8d19fe6c39ebff9259f07bcc685d3290f8fa4ea2278e51dd0008e4d6b0f2d814"}, + {file = "greenlet-3.5.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4b9d501b40e80b70e32323c799dd9b420a5577a9601469d362ae1ffb690f3a7c"}, + {file = "greenlet-3.5.3-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:962c5df2db8cb446da51edf1ca5296c389d93b99c9d8aa2ee4c7d0d8f1218260"}, + {file = "greenlet-3.5.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a1fad1d11e7d6aab184107baa8e4ece11ccba3ec9599cd7efa5ff4d70d43256a"}, + {file = "greenlet-3.5.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:fad5aec764399f1b5cc347ad250a59660f20c8f8888ea6bae1f93b769cce1154"}, + {file = "greenlet-3.5.3-cp314-cp314-win_amd64.whl", hash = "sha256:7669aa24cf2a1041d6f7899575b494a3ab4cf68bfcc8609b1dc0be7272db835e"}, + {file = "greenlet-3.5.3-cp314-cp314-win_arm64.whl", hash = "sha256:5b4807c4082c9d1b6d9eed56fcd041863e37f2228106eef24c30ca096e238605"}, + {file = "greenlet-3.5.3-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:271a8ea7c1024e8a0d7dd2be66dd66dda8a07193f41a17b9e924f7600f5b62be"}, + {file = "greenlet-3.5.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:19131729ae0ddc3c2e1ef85e650169b5e37ee32e400f215f78b94d7b0d567310"}, + {file = "greenlet-3.5.3-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1540dd8e5fc2a5aec40fbb98ef8e149fa47c89a4b4a1cf2575a14d3d1869d7a8"}, + {file = "greenlet-3.5.3-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b897d97759425953f69a9c0fac67f8fe333ec0ce7377ef186fb2b0c3ad5e354d"}, + {file = "greenlet-3.5.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e81fa194a1d20967877bdf9c7794db2bc99063e5be36aee710c08f04c5bb087f"}, + {file = "greenlet-3.5.3-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:3236754d423955ea08e9bb5f6c04a7895f9e22c290b66aa7653fcb922d839eb0"}, + {file = "greenlet-3.5.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:55cf4d777485d43110e47133cbba6d74a8885a87ec1227ef0267f9ee80c5aa21"}, + {file = "greenlet-3.5.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:12a248ba75f6a9a236375f52296c498c89ff1d8badf32deb9eca7abd5853f7da"}, + {file = "greenlet-3.5.3-cp314-cp314t-win_amd64.whl", hash = "sha256:efc6bd60ea02e085862c74a3ef64b147ffc6f1a5ea7d9f26e7a939943f68c1e3"}, + {file = "greenlet-3.5.3-cp315-cp315-macosx_11_0_universal2.whl", hash = "sha256:ea03f2f04367845d6b58eeed276e1e56e51f0b97d8ad5a88a7d20a91dc9056cc"}, + {file = "greenlet-3.5.3-cp315-cp315-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78dbef602fda6d97d957eb7937f70c9ce9e9527330347f8f6b6f9e554a9e7a47"}, + {file = "greenlet-3.5.3-cp315-cp315-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f73857adb8fee13fa56c172bd11262f888c0c648f9fea113e777bb2c7904a81"}, + {file = "greenlet-3.5.3-cp315-cp315-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:cefa9cef4b371f9844c6053db71f1138bc6807bab1578b0dae5149c1f1141357"}, + {file = "greenlet-3.5.3-cp315-cp315-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:232fec92e823addaf02d9472cf7381e24a1d046a6ced1103c5caa4c21b9dfc1d"}, + {file = "greenlet-3.5.3-cp315-cp315-manylinux_2_39_riscv64.whl", hash = "sha256:6219b6d04dbf6ba6084d77dc609e8473060dc55f759cbf626d512122781fa128"}, + {file = "greenlet-3.5.3-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:2421c3564da9429d5586d46ca31ebb26516b5498a802cf65c041a8e8a8980d34"}, + {file = "greenlet-3.5.3-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:e0f0d160f0b2e558e6c75f7930967183255dc9735e5f5b8cae58ee09c9576d8b"}, + {file = "greenlet-3.5.3-cp315-cp315-win_amd64.whl", hash = "sha256:dd99329bbc15ca78dcc583dba05d0b1b0bae01ab6c2174989f5aaee3e41ac930"}, + {file = "greenlet-3.5.3-cp315-cp315-win_arm64.whl", hash = "sha256:499fef2acede88c1864a57bb586b4bf533c81e1b82df7ab93451cdb47dfec227"}, + {file = "greenlet-3.5.3-cp315-cp315t-macosx_11_0_universal2.whl", hash = "sha256:176bc16a721fa5fc294d70b87b4dfa5fbdd251b3da5d5372735ecef9bd7d6d0c"}, + {file = "greenlet-3.5.3-cp315-cp315t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:629b614d2b786e89c50440e246f33eea78f58a962d0bdbbcc809e6d13605903f"}, + {file = "greenlet-3.5.3-cp315-cp315t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2b2e857ae16f5f72142edf75f9f176fe7526ba19a2841df1420516f83831c9f2"}, + {file = "greenlet-3.5.3-cp315-cp315t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:16d192579ed281051396dddd7f7754dac6259e6b1fb26378c87b66622f8e3f91"}, + {file = "greenlet-3.5.3-cp315-cp315t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e515757e2e36bcbf1fad09a46e1557e8b1ae1797d4b44d09da7deed88ad28608"}, + {file = "greenlet-3.5.3-cp315-cp315t-manylinux_2_39_riscv64.whl", hash = "sha256:4399eb8d041f20b68d943918bc55502a93d6fdc0a37c14da7881c04139acee9d"}, + {file = "greenlet-3.5.3-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:b363d46ed1ea431825fdb01471bb024fc08399bad1572a616e853c7684415adb"}, + {file = "greenlet-3.5.3-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:e44da2f5bbdaabaf7d80b73dbb430c7035771e9f244e3c8b769715c9d8fa0a16"}, + {file = "greenlet-3.5.3-cp315-cp315t-win_amd64.whl", hash = "sha256:8ff8bed3e3baa20a3ea261ce00526f1898ad4801d4886fd2220580ee0ad8fadf"}, + {file = "greenlet-3.5.3-cp315-cp315t-win_arm64.whl", hash = "sha256:b7068bd09f761f3f5b4d214c2bed063186b2a86148c740b3873e3f56d79bac31"}, + {file = "greenlet-3.5.3.tar.gz", hash = "sha256:a61efc018fd3eb317eeca31aba90ee9e7f26f22884a79b6c6ec715bf71bb62f1"}, ] [package.extras] docs = ["Sphinx", "furo"] -test = ["objgraph", "psutil"] +test = ["objgraph", "psutil", "setuptools"] [[package]] name = "h11" -version = "0.14.0" +version = "0.16.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, - {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, + {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, + {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, ] [[package]] name = "h5py" -version = "3.10.0" +version = "3.16.0" description = "Read and write HDF5 files from Python" optional = false -python-versions = ">=3.8" -files = [ - {file = "h5py-3.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b963fb772964fc1d1563c57e4e2e874022ce11f75ddc6df1a626f42bd49ab99f"}, - {file = "h5py-3.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:012ab448590e3c4f5a8dd0f3533255bc57f80629bf7c5054cf4c87b30085063c"}, - {file = "h5py-3.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:781a24263c1270a62cd67be59f293e62b76acfcc207afa6384961762bb88ea03"}, - {file = "h5py-3.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f42e6c30698b520f0295d70157c4e202a9e402406f50dc08f5a7bc416b24e52d"}, - {file = "h5py-3.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:93dd840bd675787fc0b016f7a05fc6efe37312a08849d9dd4053fd0377b1357f"}, - {file = "h5py-3.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2381e98af081b6df7f6db300cd88f88e740649d77736e4b53db522d8874bf2dc"}, - {file = "h5py-3.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:667fe23ab33d5a8a6b77970b229e14ae3bb84e4ea3382cc08567a02e1499eedd"}, - {file = "h5py-3.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90286b79abd085e4e65e07c1bd7ee65a0f15818ea107f44b175d2dfe1a4674b7"}, - {file = "h5py-3.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c013d2e79c00f28ffd0cc24e68665ea03ae9069e167087b2adb5727d2736a52"}, - {file = "h5py-3.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:92273ce69ae4983dadb898fd4d3bea5eb90820df953b401282ee69ad648df684"}, - {file = "h5py-3.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c97d03f87f215e7759a354460fb4b0d0f27001450b18b23e556e7856a0b21c3"}, - {file = "h5py-3.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86df4c2de68257b8539a18646ceccdcf2c1ce6b1768ada16c8dcfb489eafae20"}, - {file = "h5py-3.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba9ab36be991119a3ff32d0c7cbe5faf9b8d2375b5278b2aea64effbeba66039"}, - {file = "h5py-3.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:2c8e4fda19eb769e9a678592e67eaec3a2f069f7570c82d2da909c077aa94339"}, - {file = "h5py-3.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:492305a074327e8d2513011fa9fffeb54ecb28a04ca4c4227d7e1e9616d35641"}, - {file = "h5py-3.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9450464b458cca2c86252b624279115dcaa7260a40d3cb1594bf2b410a2bd1a3"}, - {file = "h5py-3.10.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd6f6d1384a9f491732cee233b99cd4bfd6e838a8815cc86722f9d2ee64032af"}, - {file = "h5py-3.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3074ec45d3dc6e178c6f96834cf8108bf4a60ccb5ab044e16909580352010a97"}, - {file = "h5py-3.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:212bb997a91e6a895ce5e2f365ba764debeaef5d2dca5c6fb7098d66607adf99"}, - {file = "h5py-3.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5dfc65ac21fa2f630323c92453cadbe8d4f504726ec42f6a56cf80c2f90d6c52"}, - {file = "h5py-3.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d4682b94fd36ab217352be438abd44c8f357c5449b8995e63886b431d260f3d3"}, - {file = "h5py-3.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aece0e2e1ed2aab076c41802e50a0c3e5ef8816d60ece39107d68717d4559824"}, - {file = "h5py-3.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43a61b2c2ad65b1fabc28802d133eed34debcc2c8b420cb213d3d4ef4d3e2229"}, - {file = "h5py-3.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:ae2f0201c950059676455daf92700eeb57dcf5caaf71b9e1328e6e6593601770"}, - {file = "h5py-3.10.0.tar.gz", hash = "sha256:d93adc48ceeb33347eb24a634fb787efc7ae4644e6ea4ba733d099605045c049"}, +python-versions = ">=3.10" +files = [ + {file = "h5py-3.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e06f864bedb2c8e7c1358e6c73af48519e317457c444d6f3d332bb4e8fa6d7d9"}, + {file = "h5py-3.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ec86d4fffd87a0f4cb3d5796ceb5a50123a2a6d99b43e616e5504e66a953eca3"}, + {file = "h5py-3.16.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:86385ea895508220b8a7e45efa428aeafaa586bd737c7af9ee04661d8d84a10d"}, + {file = "h5py-3.16.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:8975273c2c5921c25700193b408e28d6bdd0111c37468b2d4e25dcec4cd1d84d"}, + {file = "h5py-3.16.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:1677ad48b703f44efc9ea0c3ab284527f81bc4f318386aaaebc5fede6bbae56f"}, + {file = "h5py-3.16.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c4dd4cf5f0a4e36083f73172f6cfc25a5710789269547f132a20975bfe2434c"}, + {file = "h5py-3.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:bdef06507725b455fccba9c16529121a5e1fbf56aa375f7d9713d9e8ff42454d"}, + {file = "h5py-3.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:719439d14b83f74eeb080e9650a6c7aa6d0d9ea0ca7f804347b05fac6fbf18af"}, + {file = "h5py-3.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c3f0a0e136f2e95dd0b67146abb6668af4f1a69c81ef8651a2d316e8e01de447"}, + {file = "h5py-3.16.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:a6fbc5367d4046801f9b7db9191b31895f22f1c6df1f9987d667854cac493538"}, + {file = "h5py-3.16.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:fb1720028d99040792bb2fb31facb8da44a6f29df7697e0b84f0d79aff2e9bd3"}, + {file = "h5py-3.16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:314b6054fe0b1051c2b0cb2df5cbdab15622fb05e80f202e3b6a5eee0d6fe365"}, + {file = "h5py-3.16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ffbab2fedd6581f6aa31cf1639ca2cb86e02779de525667892ebf4cc9fd26434"}, + {file = "h5py-3.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:17d1f1630f92ad74494a9a7392ab25982ce2b469fc62da6074c0ce48366a2999"}, + {file = "h5py-3.16.0-cp311-cp311-win_arm64.whl", hash = "sha256:85b9c49dd58dc44cf70af944784e2c2038b6f799665d0dcbbc812a26e0faa859"}, + {file = "h5py-3.16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c5313566f4643121a78503a473f0fb1e6dcc541d5115c44f05e037609c565c4d"}, + {file = "h5py-3.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:42b012933a83e1a558c673176676a10ce2fd3759976a0fedee1e672d1e04fc9d"}, + {file = "h5py-3.16.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:ff24039e2573297787c3063df64b60aab0591980ac898329a08b0320e0cf2527"}, + {file = "h5py-3.16.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:dfc21898ff025f1e8e67e194965a95a8d4754f452f83454538f98f8a3fcb207e"}, + {file = "h5py-3.16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:698dd69291272642ffda44a0ecd6cd3bda5faf9621452d255f57ce91487b9794"}, + {file = "h5py-3.16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2b2c02b0a160faed5fb33f1ba8a264a37ee240b22e049ecc827345d0d9043074"}, + {file = "h5py-3.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:96b422019a1c8975c2d5dadcf61d4ba6f01c31f92bbde6e4649607885fe502d6"}, + {file = "h5py-3.16.0-cp312-cp312-win_arm64.whl", hash = "sha256:39c2838fb1e8d97bcf1755e60ad1f3dd76a7b2a475928dc321672752678b96db"}, + {file = "h5py-3.16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:370a845f432c2c9619db8eed334d1e610c6015796122b0e57aa46312c22617d9"}, + {file = "h5py-3.16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:42108e93326c50c2810025aade9eac9d6827524cdccc7d4b75a546e5ab308edb"}, + {file = "h5py-3.16.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:099f2525c9dcf28de366970a5fb34879aab20491589fa89ce2863a84218bb524"}, + {file = "h5py-3.16.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:9300ad32dea9dfc5171f94d5f6948e159ed93e4701280b0f508773b3f582f402"}, + {file = "h5py-3.16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:171038f23bccddfc23f344cadabdfc9917ff554db6a0d417180d2747fe4c75a7"}, + {file = "h5py-3.16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7e420b539fb6023a259a1b14d4c9f6df8cf50d7268f48e161169987a57b737ff"}, + {file = "h5py-3.16.0-cp313-cp313-win_amd64.whl", hash = "sha256:18f2bbcd545e6991412253b98727374c356d67caa920e68dc79eab36bf5fedad"}, + {file = "h5py-3.16.0-cp313-cp313-win_arm64.whl", hash = "sha256:656f00e4d903199a1d58df06b711cf3ca632b874b4207b7dbec86185b5c8c7d4"}, + {file = "h5py-3.16.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:9c9d307c0ef862d1cd5714f72ecfafe0a5d7529c44845afa8de9f46e5ba8bd65"}, + {file = "h5py-3.16.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8c1eff849cdd53cbc73c214c30ebdb6f1bb8b64790b4b4fc36acdb5e43570210"}, + {file = "h5py-3.16.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:e2c04d129f180019e216ee5f9c40b78a418634091c8782e1f723a6ca3658b965"}, + {file = "h5py-3.16.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:e4360f15875a532bc7b98196c7592ed4fc92672a57c0a621355961cafb17a6dd"}, + {file = "h5py-3.16.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3fae9197390c325e62e0a1aa977f2f62d994aa87aab182abbea85479b791197c"}, + {file = "h5py-3.16.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:43259303989ac8adacc9986695b31e35dba6fd1e297ff9c6a04b7da5542139cc"}, + {file = "h5py-3.16.0-cp314-cp314-win_amd64.whl", hash = "sha256:fa48993a0b799737ba7fd21e2350fa0a60701e58180fae9f2de834bc39a147ab"}, + {file = "h5py-3.16.0-cp314-cp314-win_arm64.whl", hash = "sha256:1897a771a7f40d05c262fc8f37376ec37873218544b70216872876c627640f63"}, + {file = "h5py-3.16.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:15922e485844f77c0b9d275396d435db3baa58292a9c2176a386e072e0cf2491"}, + {file = "h5py-3.16.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:df02dd29bd247f98674634dfe41f89fd7c16ba3d7de8695ec958f58404a4e618"}, + {file = "h5py-3.16.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:0f456f556e4e2cebeebd9d66adf8dc321770a42593494a0b6f0af54a7567b242"}, + {file = "h5py-3.16.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:3e6cb3387c756de6a9492d601553dffea3fe11b5f22b443aac708c69f3f55e16"}, + {file = "h5py-3.16.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8389e13a1fd745ad2856873e8187fd10268b2d9677877bb667b41aebd771d8b7"}, + {file = "h5py-3.16.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:346df559a0f7dcb31cf8e44805319e2ab24b8957c45e7708ce503b2ec79ba725"}, + {file = "h5py-3.16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:4c6ab014ab704b4feaa719ae783b86522ed0bf1f82184704ed3c9e4e3228796e"}, + {file = "h5py-3.16.0-cp314-cp314t-win_arm64.whl", hash = "sha256:faca8fb4e4319c09d83337adc80b2ca7d5c5a343c2d6f1b6388f32cfecca13c1"}, + {file = "h5py-3.16.0.tar.gz", hash = "sha256:a0dbaad796840ccaa67a4c144a0d0c8080073c34c76d5a6941d6818678ef2738"}, ] [package.dependencies] -numpy = ">=1.17.3" +numpy = ">=1.21.2" [[package]] name = "hexbytes" -version = "1.2.1" +version = "1.3.1" description = "hexbytes: Python `bytes` subclass that decodes hex, with a readable console output" optional = false python-versions = "<4,>=3.8" files = [ - {file = "hexbytes-1.2.1-py3-none-any.whl", hash = "sha256:e64890b203a31f4a23ef11470ecfcca565beaee9198df623047df322b757471a"}, - {file = "hexbytes-1.2.1.tar.gz", hash = "sha256:515f00dddf31053db4d0d7636dd16061c1d896c3109b8e751005db4ca46bcca7"}, + {file = "hexbytes-1.3.1-py3-none-any.whl", hash = "sha256:da01ff24a1a9a2b1881c4b85f0e9f9b0f51b526b379ffa23832ae7899d29c2c7"}, + {file = "hexbytes-1.3.1.tar.gz", hash = "sha256:a657eebebdfe27254336f98d8af6e2236f3f83aed164b87466b6cf6c5f5a4765"}, ] [package.extras] -dev = ["build (>=0.9.0)", "bump-my-version (>=0.19.0)", "eth-utils (>=2.0.0)", "hypothesis (>=3.44.24,<=6.31.6)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] -docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] -test = ["eth-utils (>=2.0.0)", "hypothesis (>=3.44.24,<=6.31.6)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] +dev = ["build (>=0.9.0)", "bump_my_version (>=0.19.0)", "eth_utils (>=2.0.0)", "hypothesis (>=3.44.24)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)", "tox (>=4.0.0)", "twine", "wheel"] +docs = ["sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)"] +test = ["eth_utils (>=2.0.0)", "hypothesis (>=3.44.24)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] [[package]] name = "httpcore" -version = "0.17.3" +version = "1.0.9" description = "A minimal low-level HTTP client." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "httpcore-0.17.3-py3-none-any.whl", hash = "sha256:c2789b767ddddfa2a5782e3199b2b7f6894540b17b16ec26b2c4d8e103510b87"}, - {file = "httpcore-0.17.3.tar.gz", hash = "sha256:a6f30213335e34c1ade7be6ec7c47f19f50c56db36abef1a9dfa3815b1cb3888"}, + {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, + {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, ] [package.dependencies] -anyio = ">=3.0,<5.0" certifi = "*" -h11 = ">=0.13,<0.15" -sniffio = "==1.*" +h11 = ">=0.16" [package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<1.0)"] [[package]] -name = "httptools" -version = "0.6.4" -description = "A collection of framework independent HTTP protocol utils." +name = "httpcore2" +version = "2.7.0" +description = "A minimal low-level HTTP client." optional = false -python-versions = ">=3.8.0" -files = [ - {file = "httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0"}, - {file = "httptools-0.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:345c288418f0944a6fe67be8e6afa9262b18c7626c3ef3c28adc5eabc06a68da"}, - {file = "httptools-0.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deee0e3343f98ee8047e9f4c5bc7cedbf69f5734454a94c38ee829fb2d5fa3c1"}, - {file = "httptools-0.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca80b7485c76f768a3bc83ea58373f8db7b015551117375e4918e2aa77ea9b50"}, - {file = "httptools-0.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:90d96a385fa941283ebd231464045187a31ad932ebfa541be8edf5b3c2328959"}, - {file = "httptools-0.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:59e724f8b332319e2875efd360e61ac07f33b492889284a3e05e6d13746876f4"}, - {file = "httptools-0.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:c26f313951f6e26147833fc923f78f95604bbec812a43e5ee37f26dc9e5a686c"}, - {file = "httptools-0.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f47f8ed67cc0ff862b84a1189831d1d33c963fb3ce1ee0c65d3b0cbe7b711069"}, - {file = "httptools-0.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0614154d5454c21b6410fdf5262b4a3ddb0f53f1e1721cfd59d55f32138c578a"}, - {file = "httptools-0.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8787367fbdfccae38e35abf7641dafc5310310a5987b689f4c32cc8cc3ee975"}, - {file = "httptools-0.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b0f7fe4fd38e6a507bdb751db0379df1e99120c65fbdc8ee6c1d044897a636"}, - {file = "httptools-0.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40a5ec98d3f49904b9fe36827dcf1aadfef3b89e2bd05b0e35e94f97c2b14721"}, - {file = "httptools-0.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dacdd3d10ea1b4ca9df97a0a303cbacafc04b5cd375fa98732678151643d4988"}, - {file = "httptools-0.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:288cd628406cc53f9a541cfaf06041b4c71d751856bab45e3702191f931ccd17"}, - {file = "httptools-0.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2"}, - {file = "httptools-0.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44"}, - {file = "httptools-0.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1"}, - {file = "httptools-0.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2"}, - {file = "httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81"}, - {file = "httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f"}, - {file = "httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970"}, - {file = "httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660"}, - {file = "httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083"}, - {file = "httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3"}, - {file = "httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071"}, - {file = "httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5"}, - {file = "httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0"}, - {file = "httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8"}, - {file = "httptools-0.6.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:d3f0d369e7ffbe59c4b6116a44d6a8eb4783aae027f2c0b366cf0aa964185dba"}, - {file = "httptools-0.6.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:94978a49b8f4569ad607cd4946b759d90b285e39c0d4640c6b36ca7a3ddf2efc"}, - {file = "httptools-0.6.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40dc6a8e399e15ea525305a2ddba998b0af5caa2566bcd79dcbe8948181eeaff"}, - {file = "httptools-0.6.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab9ba8dcf59de5181f6be44a77458e45a578fc99c31510b8c65b7d5acc3cf490"}, - {file = "httptools-0.6.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:fc411e1c0a7dcd2f902c7c48cf079947a7e65b5485dea9decb82b9105ca71a43"}, - {file = "httptools-0.6.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:d54efd20338ac52ba31e7da78e4a72570cf729fac82bc31ff9199bedf1dc7440"}, - {file = "httptools-0.6.4-cp38-cp38-win_amd64.whl", hash = "sha256:df959752a0c2748a65ab5387d08287abf6779ae9165916fe053e68ae1fbdc47f"}, - {file = "httptools-0.6.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:85797e37e8eeaa5439d33e556662cc370e474445d5fab24dcadc65a8ffb04003"}, - {file = "httptools-0.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:db353d22843cf1028f43c3651581e4bb49374d85692a85f95f7b9a130e1b2cab"}, - {file = "httptools-0.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1ffd262a73d7c28424252381a5b854c19d9de5f56f075445d33919a637e3547"}, - {file = "httptools-0.6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:703c346571fa50d2e9856a37d7cd9435a25e7fd15e236c397bf224afaa355fe9"}, - {file = "httptools-0.6.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aafe0f1918ed07b67c1e838f950b1c1fabc683030477e60b335649b8020e1076"}, - {file = "httptools-0.6.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0e563e54979e97b6d13f1bbc05a96109923e76b901f786a5eae36e99c01237bd"}, - {file = "httptools-0.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:b799de31416ecc589ad79dd85a0b2657a8fe39327944998dea368c1d4c9e55e6"}, - {file = "httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c"}, +python-versions = ">=3.10" +files = [ + {file = "httpcore2-2.7.0-py3-none-any.whl", hash = "sha256:1452f589fe23f55b44546cd884294c41a29330af902bc0b71a761fd52d18f92b"}, + {file = "httpcore2-2.7.0.tar.gz", hash = "sha256:6dc0fedf329a52a990930a5579edfebaea81118ea700ea0dd7de2b5e5be49efc"}, ] +[package.dependencies] +h11 = ">=0.16" +truststore = ">=0.10" + [package.extras] -test = ["Cython (>=0.29.24)"] +asyncio = ["anyio (>=4.5.0,<5.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<1.0)"] + +[[package]] +name = "httptools" +version = "0.8.0" +description = "A collection of framework independent HTTP protocol utils." +optional = false +python-versions = ">=3.9" +files = [ + {file = "httptools-0.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:bf3b6f807c8541503cecfbb8a8dffb385640d0d96102f3d112aa8740f9b7c826"}, + {file = "httptools-0.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:da684f2e1aa2ee9bdcb083f3f3a68c5956750b375bc5df864d3a5f0c42a40b77"}, + {file = "httptools-0.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a6f21e2a3b0067bbe7f67e34cfd16276af556e5e52f4c7503be0cb5f90e905e4"}, + {file = "httptools-0.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea897f0c729581ebf72131a438a7932d9b14efef72d75ada966700cac3caaeb"}, + {file = "httptools-0.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c0d726cc107fceb7d45f978483b4b70dd8caa836f5914d3434bb18628eb73813"}, + {file = "httptools-0.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9878eb2785ba5eb70631ad269b37976f73d647955e26c91d490eb8a4edfda4ba"}, + {file = "httptools-0.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:b205e5f5523fa039679da0dfe5a10132b2a4abeae6a86fdd1ddc035f7f836557"}, + {file = "httptools-0.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ed377e64805bdba4943c82717333f8f8603a13b09aff9cead2717c6c817fb168"}, + {file = "httptools-0.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9518c406d7b310f05adb1a37f80acabac40504a575d7c0da6d3e365c695ac20d"}, + {file = "httptools-0.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:57278e6fa0424c42a8a3e454828ab4f0aff27b40cddf9679579b98c6dce6a376"}, + {file = "httptools-0.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bbb8caadb2b742d293169d2b458b5c001ef70e3158704aa3d3ef9597624c5d1d"}, + {file = "httptools-0.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:52dd695b865fe96d9d2b16b64a895f3f57bf3cb064e8383cd3b5713a069e8085"}, + {file = "httptools-0.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:20b4aac66ff65f7db06a375808b78f42a94970aa22e826b3cb2b43eb09174124"}, + {file = "httptools-0.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:a1b4c8e7a489a0d750d91894e9a8cdc295838f1924c0ca903ae993456fddec07"}, + {file = "httptools-0.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:880490234c10f70a9830743097e8958d6e4b9f5a0ffc24515023afeef984054d"}, + {file = "httptools-0.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5931891fb7b441b8a3853cf1b85c82c903defce084dd5f6771ca46e31bf862c5"}, + {file = "httptools-0.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b15fc622b0f869d19207c4089a501d9bcc63ca5e071ffdd2f03f922df882dcb2"}, + {file = "httptools-0.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:425f83884fd6343828d8c565f046cb72b6d19063f6924093e11bcd8e1548cd09"}, + {file = "httptools-0.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ef7c3c97f4311c7be57e2986629df89d49cb434dbff78eafcd48c2bff986b15a"}, + {file = "httptools-0.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a1afd7c9fbff0d9f5d489c4ce2768bd09c84a46ddefc7161e6aa82ae35c85745"}, + {file = "httptools-0.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:cd96f29b4bab1d42fa6e3d008711c75e0f79e94e06827330160e3a304227f150"}, + {file = "httptools-0.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:614ceea8ea606848bece2338ac03b3ce5324bcb4be8dc7d377ed708012fa4db8"}, + {file = "httptools-0.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2d689918c15a013c65ef52d9fd495d766893ab831a2c8d89f2ac5940a5df847c"}, + {file = "httptools-0.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:eb3028cca2fc0a6d720e52ef61d8ebb62fcbfeb1de56874546d858d3f25a26b7"}, + {file = "httptools-0.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:88bdd940f2b5d487b4d032c6afa5489a7dc4694410d43de3c38c4fb3af0dc45d"}, + {file = "httptools-0.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6a43c9dd399758ccc0531acb0a3c4a6c299ee893ee9400e9c893b7bdcfae0681"}, + {file = "httptools-0.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0770728beb05094c809b98e814edff5fef69d26ad7d21185f2f6d5884a0ba683"}, + {file = "httptools-0.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:7685df791fad561384bfb139e77fde27a1ffd93134e016f95a0db424ffbf77b1"}, + {file = "httptools-0.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:de242a49b5d18e0a8776e654e9f6bf6d89f3875a5c35b425a0e7ce940feb3fd6"}, + {file = "httptools-0.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:159e9ab5f701ccd42e555a12f1ad8ff69702910fc1c996cf2bb66e5fcb7a231b"}, + {file = "httptools-0.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c4a9f1707e4823d54dfec6c33fa3697d302aed536ed352a7ebb5a061ddb869d0"}, + {file = "httptools-0.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d76ad7b951387e3632c8716a9bb03ac5b45c5f16119aa409db0459520887944e"}, + {file = "httptools-0.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a3b7387147361c3fd47a0bde763c5c91b5b4cd4dc9989b8ece84ff436c99843b"}, + {file = "httptools-0.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f256d6ce930c52ca1cb2a960b7da03548c454e7d28b06059ad41bfe789036ce0"}, + {file = "httptools-0.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:19d1ee275bb59ba2643ba9a3a1e51cc0c788caf2b8df506368e03f56fdd08527"}, + {file = "httptools-0.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:de1ed58a974e75d56560acc7e7fed01a454994429456f65209789992e41f2568"}, + {file = "httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e93c227b595c6926c1acee96891dd9da4be338cfbe82e5cd3bb9d8dd7dc4ac0b"}, + {file = "httptools-0.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2a021c3a8e65cc125390d72f59b968afca3bdcaff25bd67965e0a055a14946ca"}, + {file = "httptools-0.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48774d39cbb70e2b1f71f88852a3087ae1d3a1eb80482bb48c13067ab080c14f"}, + {file = "httptools-0.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:88eead8ec8680a9f146c655bc88445a325bd7921cfd8194c7337e9467282427d"}, + {file = "httptools-0.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2c032fa028f46871ec7e1fc59fc15e8023eab3e6bbe6ece786a1611719a5d081"}, + {file = "httptools-0.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:384c17174464c8e873398b7af24f0b1f44d992c820328413951a625323155d77"}, + {file = "httptools-0.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:df31ef5494f406ab6cf827b7e64a22841c6e2d654100e6a116ea15b46d02d5e8"}, + {file = "httptools-0.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5eb911c515b96ee44bbd861e42cbefc488681d450545b1d02127f6136e3a86f5"}, + {file = "httptools-0.8.0-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c08ffe3e79756e0963cbc8fe410139f38a5884874b6f2e17761bef6563fdcd9b"}, + {file = "httptools-0.8.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fe2a4c95aeba2209434e7b31172da572846cae8ca0bf1e7013e61b99fbbf5e72"}, + {file = "httptools-0.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7b71e7d7031928c650e1006e6c03e911bf967f7c69c011d37d541c3e7bf55005"}, + {file = "httptools-0.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9fc1644f415372cec4f8a5be3a64183737398f10dbb1263602a036427fe75247"}, + {file = "httptools-0.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:5d7fa4ba7292c1139c0526f0b5aad507c6263c948206ea1b1cbca015c8af1b62"}, + {file = "httptools-0.8.0.tar.gz", hash = "sha256:6b2a32f18d97e16e90827d7a819ffa8dbd8cc245fc4e1fa9d1095b54ef4bd999"}, +] [[package]] name = "httpx" -version = "0.24.1" +version = "0.28.1" description = "The next generation HTTP client." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "httpx-0.24.1-py3-none-any.whl", hash = "sha256:06781eb9ac53cde990577af654bd990a4949de37a28bdb4a230d434f3a30b9bd"}, - {file = "httpx-0.24.1.tar.gz", hash = "sha256:5853a43053df830c20f8110c5e69fe44d035d850b2dfe795e196f00fdb774bdd"}, + {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"}, + {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"}, ] [package.dependencies] +anyio = "*" certifi = "*" -httpcore = ">=0.15.0,<0.18.0" +httpcore = "==1.*" idna = "*" -sniffio = "*" [package.extras] brotli = ["brotli", "brotlicffi"] cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "httpx2" +version = "2.7.0" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.10" +files = [ + {file = "httpx2-2.7.0-py3-none-any.whl", hash = "sha256:ed2a2719c696789e09493bd8e2bec3d8bd925cc6e26b68389ec25ade132f7bf4"}, + {file = "httpx2-2.7.0.tar.gz", hash = "sha256:8b30709aed5c8465b0dd3b95c09ce301c8f79e7e7a2d00ab0af551e0d0375b07"}, +] + +[package.dependencies] +anyio = ">=4.10" +httpcore2 = "2.7.0" +idna = ">=3.18" +truststore = ">=0.10" +typing-extensions = {version = ">=4.5.0", markers = "python_version < \"3.13\""} + +[package.extras] +brotli = ["brotli", "brotlicffi"] +cli = ["click (>=8.4)", "pygments (==2.*)", "rich (>=10,<16)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +ws = ["wsproto (>=1.2)"] +zstd = ["zstandard (>=0.18.0)"] [[package]] name = "human-protocol-sdk" @@ -2093,13 +2491,13 @@ agreement = ["numpy", "pyerf"] [[package]] name = "identify" -version = "2.5.33" +version = "2.6.19" description = "File identification library for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "identify-2.5.33-py2.py3-none-any.whl", hash = "sha256:d40ce5fcd762817627670da8a7d8d8e65f24342d14539c59488dc603bf662e34"}, - {file = "identify-2.5.33.tar.gz", hash = "sha256:161558f9fe4559e1557e1bff323e8631f6a0e4837f7497767c1782832f16b62d"}, + {file = "identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a"}, + {file = "identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842"}, ] [package.extras] @@ -2107,35 +2505,57 @@ license = ["ukkonen"] [[package]] name = "idna" -version = "3.6" +version = "3.18" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.5" +python-versions = ">=3.9" files = [ - {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, - {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, + {file = "idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2"}, + {file = "idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848"}, ] +[package.extras] +all = ["mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + +[[package]] +name = "importlib-resources" +version = "7.1.0" +description = "Read resources from Python packages" +optional = false +python-versions = ">=3.10" +files = [ + {file = "importlib_resources-7.1.0-py3-none-any.whl", hash = "sha256:1bd7b48b4088eddb2cd16382150bb515af0bd2c70128194392725f82ad2c96a1"}, + {file = "importlib_resources-7.1.0.tar.gz", hash = "sha256:0722d4c6212489c530f2a145a34c0a7a3b4721bc96a15fada5930e2a0b760708"}, +] + +[package.extras] +check = ["pytest-checkdocs (>=2.14)", "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"] +enabler = ["pytest-enabler (>=3.4)"] +test = ["jaraco.test (>=5.4)", "pytest (>=6,!=8.1.*)", "zipp (>=3.17)"] +type = ["pytest-mypy (>=1.0.1)"] + [[package]] name = "iniconfig" -version = "2.0.0" +version = "2.3.0" description = "brain-dead simple config-ini parsing" optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, + {file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"}, + {file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"}, ] [[package]] name = "jinja2" -version = "3.1.4" +version = "3.1.6" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" files = [ - {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, - {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, + {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, + {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, ] [package.dependencies] @@ -2146,230 +2566,299 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "jmespath" -version = "1.0.1" +version = "1.1.0" description = "JSON Matching Expressions" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, - {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, + {file = "jmespath-1.1.0-py3-none-any.whl", hash = "sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64"}, + {file = "jmespath-1.1.0.tar.gz", hash = "sha256:472c87d80f36026ae83c6ddd0f1d05d4e510134ed462851fd5f754c8c3cbb88d"}, ] [[package]] name = "kiwisolver" -version = "1.4.5" +version = "1.5.0" description = "A fast implementation of the Cassowary constraint solver" optional = false -python-versions = ">=3.7" -files = [ - {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af"}, - {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3"}, - {file = "kiwisolver-1.4.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b"}, - {file = "kiwisolver-1.4.5-cp310-cp310-win32.whl", hash = "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238"}, - {file = "kiwisolver-1.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276"}, - {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5"}, - {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90"}, - {file = "kiwisolver-1.4.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f"}, - {file = "kiwisolver-1.4.5-cp311-cp311-win32.whl", hash = "sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac"}, - {file = "kiwisolver-1.4.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355"}, - {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a"}, - {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192"}, - {file = "kiwisolver-1.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a"}, - {file = "kiwisolver-1.4.5-cp312-cp312-win32.whl", hash = "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20"}, - {file = "kiwisolver-1.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-win32.whl", hash = "sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-win_amd64.whl", hash = "sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a"}, - {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71"}, - {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93"}, - {file = "kiwisolver-1.4.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250"}, - {file = "kiwisolver-1.4.5-cp38-cp38-win32.whl", hash = "sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e"}, - {file = "kiwisolver-1.4.5-cp38-cp38-win_amd64.whl", hash = "sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced"}, - {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d"}, - {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9"}, - {file = "kiwisolver-1.4.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77"}, - {file = "kiwisolver-1.4.5-cp39-cp39-win32.whl", hash = "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f"}, - {file = "kiwisolver-1.4.5-cp39-cp39-win_amd64.whl", hash = "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee"}, - {file = "kiwisolver-1.4.5.tar.gz", hash = "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec"}, +python-versions = ">=3.10" +files = [ + {file = "kiwisolver-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:32cc0a5365239a6ea0c6ed461e8838d053b57e397443c0ca894dcc8e388d4374"}, + {file = "kiwisolver-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cc0b66c1eec9021353a4b4483afb12dfd50e3669ffbb9152d6842eb34c7e29fd"}, + {file = "kiwisolver-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:86e0287879f75621ae85197b0877ed2f8b7aa57b511c7331dce2eb6f4de7d476"}, + {file = "kiwisolver-1.5.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:62f59da443c4f4849f73a51a193b1d9d258dcad0c41bc4d1b8fb2bcc04bfeb22"}, + {file = "kiwisolver-1.5.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9190426b7aa26c5229501fa297b8d0653cfd3f5a36f7990c264e157cbf886b3b"}, + {file = "kiwisolver-1.5.0-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c8277104ded0a51e699c8c3aff63ce2c56d4ed5519a5f73e0fd7057f959a2b9e"}, + {file = "kiwisolver-1.5.0-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8f9baf6f0a6e7571c45c8863010b45e837c3ee1c2c77fcd6ef423be91b21fedb"}, + {file = "kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cff8e5383db4989311f99e814feeb90c4723eb4edca425b9d5d9c3fefcdd9537"}, + {file = "kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ebae99ed6764f2b5771c522477b311be313e8841d2e0376db2b10922daebbba4"}, + {file = "kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:d5cd5189fc2b6a538b75ae45433140c4823463918f7b1617c31e68b085c0022c"}, + {file = "kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f42c23db5d1521218a3276bb08666dcb662896a0be7347cba864eca45ff64ede"}, + {file = "kiwisolver-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:94eff26096eb5395136634622515b234ecb6c9979824c1f5004c6e3c3c85ccd2"}, + {file = "kiwisolver-1.5.0-cp310-cp310-win_arm64.whl", hash = "sha256:dd952e03bfbb096cfe2dd35cd9e00f269969b67536cb4370994afc20ff2d0875"}, + {file = "kiwisolver-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9eed0f7edbb274413b6ee781cca50541c8c0facd3d6fd289779e494340a2b85c"}, + {file = "kiwisolver-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c4923e404d6bcd91b6779c009542e5647fef32e4a5d75e115e3bbac6f2335eb"}, + {file = "kiwisolver-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0df54df7e686afa55e6f21fb86195224a6d9beb71d637e8d7920c95cf0f89aac"}, + {file = "kiwisolver-1.5.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2517e24d7315eb51c10664cdb865195df38ab74456c677df67bb47f12d088a27"}, + {file = "kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff710414307fefa903e0d9bdf300972f892c23477829f49504e59834f4195398"}, + {file = "kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6176c1811d9d5a04fa391c490cc44f451e240697a16977f11c6f722efb9041db"}, + {file = "kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50847dca5d197fcbd389c805aa1a1cf32f25d2e7273dc47ab181a517666b68cc"}, + {file = "kiwisolver-1.5.0-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:01808c6d15f4c3e8559595d6d1fe6411c68e4a3822b4b9972b44473b24f4e679"}, + {file = "kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f1f9f4121ec58628c96baa3de1a55a4e3a333c5102c8e94b64e23bf7b2083309"}, + {file = "kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b7d335370ae48a780c6e6a6bbfa97342f563744c39c35562f3f367665f5c1de2"}, + {file = "kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:800ee55980c18545af444d93fdd60c56b580db5cc54867d8cbf8a1dc0829938c"}, + {file = "kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c438f6ca858697c9ab67eb28246c92508af972e114cac34e57a6d4ba17a3ac08"}, + {file = "kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8c63c91f95173f9c2a67c7c526b2cea976828a0e7fced9cdcead2802dc10f8a4"}, + {file = "kiwisolver-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:beb7f344487cdcb9e1efe4b7a29681b74d34c08f0043a327a74da852a6749e7b"}, + {file = "kiwisolver-1.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:ad4ae4ffd1ee9cd11357b4c66b612da9888f4f4daf2f36995eda64bd45370cac"}, + {file = "kiwisolver-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4e9750bc21b886308024f8a54ccb9a2cc38ac9fa813bf4348434e3d54f337ff9"}, + {file = "kiwisolver-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:72ec46b7eba5b395e0a7b63025490d3214c11013f4aacb4f5e8d6c3041829588"}, + {file = "kiwisolver-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ed3a984b31da7481b103f68776f7128a89ef26ed40f4dc41a2223cda7fb24819"}, + {file = "kiwisolver-1.5.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb5136fb5352d3f422df33f0c879a1b0c204004324150cc3b5e3c4f310c9049f"}, + {file = "kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2af221f268f5af85e776a73d62b0845fc8baf8ef0abfae79d29c77d0e776aaf"}, + {file = "kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b0f172dc8ffaccb8522d7c5d899de00133f2f1ca7b0a49b7da98e901de87bf2d"}, + {file = "kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6ab8ba9152203feec73758dad83af9a0bbe05001eb4639e547207c40cfb52083"}, + {file = "kiwisolver-1.5.0-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:cdee07c4d7f6d72008d3f73b9bf027f4e11550224c7c50d8df1ae4a37c1402a6"}, + {file = "kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7c60d3c9b06fb23bd9c6139281ccbdc384297579ae037f08ae90c69f6845c0b1"}, + {file = "kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e315e5ec90d88e140f57696ff85b484ff68bb311e36f2c414aa4286293e6dee0"}, + {file = "kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:1465387ac63576c3e125e5337a6892b9e99e0627d52317f3ca79e6930d889d15"}, + {file = "kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:530a3fd64c87cffa844d4b6b9768774763d9caa299e9b75d8eca6a4423b31314"}, + {file = "kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1d9daea4ea6b9be74fe2f01f7fbade8d6ffab263e781274cffca0dba9be9eec9"}, + {file = "kiwisolver-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:f18c2d9782259a6dc132fdc7a63c168cbc74b35284b6d75c673958982a378384"}, + {file = "kiwisolver-1.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:f7c7553b13f69c1b29a5bde08ddc6d9d0c8bfb84f9ed01c30db25944aeb852a7"}, + {file = "kiwisolver-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:fd40bb9cd0891c4c3cb1ddf83f8bbfa15731a248fdc8162669405451e2724b09"}, + {file = "kiwisolver-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c0e1403fd7c26d77c1f03e096dc58a5c726503fa0db0456678b8668f76f521e3"}, + {file = "kiwisolver-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dda366d548e89a90d88a86c692377d18d8bd64b39c1fb2b92cb31370e2896bbd"}, + {file = "kiwisolver-1.5.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:332b4f0145c30b5f5ad9374881133e5aa64320428a57c2c2b61e9d891a51c2f3"}, + {file = "kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c50b89ffd3e1a911c69a1dd3de7173c0cd10b130f56222e57898683841e4f96"}, + {file = "kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4db576bb8c3ef9365f8b40fe0f671644de6736ae2c27a2c62d7d8a1b4329f099"}, + {file = "kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0b85aad90cea8ac6797a53b5d5f2e967334fa4d1149f031c4537569972596cb8"}, + {file = "kiwisolver-1.5.0-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:d36ca54cb4c6c4686f7cbb7b817f66f5911c12ddb519450bbe86707155028f87"}, + {file = "kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:38f4a703656f493b0ad185211ccfca7f0386120f022066b018eb5296d8613e23"}, + {file = "kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3ac2360e93cb41be81121755c6462cff3beaa9967188c866e5fce5cf13170859"}, + {file = "kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c95cab08d1965db3d84a121f1c7ce7479bdd4072c9b3dafd8fecce48a2e6b902"}, + {file = "kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fc20894c3d21194d8041a28b65622d5b86db786da6e3cfe73f0c762951a61167"}, + {file = "kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7a32f72973f0f950c1920475d5c5ea3d971b81b6f0ec53b8d0a956cc965f22e0"}, + {file = "kiwisolver-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bf3acf1419fa93064a4c2189ac0b58e3be7872bf6ee6177b0d4c63dc4cea276"}, + {file = "kiwisolver-1.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:fa8eb9ecdb7efb0b226acec134e0d709e87a909fa4971a54c0c4f6e88635484c"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:db485b3847d182b908b483b2ed133c66d88d49cacf98fd278fadafe11b4478d1"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:be12f931839a3bdfe28b584db0e640a65a8bcbc24560ae3fdb025a449b3d754e"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:16b85d37c2cbb3253226d26e64663f755d88a03439a9c47df6246b35defbdfb7"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4432b835675f0ea7414aab3d37d119f7226d24869b7a829caeab49ebda407b0c"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b0feb50971481a2cc44d94e88bdb02cdd497618252ae226b8eb1201b957e368"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56fa888f10d0f367155e76ce849fa1166fc9730d13bd2d65a2aa13b6f5424489"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:940dda65d5e764406b9fb92761cbf462e4e63f712ab60ed98f70552e496f3bf1"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-manylinux_2_39_riscv64.whl", hash = "sha256:89fc958c702ee9a745e4700378f5d23fddbc46ff89e8fdbf5395c24d5c1452a3"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9027d773c4ff81487181a925945743413f6069634d0b122d0b37684ccf4f1e18"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:5b233ea3e165e43e35dba1d2b8ecc21cf070b45b65ae17dd2747d2713d942021"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ce9bf03dad3b46408c08649c6fbd6ca28a9fce0eb32fdfffa6775a13103b5310"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:fc4d3f1fb9ca0ae9f97b095963bc6326f1dbfd3779d6679a1e016b9baaa153d3"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f443b4825c50a51ee68585522ab4a1d1257fac65896f282b4c6763337ac9f5d2"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-win_arm64.whl", hash = "sha256:893ff3a711d1b515ba9da14ee090519bad4610ed1962fbe298a434e8c5f8db53"}, + {file = "kiwisolver-1.5.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8df31fe574b8b3993cc61764f40941111b25c2d9fea13d3ce24a49907cd2d615"}, + {file = "kiwisolver-1.5.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1d49a49ac4cbfb7c1375301cd1ec90169dfeae55ff84710d782260ce77a75a02"}, + {file = "kiwisolver-1.5.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0cbe94b69b819209a62cb27bdfa5dc2a8977d8de2f89dfd97ba4f53ed3af754e"}, + {file = "kiwisolver-1.5.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:80aa065ffd378ff784822a6d7c3212f2d5f5e9c3589614b5c228b311fd3063ac"}, + {file = "kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e7f886f47ab881692f278ae901039a234e4025a68e6dfab514263a0b1c4ae05"}, + {file = "kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5060731cc3ed12ca3a8b57acd4aeca5bbc2f49216dd0bec1650a1acd89486bcd"}, + {file = "kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7a4aa69609f40fce3cbc3f87b2061f042eee32f94b8f11db707b66a26461591a"}, + {file = "kiwisolver-1.5.0-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:d168fda2dbff7b9b5f38e693182d792a938c31db4dac3a80a4888de603c99554"}, + {file = "kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:413b820229730d358efd838ecbab79902fe97094565fdc80ddb6b0a18c18a581"}, + {file = "kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5124d1ea754509b09e53738ec185584cc609aae4a3b510aaf4ed6aa047ef9303"}, + {file = "kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e4415a8db000bf49a6dd1c478bf70062eaacff0f462b92b0ba68791a905861f9"}, + {file = "kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d618fd27420381a4f6044faa71f46d8bfd911bd077c555f7138ed88729bfbe79"}, + {file = "kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5092eb5b1172947f57d6ea7d89b2f29650414e4293c47707eb499ec07a0ac796"}, + {file = "kiwisolver-1.5.0-cp314-cp314-win_amd64.whl", hash = "sha256:d76e2d8c75051d58177e762164d2e9ab92886534e3a12e795f103524f221dd8e"}, + {file = "kiwisolver-1.5.0-cp314-cp314-win_arm64.whl", hash = "sha256:fa6248cd194edff41d7ea9425ced8ca3a6f838bfb295f6f1d6e6bb694a8518df"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:d1ffeb80b5676463d7a7d56acbe8e37a20ce725570e09549fe738e02ca6b7e1e"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:bc4d8e252f532ab46a1de9349e2d27b91fce46736a9eedaa37beaca66f574ed4"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6783e069732715ad0c3ce96dbf21dbc2235ab0593f2baf6338101f70371f4028"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e7c4c09a490dc4d4a7f8cbee56c606a320f9dc28cf92a7157a39d1ce7676a657"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a075bd7bd19c70cf67c8badfa36cf7c5d8de3c9ddb8420c51e10d9c50e94920"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bdd3e53429ff02aa319ba59dfe4ceeec345bf46cf180ec2cf6fd5b942e7975e9"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cdcb35dc9d807259c981a85531048ede628eabcffb3239adf3d17463518992d"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:70d593af6a6ca332d1df73d519fddb5148edb15cd90d5f0155e3746a6d4fcc65"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:377815a8616074cabbf3f53354e1d040c35815a134e01d7614b7692e4bf8acfa"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0255a027391d52944eae1dbb5d4cc5903f57092f3674e8e544cdd2622826b3f0"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:012b1eb16e28718fa782b5e61dc6f2da1f0792ca73bd05d54de6cb9561665fc9"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0e3aafb33aed7479377e5e9a82e9d4bf87063741fc99fc7ae48b0f16e32bdd6f"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e7a116ae737f0000343218c4edf5bd45893bfeaff0993c0b215d7124c9f77646"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:1dd9b0b119a350976a6d781e7278ec7aca0b201e1a9e2d23d9804afecb6ca681"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:58f812017cd2985c21fbffb4864d59174d4903dd66fa23815e74bbc7a0e2dd57"}, + {file = "kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_10_13_x86_64.whl", hash = "sha256:5ae8e62c147495b01a0f4765c878e9bfdf843412446a247e28df59936e99e797"}, + {file = "kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f6764a4ccab3078db14a632420930f6186058750df066b8ea2a7106df91d3203"}, + {file = "kiwisolver-1.5.0-graalpy312-graalpy250_312_native-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c31c13da98624f957b0fb1b5bae5383b2333c2c3f6793d9825dd5ce79b525cb7"}, + {file = "kiwisolver-1.5.0-graalpy312-graalpy250_312_native-win_amd64.whl", hash = "sha256:1f1489f769582498610e015a8ef2d36f28f505ab3096d0e16b4858a9ec214f57"}, + {file = "kiwisolver-1.5.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:295d9ffe712caa9f8a3081de8d32fc60191b4b51c76f02f951fd8407253528f4"}, + {file = "kiwisolver-1.5.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:51e8c4084897de9f05898c2c2a39af6318044ae969d46ff7a34ed3f96274adca"}, + {file = "kiwisolver-1.5.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b83af57bdddef03c01a9138034c6ff03181a3028d9a1003b301eb1a55e161a3f"}, + {file = "kiwisolver-1.5.0-pp310-pypy310_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf4679a3d71012a7c2bf360e5cd878fbd5e4fcac0896b56393dec239d81529ed"}, + {file = "kiwisolver-1.5.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:41024ed50e44ab1a60d3fe0a9d15a4ccc9f5f2b1d814ff283c8d01134d5b81bc"}, + {file = "kiwisolver-1.5.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ec4c85dc4b687c7f7f15f553ff26a98bfe8c58f5f7f0ac8905f0ba4c7be60232"}, + {file = "kiwisolver-1.5.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:12e91c215a96e39f57989c8912ae761286ac5a9584d04030ceb3368a357f017a"}, + {file = "kiwisolver-1.5.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:be4a51a55833dc29ab5d7503e7bcb3b3af3402d266018137127450005cdfe737"}, + {file = "kiwisolver-1.5.0-pp311-pypy311_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:daae526907e262de627d8f70058a0f64acc9e2641c164c99c8f594b34a799a16"}, + {file = "kiwisolver-1.5.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:59cd8683f575d96df5bb48f6add94afc055012c29e28124fcae2b63661b9efb1"}, + {file = "kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a"}, ] [[package]] name = "lxml" -version = "5.1.0" +version = "6.1.1" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "lxml-5.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:704f5572ff473a5f897745abebc6df40f22d4133c1e0a1f124e4f2bd3330ff7e"}, - {file = "lxml-5.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9d3c0f8567ffe7502d969c2c1b809892dc793b5d0665f602aad19895f8d508da"}, - {file = "lxml-5.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5fcfbebdb0c5d8d18b84118842f31965d59ee3e66996ac842e21f957eb76138c"}, - {file = "lxml-5.1.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f37c6d7106a9d6f0708d4e164b707037b7380fcd0b04c5bd9cae1fb46a856fb"}, - {file = "lxml-5.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2befa20a13f1a75c751f47e00929fb3433d67eb9923c2c0b364de449121f447c"}, - {file = "lxml-5.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22b7ee4c35f374e2c20337a95502057964d7e35b996b1c667b5c65c567d2252a"}, - {file = "lxml-5.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bf8443781533b8d37b295016a4b53c1494fa9a03573c09ca5104550c138d5c05"}, - {file = "lxml-5.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:82bddf0e72cb2af3cbba7cec1d2fd11fda0de6be8f4492223d4a268713ef2147"}, - {file = "lxml-5.1.0-cp310-cp310-win32.whl", hash = "sha256:b66aa6357b265670bb574f050ffceefb98549c721cf28351b748be1ef9577d93"}, - {file = "lxml-5.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:4946e7f59b7b6a9e27bef34422f645e9a368cb2be11bf1ef3cafc39a1f6ba68d"}, - {file = "lxml-5.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:14deca1460b4b0f6b01f1ddc9557704e8b365f55c63070463f6c18619ebf964f"}, - {file = "lxml-5.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ed8c3d2cd329bf779b7ed38db176738f3f8be637bb395ce9629fc76f78afe3d4"}, - {file = "lxml-5.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:436a943c2900bb98123b06437cdd30580a61340fbdb7b28aaf345a459c19046a"}, - {file = "lxml-5.1.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:acb6b2f96f60f70e7f34efe0c3ea34ca63f19ca63ce90019c6cbca6b676e81fa"}, - {file = "lxml-5.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af8920ce4a55ff41167ddbc20077f5698c2e710ad3353d32a07d3264f3a2021e"}, - {file = "lxml-5.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cfced4a069003d8913408e10ca8ed092c49a7f6cefee9bb74b6b3e860683b45"}, - {file = "lxml-5.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9e5ac3437746189a9b4121db2a7b86056ac8786b12e88838696899328fc44bb2"}, - {file = "lxml-5.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f4c9bda132ad108b387c33fabfea47866af87f4ea6ffb79418004f0521e63204"}, - {file = "lxml-5.1.0-cp311-cp311-win32.whl", hash = "sha256:bc64d1b1dab08f679fb89c368f4c05693f58a9faf744c4d390d7ed1d8223869b"}, - {file = "lxml-5.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:a5ab722ae5a873d8dcee1f5f45ddd93c34210aed44ff2dc643b5025981908cda"}, - {file = "lxml-5.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9aa543980ab1fbf1720969af1d99095a548ea42e00361e727c58a40832439114"}, - {file = "lxml-5.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6f11b77ec0979f7e4dc5ae081325a2946f1fe424148d3945f943ceaede98adb8"}, - {file = "lxml-5.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a36c506e5f8aeb40680491d39ed94670487ce6614b9d27cabe45d94cd5d63e1e"}, - {file = "lxml-5.1.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f643ffd2669ffd4b5a3e9b41c909b72b2a1d5e4915da90a77e119b8d48ce867a"}, - {file = "lxml-5.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16dd953fb719f0ffc5bc067428fc9e88f599e15723a85618c45847c96f11f431"}, - {file = "lxml-5.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16018f7099245157564d7148165132c70adb272fb5a17c048ba70d9cc542a1a1"}, - {file = "lxml-5.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:82cd34f1081ae4ea2ede3d52f71b7be313756e99b4b5f829f89b12da552d3aa3"}, - {file = "lxml-5.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:19a1bc898ae9f06bccb7c3e1dfd73897ecbbd2c96afe9095a6026016e5ca97b8"}, - {file = "lxml-5.1.0-cp312-cp312-win32.whl", hash = "sha256:13521a321a25c641b9ea127ef478b580b5ec82aa2e9fc076c86169d161798b01"}, - {file = "lxml-5.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:1ad17c20e3666c035db502c78b86e58ff6b5991906e55bdbef94977700c72623"}, - {file = "lxml-5.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:24ef5a4631c0b6cceaf2dbca21687e29725b7c4e171f33a8f8ce23c12558ded1"}, - {file = "lxml-5.1.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d2900b7f5318bc7ad8631d3d40190b95ef2aa8cc59473b73b294e4a55e9f30f"}, - {file = "lxml-5.1.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:601f4a75797d7a770daed8b42b97cd1bb1ba18bd51a9382077a6a247a12aa38d"}, - {file = "lxml-5.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4b68c961b5cc402cbd99cca5eb2547e46ce77260eb705f4d117fd9c3f932b95"}, - {file = "lxml-5.1.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:afd825e30f8d1f521713a5669b63657bcfe5980a916c95855060048b88e1adb7"}, - {file = "lxml-5.1.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:262bc5f512a66b527d026518507e78c2f9c2bd9eb5c8aeeb9f0eb43fcb69dc67"}, - {file = "lxml-5.1.0-cp36-cp36m-win32.whl", hash = "sha256:e856c1c7255c739434489ec9c8aa9cdf5179785d10ff20add308b5d673bed5cd"}, - {file = "lxml-5.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:c7257171bb8d4432fe9d6fdde4d55fdbe663a63636a17f7f9aaba9bcb3153ad7"}, - {file = "lxml-5.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b9e240ae0ba96477682aa87899d94ddec1cc7926f9df29b1dd57b39e797d5ab5"}, - {file = "lxml-5.1.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a96f02ba1bcd330807fc060ed91d1f7a20853da6dd449e5da4b09bfcc08fdcf5"}, - {file = "lxml-5.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e3898ae2b58eeafedfe99e542a17859017d72d7f6a63de0f04f99c2cb125936"}, - {file = "lxml-5.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61c5a7edbd7c695e54fca029ceb351fc45cd8860119a0f83e48be44e1c464862"}, - {file = "lxml-5.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3aeca824b38ca78d9ee2ab82bd9883083d0492d9d17df065ba3b94e88e4d7ee6"}, - {file = "lxml-5.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8f52fe6859b9db71ee609b0c0a70fea5f1e71c3462ecf144ca800d3f434f0764"}, - {file = "lxml-5.1.0-cp37-cp37m-win32.whl", hash = "sha256:d42e3a3fc18acc88b838efded0e6ec3edf3e328a58c68fbd36a7263a874906c8"}, - {file = "lxml-5.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:eac68f96539b32fce2c9b47eb7c25bb2582bdaf1bbb360d25f564ee9e04c542b"}, - {file = "lxml-5.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ae15347a88cf8af0949a9872b57a320d2605ae069bcdf047677318bc0bba45b1"}, - {file = "lxml-5.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c26aab6ea9c54d3bed716b8851c8bfc40cb249b8e9880e250d1eddde9f709bf5"}, - {file = "lxml-5.1.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:342e95bddec3a698ac24378d61996b3ee5ba9acfeb253986002ac53c9a5f6f84"}, - {file = "lxml-5.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:725e171e0b99a66ec8605ac77fa12239dbe061482ac854d25720e2294652eeaa"}, - {file = "lxml-5.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d184e0d5c918cff04cdde9dbdf9600e960161d773666958c9d7b565ccc60c45"}, - {file = "lxml-5.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:98f3f020a2b736566c707c8e034945c02aa94e124c24f77ca097c446f81b01f1"}, - {file = "lxml-5.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6d48fc57e7c1e3df57be5ae8614bab6d4e7b60f65c5457915c26892c41afc59e"}, - {file = "lxml-5.1.0-cp38-cp38-win32.whl", hash = "sha256:7ec465e6549ed97e9f1e5ed51c657c9ede767bc1c11552f7f4d022c4df4a977a"}, - {file = "lxml-5.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:b21b4031b53d25b0858d4e124f2f9131ffc1530431c6d1321805c90da78388d1"}, - {file = "lxml-5.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:52427a7eadc98f9e62cb1368a5079ae826f94f05755d2d567d93ee1bc3ceb354"}, - {file = "lxml-5.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6a2a2c724d97c1eb8cf966b16ca2915566a4904b9aad2ed9a09c748ffe14f969"}, - {file = "lxml-5.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:843b9c835580d52828d8f69ea4302537337a21e6b4f1ec711a52241ba4a824f3"}, - {file = "lxml-5.1.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9b99f564659cfa704a2dd82d0684207b1aadf7d02d33e54845f9fc78e06b7581"}, - {file = "lxml-5.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f8b0c78e7aac24979ef09b7f50da871c2de2def043d468c4b41f512d831e912"}, - {file = "lxml-5.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9bcf86dfc8ff3e992fed847c077bd875d9e0ba2fa25d859c3a0f0f76f07f0c8d"}, - {file = "lxml-5.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:49a9b4af45e8b925e1cd6f3b15bbba2c81e7dba6dce170c677c9cda547411e14"}, - {file = "lxml-5.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:280f3edf15c2a967d923bcfb1f8f15337ad36f93525828b40a0f9d6c2ad24890"}, - {file = "lxml-5.1.0-cp39-cp39-win32.whl", hash = "sha256:ed7326563024b6e91fef6b6c7a1a2ff0a71b97793ac33dbbcf38f6005e51ff6e"}, - {file = "lxml-5.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:8d7b4beebb178e9183138f552238f7e6613162a42164233e2bda00cb3afac58f"}, - {file = "lxml-5.1.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9bd0ae7cc2b85320abd5e0abad5ccee5564ed5f0cc90245d2f9a8ef330a8deae"}, - {file = "lxml-5.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8c1d679df4361408b628f42b26a5d62bd3e9ba7f0c0e7969f925021554755aa"}, - {file = "lxml-5.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2ad3a8ce9e8a767131061a22cd28fdffa3cd2dc193f399ff7b81777f3520e372"}, - {file = "lxml-5.1.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:304128394c9c22b6569eba2a6d98392b56fbdfbad58f83ea702530be80d0f9df"}, - {file = "lxml-5.1.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d74fcaf87132ffc0447b3c685a9f862ffb5b43e70ea6beec2fb8057d5d2a1fea"}, - {file = "lxml-5.1.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:8cf5877f7ed384dabfdcc37922c3191bf27e55b498fecece9fd5c2c7aaa34c33"}, - {file = "lxml-5.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:877efb968c3d7eb2dad540b6cabf2f1d3c0fbf4b2d309a3c141f79c7e0061324"}, - {file = "lxml-5.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f14a4fb1c1c402a22e6a341a24c1341b4a3def81b41cd354386dcb795f83897"}, - {file = "lxml-5.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:25663d6e99659544ee8fe1b89b1a8c0aaa5e34b103fab124b17fa958c4a324a6"}, - {file = "lxml-5.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8b9f19df998761babaa7f09e6bc169294eefafd6149aaa272081cbddc7ba4ca3"}, - {file = "lxml-5.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e53d7e6a98b64fe54775d23a7c669763451340c3d44ad5e3a3b48a1efbdc96f"}, - {file = "lxml-5.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c3cd1fc1dc7c376c54440aeaaa0dcc803d2126732ff5c6b68ccd619f2e64be4f"}, - {file = "lxml-5.1.0.tar.gz", hash = "sha256:3eea6ed6e6c918e468e693c41ef07f3c3acc310b70ddd9cc72d9ef84bc9564ca"}, + {file = "lxml-6.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:09dd5b7075dc2f7709654a46543ba1ea3c2e217b2ed8fbd413a8a945a0f40f60"}, + {file = "lxml-6.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f6ac4ef4d82dff54670227a69c67782ae0b811b5cf6b17954f1e8f7502fc0d1d"}, + {file = "lxml-6.1.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:556e94a63c9b04716f8e4de2abb65775061f846e89331b6c5be79183a24f98ea"}, + {file = "lxml-6.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5c6bf403fbb3b3e348a561a5f4f0b9961835657981c802a1df03653eef8a9074"}, + {file = "lxml-6.1.1-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1dde6131244bba38a17c745836ba190bc753fd73c9291666287fd0a3fa3dcf30"}, + {file = "lxml-6.1.1-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:98fc784c2c1440667aeedf8465bdfe10208acf0ead656a2c68627299f546b315"}, + {file = "lxml-6.1.1-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:add8cf6ddf9a65116119a28ece0f7886e30af27ba724a7594305f1d1b58a92a1"}, + {file = "lxml-6.1.1-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:cf9d57306d848218f3601fee7601fab1a327c942d56e2e97610583cb4dd74206"}, + {file = "lxml-6.1.1-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:88136950da4d13c318bde414ce10219931937851327f44328f2df4d2c4614067"}, + {file = "lxml-6.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cecdd5dfdc87b1fd87dbf81d4b037a544f47f4c744200a67013771682d67686a"}, + {file = "lxml-6.1.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:cd312b9692e831d2ffcad61eab31d91d4b4655a962e61de8fb410472cbcd37aa"}, + {file = "lxml-6.1.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:5b7328b46d49fc9477d91ae8f6d55340347d827b7734ba3ea33faae0efef1383"}, + {file = "lxml-6.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:37a58976370f36d9329d118ad0b953c5aeb9119ac9c6a4e258942a225d0573a1"}, + {file = "lxml-6.1.1-cp310-cp310-win32.whl", hash = "sha256:cea3f4c1af79af13cdb2da0c028111d8f8522d4f22a000c82385535f24e5cf3a"}, + {file = "lxml-6.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:3abf332af33a74288675d936fe861fd4344da0dd6622193fbc4f2bfbb35536b5"}, + {file = "lxml-6.1.1-cp310-cp310-win_arm64.whl", hash = "sha256:8dadbe5b217ff35b6a8d16610dd710219b59b76d13f0e3f0d9f36786206e4485"}, + {file = "lxml-6.1.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:53b7d2b7a10b1c35c0a5e21e9224accf60c1bbfba523990732e521b2b73adef2"}, + {file = "lxml-6.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ff3f333630ab480244a1bff72043e511a91eb22e7595dead8653ee5612dd8f3d"}, + {file = "lxml-6.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a4bbea04c97f6d78a48e3fbc1cb9116d2780b1b39e03a23f6eb9b603fd61f510"}, + {file = "lxml-6.1.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:db1d75f6617a49c1c01bc7023713e0ff59ab32c9579ae62a7674c0e34f3b0b0a"}, + {file = "lxml-6.1.1-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a12689be69a28ddaa0ab99a5a1137da2afd5f8f16df7b5680b66f616d3eda1d"}, + {file = "lxml-6.1.1-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b73c339ae29b90fd2d06e58ebd555a751bde9cd6bbd36cc0281b9a2c94e9d8"}, + {file = "lxml-6.1.1-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:752d3bbfe874715ccd0aec7f88d7fc623c0f1fd7aa7b3238a084e017bad2a009"}, + {file = "lxml-6.1.1-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:6b1761fbf9ec984e2e9d9c589ef5f5fd684b7c19f92aadd567a26c5224958db6"}, + {file = "lxml-6.1.1-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d680fbcb768404c601ecb43519ecd8461f6954cb11c06a78962f666832ccfca8"}, + {file = "lxml-6.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:162af1091cd785f2f27e62d3547ae9bc58ec5c86dd314d67021fd02463708d83"}, + {file = "lxml-6.1.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:e9308ff8241c532df3f3e570f9a5aeed6c853f888512ba4b75638d7c11c95ef6"}, + {file = "lxml-6.1.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:5f6994074ebae6ffb04447268e37dc16edc304f9859cf91acb86e0af6c1b395c"}, + {file = "lxml-6.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:80c2dfadb855da477cf73373ad29a333535dedb9b12bad02c9814c8e2b43bf08"}, + {file = "lxml-6.1.1-cp311-cp311-win32.whl", hash = "sha256:30a89d3ac8faec007453fb541f3f46807eeec88edd5826f6e3fe001752a2c621"}, + {file = "lxml-6.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:abbefa31eee84842140f67acef1c828e28bba8bbf0c3bc6e5492a9af88152c28"}, + {file = "lxml-6.1.1-cp311-cp311-win_arm64.whl", hash = "sha256:dcb292aa7fe485ceff7af4f92e46c5af397daec5dff64871a528f0fc47a3cc5b"}, + {file = "lxml-6.1.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:104c09bda8d2a562824c0e319d0768ce26a779b7601e0931d33b09b53c392ef7"}, + {file = "lxml-6.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:25c6997a9a534e016695a0ba06b2f07945de682731ff01065b6d5a4474179da1"}, + {file = "lxml-6.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c921ba5c51e4e9f63b8b00267d06566e1f63407408a0496da2d1d0bfc819c7fc"}, + {file = "lxml-6.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:54a7f95e4de5fb94e2f9f4b9055c6ba33bf3d628fd77a1d647c5923caa2cdcdc"}, + {file = "lxml-6.1.1-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f2ec43df44b1f76249ee0a615334f9b5b060e1c8bd90e706dad2d14d02f383"}, + {file = "lxml-6.1.1-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:70ef8a7e102a1508f8121aae5b0867abd663f72c14f0a9c937e6554cb4587b7b"}, + {file = "lxml-6.1.1-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ebe6af670449830d6d9b752c256a983291c766a1365ba5d5460048f9e33a7818"}, + {file = "lxml-6.1.1-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:27acc820660aaffa4f7c087f29120e12980f7779d56d8492d263170111284740"}, + {file = "lxml-6.1.1-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:1db753c9115ec7100d073b744d17e25e88a8f90f5c39b2f5dd878149af59671f"}, + {file = "lxml-6.1.1-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c4f469aebd783bb741c2ecb2a681008fd26bfe5c16a9a72ed5467f834e810df2"}, + {file = "lxml-6.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:766b010012d59470072c1816b5b6c69f1d243e5db36ea5968e94accf430a4635"}, + {file = "lxml-6.1.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b8d812c6011c08b8111a15e54dd990b8923692d80adf35488bee34026c35accf"}, + {file = "lxml-6.1.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:fe0306bd29505a9177aac19f1877174b0e7422c222a59f70b2cd41633448c3dc"}, + {file = "lxml-6.1.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:5ba186ad207446c65d3bb3d3e0412b032b1d9f595e59861e2354798c5703d955"}, + {file = "lxml-6.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aa366a1e55b8ebfe8ca8ddc3cfe75c8ebade181aeb0f661d0cb05986b647f72a"}, + {file = "lxml-6.1.1-cp312-cp312-win32.whl", hash = "sha256:126c93f7f56f0eda92f6d8c619edc463a4f23d9252f1c9d0405a76f25fa9f11a"}, + {file = "lxml-6.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:26e6eda8d38c1fcab1090dd196ee87cbd13788e531937610e2589085de074e77"}, + {file = "lxml-6.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:6540377fbd53fe1b629172288c464fb18db11ce1fa7dc15891da10aa9dcc3e7f"}, + {file = "lxml-6.1.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:68a9198d0fc122d14bb76837de9aa80cf84caed990b5b237f532ed87d3706736"}, + {file = "lxml-6.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7d47866cb32fb503450b6edc9df355d10dc49836af2e89901bd6ac6b0896d9d9"}, + {file = "lxml-6.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb7c9811bfaa8b1ed5ed319f5d370dfbcaa59d52ea64be2a5a85e18195930354"}, + {file = "lxml-6.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:762ff394d5bd56da0cf034a23dcce4e13923f15321a2adfa2ac00201dc6d3fca"}, + {file = "lxml-6.1.1-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a088f287f7d8275a33c07f2cac6c50b9319309a0200a39e7e75d80c707723099"}, + {file = "lxml-6.1.1-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e902da4b04e6b52e5893900d4b8ab46068f75f3561f01bf1080957f9fd932ed6"}, + {file = "lxml-6.1.1-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1d4962d4c66bf830a7e59ed6cfc17d148149898a3aefa8ec6e59763e6e3ed085"}, + {file = "lxml-6.1.1-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:581d4c8ae690a6609e64862dd6b7c2489635c2d13907fc2b20f2bc200ff1d21e"}, + {file = "lxml-6.1.1-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:876e1ff5930ed8bf295ec5ef9a8155e9b6b1876bbf1deed8b3a8069311875a8f"}, + {file = "lxml-6.1.1-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9eb9b5a968f6e0f6d640092a567e14529ff8cea2e29d00da6f78a79fa49f013c"}, + {file = "lxml-6.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:aa49e06d94aba782c6a02eecb7e507969e7e7a41b267f1b359bb35585f295d5b"}, + {file = "lxml-6.1.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:70cdfd80589d59e43e18005dd7244e8895e93db8ab6a620b7e23df5445a4e3d2"}, + {file = "lxml-6.1.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:aad9aa39483ed8ec44d6d2e59e5b98a0d80676ef0d92f44bfc374836111f62f5"}, + {file = "lxml-6.1.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:d49514be2f28d895c38cf9d2b72d7b9a07d00314519f456c0b50b53cfcf4c785"}, + {file = "lxml-6.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:47402e62c52ff5988c1e8c6c63177f5708bccf48e366dea4e3dcf1e645e04947"}, + {file = "lxml-6.1.1-cp313-cp313-win32.whl", hash = "sha256:3483644525531e1d5762b0c44a8e18b6efba321b6dcf8a8952de10b037618bca"}, + {file = "lxml-6.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:a10bd2fd62e8ce916ececb342f348f190724a098c1faa056fdfb2a22ad5e8660"}, + {file = "lxml-6.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:424aa57aca0897eb922aef34395bd1289b3b6f04e6bae20ea123c0c7e333cffc"}, + {file = "lxml-6.1.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:19b7ab10b210b0b3ad7985d9ac4eb66ab09a90b20fe6e2f7ba55d01a234345d0"}, + {file = "lxml-6.1.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:c08e5c694306507275f2290073350c4f32e383db15213b2c69e7ff39c1193840"}, + {file = "lxml-6.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:74a9717fd0d82effef5c2854f0d917231d5324b5a3eb7275c43ac9fa32f97a14"}, + {file = "lxml-6.1.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:efe0374196335f93b53269acd811b944f2e6bdc88e8894f214bd636455484909"}, + {file = "lxml-6.1.1-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac931cdc9442c1763b8a8f6cd62c0c938737eafc5be75eff88df55fc73bc0d00"}, + {file = "lxml-6.1.1-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:aee395f5d0927f947758b4ec119fd5fc8ec71f07a1c5c52077b30b04c0fa6955"}, + {file = "lxml-6.1.1-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9395002973c827b3ed67db77e6ec09f092919a587022174554096a269378fb13"}, + {file = "lxml-6.1.1-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:73bc2086f141224ebddb7fc5c6a36ca58b31b94b561e1dfe8e073e3270fad1e7"}, + {file = "lxml-6.1.1-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:3779def59032b81e44a5f70096ef6bf2082f8d901937dca354474ba09782e245"}, + {file = "lxml-6.1.1-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:86c89b9d55ebf820ad7c90bc533410f0d098054f293351f10603c0c46ff598f5"}, + {file = "lxml-6.1.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:19607c6bbff2a44cf3fe8250abccd20942d3462473e0a721d01d379ed017e462"}, + {file = "lxml-6.1.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:c6ed5141a5c7507cf3ee76bd363b0d6f801e3321adc35b5d825a23115faa5465"}, + {file = "lxml-6.1.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:62aeb7e85b5d60320b9d77eef2e773994e2c0ce10121b277e0a19804e1654a5a"}, + {file = "lxml-6.1.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:b1b963fd8f5caa68e99dfae060d54de1fe9cba899b8718b44a00cdca53c3e590"}, + {file = "lxml-6.1.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:63876be28efefa04a1df615b46770e82042cce445cfdce55160522f57b231ccb"}, + {file = "lxml-6.1.1-cp314-cp314-win32.whl", hash = "sha256:7f7a92e8583f06b1fd49d01158143b8461cfcd135dcb10ec807270a3051bd603"}, + {file = "lxml-6.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:b2d444f2e66624d68e9c6b211e28a76e22fff5fcabcfff4deac18b529b7d4137"}, + {file = "lxml-6.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:3fd9728a2735fda14f4e8235830c86b539e9661e849665bf926d3f867943b4bf"}, + {file = "lxml-6.1.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:787b2496d0dbe8cd180984e8d29e3a6f76e7ea34db781cb3bd55e4ba1ef8b4ee"}, + {file = "lxml-6.1.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:2c8daa471358dc2d6fcf02165e80ec68f77871a286df95bc5cc3816153b0fd2c"}, + {file = "lxml-6.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:acd7d70b64c0aae0c7922cca83d288a16f5f6da523637697872253415269baef"}, + {file = "lxml-6.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4f0dd2f01f9f8a89f565d000e03abcf0a13d692a346c8d22f628d49af098777a"}, + {file = "lxml-6.1.1-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b7e8a14c8634bf6f7a568634cb395305a6d964aeb5b7ee32248094bed3a7e2c"}, + {file = "lxml-6.1.1-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:86281fbdd6a8162756f8d603f37e3435bfa38043adb79c6dc6a2dfee065e7525"}, + {file = "lxml-6.1.1-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5d7152ec39ca7c402d8fb9bad86140a15b9503bd0c54484e3f1bbe3dd37ceca"}, + {file = "lxml-6.1.1-cp314-cp314t-manylinux_2_28_i686.whl", hash = "sha256:88d8cb75b9d82858497a5393e3c63cfbf03035225e4b35a49ed7ccb151e4dc0e"}, + {file = "lxml-6.1.1-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:f64ec5397ea6a41fc1b4af0380d79b44a755b5531dcaccd9940fb260dca93038"}, + {file = "lxml-6.1.1-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d34bbf07dbc7ca5970671b1512e928991fb5e9d95365636c9b2d8b4f53af405e"}, + {file = "lxml-6.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:17e0e18d4ad8adbd0399291bc44845b69d9dd68439a3cdebdf35ff902ec05072"}, + {file = "lxml-6.1.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:3ab541146f1f6968c462d6c2ac495148e8cdba2f8347700b2141b6ec5a75bf52"}, + {file = "lxml-6.1.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:2a0217714657e023ef4293500f65aa20fce6164c8fd6b08fa5bd4a859fb14b9b"}, + {file = "lxml-6.1.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:05a82eb6e1530a64f26225b55cbd178113bd0b5af1c2b625f25e5296742c26d2"}, + {file = "lxml-6.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9e36f163528fc50cbef305f02a5fd66d404edf7049cdaff211dbc2cba5a7013e"}, + {file = "lxml-6.1.1-cp314-cp314t-win32.whl", hash = "sha256:649dda677cf3bd6ac9ae14007ba0c824ded8ce5808b53fc7431d9140399118c1"}, + {file = "lxml-6.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:793033d6c5cdf33a573f910d9bea14ef8f5771820411d118da8e1182edb53d5e"}, + {file = "lxml-6.1.1-cp314-cp314t-win_arm64.whl", hash = "sha256:58bb955caba94e467d2a96da17660d2d704e0675894cba21ab8a775b8621fd1c"}, + {file = "lxml-6.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6689e828a94eee4f139408c337bb198e014724bb8a8c26d3cfac49d119ed69a6"}, + {file = "lxml-6.1.1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bdebcc8a75d38c7598dfb2c9ed852d7a9eb4a10d6e2d0764b919b802bf32ac88"}, + {file = "lxml-6.1.1-cp38-cp38-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8be8ad51249698103d24b0571df35a10990fbe93dd043b6c024172189485f5e3"}, + {file = "lxml-6.1.1-cp38-cp38-manylinux_2_28_i686.whl", hash = "sha256:76447f65250ed2501ead1a1552f5ce8edff159a86f308348e6a9c4acb5e1f1b4"}, + {file = "lxml-6.1.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ffecec8eb889b58ba9be5b95fb1cc78e22ea8eedea38e8736a1568fe1979250e"}, + {file = "lxml-6.1.1-cp38-cp38-win32.whl", hash = "sha256:c674693f055fa2495de12292cb45e9944199d8eaef5a2dec45175c7c61cb73e3"}, + {file = "lxml-6.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:55b03549819867ea141c0202242c4816c82e52ec36e7e648db9d8da5a3dc3ed6"}, + {file = "lxml-6.1.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c9f79d5325907f13e1be0b3e4dacc1049d1dffc4aeee3c995284bea5fe0fab7d"}, + {file = "lxml-6.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:83b6b30eb131da7a75b601f28c5d6971e6ed3e887919bf6b6a1ad3c2df289080"}, + {file = "lxml-6.1.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:441dd227fa0690eb9fc81edabc63cdcefc212bba99b906dcf6e32cc1a9d3e533"}, + {file = "lxml-6.1.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e07c65f443c887bbcf31cc1771d932ecc192a5273943589b3c7572b749f1ffb2"}, + {file = "lxml-6.1.1-cp39-cp39-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5bec7d03d78d853597d6107854c2310ce3f761fd218fe9fe91d5101fcf6c2efe"}, + {file = "lxml-6.1.1-cp39-cp39-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9f76acfb5f68ba982635a53fd985a8044be98a35b43232c2a1ee235ffab3e1dd"}, + {file = "lxml-6.1.1-cp39-cp39-manylinux_2_28_i686.whl", hash = "sha256:8d43ca737b20e106e4aebc42b2f3ae19f00ba63d7eb731698ee083d72d15646f"}, + {file = "lxml-6.1.1-cp39-cp39-manylinux_2_31_armv7l.whl", hash = "sha256:32ab449a5486f6c758e849bb86710d0e45edc24a04e250c01555f8f5653958f8"}, + {file = "lxml-6.1.1-cp39-cp39-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:53c909b62a0532183542fed00c5a7218258c56292d409bc789886fe1cb04c438"}, + {file = "lxml-6.1.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:640f97d43d867bcb9c75b3af013b64850756b746cb6bce8ace83b70da3abba9d"}, + {file = "lxml-6.1.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:469e3618338bd7ab5beb412d2439825479fcf0dab99e394ca563dbc4eaf6c834"}, + {file = "lxml-6.1.1-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:aae97dfdb60715c164419ac2532a76d013c3918a665eb6cb7288098b5f349aaf"}, + {file = "lxml-6.1.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c9a4b821dc7055bf9e05ff5719e18ec501f75c0f0bbfabd573b277559780833d"}, + {file = "lxml-6.1.1-cp39-cp39-win32.whl", hash = "sha256:639f6c857d91d9be29bd7502348d6736dab168b54b5158cd899abf11684dc186"}, + {file = "lxml-6.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:34c2d737beabfe35baada43941ed519251e9a12e779031496bcd5d539fcfd730"}, + {file = "lxml-6.1.1-cp39-cp39-win_arm64.whl", hash = "sha256:07a4a68e286ee7a1ed7dfb8af83e615757c0ccfe9f18c6b4ea6771388d9ba8c9"}, + {file = "lxml-6.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:31033dc34636ea6b7d5cc11b1ddbda78a14de858ba9d3e1ed4b69a3085bc521e"}, + {file = "lxml-6.1.1-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3893c14c4b6ac5b2d54ba8cf03e99fe5104e592de491f19bd6b82756c09f8004"}, + {file = "lxml-6.1.1-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c07da4cebf6889f03ebac8d238f62318e29f495de0aa18a51ea14e61ae907e2e"}, + {file = "lxml-6.1.1-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f6f0ce10945fab9c4c06ce14e22af9059d1a87493a9af4501a5b0b9187e21cf2"}, + {file = "lxml-6.1.1-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f8844cd288697c6425c9beba919302241e3278871dc6519515e72b04e987abcf"}, + {file = "lxml-6.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:ed21202aec73cda4d55d1ce57b389aadb90ffb044e6cd1080b8347efe1b1ec84"}, + {file = "lxml-6.1.1.tar.gz", hash = "sha256:ba96ae44888e0185281e937633a743ea90d5a196c6000f82565ebb0580012d40"}, ] [package.extras] cssselect = ["cssselect (>=0.7)"] +html-clean = ["lxml_html_clean"] html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] -source = ["Cython (>=3.0.7)"] [[package]] name = "mako" -version = "1.3.2" +version = "1.3.12" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." optional = false python-versions = ">=3.8" files = [ - {file = "Mako-1.3.2-py3-none-any.whl", hash = "sha256:32a99d70754dfce237019d17ffe4a282d2d3351b9c476e90d8a60e63f133b80c"}, - {file = "Mako-1.3.2.tar.gz", hash = "sha256:2a0c8ad7f6274271b3bb7467dd37cf9cc6dab4bc19cb69a4ef10669402de698e"}, + {file = "mako-1.3.12-py3-none-any.whl", hash = "sha256:8f61569480282dbf557145ce441e4ba888be453c30989f879f0d652e39f53ea9"}, + {file = "mako-1.3.12.tar.gz", hash = "sha256:9f778e93289bd410bb35daadeb4fc66d95a746f0b75777b942088b7fd7af550a"}, ] [package.dependencies] @@ -2382,13 +2871,13 @@ testing = ["pytest"] [[package]] name = "markdown-it-py" -version = "3.0.0" +version = "4.2.0" description = "Python port of markdown-it. Markdown parsing, done right!" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, - {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, + {file = "markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a"}, + {file = "markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49"}, ] [package.dependencies] @@ -2396,118 +2885,173 @@ mdurl = ">=0.1,<1.0" [package.extras] benchmarking = ["psutil", "pytest", "pytest-benchmark"] -code-style = ["pre-commit (>=3.0,<4.0)"] -compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "markdown-it-pyrs", "mistletoe (>=1.0,<2.0)", "mistune (>=3.0,<4.0)", "panflute (>=2.3,<3.0)"] linkify = ["linkify-it-py (>=1,<3)"] -plugins = ["mdit-py-plugins"] +plugins = ["mdit-py-plugins (>=0.5.0)"] profiling = ["gprof2dot"] -rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] -testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] +rtd = ["ipykernel", "jupyter_sphinx", "mdit-py-plugins (>=0.5.0)", "myst-parser", "pyyaml", "sphinx", "sphinx-book-theme (>=1.0,<2.0)", "sphinx-copybutton", "sphinx-design"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions", "pytest-timeout", "requests"] [[package]] name = "markupsafe" -version = "2.1.4" +version = "3.0.3" description = "Safely add untrusted strings to HTML/XML markup." optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de8153a7aae3835484ac168a9a9bdaa0c5eee4e0bc595503c95d53b942879c84"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e888ff76ceb39601c59e219f281466c6d7e66bd375b4ec1ce83bcdc68306796b"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0b838c37ba596fcbfca71651a104a611543077156cb0a26fe0c475e1f152ee8"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac1ebf6983148b45b5fa48593950f90ed6d1d26300604f321c74a9ca1609f8e"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fbad3d346df8f9d72622ac71b69565e621ada2ce6572f37c2eae8dacd60385d"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5291d98cd3ad9a562883468c690a2a238c4a6388ab3bd155b0c75dd55ece858"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a7cc49ef48a3c7a0005a949f3c04f8baa5409d3f663a1b36f0eba9bfe2a0396e"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b83041cda633871572f0d3c41dddd5582ad7d22f65a72eacd8d3d6d00291df26"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-win32.whl", hash = "sha256:0c26f67b3fe27302d3a412b85ef696792c4a2386293c53ba683a89562f9399b0"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-win_amd64.whl", hash = "sha256:a76055d5cb1c23485d7ddae533229039b850db711c554a12ea64a0fd8a0129e2"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9e9e3c4020aa2dc62d5dd6743a69e399ce3de58320522948af6140ac959ab863"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0042d6a9880b38e1dd9ff83146cc3c9c18a059b9360ceae207805567aacccc69"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55d03fea4c4e9fd0ad75dc2e7e2b6757b80c152c032ea1d1de487461d8140efc"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ab3a886a237f6e9c9f4f7d272067e712cdb4efa774bef494dccad08f39d8ae6"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abf5ebbec056817057bfafc0445916bb688a255a5146f900445d081db08cbabb"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e1a0d1924a5013d4f294087e00024ad25668234569289650929ab871231668e7"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e7902211afd0af05fbadcc9a312e4cf10f27b779cf1323e78d52377ae4b72bea"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c669391319973e49a7c6230c218a1e3044710bc1ce4c8e6eb71f7e6d43a2c131"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-win32.whl", hash = "sha256:31f57d64c336b8ccb1966d156932f3daa4fee74176b0fdc48ef580be774aae74"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-win_amd64.whl", hash = "sha256:54a7e1380dfece8847c71bf7e33da5d084e9b889c75eca19100ef98027bd9f56"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a76cd37d229fc385738bd1ce4cba2a121cf26b53864c1772694ad0ad348e509e"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:987d13fe1d23e12a66ca2073b8d2e2a75cec2ecb8eab43ff5624ba0ad42764bc"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5244324676254697fe5c181fc762284e2c5fceeb1c4e3e7f6aca2b6f107e60dc"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78bc995e004681246e85e28e068111a4c3f35f34e6c62da1471e844ee1446250"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4d176cfdfde84f732c4a53109b293d05883e952bbba68b857ae446fa3119b4f"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f9917691f410a2e0897d1ef99619fd3f7dd503647c8ff2475bf90c3cf222ad74"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:f06e5a9e99b7df44640767842f414ed5d7bedaaa78cd817ce04bbd6fd86e2dd6"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:396549cea79e8ca4ba65525470d534e8a41070e6b3500ce2414921099cb73e8d"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-win32.whl", hash = "sha256:f6be2d708a9d0e9b0054856f07ac7070fbe1754be40ca8525d5adccdbda8f475"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-win_amd64.whl", hash = "sha256:5045e892cfdaecc5b4c01822f353cf2c8feb88a6ec1c0adef2a2e705eef0f656"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7a07f40ef8f0fbc5ef1000d0c78771f4d5ca03b4953fc162749772916b298fc4"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d18b66fe626ac412d96c2ab536306c736c66cf2a31c243a45025156cc190dc8a"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:698e84142f3f884114ea8cf83e7a67ca8f4ace8454e78fe960646c6c91c63bfa"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a3b78a5af63ec10d8604180380c13dcd870aba7928c1fe04e881d5c792dc4e"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:15866d7f2dc60cfdde12ebb4e75e41be862348b4728300c36cdf405e258415ec"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6aa5e2e7fc9bc042ae82d8b79d795b9a62bd8f15ba1e7594e3db243f158b5565"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:54635102ba3cf5da26eb6f96c4b8c53af8a9c0d97b64bdcb592596a6255d8518"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-win32.whl", hash = "sha256:3583a3a3ab7958e354dc1d25be74aee6228938312ee875a22330c4dc2e41beb0"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-win_amd64.whl", hash = "sha256:d6e427c7378c7f1b2bef6a344c925b8b63623d3321c09a237b7cc0e77dd98ceb"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:bf1196dcc239e608605b716e7b166eb5faf4bc192f8a44b81e85251e62584bd2"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4df98d4a9cd6a88d6a585852f56f2155c9cdb6aec78361a19f938810aa020954"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b835aba863195269ea358cecc21b400276747cc977492319fd7682b8cd2c253d"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23984d1bdae01bee794267424af55eef4dfc038dc5d1272860669b2aa025c9e3"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c98c33ffe20e9a489145d97070a435ea0679fddaabcafe19982fe9c971987d5"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9896fca4a8eb246defc8b2a7ac77ef7553b638e04fbf170bff78a40fa8a91474"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b0fe73bac2fed83839dbdbe6da84ae2a31c11cfc1c777a40dbd8ac8a6ed1560f"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c7556bafeaa0a50e2fe7dc86e0382dea349ebcad8f010d5a7dc6ba568eaaa789"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-win32.whl", hash = "sha256:fc1a75aa8f11b87910ffd98de62b29d6520b6d6e8a3de69a70ca34dea85d2a8a"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-win_amd64.whl", hash = "sha256:3a66c36a3864df95e4f62f9167c734b3b1192cb0851b43d7cc08040c074c6279"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:765f036a3d00395a326df2835d8f86b637dbaf9832f90f5d196c3b8a7a5080cb"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:21e7af8091007bf4bebf4521184f4880a6acab8df0df52ef9e513d8e5db23411"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5c31fe855c77cad679b302aabc42d724ed87c043b1432d457f4976add1c2c3e"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7653fa39578957bc42e5ebc15cf4361d9e0ee4b702d7d5ec96cdac860953c5b4"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47bb5f0142b8b64ed1399b6b60f700a580335c8e1c57f2f15587bd072012decc"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fe8512ed897d5daf089e5bd010c3dc03bb1bdae00b35588c49b98268d4a01e00"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:36d7626a8cca4d34216875aee5a1d3d654bb3dac201c1c003d182283e3205949"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b6f14a9cd50c3cb100eb94b3273131c80d102e19bb20253ac7bd7336118a673a"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-win32.whl", hash = "sha256:c8f253a84dbd2c63c19590fa86a032ef3d8cc18923b8049d91bcdeeb2581fbf6"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-win_amd64.whl", hash = "sha256:8b570a1537367b52396e53325769608f2a687ec9a4363647af1cded8928af959"}, - {file = "MarkupSafe-2.1.4.tar.gz", hash = "sha256:3aae9af4cac263007fd6309c64c6ab4506dd2b79382d9d19a1994f9240b8db4f"}, + {file = "markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559"}, + {file = "markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1"}, + {file = "markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa"}, + {file = "markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8"}, + {file = "markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1"}, + {file = "markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad"}, + {file = "markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a"}, + {file = "markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19"}, + {file = "markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01"}, + {file = "markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c"}, + {file = "markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e"}, + {file = "markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b"}, + {file = "markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d"}, + {file = "markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c"}, + {file = "markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f"}, + {file = "markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795"}, + {file = "markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12"}, + {file = "markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed"}, + {file = "markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5"}, + {file = "markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485"}, + {file = "markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73"}, + {file = "markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287"}, + {file = "markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe"}, + {file = "markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe"}, + {file = "markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9"}, + {file = "markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581"}, + {file = "markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4"}, + {file = "markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab"}, + {file = "markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa"}, + {file = "markupsafe-3.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26"}, + {file = "markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d"}, + {file = "markupsafe-3.0.3-cp39-cp39-win32.whl", hash = "sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7"}, + {file = "markupsafe-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e"}, + {file = "markupsafe-3.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8"}, + {file = "markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698"}, ] [[package]] name = "matplotlib" -version = "3.8.2" +version = "3.10.9" description = "Python plotting package" optional = false -python-versions = ">=3.9" -files = [ - {file = "matplotlib-3.8.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:09796f89fb71a0c0e1e2f4bdaf63fb2cefc84446bb963ecdeb40dfee7dfa98c7"}, - {file = "matplotlib-3.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6f9c6976748a25e8b9be51ea028df49b8e561eed7809146da7a47dbecebab367"}, - {file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b78e4f2cedf303869b782071b55fdde5987fda3038e9d09e58c91cc261b5ad18"}, - {file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e208f46cf6576a7624195aa047cb344a7f802e113bb1a06cfd4bee431de5e31"}, - {file = "matplotlib-3.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:46a569130ff53798ea5f50afce7406e91fdc471ca1e0e26ba976a8c734c9427a"}, - {file = "matplotlib-3.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:830f00640c965c5b7f6bc32f0d4ce0c36dfe0379f7dd65b07a00c801713ec40a"}, - {file = "matplotlib-3.8.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d86593ccf546223eb75a39b44c32788e6f6440d13cfc4750c1c15d0fcb850b63"}, - {file = "matplotlib-3.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9a5430836811b7652991939012f43d2808a2db9b64ee240387e8c43e2e5578c8"}, - {file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9576723858a78751d5aacd2497b8aef29ffea6d1c95981505877f7ac28215c6"}, - {file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ba9cbd8ac6cf422f3102622b20f8552d601bf8837e49a3afed188d560152788"}, - {file = "matplotlib-3.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:03f9d160a29e0b65c0790bb07f4f45d6a181b1ac33eb1bb0dd225986450148f0"}, - {file = "matplotlib-3.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:3773002da767f0a9323ba1a9b9b5d00d6257dbd2a93107233167cfb581f64717"}, - {file = "matplotlib-3.8.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:4c318c1e95e2f5926fba326f68177dee364aa791d6df022ceb91b8221bd0a627"}, - {file = "matplotlib-3.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:091275d18d942cf1ee9609c830a1bc36610607d8223b1b981c37d5c9fc3e46a4"}, - {file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b0f3b8ea0e99e233a4bcc44590f01604840d833c280ebb8fe5554fd3e6cfe8d"}, - {file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7b1704a530395aaf73912be741c04d181f82ca78084fbd80bc737be04848331"}, - {file = "matplotlib-3.8.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:533b0e3b0c6768eef8cbe4b583731ce25a91ab54a22f830db2b031e83cca9213"}, - {file = "matplotlib-3.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:0f4fc5d72b75e2c18e55eb32292659cf731d9d5b312a6eb036506304f4675630"}, - {file = "matplotlib-3.8.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:deaed9ad4da0b1aea77fe0aa0cebb9ef611c70b3177be936a95e5d01fa05094f"}, - {file = "matplotlib-3.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:172f4d0fbac3383d39164c6caafd3255ce6fa58f08fc392513a0b1d3b89c4f89"}, - {file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7d36c2209d9136cd8e02fab1c0ddc185ce79bc914c45054a9f514e44c787917"}, - {file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5864bdd7da445e4e5e011b199bb67168cdad10b501750367c496420f2ad00843"}, - {file = "matplotlib-3.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ef8345b48e95cee45ff25192ed1f4857273117917a4dcd48e3905619bcd9c9b8"}, - {file = "matplotlib-3.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:7c48d9e221b637c017232e3760ed30b4e8d5dfd081daf327e829bf2a72c731b4"}, - {file = "matplotlib-3.8.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:aa11b3c6928a1e496c1a79917d51d4cd5d04f8a2e75f21df4949eeefdf697f4b"}, - {file = "matplotlib-3.8.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1095fecf99eeb7384dabad4bf44b965f929a5f6079654b681193edf7169ec20"}, - {file = "matplotlib-3.8.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:bddfb1db89bfaa855912261c805bd0e10218923cc262b9159a49c29a7a1c1afa"}, - {file = "matplotlib-3.8.2.tar.gz", hash = "sha256:01a978b871b881ee76017152f1f1a0cbf6bd5f7b8ff8c96df0df1bd57d8755a1"}, +python-versions = ">=3.10" +files = [ + {file = "matplotlib-3.10.9-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77210dce9cb8153dffc967efaae990543392563d5a376d4dd8539bebcb0ed217"}, + {file = "matplotlib-3.10.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1e7698ac9868428e84d2c967424803b2472ff7167d9d6590d4204ed775343c3b"}, + {file = "matplotlib-3.10.9-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1aa972116abb4c9d201bf245620b433726cb6856f3bef6a78f776a00f5c92d37"}, + {file = "matplotlib-3.10.9-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae2f11957b27ce53497dd4d7b235c4d4f1faf383dfb39d0c5beb833bff883294"}, + {file = "matplotlib-3.10.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b049278ddce116aaa1c1377ebf58adea909132dfce0281cf7e3a1ea9fc2e2c65"}, + {file = "matplotlib-3.10.9-cp310-cp310-win_amd64.whl", hash = "sha256:82834c3c292d24d3a8aae77cd2d20019de69d692a34a970e4fdb8d33e2ea3dda"}, + {file = "matplotlib-3.10.9-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:68cfdcede415f7c8f5577b03303dd94526cdb6d11036cecdc205e08733b2d2bb"}, + {file = "matplotlib-3.10.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfca0129678bd56379db26c52b5d77ed7de314c047492fbdc763aa7501710cfb"}, + {file = "matplotlib-3.10.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8e436d155fa8a3399dc62683f8f5d0e2e50d25d0144a73edd73f82eec8f4abfb"}, + {file = "matplotlib-3.10.9-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56fc0bd271b00025c6edfdc7c2dcd247372c8e1544971d62e1dc7c17367e8bf9"}, + {file = "matplotlib-3.10.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a5a6104ed666402ba5106d7f36e0e0cdca4e8d7fa4d39708ca88019e2835a2eb"}, + {file = "matplotlib-3.10.9-cp311-cp311-win_amd64.whl", hash = "sha256:d730e984eddf56974c3e72b6129c7ca462ac38dc624338f4b0b23eb23ecba00f"}, + {file = "matplotlib-3.10.9-cp311-cp311-win_arm64.whl", hash = "sha256:51bf0ddbdc598e060d46c16b5590708f81a1624cefbaaf62f6a81bf9285b8c80"}, + {file = "matplotlib-3.10.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f0c3c28d9fbcc1fe7a03be236d73430cf6409c41fb2383a7ac52fe932b072cb1"}, + {file = "matplotlib-3.10.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41cb28c2bd769aa3e98322c6ab09854cbcc52ab69d2759d681bba3e327b2b320"}, + {file = "matplotlib-3.10.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ae20801130378b82d647ff5047c07316295b68dc054ca6b3c13519d0ea624285"}, + {file = "matplotlib-3.10.9-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6c63ebcd8b4b169eb2f5c200552ae6b8be8999a005b6b507ed76fb8d7d674fe2"}, + {file = "matplotlib-3.10.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d75d11c949914165976c621b2324f9ef162af7ebf4b057ddf95dd1dba7e5edcf"}, + {file = "matplotlib-3.10.9-cp312-cp312-win_amd64.whl", hash = "sha256:d091f9d758b34aaaaa6331d13574bf01891d903b3dec59bfff458ef7551de5d6"}, + {file = "matplotlib-3.10.9-cp312-cp312-win_arm64.whl", hash = "sha256:10cc5ce06d10231c36f40e875f3c7e8050362a4ee8f0ee5d29a6b3277d57bb42"}, + {file = "matplotlib-3.10.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b580440f1ff81a0e34122051a3dfabb7e4b7f9e380629929bde0eff9af72165f"}, + {file = "matplotlib-3.10.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b1b745c489cd1a77a0dc1120a05dc87af9798faebc913601feb8c73d89bf2d1e"}, + {file = "matplotlib-3.10.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8f3bcac1ca5ed000a6f4337d47ba67dfddf37ed6a46c15fd7f014997f7bf865f"}, + {file = "matplotlib-3.10.9-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a8d66a55def891c33147ba3ba9bfcabf0b526a43764c818acbb4525e5ed0838"}, + {file = "matplotlib-3.10.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d843374407c4017a6403b59c6c81606773d136f3259d5b6da3131bc814542cc2"}, + {file = "matplotlib-3.10.9-cp313-cp313-win_amd64.whl", hash = "sha256:f4399f64b3e94cd500195490972ae1ee81170df1636fa15364d157d5bdd7b921"}, + {file = "matplotlib-3.10.9-cp313-cp313-win_arm64.whl", hash = "sha256:ba7b3b8ef09eab7df0e86e9ae086faa433efbfbdb46afcb3aa16aabf779469a8"}, + {file = "matplotlib-3.10.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:09218df8a93712bd6ea133e83a153c755448cf7868316c531cffcc43f69d1cc9"}, + {file = "matplotlib-3.10.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:82368699727bfb7b0182e1aa13082e3c08e092fa1a25d3e1fd92405bff96f6d4"}, + {file = "matplotlib-3.10.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3225f4e1edcb8c86c884ddf79ebe20ecd0a67d30188f279897554ccd8fded4dc"}, + {file = "matplotlib-3.10.9-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de2445a0c6690d21b7eb6ce071cebad6d40a2e9bdf10d039074a96ba19797b99"}, + {file = "matplotlib-3.10.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:b2b9516251cb89ff618d757daec0e2ed1bf21248013844a853d87ef85ab3081d"}, + {file = "matplotlib-3.10.9-cp313-cp313t-win_amd64.whl", hash = "sha256:e9fae004b941b23ff2edcf1567a857ed77bafc8086ffa258190462328434faf8"}, + {file = "matplotlib-3.10.9-cp313-cp313t-win_arm64.whl", hash = "sha256:6b63d9c7c769b88ab81e10dc86e4e0607cf56817b9f9e6cf24b2a5f1693b8e38"}, + {file = "matplotlib-3.10.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:172db52c9e683f5d12eaf57f0f54834190e12581fe1cc2a19595a8f5acb4e77d"}, + {file = "matplotlib-3.10.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:97e35e8d39ccc85859095e01a53847432ba9a53ddf7986f7a54a11b73d0e143f"}, + {file = "matplotlib-3.10.9-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aba1615dabe83188e19d4f75a253c6a08423e04c1425e64039f800050a69de6b"}, + {file = "matplotlib-3.10.9-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34cf8167e023ad956c15f36302911d5406bd99a9862c1a8499ea6f7c0e015dc2"}, + {file = "matplotlib-3.10.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:59476c6d29d612b8e9bb6ce8c5b631be6ba8f9e3a2421f22a02b192c7dd28716"}, + {file = "matplotlib-3.10.9-cp314-cp314-win_amd64.whl", hash = "sha256:336b9acc64d309063126edcdaca00db9373af3c476bb94388fe9c5a53ad13e6f"}, + {file = "matplotlib-3.10.9-cp314-cp314-win_arm64.whl", hash = "sha256:2dc9477819ffd78ad12a20df1d9d6a6bd4fec6aaa9072681465fddca052f1456"}, + {file = "matplotlib-3.10.9-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:da4e09638420548f31c354032a6250e473c68e5a4e96899b4844cf39ddea23fe"}, + {file = "matplotlib-3.10.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:345f6f68ecc8da0ca56fad2ea08fde1a115eda530079eca185d50a7bc3e146c6"}, + {file = "matplotlib-3.10.9-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4edcfbd8565339aa62f1cd4012f7180926fdbe71850f7b0d3c379c175cd6b66c"}, + {file = "matplotlib-3.10.9-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6be157fe17fc37cb95ac1d7374cf717ce9259616edec911a78d9d26dae8522d4"}, + {file = "matplotlib-3.10.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:4e42042d54db34fda4e95a7bd3e5789c2a995d2dad3eb8850232ee534092fbbf"}, + {file = "matplotlib-3.10.9-cp314-cp314t-win_amd64.whl", hash = "sha256:c27df8b3848f32a83d1767566595e43cfaa4460380974da06f4279a7ec143c39"}, + {file = "matplotlib-3.10.9-cp314-cp314t-win_arm64.whl", hash = "sha256:a49f1eadc84ca85fd72fa4e89e70e61bf86452df6f971af04b12c60761a0772c"}, + {file = "matplotlib-3.10.9-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1872fb212a05b729e649754a72d5da61d03e0554d76e80303b6f83d1d2c0552b"}, + {file = "matplotlib-3.10.9-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:985f2238880e2e69093f588f5fe2e46771747febf0649f3cf7f7b7480875317f"}, + {file = "matplotlib-3.10.9-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6640f75af2c6148293caa0a2b39dd806a492dd66c8a8b04035813e33d0fd2585"}, + {file = "matplotlib-3.10.9-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:42fb814efabe95c06c1994d8ab5a8385f43a249e23badd3ba931d4308e5bca20"}, + {file = "matplotlib-3.10.9-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f76e640a5268850bfda54b5131b1b1941cc685e42c5fa98ed9f2d64038308cba"}, + {file = "matplotlib-3.10.9-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3fc0364dfbe1d07f6d15c5ebd0c5bf89e126916e5a8667dd4a7a6e84c36653d4"}, + {file = "matplotlib-3.10.9.tar.gz", hash = "sha256:fd66508e8c6877d98e586654b608a0456db8d7e8a546eb1e2600efd957302358"}, ] [package.dependencies] @@ -2515,12 +3059,15 @@ contourpy = ">=1.0.1" cycler = ">=0.10" fonttools = ">=4.22.0" kiwisolver = ">=1.3.1" -numpy = ">=1.21,<2" +numpy = ">=1.23" packaging = ">=20.0" pillow = ">=8" -pyparsing = ">=2.3.1" +pyparsing = ">=3" python-dateutil = ">=2.7" +[package.extras] +dev = ["meson-python (>=0.13.1,<0.17.0)", "pybind11 (>=2.13.2,!=2.13.3)", "setuptools (>=64)", "setuptools_scm (>=7,<10)"] + [[package]] name = "mdurl" version = "0.1.2" @@ -2534,176 +3081,232 @@ files = [ [[package]] name = "msgpack" -version = "1.1.0" +version = "1.2.1" description = "MessagePack serializer" optional = false -python-versions = ">=3.8" -files = [ - {file = "msgpack-1.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7ad442d527a7e358a469faf43fda45aaf4ac3249c8310a82f0ccff9164e5dccd"}, - {file = "msgpack-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:74bed8f63f8f14d75eec75cf3d04ad581da6b914001b474a5d3cd3372c8cc27d"}, - {file = "msgpack-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:914571a2a5b4e7606997e169f64ce53a8b1e06f2cf2c3a7273aa106236d43dd5"}, - {file = "msgpack-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c921af52214dcbb75e6bdf6a661b23c3e6417f00c603dd2070bccb5c3ef499f5"}, - {file = "msgpack-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8ce0b22b890be5d252de90d0e0d119f363012027cf256185fc3d474c44b1b9e"}, - {file = "msgpack-1.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:73322a6cc57fcee3c0c57c4463d828e9428275fb85a27aa2aa1a92fdc42afd7b"}, - {file = "msgpack-1.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e1f3c3d21f7cf67bcf2da8e494d30a75e4cf60041d98b3f79875afb5b96f3a3f"}, - {file = "msgpack-1.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64fc9068d701233effd61b19efb1485587560b66fe57b3e50d29c5d78e7fef68"}, - {file = "msgpack-1.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:42f754515e0f683f9c79210a5d1cad631ec3d06cea5172214d2176a42e67e19b"}, - {file = "msgpack-1.1.0-cp310-cp310-win32.whl", hash = "sha256:3df7e6b05571b3814361e8464f9304c42d2196808e0119f55d0d3e62cd5ea044"}, - {file = "msgpack-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:685ec345eefc757a7c8af44a3032734a739f8c45d1b0ac45efc5d8977aa4720f"}, - {file = "msgpack-1.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3d364a55082fb2a7416f6c63ae383fbd903adb5a6cf78c5b96cc6316dc1cedc7"}, - {file = "msgpack-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:79ec007767b9b56860e0372085f8504db5d06bd6a327a335449508bbee9648fa"}, - {file = "msgpack-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6ad622bf7756d5a497d5b6836e7fc3752e2dd6f4c648e24b1803f6048596f701"}, - {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e59bca908d9ca0de3dc8684f21ebf9a690fe47b6be93236eb40b99af28b6ea6"}, - {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1da8f11a3dd397f0a32c76165cf0c4eb95b31013a94f6ecc0b280c05c91b59"}, - {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:452aff037287acb1d70a804ffd022b21fa2bb7c46bee884dbc864cc9024128a0"}, - {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8da4bf6d54ceed70e8861f833f83ce0814a2b72102e890cbdfe4b34764cdd66e"}, - {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:41c991beebf175faf352fb940bf2af9ad1fb77fd25f38d9142053914947cdbf6"}, - {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a52a1f3a5af7ba1c9ace055b659189f6c669cf3657095b50f9602af3a3ba0fe5"}, - {file = "msgpack-1.1.0-cp311-cp311-win32.whl", hash = "sha256:58638690ebd0a06427c5fe1a227bb6b8b9fdc2bd07701bec13c2335c82131a88"}, - {file = "msgpack-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fd2906780f25c8ed5d7b323379f6138524ba793428db5d0e9d226d3fa6aa1788"}, - {file = "msgpack-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d46cf9e3705ea9485687aa4001a76e44748b609d260af21c4ceea7f2212a501d"}, - {file = "msgpack-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5dbad74103df937e1325cc4bfeaf57713be0b4f15e1c2da43ccdd836393e2ea2"}, - {file = "msgpack-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:58dfc47f8b102da61e8949708b3eafc3504509a5728f8b4ddef84bd9e16ad420"}, - {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676e5be1b472909b2ee6356ff425ebedf5142427842aa06b4dfd5117d1ca8a2"}, - {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17fb65dd0bec285907f68b15734a993ad3fc94332b5bb21b0435846228de1f39"}, - {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a51abd48c6d8ac89e0cfd4fe177c61481aca2d5e7ba42044fd218cfd8ea9899f"}, - {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2137773500afa5494a61b1208619e3871f75f27b03bcfca7b3a7023284140247"}, - {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:398b713459fea610861c8a7b62a6fec1882759f308ae0795b5413ff6a160cf3c"}, - {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:06f5fd2f6bb2a7914922d935d3b8bb4a7fff3a9a91cfce6d06c13bc42bec975b"}, - {file = "msgpack-1.1.0-cp312-cp312-win32.whl", hash = "sha256:ad33e8400e4ec17ba782f7b9cf868977d867ed784a1f5f2ab46e7ba53b6e1e1b"}, - {file = "msgpack-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:115a7af8ee9e8cddc10f87636767857e7e3717b7a2e97379dc2054712693e90f"}, - {file = "msgpack-1.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:071603e2f0771c45ad9bc65719291c568d4edf120b44eb36324dcb02a13bfddf"}, - {file = "msgpack-1.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0f92a83b84e7c0749e3f12821949d79485971f087604178026085f60ce109330"}, - {file = "msgpack-1.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a1964df7b81285d00a84da4e70cb1383f2e665e0f1f2a7027e683956d04b734"}, - {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59caf6a4ed0d164055ccff8fe31eddc0ebc07cf7326a2aaa0dbf7a4001cd823e"}, - {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0907e1a7119b337971a689153665764adc34e89175f9a34793307d9def08e6ca"}, - {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65553c9b6da8166e819a6aa90ad15288599b340f91d18f60b2061f402b9a4915"}, - {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7a946a8992941fea80ed4beae6bff74ffd7ee129a90b4dd5cf9c476a30e9708d"}, - {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4b51405e36e075193bc051315dbf29168d6141ae2500ba8cd80a522964e31434"}, - {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4c01941fd2ff87c2a934ee6055bda4ed353a7846b8d4f341c428109e9fcde8c"}, - {file = "msgpack-1.1.0-cp313-cp313-win32.whl", hash = "sha256:7c9a35ce2c2573bada929e0b7b3576de647b0defbd25f5139dcdaba0ae35a4cc"}, - {file = "msgpack-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:bce7d9e614a04d0883af0b3d4d501171fbfca038f12c77fa838d9f198147a23f"}, - {file = "msgpack-1.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c40ffa9a15d74e05ba1fe2681ea33b9caffd886675412612d93ab17b58ea2fec"}, - {file = "msgpack-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1ba6136e650898082d9d5a5217d5906d1e138024f836ff48691784bbe1adf96"}, - {file = "msgpack-1.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0856a2b7e8dcb874be44fea031d22e5b3a19121be92a1e098f46068a11b0870"}, - {file = "msgpack-1.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:471e27a5787a2e3f974ba023f9e265a8c7cfd373632247deb225617e3100a3c7"}, - {file = "msgpack-1.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:646afc8102935a388ffc3914b336d22d1c2d6209c773f3eb5dd4d6d3b6f8c1cb"}, - {file = "msgpack-1.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:13599f8829cfbe0158f6456374e9eea9f44eee08076291771d8ae93eda56607f"}, - {file = "msgpack-1.1.0-cp38-cp38-win32.whl", hash = "sha256:8a84efb768fb968381e525eeeb3d92857e4985aacc39f3c47ffd00eb4509315b"}, - {file = "msgpack-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:879a7b7b0ad82481c52d3c7eb99bf6f0645dbdec5134a4bddbd16f3506947feb"}, - {file = "msgpack-1.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:53258eeb7a80fc46f62fd59c876957a2d0e15e6449a9e71842b6d24419d88ca1"}, - {file = "msgpack-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7e7b853bbc44fb03fbdba34feb4bd414322180135e2cb5164f20ce1c9795ee48"}, - {file = "msgpack-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3e9b4936df53b970513eac1758f3882c88658a220b58dcc1e39606dccaaf01c"}, - {file = "msgpack-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46c34e99110762a76e3911fc923222472c9d681f1094096ac4102c18319e6468"}, - {file = "msgpack-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a706d1e74dd3dea05cb54580d9bd8b2880e9264856ce5068027eed09680aa74"}, - {file = "msgpack-1.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:534480ee5690ab3cbed89d4c8971a5c631b69a8c0883ecfea96c19118510c846"}, - {file = "msgpack-1.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8cf9e8c3a2153934a23ac160cc4cba0ec035f6867c8013cc6077a79823370346"}, - {file = "msgpack-1.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3180065ec2abbe13a4ad37688b61b99d7f9e012a535b930e0e683ad6bc30155b"}, - {file = "msgpack-1.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c5a91481a3cc573ac8c0d9aace09345d989dc4a0202b7fcb312c88c26d4e71a8"}, - {file = "msgpack-1.1.0-cp39-cp39-win32.whl", hash = "sha256:f80bc7d47f76089633763f952e67f8214cb7b3ee6bfa489b3cb6a84cfac114cd"}, - {file = "msgpack-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:4d1b7ff2d6146e16e8bd665ac726a89c74163ef8cd39fa8c1087d4e52d3a2325"}, - {file = "msgpack-1.1.0.tar.gz", hash = "sha256:dd432ccc2c72b914e4cb77afce64aab761c1137cc698be3984eee260bcb2896e"}, +python-versions = ">=3.10" +files = [ + {file = "msgpack-1.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8c7b398c56ff125feae96c2737abfec5595f1fa0aa186df60c56040b8accb95c"}, + {file = "msgpack-1.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1548006a91aa93c5da81f3bdcebc1a0d10cea2d25969754fbe848da622b2b895"}, + {file = "msgpack-1.2.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1dabedcd0f23559f3596428c6589c1cd8c6eaed3a0d720795b07b0225d769203"}, + {file = "msgpack-1.2.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:83efa1c898e0fc5380fc0cabbf75164c52e3b5cbb45973710d75821928380c73"}, + {file = "msgpack-1.2.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:01e2dd6c9b19d333a00282330cc8a73d38d8dabc306dc5b42cd668c3ac82e833"}, + {file = "msgpack-1.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:350cb813d0af6e65d2f7ef0d729f7ff5be5a8bce03665892f43e5883d4ecc1b8"}, + {file = "msgpack-1.2.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:ee1d9ed27d0497b848923746cf762ed2e7db24f4be7eec8e5cbe8c766aa707b7"}, + {file = "msgpack-1.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:633727297ed063441fd1cda2288865487f33ad14eeb8831afb5f0c396a62cfce"}, + {file = "msgpack-1.2.1-cp310-cp310-win32.whl", hash = "sha256:298872ecf9e61950f1c6af4ca969b859ee91783bb920ef6e6172697d0c8aad74"}, + {file = "msgpack-1.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:2ff164c1b0bcb740b073b99e945234d0212852fa378e44a208c425379140dbeb"}, + {file = "msgpack-1.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:29a3f6e9667868429d8240dfd063ea5ffdc1321c13d783aa23827a38de0dcb22"}, + {file = "msgpack-1.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aded5bdf32609dc7987a49bbbd15a8ef096193f96dd8bbeb791de729e650acf5"}, + {file = "msgpack-1.2.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:146ee4e9ce80b365c6d4c47073da9da7bcec473e58194ceee5dd7620ace77e06"}, + {file = "msgpack-1.2.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a28d076ca7c82b9c8728ad90b7147489449557038bed50e4241eb832395169b4"}, + {file = "msgpack-1.2.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7d31c0ac0c640f877804c67cb2bc9f4e23dc2db97e96c2e67fa27d38283b41f8"}, + {file = "msgpack-1.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8ff92d7feeaf5bc26c51495b69e2f99ed97ab79346fb6555f44be7dd2ac6503b"}, + {file = "msgpack-1.2.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:779197a6513bab3c3632265e3d0f7cb3227e62510841a6f34f1eaa37efbb345e"}, + {file = "msgpack-1.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:67f6dd22fa72a93752643f07889796d62739a13415ee630169a8ce764f86cf9f"}, + {file = "msgpack-1.2.1-cp311-cp311-win32.whl", hash = "sha256:91054a783328e0ea7954b8771095705c8d2243b814743fbaadf14552c9c52c5d"}, + {file = "msgpack-1.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2eda0b7ebb1283a98d3e4492ac933c8af6aff59fd3df1c3ed024f536af4b1dc8"}, + {file = "msgpack-1.2.1-cp311-cp311-win_arm64.whl", hash = "sha256:6ee967f7c7e1df2890c671ff2ee51a28ded0efc95da3e507176dee881ce36c66"}, + {file = "msgpack-1.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2ef59c659f289eddf8aa6623823f19fa2f40a4029266889eac7a2505dd210c35"}, + {file = "msgpack-1.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d3567748a5107cb40cdf66a275430c2f87c07777698f4bfd25c35f44d533258c"}, + {file = "msgpack-1.2.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60926b75d00c8e816ef98f3034f484a8bc64242d66839cef4cf7e503142316a0"}, + {file = "msgpack-1.2.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:020e881a764b20d8d7ca1a54fc01b8175519d108e3c3f194fddc200bda95951a"}, + {file = "msgpack-1.2.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4202c74688ca06591f78cb18988228bd4cca2cc75d57b60008372892d2f1e6e6"}, + {file = "msgpack-1.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8b267ce94efb76fbd1b3373511420074ee3187f0f7811bf394531de13294735a"}, + {file = "msgpack-1.2.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e4f1d0f8f98ade9634e01fb704a408f9336c0a8f1117b369f5db83dc7551d8b1"}, + {file = "msgpack-1.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f02cf17a6ca1abe29b5f980644f7551f94d71f2011509b26d8625ce038f0df64"}, + {file = "msgpack-1.2.1-cp312-cp312-win32.whl", hash = "sha256:0c0d9802354507bcba62af19c17918e3eb437cc25e6f50657d511b5856a77aac"}, + {file = "msgpack-1.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:5c24aa15d5963051e1a5c62b12c50cd705992502b5ec1f3bece6046f33c9fc24"}, + {file = "msgpack-1.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:4227224aaec8f7fbcbfbd4272319347b2bb4030366502600f8c45588c5187b07"}, + {file = "msgpack-1.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0a70e3cf2804a300d921bb0940426e35f4e489a23adfb77a808892241db0a064"}, + {file = "msgpack-1.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:491cc39455ca765fad51fb451bf2915eb2cf41192ab5801ce8d67c1d614fe056"}, + {file = "msgpack-1.2.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f310233ef7fb9c14e201c93639fe5f5260b005f56f0b29048e999c30935596cc"}, + {file = "msgpack-1.2.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:787c9bebb5833e8f6fc8abca3c0597683d8d87f56a8842b6b89c75a5f3176e2d"}, + {file = "msgpack-1.2.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dc871b997a9370d855b7394465f2f350e847a5b806dd38dcc9c989e7d87da155"}, + {file = "msgpack-1.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:85f57e960d877f2977f6430896191b04a21f8901b3b4baf2e4604329f4db5402"}, + {file = "msgpack-1.2.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:1233ee2dd0cefba127583de50ea654677277047d238303521db35def3d7b2e7c"}, + {file = "msgpack-1.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e3dc2feb0876209d9c38aa56cb1de169bd6c4348f1aa48271f241226590993e6"}, + {file = "msgpack-1.2.1-cp313-cp313-win32.whl", hash = "sha256:6d09badf350af2be9d189184e04e64cf54ad93569ab3d96fca58bd3e84aad707"}, + {file = "msgpack-1.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:33f14fba63278b714efe6ad07e50ea5f03d91537aa6a1c5f1ceca4cf44013ca9"}, + {file = "msgpack-1.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:afc5febcd4c99effbc02b528e49d6fd0760b2b7d48c05239e345a5fa6e743d9a"}, + {file = "msgpack-1.2.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:05f340e47e7e47d2da8db9b53e1bb1d294369e9ef45a747441309f6650b8351d"}, + {file = "msgpack-1.2.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:810b916696c86ef0deb3b74588480224df4c1b071136c34183e4a2a4284d7ac7"}, + {file = "msgpack-1.2.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ca0dacff965c47afdc3749a8469d7302a8f801d6a28758d55120d75e66ce6889"}, + {file = "msgpack-1.2.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e2bf9280bceb5efca998435904b5d3e9fdbcc11d90dc9df30aec7973252b720"}, + {file = "msgpack-1.2.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aa6c4be5d1c02a42b066ca6ddb71adf36432868fdcdb6ee87e634e86e0674190"}, + {file = "msgpack-1.2.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec0e675d59150a6269ddc9139087c722292664a37d071a849c05c473350f1f2d"}, + {file = "msgpack-1.2.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:dd3bfe82d53edfe4b7fc9a7ec9761e23a7a5b1dac22264505af428253c29ed24"}, + {file = "msgpack-1.2.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5ad5467fc3f68b5468e06c5f788d712e9f8ffc8b0cd1bcb160c105c1ee92dae7"}, + {file = "msgpack-1.2.1-cp314-cp314-win32.whl", hash = "sha256:98b58bdb89c46190e4609bb36abe17c6d4105ad13f9c5f8f6f64d320f8ced3fb"}, + {file = "msgpack-1.2.1-cp314-cp314-win_amd64.whl", hash = "sha256:74847557e28ce71bd3c438a447ca90e4b507e997ddbdef8a12a7b283b86c156b"}, + {file = "msgpack-1.2.1-cp314-cp314-win_arm64.whl", hash = "sha256:b50b727bd652bdc37d950336c848ef20ec54a4cafc38dce19b1cd86ad625d0f7"}, + {file = "msgpack-1.2.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:8d00f177ca88a77c1cf848d204a38f249751650b601cb6532acc68805d8a8273"}, + {file = "msgpack-1.2.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5bb9c386f0a329c035ddbab4b72d1028bf9627add8dda41070288563d57ed1b1"}, + {file = "msgpack-1.2.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:20466cca18c49c7292a8984bc15d65857b171e7264bdcb5f96baf8be238791fc"}, + {file = "msgpack-1.2.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:196300e7e5d6e74d50f1607ab9c06c4a1484c383cd22defd727902591f7e8dde"}, + {file = "msgpack-1.2.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:575957e79cd51903a4e8495a242442949641e08f1efd5197b43bebd3ea7682b4"}, + {file = "msgpack-1.2.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8c2ed1e48cc0f460bf3c7780e7137ff21a4e18433451916f2442c1b21036cd7d"}, + {file = "msgpack-1.2.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:5f6277e5f783c36786a145e0247fc189a03f35f84b251646e53592d2bc12b355"}, + {file = "msgpack-1.2.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f9389552ecf4784886345ead0647e4edc96bee37cbab05b75540f542f766c48c"}, + {file = "msgpack-1.2.1-cp314-cp314t-win32.whl", hash = "sha256:c1c79a604a2969a868a78b6ebd27a887e00c624f14f66b3038e0590cb23332d1"}, + {file = "msgpack-1.2.1-cp314-cp314t-win_amd64.whl", hash = "sha256:f12038a35fabd52e56a3547bab42401af49a45caa6dd00b34c44de235bc93ee2"}, + {file = "msgpack-1.2.1-cp314-cp314t-win_arm64.whl", hash = "sha256:0adcf06ffde0777c0e1a9b771a2b1c4226ba1bbf748c8efcc02fcdeca3299107"}, + {file = "msgpack-1.2.1.tar.gz", hash = "sha256:04c721c2c7448767e9e3f2520a475663d8ee0f09c31890f6d2bd70fd636a9647"}, ] [[package]] name = "multidict" -version = "6.1.0" +version = "6.7.1" description = "multidict implementation" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"}, - {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"}, - {file = "multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7"}, - {file = "multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0"}, - {file = "multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d"}, - {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6"}, - {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156"}, - {file = "multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753"}, - {file = "multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80"}, - {file = "multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926"}, - {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa"}, - {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436"}, - {file = "multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3"}, - {file = "multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133"}, - {file = "multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1"}, - {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008"}, - {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f"}, - {file = "multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6"}, - {file = "multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81"}, - {file = "multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774"}, - {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392"}, - {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a"}, - {file = "multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd"}, - {file = "multidict-6.1.0-cp38-cp38-win32.whl", hash = "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167"}, - {file = "multidict-6.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef"}, - {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c"}, - {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1"}, - {file = "multidict-6.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43"}, - {file = "multidict-6.1.0-cp39-cp39-win32.whl", hash = "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada"}, - {file = "multidict-6.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a"}, - {file = "multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506"}, - {file = "multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a"}, + {file = "multidict-6.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c93c3db7ea657dd4637d57e74ab73de31bccefe144d3d4ce370052035bc85fb5"}, + {file = "multidict-6.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:974e72a2474600827abaeda71af0c53d9ebbc3c2eb7da37b37d7829ae31232d8"}, + {file = "multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdea2e7b2456cfb6694fb113066fd0ec7ea4d67e3a35e1f4cbeea0b448bf5872"}, + {file = "multidict-6.7.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17207077e29342fdc2c9a82e4b306f1127bf1ea91f8b71e02d4798a70bb99991"}, + {file = "multidict-6.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4f49cb5661344764e4c7c7973e92a47a59b8fc19b6523649ec9dc4960e58a03"}, + {file = "multidict-6.7.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a9fc4caa29e2e6ae408d1c450ac8bf19892c5fca83ee634ecd88a53332c59981"}, + {file = "multidict-6.7.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c5f0c21549ab432b57dcc82130f388d84ad8179824cc3f223d5e7cfbfd4143f6"}, + {file = "multidict-6.7.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7dfb78d966b2c906ae1d28ccf6e6712a3cd04407ee5088cd276fe8cb42186190"}, + {file = "multidict-6.7.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9b0d9b91d1aa44db9c1f1ecd0d9d2ae610b2f4f856448664e01a3b35899f3f92"}, + {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dd96c01a9dcd4889dcfcf9eb5544ca0c77603f239e3ffab0524ec17aea9a93ee"}, + {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:067343c68cd6612d375710f895337b3a98a033c94f14b9a99eff902f205424e2"}, + {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5884a04f4ff56c6120f6ccf703bdeb8b5079d808ba604d4d53aec0d55dc33568"}, + {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8affcf1c98b82bc901702eb73b6947a1bfa170823c153fe8a47b5f5f02e48e40"}, + {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0d17522c37d03e85c8098ec8431636309b2682cf12e58f4dbc76121fb50e4962"}, + {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24c0cf81544ca5e17cfcb6e482e7a82cd475925242b308b890c9452a074d4505"}, + {file = "multidict-6.7.1-cp310-cp310-win32.whl", hash = "sha256:d82dd730a95e6643802f4454b8fdecdf08667881a9c5670db85bc5a56693f122"}, + {file = "multidict-6.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cf37cbe5ced48d417ba045aca1b21bafca67489452debcde94778a576666a1df"}, + {file = "multidict-6.7.1-cp310-cp310-win_arm64.whl", hash = "sha256:59bc83d3f66b41dac1e7460aac1d196edc70c9ba3094965c467715a70ecb46db"}, + {file = "multidict-6.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ff981b266af91d7b4b3793ca3382e53229088d193a85dfad6f5f4c27fc73e5d"}, + {file = "multidict-6.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:844c5bca0b5444adb44a623fb0a1310c2f4cd41f402126bb269cd44c9b3f3e1e"}, + {file = "multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f2a0a924d4c2e9afcd7ec64f9de35fcd96915149b2216e1cb2c10a56df483855"}, + {file = "multidict-6.7.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8be1802715a8e892c784c0197c2ace276ea52702a0ede98b6310c8f255a5afb3"}, + {file = "multidict-6.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e2d2ed645ea29f31c4c7ea1552fcfd7cb7ba656e1eafd4134a6620c9f5fdd9e"}, + {file = "multidict-6.7.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:95922cee9a778659e91db6497596435777bd25ed116701a4c034f8e46544955a"}, + {file = "multidict-6.7.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6b83cabdc375ffaaa15edd97eb7c0c672ad788e2687004990074d7d6c9b140c8"}, + {file = "multidict-6.7.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:38fb49540705369bab8484db0689d86c0a33a0a9f2c1b197f506b71b4b6c19b0"}, + {file = "multidict-6.7.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:439cbebd499f92e9aa6793016a8acaa161dfa749ae86d20960189f5398a19144"}, + {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6d3bc717b6fe763b8be3f2bee2701d3c8eb1b2a8ae9f60910f1b2860c82b6c49"}, + {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:619e5a1ac57986dbfec9f0b301d865dddf763696435e2962f6d9cf2fdff2bb71"}, + {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0b38ebffd9be37c1170d33bc0f36f4f262e0a09bc1aac1c34c7aa51a7293f0b3"}, + {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:10ae39c9cfe6adedcdb764f5e8411d4a92b055e35573a2eaa88d3323289ef93c"}, + {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:25167cc263257660290fba06b9318d2026e3c910be240a146e1f66dd114af2b0"}, + {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:128441d052254f42989ef98b7b6a6ecb1e6f708aa962c7984235316db59f50fa"}, + {file = "multidict-6.7.1-cp311-cp311-win32.whl", hash = "sha256:d62b7f64ffde3b99d06b707a280db04fb3855b55f5a06df387236051d0668f4a"}, + {file = "multidict-6.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:bdbf9f3b332abd0cdb306e7c2113818ab1e922dc84b8f8fd06ec89ed2a19ab8b"}, + {file = "multidict-6.7.1-cp311-cp311-win_arm64.whl", hash = "sha256:b8c990b037d2fff2f4e33d3f21b9b531c5745b33a49a7d6dbe7a177266af44f6"}, + {file = "multidict-6.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a90f75c956e32891a4eda3639ce6dd86e87105271f43d43442a3aedf3cddf172"}, + {file = "multidict-6.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fccb473e87eaa1382689053e4a4618e7ba7b9b9b8d6adf2027ee474597128cd"}, + {file = "multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0fa96985700739c4c7853a43c0b3e169360d6855780021bfc6d0f1ce7c123e7"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cb2a55f408c3043e42b40cc8eecd575afa27b7e0b956dfb190de0f8499a57a53"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb0ce7b2a32d09892b3dd6cc44877a0d02a33241fafca5f25c8b6b62374f8b75"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c3a32d23520ee37bf327d1e1a656fec76a2edd5c038bf43eddfa0572ec49c60b"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9c90fed18bffc0189ba814749fdcc102b536e83a9f738a9003e569acd540a733"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:da62917e6076f512daccfbbde27f46fed1c98fee202f0559adec8ee0de67f71a"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfde23ef6ed9db7eaee6c37dcec08524cb43903c60b285b172b6c094711b3961"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3758692429e4e32f1ba0df23219cd0b4fc0a52f476726fff9337d1a57676a582"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:398c1478926eca669f2fd6a5856b6de9c0acf23a2cb59a14c0ba5844fa38077e"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c102791b1c4f3ab36ce4101154549105a53dc828f016356b3e3bcae2e3a039d3"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a088b62bd733e2ad12c50dad01b7d0166c30287c166e137433d3b410add807a6"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3d51ff4785d58d3f6c91bdbffcb5e1f7ddfda557727043aa20d20ec4f65e324a"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc5907494fccf3e7d3f94f95c91d6336b092b5fc83811720fae5e2765890dfba"}, + {file = "multidict-6.7.1-cp312-cp312-win32.whl", hash = "sha256:28ca5ce2fd9716631133d0e9a9b9a745ad7f60bac2bccafb56aa380fc0b6c511"}, + {file = "multidict-6.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcee94dfbd638784645b066074b338bc9cc155d4b4bffa4adce1615c5a426c19"}, + {file = "multidict-6.7.1-cp312-cp312-win_arm64.whl", hash = "sha256:ba0a9fb644d0c1a2194cf7ffb043bd852cea63a57f66fbd33959f7dae18517bf"}, + {file = "multidict-6.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2b41f5fed0ed563624f1c17630cb9941cf2309d4df00e494b551b5f3e3d67a23"}, + {file = "multidict-6.7.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84e61e3af5463c19b67ced91f6c634effb89ef8bfc5ca0267f954451ed4bb6a2"}, + {file = "multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:935434b9853c7c112eee7ac891bc4cb86455aa631269ae35442cb316790c1445"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:432feb25a1cb67fe82a9680b4d65fb542e4635cb3166cd9c01560651ad60f177"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e82d14e3c948952a1a85503817e038cba5905a3352de76b9a465075d072fba23"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4cfb48c6ea66c83bcaaf7e4dfa7ec1b6bbcf751b7db85a328902796dfde4c060"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d540e51b7e8e170174555edecddbd5538105443754539193e3e1061864d444d"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:273d23f4b40f3dce4d6c8a821c741a86dec62cded82e1175ba3d99be128147ed"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d624335fd4fa1c08a53f8b4be7676ebde19cd092b3895c421045ca87895b429"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:12fad252f8b267cc75b66e8fc51b3079604e8d43a75428ffe193cd9e2195dfd6"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:03ede2a6ffbe8ef936b92cb4529f27f42be7f56afcdab5ab739cd5f27fb1cbf9"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:90efbcf47dbe33dcf643a1e400d67d59abeac5db07dc3f27d6bdeae497a2198c"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c4b9bfc148f5a91be9244d6264c53035c8a0dcd2f51f1c3c6e30e30ebaa1c84"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:401c5a650f3add2472d1d288c26deebc540f99e2fb83e9525007a74cd2116f1d"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:97891f3b1b3ffbded884e2916cacf3c6fc87b66bb0dde46f7357404750559f33"}, + {file = "multidict-6.7.1-cp313-cp313-win32.whl", hash = "sha256:e1c5988359516095535c4301af38d8a8838534158f649c05dd1050222321bcb3"}, + {file = "multidict-6.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:960c83bf01a95b12b08fd54324a4eb1d5b52c88932b5cba5d6e712bb3ed12eb5"}, + {file = "multidict-6.7.1-cp313-cp313-win_arm64.whl", hash = "sha256:563fe25c678aaba333d5399408f5ec3c383ca5b663e7f774dd179a520b8144df"}, + {file = "multidict-6.7.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:c76c4bec1538375dad9d452d246ca5368ad6e1c9039dadcf007ae59c70619ea1"}, + {file = "multidict-6.7.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:57b46b24b5d5ebcc978da4ec23a819a9402b4228b8a90d9c656422b4bdd8a963"}, + {file = "multidict-6.7.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e954b24433c768ce78ab7929e84ccf3422e46deb45a4dc9f93438f8217fa2d34"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3bd231490fa7217cc832528e1cd8752a96f0125ddd2b5749390f7c3ec8721b65"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:253282d70d67885a15c8a7716f3a73edf2d635793ceda8173b9ecc21f2fb8292"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b4c48648d7649c9335cf1927a8b87fa692de3dcb15faa676c6a6f1f1aabda43"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:98bc624954ec4d2c7cb074b8eefc2b5d0ce7d482e410df446414355d158fe4ca"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1b99af4d9eec0b49927b4402bcbb58dea89d3e0db8806a4086117019939ad3dd"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6aac4f16b472d5b7dc6f66a0d49dd57b0e0902090be16594dc9ebfd3d17c47e7"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:21f830fe223215dffd51f538e78c172ed7c7f60c9b96a2bf05c4848ad49921c3"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f5dd81c45b05518b9aa4da4aa74e1c93d715efa234fd3e8a179df611cc85e5f4"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:eb304767bca2bb92fb9c5bd33cedc95baee5bb5f6c88e63706533a1c06ad08c8"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c9035dde0f916702850ef66460bc4239d89d08df4d02023a5926e7446724212c"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:af959b9beeb66c822380f222f0e0a1889331597e81f1ded7f374f3ecb0fd6c52"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:41f2952231456154ee479651491e94118229844dd7226541788be783be2b5108"}, + {file = "multidict-6.7.1-cp313-cp313t-win32.whl", hash = "sha256:df9f19c28adcb40b6aae30bbaa1478c389efd50c28d541d76760199fc1037c32"}, + {file = "multidict-6.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:d54ecf9f301853f2c5e802da559604b3e95bb7a3b01a9c295c6ee591b9882de8"}, + {file = "multidict-6.7.1-cp313-cp313t-win_arm64.whl", hash = "sha256:5a37ca18e360377cfda1d62f5f382ff41f2b8c4ccb329ed974cc2e1643440118"}, + {file = "multidict-6.7.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8f333ec9c5eb1b7105e3b84b53141e66ca05a19a605368c55450b6ba208cb9ee"}, + {file = "multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a407f13c188f804c759fc6a9f88286a565c242a76b27626594c133b82883b5c2"}, + {file = "multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0e161ddf326db5577c3a4cc2d8648f81456e8a20d40415541587a71620d7a7d1"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1e3a8bb24342a8201d178c3b4984c26ba81a577c80d4d525727427460a50c22d"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97231140a50f5d447d3164f994b86a0bed7cd016e2682f8650d6a9158e14fd31"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6b10359683bd8806a200fd2909e7c8ca3a7b24ec1d8132e483d58e791d881048"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:283ddac99f7ac25a4acadbf004cb5ae34480bbeb063520f70ce397b281859362"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:538cec1e18c067d0e6103aa9a74f9e832904c957adc260e61cd9d8cf0c3b3d37"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eee46ccb30ff48a1e35bb818cc90846c6be2b68240e42a78599166722cea709"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa263a02f4f2dd2d11a7b1bb4362aa7cb1049f84a9235d31adf63f30143469a0"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2e1425e2f99ec5bd36c15a01b690a1a2456209c5deed58f95469ffb46039ccbb"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:497394b3239fc6f0e13a78a3e1b61296e72bf1c5f94b4c4eb80b265c37a131cd"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:233b398c29d3f1b9676b4b6f75c518a06fcb2ea0b925119fb2c1bc35c05e1601"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:93b1818e4a6e0930454f0f2af7dfce69307ca03cdcfb3739bf4d91241967b6c1"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f33dc2a3abe9249ea5d8360f969ec7f4142e7ac45ee7014d8f8d5acddf178b7b"}, + {file = "multidict-6.7.1-cp314-cp314-win32.whl", hash = "sha256:3ab8b9d8b75aef9df299595d5388b14530839f6422333357af1339443cff777d"}, + {file = "multidict-6.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:5e01429a929600e7dab7b166062d9bb54a5eed752384c7384c968c2afab8f50f"}, + {file = "multidict-6.7.1-cp314-cp314-win_arm64.whl", hash = "sha256:4885cb0e817aef5d00a2e8451d4665c1808378dc27c2705f1bf4ef8505c0d2e5"}, + {file = "multidict-6.7.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0458c978acd8e6ea53c81eefaddbbee9c6c5e591f41b3f5e8e194780fe026581"}, + {file = "multidict-6.7.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c0abd12629b0af3cf590982c0b413b1e7395cd4ec026f30986818ab95bfaa94a"}, + {file = "multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:14525a5f61d7d0c94b368a42cff4c9a4e7ba2d52e2672a7b23d84dc86fb02b0c"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17307b22c217b4cf05033dabefe68255a534d637c6c9b0cc8382718f87be4262"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a7e590ff876a3eaf1c02a4dfe0724b6e69a9e9de6d8f556816f29c496046e59"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5fa6a95dfee63893d80a34758cd0e0c118a30b8dcb46372bf75106c591b77889"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a0543217a6a017692aa6ae5cc39adb75e587af0f3a82288b1492eb73dd6cc2a4"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f99fe611c312b3c1c0ace793f92464d8cd263cc3b26b5721950d977b006b6c4d"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9004d8386d133b7e6135679424c91b0b854d2d164af6ea3f289f8f2761064609"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e628ef0e6859ffd8273c69412a2465c4be4a9517d07261b33334b5ec6f3c7489"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:841189848ba629c3552035a6a7f5bf3b02eb304e9fea7492ca220a8eda6b0e5c"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ce1bbd7d780bb5a0da032e095c951f7014d6b0a205f8318308140f1a6aba159e"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b26684587228afed0d50cf804cc71062cc9c1cdf55051c4c6345d372947b268c"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9f9af11306994335398293f9958071019e3ab95e9a707dc1383a35613f6abcb9"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b4938326284c4f1224178a560987b6cf8b4d38458b113d9b8c1db1a836e640a2"}, + {file = "multidict-6.7.1-cp314-cp314t-win32.whl", hash = "sha256:98655c737850c064a65e006a3df7c997cd3b220be4ec8fe26215760b9697d4d7"}, + {file = "multidict-6.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:497bde6223c212ba11d462853cfa4f0ae6ef97465033e7dc9940cdb3ab5b48e5"}, + {file = "multidict-6.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:2bbd113e0d4af5db41d5ebfe9ccaff89de2120578164f86a5d17d5a576d1e5b2"}, + {file = "multidict-6.7.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:65573858d27cdeaca41893185677dc82395159aa28875a8867af66532d413a8f"}, + {file = "multidict-6.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c524c6fb8fc342793708ab111c4dbc90ff9abd568de220432500e47e990c0358"}, + {file = "multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:aa23b001d968faef416ff70dc0f1ab045517b9b42a90edd3e9bcdb06479e31d5"}, + {file = "multidict-6.7.1-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6704fa2b7453b2fb121740555fa1ee20cd98c4d011120caf4d2b8d4e7c76eec0"}, + {file = "multidict-6.7.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:121a34e5bfa410cdf2c8c49716de160de3b1dbcd86b49656f5681e4543bcd1a8"}, + {file = "multidict-6.7.1-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:026d264228bcd637d4e060844e39cdc60f86c479e463d49075dedc21b18fbbe0"}, + {file = "multidict-6.7.1-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0e697826df7eb63418ee190fd06ce9f1803593bb4b9517d08c60d9b9a7f69d8f"}, + {file = "multidict-6.7.1-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bb08271280173720e9fea9ede98e5231defcbad90f1624bea26f32ec8a956e2f"}, + {file = "multidict-6.7.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6b3228e1d80af737b72925ce5fb4daf5a335e49cd7ab77ed7b9fdfbf58c526e"}, + {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3943debf0fbb57bdde5901695c11094a9a36723e5c03875f87718ee15ca2f4d2"}, + {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:98c5787b0a0d9a41d9311eae44c3b76e6753def8d8870ab501320efe75a6a5f8"}, + {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:08ccb2a6dc72009093ebe7f3f073e5ec5964cba9a706fa94b1a1484039b87941"}, + {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb351f72c26dc9abe338ca7294661aa22969ad8ffe7ef7d5541d19f368dc854a"}, + {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ac1c665bad8b5d762f5f85ebe4d94130c26965f11de70c708c75671297c776de"}, + {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fa6609d0364f4f6f58351b4659a1f3e0e898ba2a8c5cac04cb2c7bc556b0bc5"}, + {file = "multidict-6.7.1-cp39-cp39-win32.whl", hash = "sha256:6f77ce314a29263e67adadc7e7c1bc699fcb3a305059ab973d038f87caa42ed0"}, + {file = "multidict-6.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:f537b55778cd3cbee430abe3131255d3a78202e0f9ea7ffc6ada893a4bcaeea4"}, + {file = "multidict-6.7.1-cp39-cp39-win_arm64.whl", hash = "sha256:749aa54f578f2e5f439538706a475aa844bfa8ef75854b1401e6e528e4937cf9"}, + {file = "multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56"}, + {file = "multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d"}, ] [package.dependencies] @@ -2711,247 +3314,294 @@ typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} [[package]] name = "networkx" -version = "3.2.1" +version = "3.4.2" description = "Python package for creating and manipulating graphs and networks" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" files = [ - {file = "networkx-3.2.1-py3-none-any.whl", hash = "sha256:f18c69adc97877c42332c170849c96cefa91881c99a7cb3e95b7c659ebdc1ec2"}, - {file = "networkx-3.2.1.tar.gz", hash = "sha256:9f1bb5cf3409bf324e0a722c20bdb4c20ee39bf1c30ce8ae499c8502b0b5e0c6"}, + {file = "networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f"}, + {file = "networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1"}, ] [package.extras] -default = ["matplotlib (>=3.5)", "numpy (>=1.22)", "pandas (>=1.4)", "scipy (>=1.9,!=1.11.0,!=1.11.1)"] -developer = ["changelist (==0.4)", "mypy (>=1.1)", "pre-commit (>=3.2)", "rtoml"] -doc = ["nb2plots (>=0.7)", "nbconvert (<7.9)", "numpydoc (>=1.6)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.14)", "sphinx (>=7)", "sphinx-gallery (>=0.14)", "texext (>=0.6.7)"] -extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.11)", "sympy (>=1.10)"] +default = ["matplotlib (>=3.7)", "numpy (>=1.24)", "pandas (>=2.0)", "scipy (>=1.10,!=1.11.0,!=1.11.1)"] +developer = ["changelist (==0.5)", "mypy (>=1.1)", "pre-commit (>=3.2)", "rtoml"] +doc = ["intersphinx-registry", "myst-nb (>=1.1)", "numpydoc (>=1.8.0)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.15)", "sphinx (>=7.3)", "sphinx-gallery (>=0.16)", "texext (>=0.6.7)"] +example = ["cairocffi (>=1.7)", "contextily (>=1.6)", "igraph (>=0.11)", "momepy (>=0.7.2)", "osmnx (>=1.9)", "scikit-learn (>=1.5)", "seaborn (>=0.13)"] +extra = ["lxml (>=4.6)", "pydot (>=3.0.1)", "pygraphviz (>=1.14)", "sympy (>=1.10)"] test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] [[package]] name = "nibabel" -version = "5.2.0" +version = "5.4.2" description = "Access a multitude of neuroimaging data formats" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "nibabel-5.2.0-py3-none-any.whl", hash = "sha256:77724af6e29fd9c4173702e4d031e7d8c45b5963887905a0f90edab880381b7f"}, - {file = "nibabel-5.2.0.tar.gz", hash = "sha256:3df8f1ab981d1bd92f4331d565528d126ab9717fdbd4cfe68f43fcd1c2bf3f52"}, + {file = "nibabel-5.4.2-py3-none-any.whl", hash = "sha256:553482c5f1e1034fc312edf6fb7f32236c0056439845d1c29293b7e8c98d4854"}, + {file = "nibabel-5.4.2.tar.gz", hash = "sha256:d5f4b9076a13178ae7f7acf18c8dbd503ee1c4d5c0c23b85df7be87efcbb49da"}, ] [package.dependencies] -numpy = ">=1.20" -packaging = ">=17" +importlib-resources = {version = ">=5.12", markers = "python_version < \"3.12\""} +numpy = ">=1.25" +packaging = ">=20" +typing-extensions = {version = ">=4.6", markers = "python_version < \"3.13\""} [package.extras] -all = ["nibabel[dicomfs,minc2,spm,zstd]"] -dev = ["tox"] -dicom = ["pydicom (>=1.0.0)"] -dicomfs = ["nibabel[dicom]", "pillow"] -doc = ["matplotlib (>=1.5.3)", "numpydoc", "sphinx", "texext", "tomli"] -doctest = ["tox"] -minc2 = ["h5py"] -spm = ["scipy"] -style = ["tox"] -test = ["pytest", "pytest-cov", "pytest-doctestplus", "pytest-httpserver", "pytest-xdist"] -typing = ["tox"] -zstd = ["pyzstd (>=0.14.3)"] +all = ["backports-zstd (>=1.1)", "h5py (>=3.8)", "indexed-gzip (>=1.6)", "pillow (>=8.4)", "pydicom (>=2.3)", "scipy (>=1.11)"] +dicom = ["pydicom (>=2.3)"] +dicomfs = ["pillow (>=8.4)", "pydicom (>=2.3)"] +indexed-gzip = ["indexed-gzip (>=1.6)"] +minc2 = ["h5py (>=3.8)"] +spm = ["scipy (>=1.11)"] +test = ["coverage[toml] (>=7.2)", "pytest (>=8)", "pytest-cov (>=6)", "pytest-doctestplus (>=1.4)", "pytest-httpserver (>=1.0.7)", "pytest-xdist (>=3.5)"] +viewers = ["matplotlib (>=3.7)"] +zstd = ["backports-zstd (>=1.1)"] [[package]] name = "nodeenv" -version = "1.8.0" +version = "1.10.0" description = "Node.js virtual environment builder" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ - {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, - {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, + {file = "nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827"}, + {file = "nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb"}, ] -[package.dependencies] -setuptools = "*" - [[package]] name = "numpy" -version = "1.26.3" +version = "1.26.4" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.9" files = [ - {file = "numpy-1.26.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:806dd64230dbbfaca8a27faa64e2f414bf1c6622ab78cc4264f7f5f028fee3bf"}, - {file = "numpy-1.26.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02f98011ba4ab17f46f80f7f8f1c291ee7d855fcef0a5a98db80767a468c85cd"}, - {file = "numpy-1.26.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d45b3ec2faed4baca41c76617fcdcfa4f684ff7a151ce6fc78ad3b6e85af0a6"}, - {file = "numpy-1.26.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdd2b45bf079d9ad90377048e2747a0c82351989a2165821f0c96831b4a2a54b"}, - {file = "numpy-1.26.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:211ddd1e94817ed2d175b60b6374120244a4dd2287f4ece45d49228b4d529178"}, - {file = "numpy-1.26.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b1240f767f69d7c4c8a29adde2310b871153df9b26b5cb2b54a561ac85146485"}, - {file = "numpy-1.26.3-cp310-cp310-win32.whl", hash = "sha256:21a9484e75ad018974a2fdaa216524d64ed4212e418e0a551a2d83403b0531d3"}, - {file = "numpy-1.26.3-cp310-cp310-win_amd64.whl", hash = "sha256:9e1591f6ae98bcfac2a4bbf9221c0b92ab49762228f38287f6eeb5f3f55905ce"}, - {file = "numpy-1.26.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b831295e5472954104ecb46cd98c08b98b49c69fdb7040483aff799a755a7374"}, - {file = "numpy-1.26.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9e87562b91f68dd8b1c39149d0323b42e0082db7ddb8e934ab4c292094d575d6"}, - {file = "numpy-1.26.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c66d6fec467e8c0f975818c1796d25c53521124b7cfb760114be0abad53a0a2"}, - {file = "numpy-1.26.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f25e2811a9c932e43943a2615e65fc487a0b6b49218899e62e426e7f0a57eeda"}, - {file = "numpy-1.26.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:af36e0aa45e25c9f57bf684b1175e59ea05d9a7d3e8e87b7ae1a1da246f2767e"}, - {file = "numpy-1.26.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:51c7f1b344f302067b02e0f5b5d2daa9ed4a721cf49f070280ac202738ea7f00"}, - {file = "numpy-1.26.3-cp311-cp311-win32.whl", hash = "sha256:7ca4f24341df071877849eb2034948459ce3a07915c2734f1abb4018d9c49d7b"}, - {file = "numpy-1.26.3-cp311-cp311-win_amd64.whl", hash = "sha256:39763aee6dfdd4878032361b30b2b12593fb445ddb66bbac802e2113eb8a6ac4"}, - {file = "numpy-1.26.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a7081fd19a6d573e1a05e600c82a1c421011db7935ed0d5c483e9dd96b99cf13"}, - {file = "numpy-1.26.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12c70ac274b32bc00c7f61b515126c9205323703abb99cd41836e8125ea0043e"}, - {file = "numpy-1.26.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f784e13e598e9594750b2ef6729bcd5a47f6cfe4a12cca13def35e06d8163e3"}, - {file = "numpy-1.26.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f24750ef94d56ce6e33e4019a8a4d68cfdb1ef661a52cdaee628a56d2437419"}, - {file = "numpy-1.26.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:77810ef29e0fb1d289d225cabb9ee6cf4d11978a00bb99f7f8ec2132a84e0166"}, - {file = "numpy-1.26.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8ed07a90f5450d99dad60d3799f9c03c6566709bd53b497eb9ccad9a55867f36"}, - {file = "numpy-1.26.3-cp312-cp312-win32.whl", hash = "sha256:f73497e8c38295aaa4741bdfa4fda1a5aedda5473074369eca10626835445511"}, - {file = "numpy-1.26.3-cp312-cp312-win_amd64.whl", hash = "sha256:da4b0c6c699a0ad73c810736303f7fbae483bcb012e38d7eb06a5e3b432c981b"}, - {file = "numpy-1.26.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1666f634cb3c80ccbd77ec97bc17337718f56d6658acf5d3b906ca03e90ce87f"}, - {file = "numpy-1.26.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:18c3319a7d39b2c6a9e3bb75aab2304ab79a811ac0168a671a62e6346c29b03f"}, - {file = "numpy-1.26.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b7e807d6888da0db6e7e75838444d62495e2b588b99e90dd80c3459594e857b"}, - {file = "numpy-1.26.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4d362e17bcb0011738c2d83e0a65ea8ce627057b2fdda37678f4374a382a137"}, - {file = "numpy-1.26.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b8c275f0ae90069496068c714387b4a0eba5d531aace269559ff2b43655edd58"}, - {file = "numpy-1.26.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cc0743f0302b94f397a4a65a660d4cd24267439eb16493fb3caad2e4389bccbb"}, - {file = "numpy-1.26.3-cp39-cp39-win32.whl", hash = "sha256:9bc6d1a7f8cedd519c4b7b1156d98e051b726bf160715b769106661d567b3f03"}, - {file = "numpy-1.26.3-cp39-cp39-win_amd64.whl", hash = "sha256:867e3644e208c8922a3be26fc6bbf112a035f50f0a86497f98f228c50c607bb2"}, - {file = "numpy-1.26.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3c67423b3703f8fbd90f5adaa37f85b5794d3366948efe9a5190a5f3a83fc34e"}, - {file = "numpy-1.26.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46f47ee566d98849323f01b349d58f2557f02167ee301e5e28809a8c0e27a2d0"}, - {file = "numpy-1.26.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a8474703bffc65ca15853d5fd4d06b18138ae90c17c8d12169968e998e448bb5"}, - {file = "numpy-1.26.3.tar.gz", hash = "sha256:697df43e2b6310ecc9d95f05d5ef20eacc09c7c4ecc9da3f235d39e71b7da1e4"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, + {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, + {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, + {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, + {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, + {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, + {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, + {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, + {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, + {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, ] [[package]] name = "opencv-python" -version = "4.9.0.80" +version = "4.11.0.86" description = "Wrapper package for OpenCV python bindings." optional = false python-versions = ">=3.6" files = [ - {file = "opencv-python-4.9.0.80.tar.gz", hash = "sha256:1a9f0e6267de3a1a1db0c54213d022c7c8b5b9ca4b580e80bdc58516c922c9e1"}, - {file = "opencv_python-4.9.0.80-cp37-abi3-macosx_10_16_x86_64.whl", hash = "sha256:7e5f7aa4486651a6ebfa8ed4b594b65bd2d2f41beeb4241a3e4b1b85acbbbadb"}, - {file = "opencv_python-4.9.0.80-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:71dfb9555ccccdd77305fc3dcca5897fbf0cf28b297c51ee55e079c065d812a3"}, - {file = "opencv_python-4.9.0.80-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b34a52e9da36dda8c151c6394aed602e4b17fa041df0b9f5b93ae10b0fcca2a"}, - {file = "opencv_python-4.9.0.80-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4088cab82b66a3b37ffc452976b14a3c599269c247895ae9ceb4066d8188a57"}, - {file = "opencv_python-4.9.0.80-cp37-abi3-win32.whl", hash = "sha256:dcf000c36dd1651118a2462257e3a9e76db789a78432e1f303c7bac54f63ef6c"}, - {file = "opencv_python-4.9.0.80-cp37-abi3-win_amd64.whl", hash = "sha256:3f16f08e02b2a2da44259c7cc712e779eff1dd8b55fdb0323e8cab09548086c0"}, + {file = "opencv-python-4.11.0.86.tar.gz", hash = "sha256:03d60ccae62304860d232272e4a4fda93c39d595780cb40b161b310244b736a4"}, + {file = "opencv_python-4.11.0.86-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:432f67c223f1dc2824f5e73cdfcd9db0efc8710647d4e813012195dc9122a52a"}, + {file = "opencv_python-4.11.0.86-cp37-abi3-macosx_13_0_x86_64.whl", hash = "sha256:9d05ef13d23fe97f575153558653e2d6e87103995d54e6a35db3f282fe1f9c66"}, + {file = "opencv_python-4.11.0.86-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b92ae2c8852208817e6776ba1ea0d6b1e0a1b5431e971a2a0ddd2a8cc398202"}, + {file = "opencv_python-4.11.0.86-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b02611523803495003bd87362db3e1d2a0454a6a63025dc6658a9830570aa0d"}, + {file = "opencv_python-4.11.0.86-cp37-abi3-win32.whl", hash = "sha256:810549cb2a4aedaa84ad9a1c92fbfdfc14090e2749cedf2c1589ad8359aa169b"}, + {file = "opencv_python-4.11.0.86-cp37-abi3-win_amd64.whl", hash = "sha256:085ad9b77c18853ea66283e98affefe2de8cc4c1f43eda4c100cf9b2721142ec"}, ] [package.dependencies] numpy = [ + {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, + {version = ">=1.23.5", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, {version = ">=1.21.4", markers = "python_version >= \"3.10\" and platform_system == \"Darwin\" and python_version < \"3.11\""}, {version = ">=1.21.2", markers = "platform_system != \"Darwin\" and python_version >= \"3.10\" and python_version < \"3.11\""}, - {version = ">=1.23.5", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, - {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, ] [[package]] name = "orjson" -version = "3.9.12" +version = "3.11.9" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" optional = false -python-versions = ">=3.8" -files = [ - {file = "orjson-3.9.12-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:6b4e2bed7d00753c438e83b613923afdd067564ff7ed696bfe3a7b073a236e07"}, - {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd1b8ec63f0bf54a50b498eedeccdca23bd7b658f81c524d18e410c203189365"}, - {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ab8add018a53665042a5ae68200f1ad14c7953fa12110d12d41166f111724656"}, - {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12756a108875526b76e505afe6d6ba34960ac6b8c5ec2f35faf73ef161e97e07"}, - {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:890e7519c0c70296253660455f77e3a194554a3c45e42aa193cdebc76a02d82b"}, - {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d664880d7f016efbae97c725b243b33c2cbb4851ddc77f683fd1eec4a7894146"}, - {file = "orjson-3.9.12-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cfdaede0fa5b500314ec7b1249c7e30e871504a57004acd116be6acdda3b8ab3"}, - {file = "orjson-3.9.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6492ff5953011e1ba9ed1bf086835fd574bd0a3cbe252db8e15ed72a30479081"}, - {file = "orjson-3.9.12-cp310-none-win32.whl", hash = "sha256:29bf08e2eadb2c480fdc2e2daae58f2f013dff5d3b506edd1e02963b9ce9f8a9"}, - {file = "orjson-3.9.12-cp310-none-win_amd64.whl", hash = "sha256:0fc156fba60d6b50743337ba09f052d8afc8b64595112996d22f5fce01ab57da"}, - {file = "orjson-3.9.12-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:2849f88a0a12b8d94579b67486cbd8f3a49e36a4cb3d3f0ab352c596078c730c"}, - {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3186b18754befa660b31c649a108a915493ea69b4fc33f624ed854ad3563ac65"}, - {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cbbf313c9fb9d4f6cf9c22ced4b6682230457741daeb3d7060c5d06c2e73884a"}, - {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99e8cd005b3926c3db9b63d264bd05e1bf4451787cc79a048f27f5190a9a0311"}, - {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:59feb148392d9155f3bfed0a2a3209268e000c2c3c834fb8fe1a6af9392efcbf"}, - {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4ae815a172a1f073b05b9e04273e3b23e608a0858c4e76f606d2d75fcabde0c"}, - {file = "orjson-3.9.12-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ed398f9a9d5a1bf55b6e362ffc80ac846af2122d14a8243a1e6510a4eabcb71e"}, - {file = "orjson-3.9.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d3cfb76600c5a1e6be91326b8f3b83035a370e727854a96d801c1ea08b708073"}, - {file = "orjson-3.9.12-cp311-none-win32.whl", hash = "sha256:a2b6f5252c92bcab3b742ddb3ac195c0fa74bed4319acd74f5d54d79ef4715dc"}, - {file = "orjson-3.9.12-cp311-none-win_amd64.whl", hash = "sha256:c95488e4aa1d078ff5776b58f66bd29d628fa59adcb2047f4efd3ecb2bd41a71"}, - {file = "orjson-3.9.12-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d6ce2062c4af43b92b0221ed4f445632c6bf4213f8a7da5396a122931377acd9"}, - {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:950951799967558c214cd6cceb7ceceed6f81d2c3c4135ee4a2c9c69f58aa225"}, - {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2dfaf71499d6fd4153f5c86eebb68e3ec1bf95851b030a4b55c7637a37bbdee4"}, - {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:659a8d7279e46c97661839035a1a218b61957316bf0202674e944ac5cfe7ed83"}, - {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af17fa87bccad0b7f6fd8ac8f9cbc9ee656b4552783b10b97a071337616db3e4"}, - {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd52dec9eddf4c8c74392f3fd52fa137b5f2e2bed1d9ae958d879de5f7d7cded"}, - {file = "orjson-3.9.12-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:640e2b5d8e36b970202cfd0799d11a9a4ab46cf9212332cd642101ec952df7c8"}, - {file = "orjson-3.9.12-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:daa438bd8024e03bcea2c5a92cd719a663a58e223fba967296b6ab9992259dbf"}, - {file = "orjson-3.9.12-cp312-none-win_amd64.whl", hash = "sha256:1bb8f657c39ecdb924d02e809f992c9aafeb1ad70127d53fb573a6a6ab59d549"}, - {file = "orjson-3.9.12-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:f4098c7674901402c86ba6045a551a2ee345f9f7ed54eeffc7d86d155c8427e5"}, - {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5586a533998267458fad3a457d6f3cdbddbcce696c916599fa8e2a10a89b24d3"}, - {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:54071b7398cd3f90e4bb61df46705ee96cb5e33e53fc0b2f47dbd9b000e238e1"}, - {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:67426651faa671b40443ea6f03065f9c8e22272b62fa23238b3efdacd301df31"}, - {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4a0cd56e8ee56b203abae7d482ac0d233dbfb436bb2e2d5cbcb539fe1200a312"}, - {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a84a0c3d4841a42e2571b1c1ead20a83e2792644c5827a606c50fc8af7ca4bee"}, - {file = "orjson-3.9.12-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:09d60450cda3fa6c8ed17770c3a88473a16460cd0ff2ba74ef0df663b6fd3bb8"}, - {file = "orjson-3.9.12-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bc82a4db9934a78ade211cf2e07161e4f068a461c1796465d10069cb50b32a80"}, - {file = "orjson-3.9.12-cp38-none-win32.whl", hash = "sha256:61563d5d3b0019804d782137a4f32c72dc44c84e7d078b89d2d2a1adbaa47b52"}, - {file = "orjson-3.9.12-cp38-none-win_amd64.whl", hash = "sha256:410f24309fbbaa2fab776e3212a81b96a1ec6037259359a32ea79fbccfcf76aa"}, - {file = "orjson-3.9.12-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e773f251258dd82795fd5daeac081d00b97bacf1548e44e71245543374874bcf"}, - {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b159baecfda51c840a619948c25817d37733a4d9877fea96590ef8606468b362"}, - {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:975e72e81a249174840d5a8df977d067b0183ef1560a32998be340f7e195c730"}, - {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:06e42e899dde61eb1851a9fad7f1a21b8e4be063438399b63c07839b57668f6c"}, - {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c157e999e5694475a5515942aebeed6e43f7a1ed52267c1c93dcfde7d78d421"}, - {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dde1bc7c035f2d03aa49dc8642d9c6c9b1a81f2470e02055e76ed8853cfae0c3"}, - {file = "orjson-3.9.12-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b0e9d73cdbdad76a53a48f563447e0e1ce34bcecef4614eb4b146383e6e7d8c9"}, - {file = "orjson-3.9.12-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:96e44b21fe407b8ed48afbb3721f3c8c8ce17e345fbe232bd4651ace7317782d"}, - {file = "orjson-3.9.12-cp39-none-win32.whl", hash = "sha256:cbd0f3555205bf2a60f8812133f2452d498dbefa14423ba90fe89f32276f7abf"}, - {file = "orjson-3.9.12-cp39-none-win_amd64.whl", hash = "sha256:03ea7ee7e992532c2f4a06edd7ee1553f0644790553a118e003e3c405add41fa"}, - {file = "orjson-3.9.12.tar.gz", hash = "sha256:da908d23a3b3243632b523344403b128722a5f45e278a8343c2bb67538dff0e4"}, +python-versions = ">=3.10" +files = [ + {file = "orjson-3.11.9-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:135869ef917b8704ea0a94e01620e0c05021c15c52036e4663baffe75e72f8ce"}, + {file = "orjson-3.11.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:115ab5f5f4a0f203cc2a5f0fb09aee503a3f771aa08392949ab5ca230c4fbdbd"}, + {file = "orjson-3.11.9-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4da3c38a2083ca4aaf9c2a36776cce3e9328e6647b10d118948f3cfb4913ffe4"}, + {file = "orjson-3.11.9-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53b50b0e14084b8f7e29c5ce84c5af0f1160169b30d8a6914231d97d2fe297d4"}, + {file = "orjson-3.11.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:231742b4a11dad8d5380a435962c57e91b7c37b79be858f4ef1c0df1a259897e"}, + {file = "orjson-3.11.9-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:34fd2317602587321faab75ab76c623a0117e80841a6413654f04e47f339a8fb"}, + {file = "orjson-3.11.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:71f3db16e69b667b132e0f305a833d5497da302d801508cbb051ed9a9819da47"}, + {file = "orjson-3.11.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0b34789fa0da61cf7bef0546b09c738fb195331e017e477096d129e9105ab03d"}, + {file = "orjson-3.11.9-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:87e4d4ab280b0c87424d47695bec2182caf8cfc17879ea78dab76680194abc13"}, + {file = "orjson-3.11.9-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ace6c58523302d3b97b6ac5c38a5298a54b473762b6be82726b4265c41029f92"}, + {file = "orjson-3.11.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:97d0d932803c1b164fde11cb542a9efcb1e0f63b184537cca65887147906ff48"}, + {file = "orjson-3.11.9-cp310-cp310-win32.whl", hash = "sha256:b3afcf569c15577a9fe64627292daa3e6b3a70f4fb77a5df246a87ec21681b94"}, + {file = "orjson-3.11.9-cp310-cp310-win_amd64.whl", hash = "sha256:8697ab6a080a5c46edaad50e2bc5bd8c7ca5c66442d24104fa44ec74910a8244"}, + {file = "orjson-3.11.9-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:f01c4818b3fc9b0da8e096722a84318071eaa118df35f6ed2344da0e73a5444f"}, + {file = "orjson-3.11.9-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:3ebca4179031ee716ed076ffadc29428e900512f6fccee8614c9983157fcf19c"}, + {file = "orjson-3.11.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48ee05097750de0ff69ed5b7bbcf0732182fd57a24043dcc2a1da780a5ead3a5"}, + {file = "orjson-3.11.9-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a6082706765a95a6680d812e1daf1c0cfe8adec7831b3ff3b625693f3b461b1c"}, + {file = "orjson-3.11.9-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:277fefe9d76ee17eb14debf399e3533d4d63b5f677a4d3719eb763536af1f4bd"}, + {file = "orjson-3.11.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03db380e3780fa0015ed776a90f20e8e20bb11dde13b216ce19e5718e3dfba62"}, + {file = "orjson-3.11.9-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33d7d766701847dc6729846362dc27895d2f2d2251264f9d10e7cb9878194877"}, + {file = "orjson-3.11.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:147302878da387104b66bb4a8b0227d1d487e976ce41a8501916161072ed87b1"}, + {file = "orjson-3.11.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3513550321f8c8c811a7c3297b8a630e82dc08e4c10216d07703c997776236cd"}, + {file = "orjson-3.11.9-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:c5d001196b89fa9cf0a4ab79766cd835b991a166e4b621ba95089edc50c429ff"}, + {file = "orjson-3.11.9-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:16969c9d369c98eb084889c6e4d2d39b77c7eb38ceccf8da2a9fff62ae908980"}, + {file = "orjson-3.11.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:63e0efbc991250c0b3143488fa57d95affcabbfc63c99c48d625dd37779aafe2"}, + {file = "orjson-3.11.9-cp311-cp311-win32.whl", hash = "sha256:14ed654580c1ed2bc217352ec82f91b047aef82951aa71c7f64e0dcb03c0e180"}, + {file = "orjson-3.11.9-cp311-cp311-win_amd64.whl", hash = "sha256:57ea77fb70a448ce87d18fca050193202a3da5e54598f6501ca5476fb66cfe02"}, + {file = "orjson-3.11.9-cp311-cp311-win_arm64.whl", hash = "sha256:19b72ed11572a2ee51a67a903afbe5af504f84ed6f529c0fe44b0ab3fb5cc697"}, + {file = "orjson-3.11.9-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9ef6fe90aadef185c7b128859f40beb24720b4ecea95379fc9000931179c3a49"}, + {file = "orjson-3.11.9-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:e5c9b8f28e726e97d97696c826bc7bea5d71cecd63576dba92924a32c1961291"}, + {file = "orjson-3.11.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26a473dbb4162108b27901492546f83c76fdcea3d0eadff00ae7a07e18dcce09"}, + {file = "orjson-3.11.9-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:011382e2a60fda9d46f1cdee31068cfc52ffe952b587d683ec0463002802a0f4"}, + {file = "orjson-3.11.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c2d3dc759490128c5c1711a53eeaa8ee1d437fd0038ffd2b6008abf46db3f882"}, + {file = "orjson-3.11.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d8ea516b3726d190e1b4297e6f4e7a8650347ae053868a18163b4dd3641d1fff"}, + {file = "orjson-3.11.9-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:380cdce7ba24989af81d0a7013d0aaec5d0e2a21734c0e2681b1bc4f141957fe"}, + {file = "orjson-3.11.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be4fa4f0af7fa18951f7ab3fc2148e223af211bf03f59e1c6034ec3f97f21d61"}, + {file = "orjson-3.11.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a8f5f8bc7ce7d59f08d9f99fa510c06496164a24cb5f3d34537dbd9ca30132e2"}, + {file = "orjson-3.11.9-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:4d7fde5501b944f83b3e665e1b31343ff6e154b15560a16b7130ea1e594a4206"}, + {file = "orjson-3.11.9-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cde1a448023ba7d5bb4c01c5afb48894380b5e4956e0627266526587ef4e535f"}, + {file = "orjson-3.11.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:71e63adb0e1f1ed5d9e168f50a91ceb93ae6420731d222dc7da5c69409aa47aa"}, + {file = "orjson-3.11.9-cp312-cp312-win32.whl", hash = "sha256:2d057a602cdd19a0ad680417527c45b6961a095081c0f46fe0e03e304aac6470"}, + {file = "orjson-3.11.9-cp312-cp312-win_amd64.whl", hash = "sha256:59e403b1cc5a676da8eaf31f6254801b7341b3e29efa85f92b48d272637e77be"}, + {file = "orjson-3.11.9-cp312-cp312-win_arm64.whl", hash = "sha256:9af678d6488357948f1f84c6cd1c1d397c014e1ae2f98ae082a44eb48f602624"}, + {file = "orjson-3.11.9-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:4bab1b2d6141fe7b32ae71dac905666ece4f94936efbfb13d55bb7739a3a6021"}, + {file = "orjson-3.11.9-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:844417969855fc7a41be124aafe83dc424592a7f77cd4501900c67307122b92c"}, + {file = "orjson-3.11.9-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffe02797b5e9f3a9d8292ddcd289b474ad13e81ad83cd1891a240811f1d2cb81"}, + {file = "orjson-3.11.9-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e4eed3b200023042814d2fc8a5d2e880f13b52e1ed2485e83da4f3962f7dc1a"}, + {file = "orjson-3.11.9-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8aff7da9952a5ad1cef8e68017724d96c7b9a66e99e91d6252e1b133d67a7b10"}, + {file = "orjson-3.11.9-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4d4e98d6f3b8afed8bc8cd9718ec0cdf46661826beefb53fe8eafb37f2bf0362"}, + {file = "orjson-3.11.9-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a81d52442a7c99b3662333235b3adf96a1715864658b35bb797212be7bddb97"}, + {file = "orjson-3.11.9-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e39364e726a8fff737309aff059ff67d8a8c8d5b677be7bb49a8b3e84b7e218"}, + {file = "orjson-3.11.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4fd66214623f1b17501df9f0543bef0b833979ab5b6ded1e1d123222866aa8c9"}, + {file = "orjson-3.11.9-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:8ecc30f10465fa1e0ce13fd01d9e22c316e5053a719a8d915d4545a09a5ff677"}, + {file = "orjson-3.11.9-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:97db4c94a7db398a5bd636273324f0b3fd58b350bbbac8bb380ceb825a9b40f4"}, + {file = "orjson-3.11.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9f78cf8fec5bd627f4082b8dfeac7871b43d7f3274904492a43dab39f18a19a0"}, + {file = "orjson-3.11.9-cp313-cp313-win32.whl", hash = "sha256:d4087e5c0209a0a8efe4de3303c234b9c44d1174161dcd851e8eea07c7560b32"}, + {file = "orjson-3.11.9-cp313-cp313-win_amd64.whl", hash = "sha256:051b102c93b4f634e89f3866b07b9a9a98915ada541f4ec30f177067b2694979"}, + {file = "orjson-3.11.9-cp313-cp313-win_arm64.whl", hash = "sha256:cce9127885941bd28f080cecf1f1d288336b7e0d812c345b08be88b572796254"}, + {file = "orjson-3.11.9-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:b6ef1979adc4bc243523f1a2ba91418030a8e29b0a99cbe7e0e2d6807d4dce6e"}, + {file = "orjson-3.11.9-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:f36b7f32c7c0db4a719f1fc5824db4a9c6f8bd1a354debb91faf26ebf3a4c71e"}, + {file = "orjson-3.11.9-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08f4d8ebb44925c794e535b2bebc507cebf32209df81de22ae285fb0d8d66de0"}, + {file = "orjson-3.11.9-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6cc7923789694fd58f001cbcac7e47abc13af4d560ebbfcf3b41a8b1a0748124"}, + {file = "orjson-3.11.9-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea5c46eb2d3af39e806b986f4b09d5c2706a1f5afde3cbf7544ce6616127173c"}, + {file = "orjson-3.11.9-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f5d89a2ed90731df3be64bab0aa44f78bff39fdc9d71c291f4a8023aa46425b7"}, + {file = "orjson-3.11.9-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:25e4aed0312d292c09f61af25bba34e0b2c88546041472b09088c39a4d828af1"}, + {file = "orjson-3.11.9-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaea64f3f467d22e70eeed68bdccb3bc4f83f650446c4a03c59f2cba28a108db"}, + {file = "orjson-3.11.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a028425d1b440c5d92a6be1e1a020739dfe67ea87d96c6dbe828c1b30041728b"}, + {file = "orjson-3.11.9-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:5b192c6cf397e4455b11523c5cf2b18ed084c1bbd61b6c0926344d2129481972"}, + {file = "orjson-3.11.9-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ea407d4ccf5891d667d045fecae97a7a1e5e87b3b97f97ae1803c2e741130be0"}, + {file = "orjson-3.11.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5f63aaf97afd9f6dec5b1a68e1b8da12bfccb4cb9a9a65c3e0b6c847849e7586"}, + {file = "orjson-3.11.9-cp314-cp314-win32.whl", hash = "sha256:e30ab17845bb9fa54ccf67fa4f9f5282652d54faa6d17452f47d0f369d038673"}, + {file = "orjson-3.11.9-cp314-cp314-win_amd64.whl", hash = "sha256:32ef5f4283a3be81913947d19608eacb7c6608026851123790cd9cc8982af34b"}, + {file = "orjson-3.11.9-cp314-cp314-win_arm64.whl", hash = "sha256:eebdbdeef0094e4f5aefa20dcd4eb2368ab5e7a3b4edea27f1e7b2892e009cf9"}, + {file = "orjson-3.11.9.tar.gz", hash = "sha256:4fef17e1f8722c11587a6ef18e35902450221da0028e65dbaaa543619e68e48f"}, ] [[package]] name = "packaging" -version = "23.2" +version = "26.2" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, + {file = "packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e"}, + {file = "packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661"}, ] [[package]] name = "pandas" -version = "2.2.0" +version = "2.3.3" description = "Powerful data structures for data analysis, time series, and statistics" optional = false python-versions = ">=3.9" files = [ - {file = "pandas-2.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8108ee1712bb4fa2c16981fba7e68b3f6ea330277f5ca34fa8d557e986a11670"}, - {file = "pandas-2.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:736da9ad4033aeab51d067fc3bd69a0ba36f5a60f66a527b3d72e2030e63280a"}, - {file = "pandas-2.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38e0b4fc3ddceb56ec8a287313bc22abe17ab0eb184069f08fc6a9352a769b18"}, - {file = "pandas-2.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20404d2adefe92aed3b38da41d0847a143a09be982a31b85bc7dd565bdba0f4e"}, - {file = "pandas-2.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7ea3ee3f125032bfcade3a4cf85131ed064b4f8dd23e5ce6fa16473e48ebcaf5"}, - {file = "pandas-2.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f9670b3ac00a387620489dfc1bca66db47a787f4e55911f1293063a78b108df1"}, - {file = "pandas-2.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:5a946f210383c7e6d16312d30b238fd508d80d927014f3b33fb5b15c2f895430"}, - {file = "pandas-2.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a1b438fa26b208005c997e78672f1aa8138f67002e833312e6230f3e57fa87d5"}, - {file = "pandas-2.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8ce2fbc8d9bf303ce54a476116165220a1fedf15985b09656b4b4275300e920b"}, - {file = "pandas-2.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2707514a7bec41a4ab81f2ccce8b382961a29fbe9492eab1305bb075b2b1ff4f"}, - {file = "pandas-2.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85793cbdc2d5bc32620dc8ffa715423f0c680dacacf55056ba13454a5be5de88"}, - {file = "pandas-2.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cfd6c2491dc821b10c716ad6776e7ab311f7df5d16038d0b7458bc0b67dc10f3"}, - {file = "pandas-2.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a146b9dcacc3123aa2b399df1a284de5f46287a4ab4fbfc237eac98a92ebcb71"}, - {file = "pandas-2.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:fbc1b53c0e1fdf16388c33c3cca160f798d38aea2978004dd3f4d3dec56454c9"}, - {file = "pandas-2.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a41d06f308a024981dcaa6c41f2f2be46a6b186b902c94c2674e8cb5c42985bc"}, - {file = "pandas-2.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:159205c99d7a5ce89ecfc37cb08ed179de7783737cea403b295b5eda8e9c56d1"}, - {file = "pandas-2.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb1e1f3861ea9132b32f2133788f3b14911b68102d562715d71bd0013bc45440"}, - {file = "pandas-2.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:761cb99b42a69005dec2b08854fb1d4888fdf7b05db23a8c5a099e4b886a2106"}, - {file = "pandas-2.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a20628faaf444da122b2a64b1e5360cde100ee6283ae8effa0d8745153809a2e"}, - {file = "pandas-2.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f5be5d03ea2073627e7111f61b9f1f0d9625dc3c4d8dda72cc827b0c58a1d042"}, - {file = "pandas-2.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:a626795722d893ed6aacb64d2401d017ddc8a2341b49e0384ab9bf7112bdec30"}, - {file = "pandas-2.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9f66419d4a41132eb7e9a73dcec9486cf5019f52d90dd35547af11bc58f8637d"}, - {file = "pandas-2.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:57abcaeda83fb80d447f28ab0cc7b32b13978f6f733875ebd1ed14f8fbc0f4ab"}, - {file = "pandas-2.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e60f1f7dba3c2d5ca159e18c46a34e7ca7247a73b5dd1a22b6d59707ed6b899a"}, - {file = "pandas-2.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb61dc8567b798b969bcc1fc964788f5a68214d333cade8319c7ab33e2b5d88a"}, - {file = "pandas-2.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:52826b5f4ed658fa2b729264d63f6732b8b29949c7fd234510d57c61dbeadfcd"}, - {file = "pandas-2.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bde2bc699dbd80d7bc7f9cab1e23a95c4375de615860ca089f34e7c64f4a8de7"}, - {file = "pandas-2.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:3de918a754bbf2da2381e8a3dcc45eede8cd7775b047b923f9006d5f876802ae"}, - {file = "pandas-2.2.0.tar.gz", hash = "sha256:30b83f7c3eb217fb4d1b494a57a2fda5444f17834f5df2de6b2ffff68dc3c8e2"}, + {file = "pandas-2.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:376c6446ae31770764215a6c937f72d917f214b43560603cd60da6408f183b6c"}, + {file = "pandas-2.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e19d192383eab2f4ceb30b412b22ea30690c9e618f78870357ae1d682912015a"}, + {file = "pandas-2.3.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5caf26f64126b6c7aec964f74266f435afef1c1b13da3b0636c7518a1fa3e2b1"}, + {file = "pandas-2.3.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd7478f1463441ae4ca7308a70e90b33470fa593429f9d4c578dd00d1fa78838"}, + {file = "pandas-2.3.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4793891684806ae50d1288c9bae9330293ab4e083ccd1c5e383c34549c6e4250"}, + {file = "pandas-2.3.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:28083c648d9a99a5dd035ec125d42439c6c1c525098c58af0fc38dd1a7a1b3d4"}, + {file = "pandas-2.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:503cf027cf9940d2ceaa1a93cfb5f8c8c7e6e90720a2850378f0b3f3b1e06826"}, + {file = "pandas-2.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:602b8615ebcc4a0c1751e71840428ddebeb142ec02c786e8ad6b1ce3c8dec523"}, + {file = "pandas-2.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8fe25fc7b623b0ef6b5009149627e34d2a4657e880948ec3c840e9402e5c1b45"}, + {file = "pandas-2.3.3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b468d3dad6ff947df92dcb32ede5b7bd41a9b3cceef0a30ed925f6d01fb8fa66"}, + {file = "pandas-2.3.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b98560e98cb334799c0b07ca7967ac361a47326e9b4e5a7dfb5ab2b1c9d35a1b"}, + {file = "pandas-2.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37b5848ba49824e5c30bedb9c830ab9b7751fd049bc7914533e01c65f79791"}, + {file = "pandas-2.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:db4301b2d1f926ae677a751eb2bd0e8c5f5319c9cb3f88b0becbbb0b07b34151"}, + {file = "pandas-2.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:f086f6fe114e19d92014a1966f43a3e62285109afe874f067f5abbdcbb10e59c"}, + {file = "pandas-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d21f6d74eb1725c2efaa71a2bfc661a0689579b58e9c0ca58a739ff0b002b53"}, + {file = "pandas-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3fd2f887589c7aa868e02632612ba39acb0b8948faf5cc58f0850e165bd46f35"}, + {file = "pandas-2.3.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecaf1e12bdc03c86ad4a7ea848d66c685cb6851d807a26aa245ca3d2017a1908"}, + {file = "pandas-2.3.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b3d11d2fda7eb164ef27ffc14b4fcab16a80e1ce67e9f57e19ec0afaf715ba89"}, + {file = "pandas-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a68e15f780eddf2b07d242e17a04aa187a7ee12b40b930bfdd78070556550e98"}, + {file = "pandas-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:371a4ab48e950033bcf52b6527eccb564f52dc826c02afd9a1bc0ab731bba084"}, + {file = "pandas-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:a16dcec078a01eeef8ee61bf64074b4e524a2a3f4b3be9326420cabe59c4778b"}, + {file = "pandas-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:56851a737e3470de7fa88e6131f41281ed440d29a9268dcbf0002da5ac366713"}, + {file = "pandas-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdcd9d1167f4885211e401b3036c0c8d9e274eee67ea8d0758a256d60704cfe8"}, + {file = "pandas-2.3.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e32e7cc9af0f1cc15548288a51a3b681cc2a219faa838e995f7dc53dbab1062d"}, + {file = "pandas-2.3.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318d77e0e42a628c04dc56bcef4b40de67918f7041c2b061af1da41dcff670ac"}, + {file = "pandas-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e0a175408804d566144e170d0476b15d78458795bb18f1304fb94160cabf40c"}, + {file = "pandas-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2d9ab0fc11822b5eece72ec9587e172f63cff87c00b062f6e37448ced4493"}, + {file = "pandas-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f8bfc0e12dc78f777f323f55c58649591b2cd0c43534e8355c51d3fede5f4dee"}, + {file = "pandas-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:75ea25f9529fdec2d2e93a42c523962261e567d250b0013b16210e1d40d7c2e5"}, + {file = "pandas-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74ecdf1d301e812db96a465a525952f4dde225fdb6d8e5a521d47e1f42041e21"}, + {file = "pandas-2.3.3-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6435cb949cb34ec11cc9860246ccb2fdc9ecd742c12d3304989017d53f039a78"}, + {file = "pandas-2.3.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:900f47d8f20860de523a1ac881c4c36d65efcb2eb850e6948140fa781736e110"}, + {file = "pandas-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a45c765238e2ed7d7c608fc5bc4a6f88b642f2f01e70c0c23d2224dd21829d86"}, + {file = "pandas-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4fc4c21971a1a9f4bdb4c73978c7f7256caa3e62b323f70d6cb80db583350bc"}, + {file = "pandas-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ee15f284898e7b246df8087fc82b87b01686f98ee67d85a17b7ab44143a3a9a0"}, + {file = "pandas-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1611aedd912e1ff81ff41c745822980c49ce4a7907537be8692c8dbc31924593"}, + {file = "pandas-2.3.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d2cefc361461662ac48810cb14365a365ce864afe85ef1f447ff5a1e99ea81c"}, + {file = "pandas-2.3.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ee67acbbf05014ea6c763beb097e03cd629961c8a632075eeb34247120abcb4b"}, + {file = "pandas-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c46467899aaa4da076d5abc11084634e2d197e9460643dd455ac3db5856b24d6"}, + {file = "pandas-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6253c72c6a1d990a410bc7de641d34053364ef8bcd3126f7e7450125887dffe3"}, + {file = "pandas-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:1b07204a219b3b7350abaae088f451860223a52cfb8a6c53358e7948735158e5"}, + {file = "pandas-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2462b1a365b6109d275250baaae7b760fd25c726aaca0054649286bcfbb3e8ec"}, + {file = "pandas-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0242fe9a49aa8b4d78a4fa03acb397a58833ef6199e9aa40a95f027bb3a1b6e7"}, + {file = "pandas-2.3.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a21d830e78df0a515db2b3d2f5570610f5e6bd2e27749770e8bb7b524b89b450"}, + {file = "pandas-2.3.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e3ebdb170b5ef78f19bfb71b0dc5dc58775032361fa188e814959b74d726dd5"}, + {file = "pandas-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d051c0e065b94b7a3cea50eb1ec32e912cd96dba41647eb24104b6c6c14c5788"}, + {file = "pandas-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3869faf4bd07b3b66a9f462417d0ca3a9df29a9f6abd5d0d0dbab15dac7abe87"}, + {file = "pandas-2.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c503ba5216814e295f40711470446bc3fd00f0faea8a086cbc688808e26f92a2"}, + {file = "pandas-2.3.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a637c5cdfa04b6d6e2ecedcb81fc52ffb0fd78ce2ebccc9ea964df9f658de8c8"}, + {file = "pandas-2.3.3-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:854d00d556406bffe66a4c0802f334c9ad5a96b4f1f868adf036a21b11ef13ff"}, + {file = "pandas-2.3.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bf1f8a81d04ca90e32a0aceb819d34dbd378a98bf923b6398b9a3ec0bf44de29"}, + {file = "pandas-2.3.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:23ebd657a4d38268c7dfbdf089fbc31ea709d82e4923c5ffd4fbd5747133ce73"}, + {file = "pandas-2.3.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5554c929ccc317d41a5e3d1234f3be588248e61f08a74dd17c9eabb535777dc9"}, + {file = "pandas-2.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:d3e28b3e83862ccf4d85ff19cf8c20b2ae7e503881711ff2d534dc8f761131aa"}, + {file = "pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b"}, ] [package.dependencies] numpy = [ - {version = ">=1.22.4,<2", markers = "python_version < \"3.11\""}, - {version = ">=1.23.2,<2", markers = "python_version == \"3.11\""}, - {version = ">=1.26.0,<2", markers = "python_version >= \"3.12\""}, + {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, + {version = ">=1.23.2", markers = "python_version == \"3.11\""}, + {version = ">=1.22.4", markers = "python_version < \"3.11\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" @@ -2976,6 +3626,7 @@ parquet = ["pyarrow (>=10.0.1)"] performance = ["bottleneck (>=1.3.6)", "numba (>=0.56.4)", "numexpr (>=2.8.4)"] plot = ["matplotlib (>=3.6.3)"] postgresql = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "psycopg2 (>=2.9.6)"] +pyarrow = ["pyarrow (>=10.0.1)"] spss = ["pyreadstat (>=1.2.0)"] sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)"] test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] @@ -3011,140 +3662,143 @@ pyasn1 = "*" [[package]] name = "pillow" -version = "10.4.0" -description = "Python Imaging Library (Fork)" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e"}, - {file = "pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d"}, - {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856"}, - {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f"}, - {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b"}, - {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc"}, - {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e"}, - {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46"}, - {file = "pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984"}, - {file = "pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141"}, - {file = "pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1"}, - {file = "pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c"}, - {file = "pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be"}, - {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3"}, - {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6"}, - {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe"}, - {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319"}, - {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d"}, - {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696"}, - {file = "pillow-10.4.0-cp311-cp311-win32.whl", hash = "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496"}, - {file = "pillow-10.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91"}, - {file = "pillow-10.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22"}, - {file = "pillow-10.4.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94"}, - {file = "pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597"}, - {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80"}, - {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca"}, - {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef"}, - {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a"}, - {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b"}, - {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9"}, - {file = "pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42"}, - {file = "pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a"}, - {file = "pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9"}, - {file = "pillow-10.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3"}, - {file = "pillow-10.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb"}, - {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70"}, - {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be"}, - {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0"}, - {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc"}, - {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a"}, - {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309"}, - {file = "pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060"}, - {file = "pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea"}, - {file = "pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d"}, - {file = "pillow-10.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736"}, - {file = "pillow-10.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b"}, - {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2"}, - {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680"}, - {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b"}, - {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd"}, - {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84"}, - {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0"}, - {file = "pillow-10.4.0-cp38-cp38-win32.whl", hash = "sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e"}, - {file = "pillow-10.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab"}, - {file = "pillow-10.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d"}, - {file = "pillow-10.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b"}, - {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd"}, - {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126"}, - {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b"}, - {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c"}, - {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1"}, - {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df"}, - {file = "pillow-10.4.0-cp39-cp39-win32.whl", hash = "sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef"}, - {file = "pillow-10.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5"}, - {file = "pillow-10.4.0-cp39-cp39-win_arm64.whl", hash = "sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885"}, - {file = "pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27"}, - {file = "pillow-10.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3"}, - {file = "pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06"}, +version = "12.3.0" +description = "Python Imaging Library (fork)" +optional = false +python-versions = ">=3.10" +files = [ + {file = "pillow-12.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:6c0016e7b354317c4e9e525b937ac8596c38d2d232b419529b9cd7a1cd46e39a"}, + {file = "pillow-12.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bcc33feacfaefce60c12fd500a277533bdc02b10a19f7f6d348763d8140bbba7"}, + {file = "pillow-12.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5594fc43d548a7ed94949d139aa1341b270f1863f11cfd37f5a6c8b778a6b67f"}, + {file = "pillow-12.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f0606c8bf2cdefea14a43530f7657cbbb7ecf1c4222512492ef4a4434a9501ec"}, + {file = "pillow-12.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:85f998ea1848bc6757289e739cfbdda3a04adfd58b02fc018ce54d754a5ce468"}, + {file = "pillow-12.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:25b9b82bb22e6e2b3cd07b39c68b7b862001226cb3dff7130d1cb914121b39ed"}, + {file = "pillow-12.3.0-cp310-cp310-win32.whl", hash = "sha256:37dc8f7bbb66efe481bb60defacef820c950c24713fb44962ed6aa2a50966de1"}, + {file = "pillow-12.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:300557495eb45ebb8aec96c2da9c4be642fbf7cd937278b4013ba894ea8eb0eb"}, + {file = "pillow-12.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:514435a37670e3e5e08f3945b68718b6ed329bb84367777e16f9f4dfe1e61a0f"}, + {file = "pillow-12.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:00808c5e14ef63ac5161091d242999076604ff74b883423a11e5d7bbb38bf756"}, + {file = "pillow-12.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:37d6d0a00072fd2948eb22bce7e1475f34569d90c87c59f7a2ec59541b77f7a6"}, + {file = "pillow-12.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bcb46e2f9feff8d06323983bd83ed00c201fdcab3d74973e7072a889b3979fcd"}, + {file = "pillow-12.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23d27a3e0307ec2244cc51e7287b919aa68d097504ebe19df4e76a98a3eea5bd"}, + {file = "pillow-12.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4f883547d4b7f0495ebe7056b0cc2aea76094e7a4abc8e933540f3271df27d9c"}, + {file = "pillow-12.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:236ff70b9312fb68943c703aa842ca6a758abfa45ac187a5e7c1452e96ef72b5"}, + {file = "pillow-12.3.0-cp311-cp311-win32.whl", hash = "sha256:10e41f0fbf1eec8cfd234b8fe17a4caac7c9d0db4c204d3c173a8f9f6ef3232b"}, + {file = "pillow-12.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8e95e1385e4998ae9694eeaa4730ba5457ff61185b3a55e2e7bea0880aef452a"}, + {file = "pillow-12.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:ebaea975e03d3141d9d3a507df75c9b3ec90fa9d2ffd07567b3a978d9d790b26"}, + {file = "pillow-12.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ba09209fbe443b4acccebe845d8a138b89a8f4fbaeedd44953490b5315d5e965"}, + {file = "pillow-12.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffd0c5368496f41b0944be820fcb7a838aa6e623d250b01acf2643939c3f99d7"}, + {file = "pillow-12.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9c7f76c0673154f044e9d78c8655fb4213f6ca31a836df48b40fe5d187717b9"}, + {file = "pillow-12.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:78cb2c6865a35ab8ff8b75fd122f6033b92a62c82801110e48ddd6c936a45d91"}, + {file = "pillow-12.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e491916b378fba47242221bb9ead245211b70d504f495d105d17b14a24b4907c"}, + {file = "pillow-12.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0dd2064cbc55aaec028ef5fbb60fa47bb6c3e7918e07ff17935284b227a9d2df"}, + {file = "pillow-12.3.0-cp312-cp312-win32.whl", hash = "sha256:dbce0b29841537a2fa4a214c2bbf14de3587c9680caa9b4e217568472490b28f"}, + {file = "pillow-12.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a2b55dd6b2a4c4b7d87ffa56bdb33fdc5fdb9a462173861a7bc097f17d91cb09"}, + {file = "pillow-12.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:331b624368d4f1d069149002f25f44bc61c8919ce8ddb3c45bdad8f6e2d89510"}, + {file = "pillow-12.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:21900ce7ba264168cd50defae43cd75d25c833ad4ad6e73ffc5596d12e25ac89"}, + {file = "pillow-12.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:4e8c2a84d977f50b9daed6eeaf3baef67d00d5d74d932288f02cb94518ee3ace"}, + {file = "pillow-12.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:ae26d61dfa7a47befdc7572b521024e8745f3d809bd95ca9505a7bba9ef849ec"}, + {file = "pillow-12.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7a743ff716f746fc19a9557f60dab1600d4613255f8a7aeb3cdde4db7eb15a66"}, + {file = "pillow-12.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d69141514cc30b774ceea5e3ed3a6635c8d8a96edf664689b890f4089111fb35"}, + {file = "pillow-12.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f7401aebd7f581d7f83a439d87d474999317ee099218e5ad25d125290990ba65"}, + {file = "pillow-12.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0847a763afefb695bc912d7c131e7e0632d4edc1d8698f58ddabec8e46b8b6d3"}, + {file = "pillow-12.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:571b9fcb07b97ef3a492028fb3d2dc0993ca23a06138b0315286566d29ef718a"}, + {file = "pillow-12.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:756c768d0c9c2955feb7a56c37ea24aea2e369f8d36a88da270b6a9f19e62b5e"}, + {file = "pillow-12.3.0-cp313-cp313-win32.whl", hash = "sha256:a876864214e136f0eb367788dbd7df045f4806801518e2cfe9e13229cfe06d8f"}, + {file = "pillow-12.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:1cca606cd25738df4ed873d5ad46bbdb3d83b5cbca291f6b4ff13a4df6b0bbe8"}, + {file = "pillow-12.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:b629de27fda84b42cde7edef0d85f13b958b47f6e9bbcbba9b673c562a89bd8b"}, + {file = "pillow-12.3.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:9cf95fe4d0f84c82d282745d9bb08ad9f926efa00be4697e767b814ce40d4330"}, + {file = "pillow-12.3.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:8728f216dcdb6e6d555cf971cb34076139ad74b31fc2c14da4fafc741c5f6217"}, + {file = "pillow-12.3.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:a45650e8ce7fafffd731db8550230db6b0d306d181a90b67d3e6bca2f1990930"}, + {file = "pillow-12.3.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ba54cfebe86920a559a7c4d6b9050791c20513650a1952ebe3368c7dc70306f8"}, + {file = "pillow-12.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e158cb00350dc278f3b91551101aa7d12415a66ebf2c91d8d5ac14e56ddd3ad0"}, + {file = "pillow-12.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9aeb04d6aef139de265b29683e119b638208f88cf73cdd1658aa07221165321"}, + {file = "pillow-12.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:251bf95b67017e27b13d82f5b326234ca62d70f9cf4c2b9032de2358a3b12c7b"}, + {file = "pillow-12.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fe3cca2e4e8a592be0f269a1ca4835c25199d9f3ce815c8491048f785b0a0198"}, + {file = "pillow-12.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:23aceaa007d6172b02c277f0cd359c79492bbb14f7072b4ede9fbcaf20648130"}, + {file = "pillow-12.3.0-cp314-cp314-win32.whl", hash = "sha256:af8d94b0db561cf68b88a267c5c44b49e134f525d0dc2cb7ed413a66bc23559a"}, + {file = "pillow-12.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:fdafc9cce40277e0f7a0feabce0ee50dd2fa1800f3b38015e51296b5e814048d"}, + {file = "pillow-12.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:e91206ee562682b51b98ef4b26a6ef48fd84e15fd4c4bc5ec768eb641d206838"}, + {file = "pillow-12.3.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:164b31cd1a0490ab6efae01aa5df49da7061be0af1b30e035b6e9a1bfe34ee6e"}, + {file = "pillow-12.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5afb51d599ea772b8365ae807ae557f18bccfe46ab261fd1c2a9ed700fc6eb17"}, + {file = "pillow-12.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3edce1d53195db527e0191f84b71d02022de0540bf43a16ed734ed7537b07385"}, + {file = "pillow-12.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bf16ba1b4d0b6b7c8e534936632270cf70eb00dbe09005bc345b2677b726855c"}, + {file = "pillow-12.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:24870b09b224f7ae3c39ed07d10e819d06f8720bc551847b1d623832b5b0e28d"}, + {file = "pillow-12.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:30f2aa603c41533cc25c05acd0da21636e84a315768feb631c937177db558931"}, + {file = "pillow-12.3.0-cp314-cp314t-win32.whl", hash = "sha256:4b0a7fe987b14c31ebda6083f74f22b561fd3739bc0ac51e019622e3d72668c7"}, + {file = "pillow-12.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:962864dc93511324d51ddbb5b9f8731bf71675b93ca612a07441896f4688fb8c"}, + {file = "pillow-12.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0740a512dc522224c77d9aa5a8d70d8b7d73fb91f2c21125d8d025d3b8990e45"}, + {file = "pillow-12.3.0-cp315-cp315-ios_13_0_arm64_iphoneos.whl", hash = "sha256:0feb2e9d6ad6c9e3c06effe9d00f3f1e618a6643273576b016f591e9315a7139"}, + {file = "pillow-12.3.0-cp315-cp315-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:9e881fca225083806662a5c43d627d215f258ff43c890f831966c7d7ba9c7402"}, + {file = "pillow-12.3.0-cp315-cp315-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:4998562bf62a445225f22e07c896bb04b35b1b1f2eb6d760584c9c51d7a5f78c"}, + {file = "pillow-12.3.0-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:dc624f6bc473dacdf7ef7eb8678d0d08edf15cd94fad6ae5c7d6cc67a4e4902f"}, + {file = "pillow-12.3.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:71d6097b330eea8fd15097780c8e89cb1a8ce7838669f48c5bacd6f663dd4701"}, + {file = "pillow-12.3.0-cp315-cp315-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:28ce87c5ab450a9dd970b52e5aca5fe63ed432d18a2eaddd1979a00a1ba24ace"}, + {file = "pillow-12.3.0-cp315-cp315-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6b02afb9b97f65fbca5f31db6a2a3ba21aa93030225f150fa3f249717e938fb4"}, + {file = "pillow-12.3.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:1182d52bc2d5e5d7d0949503aa7e36d12f42205dc287e4883f407b1988820d39"}, + {file = "pillow-12.3.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:e795b7eb908249c4e43c7c99fac7c2c75dab0c43566e37db472a355f63693d71"}, + {file = "pillow-12.3.0-cp315-cp315-win32.whl", hash = "sha256:57b3d78c95ba9059768b10e28b813002261d3f3dfc55cc48b0c988f625175827"}, + {file = "pillow-12.3.0-cp315-cp315-win_amd64.whl", hash = "sha256:fa4ecea169a355be7a3ade2c783e2ed12f0e40d2c5621cda8b3297faf7fbb9f5"}, + {file = "pillow-12.3.0-cp315-cp315-win_arm64.whl", hash = "sha256:877c3f311ff35410f690861c4409e7ccbf0cd2f878e50628a28e5a0bb689e658"}, + {file = "pillow-12.3.0-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:e9871b1ffbfa9656b60aeee92ed5136a5742696006fa322b29ea3d8da0ecc9cf"}, + {file = "pillow-12.3.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:53aa02d20d10c3d814d536aa4e5ac9b84ca0ff5a88377963b085ad6822f93e64"}, + {file = "pillow-12.3.0-cp315-cp315t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:446c34dcc4324b084a53b705127dc15717b22c5e140ae0a3c38349d4efec071e"}, + {file = "pillow-12.3.0-cp315-cp315t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf1845d02ad822a369a49f2bb9345b1614744267682e7a03527dc3bf6eea1777"}, + {file = "pillow-12.3.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:186941b6aef820ad110fb01fb06eb925374dc3a21b17e37ec9a53b250c6fe2d1"}, + {file = "pillow-12.3.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:f13c32a3abd6079a66d9526e18dad9b6d280384d49d7c54040cd57b6424041d9"}, + {file = "pillow-12.3.0-cp315-cp315t-win32.whl", hash = "sha256:1657923d2d45afb66526e5b933e5b3052e6bdea196c90d3abb2424e18c77dae8"}, + {file = "pillow-12.3.0-cp315-cp315t-win_amd64.whl", hash = "sha256:8cd2f7bdda092d99c9fc2fb7391354f306d01443d22785d0cbfafa2e2c8bb418"}, + {file = "pillow-12.3.0-cp315-cp315t-win_arm64.whl", hash = "sha256:06ff022112bc9cbf83b60f8e028d94ad87b60621706487e65f673de61610ab59"}, + {file = "pillow-12.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b3c777e849237620b022f7f297dd67705f9f5cf1685f09f02e46f93e92725468"}, + {file = "pillow-12.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:b343699e8308bdc51978310e1c959c584e7869cc8c40780058c87da7781a1e94"}, + {file = "pillow-12.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbd139c8447d25dd750ab79ee274cc5e1fe80fc56340ab10b18a195e1b6eca3e"}, + {file = "pillow-12.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e7e480451b9fa137494bccd3a7d69adbe8ac65a87d97be61e11f1b1050a5bac3"}, + {file = "pillow-12.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:04f01d28a6aaff387bf842a13be313df23ba0597a44f1a976c9feb3c6ff4711a"}, + {file = "pillow-12.3.0.tar.gz", hash = "sha256:3b8182a766685eaa002637e28b4ec8d6b18819a0c71f579bf0dbaa5830297cce"}, ] [package.extras] -docs = ["furo", "olefile", "sphinx (>=7.3)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] +docs = ["furo", "olefile", "sphinx (>=8.2)", "sphinx-autobuild", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] fpx = ["olefile"] mic = ["olefile"] -tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] -typing = ["typing-extensions"] +test-arrow = ["arro3-compute", "arro3-core", "nanoarrow", "pyarrow"] +tests = ["coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "setuptools", "trove-classifiers (>=2024.10.12)"] xmp = ["defusedxml"] [[package]] name = "platformdirs" -version = "4.1.0" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +version = "4.10.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, - {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, + {file = "platformdirs-4.10.0-py3-none-any.whl", hash = "sha256:fb516cdb12eb0d857d0cd85a7c57cea4d060bee4578d6cf5a14dfdf8cbf8784a"}, + {file = "platformdirs-4.10.0.tar.gz", hash = "sha256:31e761a6a0ca04faf7353ea759bdba55652be214725111e5aac52dfa29d4bef7"}, ] -[package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] - [[package]] name = "pluggy" -version = "1.4.0" +version = "1.6.0" description = "plugin and hook calling mechanisms for python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, - {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, + {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, + {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, ] [package.extras] dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] +testing = ["coverage", "pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "3.6.0" +version = "4.6.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" files = [ - {file = "pre_commit-3.6.0-py2.py3-none-any.whl", hash = "sha256:c255039ef399049a5544b6ce13d135caba8f2c28c3b4033277a788f434308376"}, - {file = "pre_commit-3.6.0.tar.gz", hash = "sha256:d30bad9abf165f7785c15a21a1f46da7d0677cb00ee7ff4c579fd38922efe15d"}, + {file = "pre_commit-4.6.0-py2.py3-none-any.whl", hash = "sha256:e2cf246f7299edcabcf15f9b0571fdce06058527f0a06535068a86d38089f29b"}, + {file = "pre_commit-4.6.0.tar.gz", hash = "sha256:718d2208cef53fdc38206e40524a6d4d9576d103eb16f0fec11c875e7716e9d9"}, ] [package.dependencies] @@ -3156,382 +3810,539 @@ virtualenv = ">=20.10.0" [[package]] name = "propcache" -version = "0.3.0" +version = "0.5.2" description = "Accelerated property cache" optional = false -python-versions = ">=3.9" -files = [ - {file = "propcache-0.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:efa44f64c37cc30c9f05932c740a8b40ce359f51882c70883cc95feac842da4d"}, - {file = "propcache-0.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2383a17385d9800b6eb5855c2f05ee550f803878f344f58b6e194de08b96352c"}, - {file = "propcache-0.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d3e7420211f5a65a54675fd860ea04173cde60a7cc20ccfbafcccd155225f8bc"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3302c5287e504d23bb0e64d2a921d1eb4a03fb93a0a0aa3b53de059f5a5d737d"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7e2e068a83552ddf7a39a99488bcba05ac13454fb205c847674da0352602082f"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d913d36bdaf368637b4f88d554fb9cb9d53d6920b9c5563846555938d5450bf"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ee1983728964d6070ab443399c476de93d5d741f71e8f6e7880a065f878e0b9"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:36ca5e9a21822cc1746023e88f5c0af6fce3af3b85d4520efb1ce4221bed75cc"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9ecde3671e62eeb99e977f5221abcf40c208f69b5eb986b061ccec317c82ebd0"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d383bf5e045d7f9d239b38e6acadd7b7fdf6c0087259a84ae3475d18e9a2ae8b"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:8cb625bcb5add899cb8ba7bf716ec1d3e8f7cdea9b0713fa99eadf73b6d4986f"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5fa159dcee5dba00c1def3231c249cf261185189205073bde13797e57dd7540a"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:a7080b0159ce05f179cfac592cda1a82898ca9cd097dacf8ea20ae33474fbb25"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ed7161bccab7696a473fe7ddb619c1d75963732b37da4618ba12e60899fefe4f"}, - {file = "propcache-0.3.0-cp310-cp310-win32.whl", hash = "sha256:bf0d9a171908f32d54f651648c7290397b8792f4303821c42a74e7805bfb813c"}, - {file = "propcache-0.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:42924dc0c9d73e49908e35bbdec87adedd651ea24c53c29cac103ede0ea1d340"}, - {file = "propcache-0.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9ddd49258610499aab83b4f5b61b32e11fce873586282a0e972e5ab3bcadee51"}, - {file = "propcache-0.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2578541776769b500bada3f8a4eeaf944530516b6e90c089aa368266ed70c49e"}, - {file = "propcache-0.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8074c5dd61c8a3e915fa8fc04754fa55cfa5978200d2daa1e2d4294c1f136aa"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b58229a844931bca61b3a20efd2be2a2acb4ad1622fc026504309a6883686fbf"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e45377d5d6fefe1677da2a2c07b024a6dac782088e37c0b1efea4cfe2b1be19b"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ec5060592d83454e8063e487696ac3783cc48c9a329498bafae0d972bc7816c9"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15010f29fbed80e711db272909a074dc79858c6d28e2915704cfc487a8ac89c6"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a254537b9b696ede293bfdbc0a65200e8e4507bc9f37831e2a0318a9b333c85c"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2b975528998de037dfbc10144b8aed9b8dd5a99ec547f14d1cb7c5665a43f075"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:19d36bb351ad5554ff20f2ae75f88ce205b0748c38b146c75628577020351e3c"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6032231d4a5abd67c7f71168fd64a47b6b451fbcb91c8397c2f7610e67683810"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6985a593417cdbc94c7f9c3403747335e450c1599da1647a5af76539672464d3"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:6a1948df1bb1d56b5e7b0553c0fa04fd0e320997ae99689488201f19fa90d2e7"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8319293e85feadbbfe2150a5659dbc2ebc4afdeaf7d98936fb9a2f2ba0d4c35c"}, - {file = "propcache-0.3.0-cp311-cp311-win32.whl", hash = "sha256:63f26258a163c34542c24808f03d734b338da66ba91f410a703e505c8485791d"}, - {file = "propcache-0.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:cacea77ef7a2195f04f9279297684955e3d1ae4241092ff0cfcef532bb7a1c32"}, - {file = "propcache-0.3.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e53d19c2bf7d0d1e6998a7e693c7e87300dd971808e6618964621ccd0e01fe4e"}, - {file = "propcache-0.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a61a68d630e812b67b5bf097ab84e2cd79b48c792857dc10ba8a223f5b06a2af"}, - {file = "propcache-0.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fb91d20fa2d3b13deea98a690534697742029f4fb83673a3501ae6e3746508b5"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67054e47c01b7b349b94ed0840ccae075449503cf1fdd0a1fdd98ab5ddc2667b"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:997e7b8f173a391987df40f3b52c423e5850be6f6df0dcfb5376365440b56667"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d663fd71491dde7dfdfc899d13a067a94198e90695b4321084c6e450743b8c7"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8884ba1a0fe7210b775106b25850f5e5a9dc3c840d1ae9924ee6ea2eb3acbfe7"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa806bbc13eac1ab6291ed21ecd2dd426063ca5417dd507e6be58de20e58dfcf"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6f4d7a7c0aff92e8354cceca6fe223973ddf08401047920df0fcb24be2bd5138"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:9be90eebc9842a93ef8335291f57b3b7488ac24f70df96a6034a13cb58e6ff86"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:bf15fc0b45914d9d1b706f7c9c4f66f2b7b053e9517e40123e137e8ca8958b3d"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5a16167118677d94bb48bfcd91e420088854eb0737b76ec374b91498fb77a70e"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:41de3da5458edd5678b0f6ff66691507f9885f5fe6a0fb99a5d10d10c0fd2d64"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:728af36011bb5d344c4fe4af79cfe186729efb649d2f8b395d1572fb088a996c"}, - {file = "propcache-0.3.0-cp312-cp312-win32.whl", hash = "sha256:6b5b7fd6ee7b54e01759f2044f936dcf7dea6e7585f35490f7ca0420fe723c0d"}, - {file = "propcache-0.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:2d15bc27163cd4df433e75f546b9ac31c1ba7b0b128bfb1b90df19082466ff57"}, - {file = "propcache-0.3.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a2b9bf8c79b660d0ca1ad95e587818c30ccdb11f787657458d6f26a1ea18c568"}, - {file = "propcache-0.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b0c1a133d42c6fc1f5fbcf5c91331657a1ff822e87989bf4a6e2e39b818d0ee9"}, - {file = "propcache-0.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bb2f144c6d98bb5cbc94adeb0447cfd4c0f991341baa68eee3f3b0c9c0e83767"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1323cd04d6e92150bcc79d0174ce347ed4b349d748b9358fd2e497b121e03c8"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b812b3cb6caacd072276ac0492d249f210006c57726b6484a1e1805b3cfeea0"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:742840d1d0438eb7ea4280f3347598f507a199a35a08294afdcc560c3739989d"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c6e7e4f9167fddc438cd653d826f2222222564daed4116a02a184b464d3ef05"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a94ffc66738da99232ddffcf7910e0f69e2bbe3a0802e54426dbf0714e1c2ffe"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c6ec957025bf32b15cbc6b67afe233c65b30005e4c55fe5768e4bb518d712f1"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:549722908de62aa0b47a78b90531c022fa6e139f9166be634f667ff45632cc92"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5d62c4f6706bff5d8a52fd51fec6069bef69e7202ed481486c0bc3874912c787"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:24c04f8fbf60094c531667b8207acbae54146661657a1b1be6d3ca7773b7a545"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7c5f5290799a3f6539cc5e6f474c3e5c5fbeba74a5e1e5be75587746a940d51e"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4fa0e7c9c3cf7c276d4f6ab9af8adddc127d04e0fcabede315904d2ff76db626"}, - {file = "propcache-0.3.0-cp313-cp313-win32.whl", hash = "sha256:ee0bd3a7b2e184e88d25c9baa6a9dc609ba25b76daae942edfb14499ac7ec374"}, - {file = "propcache-0.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:1c8f7d896a16da9455f882870a507567d4f58c53504dc2d4b1e1d386dfe4588a"}, - {file = "propcache-0.3.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e560fd75aaf3e5693b91bcaddd8b314f4d57e99aef8a6c6dc692f935cc1e6bbf"}, - {file = "propcache-0.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:65a37714b8ad9aba5780325228598a5b16c47ba0f8aeb3dc0514701e4413d7c0"}, - {file = "propcache-0.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:07700939b2cbd67bfb3b76a12e1412405d71019df00ca5697ce75e5ef789d829"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c0fdbdf6983526e269e5a8d53b7ae3622dd6998468821d660d0daf72779aefa"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:794c3dd744fad478b6232289c866c25406ecdfc47e294618bdf1697e69bd64a6"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4544699674faf66fb6b4473a1518ae4999c1b614f0b8297b1cef96bac25381db"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fddb8870bdb83456a489ab67c6b3040a8d5a55069aa6f72f9d872235fbc52f54"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f857034dc68d5ceb30fb60afb6ff2103087aea10a01b613985610e007053a121"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:02df07041e0820cacc8f739510078f2aadcfd3fc57eaeeb16d5ded85c872c89e"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f47d52fd9b2ac418c4890aad2f6d21a6b96183c98021f0a48497a904199f006e"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9ff4e9ecb6e4b363430edf2c6e50173a63e0820e549918adef70515f87ced19a"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ecc2920630283e0783c22e2ac94427f8cca29a04cfdf331467d4f661f4072dac"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:c441c841e82c5ba7a85ad25986014be8d7849c3cfbdb6004541873505929a74e"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6c929916cbdb540d3407c66f19f73387f43e7c12fa318a66f64ac99da601bcdf"}, - {file = "propcache-0.3.0-cp313-cp313t-win32.whl", hash = "sha256:0c3e893c4464ebd751b44ae76c12c5f5c1e4f6cbd6fbf67e3783cd93ad221863"}, - {file = "propcache-0.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:75e872573220d1ee2305b35c9813626e620768248425f58798413e9c39741f46"}, - {file = "propcache-0.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:03c091bb752349402f23ee43bb2bff6bd80ccab7c9df6b88ad4322258d6960fc"}, - {file = "propcache-0.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:46ed02532cb66612d42ae5c3929b5e98ae330ea0f3900bc66ec5f4862069519b"}, - {file = "propcache-0.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11ae6a8a01b8a4dc79093b5d3ca2c8a4436f5ee251a9840d7790dccbd96cb649"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df03cd88f95b1b99052b52b1bb92173229d7a674df0ab06d2b25765ee8404bce"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03acd9ff19021bd0567582ac88f821b66883e158274183b9e5586f678984f8fe"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd54895e4ae7d32f1e3dd91261df46ee7483a735017dc6f987904f194aa5fd14"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26a67e5c04e3119594d8cfae517f4b9330c395df07ea65eab16f3d559b7068fe"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee25f1ac091def37c4b59d192bbe3a206298feeb89132a470325bf76ad122a1e"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:58e6d2a5a7cb3e5f166fd58e71e9a4ff504be9dc61b88167e75f835da5764d07"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:be90c94570840939fecedf99fa72839aed70b0ced449b415c85e01ae67422c90"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:49ea05212a529c2caffe411e25a59308b07d6e10bf2505d77da72891f9a05641"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:119e244ab40f70a98c91906d4c1f4c5f2e68bd0b14e7ab0a06922038fae8a20f"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:507c5357a8d8b4593b97fb669c50598f4e6cccbbf77e22fa9598aba78292b4d7"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8526b0941ec5a40220fc4dfde76aed58808e2b309c03e9fa8e2260083ef7157f"}, - {file = "propcache-0.3.0-cp39-cp39-win32.whl", hash = "sha256:7cedd25e5f678f7738da38037435b340694ab34d424938041aa630d8bac42663"}, - {file = "propcache-0.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:bf4298f366ca7e1ad1d21bbb58300a6985015909964077afd37559084590c929"}, - {file = "propcache-0.3.0-py3-none-any.whl", hash = "sha256:67dda3c7325691c2081510e92c561f465ba61b975f481735aefdfc845d2cd043"}, - {file = "propcache-0.3.0.tar.gz", hash = "sha256:a8fd93de4e1d278046345f49e2238cdb298589325849b2645d4a94c53faeffc5"}, +python-versions = ">=3.10" +files = [ + {file = "propcache-0.5.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5a81be28596d6559f6131ef33e10200de6e17643b3c74ce03f9eb103be6ae8b"}, + {file = "propcache-0.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29cbaac5ea0212663e6845e04b5e188d5a6ae6dd919810ac835bf1d3b42c3f4c"}, + {file = "propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6bf3be92233808fcd338eba0fb4d0b59ec5772af4f4ecfcec450d1bfc0f8b5eb"}, + {file = "propcache-0.5.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2f8ea531c794b9d6274acd4e8d2c2ebcac590a4361d27482edd3010b79f1325e"}, + {file = "propcache-0.5.2-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:decfca4c79dd53ebab484b00cc4b6717d8c369f86e74aa4ca395a64ac651495e"}, + {file = "propcache-0.5.2-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4621064bbf28fa77ff64dd5d94367c04684c67d3a5bf1dff25f0cd0d98a38f3b"}, + {file = "propcache-0.5.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b96db7141a592cbc968daf1feea83a118e6ab378af4abbc72b248c895414c22d"}, + {file = "propcache-0.5.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1ca071adabaab6e9219924bbe00af821f1ee7de113a9eca1cdc292de3d120f4d"}, + {file = "propcache-0.5.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e4294d04a94dcab1b3bccd8b66d962dcad411a1d19414b2a41d1445f1de32ad0"}, + {file = "propcache-0.5.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a0e399a2eccb91ed18721f86aa85757727400b6865c89e88934781deb9c8498b"}, + {file = "propcache-0.5.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:823581fd5cb08b12a48bfa11fe962a7916766b6170c17b028fbdf762b85eb9bf"}, + {file = "propcache-0.5.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:949c91d1a990cf3b2e8188dfcfb25005e0b834a06c63fa4ef9f360878ce21ecf"}, + {file = "propcache-0.5.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:cc1177027eda740fdb152706bd215a3f124e3eea15afc39f2cb9fe351b50619e"}, + {file = "propcache-0.5.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b05d643f944a8c3c4bd86d65ffd87bf3264b617f87791940302bc474d2ff5274"}, + {file = "propcache-0.5.2-cp310-cp310-win32.whl", hash = "sha256:8114f28879e0904748e831c3a7774261bd9e75f49be089f389a76f959dcd13fe"}, + {file = "propcache-0.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:5fcb98e7598b1ee0addab320d90f65b530297a867dbfe9de52ea838077e16e3d"}, + {file = "propcache-0.5.2-cp310-cp310-win_arm64.whl", hash = "sha256:04dc2390d9edbbaef7461f33322555976ffddf0b650a038649d026358714e6c5"}, + {file = "propcache-0.5.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:74b70780220e2dd89175ca24b81b68b67c83db499ae611e7f2313cb329801c78"}, + {file = "propcache-0.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a4840ab0ae0216d952f4b53dc6d0b992bfc2bedbfe360bdd9b548bc184c08959"}, + {file = "propcache-0.5.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c6844ba6364fb12f403928a82cfd295ab103a2b315c77c747b2dbe4a41894ea7"}, + {file = "propcache-0.5.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2293949b855ce597f2826452d17c2d545fb5622379c4ea6fdf525e9b8e8a2511"}, + {file = "propcache-0.5.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0fd59b5af35f74da48d905dcbad55449ba13be91823cb05a9bd590bbf5b61660"}, + {file = "propcache-0.5.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29f9309a2e42b0d273be006fdb4be2d6c39a47f6f57d8fb1cf9f81481df81b66"}, + {file = "propcache-0.5.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5aaa2b923c1944ac8febd6609cb373540a5563e7cbcb0fd770f75dace2eb817b"}, + {file = "propcache-0.5.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:66ea454f095ddf5b6b14f56c064c0941c4788be11e18d2464cf643bf7203ff67"}, + {file = "propcache-0.5.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:95f1e3f4760d404b13c9976c0229b2b49a3c8e2c62a9ce92efdd2b11ada75e3f"}, + {file = "propcache-0.5.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:85341b12b9d55bad0bded24cac341bb34289469e03a11f3f583ea1cc1db0326c"}, + {file = "propcache-0.5.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:26a4dca084132874e639895c3135dfad5eb20bae209f62d1aeb31b03e601c3c0"}, + {file = "propcache-0.5.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3b199b9b2b3d6a7edf3183ba8a9a137a22b97f7df525feb5ae1eccf026d2a9c6"}, + {file = "propcache-0.5.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e59bc9e66329185b93dab73f210f1a37f81cb40f321501db8017c9aea15dba27"}, + {file = "propcache-0.5.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:552ffadf6ad409844bc5919c42a0a83d88314cedddaea0e41e80a8b8fffe881f"}, + {file = "propcache-0.5.2-cp311-cp311-win32.whl", hash = "sha256:cd416c1de191973c52ff1a12a57446bfc7642797b282d7caf2162d7d1b8aa9a0"}, + {file = "propcache-0.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:44e488ef40dbb452700b2b1f8188934121f6648f52c295055662d2191959ff82"}, + {file = "propcache-0.5.2-cp311-cp311-win_arm64.whl", hash = "sha256:54adaa85a22078d1e306304a40984dc5be99d599bf3dc0a24dc98f7daeab89ab"}, + {file = "propcache-0.5.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:806719138ecd720339a12410fb9614ac9b2b2d3a5fdf8235d56981c36f4039ba"}, + {file = "propcache-0.5.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:db2b80ea58eab4f86b2beec3cc8b39e8ff9276ac20e96b7cce43c8ae84cd6b5a"}, + {file = "propcache-0.5.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e5cbfac9f61484f7e9f3597775500cd3ebe8274e9b050c38f9525c77c97520bf"}, + {file = "propcache-0.5.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5dbc581d2814337da56222fab8dc5f161cd798a434e49bac27930aaef798e144"}, + {file = "propcache-0.5.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:857187f381f88c8e2fa2fe56ab94879d011b883d5a2ee5a1b60a8cd2a06846d9"}, + {file = "propcache-0.5.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:178b4a2cdaac1818e2bf1c5a99b94383fa73ea5382e032a48dec07dc5668dc42"}, + {file = "propcache-0.5.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f328175a2cde1f0ff2c4ed8ce968b9dcfb55f3a7153f39e2957ed994da13476"}, + {file = "propcache-0.5.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5671d09a36b06d0fd4a3da0fccbcae360e9b1570924171a15e9e0997f0249fba"}, + {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:80168e2ebe4d3ec6599d10ad8f520304ae1cad9b6c5a95372aef1b66b7bfb53a"}, + {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:45f11346f884bc47444f6e6647131055844134c3175b629f84952e2b5cd62b64"}, + {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8e778ebd44ef4f66ed60a0416b06b489687db264a9c0b3620362f26489492913"}, + {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:c0cb9ed24c8964e172768d455a38254c2dd8a552905729ce006cad3d3dda59b1"}, + {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1d1ad32d9d4355e2be65574fd0bfd3677e7066b009cd5b9b2dee8aa6a6393b33"}, + {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c80f4ba3e8f00189165999a742ee526ebeccedf6c3f7beb0c7df821e9772435a"}, + {file = "propcache-0.5.2-cp312-cp312-win32.whl", hash = "sha256:8c7972d8f193740d9175f0998ab38717e6cd322d5935c5b0fef8c0d323fd9031"}, + {file = "propcache-0.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:d9ee8826a7d47863a08ac44e1a5f611a462eefc3a194b492da242128bec75b42"}, + {file = "propcache-0.5.2-cp312-cp312-win_arm64.whl", hash = "sha256:2800a4a8ead6b28cccd1ec54b59346f0def7922ee1c7598e8499c733cfbb7c84"}, + {file = "propcache-0.5.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:099aaf4b4d1a02265b92a977edf00b5c4f63b3b17ac6de39b0d637c9cac0188a"}, + {file = "propcache-0.5.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:68ce1c44c7a813a7f71ea04315a8c7b330b63db99d059a797a4651bb6f69f117"}, + {file = "propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fc299c129490f55f254cd90be0deca4764e36e9a7c08b4aa588479a3bbed3098"}, + {file = "propcache-0.5.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a6ae2198be502c10f09b2516e7b5d019816924bc3183a43ce792a7bd6625e6f4"}, + {file = "propcache-0.5.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6041d31504dc1779d700e1edcfb08eea334b357620b06681a4eabb57a74e574e"}, + {file = "propcache-0.5.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7eabc04151c78a9f4d5bbb5f1faf571e4defeb4b585e0fe95b60ff2dbe4d3d7"}, + {file = "propcache-0.5.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4db0ba63d693afd40d249bd93f842b5f144f8fcbb83de05660373bcf30517b1d"}, + {file = "propcache-0.5.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1dbcf7675229b35d31abb6547d8ebc8c27a830ac3f9a794edff6254873ec7c0a"}, + {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d310c013aad2c72f1c3f2f8dd3279d460a858c551f97aeb8c63e4693cca7b4d2"}, + {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:06187263ddad280d05b4d8a8b3bb7d164cbebd469236544a42e6d9b28ac6a4fa"}, + {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3115559b8effafd63b142ea5ed53d63a16ea6469cbc63dce4ee194b42db5d853"}, + {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c60462af8e6dc30c35407c7237ea908d777b22862bbee27bc4699c0d8bcdc45a"}, + {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:40314bca9ac559716fe374094fc81c11dcc34b64fd6c585360f5775690505704"}, + {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cfa21e036ce1e1db2be04ba3b85d2df1bb1702fa01932d984c5464c665228ff4"}, + {file = "propcache-0.5.2-cp313-cp313-win32.whl", hash = "sha256:f156a3529f38063b6dbaf356e15602a7f95f8055b1295a438433a6386f10463d"}, + {file = "propcache-0.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:dfed59d0a5aeb01e242e66ff0300bc4a265a7c05f612d30016f0b60b1017d757"}, + {file = "propcache-0.5.2-cp313-cp313-win_arm64.whl", hash = "sha256:ba338430e87ceb9c8f0cf754de38a9860560261e56c00376debd628698a7364f"}, + {file = "propcache-0.5.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a592f5f3da71c8691c788c13cb6734b6d17663d2e1cb8caddf0673d01ef8847d"}, + {file = "propcache-0.5.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6a997d0489e9668a384fcfd5061b857aa5361de73191cac204d04b889cfbbafa"}, + {file = "propcache-0.5.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:10734b5484ea113152ee25a91dccedf81631791805d2c9ccb054958e51842c94"}, + {file = "propcache-0.5.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cafca7e56c12bb02ae16d283742bef25a61122e9dab2b5b3f2ccbe589ce32164"}, + {file = "propcache-0.5.2-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f064f8d2b59177878b7615df1735cd8fe3462ed6be8c7b217d17a276489c2b7f"}, + {file = "propcache-0.5.2-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f78abfa8dfc32376fd1aacf597b2f2fbbe0ea751419aee718af5d4f82537ef8c"}, + {file = "propcache-0.5.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7467da8a9822bf1a55336f877340c5bcbd3c482afc43a99771169f74a26dedc"}, + {file = "propcache-0.5.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a6ddc6ac9e25de626c1f129c1b467d7ecd33ce2237d3fd0c4e429feef0a7ee1f"}, + {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2f22cbbac9e26a8e864c0985ff1268d5d939d53d9d9411a9824279097e03a2cb"}, + {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:fc76378c62a0f04d0cd82fbb1a2cd2d7e28fcb40d5873f28a6c44e388aaa2751"}, + {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:acd2c8edba48e31e58a363b8cf4e5c7db3b04b3f9e371f601df30d9b0d244836"}, + {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:452b5065457eb9991ec5eb38ff41d6cd4c991c9ac7c531c4d5849ae473a9a13f"}, + {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:3430bb2bfe1331885c427745a751e774ee679fd4344f80b97bf879815fe8fa55"}, + {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cef6cea3922890dd6c9654971001fa797b526c16ab5e1e46c05fd6f877be7568"}, + {file = "propcache-0.5.2-cp313-cp313t-win32.whl", hash = "sha256:72d61e16dd78228b58c5d47be830ff3da7e5f139abdf0aef9d86cde1c5cf2191"}, + {file = "propcache-0.5.2-cp313-cp313t-win_amd64.whl", hash = "sha256:0958834041a0166d343b8d2cedcd8bcbaeb4fdbe0cf08320c5379f143c3be6e7"}, + {file = "propcache-0.5.2-cp313-cp313t-win_arm64.whl", hash = "sha256:6de8bd93ddde9b992cf2b2e0d796d501a19026b5b9fd87356d7d0779531a8d96"}, + {file = "propcache-0.5.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:46088abff4cba581dea21ae0467a480526cb25aa5f3c269e909f800328bc3999"}, + {file = "propcache-0.5.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fc88b26f08d634f7bc819a7852e5214f5802641ab8d9fd5326892292eee1993e"}, + {file = "propcache-0.5.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:97797ebb098e670a2f92dd66f32897e30d7615b14e7f59711de23e30a9072539"}, + {file = "propcache-0.5.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba57fffe4ac99c5d30076161b5866336d97600769bad35cc68f7774b15298a4e"}, + {file = "propcache-0.5.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:583c19759d9eec1e5b69e2fbef36a7d9c326041be9746cb822d335c8cedc2979"}, + {file = "propcache-0.5.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d0326e2e5e1f3163fa306c834e48e8d490e5fae607a097a40c0648109b47ba80"}, + {file = "propcache-0.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e00820e192c8dbebcafb383ebbf99030895f09905e7a0eb2e0340a0bcc2bc825"}, + {file = "propcache-0.5.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c66afea89b1e43725731d2004732a046fe6fe955d51f952c3e95a7314a284a39"}, + {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d4dc37dec6c6cdad0b57881a5658fd14fbf53e333b1a86cf86559f190e1d9ec4"}, + {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:5570dbcc97571c15f68068e529c92715a12f8d54030e272d264b377e22bd17a5"}, + {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f814362777a9f841adddb200ecdf8f5cb1e5a3c4b7a86378edbd6ccb26edd702"}, + {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:196913dea116aeb5a2ba95af4ddcb7ea85559ae07d8eee8751688310d09168c3"}, + {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:6e7b8719005dd1175be4ab1cd25e9b98659a5e0347331506ec6760d2773a7fb5"}, + {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:51f96d685ab16e88cab128cd37a52c5da540809c8b879fa047731bfcb4ad35a4"}, + {file = "propcache-0.5.2-cp314-cp314-win32.whl", hash = "sha256:cc6fc3cc62e8501d3ed62894425040d2728ecddb1ed072737a5c70bd537aa9f0"}, + {file = "propcache-0.5.2-cp314-cp314-win_amd64.whl", hash = "sha256:81e3a30b0bb60caa22033dd0f8a3618d1d67356212514f62c57db75cb0ef410c"}, + {file = "propcache-0.5.2-cp314-cp314-win_arm64.whl", hash = "sha256:0d2c9bf8528f135dbb805ce027567e09164f7efa51a2be07458a2c0420f292d0"}, + {file = "propcache-0.5.2-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:4bc8ff1feffc6a61c7002ffe84634c41b822e104990ae009f44a0834430070bb"}, + {file = "propcache-0.5.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:79aa3ff0a9b566633b642fa9caf7e21ed1c13d6feca718187873f199e1514078"}, + {file = "propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1b31822f4474c4036bae62de9402710051d431a606d6a0f907fec79935a071aa"}, + {file = "propcache-0.5.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13fef48778b5a2a756523fdb781326b028ca75e32858b04f2cdd19f394564917"}, + {file = "propcache-0.5.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8b73ab70f1a3351fbc71f663b3e645af6dd0329100c353081cf69c37433fc6fe"}, + {file = "propcache-0.5.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5538d2c13d93e4698af7e092b57bc7298fd35d1d58e656ae18f23ee0d0378e03"}, + {file = "propcache-0.5.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd645f03898405cabe694fb8bc35241e3a9c332ec85627584fe3de201452b335"}, + {file = "propcache-0.5.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a473b3440261e0c60706e732b2ed2f517857344fc21bf48fdfe211e2d98eb285"}, + {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7afa37062e6650640e932e4cc9297d81f9f42d9944029cc386b8247dea4da837"}, + {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:8a90efd5777e996e42d568db9ac740b944d691e565cbfd31b2f7832f9184b2b8"}, + {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:f19bb891234d72535764d703bfed1153cc34f4214d5bd7150aee1eec9e8f4366"}, + {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:32775082acd2d807ee3db715c7770d38767b817870acfa08c29e057f3c4d5b56"}, + {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9282fb1a3bccd038da9f768b927b24a0c753e466c086b7c4f3c6982851eefb2d"}, + {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cc49723e2f60d6b32a0f0b08a3fd6d13203c07f1cd9566cfce0f12a917c967a2"}, + {file = "propcache-0.5.2-cp314-cp314t-win32.whl", hash = "sha256:2d7aa89ebca5acc98cba9d1472d976e394782f587bad6661003602a619fd1821"}, + {file = "propcache-0.5.2-cp314-cp314t-win_amd64.whl", hash = "sha256:d447bb0b3054be5818458fbb171208b1d9ff11eba14e18ca18b90cbb45767370"}, + {file = "propcache-0.5.2-cp314-cp314t-win_arm64.whl", hash = "sha256:fe67a3d11cd9b4efabfa45c3d00ffba2b26811442a73a581a94b67c2b5faccf6"}, + {file = "propcache-0.5.2-py3-none-any.whl", hash = "sha256:be1ddfcbb376e3de5d2e2db1d58d6d67463e6b4f9f040c000de8e300295465fe"}, + {file = "propcache-0.5.2.tar.gz", hash = "sha256:01c4fc7480cd0598bb4b57022df55b9ca296da7fc5a8760bd8451a7e63a7d427"}, +] + +[[package]] +name = "proto-plus" +version = "1.28.1" +description = "Beautiful, Pythonic protocol buffers" +optional = false +python-versions = ">=3.10" +files = [ + {file = "proto_plus-1.28.1-py3-none-any.whl", hash = "sha256:6660f5f1970874bdcfc3088b435188a36a37bd3596668f7d726417c4ae8cfbed"}, + {file = "proto_plus-1.28.1.tar.gz", hash = "sha256:832e68e7fe064cf90ab153b6e5eb935b27891bb89aaeb68b115e9b702f6cb168"}, ] +[package.dependencies] +protobuf = ">=4.25.8,<8.0.0" + +[package.extras] +testing = ["google-api-core (>=1.31.5)"] + [[package]] name = "protobuf" -version = "4.25.2" +version = "7.35.1" description = "" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "protobuf-4.25.2-cp310-abi3-win32.whl", hash = "sha256:b50c949608682b12efb0b2717f53256f03636af5f60ac0c1d900df6213910fd6"}, - {file = "protobuf-4.25.2-cp310-abi3-win_amd64.whl", hash = "sha256:8f62574857ee1de9f770baf04dde4165e30b15ad97ba03ceac65f760ff018ac9"}, - {file = "protobuf-4.25.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:2db9f8fa64fbdcdc93767d3cf81e0f2aef176284071507e3ede160811502fd3d"}, - {file = "protobuf-4.25.2-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:10894a2885b7175d3984f2be8d9850712c57d5e7587a2410720af8be56cdaf62"}, - {file = "protobuf-4.25.2-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:fc381d1dd0516343f1440019cedf08a7405f791cd49eef4ae1ea06520bc1c020"}, - {file = "protobuf-4.25.2-cp38-cp38-win32.whl", hash = "sha256:33a1aeef4b1927431d1be780e87b641e322b88d654203a9e9d93f218ee359e61"}, - {file = "protobuf-4.25.2-cp38-cp38-win_amd64.whl", hash = "sha256:47f3de503fe7c1245f6f03bea7e8d3ec11c6c4a2ea9ef910e3221c8a15516d62"}, - {file = "protobuf-4.25.2-cp39-cp39-win32.whl", hash = "sha256:5e5c933b4c30a988b52e0b7c02641760a5ba046edc5e43d3b94a74c9fc57c1b3"}, - {file = "protobuf-4.25.2-cp39-cp39-win_amd64.whl", hash = "sha256:d66a769b8d687df9024f2985d5137a337f957a0916cf5464d1513eee96a63ff0"}, - {file = "protobuf-4.25.2-py3-none-any.whl", hash = "sha256:a8b7a98d4ce823303145bf3c1a8bdb0f2f4642a414b196f04ad9853ed0c8f830"}, - {file = "protobuf-4.25.2.tar.gz", hash = "sha256:fe599e175cb347efc8ee524bcd4b902d11f7262c0e569ececcb89995c15f0a5e"}, + {file = "protobuf-7.35.1-cp310-abi3-macosx_10_9_universal2.whl", hash = "sha256:24f857477359a85c0c235261b8ba905fd51b2562f4a64ca1df5473f29850cbf6"}, + {file = "protobuf-7.35.1-cp310-abi3-manylinux2014_aarch64.whl", hash = "sha256:11d6b0ec246892d85215b0a13ca6e0233cf5284b68f0ac02646427f4ff88a799"}, + {file = "protobuf-7.35.1-cp310-abi3-manylinux2014_s390x.whl", hash = "sha256:b73f9489a4b8b1c9cb1f8ed951c736392592edb24b9d6819f36d2e10b171d5b4"}, + {file = "protobuf-7.35.1-cp310-abi3-manylinux2014_x86_64.whl", hash = "sha256:74758715c53d7158fb76caf4f0cfdacc5329a4b1bb994f865d6cf302d413a1c4"}, + {file = "protobuf-7.35.1-cp310-abi3-win32.whl", hash = "sha256:353652e4efd0bca5b5fc2656abf8307ef351f0cf938c9eba09f0e09c20a25c30"}, + {file = "protobuf-7.35.1-cp310-abi3-win_amd64.whl", hash = "sha256:230a75ddfc2de4806e56696ce9640c1cdfdb6543b7cfce98d42a4c0a0e7bdb87"}, + {file = "protobuf-7.35.1-py3-none-any.whl", hash = "sha256:4bc97768d8fe4ad6743c8a19403e314511ed9f6d13205b687e52421c023ac1b9"}, + {file = "protobuf-7.35.1.tar.gz", hash = "sha256:ce115a26fe0c39a2c29973d914d327e516a6455464489fe3cd1e51a1b354f81a"}, ] [[package]] name = "psycopg2" -version = "2.9.9" +version = "2.9.12" description = "psycopg2 - Python-PostgreSQL Database Adapter" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "psycopg2-2.9.9-cp310-cp310-win32.whl", hash = "sha256:38a8dcc6856f569068b47de286b472b7c473ac7977243593a288ebce0dc89516"}, - {file = "psycopg2-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:426f9f29bde126913a20a96ff8ce7d73fd8a216cfb323b1f04da402d452853c3"}, - {file = "psycopg2-2.9.9-cp311-cp311-win32.whl", hash = "sha256:ade01303ccf7ae12c356a5e10911c9e1c51136003a9a1d92f7aa9d010fb98372"}, - {file = "psycopg2-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:121081ea2e76729acfb0673ff33755e8703d45e926e416cb59bae3a86c6a4981"}, - {file = "psycopg2-2.9.9-cp312-cp312-win32.whl", hash = "sha256:d735786acc7dd25815e89cc4ad529a43af779db2e25aa7c626de864127e5a024"}, - {file = "psycopg2-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:a7653d00b732afb6fc597e29c50ad28087dcb4fbfb28e86092277a559ae4e693"}, - {file = "psycopg2-2.9.9-cp37-cp37m-win32.whl", hash = "sha256:5e0d98cade4f0e0304d7d6f25bbfbc5bd186e07b38eac65379309c4ca3193efa"}, - {file = "psycopg2-2.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:7e2dacf8b009a1c1e843b5213a87f7c544b2b042476ed7755be813eaf4e8347a"}, - {file = "psycopg2-2.9.9-cp38-cp38-win32.whl", hash = "sha256:ff432630e510709564c01dafdbe996cb552e0b9f3f065eb89bdce5bd31fabf4c"}, - {file = "psycopg2-2.9.9-cp38-cp38-win_amd64.whl", hash = "sha256:bac58c024c9922c23550af2a581998624d6e02350f4ae9c5f0bc642c633a2d5e"}, - {file = "psycopg2-2.9.9-cp39-cp39-win32.whl", hash = "sha256:c92811b2d4c9b6ea0285942b2e7cac98a59e166d59c588fe5cfe1eda58e72d59"}, - {file = "psycopg2-2.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:de80739447af31525feddeb8effd640782cf5998e1a4e9192ebdf829717e3913"}, - {file = "psycopg2-2.9.9.tar.gz", hash = "sha256:d1454bde93fb1e224166811694d600e746430c006fbb031ea06ecc2ea41bf156"}, + {file = "psycopg2-2.9.12-cp310-cp310-win_amd64.whl", hash = "sha256:d5fbe092315fb007c03544704e6d1e678a6c0378139d01cea433dc59edf041b4"}, + {file = "psycopg2-2.9.12-cp311-cp311-win_amd64.whl", hash = "sha256:2532c0cdc6ad18c9c35cd935cc3159712e14f05276a6d29a6435c52d24b840c1"}, + {file = "psycopg2-2.9.12-cp312-cp312-win_amd64.whl", hash = "sha256:83d48e66e18c301d832e93c984a7bcbc0f4ac3bb79e2137e3bc335978c756dc0"}, + {file = "psycopg2-2.9.12-cp313-cp313-win_amd64.whl", hash = "sha256:3d23e684927d37b95cee9a943f6927b04ae2fdcd056fd0e2a30929ee89fee5a9"}, + {file = "psycopg2-2.9.12-cp314-cp314-win_amd64.whl", hash = "sha256:a73d5513bfe929c56555006c7a9cc7ae6e4276aa99dd2b1e2544eb8bb54f8b23"}, + {file = "psycopg2-2.9.12-cp39-cp39-win_amd64.whl", hash = "sha256:09826a6b89714626a662275d03f21639f1c68d183e2dcc9ba134d463a3da753e"}, + {file = "psycopg2-2.9.12.tar.gz", hash = "sha256:1dedb1c7a1d8552c4a6044c6b1c41a52e6a8e2d144af83eccac758076b1b7c15"}, ] [[package]] name = "pyasn1" -version = "0.5.1" +version = "0.6.4" description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +python-versions = ">=3.8" files = [ - {file = "pyasn1-0.5.1-py2.py3-none-any.whl", hash = "sha256:4439847c58d40b1d0a573d07e3856e95333f1976294494c325775aeca506eb58"}, - {file = "pyasn1-0.5.1.tar.gz", hash = "sha256:6d391a96e59b23130a5cfa74d6fd7f388dbbe26cc8f1edf39fdddf08d9d6676c"}, + {file = "pyasn1-0.6.4-py3-none-any.whl", hash = "sha256:deda9277cfd454080ec40b207fb6df82206a3a2688735233cdcd8d3d565f088b"}, + {file = "pyasn1-0.6.4.tar.gz", hash = "sha256:9c447d8431c947fe4c8febc4ed9e760bc29011a5b01e5c74b67025bd9fb8ce81"}, ] [[package]] name = "pyasn1-modules" -version = "0.3.0" +version = "0.4.2" description = "A collection of ASN.1-based protocols modules" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +python-versions = ">=3.8" files = [ - {file = "pyasn1_modules-0.3.0-py2.py3-none-any.whl", hash = "sha256:d3ccd6ed470d9ffbc716be08bd90efbd44d0734bc9303818f7336070984a162d"}, - {file = "pyasn1_modules-0.3.0.tar.gz", hash = "sha256:5bd01446b736eb9d31512a30d46c1ac3395d676c6f3cafa4c03eb54b9925631c"}, + {file = "pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a"}, + {file = "pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6"}, ] [package.dependencies] -pyasn1 = ">=0.4.6,<0.6.0" +pyasn1 = ">=0.6.1,<0.7.0" [[package]] name = "pycocotools" -version = "2.0.7" +version = "2.0.11" description = "Official APIs for the MS-COCO dataset" optional = false -python-versions = ">=3.5" -files = [ - {file = "pycocotools-2.0.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a6683a002fcb4500edbcec94bdf48be69f578a9aa5c638db38614df1f45cc935"}, - {file = "pycocotools-2.0.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d517ec315e53ef8df9f6b0899ebc4c79bd61fd715383861949bb1c3fca2c6d5"}, - {file = "pycocotools-2.0.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eb5d46900375adaba88eedb5cbc29d8cbcf43e82505d67378df1c3b720a8c5f"}, - {file = "pycocotools-2.0.7-cp310-cp310-win_amd64.whl", hash = "sha256:363a6be808125306ace1a163c0b9ba479ee08eceec1fbd3889a88bd8245f73dc"}, - {file = "pycocotools-2.0.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:623b941bbafecbfee574aedbf3cb257f7a879f4fdb79394e6d3fb9c76e7ad6cf"}, - {file = "pycocotools-2.0.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ac4f30bac1503c780072053e6922971392fa3628b2e6967192bfca1f14736e2"}, - {file = "pycocotools-2.0.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:121017ca87e2eec4e9081636d1a79519b50f473959defc5671c2d1ce0eec482e"}, - {file = "pycocotools-2.0.7-cp311-cp311-win_amd64.whl", hash = "sha256:4a8ec6f439638120e11f49120e1ddb6c66e0b1f293d7884207d02703a73d25a1"}, - {file = "pycocotools-2.0.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1a675728e459d72be6e3bb3546672bb37c7daffdc2e5335aa7b834aece2b560"}, - {file = "pycocotools-2.0.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6541340f26bae32e044eedc5d8ccdac5bd0cb64eb2b0a342dac859b696edd0aa"}, - {file = "pycocotools-2.0.7-cp37-cp37m-win_amd64.whl", hash = "sha256:8def3c46349e919999d6d5a1d6b7e587e6891524cc28f8b4a11e463bf0914621"}, - {file = "pycocotools-2.0.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6469089b9b36a1f645dc9ee830f29d261e99b4b3be73cb260688fd8b6d02760c"}, - {file = "pycocotools-2.0.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1dbc429018149dc34e206ea32ee6297ff30b55a8615a3f7f4c6e3842f9df73db"}, - {file = "pycocotools-2.0.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66864bec8b30d47faa946bb55c8e8d6b7acb9fba0c17ff6aaa37abd78cda962a"}, - {file = "pycocotools-2.0.7-cp38-cp38-win_amd64.whl", hash = "sha256:625388f52e543f6f798f75f1ec125fe519580f22e72ccbd75eee0355ce336e18"}, - {file = "pycocotools-2.0.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:73dc251ae4a06b7c10747ca7e2d29faabb4f13e5fc43760945966845581e79ae"}, - {file = "pycocotools-2.0.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e6f7bfa1c5fb206a614bf2382c923d56092219a12dfd0fec3b5f83c13e29e00"}, - {file = "pycocotools-2.0.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b29086b6ce7b73e4ddaf3045006f5c059f344a2720605cd4474814017ff2af53"}, - {file = "pycocotools-2.0.7-cp39-cp39-win_amd64.whl", hash = "sha256:254506c0eecabb3abbde17640f82103c0c04d53148ae920657664cab9cd649fc"}, - {file = "pycocotools-2.0.7.tar.gz", hash = "sha256:da8b7815196eebf0adabf67fcc459126cbc6498bbc6ab1fd144c371465d86879"}, +python-versions = ">=3.9" +files = [ + {file = "pycocotools-2.0.11-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:484d33515353186aadba9e2a290d81b107275cdb9565084e31a5568a52a0b120"}, + {file = "pycocotools-2.0.11-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ca9f120f719ec405ad0c74ccfdb8402b0c37bd5f88ab5b6482a0de2efd5a36f4"}, + {file = "pycocotools-2.0.11-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e40a3a898c6e5340b8d70cf7984868b9bff8c3d80187de9a3b661d504d665978"}, + {file = "pycocotools-2.0.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7cd4cdfd2c676f30838aa0b1047441892fb4f97d70bf3df480bcc7a18a64d7d4"}, + {file = "pycocotools-2.0.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08c79789fd79e801ae4ecfcfeec32b31e36254e7a2b4019af28c104975d5e730"}, + {file = "pycocotools-2.0.11-cp310-cp310-win_amd64.whl", hash = "sha256:f78cbb1a32d061fcad4bdba083de70a39a21c1c3d9235a3f77d8f007541ec5ef"}, + {file = "pycocotools-2.0.11-cp310-cp310-win_arm64.whl", hash = "sha256:e21311ea71f85591680d8992858e2d44a2a156dc3b2bf1c5c901c4a19348177b"}, + {file = "pycocotools-2.0.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:81bdceebb4c64e9265213e2d733808a12f9c18dfb14457323cc6b9af07fa0e61"}, + {file = "pycocotools-2.0.11-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a1c05f91ccc658dfe01325267209c4b435da1722c93eeb5749fabc1d087b6882"}, + {file = "pycocotools-2.0.11-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18ba75ff58cedb33a85ce2c18f1452f1fe20c9dd59925eec5300b2bf6205dbe1"}, + {file = "pycocotools-2.0.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:693417797f0377fd094eb815c0a1e7d1c3c0251b71e3b3779fce3b3cf24793c5"}, + {file = "pycocotools-2.0.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b6a07071c441d0f5e480a8f287106191582e40289d4e242dfe684e0c8a751088"}, + {file = "pycocotools-2.0.11-cp311-cp311-win_amd64.whl", hash = "sha256:8e159232adae3aef6b4e2d37b008bff107b26e9ed3b48e70ea6482302834bd34"}, + {file = "pycocotools-2.0.11-cp311-cp311-win_arm64.whl", hash = "sha256:4fc9889e819452b9c142036e1eabac8a13a8bd552d8beba299a57e0da6bfa1ec"}, + {file = "pycocotools-2.0.11-cp312-abi3-macosx_10_13_universal2.whl", hash = "sha256:a2e9634bc7cadfb01c88e0b98589aaf0bd12983c7927bde93f19c0103e5441f4"}, + {file = "pycocotools-2.0.11-cp312-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7fd4121766cc057133534679c0ec3f9023dbd96e9b31cf95c86a069ebdac2b65"}, + {file = "pycocotools-2.0.11-cp312-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a82d1c9ed83f75da0b3f244f2a3cf559351a283307bd9b79a4ee2b93ab3231dd"}, + {file = "pycocotools-2.0.11-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:89e853425018e2c2920ee0f2112cf7c140a1dcf5f4f49abd9c2da112c3e0f4b3"}, + {file = "pycocotools-2.0.11-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:87af87b8d06d5b852a885a319d9362dca3bed9f8bbcc3feb6513acb1f88ea242"}, + {file = "pycocotools-2.0.11-cp312-abi3-win_amd64.whl", hash = "sha256:ffe806ce535f5996445188f9a35643791dc54beabc61bd81e2b03367356d604f"}, + {file = "pycocotools-2.0.11-cp312-abi3-win_arm64.whl", hash = "sha256:c230f5e7b14bd19085217b4f40bba81bf14a182b150b8e9fab1c15d504ade343"}, + {file = "pycocotools-2.0.11-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:fd72b9734e6084b217c1fc3945bfd4ec05bdc75a44e4f0c461a91442bb804973"}, + {file = "pycocotools-2.0.11-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f7eb43b79448476b094240450420b7425d06e297880144b8ea6f01e9b4340e43"}, + {file = "pycocotools-2.0.11-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c3546b93b39943347c4f5b0694b5824105cbe2174098a416bcad4acd9c21e957"}, + {file = "pycocotools-2.0.11-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:efd1694b2075f2f10c5828f10f6e6c4e44368841fd07dae385c3aa015c8e25f9"}, + {file = "pycocotools-2.0.11-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:368244f30eb8d6cae7003aa2c0831fbdf0153664a32859ec7fbceea52bfb6878"}, + {file = "pycocotools-2.0.11-cp313-cp313t-win_amd64.whl", hash = "sha256:ac8aa17263e6489aa521f9fa91e959dfe0ea3a5519fde2cbf547312cdce7559e"}, + {file = "pycocotools-2.0.11-cp313-cp313t-win_arm64.whl", hash = "sha256:04480330df5013f6edd94891a0ee8294274185f1b5093d1b0f23d51778f0c0e9"}, + {file = "pycocotools-2.0.11-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:a6b13baf6bfcf881b6d6ac6e23c776f87a68304cd86e53d1d6b9afa31e363c4e"}, + {file = "pycocotools-2.0.11-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78bae4a9de9d34c4759754a848dfb3306f9ef1c2fcb12164ffbd3d013d008321"}, + {file = "pycocotools-2.0.11-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:83d896f4310379849dfcfa7893afb0ff21f4f3cdb04ab3f61b05dd98953dd0ad"}, + {file = "pycocotools-2.0.11-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:eebd723503a2eb2c8b285f56ea3be1d9f3875cd7c40d945358a428db94f14015"}, + {file = "pycocotools-2.0.11-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:bd7a1e19ef56a828a94bace673372071d334a9232cd32ae3cd48845a04d45c4f"}, + {file = "pycocotools-2.0.11-cp314-cp314t-win_amd64.whl", hash = "sha256:63026e11a56211058d0e84e8263f74cbccd5e786fac18d83fd221ecb9819fcc7"}, + {file = "pycocotools-2.0.11-cp314-cp314t-win_arm64.whl", hash = "sha256:8cedb8ccb97ffe9ed2c8c259234fa69f4f1e8665afe3a02caf93f6ef2952c07f"}, + {file = "pycocotools-2.0.11-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9dc8b388984c72aa84b1a68933f196ce71ab114c59232d0eab20c97cc1300875"}, + {file = "pycocotools-2.0.11-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2b018497ec198ffc737dd7e6306a2e69999779ca619a9e12950e4506e410c3e"}, + {file = "pycocotools-2.0.11-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e72527fdc00985d29dbe31d17b19cd2d16fbad7b01e974c567b593d5844de710"}, + {file = "pycocotools-2.0.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d6b88557166794a24acd03f50296f2b95adf3e4206b4b8995e6bdca925c9cb72"}, + {file = "pycocotools-2.0.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6a2f4f036f5bfdaf8c9625279051e921721fc9d27f92c97a3f3355a07ba38513"}, + {file = "pycocotools-2.0.11-cp39-cp39-win_amd64.whl", hash = "sha256:eba35d6e06caaea28ce65a4b92e4343ecbb9abf4915f7ef7fca989b80839111c"}, + {file = "pycocotools-2.0.11-cp39-cp39-win_arm64.whl", hash = "sha256:1192de413a23b4b94199197e8f8dbe1277cc24e6e9847bee6a71be3d8e543963"}, + {file = "pycocotools-2.0.11.tar.gz", hash = "sha256:34254d76da85576fcaf5c1f3aa9aae16b8cb15418334ba4283b800796bd1993d"}, ] [package.dependencies] -matplotlib = ">=2.1.0" numpy = "*" +[package.extras] +all = ["matplotlib (>=2.1.0)"] + [[package]] name = "pycparser" -version = "2.21" +version = "3.0" description = "C parser in Python" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.10" files = [ - {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, - {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, + {file = "pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992"}, + {file = "pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29"}, ] [[package]] name = "pycryptodome" -version = "3.21.0" +version = "3.23.0" description = "Cryptographic library for Python" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" -files = [ - {file = "pycryptodome-3.21.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:dad9bf36eda068e89059d1f07408e397856be9511d7113ea4b586642a429a4fd"}, - {file = "pycryptodome-3.21.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:a1752eca64c60852f38bb29e2c86fca30d7672c024128ef5d70cc15868fa10f4"}, - {file = "pycryptodome-3.21.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:3ba4cc304eac4d4d458f508d4955a88ba25026890e8abff9b60404f76a62c55e"}, - {file = "pycryptodome-3.21.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7cb087b8612c8a1a14cf37dd754685be9a8d9869bed2ffaaceb04850a8aeef7e"}, - {file = "pycryptodome-3.21.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:26412b21df30b2861424a6c6d5b1d8ca8107612a4cfa4d0183e71c5d200fb34a"}, - {file = "pycryptodome-3.21.0-cp27-cp27m-win32.whl", hash = "sha256:cc2269ab4bce40b027b49663d61d816903a4bd90ad88cb99ed561aadb3888dd3"}, - {file = "pycryptodome-3.21.0-cp27-cp27m-win_amd64.whl", hash = "sha256:0fa0a05a6a697ccbf2a12cec3d6d2650b50881899b845fac6e87416f8cb7e87d"}, - {file = "pycryptodome-3.21.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6cce52e196a5f1d6797ff7946cdff2038d3b5f0aba4a43cb6bf46b575fd1b5bb"}, - {file = "pycryptodome-3.21.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:a915597ffccabe902e7090e199a7bf7a381c5506a747d5e9d27ba55197a2c568"}, - {file = "pycryptodome-3.21.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4e74c522d630766b03a836c15bff77cb657c5fdf098abf8b1ada2aebc7d0819"}, - {file = "pycryptodome-3.21.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:a3804675283f4764a02db05f5191eb8fec2bb6ca34d466167fc78a5f05bbe6b3"}, - {file = "pycryptodome-3.21.0-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:2480ec2c72438430da9f601ebc12c518c093c13111a5c1644c82cdfc2e50b1e4"}, - {file = "pycryptodome-3.21.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:de18954104667f565e2fbb4783b56667f30fb49c4d79b346f52a29cb198d5b6b"}, - {file = "pycryptodome-3.21.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2de4b7263a33947ff440412339cb72b28a5a4c769b5c1ca19e33dd6cd1dcec6e"}, - {file = "pycryptodome-3.21.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0714206d467fc911042d01ea3a1847c847bc10884cf674c82e12915cfe1649f8"}, - {file = "pycryptodome-3.21.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d85c1b613121ed3dbaa5a97369b3b757909531a959d229406a75b912dd51dd1"}, - {file = "pycryptodome-3.21.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:8898a66425a57bcf15e25fc19c12490b87bd939800f39a03ea2de2aea5e3611a"}, - {file = "pycryptodome-3.21.0-cp36-abi3-musllinux_1_2_i686.whl", hash = "sha256:932c905b71a56474bff8a9c014030bc3c882cee696b448af920399f730a650c2"}, - {file = "pycryptodome-3.21.0-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:18caa8cfbc676eaaf28613637a89980ad2fd96e00c564135bf90bc3f0b34dd93"}, - {file = "pycryptodome-3.21.0-cp36-abi3-win32.whl", hash = "sha256:280b67d20e33bb63171d55b1067f61fbd932e0b1ad976b3a184303a3dad22764"}, - {file = "pycryptodome-3.21.0-cp36-abi3-win_amd64.whl", hash = "sha256:b7aa25fc0baa5b1d95b7633af4f5f1838467f1815442b22487426f94e0d66c53"}, - {file = "pycryptodome-3.21.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:2cb635b67011bc147c257e61ce864879ffe6d03342dc74b6045059dfbdedafca"}, - {file = "pycryptodome-3.21.0-pp27-pypy_73-win32.whl", hash = "sha256:4c26a2f0dc15f81ea3afa3b0c87b87e501f235d332b7f27e2225ecb80c0b1cdd"}, - {file = "pycryptodome-3.21.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d5ebe0763c982f069d3877832254f64974139f4f9655058452603ff559c482e8"}, - {file = "pycryptodome-3.21.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ee86cbde706be13f2dec5a42b52b1c1d1cbb90c8e405c68d0755134735c8dc6"}, - {file = "pycryptodome-3.21.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fd54003ec3ce4e0f16c484a10bc5d8b9bd77fa662a12b85779a2d2d85d67ee0"}, - {file = "pycryptodome-3.21.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5dfafca172933506773482b0e18f0cd766fd3920bd03ec85a283df90d8a17bc6"}, - {file = "pycryptodome-3.21.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:590ef0898a4b0a15485b05210b4a1c9de8806d3ad3d47f74ab1dc07c67a6827f"}, - {file = "pycryptodome-3.21.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f35e442630bc4bc2e1878482d6f59ea22e280d7121d7adeaedba58c23ab6386b"}, - {file = "pycryptodome-3.21.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff99f952db3db2fbe98a0b355175f93ec334ba3d01bbde25ad3a5a33abc02b58"}, - {file = "pycryptodome-3.21.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8acd7d34af70ee63f9a849f957558e49a98f8f1634f86a59d2be62bb8e93f71c"}, - {file = "pycryptodome-3.21.0.tar.gz", hash = "sha256:f7787e0d469bdae763b876174cf2e6c0f7be79808af26b1da96f1a64bcf47297"}, +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "pycryptodome-3.23.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a176b79c49af27d7f6c12e4b178b0824626f40a7b9fed08f712291b6d54bf566"}, + {file = "pycryptodome-3.23.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:573a0b3017e06f2cffd27d92ef22e46aa3be87a2d317a5abf7cc0e84e321bd75"}, + {file = "pycryptodome-3.23.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:63dad881b99ca653302b2c7191998dd677226222a3f2ea79999aa51ce695f720"}, + {file = "pycryptodome-3.23.0-cp27-cp27m-win32.whl", hash = "sha256:b34e8e11d97889df57166eda1e1ddd7676da5fcd4d71a0062a760e75060514b4"}, + {file = "pycryptodome-3.23.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:7ac1080a8da569bde76c0a104589c4f414b8ba296c0b3738cf39a466a9fb1818"}, + {file = "pycryptodome-3.23.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6fe8258e2039eceb74dfec66b3672552b6b7d2c235b2dfecc05d16b8921649a8"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:0011f7f00cdb74879142011f95133274741778abba114ceca229adbf8e62c3e4"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:90460fc9e088ce095f9ee8356722d4f10f86e5be06e2354230a9880b9c549aae"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4764e64b269fc83b00f682c47443c2e6e85b18273712b98aa43bcb77f8570477"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d97618c9c6684a97ef7637ba43bdf6663a2e2e77efe0f863cce97a76af396446"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a53a4fe5cb075075d515797d6ce2f56772ea7e6a1e5e4b96cf78a14bac3d265"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:763d1d74f56f031788e5d307029caef067febf890cd1f8bf61183ae142f1a77b"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:954af0e2bd7cea83ce72243b14e4fb518b18f0c1649b576d114973e2073b273d"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:257bb3572c63ad8ba40b89f6fc9d63a2a628e9f9708d31ee26560925ebe0210a"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6501790c5b62a29fcb227bd6b62012181d886a767ce9ed03b303d1f22eb5c625"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9a77627a330ab23ca43b48b130e202582e91cc69619947840ea4d2d1be21eb39"}, + {file = "pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27"}, + {file = "pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843"}, + {file = "pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490"}, + {file = "pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575"}, + {file = "pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b"}, + {file = "pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a"}, + {file = "pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f"}, + {file = "pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa"}, + {file = "pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886"}, + {file = "pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2"}, + {file = "pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c"}, + {file = "pycryptodome-3.23.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:350ebc1eba1da729b35ab7627a833a1a355ee4e852d8ba0447fafe7b14504d56"}, + {file = "pycryptodome-3.23.0-pp27-pypy_73-win32.whl", hash = "sha256:93837e379a3e5fd2bb00302a47aee9fdf7940d83595be3915752c74033d17ca7"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddb95b49df036ddd264a0ad246d1be5b672000f12d6961ea2c267083a5e19379"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e95564beb8782abfd9e431c974e14563a794a4944c29d6d3b7b5ea042110b4"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e15c081e912c4b0d75632acd8382dfce45b258667aa3c67caf7a4d4c13f630"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7fc76bf273353dc7e5207d172b83f569540fc9a28d63171061c42e361d22353"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:865d83c906b0fc6a59b510deceee656b6bc1c4fa0d82176e2b77e97a420a996a"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89d4d56153efc4d81defe8b65fd0821ef8b2d5ddf8ed19df31ba2f00872b8002"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3f2d0aaf8080bda0587d58fc9fe4766e012441e2eed4269a77de6aea981c8be"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64093fc334c1eccfd3933c134c4457c34eaca235eeae49d69449dc4728079339"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ce64e84a962b63a47a592690bdc16a7eaf709d2c2697ababf24a0def566899a6"}, + {file = "pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef"}, ] [[package]] name = "pydantic" -version = "2.6.4" +version = "2.13.4" description = "Data validation using Python type hints" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pydantic-2.6.4-py3-none-any.whl", hash = "sha256:cc46fce86607580867bdc3361ad462bab9c222ef042d3da86f2fb333e1d916c5"}, - {file = "pydantic-2.6.4.tar.gz", hash = "sha256:b1704e0847db01817624a6b86766967f552dd9dbf3afba4004409f908dcc84e6"}, + {file = "pydantic-2.13.4-py3-none-any.whl", hash = "sha256:45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba"}, + {file = "pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6"}, ] [package.dependencies] -annotated-types = ">=0.4.0" -pydantic-core = "2.16.3" -typing-extensions = ">=4.6.1" +annotated-types = ">=0.6.0" +email-validator = {version = ">=2.0.0", optional = true, markers = "extra == \"email\""} +pydantic-core = "2.46.4" +typing-extensions = ">=4.14.1" +typing-inspection = ">=0.4.2" [package.extras] email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata"] [[package]] name = "pydantic-core" -version = "2.16.3" -description = "" +version = "2.46.4" +description = "Core functionality for Pydantic validation and serialization" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" +files = [ + {file = "pydantic_core-2.46.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a396dcc17e5a0b164dbe026896245a4fa9ff402edca1dff0be3d53a517f74de4"}, + {file = "pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:da4b951fe36dc7c3a1ccb4e3cd1747c3542b8c9ceede8fc86cae054e764485f5"}, + {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb63e0198ca18aad131c089b9204c23079c3afa95487e561f4c522d519e55aba"}, + {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f47286a97f0bc9b8859519809077b91b2cefe4ae47fcbf5e466a009c1c5d742b"}, + {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:905a0ed8ea6f2d61c1738835f99b699348d7857379083e5fc497fa0c967a407c"}, + {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea793e075b70290d89d8142074262885d3f7da19634845135751bd6344f73b50"}, + {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:395aebd9183f9d112f569aeb5b2214d1a10a33bec8456447f7fbdfa51d38d4cd"}, + {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:b078afbc25f3a1436c7a1d2cd3e322497ee99615ba97c563566fdf46aff1ee01"}, + {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f747929cf940cddb5b3668a390056ddd5ba2e5010615ea2dcf4f9c4f3ab8791d"}, + {file = "pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:daa27d92c36f24388fe3ad306b174781c747627f134452e4f128ea00ce1fe8c4"}, + {file = "pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:19e51f073cd3df251856a8a4189fbdf1de4012c3ebacfb1884f94f1eb406079f"}, + {file = "pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1747f85cee84c26985853c6f3d9bd3e75da5212912443fa111c113b9c246f39"}, + {file = "pydantic_core-2.46.4-cp310-cp310-win32.whl", hash = "sha256:2f84c03c8607173d16b5a854ec68a2f9079ae03237a54fb506d13af47e1d018d"}, + {file = "pydantic_core-2.46.4-cp310-cp310-win_amd64.whl", hash = "sha256:8358a950c8909158e3df31538a7e4edc2d7265a7c54b47f0864d9e5bae9dcebf"}, + {file = "pydantic_core-2.46.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0e96592440881c74a213e5ad528e2b24d3d4f940de2766bed9010ab1d9e51594"}, + {file = "pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0d65b8c354be7fb5f720c3caa8bc940bc2d20ce749c8e06135f07f8ed95dd7c"}, + {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bfb192b3f4b9e8a89b6277b6ce787564f62cfd272055f6e685726b111dc7826"}, + {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9037063db01f09b09e237c282b6792bd4da634b5402c4e7f0c61effed7701a04"}, + {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc010ab034c8c7452522748bf937df58020d256ccae0874463d1f4d01758af8e"}, + {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c5dac79fa1614d1e06ca695109c6105923bd9c7d1d6c918d4e637b7e6b32fd3"}, + {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9fa868638bf362d3d138ea55829cefb3d5f4b0d7f142234382a15e2485dbec4"}, + {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:17299feefe090f2caa5b8e37222bb5f663e4935a8bfa6931d4102e5df1a9f398"}, + {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4c63ebc82684aa89d9a3bcbd13d515b3be44250dc68dd3bd81526c1cb31286c3"}, + {file = "pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:aaa2a54443eff1950ba5ddc6b6ccda0d9c84a364276a62f969bdf2a390650848"}, + {file = "pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:18e5ceec2ab67e6d5f1a9085e5a24c9c4e2ac4545730bfe668680bca05e555f3"}, + {file = "pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a0f62d0a58f4e7da165457e995725421e0064f2255d8eccebc49f41bbc23b109"}, + {file = "pydantic_core-2.46.4-cp311-cp311-win32.whl", hash = "sha256:041bde0a48fd37cf71cab1c9d56d3e8625a3793fef1f7dd232b3ff37e978ecda"}, + {file = "pydantic_core-2.46.4-cp311-cp311-win_amd64.whl", hash = "sha256:6f2eeda33a839975441c86a4119e1383c50b47faf0cbb5176985565c6bb02c33"}, + {file = "pydantic_core-2.46.4-cp311-cp311-win_arm64.whl", hash = "sha256:14f4c5d6db102bd796a627bbb3a17b4cf4574b9ae861d8b7c9a9661c6dd3362d"}, + {file = "pydantic_core-2.46.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3245406455a5d98187ec35530fd772b1d799b26667980872c8d4614991e2c4a2"}, + {file = "pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:962ccbab7b642487b1d8b7df90ef677e03134cf1fd8880bf698649b22a69371f"}, + {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8233f2947cf85404441fd7e0085f53b10c93e0ee78611099b5c7237e36aacbf7"}, + {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a233125ac121aa3ffba9a2b59edfc4a985a76092dc8279586ab4b71390875e7"}, + {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b712b53160b79a5850310b912a5ef8e57e56947c8ad690c227f5c9d7e561712"}, + {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9401557acd873c3a7f3eb9383edef8ac4968f9510e340f4808d427e75667e7b4"}, + {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:926c9541b14b12b1681dca8a0b75feb510b06c6341b70a8e500c2fdcff837cce"}, + {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:56cb4851bcaf3d117eddcef4fe66afd750a50274b0da8e22be256d10e5611987"}, + {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c68fcd102d71ea85c5b2dfac3f4f8476eff42a9e078fd5faefff6d145063536b"}, + {file = "pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b2f69dec1725e79a012d920df1707de5caf7ed5e08f3be4435e25803efc47458"}, + {file = "pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:8d0820e8192167f80d88d64038e609c31452eeca865b4e1d9950a27a4609b00b"}, + {file = "pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fbdb89b3e1c94a30cc5edfce477c6e6a5dc4d8f84665b455c27582f211a1c72c"}, + {file = "pydantic_core-2.46.4-cp312-cp312-win32.whl", hash = "sha256:9aa768456404a8bf48a4406685ac2bec8e72b62c69313734fa3b73cf33b3a894"}, + {file = "pydantic_core-2.46.4-cp312-cp312-win_amd64.whl", hash = "sha256:e9c26f834c65f5752f3f06cb08cb86a913ceb7274d0db6e267808a708b46bc89"}, + {file = "pydantic_core-2.46.4-cp312-cp312-win_arm64.whl", hash = "sha256:4fc73cb559bdb54b1134a706a2802a4cddd27a0633f5abb7e53056268751ac6a"}, + {file = "pydantic_core-2.46.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5d5902252db0d3cedf8d4a1bc68f70eeb430f7e4c7104c8c476753519b423008"}, + {file = "pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c94f0688e7b8d0a67abf40e57a7eaaecd17cc9586706a31b76c031f63df052b4"}, + {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f027324c56cd5406ca49c124b0db10e56c69064fec039acc571c29020cc87c76"}, + {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e739fee756ba1010f8bcccb534252e85a35fe45ae92c295a06059ce58b74ccd3"}, + {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d56801be94b86a9da183e5f3766e6310752b99ff647e38b09a9500d88e46e76"}, + {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2412e734dcb48da14d4e4006b82b46b74f2518b8a26ee7e58c6844a6cd6d03c4"}, + {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9551187363ffc0de2a00b2e47c25aeaeb1020b69b668762966df15fc5659dd5a"}, + {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0186750b482eefa11d7f435892b09c5c606193ef3375bcf94aa00ae6bfb66262"}, + {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5855698a4856556d86e8e6cd8434bc3ac0314ee8e12089ae0e143f64c6256e4e"}, + {file = "pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cbaf13819775b7f769bf4a1f066cb6df7a28d4480081a589828ef190226881cd"}, + {file = "pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:633147d34cf4550417f12e2b1a0383973bdf5cdfde212cb09e9a581cf10820be"}, + {file = "pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:82cf5301172168103724d49a1444d3378cb20cdee30b116a1bd6031236298a5d"}, + {file = "pydantic_core-2.46.4-cp313-cp313-win32.whl", hash = "sha256:9fa8ae11da9e2b3126c6426f147e0fba88d96d65921799bb30c6abd1cb2c97fb"}, + {file = "pydantic_core-2.46.4-cp313-cp313-win_amd64.whl", hash = "sha256:6b3ace8194b0e5204818c92802dcdca7fc6d88aabbb799d7c795540d9cd6d292"}, + {file = "pydantic_core-2.46.4-cp313-cp313-win_arm64.whl", hash = "sha256:184c081504d17f1c1066e430e117142b2c77d9448a97f7b65c6ac9fd9aee238d"}, + {file = "pydantic_core-2.46.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:428e04521a40150c85216fc8b85e8d39fece235a9cf5e383761238c7fa9b96fb"}, + {file = "pydantic_core-2.46.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23ace664830ee0bfe014a0c7bc248b1f7f25ed7ad103852c317624a1083af462"}, + {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce5c1d2a8b27468f433ca974829c44060b8097eedc39933e3c206a90ee49c4a9"}, + {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7283d57845ecf5a163403eb0702dfc220cc4fbdd18919cb5ccea4f95ee1cdab4"}, + {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8daafc69c93ee8a0204506a3b6b30f586ef54028f52aeeeb5c4cfc5184fd5914"}, + {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd2213145bcc2ba85884d0ac63d222fece9209678f77b9b4d76f054c561adb28"}, + {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a5f930472650a82629163023e630d160863fce524c616f4e5186e5de9d9a49b"}, + {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:c1b3f518abeca3aa13c712fd202306e145abf59a18b094a6bafb2d2bbf59192c"}, + {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a7dd0b3ee80d90150e3495a3a13ac34dbcbfd4f012996a6a1d8900e91b5c0fb"}, + {file = "pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:3fb702cd90b0446a3a1c5e470bfa0dd23c0233b676a9099ddcc964fa6ca13898"}, + {file = "pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b8458003118a712e66286df6a707db01c52c0f52f7db8e4a38f0da1d3b94fc4e"}, + {file = "pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:372429a130e469c9cd698925ce5fc50940b7a1336b0d82038e63d5bbc4edc519"}, + {file = "pydantic_core-2.46.4-cp314-cp314-win32.whl", hash = "sha256:85bb3611ff1802f3ee7fdd7dbff26b56f343fb432d57a4728fdd49b6ef35e2f4"}, + {file = "pydantic_core-2.46.4-cp314-cp314-win_amd64.whl", hash = "sha256:811ff8e9c313ab425368bcbb36e5c4ebd7108c2bbf4e4089cfbb0b01eff63fac"}, + {file = "pydantic_core-2.46.4-cp314-cp314-win_arm64.whl", hash = "sha256:bfec22eab3c8cc2ceec0248aec886624116dc079afa027ecc8ad4a7e62010f8a"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:af8244b2bef6aaad6d92cda81372de7f8c8d36c9f0c3ea36e827c60e7d9467a0"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a4330cdbc57162e4b3aa303f588ba752257694c9c9be3e7ebb11b4aca659b5d"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c61fc04a3d840155ff08e475a04809278972fe6aef51e2720554e96367e34b"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c50f2528cf200c5eed56faf3f4e22fcd5f38c157a8b78576e6ba3168ec35f000"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0cbe8b01f948de4286c74cdd6c667aceb38f5c1e26f0693b3983d9d74887c65e"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:617d7e2ca7dcb8c5cf6bcb8c59b8832c94b36196bbf1cbd1bfb56ed341905edd"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7027560ee92211647d0d34e3f7cd6f50da56399d26a9c8ad0da286d3869a53f3"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:f99626688942fb746e545232e7726926f3be91b5975f8b55327665fafda991c7"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc3e9034a63de20e15e8ade85358bc6efc614008cab72898b4b4952bea0509ff"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:97e7cf2be5c77b7d1a9713a05605d49460d02c6078d38d8bef3cbe323c548424"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:3bf92c5d0e00fefaab325a4d27828fe6b6e2a21848686b5b60d2d9eeb09d76c6"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:3ecbc122d18468d06ca279dc26a8c2e2d5acb10943bb35e36ae92096dc3b5565"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-win32.whl", hash = "sha256:e846ae7835bf0703ae43f534ab79a867146dadd59dc9ca5c8b53d5c8f7c9ef02"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-win_amd64.whl", hash = "sha256:2108ba5c1c1eca18030634489dc544844144ee36357f2f9f780b93e7ddbb44b5"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-win_arm64.whl", hash = "sha256:4fcbe087dbc2068af7eda3aa87634eba216dbda64d1ae73c8684b621d33f6596"}, + {file = "pydantic_core-2.46.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:fd8b3d9fd264be37976686c7f65cd52a83f5e84f4bfd2adf9c1d469676bbb6ae"}, + {file = "pydantic_core-2.46.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9f444c499b3eefd3a92e348059471ea0c3a6e303d9c1cec09fa748fd9f895201"}, + {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3447661d99f75a3683a4cf5c87da72f2161964611864dbbeac7fbb118bb4bfc0"}, + {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b9bab013d1c7a79d3501ff86d0bc9c31bf587db4551677b96bec07df78c6b15"}, + {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d995260fdf4e1db774581b4900e0f832abe3c7c84996726bbc161b19c8f29e76"}, + {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f13a646d65d09fbf1bc6b3a9635d30095c8e7e5cc419ff35ecc563c5fd04cd49"}, + {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432c179df7874eeb73307aad2df0755e1ae0efa61ff0ea89b93e194411ae3928"}, + {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_31_riscv64.whl", hash = "sha256:e68b7a074f65a2fd746c52a7ce6142ab7006074ac269ace0c25cd8ba171f8066"}, + {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4a05d69cba51d852c5c3e92758653245a50c0b646ced0cf05bd793ed592839d6"}, + {file = "pydantic_core-2.46.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:228ee9bae8bef5b1e97ec58302f80357c37199e0d0a99174e138d28e6957b9d9"}, + {file = "pydantic_core-2.46.4-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:10e17cbb10a330363733efc4d7c4d0dd827ac0909b8f6a6542298fed1ea62f29"}, + {file = "pydantic_core-2.46.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:91a06d2e259ecfbd8c901d70c3c507900458498142b3026a296b7de4d1322cc9"}, + {file = "pydantic_core-2.46.4-cp39-cp39-win32.whl", hash = "sha256:d80ee3d731373b24cebbc10d689ca4ee1875caf0d5703a245db18efd4dd37fc1"}, + {file = "pydantic_core-2.46.4-cp39-cp39-win_amd64.whl", hash = "sha256:3be77f45df024d789a672ae34f8b06fb346c4f9f46ea714956660ea4862e89ac"}, + {file = "pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:14d4edf427bdcf950a8a02d7cb44a08614388dd6e1bdcbf4f67504fa7887da9c"}, + {file = "pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:0ce40cd7b21210e99342afafbd4d0f76d784eb5b1d60f3bdc566be4983c6c73b"}, + {file = "pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90884113d8b48f760e9587002789ddd741e76ab9f89518cd1e43b1f1a52ec44b"}, + {file = "pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66ce7632c22d837c95301830e111ad0128a32b8207533b60896a96c4915192ea"}, + {file = "pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:1d8ba486450b14f3b1d63bc521d410ec7565e52f887b9fb671791886436a42f7"}, + {file = "pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:3009f12e4e90b7f88b4f9adb1b0c4a3d58fe7820f3238c190047209d148026df"}, + {file = "pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad785e92e6dc634c21555edc8bd6b64957ab844541bcb96a1366c202951ae526"}, + {file = "pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00c603d540afdd6b80eb39f078f33ebd46211f02f33e34a32d9f053bba711de0"}, + {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0c563b08bca408dc7f65f700633d8442fffb2421fc47b8101377e9fd65051ff0"}, + {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:db06ffe51636ffe9ca531fe9023dd64bdd794be8754cb5df57c5498ae5b518a7"}, + {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:133878133d271ade3d41d1bfb2a45ec38dbdbda40bc065921c6b04e4630127e2"}, + {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9bc519fbf2b7578398853d815009ae5e4d4603d12f4e3f91da8c06852d3da3e9"}, + {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c7a7bd4e39e8e4c12c39cd480356842b6a8a06e41b23a55a5e3e191718838ddf"}, + {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:d396ec2b979760aaf3218e76c24e65bd0aca24983298653b3a9d7a45f9e47b30"}, + {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:86e1a4418c6cd97d60c95c71164158eaf7324fae7b0923264016baa993eba6fc"}, + {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:d51026d73fcfd93610abc7b27789c26b313920fcfb20e27462d74a7f8b06e983"}, + {file = "pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1"}, +] + +[package.dependencies] +typing-extensions = ">=4.14.1" + +[[package]] +name = "pydantic-extra-types" +version = "2.11.1" +description = "Extra Pydantic types." +optional = false +python-versions = ">=3.9" files = [ - {file = "pydantic_core-2.16.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4"}, - {file = "pydantic_core-2.16.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99"}, - {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979"}, - {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db"}, - {file = "pydantic_core-2.16.3-cp310-none-win32.whl", hash = "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132"}, - {file = "pydantic_core-2.16.3-cp310-none-win_amd64.whl", hash = "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb"}, - {file = "pydantic_core-2.16.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4"}, - {file = "pydantic_core-2.16.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f"}, - {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e"}, - {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba"}, - {file = "pydantic_core-2.16.3-cp311-none-win32.whl", hash = "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721"}, - {file = "pydantic_core-2.16.3-cp311-none-win_amd64.whl", hash = "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df"}, - {file = "pydantic_core-2.16.3-cp311-none-win_arm64.whl", hash = "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9"}, - {file = "pydantic_core-2.16.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff"}, - {file = "pydantic_core-2.16.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e"}, - {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca"}, - {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf"}, - {file = "pydantic_core-2.16.3-cp312-none-win32.whl", hash = "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe"}, - {file = "pydantic_core-2.16.3-cp312-none-win_amd64.whl", hash = "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed"}, - {file = "pydantic_core-2.16.3-cp312-none-win_arm64.whl", hash = "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6"}, - {file = "pydantic_core-2.16.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01"}, - {file = "pydantic_core-2.16.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c"}, - {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8"}, - {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5"}, - {file = "pydantic_core-2.16.3-cp38-none-win32.whl", hash = "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a"}, - {file = "pydantic_core-2.16.3-cp38-none-win_amd64.whl", hash = "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed"}, - {file = "pydantic_core-2.16.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820"}, - {file = "pydantic_core-2.16.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8"}, - {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b"}, - {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972"}, - {file = "pydantic_core-2.16.3-cp39-none-win32.whl", hash = "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2"}, - {file = "pydantic_core-2.16.3-cp39-none-win_amd64.whl", hash = "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da"}, - {file = "pydantic_core-2.16.3.tar.gz", hash = "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad"}, + {file = "pydantic_extra_types-2.11.1-py3-none-any.whl", hash = "sha256:1722ea2bddae5628ace25f2aa685b69978ef533123e5638cfbddb999e0100ec1"}, + {file = "pydantic_extra_types-2.11.1.tar.gz", hash = "sha256:46792d2307383859e923d8fcefa82108b1a141f8a9c0198982b3832ab5ef1049"}, ] [package.dependencies] -typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" +pydantic = ">=2.5.2" +typing-extensions = "*" + +[package.extras] +all = ["cron-converter (>=1.2.2)", "pendulum (>=3.0.0,<4.0.0)", "phonenumbers (>=8,<10)", "pycountry (>=23)", "pymongo (>=4.0.0,<5.0.0)", "python-ulid (>=1,<2)", "python-ulid (>=1,<4)", "pytz (>=2024.1)", "semver (>=3.0.2)", "semver (>=3.0.2,<3.1.0)", "tzdata (>=2024.1)", "uuid-utils (>=0.6.0)"] +cron = ["cron-converter (>=1.2.2)"] +pendulum = ["pendulum (>=3.0.0,<4.0.0)"] +phonenumbers = ["phonenumbers (>=8,<10)"] +pycountry = ["pycountry (>=23)"] +python-ulid = ["python-ulid (>=1,<2)", "python-ulid (>=1,<4)"] +semver = ["semver (>=3.0.2)"] +uuid-utils = ["uuid-utils (>=0.6.0)"] + +[[package]] +name = "pydantic-settings" +version = "2.14.2" +description = "Settings management using Pydantic" +optional = false +python-versions = ">=3.10" +files = [ + {file = "pydantic_settings-2.14.2-py3-none-any.whl", hash = "sha256:a20c97b37910b6550d5ea50fbcc2d4187defe58cd57070b73863d069419c9440"}, + {file = "pydantic_settings-2.14.2.tar.gz", hash = "sha256:c19dd64b19097f1de80184f0cc7b0272a13ae6e170cbf240a3e27e381ed14a5f"}, +] + +[package.dependencies] +pydantic = ">=2.7.0" +python-dotenv = ">=0.21.0" +typing-inspection = ">=0.4.0" + +[package.extras] +aws-secrets-manager = ["boto3 (>=1.35.0)", "types-boto3[secretsmanager]"] +azure-key-vault = ["azure-identity (>=1.16.0)", "azure-keyvault-secrets (>=4.8.0)"] +gcp-secret-manager = ["google-cloud-secret-manager (>=2.23.1)"] +toml = ["tomli (>=2.0.1)"] +yaml = ["pyyaml (>=6.0.1)"] [[package]] name = "pygments" -version = "2.18.0" +version = "2.20.0" description = "Pygments is a syntax highlighting package written in Python." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, - {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, + {file = "pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176"}, + {file = "pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f"}, ] [package.extras] @@ -3539,106 +4350,111 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyinstrument" -version = "4.6.2" +version = "5.1.2" description = "Call stack profiler for Python. Shows you why your code is slow!" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pyinstrument-4.6.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7a1b1cd768ea7ea9ab6f5490f7e74431321bcc463e9441dbc2f769617252d9e2"}, - {file = "pyinstrument-4.6.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8a386b9d09d167451fb2111eaf86aabf6e094fed42c15f62ec51d6980bce7d96"}, - {file = "pyinstrument-4.6.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23c3e3ca8553b9aac09bd978c73d21b9032c707ac6d803bae6a20ecc048df4a8"}, - {file = "pyinstrument-4.6.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f329f5534ca069420246f5ce57270d975229bcb92a3a3fd6b2ca086527d9764"}, - {file = "pyinstrument-4.6.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4dcdcc7ba224a0c5edfbd00b0f530f5aed2b26da5aaa2f9af5519d4aa8c7e41"}, - {file = "pyinstrument-4.6.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73db0c2c99119c65b075feee76e903b4ed82e59440fe8b5724acf5c7cb24721f"}, - {file = "pyinstrument-4.6.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:da58f265326f3cf3975366ccb8b39014f1e69ff8327958a089858d71c633d654"}, - {file = "pyinstrument-4.6.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:feebcf860f955401df30d029ec8de7a0c5515d24ea809736430fd1219686fe14"}, - {file = "pyinstrument-4.6.2-cp310-cp310-win32.whl", hash = "sha256:b2b66ff0b16c8ecf1ec22de001cfff46872b2c163c62429055105564eef50b2e"}, - {file = "pyinstrument-4.6.2-cp310-cp310-win_amd64.whl", hash = "sha256:8d104b7a7899d5fa4c5bf1ceb0c1a070615a72c5dc17bc321b612467ad5c5d88"}, - {file = "pyinstrument-4.6.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:62f6014d2b928b181a52483e7c7b82f2c27e22c577417d1681153e5518f03317"}, - {file = "pyinstrument-4.6.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dcb5c8d763c5df55131670ba2a01a8aebd0d490a789904a55eb6a8b8d497f110"}, - {file = "pyinstrument-4.6.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ed4e8c6c84e0e6429ba7008a66e435ede2d8cb027794c20923c55669d9c5633"}, - {file = "pyinstrument-4.6.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c0f0e1d8f8c70faa90ff57f78ac0dda774b52ea0bfb2d9f0f41ce6f3e7c869e"}, - {file = "pyinstrument-4.6.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b3c44cb037ad0d6e9d9a48c14d856254ada641fbd0ae9de40da045fc2226a2a"}, - {file = "pyinstrument-4.6.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:be9901f17ac2f527c352f2fdca3d717c1d7f2ce8a70bad5a490fc8cc5d2a6007"}, - {file = "pyinstrument-4.6.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8a9791bf8916c1cf439c202fded32de93354b0f57328f303d71950b0027c7811"}, - {file = "pyinstrument-4.6.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d6162615e783c59e36f2d7caf903a7e3ecb6b32d4a4ae8907f2760b2ef395bf6"}, - {file = "pyinstrument-4.6.2-cp311-cp311-win32.whl", hash = "sha256:28af084aa84bbfd3620ebe71d5f9a0deca4451267f363738ca824f733de55056"}, - {file = "pyinstrument-4.6.2-cp311-cp311-win_amd64.whl", hash = "sha256:dd6007d3c2e318e09e582435dd8d111cccf30d342af66886b783208813caf3d7"}, - {file = "pyinstrument-4.6.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e3813c8ecfab9d7d855c5f0f71f11793cf1507f40401aa33575c7fd613577c23"}, - {file = "pyinstrument-4.6.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6c761372945e60fc1396b7a49f30592e8474e70a558f1a87346d27c8c4ce50f7"}, - {file = "pyinstrument-4.6.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fba3244e94c117bf4d9b30b8852bbdcd510e7329fdd5c7c8b3799e00a9215a8"}, - {file = "pyinstrument-4.6.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:803ac64e526473d64283f504df3b0d5c2c203ea9603cab428641538ffdc753a7"}, - {file = "pyinstrument-4.6.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2e554b1bb0df78f5ce8a92df75b664912ca93aa94208386102af454ec31b647"}, - {file = "pyinstrument-4.6.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7c671057fad22ee3ded897a6a361204ea2538e44c1233cad0e8e30f6d27f33db"}, - {file = "pyinstrument-4.6.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:d02f31fa13a9e8dc702a113878419deba859563a32474c9f68e04619d43d6f01"}, - {file = "pyinstrument-4.6.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b55983a884f083f93f0fc6d12ff8df0acd1e2fb0580d2f4c7bfe6def33a84b58"}, - {file = "pyinstrument-4.6.2-cp312-cp312-win32.whl", hash = "sha256:fdc0a53b27e5d8e47147489c7dab596ddd1756b1e053217ef5bc6718567099ff"}, - {file = "pyinstrument-4.6.2-cp312-cp312-win_amd64.whl", hash = "sha256:dd5c53a0159126b5ce7cbc4994433c9c671e057c85297ff32645166a06ad2c50"}, - {file = "pyinstrument-4.6.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b082df0bbf71251a7f4880a12ed28421dba84ea7110bb376e0533067a4eaff40"}, - {file = "pyinstrument-4.6.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90350533396071cb2543affe01e40bf534c35cb0d4b8fa9fdb0f052f9ca2cfe3"}, - {file = "pyinstrument-4.6.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:67268bb0d579330cff40fd1c90b8510363ca1a0e7204225840614068658dab77"}, - {file = "pyinstrument-4.6.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20e15b4e1d29ba0b7fc81aac50351e0dc0d7e911e93771ebc3f408e864a2c93b"}, - {file = "pyinstrument-4.6.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:2e625fc6ffcd4fd420493edd8276179c3f784df207bef4c2192725c1b310534c"}, - {file = "pyinstrument-4.6.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:113d2fc534c9ca7b6b5661d6ada05515bf318f6eb34e8d05860fe49eb7cfe17e"}, - {file = "pyinstrument-4.6.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3098cd72b71a322a72dafeb4ba5c566465e193d2030adad4c09566bd2f89bf4f"}, - {file = "pyinstrument-4.6.2-cp37-cp37m-win32.whl", hash = "sha256:08fdc7f88c989316fa47805234c37a40fafe7b614afd8ae863f0afa9d1707b37"}, - {file = "pyinstrument-4.6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:5ebeba952c0056dcc9b9355328c78c4b5c2a33b4b4276a9157a3ab589f3d1bac"}, - {file = "pyinstrument-4.6.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:34e59e91c88ec9ad5630c0964eca823949005e97736bfa838beb4789e94912a2"}, - {file = "pyinstrument-4.6.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cd0320c39e99e3c0a3129d1ed010ac41e5a7eb96fb79900d270080a97962e995"}, - {file = "pyinstrument-4.6.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46992e855d630575ec635eeca0068a8ddf423d4fd32ea0875a94e9f8688f0b95"}, - {file = "pyinstrument-4.6.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e474c56da636253dfdca7cd1998b240d6b39f7ed34777362db69224fcf053b1"}, - {file = "pyinstrument-4.6.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4b559322f30509ad8f082561792352d0805b3edfa508e492a36041fdc009259"}, - {file = "pyinstrument-4.6.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:06a8578b2943eb1dbbf281e1e59e44246acfefd79e1b06d4950f01b693de12af"}, - {file = "pyinstrument-4.6.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7bd3da31c46f1c1cb7ae89031725f6a1d1015c2041d9c753fe23980f5f9fd86c"}, - {file = "pyinstrument-4.6.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e63f4916001aa9c625976a50779282e0a5b5e9b17c52a50ef4c651e468ed5b88"}, - {file = "pyinstrument-4.6.2-cp38-cp38-win32.whl", hash = "sha256:32ec8db6896b94af790a530e1e0edad4d0f941a0ab8dd9073e5993e7ea46af7d"}, - {file = "pyinstrument-4.6.2-cp38-cp38-win_amd64.whl", hash = "sha256:a59fc4f7db738a094823afe6422509fa5816a7bf74e768ce5a7a2ddd91af40ac"}, - {file = "pyinstrument-4.6.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3a165e0d2deb212d4cf439383982a831682009e1b08733c568cac88c89784e62"}, - {file = "pyinstrument-4.6.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7ba858b3d6f6e5597c641edcc0e7e464f85aba86d71bc3b3592cb89897bf43f6"}, - {file = "pyinstrument-4.6.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fd8e547cf3df5f0ec6e4dffbe2e857f6b28eda51b71c3c0b5a2fc0646527835"}, - {file = "pyinstrument-4.6.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0de2c1714a37a820033b19cf134ead43299a02662f1379140974a9ab733c5f3a"}, - {file = "pyinstrument-4.6.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01fc45dedceec3df81668d702bca6d400d956c8b8494abc206638c167c78dfd9"}, - {file = "pyinstrument-4.6.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5b6e161ef268d43ee6bbfae7fd2cdd0a52c099ddd21001c126ca1805dc906539"}, - {file = "pyinstrument-4.6.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6ba8e368d0421f15ba6366dfd60ec131c1b46505d021477e0f865d26cf35a605"}, - {file = "pyinstrument-4.6.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edca46f04a573ac2fb11a84b937844e6a109f38f80f4b422222fb5be8ecad8cb"}, - {file = "pyinstrument-4.6.2-cp39-cp39-win32.whl", hash = "sha256:baf375953b02fe94d00e716f060e60211ede73f49512b96687335f7071adb153"}, - {file = "pyinstrument-4.6.2-cp39-cp39-win_amd64.whl", hash = "sha256:af1a953bce9fd530040895d01ff3de485e25e1576dccb014f76ba9131376fcad"}, - {file = "pyinstrument-4.6.2.tar.gz", hash = "sha256:0002ee517ed8502bbda6eb2bb1ba8f95a55492fcdf03811ba13d4806e50dd7f6"}, + {file = "pyinstrument-5.1.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f224fe80ba288a00980af298d3808219f9d246fd95b4f91729c9c33a0dc54fe6"}, + {file = "pyinstrument-5.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7df09fc0d5b72daf48b73cdf07738761bff7f656c81aff686b3ccdd7d2abe236"}, + {file = "pyinstrument-5.1.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:75a7e17377d4405666bbaf126b1fd7bbb7e206d7246e6db3d62864d3d4790ae3"}, + {file = "pyinstrument-5.1.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5381cc6583d26e04d9298acded4242f4fe71986f1472c8aee6992c6816f0cac5"}, + {file = "pyinstrument-5.1.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ec08a530bef8d3492d31d8b0b12d0cfde09539f2a1c4b9678662ebc3c843e478"}, + {file = "pyinstrument-5.1.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9d671168508129b472be570bc9aee361190ba917b997c703bd134bb4de445ce7"}, + {file = "pyinstrument-5.1.2-cp310-cp310-win32.whl", hash = "sha256:5957a94f84564b374a7f856d1b322345d600964280b0d687b8ddcc483f21e576"}, + {file = "pyinstrument-5.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:38a2180a7801c51610b50e5d423674b21872efd019ccf05a11b7f9016cb1dcfc"}, + {file = "pyinstrument-5.1.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3739a05583ea6312c385eb59fe985cd20d9048e95f9eeeb6a2f6c35202e2d36e"}, + {file = "pyinstrument-5.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7c9ee05dc75ac5fb18498c311e624f77f7f321f7ff325b251aa09e52e46f1d6a"}, + {file = "pyinstrument-5.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a49a55ca5b75218767e29cacbe515d0b66fc18cb48a937bca0f77b8dafc7202"}, + {file = "pyinstrument-5.1.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0c45c14974ff04b1bfdc6c2a448627c6da7409c7800d0eb7bd03fb435dcb41d7"}, + {file = "pyinstrument-5.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:22b9c04b3982c41c04b1c5ed05d1bc3a2ba26533450084058119f6dc160e70a3"}, + {file = "pyinstrument-5.1.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5c4995ee0774801790c138f0dfec17d4e7a7ef09a6d56d53cbcbf0578a711021"}, + {file = "pyinstrument-5.1.2-cp311-cp311-win32.whl", hash = "sha256:fe449e4a8ee60a2a27cf509350a584670f4c3704649601be7937598f09dbe7ca"}, + {file = "pyinstrument-5.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:3fb839429671a42bf349335af4c1ce5cf83386ac11f04df0bc40720d4cb7d77d"}, + {file = "pyinstrument-5.1.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2519865d4bf58936f2506c1c46a82d29a20f3239aa50c941df1ca9618c7da5f0"}, + {file = "pyinstrument-5.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:059442106b8b5de29ae5ac1bdc20d044fed4da534b8caba434b6ffb119037bf5"}, + {file = "pyinstrument-5.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cd51f2d54fc39a4cfd73ba6be27cd0187123132ce3f445b639bff5e1b23d7e26"}, + {file = "pyinstrument-5.1.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:12af1e83795b6c640d657d339014dd1ff718b182dec736d7d1f1d8a97534eb53"}, + {file = "pyinstrument-5.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2565513658e742c5eb691a779cb29d19d01bc9ee951d0eb76482e9f343c38c2e"}, + {file = "pyinstrument-5.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5afd0ba788a1d112da49fb77966918e01df1f9e7d62e72894d82f7acb0996c2d"}, + {file = "pyinstrument-5.1.2-cp312-cp312-win32.whl", hash = "sha256:554077b031b278593cb2301f0057be771ea62a729878c69aaf29fcdfb7b71281"}, + {file = "pyinstrument-5.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:55a905384ba43efc924b8863aa6cfd276f029e4aa70c4a0e3b7389e27b191e45"}, + {file = "pyinstrument-5.1.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7b8bab2334bf1d4c9e92d61db574300b914b594588a6b6dd67c45450152dfc29"}, + {file = "pyinstrument-5.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:13dcc138a61298ef4994b7aebff509d2c06db89dfd6e2021f0b9cd96aaa44ec3"}, + {file = "pyinstrument-5.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c8abd4a7ffa2e7f9e00039a5e549e8eebc80d7ca8d43f0fb51a50ff2b117ce4a"}, + {file = "pyinstrument-5.1.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eb3a05108edebc30f31e2c69c904576042f1158b2513ab80adc08f7848a7a8f0"}, + {file = "pyinstrument-5.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f70d588b53f3f35829d1d1ddfa05e07fcebf1434b3b1509d542ca317d8e9a2a5"}, + {file = "pyinstrument-5.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b007327e0d6a6a01d5064883dd27c19996f044ce7488d507826fee7884e6a32e"}, + {file = "pyinstrument-5.1.2-cp313-cp313-win32.whl", hash = "sha256:9ba0e6b17a7e86c3dc02d208e4c25506e8f914d9964ae89449f1f37f0b70abc0"}, + {file = "pyinstrument-5.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:660d7fc486a839814db0b2f716bc13d8b99b9c780aaeb47f74a70a34adc02a7b"}, + {file = "pyinstrument-5.1.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:0baed297beee2bb9897e737bbd89e3b9d45a2fbbea9f1ad4e809007d780a9b1e"}, + {file = "pyinstrument-5.1.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ebb910a32a45bde6c3fc30c578efc28a54517990e11e94b5e48a0d5479728568"}, + {file = "pyinstrument-5.1.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bad403c157f9c6dba7f731a6fca5bfcd8ca2701a39bcc717dcc6e0b10055ffc4"}, + {file = "pyinstrument-5.1.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2f456cabdb95fd343c798a7f2a56688b028f981522e283c5f59bd59195b66df5"}, + {file = "pyinstrument-5.1.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4e9c4dcc1f2c4a0cd6b576e3604abc37496a7868243c9a1443ad3b9db69d590f"}, + {file = "pyinstrument-5.1.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:acf93b128328c6d80fdb85431068ac17508f0f7845e89505b0ea6130dead5ca6"}, + {file = "pyinstrument-5.1.2-cp314-cp314-win32.whl", hash = "sha256:9c7f0167903ecff8b1d744f7e37b2bd4918e05a69cca724cb112f5ed59d1e41b"}, + {file = "pyinstrument-5.1.2-cp314-cp314-win_amd64.whl", hash = "sha256:ce3f6b1f9a2b5d74819ecc07d631eadececf915f551474a75ad65ac580ec5a0e"}, + {file = "pyinstrument-5.1.2-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:af8651b239049accbeecd389d35823233f649446f76f47fd005316b05d08cef2"}, + {file = "pyinstrument-5.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c6082f1c3e43e1d22834e91ba8975f0080186df4018a04b4dd29f9623c59df1d"}, + {file = "pyinstrument-5.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c031eb066ddc16425e1e2f56aad5c1ce1e27b2432a70329e5385b85e812decee"}, + {file = "pyinstrument-5.1.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f447ec391cad30667ba412dce41607aaa20d4a2496a7ab867e0c199f0fe3ae3d"}, + {file = "pyinstrument-5.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:50299bddfc1fe0039898f895b10ef12f9db08acffb4d85326fad589cda24d2ee"}, + {file = "pyinstrument-5.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a193ff08825ece115ececa136832acb14c491c77ab1e6b6a361905df8753d5c6"}, + {file = "pyinstrument-5.1.2-cp314-cp314t-win32.whl", hash = "sha256:de887ba19e1057bd2d86e6584f17788516a890ae6fe1b7eed9927873f416b4d8"}, + {file = "pyinstrument-5.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:b6a71f5e7f53c86c9b476b30cf19509463a63581ef17ddbd8680fee37ae509db"}, + {file = "pyinstrument-5.1.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:47f14f248108f1202d48f34903bddc053a47c62ce46908aee848c1f667a1925b"}, + {file = "pyinstrument-5.1.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cc3f2688981af764fa2c5f5a00d7040c0c12771ca5a026730f2d826f7a28d277"}, + {file = "pyinstrument-5.1.2-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7afb24d11d24fb1762059240ed97a1a4607779d5f221f91d62b67ae089bd506d"}, + {file = "pyinstrument-5.1.2-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3d21221a29718d5dcdc1453dbbbdd100734525672ef1e34ff03d49bc5d688ca4"}, + {file = "pyinstrument-5.1.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:3b68aa9f0d5217c67370762c99a80750ce56f66e5e9281c31b5baa3e4b88894d"}, + {file = "pyinstrument-5.1.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:755702f01800934c3bec3c0d30483f97b6ff1fc1d2afcf6d816584703c9f1235"}, + {file = "pyinstrument-5.1.2-cp38-cp38-win32.whl", hash = "sha256:2bacb980c95d4c9ea6a253e5ccf3e99993082de29ff7e7fc397e9484355577b1"}, + {file = "pyinstrument-5.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:2588bc34c25d50f29d3a117c7dfac06513ee59c507b65081e66ca9569bcf45e0"}, + {file = "pyinstrument-5.1.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bea0687665c181c6e62677fb560739a473c4286816582a43f8eb0aa6094ed529"}, + {file = "pyinstrument-5.1.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:64246d2bd475870b62ed5df4808bfb33328135e8dfbdff823f9cb7d1358eb40b"}, + {file = "pyinstrument-5.1.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff6fd3c7907e57f082cdd405bec1b34768c1810a165538299d259ee1bff5d7b6"}, + {file = "pyinstrument-5.1.2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:af09af38ee8407ca273407e24a8e6470d2444561d01005ee6a8db5f2fd908c08"}, + {file = "pyinstrument-5.1.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1249d2799cdd57151b4444167e5c7736e2c9b5e79bd781b0779d631338509553"}, + {file = "pyinstrument-5.1.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2d653206f50260f20bc78339c3d7aa0f19f8cf9c9f71939fbf02e2ea30353487"}, + {file = "pyinstrument-5.1.2-cp39-cp39-win32.whl", hash = "sha256:d0b0c6e289725f14d0ff73f8190c953bdcb98f21c5c29c3eafb0dca8025583cb"}, + {file = "pyinstrument-5.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:db8243e602aca43dc7ce8e40ed7d0ca4820d024c3c03824870c5a9e98f84e953"}, + {file = "pyinstrument-5.1.2.tar.gz", hash = "sha256:af149d672da9493fa37334a1cc68f7b80c3e6cb9fd99b9e426c447db5c650bf0"}, ] [package.extras] bin = ["click", "nox"] -docs = ["furo (==2021.6.18b36)", "myst-parser (==0.15.1)", "sphinx (==4.2.0)", "sphinxcontrib-programoutput (==0.17)"] -examples = ["django", "numpy"] -test = ["flaky", "greenlet (>=3.0.0a1)", "ipython", "pytest", "pytest-asyncio (==0.12.0)", "sphinx-autobuild (==2021.3.14)", "trio"] -types = ["typing-extensions"] +docs = ["furo (==2024.7.18)", "myst-parser (==3.0.1)", "sphinx (==7.4.7)", "sphinx-autobuild (==2024.4.16)", "sphinxcontrib-programoutput (==0.17)"] +examples = ["django", "litestar", "numpy"] +test = ["cffi (>=1.17.0)", "flaky", "greenlet (>=3)", "ipython", "pytest", "pytest-asyncio (==0.23.8)", "trio"] +types = ["typing_extensions"] [[package]] name = "pyjwt" -version = "2.9.0" +version = "2.13.0" description = "JSON Web Token implementation in Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "PyJWT-2.9.0-py3-none-any.whl", hash = "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850"}, - {file = "pyjwt-2.9.0.tar.gz", hash = "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c"}, + {file = "pyjwt-2.13.0-py3-none-any.whl", hash = "sha256:66adcc2aff09b3f1bbd95fc1e1577df8ac8723c978552fd43304c8a290ac5728"}, + {file = "pyjwt-2.13.0.tar.gz", hash = "sha256:41571c89ca91598c79e8ef18a2d07367d4810fbbd6f637794879baf1b7703423"}, ] +[package.dependencies] +typing_extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} + [package.extras] crypto = ["cryptography (>=3.4.0)"] -dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"] -docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] -tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] [[package]] name = "pyparsing" -version = "3.1.1" -description = "pyparsing module - Classes and methods to define and execute parsing grammars" +version = "3.3.2" +description = "pyparsing - Classes and methods to define and execute parsing grammars" optional = false -python-versions = ">=3.6.8" +python-versions = ">=3.9" files = [ - {file = "pyparsing-3.1.1-py3-none-any.whl", hash = "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb"}, - {file = "pyparsing-3.1.1.tar.gz", hash = "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db"}, + {file = "pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d"}, + {file = "pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc"}, ] [package.extras] @@ -3646,35 +4462,36 @@ diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "pytest" -version = "7.4.4" +version = "9.1.1" description = "pytest: simple powerful testing with Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" files = [ - {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, - {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, + {file = "pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c"}, + {file = "pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313"}, ] [package.dependencies] -colorama = {version = "*", markers = "sys_platform == \"win32\""} -exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} -iniconfig = "*" -packaging = "*" -pluggy = ">=0.12,<2.0" -tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} +colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1", markers = "python_version < \"3.11\""} +iniconfig = ">=1.0.1" +packaging = ">=22" +pluggy = ">=1.5,<2" +pygments = ">=2.7.2" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-mock" -version = "3.14.0" +version = "3.15.1" description = "Thin-wrapper around the mock package for easier use with pytest" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0"}, - {file = "pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f"}, + {file = "pytest_mock-3.15.1-py3-none-any.whl", hash = "sha256:0a25e2eb88fe5168d535041d09a4529a188176ae608a6d249ee65abc0949630d"}, + {file = "pytest_mock-3.15.1.tar.gz", hash = "sha256:1849a238f6f396da19762269de72cb1814ab44416fa73a8686deac10b0d87a0f"}, ] [package.dependencies] @@ -3685,13 +4502,13 @@ dev = ["pre-commit", "pytest-asyncio", "tox"] [[package]] name = "python-dateutil" -version = "2.8.2" +version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, ] [package.dependencies] @@ -3699,13 +4516,13 @@ six = ">=1.5" [[package]] name = "python-dotenv" -version = "1.0.1" +version = "1.2.2" description = "Read key-value pairs from a .env file and set them as environment variables" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, - {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, + {file = "python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a"}, + {file = "python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3"}, ] [package.extras] @@ -3713,285 +4530,512 @@ cli = ["click (>=5.0)"] [[package]] name = "python-multipart" -version = "0.0.16" +version = "0.0.32" description = "A streaming multipart parser for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "python_multipart-0.0.16-py3-none-any.whl", hash = "sha256:c2759b7b976ef3937214dfb592446b59dfaa5f04682a076f78b117c94776d87a"}, - {file = "python_multipart-0.0.16.tar.gz", hash = "sha256:8dee37b88dab9b59922ca173c35acb627cc12ec74019f5cd4578369c6df36554"}, + {file = "python_multipart-0.0.32-py3-none-any.whl", hash = "sha256:ff6d3f776f16878c894e52e107296ffc890e913c611b1a4ec6c44e2821fe2e23"}, + {file = "python_multipart-0.0.32.tar.gz", hash = "sha256:be54b7f3fa167bb83e4fcd936b887b708f4e57fe75911c02aebf53efaf8d938e"}, ] [[package]] name = "pytz" -version = "2023.4" +version = "2026.2" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" files = [ - {file = "pytz-2023.4-py2.py3-none-any.whl", hash = "sha256:f90ef520d95e7c46951105338d918664ebfd6f1d995bd7d153127ce90efafa6a"}, - {file = "pytz-2023.4.tar.gz", hash = "sha256:31d4583c4ed539cd037956140d695e42c033a19e984bfce9964a3f7d59bc2b40"}, + {file = "pytz-2026.2-py2.py3-none-any.whl", hash = "sha256:04156e608bee23d3792fd45c94ae47fae1036688e75032eea2e3bf0323d1f126"}, + {file = "pytz-2026.2.tar.gz", hash = "sha256:0e60b47b29f21574376f218fe21abc009894a2321ea16c6754f3cad6eb7cdd6a"}, ] [[package]] name = "pyunormalize" -version = "16.0.0" -description = "Unicode normalization forms (NFC, NFKC, NFD, NFKD). A library independent of the Python core Unicode database." +version = "17.0.0" +description = "A library for Unicode normalization (NFC, NFD, NFKC, NFKD) independent of Python's core Unicode database." optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "pyunormalize-16.0.0-py3-none-any.whl", hash = "sha256:c647d95e5d1e2ea9a2f448d1d95d8518348df24eab5c3fd32d2b5c3300a49152"}, - {file = "pyunormalize-16.0.0.tar.gz", hash = "sha256:2e1dfbb4a118154ae26f70710426a52a364b926c9191f764601f5a8cb12761f7"}, + {file = "pyunormalize-17.0.0-py3-none-any.whl", hash = "sha256:f0d93b076f938db2b26d319d04f2b58505d1cd7a80b5b72badbe7d1aa4d2a31c"}, + {file = "pyunormalize-17.0.0.tar.gz", hash = "sha256:0949a3e56817e287febcaf1b0cc4b5adf0bb107628d379335938040947eec792"}, ] [[package]] name = "pywin32" -version = "308" -description = "Python for Window Extensions" +version = "312" +description = "Python for Windows Extensions" optional = false -python-versions = "*" +python-versions = ">=3.9" files = [ - {file = "pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e"}, - {file = "pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e"}, - {file = "pywin32-308-cp310-cp310-win_arm64.whl", hash = "sha256:a5ab5381813b40f264fa3495b98af850098f814a25a63589a8e9eb12560f450c"}, - {file = "pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a"}, - {file = "pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b"}, - {file = "pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6"}, - {file = "pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897"}, - {file = "pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47"}, - {file = "pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091"}, - {file = "pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed"}, - {file = "pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4"}, - {file = "pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd"}, - {file = "pywin32-308-cp37-cp37m-win32.whl", hash = "sha256:1f696ab352a2ddd63bd07430080dd598e6369152ea13a25ebcdd2f503a38f1ff"}, - {file = "pywin32-308-cp37-cp37m-win_amd64.whl", hash = "sha256:13dcb914ed4347019fbec6697a01a0aec61019c1046c2b905410d197856326a6"}, - {file = "pywin32-308-cp38-cp38-win32.whl", hash = "sha256:5794e764ebcabf4ff08c555b31bd348c9025929371763b2183172ff4708152f0"}, - {file = "pywin32-308-cp38-cp38-win_amd64.whl", hash = "sha256:3b92622e29d651c6b783e368ba7d6722b1634b8e70bd376fd7610fe1992e19de"}, - {file = "pywin32-308-cp39-cp39-win32.whl", hash = "sha256:7873ca4dc60ab3287919881a7d4f88baee4a6e639aa6962de25a98ba6b193341"}, - {file = "pywin32-308-cp39-cp39-win_amd64.whl", hash = "sha256:71b3322d949b4cc20776436a9c9ba0eeedcbc9c650daa536df63f0ff111bb920"}, + {file = "pywin32-312-cp310-cp310-win32.whl", hash = "sha256:772235332b5d1024c696f11cea1ae4be7930f0a8b894bb43db14e3f435f1ff7e"}, + {file = "pywin32-312-cp310-cp310-win_amd64.whl", hash = "sha256:5dbc35d2b5320dc07f25fa31269cfb767471002b17de5eb067d03da68c7cb2db"}, + {file = "pywin32-312-cp310-cp310-win_arm64.whl", hash = "sha256:3020656e34f1cf7faeb7bccd2b84653a607c6ff0c55ada85e6487d61716deabd"}, + {file = "pywin32-312-cp311-cp311-win32.whl", hash = "sha256:17948aeadbdb091f0ced6ef0841620794e68327b94ee415571c1203594b7215c"}, + {file = "pywin32-312-cp311-cp311-win_amd64.whl", hash = "sha256:d11417d84412f859b722fad0841b3614459ed0047f7542d8362e77884f6b6e8a"}, + {file = "pywin32-312-cp311-cp311-win_arm64.whl", hash = "sha256:b2200a054ca6d6625c4842fc56a4976a4b47f96b73dbe5538c3f813a80359f47"}, + {file = "pywin32-312-cp312-cp312-win32.whl", hash = "sha256:dab4f65ac9c4e48400a2a0530c46c3c579cd5905ecd11b80692373915269208b"}, + {file = "pywin32-312-cp312-cp312-win_amd64.whl", hash = "sha256:b457f6d628a47e8a7346ce22acb7e1a46a4a78b52e1d17e1af56871bd19a93bc"}, + {file = "pywin32-312-cp312-cp312-win_arm64.whl", hash = "sha256:6017c58e12f6809fbb0555b75df144c2922a9ffd18e4b9b5afa863b6c1a9d950"}, + {file = "pywin32-312-cp313-cp313-win32.whl", hash = "sha256:7a27df850933d16a8eabfbaeb73d52b273e2da667f80d70b01a89d1f6828d02c"}, + {file = "pywin32-312-cp313-cp313-win_amd64.whl", hash = "sha256:c53e878d15a1c44788082bfe712a905433473aa38f86375b7cf8b45e3acbaaf9"}, + {file = "pywin32-312-cp313-cp313-win_arm64.whl", hash = "sha256:59aba5d5940842075343a5ddc6b11f1cdf0d1567fe745290359dfbcc7c2eb831"}, + {file = "pywin32-312-cp314-cp314-win32.whl", hash = "sha256:a77a90fbb6881238d2ca9c6fd797b25817f3768fe78d214a90137ff055a75f5b"}, + {file = "pywin32-312-cp314-cp314-win_amd64.whl", hash = "sha256:a4dd3a848290ef724347b19f301045831d8e802fa4464f491b98b1e0a081432e"}, + {file = "pywin32-312-cp314-cp314-win_arm64.whl", hash = "sha256:9fce94568364e0155e6dfb781ac5d95903be8baf28670632beab1b523f300daa"}, + {file = "pywin32-312-cp315-cp315-win32.whl", hash = "sha256:5c1fbe4a937a73ae9297384a3da38518cbc694c68ad8a809b2e19acd350f03ed"}, + {file = "pywin32-312-cp315-cp315-win_amd64.whl", hash = "sha256:c2f03a0f73f804a13c2735b99392b0cd426bb4f2c4d0178e5ac966a0f21618d5"}, + {file = "pywin32-312-cp315-cp315-win_arm64.whl", hash = "sha256:a8597d28f267b39074aef51fa593530082b39cbe5a074226096857b1fed2dfb9"}, + {file = "pywin32-312-cp39-cp39-win32.whl", hash = "sha256:d620900033cc7531e50727c3c8333091df5dd3ffe6d68cdca38c03f5821408d5"}, + {file = "pywin32-312-cp39-cp39-win_amd64.whl", hash = "sha256:dc90147579a905b8635e1b0ec6514967dcb07e6e0d9c42f1477feef14cac23bb"}, + {file = "pywin32-312-cp39-cp39-win_arm64.whl", hash = "sha256:02ebca0f0242b75292e218065004310d6a477407c09fa449bfe4f6022bc0c0fc"}, ] [[package]] name = "pyyaml" -version = "6.0.1" +version = "6.0.3" description = "YAML parser and emitter for Python" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, - {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, - {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, - {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, - {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, - {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, - {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, - {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, - {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, - {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, - {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, - {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, - {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, - {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, + {file = "PyYAML-6.0.3-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6"}, + {file = "PyYAML-6.0.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369"}, + {file = "PyYAML-6.0.3-cp38-cp38-win32.whl", hash = "sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295"}, + {file = "PyYAML-6.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b"}, + {file = "pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b"}, + {file = "pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b"}, + {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0"}, + {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69"}, + {file = "pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e"}, + {file = "pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c"}, + {file = "pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e"}, + {file = "pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d"}, + {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a"}, + {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4"}, + {file = "pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b"}, + {file = "pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf"}, + {file = "pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196"}, + {file = "pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc"}, + {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e"}, + {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea"}, + {file = "pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5"}, + {file = "pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b"}, + {file = "pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd"}, + {file = "pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8"}, + {file = "pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6"}, + {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6"}, + {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be"}, + {file = "pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26"}, + {file = "pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c"}, + {file = "pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb"}, + {file = "pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac"}, + {file = "pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5"}, + {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764"}, + {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35"}, + {file = "pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac"}, + {file = "pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3"}, + {file = "pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3"}, + {file = "pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c"}, + {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065"}, + {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65"}, + {file = "pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9"}, + {file = "pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b"}, + {file = "pyyaml-6.0.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da"}, + {file = "pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a"}, + {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926"}, + {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7"}, + {file = "pyyaml-6.0.3-cp39-cp39-win32.whl", hash = "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0"}, + {file = "pyyaml-6.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007"}, + {file = "pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f"}, ] [[package]] name = "redis" -version = "5.0.8" +version = "8.0.1" description = "Python client for Redis database and key-value store" optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" files = [ - {file = "redis-5.0.8-py3-none-any.whl", hash = "sha256:56134ee08ea909106090934adc36f65c9bcbbaecea5b21ba704ba6fb561f8eb4"}, - {file = "redis-5.0.8.tar.gz", hash = "sha256:0c5b10d387568dfe0698c6fad6615750c24170e548ca2deac10c649d463e9870"}, + {file = "redis-8.0.1-py3-none-any.whl", hash = "sha256:47daa35a058c23468d6437f17a8c76882cb316b838ef763036af99b96cedd743"}, + {file = "redis-8.0.1.tar.gz", hash = "sha256:afc5a7a2f5a084f5b1880dec548dd45be17db7e43c82a30d84f952aefb05cfb0"}, ] [package.dependencies] async-timeout = {version = ">=4.0.3", markers = "python_full_version < \"3.11.3\""} [package.extras] -hiredis = ["hiredis (>1.0.0)"] -ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"] +circuit-breaker = ["pybreaker (>=1.4.0)"] +hiredis = ["hiredis (>=3.2.0)"] +jwt = ["pyjwt (>=2.13.0)"] +ocsp = ["cryptography (>=36.0.1)", "pyopenssl (>=20.0.1)", "requests (>=2.31.0)"] +otel = ["opentelemetry-api (>=1.39.1)", "opentelemetry-exporter-otlp-proto-http (>=1.39.1)", "opentelemetry-sdk (>=1.39.1)"] +xxhash = ["xxhash (>=3.6.0,<3.7.0)"] [[package]] name = "regex" -version = "2024.11.6" +version = "2026.7.10" description = "Alternative regular expression module, to replace re." optional = false -python-versions = ">=3.8" -files = [ - {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91"}, - {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0"}, - {file = "regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e"}, - {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde"}, - {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e"}, - {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2"}, - {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf"}, - {file = "regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c"}, - {file = "regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86"}, - {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67"}, - {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d"}, - {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2"}, - {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008"}, - {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62"}, - {file = "regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e"}, - {file = "regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519"}, - {file = "regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638"}, - {file = "regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7"}, - {file = "regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20"}, - {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114"}, - {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3"}, - {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f"}, - {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0"}, - {file = "regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55"}, - {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89"}, - {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d"}, - {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34"}, - {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d"}, - {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45"}, - {file = "regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9"}, - {file = "regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60"}, - {file = "regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a"}, - {file = "regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9"}, - {file = "regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2"}, - {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4"}, - {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577"}, - {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3"}, - {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e"}, - {file = "regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe"}, - {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e"}, - {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29"}, - {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39"}, - {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51"}, - {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad"}, - {file = "regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54"}, - {file = "regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b"}, - {file = "regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84"}, - {file = "regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4"}, - {file = "regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0"}, - {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0"}, - {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7"}, - {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7"}, - {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c"}, - {file = "regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3"}, - {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07"}, - {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e"}, - {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6"}, - {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4"}, - {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d"}, - {file = "regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff"}, - {file = "regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a"}, - {file = "regex-2024.11.6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3a51ccc315653ba012774efca4f23d1d2a8a8f278a6072e29c7147eee7da446b"}, - {file = "regex-2024.11.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ad182d02e40de7459b73155deb8996bbd8e96852267879396fb274e8700190e3"}, - {file = "regex-2024.11.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ba9b72e5643641b7d41fa1f6d5abda2c9a263ae835b917348fc3c928182ad467"}, - {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40291b1b89ca6ad8d3f2b82782cc33807f1406cf68c8d440861da6304d8ffbbd"}, - {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cdf58d0e516ee426a48f7b2c03a332a4114420716d55769ff7108c37a09951bf"}, - {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a36fdf2af13c2b14738f6e973aba563623cb77d753bbbd8d414d18bfaa3105dd"}, - {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1cee317bfc014c2419a76bcc87f071405e3966da434e03e13beb45f8aced1a6"}, - {file = "regex-2024.11.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50153825ee016b91549962f970d6a4442fa106832e14c918acd1c8e479916c4f"}, - {file = "regex-2024.11.6-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea1bfda2f7162605f6e8178223576856b3d791109f15ea99a9f95c16a7636fb5"}, - {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:df951c5f4a1b1910f1a99ff42c473ff60f8225baa1cdd3539fe2819d9543e9df"}, - {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:072623554418a9911446278f16ecb398fb3b540147a7828c06e2011fa531e773"}, - {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f654882311409afb1d780b940234208a252322c24a93b442ca714d119e68086c"}, - {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:89d75e7293d2b3e674db7d4d9b1bee7f8f3d1609428e293771d1a962617150cc"}, - {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:f65557897fc977a44ab205ea871b690adaef6b9da6afda4790a2484b04293a5f"}, - {file = "regex-2024.11.6-cp38-cp38-win32.whl", hash = "sha256:6f44ec28b1f858c98d3036ad5d7d0bfc568bdd7a74f9c24e25f41ef1ebfd81a4"}, - {file = "regex-2024.11.6-cp38-cp38-win_amd64.whl", hash = "sha256:bb8f74f2f10dbf13a0be8de623ba4f9491faf58c24064f32b65679b021ed0001"}, - {file = "regex-2024.11.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5704e174f8ccab2026bd2f1ab6c510345ae8eac818b613d7d73e785f1310f839"}, - {file = "regex-2024.11.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:220902c3c5cc6af55d4fe19ead504de80eb91f786dc102fbd74894b1551f095e"}, - {file = "regex-2024.11.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e7e351589da0850c125f1600a4c4ba3c722efefe16b297de54300f08d734fbf"}, - {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5056b185ca113c88e18223183aa1a50e66507769c9640a6ff75859619d73957b"}, - {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e34b51b650b23ed3354b5a07aab37034d9f923db2a40519139af34f485f77d0"}, - {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5670bce7b200273eee1840ef307bfa07cda90b38ae56e9a6ebcc9f50da9c469b"}, - {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08986dce1339bc932923e7d1232ce9881499a0e02925f7402fb7c982515419ef"}, - {file = "regex-2024.11.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93c0b12d3d3bc25af4ebbf38f9ee780a487e8bf6954c115b9f015822d3bb8e48"}, - {file = "regex-2024.11.6-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:764e71f22ab3b305e7f4c21f1a97e1526a25ebdd22513e251cf376760213da13"}, - {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f056bf21105c2515c32372bbc057f43eb02aae2fda61052e2f7622c801f0b4e2"}, - {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:69ab78f848845569401469da20df3e081e6b5a11cb086de3eed1d48f5ed57c95"}, - {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:86fddba590aad9208e2fa8b43b4c098bb0ec74f15718bb6a704e3c63e2cef3e9"}, - {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:684d7a212682996d21ca12ef3c17353c021fe9de6049e19ac8481ec35574a70f"}, - {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a03e02f48cd1abbd9f3b7e3586d97c8f7a9721c436f51a5245b3b9483044480b"}, - {file = "regex-2024.11.6-cp39-cp39-win32.whl", hash = "sha256:41758407fc32d5c3c5de163888068cfee69cb4c2be844e7ac517a52770f9af57"}, - {file = "regex-2024.11.6-cp39-cp39-win_amd64.whl", hash = "sha256:b2837718570f95dd41675328e111345f9b7095d821bac435aac173ac80b19983"}, - {file = "regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519"}, +python-versions = ">=3.10" +files = [ + {file = "regex-2026.7.10-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:799a369bdab91dcf0eb424ebd7aa9650897025ce22f729248d8f2c72002c4daa"}, + {file = "regex-2026.7.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f0192e5f1cfc70e3cb35347135dd02e7497b3e7d83e378aa226d8b3e53a93f19"}, + {file = "regex-2026.7.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:221f2771cb780186b94bbf125a151bbeb242fa1a971da6ad59d7b0370f19de9a"}, + {file = "regex-2026.7.10-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab2fb1f7a2deb4ca3ddebbae6b93905d21480a3b4e11de28d79d9fb0d316fcf8"}, + {file = "regex-2026.7.10-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2f98ef73a13791a387d5c841416ad7f52040ae5caf10bcf46fa12bd2b3d63745"}, + {file = "regex-2026.7.10-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9a094ed44a22f9da497453137c3118b531fd783866ab524b0b0fc146e7395e1d"}, + {file = "regex-2026.7.10-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:53bbbd6c610489700f7110db1d85f3623924c3f7c760f987eca033867360788a"}, + {file = "regex-2026.7.10-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:87b776cf2890e356e4ab104b9df846e169da3eb5b0f110975547091f4e51854e"}, + {file = "regex-2026.7.10-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ab39d2c967aae3b48a412bff9cdbe7cd7559cd1e277599aceaeada7bc82b7200"}, + {file = "regex-2026.7.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b56416091bfd7a429f958f69aaf6823c517be9a49cb5bf1daa3767ce8bf8095e"}, + {file = "regex-2026.7.10-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:617e8f10472e34a8477931f978ff3a88d46ae2ba0e41927e580b933361f60948"}, + {file = "regex-2026.7.10-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:31fa17378b29519bfd0a1b8ba4e9c10cf0baf1cf4099b39b0689429e7dc2c795"}, + {file = "regex-2026.7.10-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5c363de7c0339d39341b6181839ed32509820b85ef506deafcf2e7e43baadab4"}, + {file = "regex-2026.7.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ed7c886a2fcbf14493ceaf9579394b33521730c161ebb8dad7db9c3e9fcab1a8"}, + {file = "regex-2026.7.10-cp310-cp310-win32.whl", hash = "sha256:b04583e8867136ae66353fa274f45121ab3ec3166dc45aaff3655a5db90d9f0e"}, + {file = "regex-2026.7.10-cp310-cp310-win_amd64.whl", hash = "sha256:e21e888a6b471b2bb1cdd4247e8d86632672232f29be583e7eafaa5f4634d34c"}, + {file = "regex-2026.7.10-cp310-cp310-win_arm64.whl", hash = "sha256:081acf191b4d614d573a56cab69f948b6864daa5e3cc69f209ee92e26e454c2f"}, + {file = "regex-2026.7.10-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:66d2c35587cd601c95965d5c0415058ba5cfd6ffbab7624ce198bd967102b341"}, + {file = "regex-2026.7.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:28a0973eeffff4292f5a7ee498ab65d5e94ee8cc9cea364239251eb4a260a0f1"}, + {file = "regex-2026.7.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8331484450b3894298bef8abecce532171ff6ac60b71f999eed10f2c01941a8a"}, + {file = "regex-2026.7.10-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0639b2488b775a0109f55a5a2172deebdedb4b6c5ab0d48c90b43cbf5de58d17"}, + {file = "regex-2026.7.10-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:be4223af640d0aa04c05db81d5d96ada3ead9c09187d892fd37f4f97829480be"}, + {file = "regex-2026.7.10-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d3c75d57a00109255e60bc9c623b6ececaf7905eaab845c79f036670ed4750a2"}, + {file = "regex-2026.7.10-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:724ee9379568658ec06362cf24325c5315cc5a67f61dfe585bfeff58300a355b"}, + {file = "regex-2026.7.10-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:732c19e5828eb287d01edb83b2eb87f283ba8e5fc3441c732709d3e8cbd14aaa"}, + {file = "regex-2026.7.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:982d07727c809b42a3968785354f11c3728414e4e90af0754345b431b2c32561"}, + {file = "regex-2026.7.10-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4574feca202f8c470bf678aed8b5d89df04aaf8dc677f3b83d92825051301c0f"}, + {file = "regex-2026.7.10-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:80151ca5bfc6c4524186b3e08b499e97319b2001fc265ed2d4fc12c0d5692cdf"}, + {file = "regex-2026.7.10-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bb52e10e453b5493afe1f7702a2973bc10f4dd8901c0f2ed869ffaa3f8319296"}, + {file = "regex-2026.7.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e37aba1994d73b4944053ab65a15f313bd5c28c885dd7f0d494a11749d89db6e"}, + {file = "regex-2026.7.10-cp311-cp311-win32.whl", hash = "sha256:6cbedeb5112f59dbd169385459b9943310bdd241c6966c19c5f6e2295055c93a"}, + {file = "regex-2026.7.10-cp311-cp311-win_amd64.whl", hash = "sha256:b1963ec5ba4d52788fb0eac6aca6eb8040e8e318c7e47ebbdfc09440c802919c"}, + {file = "regex-2026.7.10-cp311-cp311-win_arm64.whl", hash = "sha256:3750c42d47712e362158a04d0fd80131f73a55e8c715b2885442a0ff6f9fc3fc"}, + {file = "regex-2026.7.10-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:7252b48b0c60100095088fbeb281fca9a4fcf678a4e04b1c520c3f8613c952c4"}, + {file = "regex-2026.7.10-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:da6ef4cb8d457aab0482b50120136ae94238aaa421863eaa7d599759742c72d6"}, + {file = "regex-2026.7.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fe7ff456c22725c9d9017f7a2a7df2b51af6df77314176760b22e2d05278e181"}, + {file = "regex-2026.7.10-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3463a5f26be513a49e4d497debcf1b252a2db7b92c77d89621aa90b83d2dd38"}, + {file = "regex-2026.7.10-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:948dfc62683a6947b9b486c4598d8f6e3ecc542478b6767b87d52be68aeb55c6"}, + {file = "regex-2026.7.10-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c2cbd385d82f63bb35edb60b09b08abad3619bd0a4a492ae59e55afaf98e1b9d"}, + {file = "regex-2026.7.10-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f6222cafe00e072bb2b8f14142cd969637411fbc4dd3b1d73a90a3b817fa046f"}, + {file = "regex-2026.7.10-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:65ee5d1ac3cd541325f5ac92625b1c1505f4d171520dd931bda7952895c5321a"}, + {file = "regex-2026.7.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:aa34473fbcc108fea403074f3f45091461b18b2047d136f16ffaa4c65ad46a68"}, + {file = "regex-2026.7.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:9d028d189d8f38d7ff292f22187c0df37f2317f554d2ed9a2908ada330af57c0"}, + {file = "regex-2026.7.10-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:396ea70e4ea1f19571940add3bad9fd3eb6a19dc610d0d01f692bc1ba0c10cb4"}, + {file = "regex-2026.7.10-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:ebbf0d83ed5271991d666e54bb6c90ac2c55fb2ef3a88740c6af85dc85de2402"}, + {file = "regex-2026.7.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:58a4571b2a093f6f6ee4fd281faa8ebf645abcf575f758173ea2605c7a1e1ecb"}, + {file = "regex-2026.7.10-cp312-cp312-win32.whl", hash = "sha256:eac1207936555aa691ce32df1432b478f2729d54e6d93a1f4db9215bcd8eb47d"}, + {file = "regex-2026.7.10-cp312-cp312-win_amd64.whl", hash = "sha256:ecae626449d00db8c08f8f1fc00047a32d6d7eb5402b3976f5c3fda2b80a7a4f"}, + {file = "regex-2026.7.10-cp312-cp312-win_arm64.whl", hash = "sha256:87794549a3f5c1c2bdfba2380c1bf87b931e375f4133d929da44f95e396bf5fe"}, + {file = "regex-2026.7.10-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:4db009b4fc533d79af3e841d6c8538730423f82ea8508e353a3713725de7901c"}, + {file = "regex-2026.7.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b96341cb29a3faa5db05aff29c77d141d827414f145330e5d8846892119351c1"}, + {file = "regex-2026.7.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:14d27f6bd04beb01f6a25a1153d73e58c290fd45d92ba56af1bb44199fd1010d"}, + {file = "regex-2026.7.10-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e6b6a11bf898cca3ce7bfaa17b646901107f3975677fbd5097f36e5eb5641983"}, + {file = "regex-2026.7.10-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:234f8e0d65cf1df9becadae98648f74030ee85a8f12edcb5eb0f60a22a602197"}, + {file = "regex-2026.7.10-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:91b916d495db3e1b473c7c8e68733beec4dce8e487442db61764fff94f59740e"}, + {file = "regex-2026.7.10-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f0d4ccf70b1d13711242de0ba78967db5c35d12ac408378c70e06295c3f6644"}, + {file = "regex-2026.7.10-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c622f4c638a725c39abcb2e680b1bd592663c83b672a4ed350a17f806d75618e"}, + {file = "regex-2026.7.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:41a47c2b28d9421e2509a4583a22510dc31d83212fcf38e1508a7013140f71a8"}, + {file = "regex-2026.7.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:13fba679fe035037e9d5286620f88bbfd105df4d5fcd975942edd282ab986775"}, + {file = "regex-2026.7.10-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:8e26a075fa9945b9e44a3d02cc83d776c3b76bb1ff4b133bbfa620d5650131da"}, + {file = "regex-2026.7.10-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d0834c84ae8750ae1c4cede59b0afd4d2f775be958e11b18a3eea24ed9d0d9f1"}, + {file = "regex-2026.7.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64722a5031aeace7f6c8d5ea9a9b22d9368af0d6e8fa532585da8158549ea963"}, + {file = "regex-2026.7.10-cp313-cp313-win32.whl", hash = "sha256:74ae61d8573ecd51b5eeee7be2218e4c56e99c14fa8fcf97cf7519611d4be92e"}, + {file = "regex-2026.7.10-cp313-cp313-win_amd64.whl", hash = "sha256:5e792367e5f9b4ffb8cad93f1beaa91837056b94da98aa5c65a0db0c1b474927"}, + {file = "regex-2026.7.10-cp313-cp313-win_arm64.whl", hash = "sha256:82ab8330e7e2e416c2d42fcec67f02c242393b8681014750d4b70b3f158e1f08"}, + {file = "regex-2026.7.10-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:2b93eafd92c4128bab2f93500e8912cc9ecb3d3765f6685b902c6820d0909b6b"}, + {file = "regex-2026.7.10-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3f03b92fb6ec739df042e45b06423fc717ecf0063e07ffe2897f7b2d5735e1e8"}, + {file = "regex-2026.7.10-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:bb5aab464a0c5e03a97abad5bdf54517061ebbf72340d576e99ff661a42575cc"}, + {file = "regex-2026.7.10-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fadb07dbe36a541283ff454b1a268afd54b077d917043f2e1e5615372cb5f200"}, + {file = "regex-2026.7.10-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:21150500b970b12202879dfd82e7fd809d8e853140fff84d08e57a90cf1e154e"}, + {file = "regex-2026.7.10-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a68b637451d64ba30ed8ae125c973fa834cc2d37dfa7f154c2b479015d477ba8"}, + {file = "regex-2026.7.10-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3e23458d8903e33e7d27196d7a311523dc4e2f4137a5f34e4dbd30c8d37ff33e"}, + {file = "regex-2026.7.10-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cae27622c094558e519abf3242cf4272db961d12c5c9a9ffb7a1b44b2627d5c6"}, + {file = "regex-2026.7.10-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ee877b6d78f9dff1da94fef51ae8cf9cce0967e043fdcc864c40b85cf293c192"}, + {file = "regex-2026.7.10-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:2c66a8a1969cfd506d1e203c0005fd0fc3fe6efc83c945606566b6f9611d4851"}, + {file = "regex-2026.7.10-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:2bc350e1c5fa250f30ab0c3e38e5cfdffcd82cb8af224df69955cab4e3003812"}, + {file = "regex-2026.7.10-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:53f54993b462f3f91fea0f2076b46deb6619a5f45d70dbd1f543f789d8b900ef"}, + {file = "regex-2026.7.10-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cfcec18f7da682c4e2d82112829ce906569cb8d69fa6c26f3a50dfbed5ceb682"}, + {file = "regex-2026.7.10-cp313-cp313t-win32.whl", hash = "sha256:a2d6d30be35ddd70ce0f8ee259a4c25f24d6d689a45a5ac440f03e6bcc5a21d1"}, + {file = "regex-2026.7.10-cp313-cp313t-win_amd64.whl", hash = "sha256:c57b6ad3f7a1bdd101b2966f29dc161adf49727b1e8d3e1e89db2eda8a75c344"}, + {file = "regex-2026.7.10-cp313-cp313t-win_arm64.whl", hash = "sha256:3d8ef9df02c8083c7b4b855e3cb87c8e0ebbcfea088d98c7a886aaefdf88d837"}, + {file = "regex-2026.7.10-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:39f81d1fdf594446495f2f4edd8e62d8eda0f7a802c77ac596dc8448ad4cc5ca"}, + {file = "regex-2026.7.10-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:441edc66a54063f8269d1494fc8474d06605e71e8a918f4bcfd079ebda4ce042"}, + {file = "regex-2026.7.10-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cfeb11990f59e59a0df26c648f0adfcbf27be77241250636f5769eb08db662be"}, + {file = "regex-2026.7.10-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:460176b2db044a292baaee6891106566739657877af89a251cded228689015a6"}, + {file = "regex-2026.7.10-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9dc55698737aca028848bde418d6c51d74f2a5fd44872d3c8b56b626729adb89"}, + {file = "regex-2026.7.10-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d3e10779f60c000213a5b53f518824bd07b3dc119333b26d70c6be1c27b5c794"}, + {file = "regex-2026.7.10-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:38a5926601aaccf379512746b86eb0ac1d29121f6c776dac6ac5b31077432f2c"}, + {file = "regex-2026.7.10-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a72ecf5bfd3fc8d57927f7e3ded2487e144472f39010c3acaec3f6f3ff53f361"}, + {file = "regex-2026.7.10-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d50714405845c1010c871098558cfe5718fe39d2a2fab5f95c8863caeb7a82b3"}, + {file = "regex-2026.7.10-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ec1c44cf9bd22079aac37a07cb49a29ced9050ab5bddf24e50aba298f1e34d90"}, + {file = "regex-2026.7.10-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:9e9aaef25a40d1f1e1bbb1d0eb0190c4a64a7a1750f7eb67b8399bed6f4fd2a6"}, + {file = "regex-2026.7.10-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:e54e088dc64dd2766014e7cfe5f8bc45399400fd486816e494f93e3f0f55da06"}, + {file = "regex-2026.7.10-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:834271b1ff2cfa1f67fcd65a48bf11d11e9ab837e21bf79ce554efb648599ae8"}, + {file = "regex-2026.7.10-cp314-cp314-win32.whl", hash = "sha256:f988a1cec68058f71a38471813fba9e87dffe855582682e8a10e40ece12567a2"}, + {file = "regex-2026.7.10-cp314-cp314-win_amd64.whl", hash = "sha256:2129e4a5e86f26926982d883dff815056f2e98220fdf630e59f961b578a26c43"}, + {file = "regex-2026.7.10-cp314-cp314-win_arm64.whl", hash = "sha256:9cd5b6805396157b4cf993a6940cbb8663161f29b4df2458c1c9991f099299c5"}, + {file = "regex-2026.7.10-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:103e8f3acc3dcede88c0331c8612766bdcfc47c9250c5477f0e10e0550b9da49"}, + {file = "regex-2026.7.10-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:538ddb143f5ca085e372def17ef3ed9d74b50ad7fc431bd85dc50a9af1a7076f"}, + {file = "regex-2026.7.10-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6e3448e86b05ce87d4eb50f9c680860830f3b32493660b39f43957d6263e2eba"}, + {file = "regex-2026.7.10-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5eab9d3f981c423afd1a61db055cfe83553c3f6455949e334db04722469dd0a2"}, + {file = "regex-2026.7.10-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:177f930af3ad72e1045f8877540e0c43a38f7d328cf05f31963d0bd5f7ecf067"}, + {file = "regex-2026.7.10-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:dd3b6d97beb39afb412f2c79522b9e099463c31f4c49ab8347c5a2ca3531c478"}, + {file = "regex-2026.7.10-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8679f0652a183d93da646fcec8da8228db0be40d1595da37e6d74c2dc8c4713c"}, + {file = "regex-2026.7.10-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:494b19a5805438aeb582de99f9d97603d8fd48e6f4cc74d0088bb292b4da3b70"}, + {file = "regex-2026.7.10-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0911e34151a5429d0325dae538ba9851ec0b62426bdfd613060cda8f1c36ec7f"}, + {file = "regex-2026.7.10-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b862572b7a5f5ed47d2ba5921e63bf8d9e3b682f859d8f11e0e5ca46f7e82173"}, + {file = "regex-2026.7.10-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:3f361215e000d68a4aff375106637b83c80be36091d83ee5107ad3b32bd73f48"}, + {file = "regex-2026.7.10-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:4533af6099543db32ef26abc2b2f824781d4eebb309ab9296150fd1a0c7eb07d"}, + {file = "regex-2026.7.10-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:668ab85105361d0200e3545bec198a1acfc6b0aeb5fff8897647a826e5a171be"}, + {file = "regex-2026.7.10-cp314-cp314t-win32.whl", hash = "sha256:dd7715817a187edd7e2a2390908757f7ba42148e59cad755fb8ee1160c628eca"}, + {file = "regex-2026.7.10-cp314-cp314t-win_amd64.whl", hash = "sha256:78712d4954234df5ca24fdadb65a2ab034213f0cdfde376c272f9fc5e09866bb"}, + {file = "regex-2026.7.10-cp314-cp314t-win_arm64.whl", hash = "sha256:749b92640e1970e881fdf22a411d74bf9d049b154f4ef7232eeb9a90dd8be7f3"}, + {file = "regex-2026.7.10.tar.gz", hash = "sha256:1050fedf0a8a92e843971120c2f57c3a99bea86c0dfa1d63a9fac053fe54b135"}, ] [[package]] name = "requests" -version = "2.31.0" +version = "2.34.2" description = "Python HTTP for Humans." optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" files = [ - {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, - {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, + {file = "requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0"}, + {file = "requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed"}, ] [package.dependencies] -certifi = ">=2017.4.17" -charset-normalizer = ">=2,<4" +certifi = ">=2023.5.7" +charset_normalizer = ">=2,<4" idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<3" +urllib3 = ">=1.26,<3" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<8)"] [[package]] name = "rich" -version = "13.9.3" +version = "15.0.0" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false -python-versions = ">=3.8.0" +python-versions = ">=3.9.0" files = [ - {file = "rich-13.9.3-py3-none-any.whl", hash = "sha256:9836f5096eb2172c9e77df411c1b009bace4193d6a481d534fea75ebba758283"}, - {file = "rich-13.9.3.tar.gz", hash = "sha256:bc1e01b899537598cf02579d2b9f4a415104d3fc439313a7a2c165d76557a08e"}, + {file = "rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb"}, + {file = "rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36"}, ] [package.dependencies] markdown-it-py = ">=2.2.0" pygments = ">=2.13.0,<3.0.0" -typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.11\""} [package.extras] jupyter = ["ipywidgets (>=7.5.1,<9)"] +[[package]] +name = "rich-toolkit" +version = "0.20.3" +description = "Rich toolkit for building command-line applications" +optional = false +python-versions = ">=3.8" +files = [ + {file = "rich_toolkit-0.20.3-py3-none-any.whl", hash = "sha256:419aa87516d5f3849cca553c6dcf707c02a36d508fcf996946606725d34a3002"}, + {file = "rich_toolkit-0.20.3.tar.gz", hash = "sha256:223dd2cfba325ed55e94933b9e53f3aca13e9fdf76622bd564c18109a2273c1b"}, +] + +[package.dependencies] +click = ">=8.1.7" +rich = ">=13.7.1" +typing-extensions = ">=4.12.2" + +[[package]] +name = "rignore" +version = "0.7.6" +description = "Python Bindings for the ignore crate" +optional = false +python-versions = ">=3.8" +files = [ + {file = "rignore-0.7.6-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f3c74a7e5ee77aea669c95fdb3933f2a6c7549893700082e759128a29cf67e45"}, + {file = "rignore-0.7.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b7202404958f5fe3474bac91f65350f0b1dde1a5e05089f2946549b7e91e79ec"}, + {file = "rignore-0.7.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bde7c5835fa3905bfb7e329a4f1d7eccb676de63da7a3f934ddd5c06df20597"}, + {file = "rignore-0.7.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:626c3d4ba03af266694d25101bc1d8d16eda49c5feb86cedfec31c614fceca7d"}, + {file = "rignore-0.7.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a43841e651e7a05a4274b9026cc408d1912e64016ede8cd4c145dae5d0635be"}, + {file = "rignore-0.7.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7978c498dbf7f74d30cdb8859fe612167d8247f0acd377ae85180e34490725da"}, + {file = "rignore-0.7.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d22f72ab695c07d2d96d2a645208daff17084441b5d58c07378c9dd6f9c4c87"}, + {file = "rignore-0.7.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5bd8e1a91ed1a789b2cbe39eeea9204a6719d4f2cf443a9544b521a285a295f"}, + {file = "rignore-0.7.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bc1fc03efad5789365018e94ac4079f851a999bc154d1551c45179f7fcf45322"}, + {file = "rignore-0.7.6-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:ce2617fe28c51367fd8abfd4eeea9e61664af63c17d4ea00353d8ef56dfb95fa"}, + {file = "rignore-0.7.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7c4ad2cee85068408e7819a38243043214e2c3047e9bd4c506f8de01c302709e"}, + {file = "rignore-0.7.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:02cd240bfd59ecc3907766f4839cbba20530a2e470abca09eaa82225e4d946fb"}, + {file = "rignore-0.7.6-cp310-cp310-win32.whl", hash = "sha256:fe2bd8fa1ff555259df54c376abc73855cb02628a474a40d51b358c3a1ddc55b"}, + {file = "rignore-0.7.6-cp310-cp310-win_amd64.whl", hash = "sha256:d80afd6071c78baf3765ec698841071b19e41c326f994cfa69b5a1df676f5d39"}, + {file = "rignore-0.7.6-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:40be8226e12d6653abbebaffaea2885f80374c1c8f76fe5ca9e0cadd120a272c"}, + {file = "rignore-0.7.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:182f4e5e4064d947c756819446a7d4cdede8e756b8c81cf9e509683fe38778d7"}, + {file = "rignore-0.7.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16b63047648a916a87be1e51bb5c009063f1b8b6f5afe4f04f875525507e63dc"}, + {file = "rignore-0.7.6-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ba5524f5178deca4d7695e936604ebc742acb8958f9395776e1fcb8133f8257a"}, + {file = "rignore-0.7.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:62020dbb89a1dd4b84ab3d60547b3b2eb2723641d5fb198463643f71eaaed57d"}, + {file = "rignore-0.7.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b34acd532769d5a6f153a52a98dcb81615c949ab11697ce26b2eb776af2e174d"}, + {file = "rignore-0.7.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c5e53b752f9de44dff7b3be3c98455ce3bf88e69d6dc0cf4f213346c5e3416c"}, + {file = "rignore-0.7.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:25b3536d13a5d6409ce85f23936f044576eeebf7b6db1d078051b288410fc049"}, + {file = "rignore-0.7.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6e01cad2b0b92f6b1993f29fc01f23f2d78caf4bf93b11096d28e9d578eb08ce"}, + {file = "rignore-0.7.6-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:5991e46ab9b4868334c9e372ab0892b0150f3f586ff2b1e314272caeb38aaedb"}, + {file = "rignore-0.7.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6c8ae562e5d1246cba5eaeb92a47b2a279e7637102828dde41dcbe291f529a3e"}, + {file = "rignore-0.7.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:aaf938530dcc0b47c4cfa52807aa2e5bfd5ca6d57a621125fe293098692f6345"}, + {file = "rignore-0.7.6-cp311-cp311-win32.whl", hash = "sha256:166ebce373105dd485ec213a6a2695986346e60c94ff3d84eb532a237b24a4d5"}, + {file = "rignore-0.7.6-cp311-cp311-win_amd64.whl", hash = "sha256:44f35ee844b1a8cea50d056e6a595190ce9d42d3cccf9f19d280ae5f3058973a"}, + {file = "rignore-0.7.6-cp311-cp311-win_arm64.whl", hash = "sha256:14b58f3da4fa3d5c3fa865cab49821675371f5e979281c683e131ae29159a581"}, + {file = "rignore-0.7.6-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:03e82348cb7234f8d9b2834f854400ddbbd04c0f8f35495119e66adbd37827a8"}, + {file = "rignore-0.7.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b9e624f6be6116ea682e76c5feb71ea91255c67c86cb75befe774365b2931961"}, + {file = "rignore-0.7.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bda49950d405aa8d0ebe26af807c4e662dd281d926530f03f29690a2e07d649a"}, + {file = "rignore-0.7.6-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5fd5ab3840b8c16851d327ed06e9b8be6459702a53e5ab1fc4073b684b3789e"}, + {file = "rignore-0.7.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ced2a248352636a5c77504cb755dc02c2eef9a820a44d3f33061ce1bb8a7f2d2"}, + {file = "rignore-0.7.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a04a3b73b75ddc12c9c9b21efcdaab33ca3832941d6f1d67bffd860941cd448a"}, + {file = "rignore-0.7.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d24321efac92140b7ec910ac7c53ab0f0c86a41133d2bb4b0e6a7c94967f44dd"}, + {file = "rignore-0.7.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:73c7aa109d41e593785c55fdaa89ad80b10330affa9f9d3e3a51fa695f739b20"}, + {file = "rignore-0.7.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1734dc49d1e9501b07852ef44421f84d9f378da9fbeda729e77db71f49cac28b"}, + {file = "rignore-0.7.6-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5719ea14ea2b652c0c0894be5dfde954e1853a80dea27dd2fbaa749618d837f5"}, + {file = "rignore-0.7.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8e23424fc7ce35726854f639cb7968151a792c0c3d9d082f7f67e0c362cfecca"}, + {file = "rignore-0.7.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3efdcf1dd84d45f3e2bd2f93303d9be103888f56dfa7c3349b5bf4f0657ec696"}, + {file = "rignore-0.7.6-cp312-cp312-win32.whl", hash = "sha256:ccca9d1a8b5234c76b71546fc3c134533b013f40495f394a65614a81f7387046"}, + {file = "rignore-0.7.6-cp312-cp312-win_amd64.whl", hash = "sha256:c96a285e4a8bfec0652e0bfcf42b1aabcdda1e7625f5006d188e3b1c87fdb543"}, + {file = "rignore-0.7.6-cp312-cp312-win_arm64.whl", hash = "sha256:a64a750e7a8277a323f01ca50b7784a764845f6cce2fe38831cb93f0508d0051"}, + {file = "rignore-0.7.6-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:2bdab1d31ec9b4fb1331980ee49ea051c0d7f7bb6baa28b3125ef03cdc48fdaf"}, + {file = "rignore-0.7.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:90f0a00ce0c866c275bf888271f1dc0d2140f29b82fcf33cdbda1e1a6af01010"}, + {file = "rignore-0.7.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1ad295537041dc2ed4b540fb1a3906bd9ede6ccdad3fe79770cd89e04e3c73c"}, + {file = "rignore-0.7.6-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f782dbd3a65a5ac85adfff69e5c6b101285ef3f845c3a3cae56a54bebf9fe116"}, + {file = "rignore-0.7.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65cece3b36e5b0826d946494734c0e6aaf5a0337e18ff55b071438efe13d559e"}, + {file = "rignore-0.7.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7e4bb66c13cd7602dc8931822c02dfbbd5252015c750ac5d6152b186f0a8be0"}, + {file = "rignore-0.7.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:297e500c15766e196f68aaaa70e8b6db85fa23fdc075b880d8231fdfba738cd7"}, + {file = "rignore-0.7.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a07084211a8d35e1a5b1d32b9661a5ed20669970b369df0cf77da3adea3405de"}, + {file = "rignore-0.7.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:181eb2a975a22256a1441a9d2f15eb1292839ea3f05606620bd9e1938302cf79"}, + {file = "rignore-0.7.6-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:7bbcdc52b5bf9f054b34ce4af5269df5d863d9c2456243338bc193c28022bd7b"}, + {file = "rignore-0.7.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f2e027a6da21a7c8c0d87553c24ca5cc4364def18d146057862c23a96546238e"}, + {file = "rignore-0.7.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ee4a18b82cbbc648e4aac1510066682fe62beb5dc88e2c67c53a83954e541360"}, + {file = "rignore-0.7.6-cp313-cp313-win32.whl", hash = "sha256:a7d7148b6e5e95035d4390396895adc384d37ff4e06781a36fe573bba7c283e5"}, + {file = "rignore-0.7.6-cp313-cp313-win_amd64.whl", hash = "sha256:b037c4b15a64dced08fc12310ee844ec2284c4c5c1ca77bc37d0a04f7bff386e"}, + {file = "rignore-0.7.6-cp313-cp313-win_arm64.whl", hash = "sha256:e47443de9b12fe569889bdbe020abe0e0b667516ee2ab435443f6d0869bd2804"}, + {file = "rignore-0.7.6-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:8e41be9fa8f2f47239ded8920cc283699a052ac4c371f77f5ac017ebeed75732"}, + {file = "rignore-0.7.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6dc1e171e52cefa6c20e60c05394a71165663b48bca6c7666dee4f778f2a7d90"}, + {file = "rignore-0.7.6-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ce2268837c3600f82ab8db58f5834009dc638ee17103582960da668963bebc5"}, + {file = "rignore-0.7.6-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:690a3e1b54bfe77e89c4bacb13f046e642f8baadafc61d68f5a726f324a76ab6"}, + {file = "rignore-0.7.6-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09d12ac7a0b6210c07bcd145007117ebd8abe99c8eeb383e9e4673910c2754b2"}, + {file = "rignore-0.7.6-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a2b2b74a8c60203b08452479b90e5ce3dbe96a916214bc9eb2e5af0b6a9beb0"}, + {file = "rignore-0.7.6-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fc5a531ef02131e44359419a366bfac57f773ea58f5278c2cdd915f7d10ea94"}, + {file = "rignore-0.7.6-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b7a1f77d9c4cd7e76229e252614d963442686bfe12c787a49f4fe481df49e7a9"}, + {file = "rignore-0.7.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ead81f728682ba72b5b1c3d5846b011d3e0174da978de87c61645f2ed36659a7"}, + {file = "rignore-0.7.6-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:12ffd50f520c22ffdabed8cd8bfb567d9ac165b2b854d3e679f4bcaef11a9441"}, + {file = "rignore-0.7.6-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:e5a16890fbe3c894f8ca34b0fcacc2c200398d4d46ae654e03bc9b3dbf2a0a72"}, + {file = "rignore-0.7.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3abab3bf99e8a77488ef6c7c9a799fac22224c28fe9f25cc21aa7cc2b72bfc0b"}, + {file = "rignore-0.7.6-cp314-cp314-win32.whl", hash = "sha256:eeef421c1782953c4375aa32f06ecae470c1285c6381eee2a30d2e02a5633001"}, + {file = "rignore-0.7.6-cp314-cp314-win_amd64.whl", hash = "sha256:6aeed503b3b3d5af939b21d72a82521701a4bd3b89cd761da1e7dc78621af304"}, + {file = "rignore-0.7.6-cp314-cp314-win_arm64.whl", hash = "sha256:104f215b60b3c984c386c3e747d6ab4376d5656478694e22c7bd2f788ddd8304"}, + {file = "rignore-0.7.6-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:bb24a5b947656dd94cb9e41c4bc8b23cec0c435b58be0d74a874f63c259549e8"}, + {file = "rignore-0.7.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5b1e33c9501cefe24b70a1eafd9821acfd0ebf0b35c3a379430a14df089993e3"}, + {file = "rignore-0.7.6-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bec3994665a44454df86deb762061e05cd4b61e3772f5b07d1882a8a0d2748d5"}, + {file = "rignore-0.7.6-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26cba2edfe3cff1dfa72bddf65d316ddebf182f011f2f61538705d6dbaf54986"}, + {file = "rignore-0.7.6-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ffa86694fec604c613696cb91e43892aa22e1fec5f9870e48f111c603e5ec4e9"}, + {file = "rignore-0.7.6-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48efe2ed95aa8104145004afb15cdfa02bea5cdde8b0344afeb0434f0d989aa2"}, + {file = "rignore-0.7.6-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dcae43eb44b7f2457fef7cc87f103f9a0013017a6f4e62182c565e924948f21"}, + {file = "rignore-0.7.6-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2cd649a7091c0dad2f11ef65630d30c698d505cbe8660dd395268e7c099cc99f"}, + {file = "rignore-0.7.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42de84b0289d478d30ceb7ae59023f7b0527786a9a5b490830e080f0e4ea5aeb"}, + {file = "rignore-0.7.6-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:875a617e57b53b4acbc5a91de418233849711c02e29cc1f4f9febb2f928af013"}, + {file = "rignore-0.7.6-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:8703998902771e96e49968105207719f22926e4431b108450f3f430b4e268b7c"}, + {file = "rignore-0.7.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:602ef33f3e1b04c1e9a10a3c03f8bc3cef2d2383dcc250d309be42b49923cabc"}, + {file = "rignore-0.7.6-cp314-cp314t-win32.whl", hash = "sha256:c1d8f117f7da0a4a96a8daef3da75bc090e3792d30b8b12cfadc240c631353f9"}, + {file = "rignore-0.7.6-cp314-cp314t-win_amd64.whl", hash = "sha256:ca36e59408bec81de75d307c568c2d0d410fb880b1769be43611472c61e85c96"}, + {file = "rignore-0.7.6-cp314-cp314t-win_arm64.whl", hash = "sha256:b83adabeb3e8cf662cabe1931b83e165b88c526fa6af6b3aa90429686e474896"}, + {file = "rignore-0.7.6-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:1bd0bf3f4e57f3d50a91dd4eff6a22ddc9b999dbab2b20fb0473332a5551a0be"}, + {file = "rignore-0.7.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:afb5157cd217af4f47a13ad7cbfc35de0aa1740331ba662fa02fea94269d5894"}, + {file = "rignore-0.7.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca877c5a7b78fe74d97b34b735ea8f320f97c49083f7bf8fe9b61a02cf677e67"}, + {file = "rignore-0.7.6-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5fde2bdfd6b3afee19db5efe01e4165437329f9300441c1b25d5b2aa6752c0cc"}, + {file = "rignore-0.7.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ef2183285a49653517a100f28d8c1a3e037a5e8cefe79cffe205ecc4b98f5095"}, + {file = "rignore-0.7.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87554ae12f813d3a287a0f2aad957c11e5c4ace17bfed15d471e5be13e95d9fb"}, + {file = "rignore-0.7.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3111040f77ec6b543a501a194c48d5260898e618712472deb91bf48026f1606c"}, + {file = "rignore-0.7.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8dfa178ead3abeeaf6b8c4fe9c6c9b333d2d66c88735566f919169d18e728fa5"}, + {file = "rignore-0.7.6-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:112527b824eaa93c99c2c7eb11e7df83eab46a63d527bcd71a92151bba5d0435"}, + {file = "rignore-0.7.6-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:435c0c0f38f15d9bef2a97b039b5157bbc32791510670b89504e644de1d27a5e"}, + {file = "rignore-0.7.6-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:96e899cd34b422c2d3ad7bef279e16387f217d53ec5f9a25dbc3fcad19470381"}, + {file = "rignore-0.7.6-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:2ba1b9c80df4ea126ef303c7646021f44486342d43b7153f3454e15cd55eaa87"}, + {file = "rignore-0.7.6-cp38-cp38-win32.whl", hash = "sha256:1a1dffbfd930b27aef1962098710344297d52368b362f918eaf1464b0d8d052c"}, + {file = "rignore-0.7.6-cp38-cp38-win_amd64.whl", hash = "sha256:7f41cecc799005a029407893071b15082d504f9115a57db9ea893b35f3f70604"}, + {file = "rignore-0.7.6-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b3746bda73f2fe6a9c3ab2f20b792e7d810b30acbdba044313fbd2d0174802e7"}, + {file = "rignore-0.7.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:67a99cf19a5137cc12f14b78dc1bb3f48500f1d5580702c623297d5297bf2752"}, + {file = "rignore-0.7.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9e851cfa87033c0c3fd9d35dd8b102aff2981db8bc6e0cab27b460bfe38bf3f"}, + {file = "rignore-0.7.6-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e9b0def154665036516114437a5d603274e5451c0dc9694f622cc3b7e94603e7"}, + {file = "rignore-0.7.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b81274a47e8121224f7f637392b5dfcd9558e32a53e67ba7d04007d8b5281da9"}, + {file = "rignore-0.7.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d75d0b0696fb476664bea1169c8e67b13197750b91eceb4f10b3c7f379c7a204"}, + {file = "rignore-0.7.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ad3aa4dca77cef9168d0c142f72376f5bd27d1d4b8a81561bd01276d3ad9fe1"}, + {file = "rignore-0.7.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00f8a59e19d219f44a93af7173de197e0d0e61c386364da20ebe98a303cbe38c"}, + {file = "rignore-0.7.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dd6c682f3cdd741e7a30af2581f6a382ac910080977cd1f97c651467b6268352"}, + {file = "rignore-0.7.6-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:ae4e93193f75ebf6b820241594a78f347785cfd5a5fbbac94634052589418352"}, + {file = "rignore-0.7.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1163d8b5d3a320d4d7cc8635213328850dc41f60e438c7869d540061adf66c98"}, + {file = "rignore-0.7.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3e685f47b4c58b2df7dee81ebc1ec9dbb7f798b9455c3f22be6d75ac6bddee30"}, + {file = "rignore-0.7.6-cp39-cp39-win32.whl", hash = "sha256:2af6a0a76575220863cd838693c808a94e750640e0c8a3e9f707e93c2f131fdf"}, + {file = "rignore-0.7.6-cp39-cp39-win_amd64.whl", hash = "sha256:a326eab6db9ab85b4afb5e6eb28736a9f2b885a9246d9e8c1989bc693dd059a0"}, + {file = "rignore-0.7.6-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c3d3a523af1cd4ed2c0cba8d277a32d329b0c96ef9901fb7ca45c8cfaccf31a5"}, + {file = "rignore-0.7.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:990853566e65184a506e1e2af2d15045afad3ebaebb8859cb85b882081915110"}, + {file = "rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cab9ff2e436ce7240d7ee301c8ef806ed77c1fd6b8a8239ff65f9bbbcb5b8a3"}, + {file = "rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d1a6671b2082c13bfd9a5cf4ce64670f832a6d41470556112c4ab0b6519b2fc4"}, + {file = "rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2468729b4c5295c199d084ab88a40afcb7c8b974276805105239c07855bbacee"}, + {file = "rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:775710777fd71e5fdf54df69cdc249996a1d6f447a2b5bfb86dbf033fddd9cf9"}, + {file = "rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4565407f4a77f72cf9d91469e75d15d375f755f0a01236bb8aaa176278cc7085"}, + {file = "rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc44c33f8fb2d5c9da748de7a6e6653a78aa740655e7409895e94a247ffa97c8"}, + {file = "rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:8f32478f05540513c11923e8838afab9efef0131d66dca7f67f0e1bbd118af6a"}, + {file = "rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:1b63a3dd76225ea35b01dd6596aa90b275b5d0f71d6dc28fce6dd295d98614aa"}, + {file = "rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fe6c41175c36554a4ef0994cd1b4dbd6d73156fca779066456b781707402048e"}, + {file = "rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9a0c6792406ae36f4e7664dc772da909451d46432ff8485774526232d4885063"}, + {file = "rignore-0.7.6-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a20b6fb61bcced9a83dfcca6599ad45182b06ba720cff7c8d891e5b78db5b65f"}, + {file = "rignore-0.7.6-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:392dcabfecbe176c9ebbcb40d85a5e86a5989559c4f988c2741da7daf1b5be25"}, + {file = "rignore-0.7.6-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22baa462abdc36fdd5a5e2dae423107723351b85ff093762f9261148b9d0a04a"}, + {file = "rignore-0.7.6-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53fb28882d2538cb2d231972146c4927a9d9455e62b209f85d634408c4103538"}, + {file = "rignore-0.7.6-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:87409f7eeb1103d6b77f3472a3a0d9a5953e3ae804a55080bdcb0120ee43995b"}, + {file = "rignore-0.7.6-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:684014e42e4341ab3ea23a203551857fcc03a7f8ae96ca3aefb824663f55db32"}, + {file = "rignore-0.7.6-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77356ebb01ba13f8a425c3d30fcad40e57719c0e37670d022d560884a30e4767"}, + {file = "rignore-0.7.6-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6cbd8a48abbd3747a6c830393cd578782fab5d43f4deea48c5f5e344b8fed2b0"}, + {file = "rignore-0.7.6-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2673225dcec7f90497e79438c35e34638d0d0391ccea3cbb79bfb9adc0dc5bd7"}, + {file = "rignore-0.7.6-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:c081f17290d8a2b96052b79207622aa635686ea39d502b976836384ede3d303c"}, + {file = "rignore-0.7.6-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:57e8327aacc27f921968cb2a174f9e47b084ce9a7dd0122c8132d22358f6bd79"}, + {file = "rignore-0.7.6-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:d8955b57e42f2a5434670d5aa7b75eaf6e74602ccd8955dddf7045379cd762fb"}, + {file = "rignore-0.7.6-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e6ba1511c0ab8cd1ed8d6055bb0a6e629f48bfe04854293e0cd2dd88bd7153f8"}, + {file = "rignore-0.7.6-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:50586d90be15f9aa8a2e2ee5a042ee6c51e28848812a35f0c95d4bfc0533d469"}, + {file = "rignore-0.7.6-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b129873dd0ade248e67f25a09b5b72288cbef76ba1a9aae6bac193ee1d8be72"}, + {file = "rignore-0.7.6-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d9d6dd947556ddebfd62753005104986ee14a4e0663818aed19cdf2c33a6b5d5"}, + {file = "rignore-0.7.6-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91b95faa532efba888b196331e9af69e693635d469185ac52c796e435e2484e5"}, + {file = "rignore-0.7.6-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a1016f430fb56f7e400838bbc56fdf43adddb6fcb7bf2a14731dfd725c2fae6c"}, + {file = "rignore-0.7.6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f00c519861926dc703ecbb7bbeb884be67099f96f98b175671fa0a54718f55d1"}, + {file = "rignore-0.7.6-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e34d172bf50e881b7c02e530ae8b1ea96093f0b16634c344f637227b39707b41"}, + {file = "rignore-0.7.6-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:101d3143619898db1e7bede2e3e647daf19bb867c4fb25978016d67978d14868"}, + {file = "rignore-0.7.6-pp39-pypy39_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:c9f3b420f54199a2b2b3b532d8c7e0860be3fa51f67501113cca6c7bfc392840"}, + {file = "rignore-0.7.6-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:1c6795e3694d750ae5ef172eab7d68a52aefbd9168d2e06647df691db2b03a50"}, + {file = "rignore-0.7.6-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:750a83a254b020e1193bfa7219dc7edca26bd8888a94cdc59720cbe386ab0c72"}, + {file = "rignore-0.7.6.tar.gz", hash = "sha256:00d3546cd793c30cb17921ce674d2c8f3a4b00501cb0e3dd0e82217dbeba2671"}, +] + [[package]] name = "rlp" version = "4.1.0" @@ -4012,198 +5056,192 @@ docs = ["sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme rust-backend = ["rusty-rlp (>=0.2.1)"] test = ["hypothesis (>=6.22.0,<6.108.7)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] -[[package]] -name = "rsa" -version = "4.9" -description = "Pure-Python RSA implementation" -optional = false -python-versions = ">=3.6,<4" -files = [ - {file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"}, - {file = "rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"}, -] - -[package.dependencies] -pyasn1 = ">=0.1.3" - [[package]] name = "ruamel-yaml" -version = "0.18.5" +version = "0.19.1" description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "ruamel.yaml-0.18.5-py3-none-any.whl", hash = "sha256:a013ac02f99a69cdd6277d9664689eb1acba07069f912823177c5eced21a6ada"}, - {file = "ruamel.yaml-0.18.5.tar.gz", hash = "sha256:61917e3a35a569c1133a8f772e1226961bf5a1198bea7e23f06a0841dea1ab0e"}, + {file = "ruamel_yaml-0.19.1-py3-none-any.whl", hash = "sha256:27592957fedf6e0b62f281e96effd28043345e0e66001f97683aa9a40c667c93"}, + {file = "ruamel_yaml-0.19.1.tar.gz", hash = "sha256:53eb66cd27849eff968ebf8f0bf61f46cdac2da1d1f3576dd4ccee9b25c31993"}, ] -[package.dependencies] -"ruamel.yaml.clib" = {version = ">=0.2.7", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.13\""} - [package.extras] docs = ["mercurial (>5.7)", "ryd"] jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] - -[[package]] -name = "ruamel-yaml-clib" -version = "0.2.8" -description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" -optional = false -python-versions = ">=3.6" -files = [ - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win_amd64.whl", hash = "sha256:1758ce7d8e1a29d23de54a16ae867abd370f01b5a69e1a3ba75223eaa3ca1a1b"}, - {file = "ruamel.yaml.clib-0.2.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:77159f5d5b5c14f7c34073862a6b7d34944075d9f93e681638f6d753606c6ce6"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win32.whl", hash = "sha256:75e1ed13e1f9de23c5607fe6bd1aeaae21e523b32d83bb33918245361e9cc51b"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win_amd64.whl", hash = "sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win32.whl", hash = "sha256:955eae71ac26c1ab35924203fda6220f84dce57d6d7884f189743e2abe3a9fbe"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win_amd64.whl", hash = "sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win32.whl", hash = "sha256:84b554931e932c46f94ab306913ad7e11bba988104c5cff26d90d03f68258cd5"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win_amd64.whl", hash = "sha256:25ac8c08322002b06fa1d49d1646181f0b2c72f5cbc15a85e80b4c30a544bb15"}, - {file = "ruamel.yaml.clib-0.2.8.tar.gz", hash = "sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512"}, -] +libyaml = ["ruamel.yaml.clibz (>=0.3.7)"] +oldlibyaml = ["ruamel.yaml.clib"] [[package]] name = "ruff" -version = "0.6.0" +version = "0.15.22" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.6.0-py3-none-linux_armv6l.whl", hash = "sha256:92dcce923e5df265781e5fc76f9a1edad52201a7aafe56e586b90988d5239013"}, - {file = "ruff-0.6.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:31b90ff9dc79ed476c04e957ba7e2b95c3fceb76148f2079d0d68a908d2cfae7"}, - {file = "ruff-0.6.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:6d834a9ec9f8287dd6c3297058b3a265ed6b59233db22593379ee38ebc4b9768"}, - {file = "ruff-0.6.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2089267692696aba342179471831a085043f218706e642564812145df8b8d0d"}, - {file = "ruff-0.6.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aa62b423ee4bbd8765f2c1dbe8f6aac203e0583993a91453dc0a449d465c84da"}, - {file = "ruff-0.6.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7344e1a964b16b1137ea361d6516ce4ee61a0403fa94252a1913ecc1311adcae"}, - {file = "ruff-0.6.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:487f3a35c3f33bf82be212ce15dc6278ea854e35573a3f809442f73bec8b2760"}, - {file = "ruff-0.6.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:75db409984077a793cf344d499165298a6f65449e905747ac65983b12e3e64b1"}, - {file = "ruff-0.6.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84908bd603533ecf1db456d8fc2665d1f4335d722e84bc871d3bbd2d1116c272"}, - {file = "ruff-0.6.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f1749a0aef3ec41ed91a0e2127a6ae97d2e2853af16dbd4f3c00d7a3af726c5"}, - {file = "ruff-0.6.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:016fea751e2bcfbbd2f8cb19b97b37b3fd33148e4df45b526e87096f4e17354f"}, - {file = "ruff-0.6.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:6ae80f141b53b2e36e230017e64f5ea2def18fac14334ffceaae1b780d70c4f7"}, - {file = "ruff-0.6.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:eaaaf33ea4b3f63fd264d6a6f4a73fa224bbfda4b438ffea59a5340f4afa2bb5"}, - {file = "ruff-0.6.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7667ddd1fc688150a7ca4137140867584c63309695a30016880caf20831503a0"}, - {file = "ruff-0.6.0-py3-none-win32.whl", hash = "sha256:ae48365aae60d40865a412356f8c6f2c0be1c928591168111eaf07eaefa6bea3"}, - {file = "ruff-0.6.0-py3-none-win_amd64.whl", hash = "sha256:774032b507c96f0c803c8237ce7d2ef3934df208a09c40fa809c2931f957fe5e"}, - {file = "ruff-0.6.0-py3-none-win_arm64.whl", hash = "sha256:a5366e8c3ae6b2dc32821749b532606c42e609a99b0ae1472cf601da931a048c"}, - {file = "ruff-0.6.0.tar.gz", hash = "sha256:272a81830f68f9bd19d49eaf7fa01a5545c5a2e86f32a9935bb0e4bb9a1db5b8"}, + {file = "ruff-0.15.22-py3-none-linux_armv6l.whl", hash = "sha256:44423e73493737f5e7c5b41d475483898ff37afcdae38bc3da5085e29af1c2d8"}, + {file = "ruff-0.15.22-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b82c6482946e9eda7ff2e091d25b8bad3f718684e1916d41bd56873cee05b697"}, + {file = "ruff-0.15.22-py3-none-macosx_11_0_arm64.whl", hash = "sha256:11c1c715af53a09f714e011106bffc419751ec8232fcb5da42173284ea3fec6f"}, + {file = "ruff-0.15.22-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:742a29cf29bddb7c8327895d6a10e0e6c5b38a96dd407af9b5d0857f809c0576"}, + {file = "ruff-0.15.22-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72af58b951b0ae395935ae79763dc349bc0eb706319d28f7a33ad2cfb3cfc178"}, + {file = "ruff-0.15.22-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62d425005c1835eb24e2ee4161cb90e8db263415f4a71c8c72c33abaa6c0c224"}, + {file = "ruff-0.15.22-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8b9b3f8779a4f08c969defc3c8c35abffaa757e601ed5ae66d6d1db6519969a"}, + {file = "ruff-0.15.22-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e0dd1b2e4d3d585f897a0d137cbf4eaf6223bef4e8ce34d6bb12556c5f9249e"}, + {file = "ruff-0.15.22-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:365523eb91d9224e1bcb03b022fbf0facb8f9e23792a2c53d9d4b3924bdbdebb"}, + {file = "ruff-0.15.22-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:fabfd168afdf29fee5be98b831efa9683c94d7c5a3b58b9ce5a2e38444589a74"}, + {file = "ruff-0.15.22-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:225dbf095a87f1d9f90f5fd7924d2613ee452a75a4308c63a8f50f761787aa7c"}, + {file = "ruff-0.15.22-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1877d63b9d24ed278744f1523fd11b85540566d54641f97c566d7d9dc5ca5296"}, + {file = "ruff-0.15.22-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a1606c510bd7215680d32efab38965f7cdec3ef69f5170a3f4791404ffdd5262"}, + {file = "ruff-0.15.22-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:630479b18625f5ffc373f77603a22a9f8ac0acd7ff0501178b5db28ec71e9c64"}, + {file = "ruff-0.15.22-py3-none-win32.whl", hash = "sha256:e5ba0e4a13fd14abbed2a77b517a3911290c6c6c59ef67784328d1668fab76cf"}, + {file = "ruff-0.15.22-py3-none-win_amd64.whl", hash = "sha256:9be63ba1eb936acd2d1342fb8337c356353706fce233b2a15a09a97037e6acde"}, + {file = "ruff-0.15.22-py3-none-win_arm64.whl", hash = "sha256:e1168075b72158510839f250027659cdd78476f40507dd517892304c41318661"}, + {file = "ruff-0.15.22.tar.gz", hash = "sha256:3f15175b1fb580126f58285a5dae6b2ea89000136d980c64499211f116b54809"}, ] [[package]] name = "s3transfer" -version = "0.10.0" +version = "0.19.1" description = "An Amazon S3 Transfer Manager" optional = false -python-versions = ">= 3.8" +python-versions = ">=3.10" files = [ - {file = "s3transfer-0.10.0-py3-none-any.whl", hash = "sha256:3cdb40f5cfa6966e812209d0994f2a4709b561c88e90cf00c2696d2df4e56b2e"}, - {file = "s3transfer-0.10.0.tar.gz", hash = "sha256:d0c8bbf672d5eebbe4e57945e23b972d963f07d82f661cabf678a5c88831595b"}, + {file = "s3transfer-0.19.1-py3-none-any.whl", hash = "sha256:d5fd7005ee39307455ad5f310b5ea67f4b1960d7fed5b3671ee50c249de675de"}, + {file = "s3transfer-0.19.1.tar.gz", hash = "sha256:d3d6371dc3f1e5c5427b2b457bcf13bcf87bec334c95aed18642eae61f6926f3"}, ] [package.dependencies] -botocore = ">=1.33.2,<2.0a.0" +botocore = ">=1.37.4,<2.0a.0" [package.extras] -crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"] +crt = ["botocore[crt] (>=1.37.4,<2.0a.0)"] [[package]] name = "scipy" -version = "1.12.0" +version = "1.15.3" description = "Fundamental algorithms for scientific computing in Python" optional = false -python-versions = ">=3.9" -files = [ - {file = "scipy-1.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:78e4402e140879387187f7f25d91cc592b3501a2e51dfb320f48dfb73565f10b"}, - {file = "scipy-1.12.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:f5f00ebaf8de24d14b8449981a2842d404152774c1a1d880c901bf454cb8e2a1"}, - {file = "scipy-1.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e53958531a7c695ff66c2e7bb7b79560ffdc562e2051644c5576c39ff8efb563"}, - {file = "scipy-1.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e32847e08da8d895ce09d108a494d9eb78974cf6de23063f93306a3e419960c"}, - {file = "scipy-1.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4c1020cad92772bf44b8e4cdabc1df5d87376cb219742549ef69fc9fd86282dd"}, - {file = "scipy-1.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:75ea2a144096b5e39402e2ff53a36fecfd3b960d786b7efd3c180e29c39e53f2"}, - {file = "scipy-1.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:408c68423f9de16cb9e602528be4ce0d6312b05001f3de61fe9ec8b1263cad08"}, - {file = "scipy-1.12.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:5adfad5dbf0163397beb4aca679187d24aec085343755fcdbdeb32b3679f254c"}, - {file = "scipy-1.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3003652496f6e7c387b1cf63f4bb720951cfa18907e998ea551e6de51a04467"}, - {file = "scipy-1.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b8066bce124ee5531d12a74b617d9ac0ea59245246410e19bca549656d9a40a"}, - {file = "scipy-1.12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8bee4993817e204d761dba10dbab0774ba5a8612e57e81319ea04d84945375ba"}, - {file = "scipy-1.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:a24024d45ce9a675c1fb8494e8e5244efea1c7a09c60beb1eeb80373d0fecc70"}, - {file = "scipy-1.12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e7e76cc48638228212c747ada851ef355c2bb5e7f939e10952bc504c11f4e372"}, - {file = "scipy-1.12.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:f7ce148dffcd64ade37b2df9315541f9adad6efcaa86866ee7dd5db0c8f041c3"}, - {file = "scipy-1.12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c39f92041f490422924dfdb782527a4abddf4707616e07b021de33467f917bc"}, - {file = "scipy-1.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7ebda398f86e56178c2fa94cad15bf457a218a54a35c2a7b4490b9f9cb2676c"}, - {file = "scipy-1.12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:95e5c750d55cf518c398a8240571b0e0782c2d5a703250872f36eaf737751338"}, - {file = "scipy-1.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:e646d8571804a304e1da01040d21577685ce8e2db08ac58e543eaca063453e1c"}, - {file = "scipy-1.12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:913d6e7956c3a671de3b05ccb66b11bc293f56bfdef040583a7221d9e22a2e35"}, - {file = "scipy-1.12.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba1b0c7256ad75401c73e4b3cf09d1f176e9bd4248f0d3112170fb2ec4db067"}, - {file = "scipy-1.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:730badef9b827b368f351eacae2e82da414e13cf8bd5051b4bdfd720271a5371"}, - {file = "scipy-1.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6546dc2c11a9df6926afcbdd8a3edec28566e4e785b915e849348c6dd9f3f490"}, - {file = "scipy-1.12.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:196ebad3a4882081f62a5bf4aeb7326aa34b110e533aab23e4374fcccb0890dc"}, - {file = "scipy-1.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:b360f1b6b2f742781299514e99ff560d1fe9bd1bff2712894b52abe528d1fd1e"}, - {file = "scipy-1.12.0.tar.gz", hash = "sha256:4bf5abab8a36d20193c698b0f1fc282c1d083c94723902c447e5d2f1780936a3"}, +python-versions = ">=3.10" +files = [ + {file = "scipy-1.15.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a345928c86d535060c9c2b25e71e87c39ab2f22fc96e9636bd74d1dbf9de448c"}, + {file = "scipy-1.15.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ad3432cb0f9ed87477a8d97f03b763fd1d57709f1bbde3c9369b1dff5503b253"}, + {file = "scipy-1.15.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:aef683a9ae6eb00728a542b796f52a5477b78252edede72b8327a886ab63293f"}, + {file = "scipy-1.15.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:1c832e1bd78dea67d5c16f786681b28dd695a8cb1fb90af2e27580d3d0967e92"}, + {file = "scipy-1.15.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:263961f658ce2165bbd7b99fa5135195c3a12d9bef045345016b8b50c315cb82"}, + {file = "scipy-1.15.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2abc762b0811e09a0d3258abee2d98e0c703eee49464ce0069590846f31d40"}, + {file = "scipy-1.15.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ed7284b21a7a0c8f1b6e5977ac05396c0d008b89e05498c8b7e8f4a1423bba0e"}, + {file = "scipy-1.15.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5380741e53df2c566f4d234b100a484b420af85deb39ea35a1cc1be84ff53a5c"}, + {file = "scipy-1.15.3-cp310-cp310-win_amd64.whl", hash = "sha256:9d61e97b186a57350f6d6fd72640f9e99d5a4a2b8fbf4b9ee9a841eab327dc13"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:993439ce220d25e3696d1b23b233dd010169b62f6456488567e830654ee37a6b"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:34716e281f181a02341ddeaad584205bd2fd3c242063bd3423d61ac259ca7eba"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3b0334816afb8b91dab859281b1b9786934392aa3d527cd847e41bb6f45bee65"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:6db907c7368e3092e24919b5e31c76998b0ce1684d51a90943cb0ed1b4ffd6c1"}, + {file = "scipy-1.15.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:721d6b4ef5dc82ca8968c25b111e307083d7ca9091bc38163fb89243e85e3889"}, + {file = "scipy-1.15.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39cb9c62e471b1bb3750066ecc3a3f3052b37751c7c3dfd0fd7e48900ed52982"}, + {file = "scipy-1.15.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:795c46999bae845966368a3c013e0e00947932d68e235702b5c3f6ea799aa8c9"}, + {file = "scipy-1.15.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:18aaacb735ab38b38db42cb01f6b92a2d0d4b6aabefeb07f02849e47f8fb3594"}, + {file = "scipy-1.15.3-cp311-cp311-win_amd64.whl", hash = "sha256:ae48a786a28412d744c62fd7816a4118ef97e5be0bee968ce8f0a2fba7acf3bb"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6ac6310fdbfb7aa6612408bd2f07295bcbd3fda00d2d702178434751fe48e019"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:185cd3d6d05ca4b44a8f1595af87f9c372bb6acf9c808e99aa3e9aa03bd98cf6"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:05dc6abcd105e1a29f95eada46d4a3f251743cfd7d3ae8ddb4088047f24ea477"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:06efcba926324df1696931a57a176c80848ccd67ce6ad020c810736bfd58eb1c"}, + {file = "scipy-1.15.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05045d8b9bfd807ee1b9f38761993297b10b245f012b11b13b91ba8945f7e45"}, + {file = "scipy-1.15.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271e3713e645149ea5ea3e97b57fdab61ce61333f97cfae392c28ba786f9bb49"}, + {file = "scipy-1.15.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6cfd56fc1a8e53f6e89ba3a7a7251f7396412d655bca2aa5611c8ec9a6784a1e"}, + {file = "scipy-1.15.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ff17c0bb1cb32952c09217d8d1eed9b53d1463e5f1dd6052c7857f83127d539"}, + {file = "scipy-1.15.3-cp312-cp312-win_amd64.whl", hash = "sha256:52092bc0472cfd17df49ff17e70624345efece4e1a12b23783a1ac59a1b728ed"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c620736bcc334782e24d173c0fdbb7590a0a436d2fdf39310a8902505008759"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:7e11270a000969409d37ed399585ee530b9ef6aa99d50c019de4cb01e8e54e62"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8c9ed3ba2c8a2ce098163a9bdb26f891746d02136995df25227a20e71c396ebb"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0bdd905264c0c9cfa74a4772cdb2070171790381a5c4d312c973382fc6eaf730"}, + {file = "scipy-1.15.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79167bba085c31f38603e11a267d862957cbb3ce018d8b38f79ac043bc92d825"}, + {file = "scipy-1.15.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9deabd6d547aee2c9a81dee6cc96c6d7e9a9b1953f74850c179f91fdc729cb7"}, + {file = "scipy-1.15.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dde4fc32993071ac0c7dd2d82569e544f0bdaff66269cb475e0f369adad13f11"}, + {file = "scipy-1.15.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f77f853d584e72e874d87357ad70f44b437331507d1c311457bed8ed2b956126"}, + {file = "scipy-1.15.3-cp313-cp313-win_amd64.whl", hash = "sha256:b90ab29d0c37ec9bf55424c064312930ca5f4bde15ee8619ee44e69319aab163"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3ac07623267feb3ae308487c260ac684b32ea35fd81e12845039952f558047b8"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6487aa99c2a3d509a5227d9a5e889ff05830a06b2ce08ec30df6d79db5fcd5c5"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:50f9e62461c95d933d5c5ef4a1f2ebf9a2b4e83b0db374cb3f1de104d935922e"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:14ed70039d182f411ffc74789a16df3835e05dc469b898233a245cdfd7f162cb"}, + {file = "scipy-1.15.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a769105537aa07a69468a0eefcd121be52006db61cdd8cac8a0e68980bbb723"}, + {file = "scipy-1.15.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db984639887e3dffb3928d118145ffe40eff2fa40cb241a306ec57c219ebbbb"}, + {file = "scipy-1.15.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:40e54d5c7e7ebf1aa596c374c49fa3135f04648a0caabcb66c52884b943f02b4"}, + {file = "scipy-1.15.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5e721fed53187e71d0ccf382b6bf977644c533e506c4d33c3fb24de89f5c3ed5"}, + {file = "scipy-1.15.3-cp313-cp313t-win_amd64.whl", hash = "sha256:76ad1fb5f8752eabf0fa02e4cc0336b4e8f021e2d5f061ed37d6d264db35e3ca"}, + {file = "scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf"}, ] [package.dependencies] -numpy = ">=1.22.4,<1.29.0" +numpy = ">=1.23.5,<2.5" [package.extras] -dev = ["click", "cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy", "pycodestyle", "pydevtool", "rich-click", "ruff", "types-psutil", "typing_extensions"] -doc = ["jupytext", "matplotlib (>2)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (==0.9.0)", "sphinx (!=4.1.0)", "sphinx-design (>=0.2.0)"] -test = ["asv", "gmpy2", "hypothesis", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] +dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy (==1.10.0)", "pycodestyle", "pydevtool", "rich-click", "ruff (>=0.0.292)", "types-psutil", "typing_extensions"] +doc = ["intersphinx_registry", "jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.19.1)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0,<8.0.0)", "sphinx-copybutton", "sphinx-design (>=0.4.0)"] +test = ["Cython", "array-api-strict (>=2.0,<2.1.1)", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] [[package]] -name = "setuptools" -version = "69.0.3" -description = "Easily download, build, install, upgrade, and uninstall Python packages" +name = "sentry-sdk" +version = "2.66.0" +description = "Python client for Sentry (https://sentry.io)" optional = false -python-versions = ">=3.8" +python-versions = ">=3.6" files = [ - {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"}, - {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"}, + {file = "sentry_sdk-2.66.0-py3-none-any.whl", hash = "sha256:096136c214c602be2b323524d30755dc5b30ec5a218a206207f33b12c05c6f11"}, + {file = "sentry_sdk-2.66.0.tar.gz", hash = "sha256:9727d35aa83c56cd53294676fe65b96296a334c9ce107fa2142bd70f47acb265"}, ] +[package.dependencies] +certifi = "*" +urllib3 = ">=1.26.11" + [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +aiohttp = ["aiohttp (>=3.5)"] +anthropic = ["anthropic (>=0.16)"] +arq = ["arq (>=0.23)"] +asyncio = ["httpcore[asyncio] (==1.*)"] +asyncpg = ["asyncpg (>=0.23)"] +beam = ["apache-beam (>=2.12)"] +bottle = ["bottle (>=0.12.13)"] +celery = ["celery (>=3)"] +celery-redbeat = ["celery-redbeat (>=2)"] +chalice = ["chalice (>=1.16.0)"] +clickhouse-driver = ["clickhouse-driver (>=0.2.0)"] +django = ["django (>=1.8)"] +falcon = ["falcon (>=1.4)"] +fastapi = ["fastapi (>=0.79.0)"] +flask = ["blinker (>=1.1)", "flask (>=0.11)", "markupsafe"] +google-genai = ["google-genai (>=1.29.0)"] +grpcio = ["grpcio (>=1.21.1)", "protobuf (>=3.8.0)"] +http2 = ["httpcore[http2] (==1.*)"] +httpx = ["httpx (>=0.16.0)"] +huey = ["huey (>=2)"] +huggingface-hub = ["huggingface_hub (>=0.22)"] +langchain = ["langchain (>=0.0.210)"] +langgraph = ["langgraph (>=0.6.6)"] +launchdarkly = ["launchdarkly-server-sdk (>=9.8.0)"] +litellm = ["litellm (>=1.77.5,!=1.82.7,!=1.82.8)"] +litestar = ["litestar (>=2.0.0)"] +loguru = ["loguru (>=0.5)"] +mcp = ["mcp (>=1.15.0)"] +openai = ["openai (>=1.0.0)", "tiktoken (>=0.3.0)"] +openfeature = ["openfeature-sdk (>=0.7.1)"] +opentelemetry = ["opentelemetry-distro (>=0.35b0)"] +opentelemetry-experimental = ["opentelemetry-distro"] +opentelemetry-otlp = ["opentelemetry-distro[otlp] (>=0.35b0)"] +pure-eval = ["asttokens", "executing", "pure_eval"] +pydantic-ai = ["pydantic-ai (>=1.0.0)"] +pymongo = ["pymongo (>=3.1)"] +pyspark = ["pyspark (>=2.4.4)"] +quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] +rq = ["rq (>=0.6)"] +sanic = ["sanic (>=0.8)"] +sqlalchemy = ["sqlalchemy (>=1.2)"] +starlette = ["starlette (>=0.19.1)"] +starlite = ["starlite (>=1.48)"] +statsig = ["statsig (>=0.55.3)"] +tornado = ["tornado (>=6)"] +unleash = ["UnleashClient (>=6.0.1)"] [[package]] name = "shellingham" @@ -4218,95 +5256,93 @@ files = [ [[package]] name = "six" -version = "1.16.0" +version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] - -[[package]] -name = "sniffio" -version = "1.3.0" -description = "Sniff out which async library your code is running under" -optional = false -python-versions = ">=3.7" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, - {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] [[package]] name = "sqlalchemy" -version = "2.0.25" +version = "2.0.51" description = "Database Abstraction Library" optional = false python-versions = ">=3.7" files = [ - {file = "SQLAlchemy-2.0.25-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4344d059265cc8b1b1be351bfb88749294b87a8b2bbe21dfbe066c4199541ebd"}, - {file = "SQLAlchemy-2.0.25-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6f9e2e59cbcc6ba1488404aad43de005d05ca56e069477b33ff74e91b6319735"}, - {file = "SQLAlchemy-2.0.25-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84daa0a2055df9ca0f148a64fdde12ac635e30edbca80e87df9b3aaf419e144a"}, - {file = "SQLAlchemy-2.0.25-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc8b7dabe8e67c4832891a5d322cec6d44ef02f432b4588390017f5cec186a84"}, - {file = "SQLAlchemy-2.0.25-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f5693145220517b5f42393e07a6898acdfe820e136c98663b971906120549da5"}, - {file = "SQLAlchemy-2.0.25-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:db854730a25db7c956423bb9fb4bdd1216c839a689bf9cc15fada0a7fb2f4570"}, - {file = "SQLAlchemy-2.0.25-cp310-cp310-win32.whl", hash = "sha256:14a6f68e8fc96e5e8f5647ef6cda6250c780612a573d99e4d881581432ef1669"}, - {file = "SQLAlchemy-2.0.25-cp310-cp310-win_amd64.whl", hash = "sha256:87f6e732bccd7dcf1741c00f1ecf33797383128bd1c90144ac8adc02cbb98643"}, - {file = "SQLAlchemy-2.0.25-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:342d365988ba88ada8af320d43df4e0b13a694dbd75951f537b2d5e4cb5cd002"}, - {file = "SQLAlchemy-2.0.25-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f37c0caf14b9e9b9e8f6dbc81bc56db06acb4363eba5a633167781a48ef036ed"}, - {file = "SQLAlchemy-2.0.25-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa9373708763ef46782d10e950b49d0235bfe58facebd76917d3f5cbf5971aed"}, - {file = "SQLAlchemy-2.0.25-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d24f571990c05f6b36a396218f251f3e0dda916e0c687ef6fdca5072743208f5"}, - {file = "SQLAlchemy-2.0.25-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75432b5b14dc2fff43c50435e248b45c7cdadef73388e5610852b95280ffd0e9"}, - {file = "SQLAlchemy-2.0.25-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:884272dcd3ad97f47702965a0e902b540541890f468d24bd1d98bcfe41c3f018"}, - {file = "SQLAlchemy-2.0.25-cp311-cp311-win32.whl", hash = "sha256:e607cdd99cbf9bb80391f54446b86e16eea6ad309361942bf88318bcd452363c"}, - {file = "SQLAlchemy-2.0.25-cp311-cp311-win_amd64.whl", hash = "sha256:7d505815ac340568fd03f719446a589162d55c52f08abd77ba8964fbb7eb5b5f"}, - {file = "SQLAlchemy-2.0.25-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0dacf67aee53b16f365c589ce72e766efaabd2b145f9de7c917777b575e3659d"}, - {file = "SQLAlchemy-2.0.25-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b801154027107461ee992ff4b5c09aa7cc6ec91ddfe50d02bca344918c3265c6"}, - {file = "SQLAlchemy-2.0.25-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59a21853f5daeb50412d459cfb13cb82c089ad4c04ec208cd14dddd99fc23b39"}, - {file = "SQLAlchemy-2.0.25-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29049e2c299b5ace92cbed0c1610a7a236f3baf4c6b66eb9547c01179f638ec5"}, - {file = "SQLAlchemy-2.0.25-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b64b183d610b424a160b0d4d880995e935208fc043d0302dd29fee32d1ee3f95"}, - {file = "SQLAlchemy-2.0.25-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4f7a7d7fcc675d3d85fbf3b3828ecd5990b8d61bd6de3f1b260080b3beccf215"}, - {file = "SQLAlchemy-2.0.25-cp312-cp312-win32.whl", hash = "sha256:cf18ff7fc9941b8fc23437cc3e68ed4ebeff3599eec6ef5eebf305f3d2e9a7c2"}, - {file = "SQLAlchemy-2.0.25-cp312-cp312-win_amd64.whl", hash = "sha256:91f7d9d1c4dd1f4f6e092874c128c11165eafcf7c963128f79e28f8445de82d5"}, - {file = "SQLAlchemy-2.0.25-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bb209a73b8307f8fe4fe46f6ad5979649be01607f11af1eb94aa9e8a3aaf77f0"}, - {file = "SQLAlchemy-2.0.25-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:798f717ae7c806d67145f6ae94dc7c342d3222d3b9a311a784f371a4333212c7"}, - {file = "SQLAlchemy-2.0.25-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fdd402169aa00df3142149940b3bf9ce7dde075928c1886d9a1df63d4b8de62"}, - {file = "SQLAlchemy-2.0.25-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0d3cab3076af2e4aa5693f89622bef7fa770c6fec967143e4da7508b3dceb9b9"}, - {file = "SQLAlchemy-2.0.25-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:74b080c897563f81062b74e44f5a72fa44c2b373741a9ade701d5f789a10ba23"}, - {file = "SQLAlchemy-2.0.25-cp37-cp37m-win32.whl", hash = "sha256:87d91043ea0dc65ee583026cb18e1b458d8ec5fc0a93637126b5fc0bc3ea68c4"}, - {file = "SQLAlchemy-2.0.25-cp37-cp37m-win_amd64.whl", hash = "sha256:75f99202324383d613ddd1f7455ac908dca9c2dd729ec8584c9541dd41822a2c"}, - {file = "SQLAlchemy-2.0.25-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:420362338681eec03f53467804541a854617faed7272fe71a1bfdb07336a381e"}, - {file = "SQLAlchemy-2.0.25-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c88f0c7dcc5f99bdb34b4fd9b69b93c89f893f454f40219fe923a3a2fd11625"}, - {file = "SQLAlchemy-2.0.25-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3be4987e3ee9d9a380b66393b77a4cd6d742480c951a1c56a23c335caca4ce3"}, - {file = "SQLAlchemy-2.0.25-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a159111a0f58fb034c93eeba211b4141137ec4b0a6e75789ab7a3ef3c7e7e3"}, - {file = "SQLAlchemy-2.0.25-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8b8cb63d3ea63b29074dcd29da4dc6a97ad1349151f2d2949495418fd6e48db9"}, - {file = "SQLAlchemy-2.0.25-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:736ea78cd06de6c21ecba7416499e7236a22374561493b456a1f7ffbe3f6cdb4"}, - {file = "SQLAlchemy-2.0.25-cp38-cp38-win32.whl", hash = "sha256:10331f129982a19df4284ceac6fe87353ca3ca6b4ca77ff7d697209ae0a5915e"}, - {file = "SQLAlchemy-2.0.25-cp38-cp38-win_amd64.whl", hash = "sha256:c55731c116806836a5d678a70c84cb13f2cedba920212ba7dcad53260997666d"}, - {file = "SQLAlchemy-2.0.25-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:605b6b059f4b57b277f75ace81cc5bc6335efcbcc4ccb9066695e515dbdb3900"}, - {file = "SQLAlchemy-2.0.25-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:665f0a3954635b5b777a55111ababf44b4fc12b1f3ba0a435b602b6387ffd7cf"}, - {file = "SQLAlchemy-2.0.25-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecf6d4cda1f9f6cb0b45803a01ea7f034e2f1aed9475e883410812d9f9e3cfcf"}, - {file = "SQLAlchemy-2.0.25-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c51db269513917394faec5e5c00d6f83829742ba62e2ac4fa5c98d58be91662f"}, - {file = "SQLAlchemy-2.0.25-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:790f533fa5c8901a62b6fef5811d48980adeb2f51f1290ade8b5e7ba990ba3de"}, - {file = "SQLAlchemy-2.0.25-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1b1180cda6df7af84fe72e4530f192231b1f29a7496951db4ff38dac1687202d"}, - {file = "SQLAlchemy-2.0.25-cp39-cp39-win32.whl", hash = "sha256:555651adbb503ac7f4cb35834c5e4ae0819aab2cd24857a123370764dc7d7e24"}, - {file = "SQLAlchemy-2.0.25-cp39-cp39-win_amd64.whl", hash = "sha256:dc55990143cbd853a5d038c05e79284baedf3e299661389654551bd02a6a68d7"}, - {file = "SQLAlchemy-2.0.25-py3-none-any.whl", hash = "sha256:a86b4240e67d4753dc3092d9511886795b3c2852abe599cffe108952f7af7ac3"}, - {file = "SQLAlchemy-2.0.25.tar.gz", hash = "sha256:a2c69a7664fb2d54b8682dd774c3b54f67f84fa123cf84dda2a5f40dcaa04e08"}, + {file = "sqlalchemy-2.0.51-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e8203d2fbd5c6254692ef0a72c740d75b2f3c7ca345404f4c1a4604813c77c0"}, + {file = "sqlalchemy-2.0.51-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1af05726b3d0cdba1c55284bf408fd3b792e690fe2399bfb8304565551cda652"}, + {file = "sqlalchemy-2.0.51-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e54ff2dd657f2e3e0fbf2b097db1182f7bfea263eca4353f00065bae2a67c3d"}, + {file = "sqlalchemy-2.0.51-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:1e47b1199c2e832e325eacabc8d32d2487f58c9358f97e9a00f5eb93c5680d84"}, + {file = "sqlalchemy-2.0.51-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c68568f3facf8f66fa76c60e0ced69b67666ffa9941d1d0a3756fda196049080"}, + {file = "sqlalchemy-2.0.51-cp310-cp310-win32.whl", hash = "sha256:0592bdadf86ddcabfd72d9ab66ea8a5d8d2cc6be1cc51fa7e66c03868ac5eac1"}, + {file = "sqlalchemy-2.0.51-cp310-cp310-win_amd64.whl", hash = "sha256:740cf6f35351b1ac3d82369152acf1d51d37e3dcf85d4dc0a22ca01410eabe2a"}, + {file = "sqlalchemy-2.0.51-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1aa10c0daee6705294d181daadaa793221e1a59ed55000a3fab1d42b088ce4ba"}, + {file = "sqlalchemy-2.0.51-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a5b2ed6d828f1f09bd812861f4f59ca3bc3803f9df871f4555187f0faf018604"}, + {file = "sqlalchemy-2.0.51-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:436728ce18a80f6951a1e11cc6112c2ede9faf20766f1a26195a7c441ca12dbd"}, + {file = "sqlalchemy-2.0.51-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dc261707bf5739aea8a541593f3cc1d463c2701fb05fbcbba0ce031b69a21260"}, + {file = "sqlalchemy-2.0.51-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a6d26094615306d116dd5e4a51b0304c99dd2356fc569eed6922a80a6bd3b265"}, + {file = "sqlalchemy-2.0.51-cp311-cp311-win32.whl", hash = "sha256:ca8435d13829b92f4a97362d91975154a4015db3a2634154e1754e9a915e6b86"}, + {file = "sqlalchemy-2.0.51-cp311-cp311-win_amd64.whl", hash = "sha256:4a011ea4510683319ce4ed274b56ee05194b39b6da9d09ca7a39388f0fa84dcc"}, + {file = "sqlalchemy-2.0.51-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d78702b26ba1c18b2d0fb2ea940ba7f17a9581b42e8361ff93920ebbee1235a"}, + {file = "sqlalchemy-2.0.51-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581921d849d6e6f994d560389192955e80e2950e18fcdfe2ccea863e01158e6e"}, + {file = "sqlalchemy-2.0.51-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1d21ce524ab86c23046e992a5b81cb54c21079c6df6e78b8fc77d77cac70a6b9"}, + {file = "sqlalchemy-2.0.51-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c5d98a2709840027f5a347c3af0a7c3d5f6c1ff93af2ca1c54494e23cba8f389"}, + {file = "sqlalchemy-2.0.51-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1181256e0f16479691b5616d36375dc2620ad8332b25978763c3d206ad3f3f1d"}, + {file = "sqlalchemy-2.0.51-cp312-cp312-win32.whl", hash = "sha256:9f380393be5abeb6815f68fd39271b95127173511b6706b0a630a9995d53f8f5"}, + {file = "sqlalchemy-2.0.51-cp312-cp312-win_amd64.whl", hash = "sha256:2cf39aabdf48e87c1c2c2ed6d20d33ffa0733b3071ce9c5f66357947dd009080"}, + {file = "sqlalchemy-2.0.51-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7c2056838b6685b72fdb36c99996cf862753461a62f2e84f4196371d3b2d6a07"}, + {file = "sqlalchemy-2.0.51-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:483b11bd46bf35fc14c52faf338b04300c9e6ce554bce9b11be85bfec3bc3195"}, + {file = "sqlalchemy-2.0.51-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1bed1ee8b01da6088210aa9412023326fb98a599ba502e6118308601dcbef77f"}, + {file = "sqlalchemy-2.0.51-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:72ca54c952107ba5cd58854b67a5a6268631289d21651a1235396f3b98b47400"}, + {file = "sqlalchemy-2.0.51-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b3e693d15533a45cd5906f0589f9c35090bef6ef45bf1e8195c424aa0ae06a8d"}, + {file = "sqlalchemy-2.0.51-cp313-cp313-win32.whl", hash = "sha256:b93ab07b5292dbe7e6b8da89475275e7042744283921344b56105f3eeb0f828b"}, + {file = "sqlalchemy-2.0.51-cp313-cp313-win_amd64.whl", hash = "sha256:0f053118c30e53161857a953e4de667d90e274980dccbe5dd3829bbbeece72a5"}, + {file = "sqlalchemy-2.0.51-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6ea306caaae6bd5afd0a46050003c88f6bf33227377a49298c498c3cb88ff491"}, + {file = "sqlalchemy-2.0.51-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c45a496d6bc05dec41dcd4c3a2b183723f47473255c159cd80b503c8f246424d"}, + {file = "sqlalchemy-2.0.51-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4004ada0aafe8ae1991b2cd1d99c6d9146126e123bd6f883c260d974aa012e54"}, + {file = "sqlalchemy-2.0.51-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0f6bcad487aee1c638d707235682fc96f741de00663619881ab235400d03289e"}, + {file = "sqlalchemy-2.0.51-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:39a76529db6305693d8d4affa58ad5b5e2e18edd62daea628b29b97930b3513d"}, + {file = "sqlalchemy-2.0.51-cp314-cp314-win32.whl", hash = "sha256:08a204d8b5638717c26a24df18fcf40af45a6b22e35b70b1d62f0113c2e278e8"}, + {file = "sqlalchemy-2.0.51-cp314-cp314-win_amd64.whl", hash = "sha256:96747bfbadb055466e5b46d572618170046b45ce5a4879167f50d70a5319a499"}, + {file = "sqlalchemy-2.0.51-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e5ea1a213be1fcd5e49d9904c3b9939211ded90bc2a64e93f4c01963474285de"}, + {file = "sqlalchemy-2.0.51-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7c6b36ed71f41942bdcd2ad2522be46bfce09d5705be5640ecf19bbc7660e4b7"}, + {file = "sqlalchemy-2.0.51-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0c2c62877097e1a0db401fba5cb4debee33265e5b2a55c4ccb489c02c53b4f72"}, + {file = "sqlalchemy-2.0.51-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0378d055e9e8cd6ce4d8dff683bdd3d7d413533c4ee51d67a2b1e0f9eacc0f23"}, + {file = "sqlalchemy-2.0.51-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6e46fc36029eff666391e0531e5387b62ce6c4f1d8e50b3fb3099eaca1b42522"}, + {file = "sqlalchemy-2.0.51-cp314-cp314t-win32.whl", hash = "sha256:9161cfc9efce70d1715f47d6ff40f79c6778c00d53be4fbc09d70301e4b83ba7"}, + {file = "sqlalchemy-2.0.51-cp314-cp314t-win_amd64.whl", hash = "sha256:159bb6ba32059f57ad7375a8f50d844dd2f19d14954ecf820cd33e20debd46b2"}, + {file = "sqlalchemy-2.0.51-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bb1f5062f98b0b3290e72b707747fdd7e0f22d6956b236ba7ca7f5c9971d2da2"}, + {file = "sqlalchemy-2.0.51-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:247acaa29ccef6250dfd6a3eedf8f94ddf23564180a39fe362e32ae9dbdbde46"}, + {file = "sqlalchemy-2.0.51-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c95ef01f53233a305a874a44a63fbfb1d81cd79b49de0f8529b3548cde437e37"}, + {file = "sqlalchemy-2.0.51-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:fa268106c8987639a17a18514cfe0cd9bf17420ab887e1e1bf486da8836135b1"}, + {file = "sqlalchemy-2.0.51-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:b7f08588854bbb724041d9ae9d980d40040c922382e1d9a2ecb390edc4fd5032"}, + {file = "sqlalchemy-2.0.51-cp38-cp38-win32.whl", hash = "sha256:6b588fd681ddf0c196b8df1ea49a8913514894b2b8f945a9511b4b48871f99c8"}, + {file = "sqlalchemy-2.0.51-cp38-cp38-win_amd64.whl", hash = "sha256:ca216e8af5c05e326efc7e28716ac2381a7cf9791749f5ee1849dccdc99c9b00"}, + {file = "sqlalchemy-2.0.51-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:aa18ae738b5170e253ad0bb6c4b0f07585081e8a6e50893e4d911d47b39a0904"}, + {file = "sqlalchemy-2.0.51-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:59cab3686b1bc039dd9cded2f8d0c08a246e84e76bd4ab5b4f18c7cdae293825"}, + {file = "sqlalchemy-2.0.51-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:111604e637da87031255ddc26c7d7bc22bc6af6f5d459ccff3af1b4660233a85"}, + {file = "sqlalchemy-2.0.51-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ad30ae663711786303fbcd46a47516302d201ee49a877cb3fac61f672895110a"}, + {file = "sqlalchemy-2.0.51-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b21f0e7efc7a5c509e953784e9d1575ebb8b4318960e7e7d7a93bb803626cf64"}, + {file = "sqlalchemy-2.0.51-cp39-cp39-win32.whl", hash = "sha256:a42ad6afcbaaa777241e347aa2e29155993045a0d6b7db74da61053ffe875fe0"}, + {file = "sqlalchemy-2.0.51-cp39-cp39-win_amd64.whl", hash = "sha256:2a97eaad21c84b4ef8010b11eeba9fe6153eb0b3df3ff8b6abc309df1b978ef7"}, + {file = "sqlalchemy-2.0.51-py3-none-any.whl", hash = "sha256:bb024d8b621d0be75f4f44ecc7c950450026e76d66dc8f791bb5331d7fed59d5"}, + {file = "sqlalchemy-2.0.51.tar.gz", hash = "sha256:804dccd8a4a6242c4e30ad961e540e18a588f6527202f2d6791b01845d59fdc9"}, ] [package.dependencies] -greenlet = {version = "!=0.4.17", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""} +greenlet = {version = ">=1", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""} typing-extensions = ">=4.6.0" [package.extras] -aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"] -aioodbc = ["aioodbc", "greenlet (!=0.4.17)"] -aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] -asyncio = ["greenlet (!=0.4.17)"] -asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (!=0.4.17)"] -mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5)"] +aiomysql = ["aiomysql (>=0.2.0)", "greenlet (>=1)"] +aioodbc = ["aioodbc", "greenlet (>=1)"] +aiosqlite = ["aiosqlite", "greenlet (>=1)", "typing_extensions (!=3.10.0.1)"] +asyncio = ["greenlet (>=1)"] +asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (>=1)"] +mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5,!=1.1.10)"] mssql = ["pyodbc"] mssql-pymssql = ["pymssql"] mssql-pyodbc = ["pyodbc"] @@ -4316,7 +5352,7 @@ mysql-connector = ["mysql-connector-python"] oracle = ["cx_oracle (>=8)"] oracle-oracledb = ["oracledb (>=1.0.1)"] postgresql = ["psycopg2 (>=2.7)"] -postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] +postgresql-asyncpg = ["asyncpg", "greenlet (>=1)"] postgresql-pg8000 = ["pg8000 (>=1.29.1)"] postgresql-psycopg = ["psycopg (>=3.0.7)"] postgresql-psycopg2binary = ["psycopg2-binary"] @@ -4327,17 +5363,17 @@ sqlcipher = ["sqlcipher3_binary"] [[package]] name = "sqlalchemy-utils" -version = "0.41.1" +version = "0.42.1" description = "Various utility functions for SQLAlchemy." optional = false -python-versions = ">=3.6" +python-versions = ">=3.9" files = [ - {file = "SQLAlchemy-Utils-0.41.1.tar.gz", hash = "sha256:a2181bff01eeb84479e38571d2c0718eb52042f9afd8c194d0d02877e84b7d74"}, - {file = "SQLAlchemy_Utils-0.41.1-py3-none-any.whl", hash = "sha256:6c96b0768ea3f15c0dc56b363d386138c562752b84f647fb8d31a2223aaab801"}, + {file = "sqlalchemy_utils-0.42.1-py3-none-any.whl", hash = "sha256:243cfe1b3a1dae3c74118ae633f1d1e0ed8c787387bc33e556e37c990594ac80"}, + {file = "sqlalchemy_utils-0.42.1.tar.gz", hash = "sha256:881f9cd9e5044dc8f827bccb0425ce2e55490ce44fc0bb848c55cc8ee44cc02e"}, ] [package.dependencies] -SQLAlchemy = ">=1.3" +SQLAlchemy = ">=1.4" [package.extras] arrow = ["arrow (>=0.3.4)"] @@ -4348,27 +5384,28 @@ intervals = ["intervals (>=0.7.1)"] password = ["passlib (>=1.6,<2.0)"] pendulum = ["pendulum (>=2.0.5)"] phone = ["phonenumbers (>=5.9.2)"] -test = ["Jinja2 (>=2.3)", "Pygments (>=1.2)", "backports.zoneinfo", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "isort (>=4.2.2)", "pg8000 (>=1.12.4)", "psycopg (>=3.1.8)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (>=2.7.1)", "python-dateutil (>=2.6)", "pytz (>=2014.2)"] -test-all = ["Babel (>=1.3)", "Jinja2 (>=2.3)", "Pygments (>=1.2)", "arrow (>=0.3.4)", "backports.zoneinfo", "colour (>=0.0.4)", "cryptography (>=0.6)", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "furl (>=0.4.1)", "intervals (>=0.7.1)", "isort (>=4.2.2)", "passlib (>=1.6,<2.0)", "pendulum (>=2.0.5)", "pg8000 (>=1.12.4)", "phonenumbers (>=5.9.2)", "psycopg (>=3.1.8)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (>=2.7.1)", "python-dateutil", "python-dateutil (>=2.6)", "pytz (>=2014.2)"] +test = ["Jinja2 (>=2.3)", "Pygments (>=1.2)", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "isort (>=4.2.2)", "pg8000 (>=1.12.4)", "psycopg (>=3.1.8)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (==7.4.4)", "python-dateutil (>=2.6)", "pytz (>=2014.2)"] +test-all = ["Babel (>=1.3)", "Jinja2 (>=2.3)", "Pygments (>=1.2)", "arrow (>=0.3.4)", "colour (>=0.0.4)", "cryptography (>=0.6)", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "furl (>=0.4.1)", "intervals (>=0.7.1)", "isort (>=4.2.2)", "passlib (>=1.6,<2.0)", "pendulum (>=2.0.5)", "pg8000 (>=1.12.4)", "phonenumbers (>=5.9.2)", "psycopg (>=3.1.8)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (==7.4.4)", "python-dateutil", "python-dateutil (>=2.6)", "pytz (>=2014.2)"] timezone = ["python-dateutil"] url = ["furl (>=0.4.1)"] [[package]] name = "starlette" -version = "0.41.2" +version = "1.3.1" description = "The little ASGI library that shines." optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "starlette-0.41.2-py3-none-any.whl", hash = "sha256:fbc189474b4731cf30fcef52f18a8d070e3f3b46c6a04c97579e85e6ffca942d"}, - {file = "starlette-0.41.2.tar.gz", hash = "sha256:9834fd799d1a87fd346deb76158668cfa0b0d56f85caefe8268e2d97c3468b62"}, + {file = "starlette-1.3.1-py3-none-any.whl", hash = "sha256:c7372aae11c3c3f26a42df7bd626cec2f47d03483d261d369516a615a53714c6"}, + {file = "starlette-1.3.1.tar.gz", hash = "sha256:05d0213193f2fbaae60e2ecb593b4add4262ad4e46536b54abe36f11a71724e0"}, ] [package.dependencies] -anyio = ">=3.4.0,<5" +anyio = ">=3.6.2,<5" +typing-extensions = {version = ">=4.10.0", markers = "python_version < \"3.13\""} [package.extras] -full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"] +full = ["httpx (>=0.27.0,<0.29.0)", "httpx2 (>=2.0.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.18)", "pyyaml"] [[package]] name = "strenum" @@ -4388,13 +5425,13 @@ test = ["pylint", "pytest", "pytest-black", "pytest-cov", "pytest-pylint"] [[package]] name = "tensorboardx" -version = "2.6.2.2" +version = "2.6.5" description = "TensorBoardX lets you watch Tensors Flow without Tensorflow" optional = false -python-versions = "*" +python-versions = ">=3.9" files = [ - {file = "tensorboardX-2.6.2.2-py2.py3-none-any.whl", hash = "sha256:160025acbf759ede23fd3526ae9d9bfbfd8b68eb16c38a010ebe326dc6395db8"}, - {file = "tensorboardX-2.6.2.2.tar.gz", hash = "sha256:c6476d7cd0d529b0b72f4acadb1269f9ed8b22f441e87a84f2a3b940bb87b666"}, + {file = "tensorboardx-2.6.5-py3-none-any.whl", hash = "sha256:c10b891d00af306537cb8b58a039b2ba41571f0da06f433a41c4ca8d6abe1373"}, + {file = "tensorboardx-2.6.5.tar.gz", hash = "sha256:ca176db3997ee8c07d2eb77381225956a3fd1c10c91beafab1f17069adc47017"}, ] [package.dependencies] @@ -4402,107 +5439,130 @@ numpy = "*" packaging = "*" protobuf = ">=3.20" -[[package]] -name = "tinydb" -version = "4.8.0" -description = "TinyDB is a tiny, document oriented database optimized for your happiness :)" -optional = false -python-versions = ">=3.7,<4.0" -files = [ - {file = "tinydb-4.8.0-py3-none-any.whl", hash = "sha256:30c06d12383d7c332e404ca6a6103fb2b32cbf25712689648c39d9a6bd34bd3d"}, - {file = "tinydb-4.8.0.tar.gz", hash = "sha256:6dd686a9c5a75dfa9280088fd79a419aefe19cd7f4bd85eba203540ef856d564"}, -] - [[package]] name = "tomli" -version = "2.0.1" +version = "2.4.1" description = "A lil' TOML parser" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, + {file = "tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30"}, + {file = "tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a"}, + {file = "tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076"}, + {file = "tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9"}, + {file = "tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c"}, + {file = "tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc"}, + {file = "tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049"}, + {file = "tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e"}, + {file = "tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece"}, + {file = "tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a"}, + {file = "tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085"}, + {file = "tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9"}, + {file = "tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5"}, + {file = "tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585"}, + {file = "tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1"}, + {file = "tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917"}, + {file = "tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9"}, + {file = "tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257"}, + {file = "tomli-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54"}, + {file = "tomli-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a"}, + {file = "tomli-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897"}, + {file = "tomli-2.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f"}, + {file = "tomli-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d"}, + {file = "tomli-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5"}, + {file = "tomli-2.4.1-cp313-cp313-win32.whl", hash = "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd"}, + {file = "tomli-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36"}, + {file = "tomli-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd"}, + {file = "tomli-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf"}, + {file = "tomli-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac"}, + {file = "tomli-2.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662"}, + {file = "tomli-2.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853"}, + {file = "tomli-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15"}, + {file = "tomli-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba"}, + {file = "tomli-2.4.1-cp314-cp314-win32.whl", hash = "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6"}, + {file = "tomli-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7"}, + {file = "tomli-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232"}, + {file = "tomli-2.4.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4"}, + {file = "tomli-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c"}, + {file = "tomli-2.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d"}, + {file = "tomli-2.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41"}, + {file = "tomli-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c"}, + {file = "tomli-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f"}, + {file = "tomli-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8"}, + {file = "tomli-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26"}, + {file = "tomli-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396"}, + {file = "tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe"}, + {file = "tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f"}, ] [[package]] name = "toolz" -version = "1.0.0" +version = "1.1.0" description = "List processing tools and functional utilities" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "toolz-1.0.0-py3-none-any.whl", hash = "sha256:292c8f1c4e7516bf9086f8850935c799a874039c8bcf959d47b600e4c44a6236"}, - {file = "toolz-1.0.0.tar.gz", hash = "sha256:2c86e3d9a04798ac556793bced838816296a2f085017664e4995cb40a1047a02"}, + {file = "toolz-1.1.0-py3-none-any.whl", hash = "sha256:15ccc861ac51c53696de0a5d6d4607f99c210739caf987b5d2054f3efed429d8"}, + {file = "toolz-1.1.0.tar.gz", hash = "sha256:27a5c770d068c110d9ed9323f24f1543e83b2f300a687b7891c1a6d56b697b5b"}, ] [[package]] name = "tqdm" -version = "4.66.1" +version = "4.68.4" description = "Fast, Extensible Progress Meter" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tqdm-4.66.1-py3-none-any.whl", hash = "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386"}, - {file = "tqdm-4.66.1.tar.gz", hash = "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7"}, + {file = "tqdm-4.68.4-py3-none-any.whl", hash = "sha256:5168118b2368f48c561afda8020fd79195b1bdb0bdf8086b88442c267a315dc2"}, + {file = "tqdm-4.68.4.tar.gz", hash = "sha256:19829c9673638f2a0b8617da4cdcb927e831cd88bcfcb6e78d42a4d1af131520"}, ] [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} [package.extras] -dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"] +discord = ["envwrap", "requests"] notebook = ["ipywidgets (>=6)"] -slack = ["slack-sdk"] -telegram = ["requests"] +slack = ["envwrap", "slack-sdk"] +telegram = ["envwrap", "requests"] [[package]] -name = "tuspy" -version = "0.2.5" -description = "A Python client for the tus resumable upload protocol -> http://tus.io" +name = "truststore" +version = "0.10.4" +description = "Verify certificates using native system trust stores" optional = false -python-versions = "*" +python-versions = ">=3.10" files = [ - {file = "tuspy-0.2.5-py3-none-any.whl", hash = "sha256:8ce106dd139ac77a097e8728f15f90d99df7408d9e67ac780ce44aefb9b5dd8d"}, - {file = "tuspy-0.2.5.tar.gz", hash = "sha256:1f238f65d444c0688f57e1dd704d9aa11cf5747eec33669e917627150170b9b8"}, + {file = "truststore-0.10.4-py3-none-any.whl", hash = "sha256:adaeaecf1cbb5f4de3b1959b42d41f6fab57b2b1666adb59e89cb0b53361d981"}, + {file = "truststore-0.10.4.tar.gz", hash = "sha256:9d91bd436463ad5e4ee4aba766628dd6cd7010cf3e2461756b3303710eebc301"}, ] -[package.dependencies] -certifi = ">=2018.1.18" -future = ">=0.16.0" -requests = ">=2.18.4" -six = ">=1.11.0" -tinydb = ">=3.5.0" - -[package.extras] -dev = ["Sphinx (==1.7.1)", "sphinx-autobuild (==0.7.1)", "tox (>=2.3.1)"] -test = ["coverage (>=4.2)", "mock (>=2.0.0)", "pytest (>=3.0.3)", "pytest-cov (>=2.3.1,<2.6)", "responses (>=0.5.1)"] - [[package]] name = "typer" -version = "0.12.5" +version = "0.27.0" description = "Typer, build great CLIs. Easy to code. Based on Python type hints." optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" files = [ - {file = "typer-0.12.5-py3-none-any.whl", hash = "sha256:62fe4e471711b147e3365034133904df3e235698399bc4de2b36c8579298d52b"}, - {file = "typer-0.12.5.tar.gz", hash = "sha256:f592f089bedcc8ec1b974125d64851029c3b1af145f04aca64d69410f0c9b722"}, + {file = "typer-0.27.0-py3-none-any.whl", hash = "sha256:6f4b27631e47f077871b7dc30e933ec0131c1390fbe0e387ea5574b5bac9ccf1"}, + {file = "typer-0.27.0.tar.gz", hash = "sha256:629bd12ea5d13a17148125d9a264f949eb171fb3f120f9b04d85873cab054fa5"}, ] [package.dependencies] -click = ">=8.0.0" -rich = ">=10.11.0" +annotated-doc = ">=0.0.2" +colorama = {version = "*", markers = "platform_system == \"Windows\""} +rich = ">=13.8.0" shellingham = ">=1.3.0" -typing-extensions = ">=3.7.4.3" [[package]] name = "types-requests" -version = "2.32.0.20241016" +version = "2.33.0.20260712" description = "Typing stubs for requests" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "types-requests-2.32.0.20241016.tar.gz", hash = "sha256:0d9cad2f27515d0e3e3da7134a1b6f28fb97129d86b867f24d9c726452634d95"}, - {file = "types_requests-2.32.0.20241016-py3-none-any.whl", hash = "sha256:4195d62d6d3e043a4eaaf08ff8a62184584d2e8684e9d2aa178c7915a7da3747"}, + {file = "types_requests-2.33.0.20260712-py3-none-any.whl", hash = "sha256:de027e28c171d3da529689cbfa023b0b4eab188c8dfa22fd834eebd2cee6e7bb"}, + {file = "types_requests-2.33.0.20260712.tar.gz", hash = "sha256:2141b67ab534a5c5cd2dac5034f2a35f42e699c5bf185eee608c5246a069d7fb"}, ] [package.dependencies] @@ -4510,146 +5570,172 @@ urllib3 = ">=2" [[package]] name = "typing-extensions" -version = "4.9.0" -description = "Backported and Experimental Type Hints for Python 3.8+" +version = "4.16.0" +description = "Backported and Experimental Type Hints for Python 3.9+" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, - {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, + {file = "typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8"}, + {file = "typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5"}, ] +[[package]] +name = "typing-inspection" +version = "0.4.2" +description = "Runtime typing introspection tools" +optional = false +python-versions = ">=3.9" +files = [ + {file = "typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7"}, + {file = "typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464"}, +] + +[package.dependencies] +typing-extensions = ">=4.12.0" + [[package]] name = "tzdata" -version = "2023.4" +version = "2026.3" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2023.4-py2.py3-none-any.whl", hash = "sha256:aa3ace4329eeacda5b7beb7ea08ece826c28d761cda36e747cfbf97996d39bf3"}, - {file = "tzdata-2023.4.tar.gz", hash = "sha256:dd54c94f294765522c77399649b4fefd95522479a664a0cec87f41bebc6148c9"}, + {file = "tzdata-2026.3-py2.py3-none-any.whl", hash = "sha256:dc096730c87af6cab1b171c9d532be840741ff5d459015e7f6947bd7d7e54931"}, + {file = "tzdata-2026.3.tar.gz", hash = "sha256:4a1518b8993086a7982523e071643f3c0e5f213e75b21318e78bcabfff9d1415"}, ] [[package]] name = "tzlocal" -version = "5.2" +version = "5.4.4" description = "tzinfo object for the local timezone" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "tzlocal-5.2-py3-none-any.whl", hash = "sha256:49816ef2fe65ea8ac19d19aa7a1ae0551c834303d5014c6d5a62e4cbda8047b8"}, - {file = "tzlocal-5.2.tar.gz", hash = "sha256:8d399205578f1a9342816409cc1e46a93ebd5755e39ea2d85334bea911bf0e6e"}, + {file = "tzlocal-5.4.4-py3-none-any.whl", hash = "sha256:aae09f0126a8a86fa736be266eb4a471380d26a0de3bc14844e7821fee3e2a15"}, + {file = "tzlocal-5.4.4.tar.gz", hash = "sha256:8dbb8660838688a7b6ba4fed31d18dedf842afb4d47ca050d6d891c2c15f3be4"}, ] [package.dependencies] tzdata = {version = "*", markers = "platform_system == \"Windows\""} [package.extras] -devenv = ["check-manifest", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3)", "zest.releaser"] +devenv = ["zest.releaser"] +testing = ["check_manifest", "pyroma", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3)", "ruff"] [[package]] name = "urllib3" -version = "2.0.7" +version = "2.7.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" files = [ - {file = "urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"}, - {file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"}, + {file = "urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897"}, + {file = "urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c"}, ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] +brotli = ["brotli (>=1.2.0)", "brotlicffi (>=1.2.0.0)"] +h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["zstandard (>=0.18.0)"] +zstd = ["backports-zstd (>=1.0.0)"] [[package]] name = "uvicorn" -version = "0.32.1" +version = "0.51.0" description = "The lightning-fast ASGI server." optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "uvicorn-0.32.1-py3-none-any.whl", hash = "sha256:82ad92fd58da0d12af7482ecdb5f2470a04c9c9a53ced65b9bbb4a205377602e"}, - {file = "uvicorn-0.32.1.tar.gz", hash = "sha256:ee9519c246a72b1c084cea8d3b44ed6026e78a4a309cbedae9c37e4cb9fbb175"}, + {file = "uvicorn-0.51.0-py3-none-any.whl", hash = "sha256:5d38af6cd620f2ae3849fb44fd4879e0890aa1febe8d47eb355fb45d93fe6a5b"}, + {file = "uvicorn-0.51.0.tar.gz", hash = "sha256:f6f4b69b657c312f516dd2d268ab9ae6f254b11e4bac504f37b2ab58b24dd0b0"}, ] [package.dependencies] click = ">=7.0" -colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""} h11 = ">=0.8" -httptools = {version = ">=0.6.3", optional = true, markers = "extra == \"standard\""} +httptools = {version = ">=0.8.0", optional = true, markers = "extra == \"standard\""} python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} pyyaml = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} -uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "(sys_platform != \"win32\" and sys_platform != \"cygwin\") and platform_python_implementation != \"PyPy\" and extra == \"standard\""} -watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} -websockets = {version = ">=10.4", optional = true, markers = "extra == \"standard\""} +uvloop = {version = ">=0.15.1", optional = true, markers = "(sys_platform != \"win32\" and sys_platform != \"cygwin\") and platform_python_implementation != \"PyPy\" and extra == \"standard\""} +watchfiles = {version = ">=0.20", optional = true, markers = "extra == \"standard\""} +websockets = {version = ">=13.0", optional = true, markers = "extra == \"standard\""} [package.extras] -standard = ["colorama (>=0.4)", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] +standard = ["httptools (>=0.8.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.15.1)", "watchfiles (>=0.20)", "websockets (>=13.0)"] [[package]] name = "uvloop" -version = "0.21.0" +version = "0.22.1" description = "Fast implementation of asyncio event loop on top of libuv" optional = false -python-versions = ">=3.8.0" -files = [ - {file = "uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f"}, - {file = "uvloop-0.21.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:196274f2adb9689a289ad7d65700d37df0c0930fd8e4e743fa4834e850d7719d"}, - {file = "uvloop-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f38b2e090258d051d68a5b14d1da7203a3c3677321cf32a95a6f4db4dd8b6f26"}, - {file = "uvloop-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c43e0f13022b998eb9b973b5e97200c8b90823454d4bc06ab33829e09fb9bb"}, - {file = "uvloop-0.21.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10d66943def5fcb6e7b37310eb6b5639fd2ccbc38df1177262b0640c3ca68c1f"}, - {file = "uvloop-0.21.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:67dd654b8ca23aed0a8e99010b4c34aca62f4b7fce88f39d452ed7622c94845c"}, - {file = "uvloop-0.21.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c0f3fa6200b3108919f8bdabb9a7f87f20e7097ea3c543754cabc7d717d95cf8"}, - {file = "uvloop-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0"}, - {file = "uvloop-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9fb766bb57b7388745d8bcc53a359b116b8a04c83a2288069809d2b3466c37e"}, - {file = "uvloop-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a375441696e2eda1c43c44ccb66e04d61ceeffcd76e4929e527b7fa401b90fb"}, - {file = "uvloop-0.21.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:baa0e6291d91649c6ba4ed4b2f982f9fa165b5bbd50a9e203c416a2797bab3c6"}, - {file = "uvloop-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d"}, - {file = "uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c"}, - {file = "uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2"}, - {file = "uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d"}, - {file = "uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc"}, - {file = "uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb"}, - {file = "uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f"}, - {file = "uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281"}, - {file = "uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af"}, - {file = "uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6"}, - {file = "uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816"}, - {file = "uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc"}, - {file = "uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553"}, - {file = "uvloop-0.21.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:17df489689befc72c39a08359efac29bbee8eee5209650d4b9f34df73d22e414"}, - {file = "uvloop-0.21.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bc09f0ff191e61c2d592a752423c767b4ebb2986daa9ed62908e2b1b9a9ae206"}, - {file = "uvloop-0.21.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0ce1b49560b1d2d8a2977e3ba4afb2414fb46b86a1b64056bc4ab929efdafbe"}, - {file = "uvloop-0.21.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e678ad6fe52af2c58d2ae3c73dc85524ba8abe637f134bf3564ed07f555c5e79"}, - {file = "uvloop-0.21.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:460def4412e473896ef179a1671b40c039c7012184b627898eea5072ef6f017a"}, - {file = "uvloop-0.21.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:10da8046cc4a8f12c91a1c39d1dd1585c41162a15caaef165c2174db9ef18bdc"}, - {file = "uvloop-0.21.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c097078b8031190c934ed0ebfee8cc5f9ba9642e6eb88322b9958b649750f72b"}, - {file = "uvloop-0.21.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:46923b0b5ee7fc0020bef24afe7836cb068f5050ca04caf6b487c513dc1a20b2"}, - {file = "uvloop-0.21.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53e420a3afe22cdcf2a0f4846e377d16e718bc70103d7088a4f7623567ba5fb0"}, - {file = "uvloop-0.21.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88cb67cdbc0e483da00af0b2c3cdad4b7c61ceb1ee0f33fe00e09c81e3a6cb75"}, - {file = "uvloop-0.21.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:221f4f2a1f46032b403bf3be628011caf75428ee3cc204a22addf96f586b19fd"}, - {file = "uvloop-0.21.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2d1f581393673ce119355d56da84fe1dd9d2bb8b3d13ce792524e1607139feff"}, - {file = "uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3"}, +python-versions = ">=3.8.1" +files = [ + {file = "uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ef6f0d4cc8a9fa1f6a910230cd53545d9a14479311e87e3cb225495952eb672c"}, + {file = "uvloop-0.22.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7cd375a12b71d33d46af85a3343b35d98e8116134ba404bd657b3b1d15988792"}, + {file = "uvloop-0.22.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac33ed96229b7790eb729702751c0e93ac5bc3bcf52ae9eccbff30da09194b86"}, + {file = "uvloop-0.22.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:481c990a7abe2c6f4fc3d98781cc9426ebd7f03a9aaa7eb03d3bfc68ac2a46bd"}, + {file = "uvloop-0.22.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a592b043a47ad17911add5fbd087c76716d7c9ccc1d64ec9249ceafd735f03c2"}, + {file = "uvloop-0.22.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1489cf791aa7b6e8c8be1c5a080bae3a672791fcb4e9e12249b05862a2ca9cec"}, + {file = "uvloop-0.22.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c60ebcd36f7b240b30788554b6f0782454826a0ed765d8430652621b5de674b9"}, + {file = "uvloop-0.22.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b7f102bf3cb1995cfeaee9321105e8f5da76fdb104cdad8986f85461a1b7b77"}, + {file = "uvloop-0.22.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53c85520781d84a4b8b230e24a5af5b0778efdb39142b424990ff1ef7c48ba21"}, + {file = "uvloop-0.22.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:56a2d1fae65fd82197cb8c53c367310b3eabe1bbb9fb5a04d28e3e3520e4f702"}, + {file = "uvloop-0.22.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40631b049d5972c6755b06d0bfe8233b1bd9a8a6392d9d1c45c10b6f9e9b2733"}, + {file = "uvloop-0.22.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:535cc37b3a04f6cd2c1ef65fa1d370c9a35b6695df735fcff5427323f2cd5473"}, + {file = "uvloop-0.22.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:fe94b4564e865d968414598eea1a6de60adba0c040ba4ed05ac1300de402cd42"}, + {file = "uvloop-0.22.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:51eb9bd88391483410daad430813d982010f9c9c89512321f5b60e2cddbdddd6"}, + {file = "uvloop-0.22.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:700e674a166ca5778255e0e1dc4e9d79ab2acc57b9171b79e65feba7184b3370"}, + {file = "uvloop-0.22.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b5b1ac819a3f946d3b2ee07f09149578ae76066d70b44df3fa990add49a82e4"}, + {file = "uvloop-0.22.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e047cc068570bac9866237739607d1313b9253c3051ad84738cbb095be0537b2"}, + {file = "uvloop-0.22.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:512fec6815e2dd45161054592441ef76c830eddaad55c8aa30952e6fe1ed07c0"}, + {file = "uvloop-0.22.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:561577354eb94200d75aca23fbde86ee11be36b00e52a4eaf8f50fb0c86b7705"}, + {file = "uvloop-0.22.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cdf5192ab3e674ca26da2eada35b288d2fa49fdd0f357a19f0e7c4e7d5077c8"}, + {file = "uvloop-0.22.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e2ea3d6190a2968f4a14a23019d3b16870dd2190cd69c8180f7c632d21de68d"}, + {file = "uvloop-0.22.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0530a5fbad9c9e4ee3f2b33b148c6a64d47bbad8000ea63704fa8260f4cf728e"}, + {file = "uvloop-0.22.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bc5ef13bbc10b5335792360623cc378d52d7e62c2de64660616478c32cd0598e"}, + {file = "uvloop-0.22.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1f38ec5e3f18c8a10ded09742f7fb8de0108796eb673f30ce7762ce1b8550cad"}, + {file = "uvloop-0.22.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3879b88423ec7e97cd4eba2a443aa26ed4e59b45e6b76aabf13fe2f27023a142"}, + {file = "uvloop-0.22.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4baa86acedf1d62115c1dc6ad1e17134476688f08c6efd8a2ab076e815665c74"}, + {file = "uvloop-0.22.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:297c27d8003520596236bdb2335e6b3f649480bd09e00d1e3a99144b691d2a35"}, + {file = "uvloop-0.22.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c1955d5a1dd43198244d47664a5858082a3239766a839b2102a269aaff7a4e25"}, + {file = "uvloop-0.22.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b31dc2fccbd42adc73bc4e7cdbae4fc5086cf378979e53ca5d0301838c5682c6"}, + {file = "uvloop-0.22.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:93f617675b2d03af4e72a5333ef89450dfaa5321303ede6e67ba9c9d26878079"}, + {file = "uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:37554f70528f60cad66945b885eb01f1bb514f132d92b6eeed1c90fd54ed6289"}, + {file = "uvloop-0.22.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:b76324e2dc033a0b2f435f33eb88ff9913c156ef78e153fb210e03c13da746b3"}, + {file = "uvloop-0.22.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:badb4d8e58ee08dad957002027830d5c3b06aea446a6a3744483c2b3b745345c"}, + {file = "uvloop-0.22.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b91328c72635f6f9e0282e4a57da7470c7350ab1c9f48546c0f2866205349d21"}, + {file = "uvloop-0.22.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:daf620c2995d193449393d6c62131b3fbd40a63bf7b307a1527856ace637fe88"}, + {file = "uvloop-0.22.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6cde23eeda1a25c75b2e07d39970f3374105d5eafbaab2a4482be82f272d5a5e"}, + {file = "uvloop-0.22.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:80eee091fe128e425177fbd82f8635769e2f32ec9daf6468286ec57ec0313efa"}, + {file = "uvloop-0.22.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:017bd46f9e7b78e81606329d07141d3da446f8798c6baeec124260e22c262772"}, + {file = "uvloop-0.22.1-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3e5c6727a57cb6558592a95019e504f605d1c54eb86463ee9f7a2dbd411c820"}, + {file = "uvloop-0.22.1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:57df59d8b48feb0e613d9b1f5e57b7532e97cbaf0d61f7aa9aa32221e84bc4b6"}, + {file = "uvloop-0.22.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:55502bc2c653ed2e9692e8c55cb95b397d33f9f2911e929dc97c4d6b26d04242"}, + {file = "uvloop-0.22.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:4a968a72422a097b09042d5fa2c5c590251ad484acf910a651b4b620acd7f193"}, + {file = "uvloop-0.22.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b45649628d816c030dba3c80f8e2689bab1c89518ed10d426036cdc47874dfc4"}, + {file = "uvloop-0.22.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ea721dd3203b809039fcc2983f14608dae82b212288b346e0bfe46ec2fab0b7c"}, + {file = "uvloop-0.22.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ae676de143db2b2f60a9696d7eca5bb9d0dd6cc3ac3dad59a8ae7e95f9e1b54"}, + {file = "uvloop-0.22.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:17d4e97258b0172dfa107b89aa1eeba3016f4b1974ce85ca3ef6a66b35cbf659"}, + {file = "uvloop-0.22.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:05e4b5f86e621cf3927631789999e697e58f0d2d32675b67d9ca9eb0bca55743"}, + {file = "uvloop-0.22.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:286322a90bea1f9422a470d5d2ad82d38080be0a29c4dd9b3e6384320a4d11e7"}, + {file = "uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f"}, ] [package.extras] dev = ["Cython (>=3.0,<4.0)", "setuptools (>=60)"] -docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] -test = ["aiohttp (>=3.10.5)", "flake8 (>=5.0,<6.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=23.0.0,<23.1.0)", "pycodestyle (>=2.9.0,<2.10.0)"] +docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx_rtd_theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] +test = ["aiohttp (>=3.10.5)", "flake8 (>=6.1,<7.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=25.3.0,<25.4.0)", "pycodestyle (>=2.11.0,<2.12.0)"] [[package]] name = "validators" -version = "0.34.0" +version = "0.35.0" description = "Python Data Validation for Humans™" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "validators-0.34.0-py3-none-any.whl", hash = "sha256:c804b476e3e6d3786fa07a30073a4ef694e617805eb1946ceee3fe5a9b8b1321"}, - {file = "validators-0.34.0.tar.gz", hash = "sha256:647fe407b45af9a74d245b943b18e6a816acf4926974278f6dd617778e1e781f"}, + {file = "validators-0.35.0-py3-none-any.whl", hash = "sha256:e8c947097eae7892cb3d26868d637f79f47b4a0554bc6b80065dfe5aac3705dd"}, + {file = "validators-0.35.0.tar.gz", hash = "sha256:992d6c48a4e77c81f1b4daba10d16c3a9bb0dbb79b3a19ea847ff0928e70497a"}, ] [package.extras] @@ -4657,114 +5743,135 @@ crypto-eth-addresses = ["eth-hash[pycryptodome] (>=0.7.0)"] [[package]] name = "virtualenv" -version = "20.25.0" +version = "20.39.1" description = "Virtual Python Environment builder" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3"}, - {file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b"}, + {file = "virtualenv-20.39.1-py3-none-any.whl", hash = "sha256:a00332e0b089ba64edefbf94ef34e6db33f45fe5184df0652cf0b754dcd36190"}, + {file = "virtualenv-20.39.1.tar.gz", hash = "sha256:c551ea1072d7717a273dd9a4a0adad8f45571af134b0f63a12430e85f6ac1c08"}, ] [package.dependencies] distlib = ">=0.3.7,<1" -filelock = ">=3.12.2,<4" +filelock = {version = ">=3.24.2,<4", markers = "python_version >= \"3.10\""} platformdirs = ">=3.9.1,<5" - -[package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] +typing-extensions = {version = ">=4.13.2", markers = "python_version < \"3.11\""} [[package]] name = "watchfiles" -version = "0.24.0" +version = "1.2.0" description = "Simple, modern and high performance file watching and code reload in python." optional = false -python-versions = ">=3.8" -files = [ - {file = "watchfiles-0.24.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:083dc77dbdeef09fa44bb0f4d1df571d2e12d8a8f985dccde71ac3ac9ac067a0"}, - {file = "watchfiles-0.24.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e94e98c7cb94cfa6e071d401ea3342767f28eb5a06a58fafdc0d2a4974f4f35c"}, - {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82ae557a8c037c42a6ef26c494d0631cacca040934b101d001100ed93d43f361"}, - {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:acbfa31e315a8f14fe33e3542cbcafc55703b8f5dcbb7c1eecd30f141df50db3"}, - {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b74fdffce9dfcf2dc296dec8743e5b0332d15df19ae464f0e249aa871fc1c571"}, - {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:449f43f49c8ddca87c6b3980c9284cab6bd1f5c9d9a2b00012adaaccd5e7decd"}, - {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4abf4ad269856618f82dee296ac66b0cd1d71450fc3c98532d93798e73399b7a"}, - {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f895d785eb6164678ff4bb5cc60c5996b3ee6df3edb28dcdeba86a13ea0465e"}, - {file = "watchfiles-0.24.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7ae3e208b31be8ce7f4c2c0034f33406dd24fbce3467f77223d10cd86778471c"}, - {file = "watchfiles-0.24.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2efec17819b0046dde35d13fb8ac7a3ad877af41ae4640f4109d9154ed30a188"}, - {file = "watchfiles-0.24.0-cp310-none-win32.whl", hash = "sha256:6bdcfa3cd6fdbdd1a068a52820f46a815401cbc2cb187dd006cb076675e7b735"}, - {file = "watchfiles-0.24.0-cp310-none-win_amd64.whl", hash = "sha256:54ca90a9ae6597ae6dc00e7ed0a040ef723f84ec517d3e7ce13e63e4bc82fa04"}, - {file = "watchfiles-0.24.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:bdcd5538e27f188dd3c804b4a8d5f52a7fc7f87e7fd6b374b8e36a4ca03db428"}, - {file = "watchfiles-0.24.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2dadf8a8014fde6addfd3c379e6ed1a981c8f0a48292d662e27cabfe4239c83c"}, - {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6509ed3f467b79d95fc62a98229f79b1a60d1b93f101e1c61d10c95a46a84f43"}, - {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8360f7314a070c30e4c976b183d1d8d1585a4a50c5cb603f431cebcbb4f66327"}, - {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:316449aefacf40147a9efaf3bd7c9bdd35aaba9ac5d708bd1eb5763c9a02bef5"}, - {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73bde715f940bea845a95247ea3e5eb17769ba1010efdc938ffcb967c634fa61"}, - {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3770e260b18e7f4e576edca4c0a639f704088602e0bc921c5c2e721e3acb8d15"}, - {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa0fd7248cf533c259e59dc593a60973a73e881162b1a2f73360547132742823"}, - {file = "watchfiles-0.24.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d7a2e3b7f5703ffbd500dabdefcbc9eafeff4b9444bbdd5d83d79eedf8428fab"}, - {file = "watchfiles-0.24.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d831ee0a50946d24a53821819b2327d5751b0c938b12c0653ea5be7dea9c82ec"}, - {file = "watchfiles-0.24.0-cp311-none-win32.whl", hash = "sha256:49d617df841a63b4445790a254013aea2120357ccacbed00253f9c2b5dc24e2d"}, - {file = "watchfiles-0.24.0-cp311-none-win_amd64.whl", hash = "sha256:d3dcb774e3568477275cc76554b5a565024b8ba3a0322f77c246bc7111c5bb9c"}, - {file = "watchfiles-0.24.0-cp311-none-win_arm64.whl", hash = "sha256:9301c689051a4857d5b10777da23fafb8e8e921bcf3abe6448a058d27fb67633"}, - {file = "watchfiles-0.24.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7211b463695d1e995ca3feb38b69227e46dbd03947172585ecb0588f19b0d87a"}, - {file = "watchfiles-0.24.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4b8693502d1967b00f2fb82fc1e744df128ba22f530e15b763c8d82baee15370"}, - {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdab9555053399318b953a1fe1f586e945bc8d635ce9d05e617fd9fe3a4687d6"}, - {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:34e19e56d68b0dad5cff62273107cf5d9fbaf9d75c46277aa5d803b3ef8a9e9b"}, - {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:41face41f036fee09eba33a5b53a73e9a43d5cb2c53dad8e61fa6c9f91b5a51e"}, - {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5148c2f1ea043db13ce9b0c28456e18ecc8f14f41325aa624314095b6aa2e9ea"}, - {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e4bd963a935aaf40b625c2499f3f4f6bbd0c3776f6d3bc7c853d04824ff1c9f"}, - {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c79d7719d027b7a42817c5d96461a99b6a49979c143839fc37aa5748c322f234"}, - {file = "watchfiles-0.24.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:32aa53a9a63b7f01ed32e316e354e81e9da0e6267435c7243bf8ae0f10b428ef"}, - {file = "watchfiles-0.24.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ce72dba6a20e39a0c628258b5c308779b8697f7676c254a845715e2a1039b968"}, - {file = "watchfiles-0.24.0-cp312-none-win32.whl", hash = "sha256:d9018153cf57fc302a2a34cb7564870b859ed9a732d16b41a9b5cb2ebed2d444"}, - {file = "watchfiles-0.24.0-cp312-none-win_amd64.whl", hash = "sha256:551ec3ee2a3ac9cbcf48a4ec76e42c2ef938a7e905a35b42a1267fa4b1645896"}, - {file = "watchfiles-0.24.0-cp312-none-win_arm64.whl", hash = "sha256:b52a65e4ea43c6d149c5f8ddb0bef8d4a1e779b77591a458a893eb416624a418"}, - {file = "watchfiles-0.24.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3d2e3ab79a1771c530233cadfd277fcc762656d50836c77abb2e5e72b88e3a48"}, - {file = "watchfiles-0.24.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327763da824817b38ad125dcd97595f942d720d32d879f6c4ddf843e3da3fe90"}, - {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd82010f8ab451dabe36054a1622870166a67cf3fce894f68895db6f74bbdc94"}, - {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d64ba08db72e5dfd5c33be1e1e687d5e4fcce09219e8aee893a4862034081d4e"}, - {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1cf1f6dd7825053f3d98f6d33f6464ebdd9ee95acd74ba2c34e183086900a827"}, - {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43e3e37c15a8b6fe00c1bce2473cfa8eb3484bbeecf3aefbf259227e487a03df"}, - {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88bcd4d0fe1d8ff43675360a72def210ebad3f3f72cabfeac08d825d2639b4ab"}, - {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:999928c6434372fde16c8f27143d3e97201160b48a614071261701615a2a156f"}, - {file = "watchfiles-0.24.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:30bbd525c3262fd9f4b1865cb8d88e21161366561cd7c9e1194819e0a33ea86b"}, - {file = "watchfiles-0.24.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:edf71b01dec9f766fb285b73930f95f730bb0943500ba0566ae234b5c1618c18"}, - {file = "watchfiles-0.24.0-cp313-none-win32.whl", hash = "sha256:f4c96283fca3ee09fb044f02156d9570d156698bc3734252175a38f0e8975f07"}, - {file = "watchfiles-0.24.0-cp313-none-win_amd64.whl", hash = "sha256:a974231b4fdd1bb7f62064a0565a6b107d27d21d9acb50c484d2cdba515b9366"}, - {file = "watchfiles-0.24.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:ee82c98bed9d97cd2f53bdb035e619309a098ea53ce525833e26b93f673bc318"}, - {file = "watchfiles-0.24.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fd92bbaa2ecdb7864b7600dcdb6f2f1db6e0346ed425fbd01085be04c63f0b05"}, - {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f83df90191d67af5a831da3a33dd7628b02a95450e168785586ed51e6d28943c"}, - {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fca9433a45f18b7c779d2bae7beeec4f740d28b788b117a48368d95a3233ed83"}, - {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b995bfa6bf01a9e09b884077a6d37070464b529d8682d7691c2d3b540d357a0c"}, - {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed9aba6e01ff6f2e8285e5aa4154e2970068fe0fc0998c4380d0e6278222269b"}, - {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5171ef898299c657685306d8e1478a45e9303ddcd8ac5fed5bd52ad4ae0b69b"}, - {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4933a508d2f78099162da473841c652ad0de892719043d3f07cc83b33dfd9d91"}, - {file = "watchfiles-0.24.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:95cf3b95ea665ab03f5a54765fa41abf0529dbaf372c3b83d91ad2cfa695779b"}, - {file = "watchfiles-0.24.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:01def80eb62bd5db99a798d5e1f5f940ca0a05986dcfae21d833af7a46f7ee22"}, - {file = "watchfiles-0.24.0-cp38-none-win32.whl", hash = "sha256:4d28cea3c976499475f5b7a2fec6b3a36208656963c1a856d328aeae056fc5c1"}, - {file = "watchfiles-0.24.0-cp38-none-win_amd64.whl", hash = "sha256:21ab23fdc1208086d99ad3f69c231ba265628014d4aed31d4e8746bd59e88cd1"}, - {file = "watchfiles-0.24.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b665caeeda58625c3946ad7308fbd88a086ee51ccb706307e5b1fa91556ac886"}, - {file = "watchfiles-0.24.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5c51749f3e4e269231510da426ce4a44beb98db2dce9097225c338f815b05d4f"}, - {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82b2509f08761f29a0fdad35f7e1638b8ab1adfa2666d41b794090361fb8b855"}, - {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a60e2bf9dc6afe7f743e7c9b149d1fdd6dbf35153c78fe3a14ae1a9aee3d98b"}, - {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f7d9b87c4c55e3ea8881dfcbf6d61ea6775fffed1fedffaa60bd047d3c08c430"}, - {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:78470906a6be5199524641f538bd2c56bb809cd4bf29a566a75051610bc982c3"}, - {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:07cdef0c84c03375f4e24642ef8d8178e533596b229d32d2bbd69e5128ede02a"}, - {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d337193bbf3e45171c8025e291530fb7548a93c45253897cd764a6a71c937ed9"}, - {file = "watchfiles-0.24.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ec39698c45b11d9694a1b635a70946a5bad066b593af863460a8e600f0dff1ca"}, - {file = "watchfiles-0.24.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2e28d91ef48eab0afb939fa446d8ebe77e2f7593f5f463fd2bb2b14132f95b6e"}, - {file = "watchfiles-0.24.0-cp39-none-win32.whl", hash = "sha256:7138eff8baa883aeaa074359daabb8b6c1e73ffe69d5accdc907d62e50b1c0da"}, - {file = "watchfiles-0.24.0-cp39-none-win_amd64.whl", hash = "sha256:b3ef2c69c655db63deb96b3c3e587084612f9b1fa983df5e0c3379d41307467f"}, - {file = "watchfiles-0.24.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:632676574429bee8c26be8af52af20e0c718cc7f5f67f3fb658c71928ccd4f7f"}, - {file = "watchfiles-0.24.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a2a9891723a735d3e2540651184be6fd5b96880c08ffe1a98bae5017e65b544b"}, - {file = "watchfiles-0.24.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a7fa2bc0efef3e209a8199fd111b8969fe9db9c711acc46636686331eda7dd4"}, - {file = "watchfiles-0.24.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01550ccf1d0aed6ea375ef259706af76ad009ef5b0203a3a4cce0f6024f9b68a"}, - {file = "watchfiles-0.24.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:96619302d4374de5e2345b2b622dc481257a99431277662c30f606f3e22f42be"}, - {file = "watchfiles-0.24.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:85d5f0c7771dcc7a26c7a27145059b6bb0ce06e4e751ed76cdf123d7039b60b5"}, - {file = "watchfiles-0.24.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:951088d12d339690a92cef2ec5d3cfd957692834c72ffd570ea76a6790222777"}, - {file = "watchfiles-0.24.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49fb58bcaa343fedc6a9e91f90195b20ccb3135447dc9e4e2570c3a39565853e"}, - {file = "watchfiles-0.24.0.tar.gz", hash = "sha256:afb72325b74fa7a428c009c1b8be4b4d7c2afedafb2982827ef2156646df2fe1"}, +python-versions = ">=3.10" +files = [ + {file = "watchfiles-1.2.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:bb68bf4df85abebe5efddc53cf2075520f243a59868d9b3973278b23e76962a9"}, + {file = "watchfiles-1.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c16cb06dd17d43b9d185094268459eac92c9538356f050e55b54e82cf700e1d4"}, + {file = "watchfiles-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77a0feab9af4c021c581f695258c642b3d10c5fd4c676e33a0d8606425d82631"}, + {file = "watchfiles-1.2.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a16ffe19bf5cf9f5edaa1ad1dd830c5a816e8feec430c522302ab55483a4b994"}, + {file = "watchfiles-1.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:204f299afcbd65918ab78dbc52626b0ae45e9d8cef403fdbf33ecf9e40eac66e"}, + {file = "watchfiles-1.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11743adfa510bfffebe97659fb280182b5c9b238708f667e866f308c3430dc19"}, + {file = "watchfiles-1.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb72919d93e3a16fc451d3aa3d4b1698423daca1b382d3d959c9ac51297c12a8"}, + {file = "watchfiles-1.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62f042afde2dde21ec1d2c1a74361e804673df86f51e418a999c9acfe671b07"}, + {file = "watchfiles-1.2.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:027ae72bfdfd254862065d8b3e2a815c6ab9b1853ce41e6648ece84afd34a551"}, + {file = "watchfiles-1.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e1cfd51e97e13ff3bd047c140764d277fc9b95b7cb5da59e46a47d167adab310"}, + {file = "watchfiles-1.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:24b2405c0a46738dd9e1cf7135aa5dbdb9d42d024628651b3b13d5117e99f8df"}, + {file = "watchfiles-1.2.0-cp310-cp310-win32.whl", hash = "sha256:8c520725602756229f045b032a1ff33d7ef0f7404189d62f6c2438cb6d8ef6a1"}, + {file = "watchfiles-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:03b14855c6f35539e2d95c442ae9530a75762f1e26567152b9ed05f96534a74d"}, + {file = "watchfiles-1.2.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:704fd259e332e01f9b9c178f4bce9e49027e5587cc2600eeeaf8e76e1c846201"}, + {file = "watchfiles-1.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6543cf55d170003296d185c0af981f3e1311564907e1f4e08671fc7693a890a5"}, + {file = "watchfiles-1.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89d8c2394a065ca86f5d2910ff263ae67c127e1376ccc4f9fc35c71db879f80a"}, + {file = "watchfiles-1.2.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:772b80df316480d894a0e3165fdd19cf77f5d17f9a787f94029465ad0e3529d1"}, + {file = "watchfiles-1.2.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d158cd89df6053823533e06fb1d73c549133bff5f0396170c0e53d9559340717"}, + {file = "watchfiles-1.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d516b3283a758e087841aedb8031549fb41ced08f3db10aa6d2bf32dc042525b"}, + {file = "watchfiles-1.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:53b2290c92e0506d102cd448fbc610d87079553f86caa39d67440856a8b8bba5"}, + {file = "watchfiles-1.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a711b51aec4370d0dcda5b6c09463206f133a5759341d7744b953a7b62e1100e"}, + {file = "watchfiles-1.2.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:e2ca07fa7d89195ec0865d3d285666286740bfa83d83e5cee204043a31ecc165"}, + {file = "watchfiles-1.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e0618518f282c4ebff60f5e5b1247b6d91bb8b9f4476947563a1e74acc66f3c6"}, + {file = "watchfiles-1.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0d191c054d0715c3c95c99df9b8dbf6fd096d8c1e021e8f212e1bd8bc444ccb5"}, + {file = "watchfiles-1.2.0-cp311-cp311-win32.whl", hash = "sha256:9342472aff9b093c5acd4f6d8f70ae0937964ab56542502bcf5579782da69ae8"}, + {file = "watchfiles-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:dbd6c97045dad81227c8d040173da044c1de08de64a5ea8b555da4aee1d5fa22"}, + {file = "watchfiles-1.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:57a2d9fa4fb4c2ecae57b13dfff2c7ab53e21a2ba674fe9f05506680fcdcc0d7"}, + {file = "watchfiles-1.2.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:bc13eb17538be00c874699dc0abe4ee2bc8d50bb1166a6b9e175ef3fd7eb8f26"}, + {file = "watchfiles-1.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2d95ddc1eb6914154253d239089900813f6a767e174b8e6a50e7fdacb7e4236c"}, + {file = "watchfiles-1.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f70d8b291ef6e88d19b1f297a6905ddb978888d9272b0d05e6f53309856bcfc"}, + {file = "watchfiles-1.2.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:56d8641cf834c2836922899105bd3ce3d0dfc69291d52edf0b4d0436829b34c0"}, + {file = "watchfiles-1.2.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2581a94056e55d7d0a31a823ea92bf73749c489ca2285bfdc0fbe6b2bb49d50c"}, + {file = "watchfiles-1.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:41bc1199f7523b3f82843c88cbb979180c949caef0342cf90968f178e5d49b01"}, + {file = "watchfiles-1.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7571e4464cb6e434958f867f7f730b8ab0b75e3f8e5eac0499168486ab3c33a8"}, + {file = "watchfiles-1.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e53a384f76b631c3ae5334ce6a52f0baa3a911eb94a4eac7f160079868b716d5"}, + {file = "watchfiles-1.2.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:d20029a60a71a052a24c4db7673bc4de39ab89adbaccbfb5d67987c5d73f424d"}, + {file = "watchfiles-1.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:2cb93af48550faf1cea04c303107c8b75833de7013e57ce27d3b8d21d8d0f58c"}, + {file = "watchfiles-1.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2995c176de7692b86a2e4c58d9ec718f753150a979cb4a754e2b4ffa38e70906"}, + {file = "watchfiles-1.2.0-cp312-cp312-win32.whl", hash = "sha256:7a2cffd17d27d2ecbb310c2b1d8174f222a5495b1a721894afa88ec11e25b898"}, + {file = "watchfiles-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:f155b3a1b2a5fc89cdc70d47ee5d54e3b75e88efa34982028a35daef9ba00379"}, + {file = "watchfiles-1.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:8fa585ede612ee9f9e91b18bebf9ba11b9ae29a4e3a0d0cf6fca3e382133f0d5"}, + {file = "watchfiles-1.2.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:01ea8d66f0693b9b60a6541c8d10263091ca9a9060d242f3c1f3143f9aad2c98"}, + {file = "watchfiles-1.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7ba0480b9a74af058f43b337e937a451e109295c420916d68ad24e3dc02f5e44"}, + {file = "watchfiles-1.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f34e26a19f91f710c08e0183429f0d1d15df734e6bc78c31e77b9ea9c433658"}, + {file = "watchfiles-1.2.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b4e77f6a55f858504069abd35d336a637555c09bca453dde1ee1e5ada8a6a1fb"}, + {file = "watchfiles-1.2.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0cb4d80e212f116474a545c21c912b445f16bb0cef9e6a73a498164223e14e2f"}, + {file = "watchfiles-1.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b974946a10af379d425e2eef5b62f5c6ebeaccf91d45eaad6f5b27ecd4f91aa0"}, + {file = "watchfiles-1.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86bc13c25a8d1fcd70b51d0ce7c9b65e90de5666fcbfd3e34957cc73ee19aeb5"}, + {file = "watchfiles-1.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca148d73dea36c9763aaa351e4d7a51780ec1584217c45276f4fe8239c768b71"}, + {file = "watchfiles-1.2.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:c525543d91961c6955b2636b308569e84a1d1c5f5f2932041ab9ef46422f43e3"}, + {file = "watchfiles-1.2.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:a204794696ffb8f9b10fba6f7cb5216d42f3b2b71860ccac6b6e42f5f10973b0"}, + {file = "watchfiles-1.2.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:10d86db20695afe7997ac9e1717637d6714a8d0220458c33f3d2061f54cec427"}, + {file = "watchfiles-1.2.0-cp313-cp313-win32.whl", hash = "sha256:eb283ee99e21ad6443c8cdb06ac5b34b1308c329cbdf03fa02b445363714c799"}, + {file = "watchfiles-1.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:a0f27f01bee51861392bb6b7c4fdb290b27d1eb194e9e28788d68102a0e898d9"}, + {file = "watchfiles-1.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:3651aa7058595e9cfb75d35dd5ada2bf9f48a5b8a0f3562821d3e210c507e077"}, + {file = "watchfiles-1.2.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:faea288b6f0ab1902ef08f4ca6de005dccf856c4e0c4f21b8c5fce02d90a1b08"}, + {file = "watchfiles-1.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:01859b11fd9fbca670f4d5da00fbac282cfea9bd67a2125d8b2833a3b5617ea9"}, + {file = "watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fff610d7bb2256a317bb1e96f0d7862c7aa8076733ee5df0fd41bbe76a24a4f4"}, + {file = "watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b141a4891c995a039cd89e9a49e62df1dc8a559a5d1a6e4c7106d16c12777a55"}, + {file = "watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f22943b7770483f6ea0721c6b11d022947a98eb0acae14694de034f4d0d38925"}, + {file = "watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1bc6195825b7dcd217968bb1f801a60fd4c16e8eeab5bedc7fe917d7d5995ab4"}, + {file = "watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4a4b147f5dca2a5d325a06a832fb43f345751adfbc63204aec30e0d9ca965a2"}, + {file = "watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4543579a9bdb0c9560039b4ffddbdb39545707659fbc430ce4c10f3f68d557f9"}, + {file = "watchfiles-1.2.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:20aa0e708b920bde876a4aa82dc7dd6ebea228a63a67cda6632c2fc87b787efa"}, + {file = "watchfiles-1.2.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:d413349d565dab74297f2a63e84a097936be69bf8f3b3801f27f380e32040f44"}, + {file = "watchfiles-1.2.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:f28b2725eb8cce327b9b3ab02415c853011dc55c95832fe90de6bc56f5315f72"}, + {file = "watchfiles-1.2.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:b8c8358484d5fa12ef34f05b7f4168eaf1932f408725ff6d023c33ec17bd79d4"}, + {file = "watchfiles-1.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f04b092229ad2c50126dd3c922c8822e51e605993764a33058d4a791ab42281"}, + {file = "watchfiles-1.2.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a7ce236284f002a156f70add88efe5c70879cccbb658be0822c54b1306fc09d"}, + {file = "watchfiles-1.2.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b9909cc2b48468b575eefa944919e1fe8a36c5849d5c7c168f80a8c1db69398e"}, + {file = "watchfiles-1.2.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a37faaed405c67e28e6be45a1fa4f206ef5a2860f27c237db9fa30704c38242"}, + {file = "watchfiles-1.2.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9649193aa27bd9ff2e80ff29bfaa93085496c7a3a377592823cc58b77ee88add"}, + {file = "watchfiles-1.2.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e4ff8e37f99cf1da89e255e07c9c4b37c214038c4283707bdec308cb1b0ea1f"}, + {file = "watchfiles-1.2.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:054dc20fd2e3132b4c3883b4a00d72fd6e1f56fdaf89fccd12e8057d74cd74d7"}, + {file = "watchfiles-1.2.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:e140ed30ebde76796b686e67c182cff10ea2fbab186fafd1560f74bb5a473a6e"}, + {file = "watchfiles-1.2.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:bb7e52ecf68ba46d22df23467b87cffeb2146908aa523ebfe803019618cfda06"}, + {file = "watchfiles-1.2.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:23282a321c8baf9b3a3c4afff673f9fe65eb7fdc2338d765ccad9d3d1916a5ba"}, + {file = "watchfiles-1.2.0-cp314-cp314-win32.whl", hash = "sha256:c0db965c5f79aa49fe672d297cf1febc5ad149b658594944f49a54a2b96270a7"}, + {file = "watchfiles-1.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:71283b39fd17e5408eb123bd37aeecfd9d54c81fc184421943208aadb879d103"}, + {file = "watchfiles-1.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:c5c19526f4e54a00f2666a6c0e9e40d582c09e865055ea7378bf0009aab857b3"}, + {file = "watchfiles-1.2.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:d73a585accffa5ae39c17264c36ec3166d2fad7000c780f5ef83b2722afb9dd2"}, + {file = "watchfiles-1.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ae99b14c5f21e026e0e9d96f40e07d8570ebee6cafd9d8fc318354606daa7a28"}, + {file = "watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4429f3b105524a10b72c3a819b091c495d2811d419c1e1e8df773a5a5974f831"}, + {file = "watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:43d818978d06062d9b22c4fab2ebe44cf5213d42dc8e62bda8c2760cfa2eeb33"}, + {file = "watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9f732dc58b2dbe69e464ccf8fff7a03b0dd0be439da4c0720d3558527d3d6b4"}, + {file = "watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f200104103feb097de4cab8fe4f5dd18a2026934c7dea98c55a2f5fd6d5a33b"}, + {file = "watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:63ac26eefbf4af1741247d6fb68b11c49a25b2f7413fbd318a83a12aaa9cf666"}, + {file = "watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c4997d4e4a55f0d02b6cde327322daf3a0400e5df6c6b15948994bf72497925"}, + {file = "watchfiles-1.2.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:4c887eba18b7945ac73067a8b4a66f21cd46c2539b2bc68588f7be6c7eb6d26b"}, + {file = "watchfiles-1.2.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:3416ff151bb6b5a8d8d11664974fbef4d9305b9b2957839ab5a270468fd8df30"}, + {file = "watchfiles-1.2.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:0e831a271c035d89789cffc386b6aa1375f39f1cd25eb7ca0997e4970d152fc5"}, + {file = "watchfiles-1.2.0-cp315-cp315-macosx_10_12_x86_64.whl", hash = "sha256:37a6721cdf3f65dbb13aa9503510ccb4451603ac837e44d265d7992a597e1374"}, + {file = "watchfiles-1.2.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:2b37d10b5a63bd4d87e18472d80fa525bd670586fae62e5dd580452764879b65"}, + {file = "watchfiles-1.2.0-cp315-cp315-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a105bc2283f67e8fbec74253ec2d94925de92ed72c0393f1206bf326b7b7b69"}, + {file = "watchfiles-1.2.0-cp315-cp315-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5327989a465505f05cfe06f04fa9d0c2fd5432bb243e10e6f012b1bdca3c8579"}, + {file = "watchfiles-1.2.0-cp315-cp315-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ecb47f183a8025b2aa18b546725c3657e542112ae9c0613a2af79b4fa8d04ad7"}, + {file = "watchfiles-1.2.0-cp315-cp315-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8520a4ab0e37f770afc34459c4f8f7019e153f9124dc101c15538365875d1ab2"}, + {file = "watchfiles-1.2.0-cp315-cp315-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:71cd71740ed2c15211ebb237ced4e39a1cdf6f80566e5fe95428da1626f4fde6"}, + {file = "watchfiles-1.2.0-cp315-cp315-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f88af53d6ddaf72179ef613ddc905e6f4785f712b49b80b3bef9f3525e6194b4"}, + {file = "watchfiles-1.2.0-cp315-cp315-manylinux_2_31_riscv64.whl", hash = "sha256:cee9d5efd929efdac5f7e58f72b3376f676b64050a91c5b99a7094c5b2317488"}, + {file = "watchfiles-1.2.0-cp315-cp315-musllinux_1_1_aarch64.whl", hash = "sha256:b718bf356bbc15e559bd8ef41782b573b8ae0e3f177ab244b440568d7ea02cfb"}, + {file = "watchfiles-1.2.0-cp315-cp315-musllinux_1_1_x86_64.whl", hash = "sha256:922c0e019fe68b3ae392965a766b02a71ba1168c932cebc3733cd52c5fe5b377"}, + {file = "watchfiles-1.2.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:4674d49eb94706dfe666c069fc0a1b646ffcf920473492e209f6d5f60d3f0cc2"}, + {file = "watchfiles-1.2.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:094b9b70103d4e963499bdea001ee3c2697b144cd9ae6218a62c0f89ec9e31db"}, + {file = "watchfiles-1.2.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0ef001f8c25ad0fa9529f914c1600647ecd0f542d11c19b7894768c67b6acb7"}, + {file = "watchfiles-1.2.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a88fc94e647bc4eec523f1caa540258eb71d14278b9daf72fa1e2658a98df0f0"}, + {file = "watchfiles-1.2.0.tar.gz", hash = "sha256:c995fba777f1ea992f090f9236e9284cf7a5d1a0130dd5a3d82c598cacd76838"}, ] [package.dependencies] @@ -4772,19 +5879,19 @@ anyio = ">=3.0.0" [[package]] name = "web3" -version = "7.8.0" +version = "7.16.0" description = "web3: A Python library for interacting with Ethereum" optional = false python-versions = "<4,>=3.8" files = [ - {file = "web3-7.8.0-py3-none-any.whl", hash = "sha256:c8771b3d8772f7104a0462804449beb57d36cef7bd8b411140f95a92fc46b559"}, - {file = "web3-7.8.0.tar.gz", hash = "sha256:712bc9fd6b1ef6e467ee24c25b581e1951cab2cba17f9f548f12587734f2c857"}, + {file = "web3-7.16.0-py3-none-any.whl", hash = "sha256:760b2718c473980d70708c3593d9d28395db4b482f45e38a63a36fa028178f51"}, + {file = "web3-7.16.0.tar.gz", hash = "sha256:b4a75a3fa94fef4d23d502eb3c2244146ef9a1ee0082cf1cb0a91586ba0510c3"}, ] [package.dependencies] aiohttp = ">=3.7.4.post0" eth-abi = ">=5.0.1" -eth-account = ">=0.13.1" +eth-account = ">=0.13.6" eth-hash = {version = ">=0.5.1", extras = ["pycryptodome"]} eth-typing = ">=5.0.0" eth-utils = ">=5.0.0" @@ -4795,203 +5902,211 @@ pywin32 = {version = ">=223", markers = "platform_system == \"Windows\""} requests = ">=2.23.0" types-requests = ">=2.0.0" typing-extensions = ">=4.0.1" -websockets = ">=10.0.0,<14.0.0" +websockets = ">=10.0.0,<16.0.0" [package.extras] -dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "eth-tester[py-evm] (>=0.12.0b1,<0.13.0b1)", "flaky (>=3.7.0)", "hypothesis (>=3.31.2)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "py-geth (>=5.1.0)", "pytest (>=7.0.0)", "pytest-asyncio (>=0.18.1,<0.23)", "pytest-mock (>=1.10)", "pytest-xdist (>=2.4.0)", "setuptools (>=38.6.0)", "sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "tqdm (>4.32)", "twine (>=1.13)", "wheel"] -docs = ["sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=21,<22)"] -test = ["eth-tester[py-evm] (>=0.12.0b1,<0.13.0b1)", "flaky (>=3.7.0)", "hypothesis (>=3.31.2)", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "py-geth (>=5.1.0)", "pytest (>=7.0.0)", "pytest-asyncio (>=0.18.1,<0.23)", "pytest-mock (>=1.10)", "pytest-xdist (>=2.4.0)", "tox (>=4.0.0)"] -tester = ["eth-tester[py-evm] (>=0.12.0b1,<0.13.0b1)", "py-geth (>=5.1.0)"] +dev = ["build (>=0.9.0)", "bump_my_version (>=0.19.0)", "eth-tester[py-evm] (>=0.13.0b1,<0.14.0b1)", "flaky (>=3.7.0)", "hypothesis (>=3.31.2)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "py-geth (>=6.4.0)", "pytest (>=7.0.0)", "pytest-asyncio (>=0.18.1,<0.23)", "pytest-mock (>=1.10)", "pytest-xdist (>=2.4.0)", "setuptools (>=38.6.0)", "sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)", "tox (>=4.0.0)", "tqdm (>4.32)", "twine (>=1.13)", "wheel"] +docs = ["sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)"] +test = ["eth-tester[py-evm] (>=0.13.0b1,<0.14.0b1)", "flaky (>=3.7.0)", "hypothesis (>=3.31.2)", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "py-geth (>=6.4.0)", "pytest (>=7.0.0)", "pytest-asyncio (>=0.18.1,<0.23)", "pytest-mock (>=1.10)", "pytest-xdist (>=2.4.0)", "tox (>=4.0.0)"] +tester = ["eth-tester[py-evm] (>=0.13.0b1,<0.14.0b1)", "py-geth (>=6.4.0)"] [[package]] name = "websockets" -version = "12.0" +version = "15.0.1" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" 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"}, -] - -[[package]] -name = "xmltodict" -version = "0.13.0" -description = "Makes working with XML feel like you are working with JSON" -optional = false -python-versions = ">=3.4" -files = [ - {file = "xmltodict-0.13.0-py2.py3-none-any.whl", hash = "sha256:aa89e8fd76320154a40d19a0df04a4695fb9dc5ba977cbb68ab3e4eb225e7852"}, - {file = "xmltodict-0.13.0.tar.gz", hash = "sha256:341595a488e3e01a85a9d8911d8912fd922ede5fecc4dce437eb4b6c8d037e56"}, + {file = "websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b"}, + {file = "websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205"}, + {file = "websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a"}, + {file = "websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e"}, + {file = "websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf"}, + {file = "websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb"}, + {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d"}, + {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9"}, + {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c"}, + {file = "websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256"}, + {file = "websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41"}, + {file = "websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431"}, + {file = "websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57"}, + {file = "websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905"}, + {file = "websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562"}, + {file = "websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792"}, + {file = "websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413"}, + {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8"}, + {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3"}, + {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf"}, + {file = "websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85"}, + {file = "websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065"}, + {file = "websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3"}, + {file = "websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665"}, + {file = "websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2"}, + {file = "websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215"}, + {file = "websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5"}, + {file = "websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65"}, + {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe"}, + {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4"}, + {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597"}, + {file = "websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9"}, + {file = "websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7"}, + {file = "websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931"}, + {file = "websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675"}, + {file = "websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151"}, + {file = "websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22"}, + {file = "websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f"}, + {file = "websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8"}, + {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375"}, + {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d"}, + {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4"}, + {file = "websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa"}, + {file = "websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561"}, + {file = "websockets-15.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5f4c04ead5aed67c8a1a20491d54cdfba5884507a48dd798ecaf13c74c4489f5"}, + {file = "websockets-15.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abdc0c6c8c648b4805c5eacd131910d2a7f6455dfd3becab248ef108e89ab16a"}, + {file = "websockets-15.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a625e06551975f4b7ea7102bc43895b90742746797e2e14b70ed61c43a90f09b"}, + {file = "websockets-15.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d591f8de75824cbb7acad4e05d2d710484f15f29d4a915092675ad3456f11770"}, + {file = "websockets-15.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47819cea040f31d670cc8d324bb6435c6f133b8c7a19ec3d61634e62f8d8f9eb"}, + {file = "websockets-15.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac017dd64572e5c3bd01939121e4d16cf30e5d7e110a119399cf3133b63ad054"}, + {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4a9fac8e469d04ce6c25bb2610dc535235bd4aa14996b4e6dbebf5e007eba5ee"}, + {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363c6f671b761efcb30608d24925a382497c12c506b51661883c3e22337265ed"}, + {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2034693ad3097d5355bfdacfffcbd3ef5694f9718ab7f29c29689a9eae841880"}, + {file = "websockets-15.0.1-cp39-cp39-win32.whl", hash = "sha256:3b1ac0d3e594bf121308112697cf4b32be538fb1444468fb0a6ae4feebc83411"}, + {file = "websockets-15.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7643a03db5c95c799b89b31c036d5f27eeb4d259c798e878d6937d71832b1e4"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7f493881579c90fc262d9cdbaa05a6b54b3811c2f300766748db79f098db9940"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:47b099e1f4fbc95b701b6e85768e1fcdaf1630f3cbe4765fa216596f12310e2e"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67f2b6de947f8c757db2db9c71527933ad0019737ec374a8a6be9a956786aaf9"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d08eb4c2b7d6c41da6ca0600c077e93f5adcfd979cd777d747e9ee624556da4b"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b826973a4a2ae47ba357e4e82fa44a463b8f168e1ca775ac64521442b19e87f"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:21c1fa28a6a7e3cbdc171c694398b6df4744613ce9b36b1a498e816787e28123"}, + {file = "websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f"}, + {file = "websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee"}, ] [[package]] name = "yarl" -version = "1.18.3" +version = "1.24.2" description = "Yet another URL library" optional = false -python-versions = ">=3.9" -files = [ - {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34"}, - {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7"}, - {file = "yarl-1.18.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:602d98f2c2d929f8e697ed274fbadc09902c4025c5a9963bf4e9edfc3ab6f7ed"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c654d5207c78e0bd6d749f6dae1dcbbfde3403ad3a4b11f3c5544d9906969dde"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5094d9206c64181d0f6e76ebd8fb2f8fe274950a63890ee9e0ebfd58bf9d787b"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35098b24e0327fc4ebdc8ffe336cee0a87a700c24ffed13161af80124b7dc8e5"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3236da9272872443f81fedc389bace88408f64f89f75d1bdb2256069a8730ccc"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2c08cc9b16f4f4bc522771d96734c7901e7ebef70c6c5c35dd0f10845270bcd"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80316a8bd5109320d38eef8833ccf5f89608c9107d02d2a7f985f98ed6876990"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c1e1cc06da1491e6734f0ea1e6294ce00792193c463350626571c287c9a704db"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fea09ca13323376a2fdfb353a5fa2e59f90cd18d7ca4eaa1fd31f0a8b4f91e62"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e3b9fd71836999aad54084906f8663dffcd2a7fb5cdafd6c37713b2e72be1760"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:757e81cae69244257d125ff31663249b3013b5dc0a8520d73694aed497fb195b"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b1771de9944d875f1b98a745bc547e684b863abf8f8287da8466cf470ef52690"}, - {file = "yarl-1.18.3-cp310-cp310-win32.whl", hash = "sha256:8874027a53e3aea659a6d62751800cf6e63314c160fd607489ba5c2edd753cf6"}, - {file = "yarl-1.18.3-cp310-cp310-win_amd64.whl", hash = "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8"}, - {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069"}, - {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193"}, - {file = "yarl-1.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a"}, - {file = "yarl-1.18.3-cp311-cp311-win32.whl", hash = "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1"}, - {file = "yarl-1.18.3-cp311-cp311-win_amd64.whl", hash = "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5"}, - {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50"}, - {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576"}, - {file = "yarl-1.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285"}, - {file = "yarl-1.18.3-cp312-cp312-win32.whl", hash = "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2"}, - {file = "yarl-1.18.3-cp312-cp312-win_amd64.whl", hash = "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477"}, - {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb"}, - {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa"}, - {file = "yarl-1.18.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8"}, - {file = "yarl-1.18.3-cp313-cp313-win32.whl", hash = "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d"}, - {file = "yarl-1.18.3-cp313-cp313-win_amd64.whl", hash = "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c"}, - {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:61e5e68cb65ac8f547f6b5ef933f510134a6bf31bb178be428994b0cb46c2a04"}, - {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe57328fbc1bfd0bd0514470ac692630f3901c0ee39052ae47acd1d90a436719"}, - {file = "yarl-1.18.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a440a2a624683108a1b454705ecd7afc1c3438a08e890a1513d468671d90a04e"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09c7907c8548bcd6ab860e5f513e727c53b4a714f459b084f6580b49fa1b9cee"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4f6450109834af88cb4cc5ecddfc5380ebb9c228695afc11915a0bf82116789"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9ca04806f3be0ac6d558fffc2fdf8fcef767e0489d2684a21912cc4ed0cd1b8"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77a6e85b90a7641d2e07184df5557132a337f136250caafc9ccaa4a2a998ca2c"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6333c5a377c8e2f5fae35e7b8f145c617b02c939d04110c76f29ee3676b5f9a5"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0b3c92fa08759dbf12b3a59579a4096ba9af8dd344d9a813fc7f5070d86bbab1"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:4ac515b860c36becb81bb84b667466885096b5fc85596948548b667da3bf9f24"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:045b8482ce9483ada4f3f23b3774f4e1bf4f23a2d5c912ed5170f68efb053318"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:a4bb030cf46a434ec0225bddbebd4b89e6471814ca851abb8696170adb163985"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:54d6921f07555713b9300bee9c50fb46e57e2e639027089b1d795ecd9f7fa910"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1d407181cfa6e70077df3377938c08012d18893f9f20e92f7d2f314a437c30b1"}, - {file = "yarl-1.18.3-cp39-cp39-win32.whl", hash = "sha256:ac36703a585e0929b032fbaab0707b75dc12703766d0b53486eabd5139ebadd5"}, - {file = "yarl-1.18.3-cp39-cp39-win_amd64.whl", hash = "sha256:ba87babd629f8af77f557b61e49e7c7cac36f22f871156b91e10a6e9d4f829e9"}, - {file = "yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b"}, - {file = "yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1"}, +python-versions = ">=3.10" +files = [ + {file = "yarl-1.24.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5249a113065c2b7a958bc699759e359cd61cfc81e3069662208f48f191b7ed12"}, + {file = "yarl-1.24.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7f4425fa244fbf530b006d0c5f79ce920114cfff5b4f5f6056e669f8e160fdc0"}, + {file = "yarl-1.24.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:15c0b5e49d3c44e2a0b93e6a49476c5edad0a7686b92c395765a7ea775572a75"}, + {file = "yarl-1.24.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:246d32a53a947c8f0189f5d699cbd4c7036de45d9359e13ba238d1239678c727"}, + {file = "yarl-1.24.2-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:64480fb3e4d4ed9ed71c48a91a477384fc342a50ca30071d2f8a88d51d9c9413"}, + {file = "yarl-1.24.2-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:349de4701dc3760b6e876628423a8f147ef4f5599d10aba1e10702075d424ed9"}, + {file = "yarl-1.24.2-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d162677af8d5d3d6ebab8394b021f4d041ac107a4b705873148a77a49dc9e1b2"}, + {file = "yarl-1.24.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f5f5c6ec23a9043f2d139cc072f53dd23168d202a334b9b2fda8de4c3e890d90"}, + {file = "yarl-1.24.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:60de6742447fbbf697f16f070b8a443f1b5fe6ca3826fbef9fe70ecd5328e643"}, + {file = "yarl-1.24.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:acf93187c3710e422368eb768aee98db551ec7c85adc250207a95c16548ab7ac"}, + {file = "yarl-1.24.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:f4b0352fd41fd34b6651934606268816afd6914d09626f9bcbbf018edb0afb3f"}, + {file = "yarl-1.24.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:6b208bb939099b4b297438da4e9b25357f0b1c791888669b963e45b203ea9f36"}, + {file = "yarl-1.24.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:4b85b8825e631295ff4bc8943f7471d54c533a9360bbe15ebb38e018b555bb8a"}, + {file = "yarl-1.24.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e26acf20c26cb4fefc631fdb75aca2a6b8fa8b7b5d7f204fb6a8f1e63c706f53"}, + {file = "yarl-1.24.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:819ca24f8eafcfb683c1bd5f44f2f488cea1274eb8944731ffd2e1f10f619342"}, + {file = "yarl-1.24.2-cp310-cp310-win_amd64.whl", hash = "sha256:5cb0f995a901c36be096ccbf4c673591c2faabbe96279598ffaec8c030f85bf4"}, + {file = "yarl-1.24.2-cp310-cp310-win_arm64.whl", hash = "sha256:f408eace7e22a68b467a0562e0d27d322f91fe3eaaa6f466b962c6cfaea9fa39"}, + {file = "yarl-1.24.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:36348bebb147b83818b9d7e673ea4debc75970afc6ffdc7e3975ad05ce5a58c1"}, + {file = "yarl-1.24.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a97e42c8a2233f2f279ecadd9e4a037bcb5d813b78435e8eedd4db5a9e9708c"}, + {file = "yarl-1.24.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8d027d56f1035e339d1001ac33eceab5b2ec8e42e449787bb75e289fb9a5cd1d"}, + {file = "yarl-1.24.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a6377060e7927187a42b7eb202090cbe2b34933a4eeaf90e3bd9e33432e5cae"}, + {file = "yarl-1.24.2-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:17076578bce0049a5ce57d14ad1bded391b68a3b213e9b81b0097b090244999a"}, + {file = "yarl-1.24.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:50713f1d4d6be6375bb178bb43d140ee1acb8abe589cd723320b7925a275be1e"}, + {file = "yarl-1.24.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:34263e2fa8fb5bb63a0d97706cda38edbad62fddb58c7f12d6acbc092812aa50"}, + {file = "yarl-1.24.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:49016d82f032b1bd1e10b01078a7d29ae71bf468eeae0ea22df8bab691e60003"}, + {file = "yarl-1.24.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3f6d2c216318f8f32038ca3f72501ba08536f0fd18a36e858836b121b2deed9f"}, + {file = "yarl-1.24.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:08d3a33218e0c64393e7610284e770409a9c31c429b078bcb24096ed0a783b8f"}, + {file = "yarl-1.24.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:5d699376c4ca3cba49bbfae3a05b5b70ded572937171ce1e0b8d87118e2ba294"}, + {file = "yarl-1.24.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a1cab588b4fa14bea2e55ebea27478adfb05372f47573738e1acc4a36c0b05d2"}, + {file = "yarl-1.24.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:ec87ccc31bd21db7ad009d8572c127c1000f268517618a4cc09adba3c2a7f21c"}, + {file = "yarl-1.24.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d1dd47a22843b212baa8d74f37796815d43bd046b42a0f41e9da433386c3136b"}, + {file = "yarl-1.24.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7b54b9c67c2b06bd7b9a77253d242124b9c95d2c02def5a1144001ee547dd9d5"}, + {file = "yarl-1.24.2-cp311-cp311-win_amd64.whl", hash = "sha256:f8fdbcff8b2c7c9284e60c196f693588598ddcee31e11c18e14949ce44519d45"}, + {file = "yarl-1.24.2-cp311-cp311-win_arm64.whl", hash = "sha256:b32c37a7a337e90822c45797bf3d79d60875cfcccd3ecc80e9f453d87026c122"}, + {file = "yarl-1.24.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b975866c184564c827e0877380f0dae57dcca7e52782128381b72feff6dfceb8"}, + {file = "yarl-1.24.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3b075301a2836a0e297b1b658cb6d6135df535d62efefdd60366bd589c2c82f2"}, + {file = "yarl-1.24.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8ae44649b00947634ab0dab2a374a638f52923a6e67083f2c156cd5cbd1a881d"}, + {file = "yarl-1.24.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:507cc19f0b45454e2d6dcd62ff7d062b9f77a2812404e62dbdaec05b50faa035"}, + {file = "yarl-1.24.2-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c4c17bad5a530912d2111825d3f05e89bab2dd376aaa8cbc77e449e6db63e576"}, + {file = "yarl-1.24.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f5f0cbb112838a4a293985b6ed73948a547dadcc1ba6d2089938e7abdedceef8"}, + {file = "yarl-1.24.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ec8356b8a6afcf81fc7aeeef13b1ff7a49dec00f313394bbb9e83830d32ccd7"}, + {file = "yarl-1.24.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7e7ebcdef69dec6c6451e616f32b622a6d4a2e92b445c992f7c8e5274a6bbc4c"}, + {file = "yarl-1.24.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:47a55d6cf6db2f401017a9e96e5288844e5051911fb4e0c8311a3980f5e59a7d"}, + {file = "yarl-1.24.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3065657c80a2321225e804048597ad55658a7e76b32d6f5ee4074d04c50401db"}, + {file = "yarl-1.24.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:cb84b80d88e19ede158619b80813968713d8d008b0e2497a576e6a0557d50712"}, + {file = "yarl-1.24.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:990de4f680b1c217e77ff0d6aa0029f9eb79889c11fb3e9a3942c7eba29c1996"}, + {file = "yarl-1.24.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:abb8ec0323b80161e3802da3150ef660b41d0e9be2048b76a363d93eee992c2b"}, + {file = "yarl-1.24.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e7977781f83638a4c73e0f88425563d70173e0dfd90ac006a45c65036293ee3c"}, + {file = "yarl-1.24.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e30dd55825dc554ec5b66a94953b8eda8745926514c5089dfcacecb9c99b5bd1"}, + {file = "yarl-1.24.2-cp312-cp312-win_amd64.whl", hash = "sha256:7dafe10c12ddd4d120d528c4b5599c953bd7b12845347d507b95451195bb6cad"}, + {file = "yarl-1.24.2-cp312-cp312-win_arm64.whl", hash = "sha256:044a09d8401fcf8681977faef6d286b8ade1e2d2e9dceda175d1cfa5ca496f30"}, + {file = "yarl-1.24.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:491ac9141decf49ee8030199e1ee251cdff0e131f25678817ff6aa5f837a3536"}, + {file = "yarl-1.24.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e89418f65eda18f99030386305bd44d7d504e328a7945db1ead514fbe03a0607"}, + {file = "yarl-1.24.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cdfcce633b4a4bb8281913c57fcafd4b5933fbc19111a5e3930bbd299d6102f1"}, + {file = "yarl-1.24.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:863297ddede92ee49024e9a9b11ecb59f310ca85b60d8537f56bed9bbb5b1986"}, + {file = "yarl-1.24.2-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:374423f70754a2c96942ede36a29d37dc6b0cb8f92f8d009ddf3ed78d3da5488"}, + {file = "yarl-1.24.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:33a29b5d00ccbf3219bb3e351d7875739c19481e030779f48cc46a7a71681a9b"}, + {file = "yarl-1.24.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a9532c57211730c515341af11fef6e9b61d157487272a096d0c04da445642592"}, + {file = "yarl-1.24.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:91e72cf093fd833483a97ee648e0c053c7c629f51ff4a0e7edd84f806b0c5617"}, + {file = "yarl-1.24.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b3177bc0a768ef3bacceb4f272632990b7bea352f1b2f1eee9d6d6ff16516f92"}, + {file = "yarl-1.24.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e196952aacaf3b232e265ff02980b64d483dc0972bd49bcb061171ff22ac203a"}, + {file = "yarl-1.24.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:204e7a61ce99919c0de1bf904ab5d7aa188a129ea8f690a8f76cfb6e2844dc44"}, + {file = "yarl-1.24.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b156914620f0b9d78dc1adb3751141daee561cfec796088abb89ed49d220f1a"}, + {file = "yarl-1.24.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:8372a2b976cf70654b2be6619ab6068acabb35f724c0fda7b277fbf53d66a5cf"}, + {file = "yarl-1.24.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f9a1e9b622ca284143aab5d885848686dcd85453bb1ca9abcdb7503e64dc0056"}, + {file = "yarl-1.24.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:810e19b685c8c3c5862f6a38160a1f4e4c0916c9390024ec347b6157a45a0992"}, + {file = "yarl-1.24.2-cp313-cp313-win_amd64.whl", hash = "sha256:7d37fb7c38f2b6edab0f845c4f85148d4c44204f52bc127021bd2bc9fdbf1656"}, + {file = "yarl-1.24.2-cp313-cp313-win_arm64.whl", hash = "sha256:1e831894be7c2954240e49791fa4b50c05a0dc881de2552cfe3ffd8631c7f461"}, + {file = "yarl-1.24.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:f9312b3c02d9b3d23840f67952913c9c8721d7f1b7db305289faefa878f364c2"}, + {file = "yarl-1.24.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a4f4d6cd615823bfc7fb7e9b5987c3f41666371d870d51058f77e2680fbe9630"}, + {file = "yarl-1.24.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0c3063e5c0a8e8e62fae6c2596fa01da1561e4cd1da6fec5789f5cf99a8aefd8"}, + {file = "yarl-1.24.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fecd17873a096036c1c87ab3486f1aef7f269ada7f23f7f856f93b1cc7744f14"}, + {file = "yarl-1.24.2-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a46d1ab4ba4d32e6dc80daf8a28ce0bd83d08df52fbc32f3e288663427734535"}, + {file = "yarl-1.24.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:73e68edf6dfd5f73f9ca127d84e2a6f9213c65bdffb736bda19524c0564fcd14"}, + {file = "yarl-1.24.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a296ca617f2d25fbceafb962b88750d627e5984e75732c712154d058ae8d79a3"}, + {file = "yarl-1.24.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51b2cf5ec89a8b8470177641ed62a3ba22d74e1e898e06ad53aa77972487208"}, + {file = "yarl-1.24.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:310fc687f7b2044ec54e372c8cbe923bb88f5c37bded0d3079e5791c2fc3cf50"}, + {file = "yarl-1.24.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:297a2fe352ecf858b30a98f87948746ec16f001d279f84aebdbd3bd965e2f1bd"}, + {file = "yarl-1.24.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2a263e76b97bc42bdcd7c5f4953dec1f7cd62a1112fa7f869e57255229390d67"}, + {file = "yarl-1.24.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:822519b64cf0b474f1a0aaef1dc621438ea46bb77c94df97a5b4d213a7d8a8b1"}, + {file = "yarl-1.24.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:b6067060d9dc594899ba83e6db6c48c68d1e494a6dab158156ed86977ca7bcb1"}, + {file = "yarl-1.24.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:0063adad533e57171b79db3943b229d40dfafeeee579767f96541f106bac5f1b"}, + {file = "yarl-1.24.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ee8e3fb34513e8dc082b586ef4910c98335d43a6fab688cd44d4851bacfce3e8"}, + {file = "yarl-1.24.2-cp314-cp314-win_amd64.whl", hash = "sha256:afb00d7fd8e0f285ca29a44cc50df2d622ff2f7a6d933fa641577b5f9d5f3db0"}, + {file = "yarl-1.24.2-cp314-cp314-win_arm64.whl", hash = "sha256:68cf6eacd6028ef1142bc4b48376b81566385ca6f9e7dde3b0fa91be08ffcb57"}, + {file = "yarl-1.24.2-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:221ce1dd921ac4f603957f17d7c18c5cc0797fbb52f156941f92e04605d1d67b"}, + {file = "yarl-1.24.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5f3224db28173a00d7afacdee07045cc4673dfab2b15492c7ae10deddbece761"}, + {file = "yarl-1.24.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c557165320d6244ebe3a02431b2a201a20080e02f41f0cfa0ccc47a183765da8"}, + {file = "yarl-1.24.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:904065e6e85b1fa54d0d87438bd58c14c0bad97aad654ad1077fd9d87e8478ed"}, + {file = "yarl-1.24.2-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8cec2a38d70edc10e0e856ceda886af5327a017ccbde8e1de1bd44d300357543"}, + {file = "yarl-1.24.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e7484b9361ed222ee1ca5b4337aa4cbdcc4618ce5aff57d9ef1582fd95893fc0"}, + {file = "yarl-1.24.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:84f9670b89f34db07f81e53aee83e0b938a3412329d51c8f922488be7fcc4024"}, + {file = "yarl-1.24.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:abb2759733d63a28b4956500a5dd57140f26486c92b2caedfb964ab7d9b79dbf"}, + {file = "yarl-1.24.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:081c2bf54efe03774d0311172bc04fedf9ca01e644d4cd8c805688e527209bdc"}, + {file = "yarl-1.24.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:86746bef442aa479107fe28132e1277237f9c24c2f00b0b0cf22b3ee0904f2bb"}, + {file = "yarl-1.24.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:2d07d21d0bc4b17558e8de0b02fbfdf1e347d3bb3699edd00bb92e7c57925420"}, + {file = "yarl-1.24.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:4fb1ac3fc5fecd8ae7453ea237e4d22b49befa70266dfe1629924245c21a0c7f"}, + {file = "yarl-1.24.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:4da31a5512ed1729ca8d8aacde3f7faeb8843cde3165d6bcf7f88f74f17bb8aa"}, + {file = "yarl-1.24.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:533ded4dceb5f1f3da7906244f4e82cf46cfd40d84c69a1faf5ac506aa65ecbe"}, + {file = "yarl-1.24.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7b3a85525f6e7eeabcfdd372862b21ee1915db1b498a04e8bf0e389b607ff0bd"}, + {file = "yarl-1.24.2-cp314-cp314t-win_amd64.whl", hash = "sha256:a7624b1ca46ca5d7b864ef0d2f8efe3091454085ee1855b4e992314529972215"}, + {file = "yarl-1.24.2-cp314-cp314t-win_arm64.whl", hash = "sha256:e434a45ce2e7a947f951fc5a8944c8cc080b7e59f9c50ae80fd39107cf88126d"}, + {file = "yarl-1.24.2-py3-none-any.whl", hash = "sha256:2783d9226db8797636cd6896e4de81feed252d1db72265686c9558d97a4d94b9"}, + {file = "yarl-1.24.2.tar.gz", hash = "sha256:9ac374123c6fd7abf64d1fec93962b0bd4ee2c19751755a762a72dd96c0378f8"}, ] [package.dependencies] idna = ">=2.0" multidict = ">=4.0" -propcache = ">=0.2.0" +propcache = ">=0.2.1" [metadata] lock-version = "2.0" python-versions = "^3.10,<3.13" -content-hash = "84f9ce0ad56ffab8a5101eba4d9102f9df7d27d3663fdc08aaeafa49f7f467ab" +content-hash = "9a7cd1771fe2f604ab5a55485a5f9338797c503e9ec389cefd8ff8030e6bb288" diff --git a/packages/examples/cvat/exchange-oracle/pyproject.toml b/packages/examples/cvat/exchange-oracle/pyproject.toml index 428e3a87f4..d26d171aff 100644 --- a/packages/examples/cvat/exchange-oracle/pyproject.toml +++ b/packages/examples/cvat/exchange-oracle/pyproject.toml @@ -3,45 +3,46 @@ name = "exchange-oracle" version = "0.1.0" description = "An example of decentralized exchange oracle with CVAT as annotation instrument" authors = ["Sergey Dzeranov "] -readme = "README.md" -packages = [{include = "exchange_oracle"}] +package-mode = false [tool.poetry.dependencies] python = "^3.10,<3.13" -fastapi = {version = "^0.115.4", extras = ["standard"]} +fastapi = {version = "~0.136.0", extras = ["standard"]} # <0.137: avoids the alpha router refactor (breaks fastapi-pagination), >=0.122 finally fixed https://github.com/fastapi/fastapi/issues/2026 uvicorn = ">=0.32.1" # post https://github.com/encode/uvicorn/pull/2397, where using several workers was fixed. Read more https://github.com/encode/uvicorn/discussions/2450 python-dotenv = "^1.0.0" psycopg2 = "^2.9.6" -sqlalchemy-utils = "^0.41.1" +sqlalchemy-utils = "^0.42.1" alembic = "^1.11.1" -httpx = "^0.24.1" -cvat-sdk = "2.37.0" +httpx = "0.28.1" # transitive for fastapi, pinned to the last known secure release +httpx2 = "^2.7.0" # httpx gone, the successor +cvat-sdk = "2.70.0" sqlalchemy = "^2.0.16" apscheduler = "^3.10.1" -xmltodict = "^0.13.0" -datumaro = {git = "https://github.com/cvat-ai/datumaro.git", rev = "ff83c00c2c1bc4b8fdfcc55067fcab0a9b5b6b11"} +datumaro ={git = "https://github.com/cvat-ai/datumaro.git", rev = "ff83c00c2c1bc4b8fdfcc55067fcab0a9b5b6b11"} +numpy = "^1.25.2" boto3 = "^1.28.33" google-cloud-storage = "^2.14.0" -pyinstrument = "^4.6.2" +pyinstrument = "^5.1.2" hexbytes = ">=1.2.0" # required for to_0x_hex() function -pydantic = ">=2.6.1,<2.7.0" -fastapi-pagination = "^0.12.17" +pydantic = "^2.9.0" +fastapi-pagination = "^0.15.15" fastapi-filter = "^1.1.0" -fastapi-limiter = "^0.1.6" +fastapi-limiter = "^0.1.6" # 0.2.0 is a breaking API redesign (FastAPILimiter removed) strenum = "^0.4.15" pyjwt = "^2.9.0" -starlette = ">=0.40.0" # avoid the vulnerability with multipart/form-data +starlette = ">=1.3.1" # avoid the vulnerability with multipart/form-data cryptography = "<44.0.0" # human-protocol-sdk -> pgpy dep requires cryptography < 45 aiocache = {extras = ["msgpack", "redis"], version = "^0.12.3"} # convenient api for redis (async) -cachelib = "^0.13.0" # convenient api for redis (sync) +cachelib = "^0.14.0" # convenient api for redis (sync) human-protocol-sdk = "^7.3.1" [tool.poetry.group.dev.dependencies] -pre-commit = "^3.0.4" -ruff = "^0.6.0" -pytest = "^7.2.2" +pre-commit = "^4.6.0" +ruff = "^0.15.21" +pytest = "^9.0.0" pytest-mock = "^3.14.0" +virtualenv = "<21" # 21.x drops APIs that poetry's build isolation relies on [tool.ruff] line-length = 100 @@ -68,12 +69,10 @@ ignore = [ "COM819", # | "ISC001", # | "ISC002", # | - "ANN101", # Method args annotations (mypy will take care of that) - "ANN001", # | + "ANN001", # Method args annotations (mypy will take care of that) "ANN202", # | "ANN201", # | "ANN401", # | - "ANN102", # | "RUF001", # Allow cyrillic letters in comments "B904", # Raise from: modern pythons preserve previous exceptions @@ -109,6 +108,7 @@ ignore = [ "ANN204", # Missing return type annotation for special method "ERA001", # Found commented-out code "N801", # Class name should use CapWords convention + "PLR0913", # Too many arguments in function definition "PLR0915", # Too many statements "PLR2004", # Magic value used in comparison, consider replacing with a constant variable "ANN002", # Missing type annotation for `*args` @@ -123,6 +123,10 @@ ignore = [ "UP032", # Upgrades .format() to f-strings. Disabling until it ignores line-length "C401", # set comprehensions are apparently can be hard to distinguish from dict comprehensions "RET505", # Unnecessary elif/else statements after/before raise/return. + "PLC0415", # import-outside-top-level + "INP001", # implicit-namespace-package (app is not packaged; package-mode = false) + "FBT001", # boolean-typed positional argument + "DTZ901", # datetime.min/max without tzinfo ] @@ -142,6 +146,8 @@ ignore = [ ] # alembic is not a package in a traditional sense, so putting __init__.py there doesn't make sense "alembic/*" = ["INP001"] +# Standalone maintenance scripts: not importable packages (INP001) and print to stdout (T201). +"tests/assets/utils/*" = ["INP001", "T201"] "__init__.py" = ["F401"] [tool.ruff.lint.pep8-naming] @@ -159,6 +165,11 @@ forced-separate = ["tests"] [tool.ruff.lint.flake8-tidy-imports] ban-relative-imports = "all" +[tool.ruff.lint.flake8-type-checking] +# pydantic models evaluate annotations at runtime, so imports used only in their field types must +# stay at runtime +runtime-evaluated-base-classes = ["pydantic.BaseModel"] + [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" diff --git a/packages/examples/cvat/exchange-oracle/src/__init__.py b/packages/examples/cvat/exchange-oracle/src/__init__.py index a6067b3e7b..e69de29bb2 100644 --- a/packages/examples/cvat/exchange-oracle/src/__init__.py +++ b/packages/examples/cvat/exchange-oracle/src/__init__.py @@ -1,36 +0,0 @@ -import logging - -from fastapi import FastAPI - -from src.core.config import Config -from src.crons import setup_cron_jobs -from src.endpoints import init_api -from src.handlers.error_handlers import setup_error_handlers -from src.log import setup_logging - -setup_logging() - -app = FastAPI( - title="Human Exchange Oracle", - description=""" - Exchange Oracle is a HUMAN oracle which main goal is to: - 1. Receive webhooks from a Job Launcher - 2. Process them and create jobs on CVAT - 3. Retrieve annotations and store them in a s3 bucket - 4. Notify recording oracle that raw annotations are ready - """, - version="0.1.0", -) - -init_api(app) -setup_error_handlers(app) - - -@app.on_event("startup") -async def startup_event(): - logger = logging.getLogger("app") - logger.info("Exchange Oracle is up and running!") - - -if not Config.is_test_mode(): - setup_cron_jobs(app) diff --git a/packages/examples/cvat/exchange-oracle/tests/unit/helpers/__init__.py b/packages/examples/cvat/exchange-oracle/src/apps/__init__.py similarity index 100% rename from packages/examples/cvat/exchange-oracle/tests/unit/helpers/__init__.py rename to packages/examples/cvat/exchange-oracle/src/apps/__init__.py diff --git a/packages/examples/cvat/exchange-oracle/src/apps/exchange_oracle.py b/packages/examples/cvat/exchange-oracle/src/apps/exchange_oracle.py new file mode 100644 index 0000000000..a6067b3e7b --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/apps/exchange_oracle.py @@ -0,0 +1,36 @@ +import logging + +from fastapi import FastAPI + +from src.core.config import Config +from src.crons import setup_cron_jobs +from src.endpoints import init_api +from src.handlers.error_handlers import setup_error_handlers +from src.log import setup_logging + +setup_logging() + +app = FastAPI( + title="Human Exchange Oracle", + description=""" + Exchange Oracle is a HUMAN oracle which main goal is to: + 1. Receive webhooks from a Job Launcher + 2. Process them and create jobs on CVAT + 3. Retrieve annotations and store them in a s3 bucket + 4. Notify recording oracle that raw annotations are ready + """, + version="0.1.0", +) + +init_api(app) +setup_error_handlers(app) + + +@app.on_event("startup") +async def startup_event(): + logger = logging.getLogger("app") + logger.info("Exchange Oracle is up and running!") + + +if not Config.is_test_mode(): + setup_cron_jobs(app) diff --git a/packages/examples/cvat/exchange-oracle/src/chain/escrow.py b/packages/examples/cvat/exchange-oracle/src/chain/escrow.py index df4deed4ad..43b72a28f1 100644 --- a/packages/examples/cvat/exchange-oracle/src/chain/escrow.py +++ b/packages/examples/cvat/exchange-oracle/src/chain/escrow.py @@ -1,7 +1,7 @@ import json from functools import partial -import httpx +import httpx2 from human_protocol_sdk.constants import ChainId, Status from human_protocol_sdk.encryption import Encryption, EncryptionUtils from human_protocol_sdk.escrow import EscrowData, EscrowUtils @@ -20,7 +20,7 @@ class ManifestNotAvailableError(Exception): def _get_manifest_content(manifest: str) -> str: if validate_url(manifest): try: - response = httpx.get(manifest, follow_redirects=True) + response = httpx2.get(manifest, follow_redirects=True) response.raise_for_status() except Exception as e: raise ManifestNotAvailableError( diff --git a/packages/examples/cvat/exchange-oracle/src/core/config.py b/packages/examples/cvat/exchange-oracle/src/core/config.py index 10d5bb3a5e..87a024ca00 100644 --- a/packages/examples/cvat/exchange-oracle/src/core/config.py +++ b/packages/examples/cvat/exchange-oracle/src/core/config.py @@ -4,7 +4,6 @@ import inspect import os from collections.abc import Iterable -from enum import Enum from os import getenv from typing import ClassVar, Optional @@ -14,6 +13,7 @@ from web3 import Web3 from web3.providers.rpc import HTTPProvider +from src.utils.enums import StrEnum from src.utils.logging import parse_log_level from src.utils.net import is_ipv4 @@ -321,7 +321,7 @@ class DevelopmentConfig: """ -class Environment(str, Enum): +class Environment(StrEnum): PRODUCTION = "production" DEVELOPMENT = "development" TEST = "test" diff --git a/packages/examples/cvat/exchange-oracle/src/core/manifest/__init__.py b/packages/examples/cvat/exchange-oracle/src/core/manifest/__init__.py new file mode 100644 index 0000000000..5d91f29f36 --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/core/manifest/__init__.py @@ -0,0 +1,38 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + +from src.core.manifest import v1, v2 +from src.core.manifest.base import ManifestBase + +if TYPE_CHECKING: + from src.core.tasks import TaskTypes + +__all__ = [ + "ManifestBase", + "get_manifest_task_type", + "parse_manifest", + "v1", + "v2", +] + + +def parse_manifest(manifest: Any) -> ManifestBase: + if isinstance(manifest, dict): + version = manifest.get("version") + else: + version = getattr(manifest, "version", None) + + if version == 2: + return v2.JobManifest.model_validate(manifest) + else: + return v1.JobManifest.model_validate(manifest) + + +def get_manifest_task_type(manifest: ManifestBase) -> TaskTypes: + if isinstance(manifest, v1.JobManifest): + return manifest.annotation.type + if isinstance(manifest, v2.JobManifest): + return manifest.job_type + + raise NotImplementedError(f"Unknown manifest version '{manifest.version}'") diff --git a/packages/examples/cvat/exchange-oracle/src/core/manifest/base.py b/packages/examples/cvat/exchange-oracle/src/core/manifest/base.py new file mode 100644 index 0000000000..5c14e1bc11 --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/core/manifest/base.py @@ -0,0 +1,6 @@ +from typing import Protocol, runtime_checkable + + +@runtime_checkable +class ManifestBase(Protocol): + version: int diff --git a/packages/examples/cvat/recording-oracle/src/core/manifest.py b/packages/examples/cvat/exchange-oracle/src/core/manifest/shared.py similarity index 50% rename from packages/examples/cvat/recording-oracle/src/core/manifest.py rename to packages/examples/cvat/exchange-oracle/src/core/manifest/shared.py index ca19196555..1a61fc3774 100644 --- a/packages/examples/cvat/recording-oracle/src/core/manifest.py +++ b/packages/examples/cvat/exchange-oracle/src/core/manifest/shared.py @@ -1,14 +1,11 @@ -from decimal import Decimal -from enum import Enum from typing import Annotated, Any, Literal -from pydantic import AnyUrl, BaseModel, Field, model_validator +from pydantic import BaseModel, Field, model_validator -from src.core.types import TaskTypes -from src.utils.enums import BetterEnumMeta +from src.utils.enums import BetterEnumMeta, StrEnum -class BucketProviders(str, Enum): +class BucketProviders(StrEnum): aws = "AWS" gcs = "GCS" @@ -34,28 +31,14 @@ class GcsBucketUrl(BucketUrlBase, BaseModel): BucketUrl = Annotated[AwsBucketUrl | GcsBucketUrl, Field(discriminator="provider")] -class DataInfo(BaseModel): - data_url: AnyUrl | BucketUrl - "Bucket URL, AWS S3 | GCS, virtual-hosted-style access" - # https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-bucket-intro.html - - points_url: AnyUrl | BucketUrl | None = None - "A path to an archive with a set of points in COCO Keypoints format, " - "which provides information about all objects on images" - - boxes_url: AnyUrl | BucketUrl | None = None - "A path to an archive with a set of boxes in COCO Instances format, " - "which provides information about all objects on images" - - -class LabelTypes(str, Enum, metaclass=BetterEnumMeta): +class LabelTypes(StrEnum, metaclass=BetterEnumMeta): plain = "plain" skeleton = "skeleton" class LabelInfoBase(BaseModel): name: str = Field(min_length=1) - # https://opencv.github.io/cvat/docs/api_sdk/sdk/reference/models/label/ + # https://docs.cvat.ai/docs/api_sdk/sdk/reference/models/label/ type: LabelTypes = LabelTypes.plain @@ -119,67 +102,3 @@ def validate_type(cls, values: dict[str, Any]) -> dict[str, Any]: LabelInfo = Annotated[PlainLabelInfo | SkeletonLabelInfo, Field(discriminator="type")] - - -class AnnotationInfo(BaseModel): - type: TaskTypes - - labels: list[LabelInfo] = Field(min_length=1) - "Label declarations with accepted annotation types" - - description: str = "" - "Brief task description" - - user_guide: str = "" - "User guide in markdown format" - - job_size: int = 10 - "Frames per job, validation frames are not included" - - @model_validator(mode="before") - @classmethod - def validate_label_type(cls, values: dict[str, Any]) -> dict[str, Any]: - if not isinstance(values, dict): - raise NotImplementedError - - default_label_type = LabelTypes.plain - if values["type"] == TaskTypes.image_skeletons_from_boxes: - default_label_type = LabelTypes.skeleton - - # Add default value for labels, if none provided. - # pydantic can't do this for tagged unions - try: - labels = values["labels"] - for label_info in labels: - label_info["type"] = label_info.get("type", default_label_type) - except KeyError: - pass - - return values - - -class ValidationInfo(BaseModel): - min_quality: float = Field(ge=0) - "Minimal accepted annotation accuracy" - - val_size: int = Field(default=2, gt=0) - "Validation frames per job" - - gt_url: AnyUrl | BucketUrl - "URL to the archive with Ground Truth annotations, the format is COCO keypoints" - - -class TaskManifest(BaseModel): - data: DataInfo - annotation: AnnotationInfo - validation: ValidationInfo - - job_bounty: Decimal = Field(ge=0) - "Assignment bounty, a decimal value in HMT" - - qualifications: list[str] = Field(default_factory=list) - "A list of annotator qualifications required for participation" - - -def parse_manifest(manifest: Any) -> TaskManifest: - return TaskManifest.model_validate(manifest) diff --git a/packages/examples/cvat/exchange-oracle/src/core/manifest/v1.py b/packages/examples/cvat/exchange-oracle/src/core/manifest/v1.py new file mode 100644 index 0000000000..1b774ebd5f --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/core/manifest/v1.py @@ -0,0 +1,83 @@ +from decimal import Decimal +from typing import Any, Literal + +from pydantic import AnyUrl, BaseModel, Field, model_validator + +from src.core.manifest.shared import BucketUrl, LabelInfo, LabelTypes +from src.core.tasks import TaskTypes + + +class DataInfo(BaseModel): + data_url: AnyUrl | BucketUrl + "Bucket URL, AWS S3 | GCS, virtual-hosted-style access" + # https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-bucket-intro.html + + points_url: AnyUrl | BucketUrl | None = None + "A path to an archive with a set of points in COCO Keypoints format, " + "which provides information about all objects on images" + + boxes_url: AnyUrl | BucketUrl | None = None + "A path to an archive with a set of boxes in COCO Instances format, " + "which provides information about all objects on images" + + +class AnnotationInfo(BaseModel): + type: TaskTypes + + labels: list[LabelInfo] = Field(min_length=1) + "Label declarations with accepted annotation types" + + description: str = "" + "Brief task description" + + user_guide: str = "" + "User guide in markdown format" + + job_size: int = 10 + "Frames per job, validation frames are not included" + + qualifications: list[str] = Field(default_factory=list) + "A list of annotator qualifications required for participation" + + @model_validator(mode="before") + @classmethod + def validate_label_type(cls, values: dict[str, Any]) -> dict[str, Any]: + if not isinstance(values, dict): + raise NotImplementedError + + default_label_type = LabelTypes.plain + if values["type"] == TaskTypes.image_skeletons_from_boxes: + default_label_type = LabelTypes.skeleton + + # Add default value for labels, if none provided. + # pydantic can't do this for tagged unions + try: + labels = values["labels"] + for label_info in labels: + label_info["type"] = label_info.get("type", default_label_type) + except KeyError: + pass + + return values + + +class ValidationInfo(BaseModel): + min_quality: float = Field(ge=0) + "Minimal accepted annotation accuracy" + + val_size: int = Field(default=2, gt=0) + "Validation frames per job" + + gt_url: AnyUrl | BucketUrl + "URL to the archive with Ground Truth annotations, the format is COCO keypoints" + + +class JobManifest(BaseModel): + version: Literal[1] = 1 + + data: DataInfo + annotation: AnnotationInfo + validation: ValidationInfo + + job_bounty: Decimal = Field(ge=0) + "Assignment bounty, a decimal value in HMT" diff --git a/packages/examples/cvat/exchange-oracle/src/core/manifest/v2.py b/packages/examples/cvat/exchange-oracle/src/core/manifest/v2.py new file mode 100644 index 0000000000..228986d72f --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/core/manifest/v2.py @@ -0,0 +1,170 @@ +from copy import deepcopy +from typing import Any, Literal + +from pydantic import AnyUrl, BaseModel, ConfigDict, Field, model_validator + +from src.core.manifest.shared import BucketUrl, LabelInfo, LabelTypes +from src.core.tasks import TaskTypes +from src.utils.enums import BetterEnumMeta, StrEnum + + +class DataInfo(BaseModel): + media_url: AnyUrl | BucketUrl + "Bucket URL, AWS S3 | GCS, virtual-hosted-style access" + + gt_url: AnyUrl | BucketUrl + "URL to the archive with Ground Truth annotations" + + points_url: AnyUrl | BucketUrl | None = None + """ + A path to a file or an archive with a set of points in COCO Keypoints format. + Applicable for: image_boxes_from_points + """ + + boxes_url: AnyUrl | BucketUrl | None = None + """ + A path to a file or an archive with a set of boxes in COCO Instances format. + Applicable for: image_skeletons_from_boxes + """ + + regions_url: AnyUrl | BucketUrl | None = None + """ + A path to a file or an archive with audio regions in the CVAT Generic TSV format. + Applicable for: audio_transcription + """ + + +class TargetMetrics(StrEnum, metaclass=BetterEnumMeta): + accuracy = "accuracy" + wer = "wer" + cer = "cer" + + +class ValidationInfo(BaseModel): + target_score: float = Field(ge=0) + "Required annotation score. Can be minimal or maximal depending on the metric used" + + target_metric: TargetMetrics = TargetMetrics.accuracy + "Metric used to score annotations against the target" + + +class MinComposition(BaseModel): + gt: int + "Minimal number of Ground Truth samples per composition" + + ds: int + "Minimal number of dataset samples per composition" + + +class DetailsInfoBase(BaseModel): + model_config = ConfigDict(extra="forbid") + + max_time: int | None = None + "Maximum assignment time, seconds" + + +class ImageJobDetails(DetailsInfoBase): + job_size: int | None = None + "Frames per job, validation frames are not included" + + val_size: int | None = None + "Validation frames per job" + + +class AudioJobDetails(DetailsInfoBase): + normalizer: str | None = "basic" + "Text normalizer for audio transcription" + + max_segment_duration: int | None = None + "Maximum audio segment duration, seconds" + + min_gt_span_duration: int | None = None + """ + Minimum duration of densely-annotated GT regions, in seconds. + Each is expected to contain 1 or more annotated intervals inside. + A span is identified by the span_id field. + """ + + min_composition: MinComposition | None = None + "Minimal composition of a job" + + validation_overhead: int | None = None + "Extra validation samples added on top of the required amount" + + boundary_tolerance: int | None = None + "Allowed annotation/GT interval boundary misalignment at honeypots, milliseconds" + + +DetailsInfo = ImageJobDetails | AudioJobDetails + + +class SharedAttribute(BaseModel): + name: str = Field(min_length=1) + type: str + values: list[str] = Field(default_factory=list) + default_value: str = "" + + +class AnnotationInfo(BaseModel): + description: str = "" + "Brief task description" + + user_guide_url: str = "" + "URL to the user guide in markdown format" + + labels: list[LabelInfo] = Field(min_length=1) + "Label declarations with accepted annotation types" + + shared_attributes: list[SharedAttribute] = Field(default_factory=list) + "Shared annotation attributes" + + validation: ValidationInfo + + qualifications: list[str] = Field(default_factory=list) + "A list of annotator qualifications required for participation" + + details: ImageJobDetails | AudioJobDetails | None = None + "Task-specific details" + + +class JobManifest(BaseModel): + version: Literal[2] + + job_type: TaskTypes + data: DataInfo + annotation: AnnotationInfo + + @model_validator(mode="before") + @classmethod + def parse_task_specific_params(cls, values: dict[str, Any]) -> dict[str, Any]: + if not isinstance(values, dict): + raise NotImplementedError + + values = deepcopy(values) # copy before mutating + + job_type = values.get("job_type") + + annotation = values.get("annotation") + if not isinstance(annotation, dict): + raise NotImplementedError + + # Default label types (pydantic can't do this for tagged unions). + default_label_type = ( + LabelTypes.skeleton + if job_type == TaskTypes.image_skeletons_from_boxes + else LabelTypes.plain + ) + for label_info in annotation.get("labels", []): + if isinstance(label_info, dict): + label_info.setdefault("type", default_label_type) + + if details := annotation.get("details"): + if not isinstance(details, dict): + raise NotImplementedError + + details_cls = ( + AudioJobDetails if job_type == TaskTypes.audio_transcription else ImageJobDetails + ) + annotation["details"] = details_cls.model_validate(details) + + return values diff --git a/packages/examples/cvat/exchange-oracle/src/core/tasks/__init__.py b/packages/examples/cvat/exchange-oracle/src/core/tasks/__init__.py index e69de29bb2..3f24f51e5c 100644 --- a/packages/examples/cvat/exchange-oracle/src/core/tasks/__init__.py +++ b/packages/examples/cvat/exchange-oracle/src/core/tasks/__init__.py @@ -0,0 +1,7 @@ +from src.core.tasks import errors +from src.core.tasks.types import TaskTypes + +__all__ = [ + "TaskTypes", + "errors", +] diff --git a/packages/examples/cvat/exchange-oracle/src/core/tasks/audio_transcription/__init__.py b/packages/examples/cvat/exchange-oracle/src/core/tasks/audio_transcription/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/examples/cvat/exchange-oracle/src/core/tasks/audio_transcription/meta.py b/packages/examples/cvat/exchange-oracle/src/core/tasks/audio_transcription/meta.py new file mode 100644 index 0000000000..1f7c45f2c3 --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/core/tasks/audio_transcription/meta.py @@ -0,0 +1,252 @@ +"""Domain types and meta persistence for audio transcription tasks. + +Regions are mixed across input files into assignments, so every region carries its own source +provenance. The persisted mappings (regions + assignments) let each region be located back in its +source media after mixing. +""" + +from __future__ import annotations + +import csv +import io +import time +from datetime import timedelta + +from attrs import Factory, frozen +from datumaro.util import dump_json, parse_json + +from src.utils.enums import BetterEnumMeta, StrEnum + +CVAT_EXPORT_FORMAT = "Generic TSV 1.0" + + +def parse_time(value: str) -> timedelta: + """Parse an ``H:MM:SS(.ffffff)`` timestamp (as used in the region/GT TSVs).""" + for fmt_string in ("%H:%M:%S.%f", "%H:%M:%S"): + try: + parsed_time = time.strptime(value, fmt_string) + if fmt_string.endswith(".%f"): + # time.strptime drops sub-second precision, so recover it from the raw string. + frac = value.split(".", maxsplit=1)[-1] + microseconds = int(frac.ljust(6, "0")[:6]) + else: + microseconds = 0 + except ValueError: + continue + else: + return timedelta( + hours=parsed_time.tm_hour, + minutes=parsed_time.tm_min, + seconds=parsed_time.tm_sec, + microseconds=microseconds, + ) + + raise ValueError(f"Failed to parse timestamp '{value}'") + + +def format_time(value: timedelta) -> str: + """Render a timedelta as an ``H:MM:SS.ffffff`` timestamp.""" + total = value.total_seconds() + h = int(total // 3600) + m = int((total % 3600) // 60) + s = total - h * 3600 - m * 60 + return f"{h}:{m:02d}:{s:09.6f}" + + +@frozen(kw_only=True) +class InputRegion: + """A region to annotate, parsed from the input regions TSV.""" + + filename: str + start: timedelta + stop: timedelta + label: str | None = None + row_idx: int + + @property + def id(self) -> str: + return f"{self.filename}:{self.row_idx}" + + +@frozen(kw_only=True) +class InputGtRegion: + """A ground-truth region, parsed from the input GT TSV.""" + + filename: str + start: timedelta + stop: timedelta + label: str + text: str + row_idx: int + span_id: str + + @property + def id(self) -> str: + return f"{self.filename}:{self.row_idx}" + + +def parse_gt_tsv(data: bytes) -> list[InputGtRegion]: + reader = csv.DictReader(io.StringIO(data.decode("utf-8")), delimiter="\t") + return [ + InputGtRegion( + filename=row["filename"].strip(), + row_idx=row_idx, + start=parse_time(row["start"]), + stop=parse_time(row["stop"]), + label=row["label"].strip(), + text=row["text"].strip(), + span_id=row["span_id"].strip(), + ) + for row_idx, row in enumerate(reader) + ] + + +class RegionKind(StrEnum, metaclass=BetterEnumMeta): + gt = "gt" # ground-truth honeypot region + ds = "ds" # regular dataset region to annotate + + +@frozen(kw_only=True) +class PresentedRegion: + "A bundle of consecutive input ROIs from one source file, presented as a single region." + + source_filename: str + start: float # bundle span (file-time seconds): first ROI start .. last ROI stop + stop: float + kind: RegionKind + input_ids: list[str] = Factory(list) + + @property + def duration(self) -> float: + return self.stop - self.start + + +@frozen(kw_only=True) +class PlacedRegion: + "A presented region placed in an assignment" + + index: int # 0-based position within the assignment clip + source_filename: str + source_start: float + source_stop: float + clip_start: float + clip_stop: float + kind: RegionKind + input_ids: list[str] = Factory(list) # ids of the input ROIs this bundle was built from + + +@frozen(kw_only=True) +class Clip: + """A single concatenated audio clip built from ``placed`` regions (one per CVAT task).""" + + id: str + clip_filename: str + clip_duration: float + placed: list[PlacedRegion] = Factory(list) + + +def _region_to_dict(r: PresentedRegion) -> dict: + return { + "source_filename": r.source_filename, + "start": r.start, + "stop": r.stop, + "kind": r.kind.value, + "input_ids": list(r.input_ids), + } + + +def _region_from_dict(d: dict) -> PresentedRegion: + return PresentedRegion( + source_filename=d["source_filename"], + start=d["start"], + stop=d["stop"], + kind=RegionKind(d["kind"]), + input_ids=list(d.get("input_ids", [])), + ) + + +def _placed_to_dict(r: PlacedRegion) -> dict: + return { + "index": r.index, + "source_filename": r.source_filename, + "source_start": r.source_start, + "source_stop": r.source_stop, + "clip_start": r.clip_start, + "clip_stop": r.clip_stop, + "kind": r.kind.value, + "input_ids": list(r.input_ids), + } + + +def _placed_from_dict(d: dict) -> PlacedRegion: + return PlacedRegion( + index=d["index"], + source_filename=d["source_filename"], + source_start=d["source_start"], + source_stop=d["source_stop"], + clip_start=d["clip_start"], + clip_stop=d["clip_stop"], + kind=RegionKind(d["kind"]), + input_ids=list(d.get("input_ids", [])), + ) + + +class TaskMetaLayout: + CLIPS_DIR = "clips" # assignment clips subdir on the oracle bucket + GT_FILENAME = "gt.tsv" + REGIONS_TSV_FILENAME = "regions.tsv" + REGIONS_FILENAME = "regions.json" + CLIPS_FILENAME = "assignments.json" + TASK_CLIPS_FILENAME = "task_clips.json" + DS_CUTS_DIR = "ds_cuts" + GT_CUTS_DIR = "gt_cuts" + + +class TaskResultsLayout: + "Layout of the escrow results dir on the oracle bucket." + + ASSIGNMENTS_DIR = "assignments" # per-assignment annotation TSVs (one per CVAT job) + ANNOTATIONS_FILENAME = "annotations.tsv" # merged annotations (without honeypots or GT) + + @classmethod + def assignment_annotation_filename(cls, job_id: int, assignment_id: str) -> str: + "Path (relative to the results dir) of a job's per-assignment annotation TSV." + return f"{cls.ASSIGNMENTS_DIR}/{job_id}-{assignment_id}.tsv" + + +class TaskMetaSerializer: + def serialize_regions(self, regions: list[PresentedRegion]) -> bytes: + return dump_json([_region_to_dict(r) for r in regions]) + + def parse_regions(self, data: bytes) -> list[PresentedRegion]: + return [_region_from_dict(d) for d in parse_json(data)] + + def serialize_clips(self, clips: list[Clip]) -> bytes: + return dump_json( + [ + { + "id": clip.id, + "clip_filename": clip.clip_filename, + "clip_dur": clip.clip_duration, + "placed": [_placed_to_dict(p) for p in clip.placed], + } + for clip in clips + ] + ) + + def parse_clips(self, data: bytes) -> list[Clip]: + return [ + Clip( + id=d["id"], + clip_filename=d["clip_filename"], + clip_duration=d["clip_dur"], + placed=[_placed_from_dict(p) for p in d.get("placed", [])], + ) + for d in parse_json(data) + ] + + def serialize_task_clips(self, task_clips: dict[int, str]) -> bytes: + return dump_json({str(task_id): clip_id for task_id, clip_id in task_clips.items()}) + + def parse_task_clips(self, data: bytes) -> dict[int, str]: + return {int(task_id): clip_id for task_id, clip_id in parse_json(data).items()} diff --git a/packages/examples/cvat/exchange-oracle/src/core/tasks/audio_transcription/spec.py b/packages/examples/cvat/exchange-oracle/src/core/tasks/audio_transcription/spec.py new file mode 100644 index 0000000000..7f688c983e --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/core/tasks/audio_transcription/spec.py @@ -0,0 +1,170 @@ +from __future__ import annotations + +from datetime import timedelta +from typing import TYPE_CHECKING + +from pydantic import AnyUrl, BaseModel, Field + +from src.core.manifest.shared import BucketUrl +from src.core.manifest.v2 import TargetMetrics +from src.core.tasks.errors import UnsupportedManifestError +from src.utils.enums import BetterEnumMeta, StrEnum + +if TYPE_CHECKING: + from src.core.manifest.v2 import JobManifest + + +class NormalizerPreset(StrEnum, metaclass=BetterEnumMeta): + basic = "basic" # universal Unicode + case + whitespace fold + # Tier-1 language presets (BASIC plus per-language rules) + en = "en" + es = "es" + fr = "fr" + de = "de" + it = "it" + pt = "pt" + nl = "nl" + pl = "pl" + ru = "ru" + tr = "tr" + zh = "zh" + ja = "ja" + ko = "ko" + hi = "hi" + ar = "ar" + + +class TranscriptionTaskData(BaseModel): + media_url: AnyUrl | BucketUrl + regions_url: AnyUrl | BucketUrl + gt_url: AnyUrl | BucketUrl + + +class TranscriptionTaskValidation(BaseModel): + target_metric: TargetMetrics + target_score: float + + +class TranscriptionDetails(BaseModel): + assignment_time_limit: timedelta | None = None + "Maximum time to complete an assignment" + + validation_overhead: float = 0.2 + "Honeypot share of the assignment duration" + + normalizer: NormalizerPreset | None = NormalizerPreset.basic + "Text normalization for transcriptions" + + min_composition: tuple[int, int] = (2, 2) + "(gt, ds): minimum number of honeypot and DS regions per assignment" + + min_gt_span_duration: timedelta = timedelta(seconds=30) + """ + Minimum duration of densely-annotated GT regions, in seconds. + Each is expected to contain 1 or more annotated intervals inside. + A span is identified by the span_id field. + """ + + roi_min_duration: timedelta = timedelta(seconds=5) + "Minimum presented region duration. Smaller segments are bundled together" + + roi_max_duration: timedelta = timedelta(seconds=120) + "Maximum presented region duration. Used for input validation" + + roi_join_pause: timedelta = timedelta(milliseconds=700) + "Silence inserted between concatenated regions in an assignment clip" + + boundary_tolerance: timedelta = timedelta(milliseconds=200) + "Allowed joined annotation/GT interval boundary misalignment when matching transcriptions" + + standard_assignment_duration: timedelta = timedelta(seconds=60) + "Target audio duration per assignment" + + # TODO: add honeypot rotation later + # max_validation_gt: float = 0.05 + # "Maximum share of GT regions used as honeypots. The rest is used for honeypot rotation" + + max_discarded_gt: float = 0.5 + "Maximum share of GT regions that may be discarded before job creation fails" + + sample_rate: int = 48000 + "Sample rate of the generated assignment clips, Hz" + + transcription_attr_name: str = "transcription" + "The name of the output attribute for transcriptions in CVAT tasks and annotations" + + random_seed: int = 0 + "Seed for deterministic honeypot selection and assignment mixing" + + +class TranscriptionTaskSpecification(BaseModel): + data: TranscriptionTaskData + + labels: list[str] + shared_attributes: list = Field(default_factory=list) + user_guide: str = "" + + validation: TranscriptionTaskValidation + + details: TranscriptionDetails = Field(default_factory=TranscriptionDetails) + + +def parse_audio_manifest(manifest: JobManifest) -> TranscriptionTaskSpecification: + """ + Produce the task specification from a manifest, encapsulating manifest-version differences. + + Only v2 manifests are supported. + """ + + version = getattr(manifest, "version", 1) + if version != 2: + raise UnsupportedManifestError( + f"Audio transcription requires a v2 manifest, got version {version}" + ) + + annotation = manifest.annotation + validation = annotation.validation + manifest_details = annotation.details + + # Only pass the details fields the manifest provides; pydantic fills the rest with defaults + # and coerces raw values (e.g. normalizer str -> NormalizerPreset). + details_fields: dict = {} + if manifest_details is not None: + if manifest_details.max_segment_duration is not None: + details_fields["roi_max_duration"] = timedelta( + seconds=manifest_details.max_segment_duration + ) + if manifest_details.min_gt_span_duration is not None: + details_fields["min_gt_span_duration"] = timedelta( + seconds=manifest_details.min_gt_span_duration + ) + if manifest_details.boundary_tolerance is not None: + details_fields["boundary_tolerance"] = timedelta( + milliseconds=manifest_details.boundary_tolerance + ) + if manifest_details.validation_overhead is not None: + details_fields["validation_overhead"] = manifest_details.validation_overhead / 100.0 + if manifest_details.min_composition is not None: + details_fields["min_composition"] = ( + manifest_details.min_composition.gt, + manifest_details.min_composition.ds, + ) + details_fields["normalizer"] = manifest_details.normalizer + if manifest_details.max_time is not None: + details_fields["assignment_time_limit"] = timedelta(seconds=manifest_details.max_time) + + return TranscriptionTaskSpecification( + data=TranscriptionTaskData( + media_url=manifest.data.media_url, + regions_url=manifest.data.regions_url, + gt_url=manifest.data.gt_url, + ), + labels=[label.name for label in annotation.labels], + shared_attributes=list(annotation.shared_attributes), + user_guide=annotation.user_guide_url, + validation=TranscriptionTaskValidation( + target_metric=validation.target_metric, + target_score=validation.target_score, + ), + details=TranscriptionDetails(**details_fields), + ) diff --git a/packages/examples/cvat/exchange-oracle/src/core/tasks/boxes_from_points.py b/packages/examples/cvat/exchange-oracle/src/core/tasks/boxes_from_points.py index 747d3a1c09..5a3dadec0e 100644 --- a/packages/examples/cvat/exchange-oracle/src/core/tasks/boxes_from_points.py +++ b/packages/examples/cvat/exchange-oracle/src/core/tasks/boxes_from_points.py @@ -97,9 +97,9 @@ def parse_roi_filenames(self, roi_filenames_data: bytes) -> RoiFilenames: __all__ = [ "OUTPUT_OBJECT_ID_ATTR", "BboxPointMapping", + "RoiFilenames", "RoiInfo", "RoiInfos", - "RoiFilenames", "TaskMetaLayout", "TaskMetaSerializer", ] diff --git a/packages/examples/cvat/exchange-oracle/src/core/tasks/cvat_formats.py b/packages/examples/cvat/exchange-oracle/src/core/tasks/cvat_formats.py new file mode 100644 index 0000000000..a2a465c891 --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/core/tasks/cvat_formats.py @@ -0,0 +1,22 @@ +from __future__ import annotations + +from src.core.tasks.types import TaskTypes + +DM_DATASET_FORMAT_MAPPING = { + TaskTypes.image_label_binary: "cvat_images", + TaskTypes.image_points: "coco_person_keypoints", + TaskTypes.image_boxes: "coco_instances", + TaskTypes.image_polygons: "coco_instances", + TaskTypes.image_boxes_from_points: "coco_instances", + TaskTypes.image_skeletons_from_boxes: "coco_person_keypoints", +} + +DM_GT_DATASET_FORMAT_MAPPING = { + # GT uses the same format both for boxes and points + TaskTypes.image_label_binary: "cvat_images", + TaskTypes.image_points: "coco_instances", + TaskTypes.image_boxes: "coco_instances", + TaskTypes.image_polygons: "coco_instances", + TaskTypes.image_boxes_from_points: "coco_instances", + TaskTypes.image_skeletons_from_boxes: "coco_person_keypoints", +} diff --git a/packages/examples/cvat/exchange-oracle/src/core/tasks/errors.py b/packages/examples/cvat/exchange-oracle/src/core/tasks/errors.py new file mode 100644 index 0000000000..6f002952f7 --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/core/tasks/errors.py @@ -0,0 +1,2 @@ +class UnsupportedManifestError(Exception): + pass diff --git a/packages/examples/cvat/exchange-oracle/src/core/tasks/skeletons_from_boxes.py b/packages/examples/cvat/exchange-oracle/src/core/tasks/skeletons_from_boxes.py index 0809d65316..606e3f6edc 100644 --- a/packages/examples/cvat/exchange-oracle/src/core/tasks/skeletons_from_boxes.py +++ b/packages/examples/cvat/exchange-oracle/src/core/tasks/skeletons_from_boxes.py @@ -138,11 +138,11 @@ def parse_point_labels(self, point_labels_data: bytes) -> PointLabelsMapping: __all__ = [ "OUTPUT_OBJECT_ID_ATTR", - "SkeletonBboxMapping", + "PointLabelsMapping", + "RoiFilenames", "RoiInfo", "RoiInfos", - "RoiFilenames", - "PointLabelsMapping", + "SkeletonBboxMapping", "TaskMetaLayout", "TaskMetaSerializer", ] diff --git a/packages/examples/cvat/exchange-oracle/src/core/tasks/types.py b/packages/examples/cvat/exchange-oracle/src/core/tasks/types.py new file mode 100644 index 0000000000..0233a8cc69 --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/core/tasks/types.py @@ -0,0 +1,13 @@ +from strenum import StrEnum + +from src.utils.enums import BetterEnumMeta + + +class TaskTypes(StrEnum, metaclass=BetterEnumMeta): + image_label_binary = "image_label_binary" + image_points = "image_points" + image_boxes = "image_boxes" + image_boxes_from_points = "image_boxes_from_points" + image_skeletons_from_boxes = "image_skeletons_from_boxes" + image_polygons = "image_polygons" + audio_transcription = "audio_transcription" diff --git a/packages/examples/cvat/exchange-oracle/src/core/types.py b/packages/examples/cvat/exchange-oracle/src/core/types.py index 091e2d6133..96a2c92459 100644 --- a/packages/examples/cvat/exchange-oracle/src/core/types.py +++ b/packages/examples/cvat/exchange-oracle/src/core/types.py @@ -1,16 +1,16 @@ -from enum import Enum +from enum import IntEnum from src.core.config import Config -from src.utils.enums import BetterEnumMeta +from src.utils.enums import BetterEnumMeta, StrEnum -class Networks(int, Enum, metaclass=BetterEnumMeta): +class Networks(IntEnum, metaclass=BetterEnumMeta): polygon_mainnet = Config.polygon_mainnet.chain_id polygon_amoy = Config.polygon_amoy.chain_id localhost = Config.localhost.chain_id -class ProjectStatuses(str, Enum, metaclass=BetterEnumMeta): +class ProjectStatuses(StrEnum, metaclass=BetterEnumMeta): creation = "creation" annotation = "annotation" completed = "completed" @@ -20,67 +20,58 @@ class ProjectStatuses(str, Enum, metaclass=BetterEnumMeta): deleted = "deleted" -class TaskStatuses(str, Enum, metaclass=BetterEnumMeta): +class TaskStatuses(StrEnum, metaclass=BetterEnumMeta): annotation = "annotation" completed = "completed" -class JobStatuses(str, Enum, metaclass=BetterEnumMeta): +class JobStatuses(StrEnum, metaclass=BetterEnumMeta): new = "new" in_progress = "in progress" completed = "completed" -class TaskTypes(str, Enum, metaclass=BetterEnumMeta): - image_label_binary = "image_label_binary" - image_points = "image_points" - image_boxes = "image_boxes" - image_boxes_from_points = "image_boxes_from_points" - image_skeletons_from_boxes = "image_skeletons_from_boxes" - image_polygons = "image_polygons" - - -class OracleWebhookTypes(str, Enum, metaclass=BetterEnumMeta): +class OracleWebhookTypes(StrEnum, metaclass=BetterEnumMeta): exchange_oracle = "exchange_oracle" job_launcher = "job_launcher" recording_oracle = "recording_oracle" reputation_oracle = "reputation_oracle" -class ExchangeOracleEventTypes(str, Enum, metaclass=BetterEnumMeta): +class ExchangeOracleEventTypes(StrEnum, metaclass=BetterEnumMeta): escrow_failed = "escrow_failed" job_finished = "job_finished" escrow_cleaned = "escrow_cleaned" escrow_recorded = "escrow_recorded" -class JobLauncherEventTypes(str, Enum, metaclass=BetterEnumMeta): +class JobLauncherEventTypes(StrEnum, metaclass=BetterEnumMeta): escrow_created = "escrow_created" escrow_canceled = "escrow_canceled" -class RecordingOracleEventTypes(str, Enum, metaclass=BetterEnumMeta): +class RecordingOracleEventTypes(StrEnum, metaclass=BetterEnumMeta): job_completed = "job_completed" submission_rejected = "submission_rejected" -class ReputationOracleEventTypes(str, Enum, metaclass=BetterEnumMeta): +class ReputationOracleEventTypes(StrEnum, metaclass=BetterEnumMeta): escrow_completed = "escrow_completed" -class OracleWebhookStatuses(str, Enum, metaclass=BetterEnumMeta): +class OracleWebhookStatuses(StrEnum, metaclass=BetterEnumMeta): pending = "pending" completed = "completed" failed = "failed" -class CvatWebhookStatuses(str, Enum, metaclass=BetterEnumMeta): +class CvatWebhookStatuses(StrEnum, metaclass=BetterEnumMeta): pending = "pending" completed = "completed" failed = "failed" -class AssignmentStatuses(str, Enum, metaclass=BetterEnumMeta): +class AssignmentStatuses(StrEnum, metaclass=BetterEnumMeta): """ State changes: @@ -95,7 +86,7 @@ class AssignmentStatuses(str, Enum, metaclass=BetterEnumMeta): canceled = "canceled" -class EscrowValidationStatuses(str, Enum, metaclass=BetterEnumMeta): +class EscrowValidationStatuses(StrEnum, metaclass=BetterEnumMeta): awaiting = "awaiting" in_progress = "in_progress" completed = "completed" diff --git a/packages/examples/cvat/exchange-oracle/src/crons/_cron_job.py b/packages/examples/cvat/exchange-oracle/src/crons/_cron_job.py index 2ed2b83b2c..ec0ce7c929 100644 --- a/packages/examples/cvat/exchange-oracle/src/crons/_cron_job.py +++ b/packages/examples/cvat/exchange-oracle/src/crons/_cron_job.py @@ -6,7 +6,7 @@ from sqlalchemy.orm import Session -from src import Config +from src.core.config import Config from src.db import SessionLocal from src.log import get_logger_name diff --git a/packages/examples/cvat/exchange-oracle/src/crons/cvat/state_trackers.py b/packages/examples/cvat/exchange-oracle/src/crons/cvat/state_trackers.py index f841397b45..00a000bb31 100644 --- a/packages/examples/cvat/exchange-oracle/src/crons/cvat/state_trackers.py +++ b/packages/examples/cvat/exchange-oracle/src/crons/cvat/state_trackers.py @@ -14,8 +14,8 @@ from src.db import SessionLocal from src.db import errors as db_errors from src.db.utils import ForUpdateParams -from src.handlers.completed_escrows import handle_escrows_validations from src.handlers.cvat_events import cvat_webhook_handler +from src.handlers.job_completion import handle_escrows_validations from src.utils.logging import format_sequence from src.utils.time import utcnow diff --git a/packages/examples/cvat/exchange-oracle/src/crons/webhooks/_common.py b/packages/examples/cvat/exchange-oracle/src/crons/webhooks/_common.py index 7b6c2d0095..5da368109c 100644 --- a/packages/examples/cvat/exchange-oracle/src/crons/webhooks/_common.py +++ b/packages/examples/cvat/exchange-oracle/src/crons/webhooks/_common.py @@ -2,7 +2,7 @@ from collections.abc import Callable from contextlib import contextmanager -import httpx +import httpx2 from sqlalchemy.orm import Session from src.core.types import OracleWebhookTypes @@ -60,7 +60,7 @@ def _send_webhook(url: str, webhook: Webhook, *, with_timestamp: bool = True) -> body=body, ) headers = {"human-signature": signature} - with httpx.Client() as client: + with httpx2.Client() as client: response = client.post(url, headers=headers, json=body) response.raise_for_status() diff --git a/packages/examples/cvat/exchange-oracle/src/crons/webhooks/job_launcher.py b/packages/examples/cvat/exchange-oracle/src/crons/webhooks/job_launcher.py index 2263045119..e923790b27 100644 --- a/packages/examples/cvat/exchange-oracle/src/crons/webhooks/job_launcher.py +++ b/packages/examples/cvat/exchange-oracle/src/crons/webhooks/job_launcher.py @@ -18,15 +18,18 @@ from src.crons.webhooks._common import handle_webhook, process_outgoing_webhooks from src.db.utils import ForUpdateParams from src.handlers.escrow_cleanup import cleanup_escrow +from src.log import get_logger_name from src.models.webhook import Webhook +logger = logging.getLogger(get_logger_name(__name__)) + def handle_failure(session: Session, webhook: Webhook, exc: Exception) -> None: if ( webhook.event_type == JobLauncherEventTypes.escrow_created and webhook.attempts + 1 >= Config.webhook_max_retries ): - logging.error( + logger.error( f"Exceeded maximum retries for {webhook.escrow_address=} creation. " f"Notifying job launcher." ) diff --git a/packages/examples/cvat/exchange-oracle/src/crons/webhooks/recording_oracle.py b/packages/examples/cvat/exchange-oracle/src/crons/webhooks/recording_oracle.py index bf527a9ef0..1985119256 100644 --- a/packages/examples/cvat/exchange-oracle/src/crons/webhooks/recording_oracle.py +++ b/packages/examples/cvat/exchange-oracle/src/crons/webhooks/recording_oracle.py @@ -19,7 +19,7 @@ from src.crons._cron_job import cron_job from src.crons.webhooks._common import handle_webhook, process_outgoing_webhooks from src.db.utils import ForUpdateParams -from src.handlers.completed_escrows import handle_escrow_export +from src.handlers.job_export import handle_escrow_export from src.models.webhook import Webhook diff --git a/packages/examples/cvat/exchange-oracle/src/cvat/api_calls.py b/packages/examples/cvat/exchange-oracle/src/cvat/api_calls.py index 1d4103b111..7a224ab732 100644 --- a/packages/examples/cvat/exchange-oracle/src/cvat/api_calls.py +++ b/packages/examples/cvat/exchange-oracle/src/cvat/api_calls.py @@ -6,7 +6,6 @@ from contextlib import contextmanager from contextvars import ContextVar from datetime import datetime, timedelta, timezone -from enum import Enum from http import HTTPStatus from io import BytesIO from pathlib import Path @@ -21,38 +20,42 @@ from httpx import URL from src.core.config import Config -from src.utils.enums import BetterEnumMeta +from src.utils.enums import BetterEnumMeta, StrEnum from src.utils.time import utcnow _NOTSET = object() +_PLAIN_FILE_EXPORT_FORMATS = frozenset({"Generic TSV 1.0"}) +"Export formats that return a plain file instead of a zip archive" + class CVATException(Exception): """Indicates that CVAT API returned unexpected response""" -class RequestStatus(str, Enum, metaclass=BetterEnumMeta): +class RequestStatus(StrEnum, metaclass=BetterEnumMeta): QUEUED = "Queued" STARTED = "Started" FINISHED = "Finished" FAILED = "Failed" -class JobStatus(str, Enum, metaclass=BetterEnumMeta): +class JobStatus(StrEnum, metaclass=BetterEnumMeta): new = "new" in_progress = "in progress" rejected = "rejected" completed = "completed" -class LabelType(str, Enum, metaclass=BetterEnumMeta): +class LabelType(StrEnum, metaclass=BetterEnumMeta): tag = "tag" points = "points" rectangle = "rectangle" polygon = "polygon" + interval = "interval" -class WebhookEventType(str, Enum, metaclass=BetterEnumMeta): +class WebhookEventType(StrEnum, metaclass=BetterEnumMeta): update_job = "update:job" ping = "ping" @@ -132,9 +135,15 @@ def _get_annotations( request_auths=list(api_client.configuration.auth_settings().values()), body="", ) + response = api_client.rest_client.GET(request_info.result_url, headers=headers) file_buffer = io.BytesIO(response.data) - assert zipfile.is_zipfile(file_buffer) + + # Validate the data received. Most formats return a zip archive, but some return contents + # directly. + if request_info.operation.format not in _PLAIN_FILE_EXPORT_FORMATS: + assert zipfile.is_zipfile(file_buffer) + file_buffer.seek(0) return file_buffer @@ -231,7 +240,7 @@ def _to_cvat_credentials(credentials: dict[str, Any]) -> dict: **request_kwargs, ) # CloudStorageWriteRequest try: - (data, response) = api_client.cloudstorages_api.create( + (data, _) = api_client.cloudstorages_api.create( cloud_storage_write_request, _content_type="multipart/form-data", ) @@ -253,7 +262,7 @@ def create_project( kwargs["labels"] = labels try: - (project, response) = api_client.projects_api.create( + (project, _) = api_client.projects_api.create( models.ProjectWriteRequest(name=name, **kwargs) ) if user_guide: @@ -327,7 +336,7 @@ def create_cvat_webhook(project_id: int) -> models.WebhookRead: ], ) # WebhookWriteRequest try: - (data, response) = api_client.webhooks_api.create( + (data, _) = api_client.webhooks_api.create( webhook_write_request, ) return data @@ -340,15 +349,19 @@ def create_task( project_id: int, name: str, *, - segment_size: int, + segment_size: int | None = None, ) -> models.TaskRead: logger = logging.getLogger("app") with get_api_client() as api_client: + kwargs = {} + if segment_size is not None: + kwargs["segment_size"] = segment_size + task_write_request = models.TaskWriteRequest( name=name, project_id=project_id, overlap=0, - segment_size=segment_size, + **kwargs, ) try: (task_info, _) = api_client.tasks_api.create(task_write_request) @@ -365,7 +378,7 @@ def get_cloudstorage_contents(cloudstorage_id: int) -> list[str]: try: ( content_data, - response, + _, ) = api_client.cloudstorages_api.retrieve_content(cloudstorage_id) return content_data except exceptions.ApiException as e: @@ -590,7 +603,7 @@ def get_task_upload_status(cvat_id: int) -> tuple[RequestStatus, str]: # Double check task status - the request can be removed already # TODO: remove this workaround when there is a stable replacement task = api_client.tasks_api.retrieve(cvat_id)[0] - if task.size > 0: + if task.media_type: status = RequestStatus.FINISHED reason = "" else: @@ -608,17 +621,12 @@ def clear_job_annotations(job_id: int) -> None: with get_api_client() as api_client: try: - api_client.jobs_api.update_annotations( - id=job_id, - job_annotations_update_request=models.JobAnnotationsUpdateRequest( - tags=[], shapes=[], tracks=[] - ), - ) + api_client.jobs_api.destroy_annotations(id=job_id) except exceptions.ApiException as e: if e.status == 404: return - logger.exception(f"Exception when calling JobsApi.partial_update_annotations(): {e}\n") + logger.exception(f"Exception when calling JobsApi.destroy_annotations(): {e}\n") raise diff --git a/packages/examples/cvat/exchange-oracle/src/db/__init__.py b/packages/examples/cvat/exchange-oracle/src/db/__init__.py index ba47219043..3444876173 100644 --- a/packages/examples/cvat/exchange-oracle/src/db/__init__.py +++ b/packages/examples/cvat/exchange-oracle/src/db/__init__.py @@ -80,8 +80,7 @@ def _find_existing_parent_attribute(cls) -> InstrumentedAttribute[ParentT]: case InstrumentedAttribute(prop=Relationship(argument=t)) if t is parent_type: return attr_value, parent_type raise AttributeError( - f"Could not find relationship with parent type" - f" {parent_type.__name__} on {cls.__name__}" + f"Could not find relationship with parent type {parent_type.__name__} on {cls.__name__}" ) diff --git a/packages/examples/cvat/exchange-oracle/src/endpoints/__init__.py b/packages/examples/cvat/exchange-oracle/src/endpoints/__init__.py index 9943fea79f..6910510831 100644 --- a/packages/examples/cvat/exchange-oracle/src/endpoints/__init__.py +++ b/packages/examples/cvat/exchange-oracle/src/endpoints/__init__.py @@ -14,7 +14,7 @@ greet_router = APIRouter() -@greet_router.get("/", description="Endpoint describing the API", response_model=MetaResponse) +@greet_router.get("/", description="Endpoint describing the API") def meta_route() -> MetaResponse: networks = [Config.polygon_mainnet, Config.polygon_amoy] diff --git a/packages/examples/cvat/exchange-oracle/src/endpoints/authentication.py b/packages/examples/cvat/exchange-oracle/src/endpoints/authentication.py index 54d8039f4d..4b5234ad26 100644 --- a/packages/examples/cvat/exchange-oracle/src/endpoints/authentication.py +++ b/packages/examples/cvat/exchange-oracle/src/endpoints/authentication.py @@ -3,28 +3,11 @@ import jwt import pydantic from fastapi import Depends, HTTPException, params, status -from fastapi.exceptions import HTTPException -from fastapi.security import HTTPAuthorizationCredentials -from fastapi.security import HTTPBearer as BaseHTTPBearer +from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer from pydantic import BaseModel, model_validator -from starlette.requests import Request from src.core.config import Config - -# https://github.com/fastapi/fastapi/issues/2026 -class HTTPBearer(BaseHTTPBearer): - async def __call__(self, request: Request) -> HTTPAuthorizationCredentials | None: - try: - return await super().__call__(request) - except HTTPException as ex: - if ex.status_code == status.HTTP_403_FORBIDDEN and ex.detail == "Not authenticated": - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail=ex.detail, - ) from ex - - # Customized JWT-token authorization AuthorizationDependency = HTTPBearer(scheme_name="jwt_bearer") AuthorizationToken = HTTPAuthorizationCredentials diff --git a/packages/examples/cvat/exchange-oracle/src/endpoints/exchange.py b/packages/examples/cvat/exchange-oracle/src/endpoints/exchange.py index e75b14ddaf..af4ef571c7 100644 --- a/packages/examples/cvat/exchange-oracle/src/endpoints/exchange.py +++ b/packages/examples/cvat/exchange-oracle/src/endpoints/exchange.py @@ -14,7 +14,8 @@ import src.services.cvat as cvat_service import src.services.exchange as oracle_service from src.core.config import Config -from src.core.types import ProjectStatuses, TaskTypes +from src.core.tasks import TaskTypes +from src.core.types import ProjectStatuses from src.db import SessionLocal from src.db import engine as db_engine from src.endpoints.authentication import ( diff --git a/packages/examples/cvat/exchange-oracle/src/endpoints/filtering.py b/packages/examples/cvat/exchange-oracle/src/endpoints/filtering.py index e37e6e3b9f..e3f35b630b 100644 --- a/packages/examples/cvat/exchange-oracle/src/endpoints/filtering.py +++ b/packages/examples/cvat/exchange-oracle/src/endpoints/filtering.py @@ -1,6 +1,5 @@ from __future__ import annotations -from enum import Enum from typing import TYPE_CHECKING, Any, ClassVar, TypeVar import fastapi @@ -11,13 +10,15 @@ from fastapi_filter.contrib.sqlalchemy import Filter as _Filter from pydantic import BaseModel, Field, ValidationInfo, field_validator -from src.utils.enums import BetterEnumMeta +from src.utils.enums import BetterEnumMeta, StrEnum if TYPE_CHECKING: + from enum import Enum + from pydantic.fields import FieldInfo -class OrderingDirection(str, Enum, metaclass=BetterEnumMeta): +class OrderingDirection(StrEnum, metaclass=BetterEnumMeta): asc = "ASC" desc = "DESC" @@ -157,4 +158,4 @@ def _get_field_info(klass: type[BaseModel], field_name: str): return klass.model_fields[field_name] -__all__ = ["Filter", "FilterDepends", "with_prefix", "OrderingDirection"] +__all__ = ["Filter", "FilterDepends", "OrderingDirection", "with_prefix"] diff --git a/packages/examples/cvat/exchange-oracle/src/endpoints/pagination.py b/packages/examples/cvat/exchange-oracle/src/endpoints/pagination.py index 1399d1e98e..6ffb405fb7 100644 --- a/packages/examples/cvat/exchange-oracle/src/endpoints/pagination.py +++ b/packages/examples/cvat/exchange-oracle/src/endpoints/pagination.py @@ -1,6 +1,5 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING, Any, TypeVar +from collections.abc import Sequence +from typing import Any, TypeVar import fastapi_pagination.bases import fastapi_pagination.default @@ -10,9 +9,6 @@ from src.core.config import Config -if TYPE_CHECKING: - from collections.abc import Sequence - FIRST_PAGE = 0 @@ -69,9 +65,9 @@ def create( *, total: int | None = None, **kwargs: Any, - ) -> Page[T]: + ) -> "Page[T]": assert isinstance(params, PaginationParams) return super().create(items, params, total=total, **kwargs) -__all__ = ["PaginationParams", "Page", "paginate"] +__all__ = ["Page", "PaginationParams", "paginate"] diff --git a/packages/examples/cvat/exchange-oracle/src/endpoints/serializers.py b/packages/examples/cvat/exchange-oracle/src/endpoints/serializers.py index 05b01ffb80..50049a9d5c 100644 --- a/packages/examples/cvat/exchange-oracle/src/endpoints/serializers.py +++ b/packages/examples/cvat/exchange-oracle/src/endpoints/serializers.py @@ -8,7 +8,7 @@ get_escrow_fund_token_symbol, get_escrow_manifest, ) -from src.core.manifest import parse_manifest +from src.core.manifest import ManifestBase, parse_manifest from src.core.types import AssignmentStatuses, ProjectStatuses from src.db import SessionLocal from src.schemas import exchange as service_api @@ -50,14 +50,16 @@ def serialize_job( else: raise AssertionError(f"Unexpected project status '{project.status}'") + bounty = get_assignment_bounty(project, manifest=manifest) reward_token = get_escrow_fund_token_symbol(project.chain_id, project.escrow_address) + return service_api.JobResponse( escrow_address=project.escrow_address, chain_id=project.chain_id, job_type=project.job_type, status=api_status, job_description=manifest.annotation.description if manifest else None, - reward_amount=str(manifest.job_bounty) if manifest else None, + reward_amount=bounty, reward_token=reward_token, created_at=project.created_at, updated_at=project.updated_at, @@ -65,6 +67,26 @@ def serialize_job( ) +def get_assignment_bounty( + project: cvat_service.Project, *, manifest: ManifestBase | None = None +) -> str | None: + if project.assignment_bounty is not None: + assignment_bounty = project.assignment_bounty + else: + with suppress(ManifestNotAvailableError): + if not manifest: + manifest = parse_manifest( + get_escrow_manifest(project.chain_id, project.escrow_address) + ) + + assignment_bounty = getattr(manifest, "job_bounty", None) + + if assignment_bounty is not None: + assignment_bounty = str(assignment_bounty) + + return assignment_bounty + + ASSIGNMENT_PROJECT_VALIDATION_STATUSES = [ cvat_service.ProjectStatuses.annotation, cvat_service.ProjectStatuses.completed, @@ -101,9 +123,6 @@ def serialize_assignment( f"or a cvat_service.Project instance, not {project!r}" ) - with suppress(ManifestNotAvailableError): - manifest = parse_manifest(get_escrow_manifest(project.chain_id, project.escrow_address)) - assignment_status_mapping = { AssignmentStatuses.created: service_api.AssignmentStatuses.active, AssignmentStatuses.completed: service_api.AssignmentStatuses.completed, @@ -119,6 +138,7 @@ def serialize_assignment( else: api_status = assignment_status_mapping[assignment.status] + bounty = get_assignment_bounty(project) reward_token = get_escrow_fund_token_symbol(project.chain_id, project.escrow_address) return service_api.AssignmentResponse( @@ -127,7 +147,7 @@ def serialize_assignment( chain_id=project.chain_id, job_type=project.job_type, status=api_status, - reward_amount=str(manifest.job_bounty) if manifest else None, + reward_amount=bounty, reward_token=reward_token, url=compose_assignment_url( task_id=assignment.job.cvat_task_id, diff --git a/packages/examples/cvat/exchange-oracle/src/endpoints/throttling.py b/packages/examples/cvat/exchange-oracle/src/endpoints/throttling.py index 38e69cb936..1352a252fb 100644 --- a/packages/examples/cvat/exchange-oracle/src/endpoints/throttling.py +++ b/packages/examples/cvat/exchange-oracle/src/endpoints/throttling.py @@ -24,4 +24,4 @@ def add_throttling(app: FastAPI): return register_lifespan_context(app, lifespan_context=lifespan) -__all__ = ["add_throttling", "RateLimiter"] +__all__ = ["RateLimiter", "add_throttling"] diff --git a/packages/examples/cvat/exchange-oracle/src/entrypoints/__init__.py b/packages/examples/cvat/exchange-oracle/src/entrypoints/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/examples/cvat/exchange-oracle/debug.py b/packages/examples/cvat/exchange-oracle/src/entrypoints/debug.py similarity index 85% rename from packages/examples/cvat/exchange-oracle/debug.py rename to packages/examples/cvat/exchange-oracle/src/entrypoints/debug.py index 4b89982d89..0c996dfbc2 100644 --- a/packages/examples/cvat/exchange-oracle/debug.py +++ b/packages/examples/cvat/exchange-oracle/src/entrypoints/debug.py @@ -1,7 +1,9 @@ import datetime import inspect import json +import sys import uuid +from argparse import ArgumentParser from collections.abc import Generator from contextlib import ExitStack, contextmanager from logging import Logger @@ -24,14 +26,16 @@ @contextmanager def _mock_cvat_cloud_storage_params(logger: Logger) -> Generator[None, None, None]: - from src.handlers.job_creation import ( - _make_cvat_cloud_storage_params as original_make_cvat_cloud_storage_params, + from src.handlers.job_creation.utils import ( + make_cvat_cloud_storage_params as original_make_cvat_cloud_storage_params, ) def patched_make_cvat_cloud_storage_params(bucket_info: BucketAccessInfo) -> dict: original_host_url = bucket_info.host_url - if Config.development_config.cvat_in_docker: + if Config.development_config.cvat_in_docker and ( + "localhost" in original_host_url or "127.0.0.1" in original_host_url + ): bucket_info.host_url = str( URL(original_host_url).copy_with( host=Config.development_config.exchange_oracle_host @@ -46,10 +50,16 @@ def patched_make_cvat_cloud_storage_params(bucket_info: BucketAccessInfo) -> dic finally: bucket_info.host_url = original_host_url - with mock.patch( - "src.handlers.job_creation._make_cvat_cloud_storage_params", - patched_make_cvat_cloud_storage_params, - ): + # The helper is looked up in each builder module that imports it, so patch all of them. + patch_targets = [ + "src.handlers.job_creation.builders.vision.basic.make_cvat_cloud_storage_params", + "src.handlers.job_creation.builders.vision.boxes_from_points.make_cvat_cloud_storage_params", + "src.handlers.job_creation.builders.vision.skeletons_from_boxes.make_cvat_cloud_storage_params", + "src.handlers.job_creation.builders.audio.transcription.make_cvat_cloud_storage_params", + ] + with ExitStack() as stack: + for target in patch_targets: + stack.enter_context(mock.patch(target, patched_make_cvat_cloud_storage_params)) yield @@ -69,8 +79,7 @@ def patched_get_escrow(chain_id: int, escrow_address: str) -> EscrowData: fn for fn in minio_manifests if ( - "/" in escrow_address - and fn == f"{escrow_address}.json" + ("/" in escrow_address and fn == f"{escrow_address}.json") or PurePosixPath(fn).name == f"{escrow_address}.json" ) ] @@ -219,6 +228,8 @@ def decode_plain_json_token(self, token) -> dict[str, Any]: token_data["wallet_address"] = None token_data["email"] = "" + token_data.setdefault("qualifications", []) + logger.info(f"DEV: Decoded plain JSON auth token: {token_data}") return token_data except (ValueError, TypeError): @@ -235,7 +246,7 @@ def _mock_human_app_keys(_: Logger) -> Generator[None, None, None]: from tests.api.test_exchange_api import generate_ecdsa_keys # generating keys for local development - repo_root = Path(__file__).parent + repo_root = Path(__file__).parents[2] dev_dir = repo_root / "dev" dev_dir.mkdir(exist_ok=True) @@ -280,7 +291,20 @@ def apply_local_development_patches() -> Generator[None, None, None]: yield -if __name__ == "__main__": +def run_server(): + uvicorn.run( + app="src.apps.exchange_oracle:app", + host="0.0.0.0", # noqa: S104 + port=int(Config.port), + workers=Config.workers_amount, + ) + + +def main(args: list[str] | None = None) -> int: + parser = ArgumentParser() + parser.add_argument("-e", "--entrypoint", default=run_server) + parsed_args = parser.parse_args(args) + with ExitStack() as es: is_dev = Config.environment == "development" if is_dev: @@ -289,9 +313,10 @@ def apply_local_development_patches() -> Generator[None, None, None]: Config.validate() register_in_kvstore() - uvicorn.run( - app="src:app", - host="0.0.0.0", # noqa: S104 - port=int(Config.port), - workers=Config.workers_amount, - ) + parsed_args.entrypoint() + + return 0 + + +if __name__ == "__main__": + sys.exit(main(sys.argv[1:])) diff --git a/packages/examples/cvat/exchange-oracle/run.py b/packages/examples/cvat/exchange-oracle/src/entrypoints/run.py similarity index 89% rename from packages/examples/cvat/exchange-oracle/run.py rename to packages/examples/cvat/exchange-oracle/src/entrypoints/run.py index d663c2f2a0..071c80f64f 100644 --- a/packages/examples/cvat/exchange-oracle/run.py +++ b/packages/examples/cvat/exchange-oracle/src/entrypoints/run.py @@ -9,7 +9,7 @@ register_in_kvstore() uvicorn.run( - app="src:app", + app="src.apps.exchange_oracle:app", host="0.0.0.0", # noqa: S104 port=int(Config.port), workers=Config.workers_amount, diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/completed_escrows.py b/packages/examples/cvat/exchange-oracle/src/handlers/completed_escrows.py deleted file mode 100644 index 55821087c2..0000000000 --- a/packages/examples/cvat/exchange-oracle/src/handlers/completed_escrows.py +++ /dev/null @@ -1,347 +0,0 @@ -import io -import logging -from collections.abc import Callable, Sequence -from functools import partial -from typing import Any - -from datumaro.util import take_by -from sqlalchemy.orm import Session - -import src.cvat.api_calls as cvat_api -import src.services.cloud as cloud_service -import src.services.cvat as cvat_service -import src.services.webhook as oracle_db_service -from src.chain.escrow import get_escrow_manifest, validate_escrow -from src.core.annotation_meta import ANNOTATION_RESULTS_METAFILE_NAME, RESULTING_ANNOTATIONS_FILE -from src.core.config import CronConfig, StorageConfig -from src.core.oracle_events import ( - ExchangeOracleEvent_EscrowRecorded, - ExchangeOracleEvent_JobFinished, -) -from src.core.storage import compose_results_bucket_filename -from src.core.types import EscrowValidationStatuses, OracleWebhookTypes, TaskTypes -from src.db import SessionLocal -from src.db.utils import ForUpdateParams -from src.handlers.job_export import ( - CVAT_EXPORT_FORMAT_MAPPING, - FileDescriptor, - postprocess_annotations, - prepare_annotation_metafile, -) -from src.models.cvat import Job, Project -from src.services.cloud.types import BucketAccessInfo -from src.utils.assignments import parse_manifest - - -def _download_with_retries( - logger: logging.Logger, - download_callback: Callable[[], io.RawIOBase], - retry_callback: Callable[[], Any], - *, - max_attempts: int | None = None, -) -> io.RawIOBase: - """ - Sometimes CVAT downloading can fail with the 500 error. - This function tries to repeat the export in such cases. - """ - - if max_attempts is None: - max_attempts = CronConfig.track_completed_escrows_max_downloading_retries - - attempt = 0 - while attempt < max_attempts: - try: - return download_callback() - except cvat_api.exceptions.ApiException as e: - if 500 <= e.status < 600 and attempt + 1 < max_attempts: - attempt += 1 - logger.info(f"Retrying downloading, attempt #{attempt} of {max_attempts}...") - retry_callback() - else: - raise - return None - - -def _export_escrow_annotations( - logger: logging.Logger, - chain_id: int, - escrow_address: str, - escrow_projects: Sequence[Project], - session: Session, -) -> None: - manifest = parse_manifest(get_escrow_manifest(chain_id, escrow_address)) - - escrow_creation = cvat_service.get_escrow_creation_by_escrow_address( - session, - escrow_address, - chain_id, - active=False, - ) - if not escrow_creation: - raise AssertionError(f"Can't find escrow creation for escrow '{escrow_address}'") - - jobs = cvat_service.get_jobs_by_escrow_address(session, escrow_address, chain_id) - if len(jobs) != escrow_creation.total_jobs: - raise AssertionError( - f"Unexpected number of jobs fetched for escrow " - f"'{escrow_address}': {len(jobs)}, expected {escrow_creation.total_jobs}" - ) - - logger.debug(f"Downloading results for the escrow ({escrow_address=})") - - annotation_format = CVAT_EXPORT_FORMAT_MAPPING[manifest.annotation.type] - # FUTURE-TODO: probably can be removed in the future since - # these annotations are no longer used in Recording Oracle - job_annotations = _download_job_annotations(logger, annotation_format, jobs) - - if manifest.annotation.type == TaskTypes.image_skeletons_from_boxes.value: - # we'll have to merge annotations ourselves for skeletons - # might want to make this the only behavior in the future - project_annotations_file = None - project_images = None - else: - # escrows with simple task types must have only one project - try: - (project,) = escrow_projects - except ValueError: - raise NotImplementedError( - f"{manifest.annotation.type} is expected to have exactly one project," - f" not {len(escrow_projects)}" - ) - project_annotations_file = _download_project_annotations( - logger, - annotation_format, - project.cvat_id, - ) - project_images = cvat_service.get_project_images(session, project.cvat_id) - - resulting_annotations_file_desc = FileDescriptor( - filename=RESULTING_ANNOTATIONS_FILE, - file=project_annotations_file, - ) - - logger.debug(f"Postprocessing results for the escrow ({escrow_address=})") - - postprocess_annotations( - escrow_address=escrow_address, - chain_id=chain_id, - annotations=( - resulting_annotations_file_desc, - *job_annotations.values(), - ), - merged_annotation=resulting_annotations_file_desc, - manifest=manifest, - project_images=project_images, - ) - logger.debug(f"Uploading annotations for the escrow ({escrow_address=})") - - _upload_escrow_results( - files=( - resulting_annotations_file_desc, - *job_annotations.values(), - prepare_annotation_metafile(jobs=jobs), - ), - chain_id=chain_id, - escrow_address=escrow_address, - ) - - oracle_db_service.outbox.create_webhook( - session, - escrow_address=escrow_address, - chain_id=chain_id, - type=OracleWebhookTypes.recording_oracle, - event=ExchangeOracleEvent_EscrowRecorded(), - ) - - logger.info( - f"The escrow ({escrow_address=}) is completed, " - f"resulting annotations are processed successfully" - ) - - -def _request_escrow_validation( - logger: logging.Logger, - chain_id: int, - escrow_address: str, - escrow_projects: Sequence[Project], - session: Session, -) -> None: - # TODO: lock escrow once there is such a DB object - assert escrow_projects # unused, but must hold a lock - - # TODO: maybe upload only current iteration jobs - jobs = cvat_service.get_jobs_by_escrow_address(session, escrow_address, chain_id) - - logger.debug(f"Uploading assignment info for the escrow ({escrow_address=})") - - _upload_escrow_results( - files=[prepare_annotation_metafile(jobs=jobs)], - chain_id=chain_id, - escrow_address=escrow_address, - ) - - oracle_db_service.outbox.create_webhook( - session, - escrow_address=escrow_address, - chain_id=chain_id, - type=OracleWebhookTypes.recording_oracle, - event=ExchangeOracleEvent_JobFinished(), - ) - - logger.info(f"The escrow ({escrow_address=}) annotation is finished, " f"requesting validation") - - -def _upload_escrow_results( - files: Sequence[FileDescriptor], chain_id: int, escrow_address: str -) -> None: - storage_info = BucketAccessInfo.parse_obj(StorageConfig) - storage_client = cloud_service.make_client(storage_info) - - # always update annotation meta and resulting annotations files - # to have actual data for the current epoch - existing_storage_files = set( - storage_client.list_files( - prefix=compose_results_bucket_filename(escrow_address, chain_id, ""), - trim_prefix=True, - ) - ) - {ANNOTATION_RESULTS_METAFILE_NAME, RESULTING_ANNOTATIONS_FILE} - - for file_descriptor in files: - if file_descriptor.filename in existing_storage_files: - continue - - storage_client.create_file( - compose_results_bucket_filename( - escrow_address, - chain_id, - file_descriptor.filename, - ), - file_descriptor.file.read(), - ) - - -def _download_project_annotations( - logger: logging.Logger, annotation_format: str, project_cvat_id: int -) -> io.RawIOBase: - export_ids = [] - - def _request_export(cvat_id: int): - request_id = cvat_api.request_project_annotations(cvat_id, format_name=annotation_format) - export_ids.append(request_id) - return request_id - - def _download_export(): - request_id = export_ids.pop(0) - return cvat_api.get_project_annotations(request_id=request_id) - - _request_export(project_cvat_id) - - return _download_with_retries( - logger, - download_callback=_download_export, - retry_callback=partial(_request_export, project_cvat_id), - ) - - -def _download_job_annotations( - logger: logging.Logger, annotation_format: str, jobs: Sequence[Job] -) -> dict[int, FileDescriptor]: - # Collect raw annotations from CVAT, validate and convert them - # into a recording oracle suitable format - job_annotations: dict[int, FileDescriptor] = {} - - export_ids: list[tuple[Job, str]] = [] - - def _request_export(job: Job): - request_id = cvat_api.request_job_annotations(job.cvat_id, format_name=annotation_format) - export_ids.append((job, request_id)) - return request_id - - for jobs_batch in take_by( - jobs, count=CronConfig.track_completed_escrows_jobs_downloading_batch_size - ): - # Request jobs before downloading for faster batch downloading - for job in jobs_batch: - _request_export(job) - - while export_ids: - (job, request_id) = export_ids.pop(0) - - job_annotations_file = _download_with_retries( - logger, - download_callback=partial(cvat_api.get_job_annotations, request_id=request_id), - retry_callback=partial(_request_export, job), - ) - - job_assignment = job.latest_assignment - job_annotations[job.cvat_id] = FileDescriptor( - filename="project_{}-task_{}-job_{}-user_{}-assignment_{}.zip".format( - job.cvat_project_id, - job.cvat_task_id, - job.cvat_id, - job_assignment.user.cvat_id, - job_assignment.id, - ), - file=job_annotations_file, - ) - - return job_annotations - - -def _handle_escrow_validation( - logger: logging.Logger, - session: Session, - escrow_address: str, - chain_id: int, -): - validate_escrow(chain_id, escrow_address) - - escrow_projects = cvat_service.get_projects_by_escrow_address( - session, escrow_address, limit=None, for_update=ForUpdateParams(nowait=True) - ) - _request_escrow_validation(logger, chain_id, escrow_address, escrow_projects, session) - - -def handle_escrows_validations(logger: logging.Logger) -> None: - for _ in range(CronConfig.track_escrow_validations_chunk_size): - with SessionLocal.begin() as session: - # Need to work in separate transactions for each escrow, as a failing DB call - # (e.g. a failed lock attempt) will abort the transaction. A nested transaction - # can also be used for handling this. - escrow_validation = cvat_service.lock_escrow_for_validation(session) - if not escrow_validation: - break - - escrow_address = escrow_validation.escrow_address - chain_id = escrow_validation.chain_id - - update_kwargs = {} - try: - _handle_escrow_validation(logger, session, escrow_address, chain_id) - - # Change status so validation won't be attempted again - update_kwargs["status"] = EscrowValidationStatuses.in_progress - except Exception as e: - logger.exception(e) - - cvat_service.update_escrow_validation( - session, - escrow_address=escrow_address, - chain_id=chain_id, - increase_attempts=True, # increase attempts always to allow escrow rotation - **update_kwargs, - ) - - -def handle_escrow_export( - logger: logging.Logger, - session: Session, - escrow_address: str, - chain_id: int, -): - validate_escrow(chain_id, escrow_address) - - escrow_projects = cvat_service.get_projects_by_escrow_address( - session, escrow_address, limit=None, for_update=ForUpdateParams(nowait=True) - ) - _export_escrow_annotations(logger, chain_id, escrow_address, escrow_projects, session) diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_completion/__init__.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_completion/__init__.py new file mode 100644 index 0000000000..3e77c15b70 --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_completion/__init__.py @@ -0,0 +1,3 @@ +from src.handlers.job_completion.handlers import handle_escrows_validations + +__all__ = ["handle_escrows_validations"] diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_completion/handlers.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_completion/handlers.py new file mode 100644 index 0000000000..c050160e07 --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_completion/handlers.py @@ -0,0 +1,79 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +import src.services.cvat as cvat_service +from src.chain.escrow import get_escrow_manifest, validate_escrow +from src.core.config import CronConfig +from src.core.manifest import parse_manifest +from src.core.types import EscrowValidationStatuses +from src.db import SessionLocal +from src.db.utils import ForUpdateParams +from src.handlers.job_completion.validators.factory import create_validator +from src.utils.logging import get_function_logger + +if TYPE_CHECKING: + import logging + + from sqlalchemy.orm import Session + + +def _handle_escrow_validation( + logger: logging.Logger, + session: Session, + escrow_address: str, + chain_id: int, +) -> None: + logger = get_function_logger(logger) + + validate_escrow(chain_id, escrow_address) + + # TODO: lock the escrow once there is such a DB object + escrow_projects = cvat_service.get_projects_by_escrow_address( + session, escrow_address, limit=None, for_update=ForUpdateParams(nowait=True) + ) + if not escrow_projects: + raise AssertionError(f"Can't find projects for escrow '{escrow_address}'") + + manifest = parse_manifest(get_escrow_manifest(chain_id, escrow_address)) + + with create_validator( + manifest=manifest, + escrow_address=escrow_address, + chain_id=chain_id, + session=session, + escrow_projects=escrow_projects, + ) as validator: + validator.set_logger(logger) + validator.validate() + + +def handle_escrows_validations(logger: logging.Logger) -> None: + for _ in range(CronConfig.track_escrow_validations_chunk_size): + with SessionLocal.begin() as session: + # Need to work in separate transactions for each escrow, as a failing DB call + # (e.g. a failed lock attempt) will abort the transaction. A nested transaction + # can also be used for handling this. + escrow_validation = cvat_service.lock_escrow_for_validation(session) + if not escrow_validation: + break + + escrow_address = escrow_validation.escrow_address + chain_id = escrow_validation.chain_id + + update_kwargs = {} + try: + _handle_escrow_validation(logger, session, escrow_address, chain_id) + + # Change status so validation won't be attempted again + update_kwargs["status"] = EscrowValidationStatuses.in_progress + except Exception as e: + logger.exception(e) + + cvat_service.update_escrow_validation( + session, + escrow_address=escrow_address, + chain_id=chain_id, + increase_attempts=True, # increase attempts always to allow escrow rotation + **update_kwargs, + ) diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_completion/validators/__init__.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_completion/validators/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_completion/validators/audio.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_completion/validators/audio.py new file mode 100644 index 0000000000..0da92d0f1a --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_completion/validators/audio.py @@ -0,0 +1,50 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +import src.services.cvat as cvat_service +from src.core.tasks.audio_transcription.meta import CVAT_EXPORT_FORMAT, TaskResultsLayout +from src.handlers.job_completion.validators.base import JobValidator +from src.handlers.job_export.downloading import download_job_annotations +from src.handlers.job_export.results import ( + FileDescriptor, + prepare_annotation_metafile, + upload_escrow_results, +) + +if TYPE_CHECKING: + from src.models.cvat import Job + + +class AudioTranscriptionJobValidator(JobValidator): + def _save_annotation_results(self) -> None: + assert self.escrow_projects # unused, but must hold a lock + + cvat_jobs = cvat_service.get_jobs_by_escrow_address( + self.session, self.escrow_address, self.chain_id + ) + + self.logger.debug( + f"Downloading annotations for the escrow (escrow_address={self.escrow_address})" + ) + cvat_job_annotations = download_job_annotations(self.logger, CVAT_EXPORT_FORMAT, cvat_jobs) + + result_files: list[FileDescriptor] = [ + self._make_annotation_descriptor(job, cvat_job_annotations[job.cvat_id]) + for job in cvat_jobs + ] + result_files.append(prepare_annotation_metafile(jobs=cvat_jobs)) + + self.logger.debug( + f"Recording annotations for the escrow (escrow_address={self.escrow_address})" + ) + upload_escrow_results( + files=result_files, chain_id=self.chain_id, escrow_address=self.escrow_address + ) + + def _make_annotation_descriptor(self, job: Job, annotations: FileDescriptor) -> FileDescriptor: + assignment = job.latest_assignment + return FileDescriptor( + filename=TaskResultsLayout.assignment_annotation_filename(job.cvat_id, assignment.id), + file=annotations.file, + ) diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_completion/validators/base.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_completion/validators/base.py new file mode 100644 index 0000000000..a82a93d76a --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_completion/validators/base.py @@ -0,0 +1,81 @@ +from __future__ import annotations + +from contextlib import ExitStack +from typing import TYPE_CHECKING + +import src.services.cvat as cvat_service +import src.services.webhook as oracle_db_service +from src.core.oracle_events import ExchangeOracleEvent_JobFinished +from src.core.types import OracleWebhookTypes +from src.handlers.job_export.results import prepare_annotation_metafile, upload_escrow_results +from src.utils.logging import NullLogger + +if TYPE_CHECKING: + from collections.abc import Sequence + from logging import Logger + + from sqlalchemy.orm import Session + + from src.handlers.job_export.results import FileDescriptor + from src.models.cvat import Project + + +class JobValidator: + def __init__( + self, + escrow_address: str, + chain_id: int, + session: Session, + escrow_projects: Sequence[Project], + ) -> None: + self.exit_stack = ExitStack() + self.escrow_address = escrow_address + self.chain_id = chain_id + self.session = session + self.escrow_projects = escrow_projects + + self.logger: Logger = NullLogger() + + def __enter__(self): + return self + + def __exit__(self, *args, **kwargs): + self.close() + + def close(self): + self.exit_stack.close() + + def set_logger(self, logger: Logger): + self.logger = logger + return self + + def validate(self) -> None: + self._save_annotation_results() + self._notify() + + def _save_annotation_results(self) -> None: + # TODO: maybe upload only current iteration jobs + jobs = cvat_service.get_jobs_by_escrow_address( + self.session, self.escrow_address, self.chain_id + ) + result_files: list[FileDescriptor] = [prepare_annotation_metafile(jobs=jobs)] + + self.logger.debug( + f"Uploading assignment info for the escrow (escrow_address={self.escrow_address})" + ) + upload_escrow_results( + files=result_files, chain_id=self.chain_id, escrow_address=self.escrow_address + ) + + def _notify(self) -> None: + oracle_db_service.outbox.create_webhook( + self.session, + escrow_address=self.escrow_address, + chain_id=self.chain_id, + type=OracleWebhookTypes.recording_oracle, + event=ExchangeOracleEvent_JobFinished(), + ) + self.logger.info( + f"The escrow (escrow_address={self.escrow_address}) annotation is finished, " + "requesting validation" + ) diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_completion/validators/factory.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_completion/validators/factory.py new file mode 100644 index 0000000000..f11c00dd27 --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_completion/validators/factory.py @@ -0,0 +1,42 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +from src.core.manifest import ManifestBase, get_manifest_task_type +from src.core.tasks import TaskTypes +from src.handlers.job_completion.validators.audio import AudioTranscriptionJobValidator +from src.handlers.job_completion.validators.base import JobValidator + +if TYPE_CHECKING: + from collections.abc import Sequence + + from sqlalchemy.orm import Session + + from src.models.cvat import Project + + +def create_validator( + manifest: ManifestBase, + escrow_address: str, + chain_id: int, + session: Session, + escrow_projects: Sequence[Project], +) -> JobValidator: + task_type = get_manifest_task_type(manifest) + + match task_type: + case TaskTypes.audio_transcription: + validator_type = AudioTranscriptionJobValidator + case ( + TaskTypes.image_label_binary + | TaskTypes.image_boxes + | TaskTypes.image_polygons + | TaskTypes.image_points + | TaskTypes.image_boxes_from_points + | TaskTypes.image_skeletons_from_boxes + ): + validator_type = JobValidator + case _: + raise NotADirectoryError(f"Unsupported task type '{task_type}'") + + return validator_type(escrow_address, chain_id, session, escrow_projects) diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_creation.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation.py deleted file mode 100644 index 666f71e2a8..0000000000 --- a/packages/examples/cvat/exchange-oracle/src/handlers/job_creation.py +++ /dev/null @@ -1,3060 +0,0 @@ -from __future__ import annotations - -import math -import os -import random -import uuid -from abc import ABCMeta, abstractmethod -from concurrent.futures import Future, ThreadPoolExecutor -from contextlib import ExitStack -from dataclasses import dataclass, field -from itertools import chain, groupby -from math import ceil -from pathlib import Path -from queue import Queue -from tempfile import TemporaryDirectory -from time import sleep -from typing import TYPE_CHECKING, TypeVar, cast - -import cv2 -import datumaro as dm -import numpy as np -from datumaro.util import filter_dict, take_by -from datumaro.util.annotation_util import BboxCoords, bbox_iou, find_instances -from datumaro.util.image import IMAGE_EXTENSIONS, decode_image, encode_image - -import src.core.tasks.boxes_from_points as boxes_from_points_task -import src.core.tasks.points as points_task -import src.core.tasks.simple as simple_task -import src.core.tasks.skeletons_from_boxes as skeletons_from_boxes_task -import src.cvat.api_calls as cvat_api -import src.services.cloud as cloud_service -import src.services.cvat as db_service -from src.chain.escrow import get_escrow_manifest -from src.core.config import Config -from src.core.storage import compose_data_bucket_filename, compose_data_bucket_prefix -from src.core.types import TaskStatuses, TaskTypes -from src.db import SessionLocal -from src.log import ROOT_LOGGER_NAME -from src.models.cvat import Project -from src.services.cloud import CloudProviders, StorageClient -from src.services.cloud.utils import BucketAccessInfo -from src.utils.annotations import InstanceSegmentsToBbox, ProjectLabels, is_point_in_bbox -from src.utils.assignments import parse_manifest -from src.utils.logging import NullLogger, format_sequence, get_function_logger -from src.utils.roi_uploader import BufferedRoiImageUploader -from src.utils.zip_archive import write_dir_to_zip_archive - -if TYPE_CHECKING: - from collections.abc import Generator, Sequence - from logging import Logger - - from src.core.manifest import TaskManifest - -module_logger = f"{ROOT_LOGGER_NAME}.cron.cvat" - -LABEL_TYPE_MAPPING = { - TaskTypes.image_label_binary: cvat_api.LabelType.tag, - TaskTypes.image_points: cvat_api.LabelType.points, - TaskTypes.image_boxes: cvat_api.LabelType.rectangle, - TaskTypes.image_polygons: cvat_api.LabelType.polygon, - TaskTypes.image_boxes_from_points: cvat_api.LabelType.rectangle, - TaskTypes.image_skeletons_from_boxes: cvat_api.LabelType.points, -} - -DM_DATASET_FORMAT_MAPPING = { - TaskTypes.image_label_binary: "cvat_images", - TaskTypes.image_points: "coco_person_keypoints", - TaskTypes.image_boxes: "coco_instances", - TaskTypes.image_polygons: "coco_instances", - TaskTypes.image_boxes_from_points: "coco_instances", - TaskTypes.image_skeletons_from_boxes: "coco_person_keypoints", -} - -DM_GT_DATASET_FORMAT_MAPPING = { - # GT uses the same format both for boxes and points - TaskTypes.image_label_binary: "cvat_images", - TaskTypes.image_points: "coco_instances", - TaskTypes.image_boxes: "coco_instances", - TaskTypes.image_polygons: "coco_instances", - TaskTypes.image_boxes_from_points: "coco_instances", - TaskTypes.image_skeletons_from_boxes: "coco_person_keypoints", -} - - -class DatasetValidationError(Exception): - pass - - -class MismatchingAnnotations(DatasetValidationError): - pass - - -class TooFewSamples(DatasetValidationError): - pass - - -class InvalidCategories(DatasetValidationError): - pass - - -class InvalidImageInfo(DatasetValidationError): - pass - - -class InvalidCoordinates(DatasetValidationError): - pass - - -class InvisibleSkeletonError(DatasetValidationError): - pass - - -T = TypeVar("T") - - -class _Undefined: - def __bool__(self) -> bool: - return False - - -_unset = _Undefined() - -_MaybeUnset = T | _Undefined - - -@dataclass -class _ExcludedAnnotationInfo: - message: str - sample_id: str = field(kw_only=True) - sample_subset: str = field(kw_only=True) - - -@dataclass -class _ExcludedAnnotationsInfo: - messages: list[_ExcludedAnnotationInfo] = field(default_factory=list) - - excluded_count: int = 0 - "The number of excluded annotations. Can be different from len(messages)" - - total_count: int = 0 - - def add_message(self, message: str, *, sample_id: str, sample_subset: str): - self.messages.append( - _ExcludedAnnotationInfo( - message=message, sample_id=sample_id, sample_subset=sample_subset - ) - ) - - -class _TaskBuilderBase(metaclass=ABCMeta): - def __init__(self, manifest: TaskManifest, escrow_address: str, chain_id: int) -> None: - self.exit_stack = ExitStack() - self.manifest = manifest - self.escrow_address = escrow_address - self.chain_id = chain_id - - self.logger: Logger = NullLogger() - - self._oracle_data_bucket = BucketAccessInfo.parse_obj(Config.storage_config) - - @property - def _task_segment_size(self) -> int: - return self.manifest.annotation.job_size - - @property - def _job_val_frames_count(self) -> int: - return self.manifest.validation.val_size - - def __enter__(self): - return self - - def __exit__(self, *args, **kwargs): - self.close() - - def close(self): - self.exit_stack.close() - - def set_logger(self, logger: Logger): - # TODO: add escrow info into messages - self.logger = logger - return self - - @classmethod - def _make_cloud_storage_client(cls, bucket_info: BucketAccessInfo) -> StorageClient: - extra_args = {} - - if bucket_info.provider == CloudProviders.aws: - import boto3.session - - extra_args["config"] = boto3.session.Config( - max_pool_connections=Config.features.max_data_storage_connections - ) - elif bucket_info.provider == CloudProviders.gcs: - pass # TODO: test and add connections if needed - - return cloud_service.make_client(bucket_info, **extra_args) - - def _save_cvat_gt_dataset_to_oracle_bucket( # noqa: B027 - self, - gt_dataset_path: Path, - *, - file_suffix: str = "", - ) -> None: - # method saves gt annotations that will be uploaded to CVAT - # into oracle bucket - pass - - def _wait_task_creation(self, task_id: int) -> cvat_api.RequestStatus: - # TODO: add a timeout or - # save gt datasets in the oracle bucket and upload in track_task_creation() - while True: - task_status, _ = cvat_api.get_task_upload_status(task_id) - if task_status not in [cvat_api.RequestStatus.STARTED, cvat_api.RequestStatus.QUEUED]: - return task_status - - sleep(Config.cvat_config.task_creation_check_interval) - - def _setup_gt_job_for_cvat_task( - self, task_id: int, gt_dataset: dm.Dataset, *, dm_export_format: str = "coco" - ) -> None: - task_status = self._wait_task_creation(task_id) - if task_status != cvat_api.RequestStatus.FINISHED: - return # will be handled in state_trackers.py::track_task_creation - - dm_format_to_cvat_format = { - "coco": "COCO 1.0", - "cvat": "CVAT 1.1", - "datumaro": "Datumaro 1.0", - } - - with TemporaryDirectory() as tmp_dir: - export_dir = Path(tmp_dir) / "export" - gt_dataset.export(save_dir=str(export_dir), save_media=False, format=dm_export_format) - - annotations_archive_path = Path(tmp_dir) / "annotations.zip" - with annotations_archive_path.open("wb") as annotations_archive: - write_dir_to_zip_archive(export_dir, annotations_archive) - - if Config.is_development_mode(): - self._save_cvat_gt_dataset_to_oracle_bucket( - gt_dataset_path=annotations_archive_path, file_suffix=f"for_task_{task_id}" - ) - - self._setup_gt_job( - task_id, - annotations_archive_path, - format_name=dm_format_to_cvat_format[dm_export_format], - ) - - def _setup_gt_job(self, task_id: int, dataset_path: Path, format_name: str) -> None: - gt_job = cvat_api.get_gt_job(task_id) - cvat_api.upload_gt_annotations(gt_job.id, dataset_path, format_name=format_name) - cvat_api.finish_gt_job(gt_job.id) - - def _setup_quality_settings(self, task_id: int, **overrides) -> None: - settings = cvat_api.get_quality_control_settings(task_id) - - values = { - "target_metric_threshold": self.manifest.validation.min_quality, - "empty_is_annotated": True, - } - values.update(**overrides) - cvat_api.update_quality_control_settings(settings.id, **values) - - def _split_dataset_per_task( - self, - data_filenames: list[str], - *, - subset_size: int, - ) -> Generator[str]: - random.shuffle(data_filenames) - yield from take_by(data_filenames, subset_size) - - @abstractmethod - def build(self) -> None: ... - - -class SimpleTaskBuilder(_TaskBuilderBase): - """ - Handles task creation for the IMAGE_BOXES task type - """ - - def _upload_task_meta(self, gt_dataset: dm.Dataset): - layout = simple_task.TaskMetaLayout() - serializer = simple_task.TaskMetaSerializer() - - file_list = [] - file_list.append( - ( - serializer.serialize_gt_annotations(gt_dataset), - layout.GT_FILENAME, - ) - ) - - storage_client = self._make_cloud_storage_client(self._oracle_data_bucket) - for file_data, filename in file_list: - storage_client.create_file( - compose_data_bucket_filename(self.escrow_address, self.chain_id, filename), - file_data, - ) - - def _parse_gt_dataset( - self, gt_file_data: bytes, *, add_prefix: str | None = None - ) -> dm.Dataset: - with TemporaryDirectory() as gt_temp_dir: - gt_filename = os.path.join(gt_temp_dir, "gt_annotations.json") - with open(gt_filename, "wb") as f: - f.write(gt_file_data) - - gt_dataset = dm.Dataset.import_from( - gt_filename, - format=DM_GT_DATASET_FORMAT_MAPPING[self.manifest.annotation.type], - ) - - if add_prefix: - gt_dataset = dm.Dataset.from_iterable( - [s.wrap(id=os.path.join(add_prefix, s.id)) for s in gt_dataset], - categories=gt_dataset.categories(), - media_type=gt_dataset.media_type(), - ) - - gt_dataset.init_cache() - - return gt_dataset - - def _get_gt_filenames( - self, gt_dataset: dm.Dataset, data_filenames: list[str], *, manifest: TaskManifest - ) -> list[str]: - gt_filenames = set(s.id + s.media.ext for s in gt_dataset) - known_data_filenames = set(data_filenames) - matched_gt_filenames = gt_filenames.intersection(known_data_filenames) - - if len(gt_filenames) != len(matched_gt_filenames): - missing_gt = gt_filenames - matched_gt_filenames - raise DatasetValidationError( - "Failed to find several validation samples in the dataset files: {}".format( - format_sequence(list(missing_gt)) - ) - ) - - if len(gt_filenames) < manifest.validation.val_size: - raise TooFewSamples( - f"Too few validation samples provided ({len(gt_filenames)}), " - f"at least {manifest.validation.val_size} required." - ) - - return list(matched_gt_filenames) - - def build(self): - manifest = self.manifest - escrow_address = self.escrow_address - chain_id = self.chain_id - - data_bucket = BucketAccessInfo.parse_obj(manifest.data.data_url) - gt_bucket = BucketAccessInfo.parse_obj(manifest.validation.gt_url) - - data_bucket_client = cloud_service.make_client(data_bucket) - gt_bucket_client = cloud_service.make_client(gt_bucket) - - # Task configuration creation - data_filenames = data_bucket_client.list_files(prefix=data_bucket.path) - data_filenames = filter_image_files(data_filenames) - - gt_file_data = gt_bucket_client.download_file(gt_bucket.path) - - # Validate and parse GT - gt_dataset = self._parse_gt_dataset(gt_file_data, add_prefix=data_bucket.path) - - # Create task configuration - gt_filenames = self._get_gt_filenames(gt_dataset, data_filenames, manifest=manifest) - data_to_be_annotated = [f for f in data_filenames if f not in set(gt_filenames)] - label_configuration = make_label_configuration(manifest) - - self._upload_task_meta(gt_dataset) - - # Register cloud storage on CVAT to pass user dataset - cloud_storage = cvat_api.create_cloudstorage(**_make_cvat_cloud_storage_params(data_bucket)) - - # Create a project - cvat_project = cvat_api.create_project( - escrow_address, - labels=label_configuration, - user_guide=manifest.annotation.user_guide, - ) - - # Setup webhooks for the project - cvat_webhook = cvat_api.create_cvat_webhook(cvat_project.id) - - with SessionLocal.begin() as session: - segment_size = self._task_segment_size - total_jobs = math.ceil(len(data_to_be_annotated) / segment_size) - - self.logger.info( - "Task creation for escrow '%s': will create %s assignments", - escrow_address, - total_jobs, - ) - db_service.create_escrow_creation( - session, escrow_address=escrow_address, chain_id=chain_id, total_jobs=total_jobs - ) - - project_id = db_service.create_project( - session, - cvat_project.id, - cloud_storage.id, - manifest.annotation.type, - escrow_address, - chain_id, - data_bucket.to_url(), - cvat_webhook_id=cvat_webhook.id, - ) - - db_service.get_project_by_id(session, project_id, for_update=True) # lock the row - db_service.add_project_images(session, cvat_project.id, data_filenames) - - for data_subset in self._split_dataset_per_task( - data_to_be_annotated, - subset_size=Config.cvat_config.max_jobs_per_task * segment_size, - ): - cvat_task = cvat_api.create_task( - cvat_project.id, escrow_address, segment_size=segment_size - ) - task_id = db_service.create_task( - session, cvat_task.id, cvat_project.id, TaskStatuses[cvat_task.status] - ) - db_service.get_task_by_id(session, task_id, for_update=True) # lock the row - - # The task is fully created once 'update:task' webhook is received. - cvat_api.put_task_data( - cvat_task.id, - cloud_storage.id, - filenames=data_subset, - validation_params={ - "gt_filenames": gt_filenames, # include whole GT dataset into each task - "gt_frames_per_job_count": self._job_val_frames_count, - }, - ) - - self._setup_gt_job_for_cvat_task(cvat_task.id, gt_dataset) - self._setup_quality_settings(cvat_task.id) - - db_service.create_data_upload(session, cvat_task.id) - db_service.touch(session, Project, [project_id]) - - -class PointsTaskBuilder(SimpleTaskBuilder): - def __init__(self, manifest: TaskManifest, escrow_address: str, chain_id: int) -> None: - super().__init__(manifest=manifest, escrow_address=escrow_address, chain_id=chain_id) - - self._mean_gt_bbox_radius_estimation: _MaybeUnset[float] = _unset - - def _parse_gt_dataset(self, gt_file_data, *, add_prefix=None): - gt_dataset = super()._parse_gt_dataset(gt_file_data, add_prefix=add_prefix) - - assert len(gt_dataset.categories()[dm.AnnotationType.label]) == 1 - label_id = 0 - - updated_gt_dataset = dm.Dataset(categories=gt_dataset.categories(), media_type=dm.Image) - - # Replace boxes with their center points - # Collect radius statistics - radiuses = [] - for gt_sample in gt_dataset: - image_size = gt_sample.media_as(dm.Image).size - image_half_diag = ((image_size[0] ** 2 + image_size[1] ** 2) ** 0.5) / 2 - - sample_points = [] - for gt_bbox in gt_sample.annotations: - if not isinstance(gt_bbox, dm.Bbox): - continue - - x, y, w, h = gt_bbox.get_bbox() - bbox_center = dm.Points([x + w / 2, y + h / 2], label=gt_bbox.label, id=gt_bbox.id) - - rel_int_bbox_radius = min(w, h) / 2 / image_half_diag - radiuses.append(rel_int_bbox_radius) - - sample_points.extend(bbox_center.points) - - # Join points into a single annotation for compatibility with CVAT capabilities - updated_anns = [] - if sample_points: - updated_anns.append(dm.Points(sample_points, label=label_id)) - - updated_gt_dataset.put(gt_sample.wrap(annotations=updated_anns)) - - self._mean_gt_bbox_radius_estimation = min(0.5, np.mean(radiuses).item()) - - return updated_gt_dataset - - def _upload_task_meta(self, gt_dataset: dm.Dataset): - layout = points_task.TaskMetaLayout() - serializer = points_task.TaskMetaSerializer() - - file_list = [] - file_list.append( - ( - serializer.serialize_gt_annotations(gt_dataset), - layout.GT_FILENAME, - ) - ) - - storage_client = self._make_cloud_storage_client(self._oracle_data_bucket) - for file_data, filename in file_list: - storage_client.create_file( - compose_data_bucket_filename(self.escrow_address, self.chain_id, filename), - file_data, - ) - - def _setup_gt_job_for_cvat_task( - self, task_id: int, gt_dataset: dm.Dataset, *, dm_export_format: str = "datumaro" - ) -> None: - super()._setup_gt_job_for_cvat_task( - task_id=task_id, gt_dataset=gt_dataset, dm_export_format=dm_export_format - ) - - def _setup_quality_settings(self, task_id: int, **overrides) -> None: - assert self._mean_gt_bbox_radius_estimation is not _unset - - values = { - # We have at most 1 annotation per frame, so accuracy on each frame is either 0 or 1, - # regardless of the points count. For job accuracy we'll have: - # quality = mean frame accuracy = count of correct frames / validation frame count. - # If we set quality threshold from the manifest on this value, it can break quality - # requirements. - # Example: target quality is 80%, 6 frames, 1 has 20 points, 5 others have 1. - # Suppose the 5 frames with 1 point are annotated correctly and - # the one with 20 - is not annotated. The mean frame accuracy will be 5 / 6 ~ 83%, - # which is higher than the target quality, so the job will be accepted. - # The per-point mean (aka micro) accuracy will be 5 / (20 + 5) = 20%. - # - # Instead, we require that each frame matches with the required quality threshold, - # so the job accuracy is 1. This is a more strict requirement, from which - # follows that the job quality >= required. - # For each frame, as we have just 1 annotation, quality is computed as mean - # point quality on the frame with frame matching threshold. - # Point set accuracy is controlled by iou_threshold, - # so configure it with the requested quality value. - # - # TODO: consider adding a quality option to count points as separate, - # or implement and use the mean IoU as the target metric in CVAT. - "target_metric_threshold": 0.95, # some big number close to 1 - "iou_threshold": self.manifest.validation.min_quality, - "oks_sigma": self._mean_gt_bbox_radius_estimation, - "point_size_base": "image_size", - } - values.update(overrides) - super()._setup_quality_settings(task_id, **values) - - def build(self): - if len(self.manifest.annotation.labels) != 1: - # TODO: implement support for multiple labels - # Probably, need to split the whole task into projects per label - # for efficient annotation - raise NotImplementedError("Point annotation tasks can have only 1 label") - - return super().build() - - -class PolygonTaskBuilder(SimpleTaskBuilder): - def _setup_quality_settings(self, task_id: int, **overrides) -> None: - values = {"iou_threshold": Config.cvat_config.iou_threshold, **overrides} - super()._setup_quality_settings(task_id, **values) - - -class BoxesFromPointsTaskBuilder(_TaskBuilderBase): - def __init__(self, manifest: TaskManifest, escrow_address: str, chain_id: int) -> None: - super().__init__(manifest=manifest, escrow_address=escrow_address, chain_id=chain_id) - - self._input_gt_data: _MaybeUnset[bytes] = _unset - self._input_points_data: _MaybeUnset[bytes] = _unset - - self._data_filenames: _MaybeUnset[Sequence[str]] = _unset - self._input_gt_dataset: _MaybeUnset[dm.Dataset] = _unset - self._gt_dataset: _MaybeUnset[dm.Dataset] = _unset - self._gt_roi_dataset: _MaybeUnset[dm.Dataset] = _unset - self._points_dataset: _MaybeUnset[dm.Dataset] = _unset - - self._bbox_point_mapping: _MaybeUnset[boxes_from_points_task.BboxPointMapping] = _unset - "bbox_id -> point_id" - - self._roi_size_estimations: _MaybeUnset[dict[int, tuple[float, float]]] = _unset - "label_id -> (rel. w, rel. h)" - - self._rois: _MaybeUnset[boxes_from_points_task.RoiInfos] = _unset - self._roi_filenames: _MaybeUnset[boxes_from_points_task.RoiFilenames] = _unset - self._roi_filenames_to_be_annotated: _MaybeUnset[Sequence[str]] = _unset - self._gt_roi_filenames: _MaybeUnset[Sequence[str]] = _unset - - self._job_layout: _MaybeUnset[Sequence[Sequence[str]]] = _unset - "File lists per CVAT job" - - self._label_configuration: _MaybeUnset[Sequence[dict]] = _unset - - self._excluded_points_info: _MaybeUnset[_ExcludedAnnotationsInfo] = _unset - self._excluded_gt_info: _MaybeUnset[_ExcludedAnnotationsInfo] = _unset - - # Configuration / constants - # TODO: consider WebP if produced files are too big - self.roi_file_ext = ".png" # supposed to be lossless and reasonably compressing - "File extension for RoI images, with leading dot (.) included" - - self.list_display_threshold = 5 - "The maximum number of rendered list items in a message" - - self.roi_size_mult = 1.1 - "Additional point ROI size multiplier" - - self.min_roi_size = ( - Config.core_config.min_roi_size_w, - Config.core_config.min_roi_size_h, - ) - "Minimum absolute ROI size, (w, h)" - - self.points_format = "coco_person_keypoints" - - self.embed_point_in_roi_image = True - "Put a small point into the extracted RoI images for the original point" - - self.embedded_point_radius = 15 - self.min_embedded_point_radius_percent = 0.005 - self.max_embedded_point_radius_percent = 0.01 - self.embedded_point_color = (0, 255, 255) - self.roi_background_color = (245, 240, 242) # BGR - CVAT background color - - self.oracle_data_bucket = BucketAccessInfo.parse_obj(Config.storage_config) - - self.min_class_samples_for_roi_estimation = 25 - - self.max_class_roi_image_side_threshold = 0.5 - """ - The maximum allowed percent of the image for the estimated class RoI, - before the default RoI is used. Too big RoI estimations reduce the overall - prediction quality, making them unreliable. - """ - - self.max_discarded_threshold = 0.5 - """ - The maximum allowed percent of discarded - GT boxes, points, or samples for successful job launch - """ - - # TODO: probably, need to also add an absolute number of minimum GT RoIs - - def _download_input_data(self): - data_bucket = BucketAccessInfo.parse_obj(self.manifest.data.data_url) - gt_bucket = BucketAccessInfo.parse_obj(self.manifest.validation.gt_url) - points_bucket = BucketAccessInfo.parse_obj(self.manifest.data.points_url) - - data_storage_client = self._make_cloud_storage_client(data_bucket) - gt_storage_client = self._make_cloud_storage_client(gt_bucket) - points_storage_client = self._make_cloud_storage_client(points_bucket) - - data_filenames = data_storage_client.list_files(prefix=data_bucket.path) - data_filenames = strip_bucket_prefix(data_filenames, prefix=data_bucket.path) - self._data_filenames = filter_image_files(data_filenames) - - self._input_gt_data = gt_storage_client.download_file(gt_bucket.path) - self._input_gt_filename = Path(gt_bucket.path).name - - self._input_points_data = points_storage_client.download_file(points_bucket.path) - - def _parse_dataset(self, annotation_file_data: bytes, dataset_format: str) -> dm.Dataset: - temp_dir = self.exit_stack.enter_context(TemporaryDirectory()) - - annotation_filename = os.path.join(temp_dir, "annotations.json") - with open(annotation_filename, "wb") as f: - f.write(annotation_file_data) - - return dm.Dataset.import_from(annotation_filename, format=dataset_format) - - def _parse_gt(self): - assert self._input_gt_data is not _unset - - self._input_gt_dataset = self._parse_dataset( - self._input_gt_data, - dataset_format=DM_GT_DATASET_FORMAT_MAPPING[self.manifest.annotation.type], - ) - - def _parse_points(self): - assert self._input_points_data is not _unset - - self._points_dataset = self._parse_dataset( - self._input_points_data, dataset_format=self.points_format - ) - - def _validate_gt_labels(self): - gt_labels = set( - label.name - for label in self._input_gt_dataset.categories()[dm.AnnotationType.label] - if not label.parent - ) - manifest_labels = set(label.name for label in self.manifest.annotation.labels) - if gt_labels - manifest_labels: - raise DatasetValidationError( - "GT labels do not match job labels. Unknown labels: {}".format( - format_sequence(list(gt_labels - manifest_labels)), - ) - ) - - self._input_gt_dataset.transform( - ProjectLabels, dst_labels=[label.name for label in self.manifest.annotation.labels] - ) - self._input_gt_dataset.init_cache() - - def _validate_gt_filenames(self): - gt_filenames = set(s.id + s.media.ext for s in self._input_gt_dataset) - - known_data_filenames = set(self._data_filenames) - matched_gt_filenames = gt_filenames.intersection(known_data_filenames) - - if len(gt_filenames) != len(matched_gt_filenames): - extra_gt = list(map(os.path.basename, gt_filenames - matched_gt_filenames)) - - raise MismatchingAnnotations( - "Failed to find several validation samples in the dataset files: {}".format( - format_sequence(extra_gt) - ) - ) - - if len(gt_filenames) < self._job_val_frames_count: - raise TooFewSamples( - f"Too few validation samples provided ({len(gt_filenames)}), " - f"at least {self._job_val_frames_count} required." - ) - - def _validate_gt_annotations(self): - label_cat: dm.LabelCategories = self._input_gt_dataset.categories()[dm.AnnotationType.label] - - excluded_gt_info = _ExcludedAnnotationsInfo() - excluded_samples = set() - visited_ids = set() - for gt_sample in self._input_gt_dataset: - # Could fail on this as well - img_h, img_w = gt_sample.media_as(dm.Image).size - - sample_boxes = [a for a in gt_sample.annotations if isinstance(a, dm.Bbox)] - valid_boxes = [] - for bbox in sample_boxes: - if not ( - (0 <= int(bbox.x) < int(bbox.x + bbox.w) <= img_w) - and (0 <= int(bbox.y) < int(bbox.y + bbox.h) <= img_h) - ): - excluded_gt_info.add_message( - "Sample '{}': GT bbox #{} ({}) - invalid coordinates".format( - gt_sample.id, bbox.id, label_cat[bbox.label].name - ), - sample_id=gt_sample.id, - sample_subset=gt_sample.subset, - ) - continue - - if bbox.id in visited_ids: - excluded_gt_info.add_message( - "Sample '{}': GT bbox #{} ({}) skipped - repeated annotation id {}".format( - gt_sample.id, bbox.id, label_cat[bbox.label].name, bbox.id - ), - sample_id=gt_sample.id, - sample_subset=gt_sample.subset, - ) - continue - - valid_boxes.append(bbox) - - excluded_gt_info.excluded_count += len(sample_boxes) - len(valid_boxes) - excluded_gt_info.total_count += len(sample_boxes) - - if len(valid_boxes) != len(sample_boxes): - if not valid_boxes: - excluded_samples.add((gt_sample.id, gt_sample.subset)) - else: - self._input_gt_dataset.put(gt_sample.wrap(annotations=valid_boxes)) - - for excluded_sample in excluded_samples: - self._input_gt_dataset.remove(*excluded_sample) - - if excluded_gt_info.excluded_count: - self.logger.warning( - "Some GT boxes were excluded due to the errors found: \n{}".format( - format_sequence([e.message for e in excluded_gt_info.messages], separator="\n") - ) - ) - - if excluded_gt_info.excluded_count > ceil( - excluded_gt_info.total_count * self.max_discarded_threshold - ): - raise TooFewSamples( - "Too many GT boxes discarded, canceling job creation. Errors: {}".format( - format_sequence( - [error_info.message for error_info in excluded_gt_info.messages] - ) - ) - ) - - self._excluded_gt_info = excluded_gt_info - - def _validate_gt(self): - assert self._data_filenames is not _unset - assert self._input_gt_dataset is not _unset - - self._validate_gt_filenames() - self._validate_gt_labels() - self._validate_gt_annotations() - - def _validate_points_categories(self): - invalid_point_categories_messages = [] - points_dataset_categories = self._points_dataset.categories() - points_dataset_label_cat: dm.LabelCategories = points_dataset_categories[ - dm.AnnotationType.label - ] - for category_id, category in points_dataset_categories[ - dm.AnnotationType.points - ].items.items(): - if len(category.labels) != 1: - invalid_point_categories_messages.append( - "Category '{}' (#{}): {}".format( - points_dataset_label_cat[category_id].name, - category_id, - f"too many skeleton points ({len(category.labels)}), only 1 expected", - ) - ) - - if invalid_point_categories_messages: - raise InvalidCategories( - "Invalid categories in the input point annotations: {}".format( - format_sequence(invalid_point_categories_messages, separator="; ") - ) - ) - - points_labels = set(label.name for label in points_dataset_label_cat if not label.parent) - manifest_labels = set(label.name for label in self.manifest.annotation.labels) - if manifest_labels != points_labels: - raise DatasetValidationError("Point labels do not match job labels") - - self._points_dataset.transform( - ProjectLabels, dst_labels=[label.name for label in self.manifest.annotation.labels] - ) - self._points_dataset.init_cache() - - def _validate_points_filenames(self): - points_filenames = set(sample.id + sample.media.ext for sample in self._points_dataset) - - known_data_filenames = set(self._data_filenames) - matched_points_filenames = points_filenames.intersection(known_data_filenames) - - if len(matched_points_filenames) != len(points_filenames): - extra_point_samples = list( - map(os.path.basename, points_filenames - matched_points_filenames) - ) - - raise MismatchingAnnotations( - "Failed to find several samples in the dataset files: {}".format( - format_sequence(extra_point_samples), - ) - ) - - def _validate_points_annotations(self): - def _validate_skeleton(skeleton: dm.Skeleton, *, sample_bbox: dm.Bbox): - if skeleton.id in visited_ids: - raise DatasetValidationError(f"repeated annotation id ({skeleton.id})") - - if len(skeleton.elements) != 1: - raise DatasetValidationError( - f"invalid points count ({len(skeleton.elements)}), expected 1" - ) - - point = skeleton.elements[0] - px, py = point.points[:2] - if not is_point_in_bbox(px, py, sample_bbox): - raise InvalidCoordinates("coordinates are outside image") - - label_cat: dm.LabelCategories = self._points_dataset.categories()[dm.AnnotationType.label] - - excluded_points_info = _ExcludedAnnotationsInfo() - excluded_samples = set() - visited_ids = set() - for sample in self._points_dataset: - # Could fail on this as well - image_h, image_w = sample.image.size - sample_bbox = dm.Bbox(0, 0, w=image_w, h=image_h) - - sample_skeletons = [a for a in sample.annotations if isinstance(a, dm.Skeleton)] - valid_skeletons = [] - for skeleton in sample_skeletons: - # Here 1 skeleton describes 1 point - try: - _validate_skeleton(skeleton, sample_bbox=sample_bbox) - except InvalidCoordinates as error: - excluded_points_info.add_message( - "Sample '{}': point #{} ({}) skipped - {}".format( - sample.id, skeleton.id, label_cat[skeleton.label].name, error - ), - sample_id=sample.id, - sample_subset=sample.subset, - ) - continue - except DatasetValidationError as error: - excluded_points_info.add_message( - "Sample '{}': point #{} ({}) - {}".format( - sample.id, skeleton.id, label_cat[skeleton.label].name, error - ), - sample_id=sample.id, - sample_subset=sample.subset, - ) - continue - - valid_skeletons.append(skeleton) - - excluded_points_info.excluded_count += len(sample_skeletons) - len(valid_skeletons) - excluded_points_info.total_count += len(sample_skeletons) - - if len(valid_skeletons) != len(sample_skeletons): - if not valid_skeletons: - excluded_samples.add((sample.id, sample.subset)) - else: - self._points_dataset.put(sample.wrap(annotations=valid_skeletons)) - - for excluded_sample in excluded_samples: - self._points_dataset.remove(*excluded_sample) - - if excluded_points_info.excluded_count: - self.logger.warning( - "Some points were excluded due to the errors found: \n{}".format( - format_sequence( - [e.message for e in excluded_points_info.messages], separator="\n" - ) - ) - ) - - if excluded_points_info.excluded_count > ceil( - excluded_points_info.total_count * self.max_discarded_threshold - ): - raise TooFewSamples( - "Too many points discarded, canceling job creation. Errors: {}".format( - format_sequence( - [error_info.message for error_info in excluded_points_info.messages] - ) - ) - ) - - self._excluded_points_info = excluded_points_info - - def _validate_points(self): - assert self._data_filenames is not _unset - assert self._points_dataset is not _unset - - self._validate_points_categories() - self._validate_points_filenames() - self._validate_points_annotations() - - @staticmethod - def _is_point_in_bbox(px: float, py: float, bbox: dm.Bbox) -> bool: - return is_point_in_bbox(px, py, bbox) - - def _prepare_gt(self): - def _find_unambiguous_matches( - input_skeletons: list[dm.Skeleton], - gt_boxes: list[dm.Bbox], - ) -> list[tuple[dm.Skeleton, dm.Bbox]]: - matches = [ - [ - (input_skeleton.label == gt_bbox.label) - and ( - self._is_point_in_bbox( - *input_skeleton.elements[0].points[0:2], bbox=gt_bbox - ) - ) - for gt_bbox in gt_boxes - ] - for input_skeleton in input_skeletons - ] - - ambiguous_boxes: list[int] = set() - ambiguous_skeletons: list[int] = set() - for skeleton_idx, input_skeleton in enumerate(input_skeletons): - matched_boxes: list[dm.Bbox] = [ - gt_boxes[j] for j in range(len(gt_boxes)) if matches[skeleton_idx][j] - ] - - if len(matched_boxes) > 1: - # Handle ambiguous matches - excluded_points_info.add_message( - "Sample '{}': point #{} ({}) and overlapping boxes skipped - " - "too many matching boxes ({}) found".format( - points_sample.id, - input_skeleton.id, - points_label_cat[input_skeleton.label].name, - format_sequence([f"#{a.id}" for a in matched_boxes]), - ), - sample_id=points_sample.id, - sample_subset=points_sample.subset, - ) - # not an error, should not be counted as excluded for an error - ambiguous_skeletons.add(input_skeleton.id) - ambiguous_boxes.update(a.id for a in matched_boxes) - continue - - for gt_idx, gt_bbox in enumerate(gt_boxes): - matched_skeletons: list[dm.Skeleton] = [ - input_skeletons[i] for i in range(len(input_skeletons)) if matches[i][gt_idx] - ] - - if len(matched_skeletons) > 1: - # Handle ambiguous matches - excluded_gt_info.add_message( - "Sample '{}': GT bbox #{} ({}) and overlapping points skipped - " - "too many matching points ({}) found".format( - gt_sample.id, - gt_bbox.id, - gt_label_cat[gt_bbox.label].name, - format_sequence([f"#{a.id}" for a in matched_skeletons]), - ), - sample_id=gt_sample.id, - sample_subset=gt_sample.subset, - ) - # not an error, should not be counted as excluded for an error - ambiguous_boxes.add(gt_bbox.id) - ambiguous_skeletons.update(a.id for a in matched_skeletons) - continue - if not matched_skeletons: - # Handle unmatched skeletons - excluded_gt_info.add_message( - "Sample '{}': GT bbox #{} ({}) skipped - " - "no matching points found".format( - gt_sample.id, - gt_bbox.id, - gt_label_cat[gt_bbox.label].name, - ), - sample_id=gt_sample.id, - sample_subset=gt_sample.subset, - ) - excluded_gt_info.excluded_count += 1 # an error - continue - - unambiguous_matches: list[tuple[dm.Bbox, dm.Skeleton]] = [] - for skeleton_idx, input_skeleton in enumerate(input_skeletons): - if input_skeleton.id in ambiguous_skeletons: - continue - - matched_bbox = None - for gt_idx, gt_bbox in enumerate(gt_boxes): - if gt_bbox.id in ambiguous_boxes: - continue - - if matches[skeleton_idx][gt_idx]: - matched_bbox = gt_bbox - break - - if matched_bbox: - unambiguous_matches.append((input_skeleton, matched_bbox)) - - return unambiguous_matches - - def _find_good_gt_boxes( - input_skeletons: list[dm.Skeleton], - gt_boxes: list[dm.Bbox], - ) -> list[dm.Bbox]: - matches = _find_unambiguous_matches(input_skeletons, gt_boxes) - - matched_boxes = [] - for input_skeleton, gt_bbox in matches: - gt_count_per_class[gt_bbox.label] = gt_count_per_class.get(gt_bbox.label, 0) + 1 - - matched_boxes.append(gt_bbox) - bbox_point_mapping[gt_bbox.id] = input_skeleton.id - - return matched_boxes - - assert self._data_filenames is not _unset - assert self._points_dataset is not _unset - assert self._input_gt_dataset is not _unset - assert [ - label.name for label in self._input_gt_dataset.categories()[dm.AnnotationType.label] - ] == [label.name for label in self.manifest.annotation.labels] - assert [ - label.name - for label in self._points_dataset.categories()[dm.AnnotationType.label] - if not label.parent - ] == [label.name for label in self.manifest.annotation.labels] - - points_label_cat: dm.LabelCategories = self._points_dataset.categories()[ - dm.AnnotationType.label - ] - gt_label_cat: dm.LabelCategories = self._input_gt_dataset.categories()[ - dm.AnnotationType.label - ] - - updated_gt_dataset = dm.Dataset( - categories=self._input_gt_dataset.categories(), media_type=dm.Image - ) - - excluded_points_info = _ExcludedAnnotationsInfo() # local for the function - excluded_gt_info = self._excluded_gt_info - gt_count_per_class = {} - bbox_point_mapping = {} # bbox id -> point id - for gt_sample in self._input_gt_dataset: - points_sample = self._points_dataset.get(gt_sample.id, gt_sample.subset) - assert points_sample - - gt_boxes = [a for a in gt_sample.annotations if isinstance(a, dm.Bbox)] - input_skeletons = [a for a in points_sample.annotations if isinstance(a, dm.Skeleton)] - - # Samples without boxes are allowed, so we just skip them without an error - if not gt_boxes: - continue - - matched_boxes = _find_good_gt_boxes(input_skeletons, gt_boxes) - if not matched_boxes: - continue - - updated_gt_dataset.put(gt_sample.wrap(annotations=matched_boxes)) - - if excluded_points_info.messages: - self.logger.warning( - "Some points were excluded from GT due to the problems found: \n{}".format( - format_sequence( - [e.message for e in excluded_points_info.messages], separator="\n" - ) - ) - ) - - if excluded_gt_info.messages: - self.logger.warning( - "Some GT annotations were excluded due to the problems found: \n{}".format( - format_sequence([e.message for e in excluded_gt_info.messages], separator="\n") - ) - ) - - if excluded_gt_info.excluded_count > ceil( - excluded_gt_info.total_count * self.max_discarded_threshold - ): - raise DatasetValidationError( - "Too many GT boxes discarded ({} out of {}). " - "Please make sure each GT box matches exactly 1 point".format( - excluded_gt_info.total_count - len(bbox_point_mapping), - excluded_gt_info.total_count, - ) - ) - - self.logger.info( - "GT counts per class to be used for validation: {}".format( - format_sequence( - [ - f"{gt_label_cat[label_id].name}: {count}" - for label_id, count in gt_count_per_class.items() - ] - ) - ) - ) - - gt_labels_without_anns = [ - gt_label_cat[label_id] - for label_id, label_count in gt_count_per_class.items() - if not label_count - ] - if gt_labels_without_anns: - raise DatasetValidationError( - "No matching GT boxes/points annotations found for some classes: {}".format( - format_sequence(gt_labels_without_anns) - ) - ) - - self._gt_dataset = updated_gt_dataset - self._bbox_point_mapping = bbox_point_mapping - - def _estimate_roi_sizes(self): - assert self._gt_dataset is not _unset - assert [label.name for label in self._gt_dataset.categories()[dm.AnnotationType.label]] == [ - label.name for label in self.manifest.annotation.labels - ] - - bbox_sizes_per_label = {} - for sample in self._gt_dataset: - image_h, image_w = self._points_dataset.get(sample.id, sample.subset).image.size - - for gt_bbox in sample.annotations: - gt_bbox = cast(dm.Bbox, gt_bbox) - bbox_sizes_per_label.setdefault(gt_bbox.label, []).append( - ( - gt_bbox.w / image_w, - gt_bbox.h / image_h, - ) - ) - - # Consider bbox sides as normally-distributed random variables, estimate max - # For big enough datasets, it should be reasonable approximation - # (due to the central limit theorem). This can work bad for small datasets, - # so we only do this if there are enough class samples. - classes_with_default_roi: dict[int, str] = {} # label_id -> reason - roi_size_estimations_per_label = {} # label id -> (w, h) - default_roi_size = (2, 2) # 2 will yield just the image size after halving - for label_id, label_sizes in bbox_sizes_per_label.items(): - if len(label_sizes) < self.min_class_samples_for_roi_estimation: - estimated_size = default_roi_size - classes_with_default_roi[label_id] = "too few GT provided" - else: - max_bbox = np.max(label_sizes, axis=0) - if np.any(max_bbox > self.max_class_roi_image_side_threshold): - estimated_size = default_roi_size - classes_with_default_roi[label_id] = "estimated RoI is unreliable" - else: - estimated_size = 2 * max_bbox * self.roi_size_mult - - roi_size_estimations_per_label[label_id] = estimated_size - - if classes_with_default_roi: - label_cat = self._gt_dataset.categories()[dm.AnnotationType.label] - labels_by_reason = { - g_reason: [v[0] for v in g_items] - for g_reason, g_items in groupby( - sorted(classes_with_default_roi.items(), key=lambda v: v[1]), key=lambda v: v[1] - ) - } - self.logger.warning( - "Some classes will use the full image instead of RoI - {}".format( - "; ".join( - "{}: {}".format( - g_reason, - format_sequence([label_cat[label_id].name for label_id in g_labels]), - ) - for g_reason, g_labels in labels_by_reason.items() - ) - ) - ) - - self._roi_size_estimations = roi_size_estimations_per_label - - def _prepare_roi_info(self): - assert self._gt_dataset is not _unset - assert self._roi_size_estimations is not _unset - assert self._points_dataset is not _unset - - rois: list[boxes_from_points_task.RoiInfo] = [] - for sample in self._points_dataset: - for skeleton in sample.annotations: - if not isinstance(skeleton, dm.Skeleton): - continue - - point_label_id = skeleton.label - original_point_x, original_point_y = skeleton.elements[0].points[:2] - original_point_x = int(original_point_x) - original_point_y = int(original_point_y) - - image_h, image_w = sample.image.size - - roi_est_w, roi_est_h = self._roi_size_estimations[point_label_id] - roi_est_w *= image_w - roi_est_h *= image_h - roi_est_w = max(roi_est_w, self.min_roi_size[0]) - roi_est_h = max(roi_est_h, self.min_roi_size[1]) - - roi_left = max(0, original_point_x - int(roi_est_w / 2)) - roi_top = max(0, original_point_y - int(roi_est_h / 2)) - roi_right = min(image_w, original_point_x + ceil(roi_est_w / 2)) - roi_bottom = min(image_h, original_point_y + ceil(roi_est_h / 2)) - - roi_w = roi_right - roi_left - roi_h = roi_bottom - roi_top - - new_point_x = original_point_x - roi_left - new_point_y = original_point_y - roi_top - - rois.append( - boxes_from_points_task.RoiInfo( - point_id=skeleton.id, - original_image_key=sample.attributes["id"], - point_x=new_point_x, - point_y=new_point_y, - roi_x=roi_left, - roi_y=roi_top, - roi_w=roi_w, - roi_h=roi_h, - ) - ) - - self._rois = rois - - def _mangle_filenames(self): - """ - Mangle filenames in the dataset to make them less recognizable by annotators - and hide private dataset info - """ - assert self._rois is not _unset - - # TODO: maybe add different names for the same GT images in - # different jobs to make them even less recognizable - self._roi_filenames = { - roi.point_id: str(uuid.uuid4()) + self.roi_file_ext for roi in self._rois - } - - def _prepare_job_layout(self): - assert self._rois is not _unset - assert self._bbox_point_mapping is not _unset - assert self._input_gt_dataset is not _unset - - # This list can be different from what is selected for validation - input_gt_filenames = set(sample.media.path for sample in self._input_gt_dataset) - original_image_id_to_filename = { - sample.attributes["id"]: sample.media.path for sample in self._points_dataset - } - point_id_to_original_image_id = {roi.point_id: roi.original_image_key for roi in self._rois} - - gt_point_ids = set(self._bbox_point_mapping.values()) - self._gt_roi_filenames = [self._roi_filenames[point_id] for point_id in gt_point_ids] - self._roi_filenames_to_be_annotated = [ - fn - for point_id, fn in self._roi_filenames.items() - if point_id not in gt_point_ids - if original_image_id_to_filename[point_id_to_original_image_id[point_id]] - not in input_gt_filenames - ] - - def _prepare_label_configuration(self): - self._label_configuration = make_label_configuration(self.manifest) - - def _upload_task_meta(self): - layout = boxes_from_points_task.TaskMetaLayout() - serializer = boxes_from_points_task.TaskMetaSerializer() - - file_list = [] - file_list.append((self._input_points_data, layout.POINTS_FILENAME)) - file_list.append( - ( - serializer.serialize_gt_annotations(self._gt_dataset), - layout.GT_FILENAME, - ) - ) - file_list.append( - ( - serializer.serialize_bbox_point_mapping(self._bbox_point_mapping), - layout.BBOX_POINT_MAPPING_FILENAME, - ) - ) - file_list.append((serializer.serialize_roi_info(self._rois), layout.ROI_INFO_FILENAME)) - file_list.append( - (serializer.serialize_roi_filenames(self._roi_filenames), layout.ROI_FILENAMES_FILENAME) - ) - - storage_client = self._make_cloud_storage_client(self.oracle_data_bucket) - for file_data, filename in file_list: - storage_client.create_file( - compose_data_bucket_filename(self.escrow_address, self.chain_id, filename), - file_data, - ) - - def _extract_roi( - self, source_pixels: np.ndarray, roi_info: boxes_from_points_task.RoiInfo - ) -> np.ndarray: - img_h, img_w, *_ = source_pixels.shape - - roi_pixels = source_pixels[ - max(0, roi_info.roi_y) : min(img_h, roi_info.roi_y + roi_info.roi_h), - max(0, roi_info.roi_x) : min(img_w, roi_info.roi_x + roi_info.roi_w), - ] - - if not ( - (0 <= roi_info.roi_x < roi_info.roi_x + roi_info.roi_w < img_w) - and (0 <= roi_info.roi_y < roi_info.roi_y + roi_info.roi_h < img_h) - ): - # Coords can be outside the original image - # In this case a border should be added to RoI, so that the image was centered on bbox - wrapped_roi_pixels = np.zeros((roi_info.roi_h, roi_info.roi_w, 3), dtype=np.float32) - wrapped_roi_pixels[:, :] = self.roi_background_color - - dst_y = max(-roi_info.roi_y, 0) - dst_x = max(-roi_info.roi_x, 0) - wrapped_roi_pixels[ - dst_y : dst_y + roi_pixels.shape[0], - dst_x : dst_x + roi_pixels.shape[1], - ] = roi_pixels - - roi_pixels = wrapped_roi_pixels - else: - roi_pixels = roi_pixels.copy() - - return roi_pixels - - def _draw_roi_point( - self, roi_pixels: np.ndarray, roi_info: boxes_from_points_task.RoiInfo - ) -> np.ndarray: - center = (roi_info.point_x, roi_info.point_y) - - roi_r = (roi_info.roi_w**2 + roi_info.roi_h**2) ** 0.5 / 2 - point_size = int( - min( - self.max_embedded_point_radius_percent * roi_r, - max(self.embedded_point_radius, self.min_embedded_point_radius_percent * roi_r), - ) - ) - - roi_pixels = roi_pixels.copy() - roi_pixels = cv2.circle( - roi_pixels, - center, - point_size + 1, - (255, 255, 255), - cv2.FILLED, - ) - return cv2.circle( - roi_pixels, - center, - point_size, - self.embedded_point_color, - cv2.FILLED, - ) - - def _extract_and_upload_rois(self): - assert self._points_dataset is not _unset - assert self._rois is not _unset - assert self._data_filenames is not _unset - assert self._roi_filenames is not _unset - - src_bucket = BucketAccessInfo.parse_obj(self.manifest.data.data_url) - src_prefix = src_bucket.path - dst_bucket = self.oracle_data_bucket - - src_client = self._make_cloud_storage_client(src_bucket) - dst_client = self._make_cloud_storage_client(dst_bucket) - - image_id_to_filename = { - sample.attributes["id"]: sample.image.path for sample in self._points_dataset - } - - filename_to_sample = {sample.image.path: sample for sample in self._points_dataset} - - def _roi_key(e): - return e.original_image_key - - rois_by_image: dict[str, Sequence[boxes_from_points_task.RoiInfo]] = { - image_id_to_filename[image_id]: list(g) - for image_id, g in groupby(sorted(self._rois, key=_roi_key), key=_roi_key) - } - - def process_file(filename: str, image_pixels: np.ndarray): - image_roi_infos = rois_by_image.get(filename, []) - if not image_roi_infos: - return - - sample = filename_to_sample[filename] - if tuple(sample.image.size) != tuple(image_pixels.shape[:2]): - # TODO: maybe rois should be regenerated instead - # Option 2: accumulate errors, fail when some threshold is reached - # Option 3: add special handling for cases when image is only rotated (exif etc.) - raise InvalidImageInfo( - f"Sample '{filename}': invalid size provided in the point annotations" - ) - - image_rois = {} - for roi_info in image_roi_infos: - roi_pixels = self._extract_roi(image_pixels, roi_info) - - if self.embed_point_in_roi_image: - roi_pixels = self._draw_roi_point(roi_pixels, roi_info) - - roi_filename = self._roi_filenames[roi_info.point_id] - roi_bytes = encode_image(roi_pixels, os.path.splitext(roi_filename)[-1]) - - image_rois[roi_filename] = roi_bytes - - for roi_filename, roi_bytes in image_rois.items(): - dst_client.create_file( - compose_data_bucket_filename(self.escrow_address, self.chain_id, roi_filename), - roi_bytes, - ) - - def download_and_decode(key: str): - image_bytes = src_client.download_file(key) - return decode_image(image_bytes) - - pool_size = Config.features.max_data_storage_connections - download_queue_size = 4 * pool_size - download_queue = Queue[tuple[str, Future[np.ndarray]]](download_queue_size) - roi_uploader = BufferedRoiImageUploader(queue=download_queue) - with ThreadPoolExecutor(pool_size) as pool: - - def put_callback(filename: str): - image_roi_infos = rois_by_image.get(filename, []) - if not image_roi_infos: - return None - - return ( - filename, - pool.submit(download_and_decode, os.path.join(src_prefix, filename)), - ) - - def process_callback(result: tuple[str, Future]): - filename, task = result - process_file(filename, task.result()) - - roi_uploader.process_all( - self._data_filenames, put_callback=put_callback, process_callback=process_callback - ) - - def _prepare_gt_roi_dataset(self): - self._gt_roi_dataset = dm.Dataset( - categories=self._gt_dataset.categories(), media_type=dm.Image - ) - - roi_info_by_point_id: dict[int, skeletons_from_boxes_task.RoiInfo] = { - roi_info.point_id: roi_info for roi_info in self._rois - } - - for sample in self._gt_dataset: - for gt_bbox in sample.annotations: - assert isinstance(gt_bbox, dm.Bbox) - - point_id = self._bbox_point_mapping[gt_bbox.id] - gt_roi_filename = compose_data_bucket_filename( - self.escrow_address, self.chain_id, self._roi_filenames[point_id] - ) - - # update gt bbox coordinates to match RoI shift - roi_info = roi_info_by_point_id[point_id] - new_x = gt_bbox.points[0] - roi_info.roi_x - new_y = gt_bbox.points[1] - roi_info.roi_y - - self._gt_roi_dataset.put( - sample.wrap( - id=os.path.splitext(gt_roi_filename)[0], - annotations=[gt_bbox.wrap(x=new_x, y=new_y)], - media=dm.Image(path=gt_roi_filename, size=sample.media_as(dm.Image).size), - attributes=filter_dict(sample.attributes, exclude_keys=["id"]), - ) - ) - - assert len(self._gt_roi_dataset) == len(self._gt_roi_filenames) - - def _create_on_cvat(self): - assert self._roi_filenames_to_be_annotated is not _unset - assert self._gt_roi_filenames is not _unset - assert self._label_configuration is not _unset - assert self._gt_roi_dataset is not _unset - - oracle_bucket = self.oracle_data_bucket - - # Register cloud storage on CVAT to pass user dataset - cvat_cloud_storage = cvat_api.create_cloudstorage( - **_make_cvat_cloud_storage_params(oracle_bucket) - ) - - # Create a project - cvat_project = cvat_api.create_project( - self.escrow_address, - labels=self._label_configuration, - user_guide=self.manifest.annotation.user_guide, - ) - - # Setup webhooks for the project - cvat_webhook = cvat_api.create_cvat_webhook(cvat_project.id) - - with SessionLocal.begin() as session: - segment_size = self._task_segment_size - total_jobs = math.ceil(len(self._roi_filenames_to_be_annotated) / segment_size) - self.logger.info( - "Task creation for escrow '%s': will create %s assignments", - self.escrow_address, - total_jobs, - ) - db_service.create_escrow_creation( - session, - escrow_address=self.escrow_address, - chain_id=self.chain_id, - total_jobs=total_jobs, - ) - - project_id = db_service.create_project( - session, - cvat_project.id, - cvat_cloud_storage.id, - self.manifest.annotation.type, - self.escrow_address, - self.chain_id, - oracle_bucket.to_url().rstrip("/") - + "/" - + compose_data_bucket_prefix(self.escrow_address, self.chain_id), - cvat_webhook_id=cvat_webhook.id, - ) - db_service.get_project_by_id(session, project_id, for_update=True) # lock the row - db_service.add_project_images( - session, - cvat_project.id, - [ - compose_data_bucket_filename(self.escrow_address, self.chain_id, fn) - for fn in self._roi_filenames.values() - ], - ) - - for data_subset in self._split_dataset_per_task( - self._roi_filenames_to_be_annotated, - subset_size=Config.cvat_config.max_jobs_per_task * segment_size, - ): - cvat_task = cvat_api.create_task( - cvat_project.id, self.escrow_address, segment_size=segment_size - ) - - task_id = db_service.create_task( - session, cvat_task.id, cvat_project.id, TaskStatuses[cvat_task.status] - ) - db_service.get_task_by_id(session, task_id, for_update=True) # lock the row - - filenames = [ - compose_data_bucket_filename(self.escrow_address, self.chain_id, fn) - for fn in data_subset - ] - gt_filenames = [ - compose_data_bucket_filename(self.escrow_address, self.chain_id, fn) - for fn in self._gt_roi_filenames - ] - - cvat_api.put_task_data( - cvat_task.id, - cvat_cloud_storage.id, - filenames=filenames, - validation_params={ - "gt_filenames": gt_filenames, - "gt_frames_per_job_count": self._job_val_frames_count, - }, - ) - - self._setup_gt_job_for_cvat_task( - cvat_task.id, self._gt_roi_dataset, dm_export_format="coco" - ) - self._setup_quality_settings(cvat_task.id) - - db_service.create_data_upload(session, cvat_task.id) - - db_service.touch(session, Project, [project_id]) - - def build(self): - self._download_input_data() - self._parse_gt() - self._parse_points() - self._validate_gt() - self._validate_points() - - # Task configuration creation - self._prepare_gt() - self._estimate_roi_sizes() - self._prepare_roi_info() - self._mangle_filenames() - self._prepare_label_configuration() - self._prepare_job_layout() - self._prepare_gt_roi_dataset() - - # Data preparation - self._extract_and_upload_rois() - self._upload_task_meta() - - self._create_on_cvat() - - -class SkeletonsFromBoxesTaskBuilder(_TaskBuilderBase): - @dataclass - class _TaskParams: - label_id: int - roi_ids: list[int] - roi_gt_ids: list[int] - - def __init__(self, manifest: TaskManifest, escrow_address: str, chain_id: int) -> None: - super().__init__(manifest=manifest, escrow_address=escrow_address, chain_id=chain_id) - - self._input_gt_data: _MaybeUnset[bytes] = _unset - self._input_boxes_data: _MaybeUnset[bytes] = _unset - - self._data_filenames: _MaybeUnset[Sequence[str]] = _unset - self._input_gt_dataset: _MaybeUnset[dm.Dataset] = _unset - self._gt_dataset: _MaybeUnset[dm.Dataset] = _unset - self._boxes_dataset: _MaybeUnset[dm.Dataset] = _unset - - self._skeleton_bbox_mapping: _MaybeUnset[skeletons_from_boxes_task.SkeletonBboxMapping] = ( - _unset - ) - self._roi_infos: _MaybeUnset[skeletons_from_boxes_task.RoiInfos] = _unset - self._roi_info_by_id: _MaybeUnset[dict[int, skeletons_from_boxes_task.RoiInfo]] = _unset - - self._gt_points_per_label: _MaybeUnset[ - dict[tuple[int, str], Sequence[tuple[int, dm.Points]]] - ] = _unset - "(skeleton_label_id, point_label_name) to [(skeleton_id, point), ...]" - - self._roi_filenames: _MaybeUnset[dict[int, str]] = _unset - - self._task_params: _MaybeUnset[list[self._TaskParams]] = _unset - - self._excluded_gt_info: _MaybeUnset[_ExcludedAnnotationsInfo] = _unset - self._excluded_boxes_info: _MaybeUnset[_ExcludedAnnotationsInfo] = _unset - - # Configuration / constants - self.job_size_mult = skeletons_from_boxes_task.DEFAULT_ASSIGNMENT_SIZE_MULTIPLIER - "Job size multiplier" - - # TODO: consider WebP if produced files are too big - self.roi_file_ext = ".png" # supposed to be lossless and reasonably compressing - "File extension for RoI images, with leading dot (.) included" - - self.list_display_threshold = 5 - "The maximum number of rendered list items in a message" - - self.roi_size_mult = 1.1 - "Additional point ROI size multiplier" - - self.min_roi_size = ( - Config.core_config.min_roi_size_w, - Config.core_config.min_roi_size_h, - ) - "Minimum absolute ROI size, (w, h)" - - self.boxes_format = "coco_person_keypoints" - - self.embed_bbox_in_roi_image = True - "Put a bbox into the extracted skeleton RoI images" - - self.embed_tile_border = True - - self.embedded_point_radius = 15 - self.min_embedded_point_radius_percent = 0.005 - self.max_embedded_point_radius_percent = 0.01 - self.embedded_point_color = (0, 255, 255) - - self.roi_embedded_bbox_color = (0, 255, 255) # BGR - self.roi_background_color = (245, 240, 242) # BGR - CVAT background color - - self.oracle_data_bucket = BucketAccessInfo.parse_obj(Config.storage_config) - - self.min_label_gt_samples = 2 # TODO: find good threshold - - self.max_discarded_threshold = 0.5 - """ - The maximum allowed percent of discarded - GT annotations or samples for successful job launch - """ - - self.gt_id_attribute = "object_id" - "An additional way to match GT skeletons with input boxes" - - # TODO: probably, need to also add an absolute number of minimum GT RoIs per class - - def _download_input_data(self): - data_bucket = BucketAccessInfo.parse_obj(self.manifest.data.data_url) - gt_bucket = BucketAccessInfo.parse_obj(self.manifest.validation.gt_url) - boxes_bucket = BucketAccessInfo.parse_obj(self.manifest.data.boxes_url) - - data_storage_client = self._make_cloud_storage_client(data_bucket) - gt_storage_client = self._make_cloud_storage_client(gt_bucket) - boxes_storage_client = self._make_cloud_storage_client(boxes_bucket) - - data_filenames = data_storage_client.list_files(prefix=data_bucket.path) - data_filenames = strip_bucket_prefix(data_filenames, prefix=data_bucket.path) - self._data_filenames = filter_image_files(data_filenames) - - self._input_gt_data = gt_storage_client.download_file(gt_bucket.path) - - self._input_boxes_data = boxes_storage_client.download_file(boxes_bucket.path) - - def _parse_dataset(self, annotation_file_data: bytes, dataset_format: str) -> dm.Dataset: - temp_dir = self.exit_stack.enter_context(TemporaryDirectory()) - - annotation_filename = os.path.join(temp_dir, "annotations.json") - with open(annotation_filename, "wb") as f: - f.write(annotation_file_data) - - return dm.Dataset.import_from(annotation_filename, format=dataset_format) - - def _parse_gt(self): - assert self._input_gt_data is not _unset - - self._input_gt_dataset = self._parse_dataset( - self._input_gt_data, - dataset_format=DM_GT_DATASET_FORMAT_MAPPING[self.manifest.annotation.type], - ) - - def _parse_boxes(self): - assert self._input_boxes_data is not _unset - - self._boxes_dataset = self._parse_dataset( - self._input_boxes_data, dataset_format=self.boxes_format - ) - - def _validate_gt_labels(self): - gt_labels = set( - (label.name, label.parent) - for label in self._input_gt_dataset.categories()[dm.AnnotationType.label] - ) - - manifest_labels = set() - for skeleton_label in self.manifest.annotation.labels: - manifest_labels.add((skeleton_label.name, "")) - for node_label in skeleton_label.nodes: - manifest_labels.add((node_label, skeleton_label.name)) - - if manifest_labels - gt_labels: - raise DatasetValidationError( - "Could not find GT for labels {}".format( - format_sequence( - [ - label_name if not parent_name else f"{parent_name}.{label_name}" - for label_name, parent_name in manifest_labels - gt_labels - ] - ), - ) - ) - - # It should not be an issue that there are some extra GT labels - they should - # just be skipped. - if gt_labels - manifest_labels: - self.logger.info( - "Skipping unknown GT labels: {}".format( - format_sequence( - [ - label_name if not parent_name else f"{parent_name}.{label_name}" - for label_name, parent_name in gt_labels - manifest_labels - ] - ) - ) - ) - - # Reorder and filter labels to match the manifest - self._input_gt_dataset.transform( - ProjectLabels, dst_labels=[label.name for label in self.manifest.annotation.labels] - ) - self._input_gt_dataset.init_cache() - - def _validate_gt_filenames(self): - gt_filenames = set(s.id + s.media.ext for s in self._input_gt_dataset) - - known_data_filenames = set(self._data_filenames) - matched_gt_filenames = gt_filenames.intersection(known_data_filenames) - - if len(gt_filenames) != len(matched_gt_filenames): - extra_gt = list(map(os.path.basename, gt_filenames - matched_gt_filenames)) - - raise MismatchingAnnotations( - "Failed to find several validation samples in the dataset files: {}".format( - format_sequence(extra_gt) - ) - ) - - if len(gt_filenames) < self._job_val_frames_count: - raise TooFewSamples( - f"Too few validation samples provided ({len(gt_filenames)}), " - f"at least {self._job_val_frames_count} required." - ) - - def _validate_gt_annotations(self): - def _validate_skeleton(skeleton: dm.Skeleton, *, sample_bbox: dm.Bbox): - if skeleton.id in visited_ids: - raise DatasetValidationError(f"repeated annotation id {skeleton.id}") - - for element in skeleton.elements: - # This is what Datumaro is expected to parse - assert len(element.points) == 2 - assert len(element.visibility) == 1 - - if element.visibility[0] == dm.Points.Visibility.absent: - continue - - px, py = element.points[:2] - if not is_point_in_bbox(int(px), int(py), sample_bbox): - raise InvalidCoordinates("skeleton point is outside the image") - - label_cat: dm.LabelCategories = self._input_gt_dataset.categories()[dm.AnnotationType.label] - - excluded_gt_info = _ExcludedAnnotationsInfo() - excluded_samples = set() - visited_ids = set() - for gt_sample in self._input_gt_dataset: - # Could fail on this as well - img_h, img_w = gt_sample.media_as(dm.Image).size - sample_bbox = dm.Bbox(0, 0, w=img_w, h=img_h) - - sample_skeletons = [a for a in gt_sample.annotations if isinstance(a, dm.Skeleton)] - valid_skeletons = [] - for skeleton in sample_skeletons: - try: - _validate_skeleton(skeleton, sample_bbox=sample_bbox) - except DatasetValidationError as error: - excluded_gt_info.add_message( - "Sample '{}': GT skeleton #{} ({}) skipped - {}".format( - gt_sample.id, skeleton.id, label_cat[skeleton.label].name, error - ), - sample_id=gt_sample.id, - sample_subset=gt_sample.subset, - ) - continue - - valid_skeletons.append(skeleton) - visited_ids.add(skeleton.id) - - excluded_gt_info.excluded_count += len(sample_skeletons) - len(valid_skeletons) - excluded_gt_info.total_count += len(sample_skeletons) - - if len(valid_skeletons) != len(sample_skeletons): - if not valid_skeletons: - excluded_samples.add((gt_sample.id, gt_sample.subset)) - else: - # Skeleton boxes can be in the list as well with the same ids / groups - skeleton_ids = set(a.id for a in valid_skeletons) - {0} - self._input_gt_dataset.put( - gt_sample.wrap( - annotations=[a for a in gt_sample.annotations if a.id in skeleton_ids] - ) - ) - - for excluded_sample in excluded_samples: - self._input_gt_dataset.remove(*excluded_sample) - - if excluded_gt_info.excluded_count: - self.logger.warning( - "Some GT skeletons were excluded due to the errors found: {}".format( - format_sequence([e.message for e in excluded_gt_info.messages], separator="\n") - ) - ) - - if excluded_gt_info.excluded_count > ceil( - excluded_gt_info.total_count * self.max_discarded_threshold - ): - raise TooFewSamples( - "Too many GT skeletons discarded, canceling job creation. Errors: {}".format( - format_sequence( - [error_info.message for error_info in excluded_gt_info.messages] - ) - ) - ) - - self._excluded_gt_info = excluded_gt_info - - def _validate_gt(self): - assert self._data_filenames is not _unset - assert self._input_gt_dataset is not _unset - - self._validate_gt_filenames() - self._validate_gt_labels() - self._validate_gt_annotations() - - def _validate_boxes_categories(self): - boxes_dataset_categories = self._boxes_dataset.categories() - boxes_dataset_label_cat: dm.LabelCategories = boxes_dataset_categories[ - dm.AnnotationType.label - ] - - boxes_labels = set(label.name for label in boxes_dataset_label_cat if not label.parent) - manifest_labels = set(label.name for label in self.manifest.annotation.labels) - if manifest_labels != boxes_labels: - raise DatasetValidationError("Bbox labels do not match job labels") - - # Reorder labels to match the manifest - self._boxes_dataset.transform( - ProjectLabels, dst_labels=[label.name for label in self.manifest.annotation.labels] - ) - self._boxes_dataset.init_cache() - - def _validate_boxes_filenames(self): - boxes_filenames = set(sample.id + sample.media.ext for sample in self._boxes_dataset) - - known_data_filenames = set(self._data_filenames) - matched_boxes_filenames = boxes_filenames.intersection(known_data_filenames) - - if len(matched_boxes_filenames) != len(boxes_filenames): - extra_bbox_samples = list( - map(os.path.basename, boxes_filenames - matched_boxes_filenames) - ) - - raise MismatchingAnnotations( - "Failed to find several samples in the dataset files: {}".format( - format_sequence(extra_bbox_samples), - ) - ) - - def _validate_boxes_annotations(self): # noqa: PLR0912 - # Convert possible polygons and masks into boxes - self._boxes_dataset.transform(InstanceSegmentsToBbox) - self._boxes_dataset.init_cache() - - excluded_boxes_info = _ExcludedAnnotationsInfo() - - label_cat: dm.LabelCategories = self._boxes_dataset.categories()[dm.AnnotationType.label] - - visited_ids = set() - for sample in self._boxes_dataset: - # Could fail on this as well - image_h, image_w = sample.media_as(dm.Image).size - - valid_instances: list[tuple[dm.Bbox, dm.Points]] = [] - instances = find_instances( - [a for a in sample.annotations if isinstance(a, dm.Bbox | dm.Skeleton)] - ) - for instance_anns in instances: - if len(instance_anns) != 2: - excluded_boxes_info.add_message( - "Sample '{}': object #{} ({}) skipped - unexpected group size ({})".format( - sample.id, - instance_anns[0].id, - label_cat[instance_anns[0].label].name, - len(instance_anns), - ), - sample_id=sample.id, - sample_subset=sample.subset, - ) - continue - - bbox = next((a for a in instance_anns if isinstance(a, dm.Bbox)), None) - if not bbox: - excluded_boxes_info.add_message( - "Sample '{}': object #{} ({}) skipped - no matching bbox".format( - sample.id, instance_anns[0].id, label_cat[instance_anns[0].label].name - ), - sample_id=sample.id, - sample_subset=sample.subset, - ) - continue - - skeleton = next((a for a in instance_anns if isinstance(a, dm.Skeleton)), None) - if not skeleton: - excluded_boxes_info.add_message( - "Sample '{}': object #{} ({}) skipped - no matching skeleton".format( - sample.id, instance_anns[0].id, label_cat[instance_anns[0].label].name - ), - sample_id=sample.id, - sample_subset=sample.subset, - ) - continue - - if len(skeleton.elements) != 1 or len(skeleton.elements[0].points) != 2: - excluded_boxes_info.add_message( - "Sample '{}': object #{} ({}) skipped - invalid skeleton points".format( - sample.id, skeleton.id, label_cat[skeleton.label].name - ), - sample_id=sample.id, - sample_subset=sample.subset, - ) - continue - - point = skeleton.elements[0] - if not is_point_in_bbox(point.points[0], point.points[1], (0, 0, image_w, image_h)): - excluded_boxes_info.add_message( - "Sample '{}': object #{} ({}) skipped - invalid point coordinates".format( - sample.id, skeleton.id, label_cat[skeleton.label].name - ), - sample_id=sample.id, - sample_subset=sample.subset, - ) - continue - - if not is_point_in_bbox(int(bbox.x), int(bbox.y), (0, 0, image_w, image_h)): - excluded_boxes_info.add_message( - "Sample '{}': object #{} ({}) skipped - invalid bbox coordinates".format( - sample.id, bbox.id, label_cat[bbox.label].name - ), - sample_id=sample.id, - sample_subset=sample.subset, - ) - continue - - if not is_point_in_bbox(point.points[0], point.points[1], bbox): - excluded_boxes_info.add_message( - "Sample '{}': object #{} ({}) skipped - point is outside the bbox".format( - sample.id, skeleton.id, label_cat[skeleton.label].name - ), - sample_id=sample.id, - sample_subset=sample.subset, - ) - continue - - if bbox.id in visited_ids: - excluded_boxes_info.add_message( - "Sample '{}': bbox #{} ({}) skipped - repeated annotation id {}".format( - sample.id, bbox.id, label_cat[bbox.label].name, bbox.id - ), - sample_id=sample.id, - sample_subset=sample.subset, - ) - continue - - valid_instances.append( - (bbox, point.wrap(group=bbox.group, id=bbox.id, attributes=bbox.attributes)) - ) - visited_ids.add(bbox.id) - - excluded_boxes_info.excluded_count += len(instances) - len(valid_instances) - excluded_boxes_info.total_count += len(instances) - - if len(valid_instances) != len(sample.annotations): - self._boxes_dataset.put( - sample.wrap(annotations=list(chain.from_iterable(valid_instances))) - ) - - if excluded_boxes_info.excluded_count > ceil( - excluded_boxes_info.total_count * self.max_discarded_threshold - ): - raise TooFewSamples( - "Too many boxes discarded, canceling job creation. Errors: {}".format( - format_sequence( - [error_info.message for error_info in excluded_boxes_info.messages] - ) - ) - ) - - excluded_samples = set((e.sample_id, e.sample_subset) for e in excluded_boxes_info.messages) - for excluded_sample in excluded_samples: - self._boxes_dataset.remove(*excluded_sample) - - if excluded_samples: - self.logger.warning( - "Some boxes were excluded due to the errors found: {}".format( - format_sequence( - [e.message for e in excluded_boxes_info.messages], separator="\n" - ) - ) - ) - - self._excluded_boxes_info = excluded_boxes_info - - def _validate_boxes(self): - assert self._data_filenames is not _unset - assert self._boxes_dataset is not _unset - - self._validate_boxes_categories() - self._validate_boxes_filenames() - self._validate_boxes_annotations() - - def _match_boxes(self, a: BboxCoords, b: BboxCoords) -> bool: - return bbox_iou(a, b) > 0 - - def _get_skeleton_bbox( - self, skeleton: dm.Skeleton, annotations: Sequence[dm.Annotation] - ) -> BboxCoords: - matching_bbox = None - if skeleton.group: - matching_bbox = next( - ( - bbox - for bbox in annotations - if isinstance(bbox, dm.Bbox) and bbox.group == skeleton.group - ), - None, - ) - - if matching_bbox: - bbox = matching_bbox.get_bbox() - else: - bbox = skeleton.get_bbox() - - if any( - v != dm.Points.Visibility.absent for e in skeleton.elements for v in e.visibility - ): - # If there's only 1 visible point, the bbox will have 0 w and h - bbox = [bbox[0], bbox[1], max(1, bbox[2]), max(1, bbox[3])] - - return bbox - - def _prepare_gt(self): - def _find_unambiguous_matches( - input_boxes: list[dm.Bbox], - gt_skeletons: list[dm.Skeleton], - *, - input_points: list[dm.Points], - gt_annotations: list[dm.Annotation], - ) -> list[tuple[dm.Bbox, dm.Skeleton]]: - bbox_point_mapping: dict[int, dm.Points] = { - bbox.id: next(p for p in input_points if p.group == bbox.group) - for bbox in input_boxes - } - - matches = [ - [ - (input_bbox.label == gt_skeleton.label) - and ( - self._match_boxes( - input_bbox.get_bbox(), - self._get_skeleton_bbox(gt_skeleton, gt_annotations), - ) - ) - and (input_point := bbox_point_mapping[input_bbox.id]) - and is_point_in_bbox( - input_point.points[0], - input_point.points[1], - self._get_skeleton_bbox(gt_skeleton, gt_annotations), - ) - and ( - # a way to customize matching if the default method is too rough - not (bbox_id := input_bbox.attributes.get(self.gt_id_attribute)) - or not (skeleton_id := gt_skeleton.attributes.get(self.gt_id_attribute)) - or bbox_id == skeleton_id - ) - for gt_skeleton in gt_skeletons - ] - for input_bbox in input_boxes - ] - - ambiguous_boxes: list[int] = set() - ambiguous_skeletons: list[int] = set() - for bbox_idx, input_bbox in enumerate(input_boxes): - matched_skeletons: list[dm.Skeleton] = [ - gt_skeletons[j] for j in range(len(gt_skeletons)) if matches[bbox_idx][j] - ] - - if len(matched_skeletons) > 1: - # Handle ambiguous matches - excluded_boxes_info.add_message( - "Sample '{}': bbox #{} ({}) and overlapping skeletons skipped - " - "too many matching skeletons ({}) found".format( - boxes_sample.id, - input_bbox.id, - boxes_label_cat[input_bbox.label].name, - format_sequence([f"#{a.id}" for a in matched_skeletons]), - ), - sample_id=boxes_sample.id, - sample_subset=boxes_sample.subset, - ) - # not an error, should not be counted as excluded for an error - ambiguous_boxes.add(input_bbox.id) - ambiguous_skeletons.update(s.id for s in matched_skeletons) - continue - - for skeleton_idx, gt_skeleton in enumerate(gt_skeletons): - matched_boxes: list[dm.Bbox] = [ - input_boxes[i] for i in range(len(input_boxes)) if matches[i][skeleton_idx] - ] - - if len(matched_boxes) > 1: - # Handle ambiguous matches - excluded_gt_info.add_message( - "Sample '{}': GT skeleton #{} ({}) and overlapping boxes skipped - " - "too many matching boxes ({}) found".format( - gt_sample.id, - gt_skeleton.id, - gt_label_cat[gt_skeleton.label].name, - format_sequence([f"#{a.id}" for a in matched_boxes]), - ), - sample_id=gt_sample.id, - sample_subset=gt_sample.subset, - ) - # not an error, should not be counted as excluded for an error - ambiguous_skeletons.add(gt_skeleton.id) - ambiguous_boxes.update(b.id for b in matched_boxes) - continue - if not matched_boxes: - # Handle unmatched skeletons - excluded_gt_info.add_message( - "Sample '{}': GT skeleton #{} ({}) skipped - " - "no matching boxes found".format( - gt_sample.id, - gt_skeleton.id, - gt_label_cat[gt_skeleton.label].name, - ), - sample_id=gt_sample.id, - sample_subset=gt_sample.subset, - ) - excluded_gt_info.excluded_count += 1 # an error - continue - - unambiguous_matches: list[tuple[dm.Bbox, dm.Skeleton]] = [] - for bbox_idx, input_bbox in enumerate(input_boxes): - if input_bbox.id in ambiguous_boxes: - continue - - matched_skeleton = None - for gt_idx, gt_skeleton in enumerate(gt_skeletons): - if gt_skeleton.id in ambiguous_skeletons: - continue - - if matches[bbox_idx][gt_idx]: - matched_skeleton = gt_skeleton - break - - if matched_skeleton: - unambiguous_matches.append((input_bbox, matched_skeleton)) - - return unambiguous_matches - - def _find_good_gt_skeletons( - input_boxes: list[dm.Bbox], - gt_skeletons: list[dm.Skeleton], - *, - input_points: list[dm.Points], - gt_annotations: list[dm.Annotation], - ) -> list[dm.Skeleton]: - matches = _find_unambiguous_matches( - input_boxes, gt_skeletons, input_points=input_points, gt_annotations=gt_annotations - ) - - matched_skeletons = [] - for input_bbox, gt_skeleton in matches: - gt_count_per_class[gt_skeleton.label] = ( - gt_count_per_class.get(gt_skeleton.label, 0) + 1 - ) - - matched_skeletons.append(gt_skeleton) - skeleton_bbox_mapping[gt_skeleton.id] = input_bbox.id - - return matched_skeletons - - assert self._data_filenames is not _unset - assert self._boxes_dataset is not _unset - assert self._input_gt_dataset is not _unset - assert [ - label.name - for label in self._input_gt_dataset.categories()[dm.AnnotationType.label] - if not label.parent - ] == [label.name for label in self.manifest.annotation.labels] - assert [ - label.name - for label in self._boxes_dataset.categories()[dm.AnnotationType.label] - if not label.parent - ] == [label.name for label in self.manifest.annotation.labels] - - boxes_label_cat: dm.LabelCategories = self._boxes_dataset.categories()[ - dm.AnnotationType.label - ] - gt_label_cat: dm.LabelCategories = self._input_gt_dataset.categories()[ - dm.AnnotationType.label - ] - - updated_gt_dataset = dm.Dataset( - categories=self._input_gt_dataset.categories(), media_type=dm.Image - ) - - excluded_boxes_info = _ExcludedAnnotationsInfo() # local for the function - excluded_gt_info = self._excluded_gt_info - gt_count_per_class = {} - skeleton_bbox_mapping = {} # skeleton id -> bbox id - for gt_sample in self._input_gt_dataset: - boxes_sample = self._boxes_dataset.get(gt_sample.id, gt_sample.subset) - # Samples could be discarded, so we just skip them without an error - if not boxes_sample: - continue - - gt_skeletons = [a for a in gt_sample.annotations if isinstance(a, dm.Skeleton)] - input_boxes = [a for a in boxes_sample.annotations if isinstance(a, dm.Bbox)] - input_points = [a for a in boxes_sample.annotations if isinstance(a, dm.Points)] - assert len(input_boxes) == len(input_points) - - # Samples without boxes are allowed, so we just skip them without an error - if not gt_skeletons: - continue - - matched_skeletons = _find_good_gt_skeletons( - input_boxes, - gt_skeletons, - input_points=input_points, - gt_annotations=gt_sample.annotations, - ) - if not matched_skeletons: - continue - - updated_gt_dataset.put(gt_sample.wrap(annotations=matched_skeletons)) - - if excluded_boxes_info.messages: - self.logger.warning( - "Some boxes were excluded from GT due to the problems found: {}".format( - format_sequence( - [e.message for e in excluded_boxes_info.messages], separator="\n" - ) - ) - ) - - if excluded_gt_info.messages: - self.logger.warning( - "Some GT annotations were excluded due to the errors found: {}".format( - format_sequence([e.message for e in excluded_gt_info.messages], separator="\n") - ) - ) - - if excluded_gt_info.excluded_count > ceil( - self.max_discarded_threshold * excluded_gt_info.total_count - ): - raise DatasetValidationError( - "Too many GT skeletons discarded ({} out of {}). " - "Please make sure each GT skeleton matches exactly 1 bbox " - "and has at least 1 visible point".format( - excluded_gt_info.total_count - len(skeleton_bbox_mapping), - excluded_gt_info.total_count, - ) - ) - - self.logger.info( - "GT counts per class to be used for validation: {}".format( - format_sequence( - [ - f"{gt_label_cat[label_id].name}: {count}" - for label_id, count in gt_count_per_class.items() - ] - ) - ) - ) - - labels_with_few_gt = [ - gt_label_cat[label_id] - for label_id, label_count in gt_count_per_class.items() - if label_count < self.min_label_gt_samples - ] - if labels_with_few_gt: - raise DatasetValidationError( - "Too few matching GT boxes/points annotations found for some classes: {}".format( - format_sequence(labels_with_few_gt) - ) - ) - - self._gt_dataset = updated_gt_dataset - self._skeleton_bbox_mapping = skeleton_bbox_mapping - - def _prepare_roi_infos(self): - assert self._gt_dataset is not _unset - assert self._boxes_dataset is not _unset - - rois: list[skeletons_from_boxes_task.RoiInfo] = [] - for sample in self._boxes_dataset: - instances = find_instances(sample.annotations) - for instance_anns in instances: - bbox = next(a for a in instance_anns if isinstance(a, dm.Bbox)) - point = next(a for a in instance_anns if isinstance(a, dm.Points)) - - # RoI is centered on bbox center - original_bbox_cx = int(bbox.x + bbox.w / 2) - original_bbox_cy = int(bbox.y + bbox.h / 2) - - roi_w = ceil(bbox.w * self.roi_size_mult) - roi_h = ceil(bbox.h * self.roi_size_mult) - roi_w = max(roi_w, self.min_roi_size[0]) - roi_h = max(roi_h, self.min_roi_size[1]) - - roi_x = original_bbox_cx - int(roi_w / 2) - roi_y = original_bbox_cy - int(roi_h / 2) - - new_bbox_x = bbox.x - roi_x - new_bbox_y = bbox.y - roi_y - - rois.append( - skeletons_from_boxes_task.RoiInfo( - original_image_key=sample.attributes["id"], - bbox_id=bbox.id, - bbox_label=bbox.label, - bbox_x=new_bbox_x, - bbox_y=new_bbox_y, - point_x=point.points[0] - roi_x, - point_y=point.points[1] - roi_y, - roi_x=roi_x, - roi_y=roi_y, - roi_w=roi_w, - roi_h=roi_h, - ) - ) - - self._roi_infos = rois - self._roi_info_by_id = {roi_info.bbox_id: roi_info for roi_info in self._roi_infos} - - def _mangle_filenames(self): - """ - Mangle filenames in the dataset to make them less recognizable by annotators - and hide private dataset info - """ - assert self._roi_infos is not _unset - - # TODO: maybe add different names for the same GT images in - # different jobs to make them even less recognizable - self._roi_filenames = { - roi_info.bbox_id: str(uuid.uuid4()) + self.roi_file_ext for roi_info in self._roi_infos - } - - @property - def _task_segment_size(self) -> int: - # Here we use a job size multiplier, because each image - # is supposed to be simple and the assignment is expected - # to take little time with the default job size. - # Then, we add a percent of job tiles for validation, keeping the requested ratio. - return super()._task_segment_size * self.job_size_mult - - @property - def _job_val_frames_count(self) -> int: - return super()._job_val_frames_count * self.job_size_mult - - def _prepare_task_params(self): - assert self._roi_infos is not _unset - assert self._skeleton_bbox_mapping is not _unset - assert self._input_gt_dataset is not _unset - - # This list can be different from what is selected for validation - input_gt_filenames = set(sample.media.path for sample in self._input_gt_dataset) - image_id_to_filename = { - sample.attributes["id"]: sample.media.path for sample in self._boxes_dataset - } - - task_params: list[self._TaskParams] = [] - segment_size = self._task_segment_size - for label_id, _ in enumerate(self.manifest.annotation.labels): - label_gt_roi_ids = set( - roi_id - for roi_id in self._skeleton_bbox_mapping.values() - if self._roi_info_by_id[roi_id].bbox_label == label_id - ) - - label_data_roi_ids = [ - roi_info.bbox_id - for roi_info in self._roi_infos - if roi_info.bbox_label == label_id - if roi_info.bbox_id not in label_gt_roi_ids - if image_id_to_filename[roi_info.original_image_key] not in input_gt_filenames - ] - random.shuffle(label_data_roi_ids) - - task_params.extend( - [ - self._TaskParams( - label_id=label_id, roi_ids=task_data_roi_ids, roi_gt_ids=label_gt_roi_ids - ) - for task_data_roi_ids in take_by( - label_data_roi_ids, Config.cvat_config.max_jobs_per_task * segment_size - ) - ] - ) - - self._task_params = task_params - - def _prepare_job_labels(self): - self._point_labels = {} - - for skeleton_label in self.manifest.annotation.labels: - for point_name in skeleton_label.nodes: - self._point_labels[(skeleton_label.name, point_name)] = point_name - - def _prepare_gt_points_mapping(self): - assert self._gt_dataset is not _unset - - self._gt_points_per_label = {} - - # GT should contain all GT images with only one point per skeleton node - for gt_sample in self._gt_dataset: - for gt_skeleton in gt_sample.annotations: - if not isinstance(gt_skeleton, dm.Skeleton): - continue - - for point in gt_skeleton.elements: - if point.visibility[0] in [ - dm.Points.Visibility.absent, - dm.Points.Visibility.hidden, - ]: - continue - - point_label_name = ( - self._gt_dataset.categories()[dm.AnnotationType.label] - .items[point.label] - .name - ) - - self._gt_points_per_label.setdefault( - (gt_skeleton.label, point_label_name), [] - ).append((gt_skeleton.id, point)) - - def _upload_task_meta(self): - layout = skeletons_from_boxes_task.TaskMetaLayout() - serializer = skeletons_from_boxes_task.TaskMetaSerializer() - - file_list = [] - file_list.append( - (serializer.serialize_bbox_annotations(self._boxes_dataset), layout.BOXES_FILENAME) - ) - file_list.append( - ( - serializer.serialize_gt_annotations(self._gt_dataset), - layout.GT_FILENAME, - ) - ) - file_list.append( - ( - serializer.serialize_skeleton_bbox_mapping(self._skeleton_bbox_mapping), - layout.SKELETON_BBOX_MAPPING_FILENAME, - ) - ) - file_list.append((serializer.serialize_roi_info(self._roi_infos), layout.ROI_INFO_FILENAME)) - file_list.append( - (serializer.serialize_roi_filenames(self._roi_filenames), layout.ROI_FILENAMES_FILENAME) - ) - file_list.append( - (serializer.serialize_point_labels(self._point_labels), layout.POINT_LABELS_FILENAME) - ) - - storage_client = self._make_cloud_storage_client(self.oracle_data_bucket) - for file_data, filename in file_list: - storage_client.create_file( - compose_data_bucket_filename(self.escrow_address, self.chain_id, filename), - file_data, - ) - - def _extract_roi( - self, source_pixels: np.ndarray, roi_info: skeletons_from_boxes_task.RoiInfo - ) -> np.ndarray: - img_h, img_w, *_ = source_pixels.shape - - roi_pixels = source_pixels[ - max(0, roi_info.roi_y) : min(img_h, roi_info.roi_y + roi_info.roi_h), - max(0, roi_info.roi_x) : min(img_w, roi_info.roi_x + roi_info.roi_w), - ] - - if not ( - (0 <= roi_info.roi_x < roi_info.roi_x + roi_info.roi_w < img_w) - and (0 <= roi_info.roi_y < roi_info.roi_y + roi_info.roi_h < img_h) - ): - # Coords can be outside the original image - # In this case a border should be added to RoI, so that the image was centered on bbox - wrapped_roi_pixels = np.zeros((roi_info.roi_h, roi_info.roi_w, 3), dtype=np.float32) - wrapped_roi_pixels[:, :] = self.roi_background_color - - dst_y = max(-roi_info.roi_y, 0) - dst_x = max(-roi_info.roi_x, 0) - wrapped_roi_pixels[ - dst_y : dst_y + roi_pixels.shape[0], - dst_x : dst_x + roi_pixels.shape[1], - ] = roi_pixels - - roi_pixels = wrapped_roi_pixels - else: - roi_pixels = roi_pixels.copy() - - return roi_pixels - - def _draw_roi_bbox(self, roi_image: np.ndarray, bbox: dm.Bbox) -> np.ndarray: - roi_cy = roi_image.shape[0] // 2 - roi_cx = roi_image.shape[1] // 2 - return cv2.rectangle( - roi_image, - tuple(map(int, (roi_cx - bbox.w / 2, roi_cy - bbox.h / 2))), - tuple(map(int, (roi_cx + bbox.w / 2, roi_cy + bbox.h / 2))), - self.roi_embedded_bbox_color, - 1, - cv2.LINE_4, - ) - - def _draw_roi_point(self, roi_image: np.ndarray, point: tuple[float, float]) -> np.ndarray: - roi_r = (roi_image.shape[0] ** 2 + roi_image.shape[1] ** 2) ** 0.5 / 2 - radius = int( - min( - self.max_embedded_point_radius_percent * roi_r, - max(self.embedded_point_radius, self.min_embedded_point_radius_percent * roi_r), - ) - ) - - roi_image = cv2.circle( - roi_image, - tuple(map(int, (point[0], point[1]))), - radius + 1, - (255, 255, 255), - -1, - cv2.LINE_4, - ) - return cv2.circle( - roi_image, - tuple(map(int, (point[0], point[1]))), - radius, - self.embedded_point_color, - -1, - cv2.LINE_4, - ) - - def _extract_and_upload_rois(self): - assert self._roi_filenames is not _unset - assert self._roi_infos is not _unset - - src_bucket = BucketAccessInfo.parse_obj(self.manifest.data.data_url) - src_prefix = src_bucket.path - dst_bucket = self.oracle_data_bucket - - src_client = self._make_cloud_storage_client(src_bucket) - dst_client = self._make_cloud_storage_client(dst_bucket) - - image_id_to_filename = { - sample.attributes["id"]: sample.image.path for sample in self._boxes_dataset - } - - filename_to_sample = {sample.image.path: sample for sample in self._boxes_dataset} - - def _roi_info_key(e): - return e.original_image_key - - roi_info_by_image: dict[str, Sequence[skeletons_from_boxes_task.RoiInfo]] = { - image_id_to_filename[image_id]: list(g) - for image_id, g in groupby( - sorted(self._roi_infos, key=_roi_info_key), key=_roi_info_key - ) - } - - bbox_by_id = { - bbox.id: bbox - for sample in self._boxes_dataset - for bbox in sample.annotations - if isinstance(bbox, dm.Bbox) - } - - def process_file(filename: str, image_pixels: np.ndarray): - image_roi_infos = roi_info_by_image.get(filename, []) - if not image_roi_infos: - return - - sample = filename_to_sample[filename] - if tuple(sample.image.size) != tuple(image_pixels.shape[:2]): - # TODO: maybe rois should be regenerated instead - # Option 2: accumulate errors, fail when some threshold is reached - # Option 3: add special handling for cases when image is only rotated (exif etc.) - raise InvalidImageInfo( - f"Sample '{filename}': invalid size provided in the point annotations" - ) - - for roi_info in image_roi_infos: - roi_pixels = self._extract_roi(image_pixels, roi_info) - - if self.embed_bbox_in_roi_image: - roi_pixels = self._draw_roi_bbox(roi_pixels, bbox_by_id[roi_info.bbox_id]) - roi_pixels = self._draw_roi_point( - roi_pixels, (roi_info.point_x, roi_info.point_y) - ) - - filename = self._roi_filenames[roi_info.bbox_id] - roi_bytes = encode_image(roi_pixels, os.path.splitext(filename)[-1]) - - dst_client.create_file( - compose_data_bucket_filename(self.escrow_address, self.chain_id, filename), - data=roi_bytes, - ) - - def download_and_decode(key: str): - image_bytes = src_client.download_file(key) - return decode_image(image_bytes) - - pool_size = Config.features.max_data_storage_connections - download_queue_size = 4 * pool_size - download_queue = Queue[tuple[str, Future[np.ndarray]]](download_queue_size) - roi_uploader = BufferedRoiImageUploader(queue=download_queue) - with ThreadPoolExecutor(pool_size) as pool: - - def put_callback(filename: str): - image_roi_infos = roi_info_by_image.get(filename, []) - if not image_roi_infos: - return None - - return ( - filename, - pool.submit(download_and_decode, os.path.join(src_prefix, filename)), - ) - - def process_callback(result: tuple[str, Future]): - filename, task = result - process_file(filename, task.result()) - - roi_uploader.process_all( - self._data_filenames, put_callback=put_callback, process_callback=process_callback - ) - - def _prepare_gt_dataset_for_skeleton_point( - self, - *, - point_label_name: str, - skeleton_label_id: int, - ) -> dm.Dataset: - assert self._gt_points_per_label is not _unset - - # Change annotations to Points for validation in CVAT, - # as annotators will use this annotation type - point_dataset = dm.Dataset( - categories={ - dm.AnnotationType.label: dm.LabelCategories.from_iterable([point_label_name]), - }, - media_type=dm.Image, - ) - - for gt_skeleton_id, gt_point in self._gt_points_per_label[ - (skeleton_label_id, point_label_name) - ]: - roi_key = self._skeleton_bbox_mapping[gt_skeleton_id] - roi_info = self._roi_info_by_id[roi_key] - - mangled_cvat_sample_id = compose_data_bucket_filename( - self.escrow_address, - self.chain_id, - os.path.splitext(self._roi_filenames[roi_key])[0], - ) - - # update points coordinates in accordance with roi coordinates - updated_points = [ - gt_point.points[0] - roi_info.roi_x, - gt_point.points[1] - roi_info.roi_y, - ] - - point_dataset.put( - dm.DatasetItem( - id=mangled_cvat_sample_id, - annotations=[dm.Points(id=gt_skeleton_id, points=updated_points, label=0)], - ) - ) - - return point_dataset - - def _save_cvat_gt_dataset_to_oracle_bucket( - self, - gt_dataset_path: Path, - *, - file_suffix: str = "", - ) -> None: - layout = skeletons_from_boxes_task.TaskMetaLayout() - - base_gt_filename = layout.GT_FILENAME.split(".", maxsplit=1)[0] - final_gt_filename = f"{base_gt_filename}_{file_suffix}" + ".zip" - gt_dataset_key = compose_data_bucket_filename( - self.escrow_address, self.chain_id, final_gt_filename - ) - - storage_client = self._make_cloud_storage_client(self._oracle_data_bucket) - storage_client.create_file(gt_dataset_key, gt_dataset_path.read_bytes()) - - def _setup_quality_settings(self, task_id: int, **overrides) -> None: - values = { - "oks_sigma": Config.cvat_config.oks_sigma, - "point_size_base": "image_size", # we don't expect any boxes or groups, so ignore them - } - values.update(overrides) - super()._setup_quality_settings(task_id, **values) - - def _create_on_cvat(self): - assert self._task_params is not _unset - assert self._point_labels is not _unset - assert self._gt_points_per_label is not _unset - - def _task_params_label_key(ts): - return ts.label_id - - tasks_by_skeleton_label = { - skeleton_label_id: list(g) - for skeleton_label_id, g in groupby( - sorted(self._task_params, key=_task_params_label_key), key=_task_params_label_key - ) - } - - label_specs_by_skeleton = { - skeleton_label_id: [ - { - "name": self._point_labels[(skeleton_label.name, skeleton_point)], - "type": "points", - } - for skeleton_point in skeleton_label.nodes - ] - for skeleton_label_id, skeleton_label in enumerate(self.manifest.annotation.labels) - } - - oracle_bucket = self.oracle_data_bucket - - # Register cloud storage on CVAT to pass user dataset - cvat_cloud_storage = cvat_api.create_cloudstorage( - **_make_cvat_cloud_storage_params(oracle_bucket) - ) - - segment_size = self._task_segment_size - - total_jobs = sum( - len(self.manifest.annotation.labels[tp.label_id].nodes) - * (math.ceil(len(tp.roi_ids) / segment_size)) - for tp in self._task_params - ) - self.logger.info( - "Task creation for escrow '%s': will create %s assignments", - self.escrow_address, - total_jobs, - ) - - with SessionLocal.begin() as session: - db_service.create_escrow_creation( - session, - escrow_address=self.escrow_address, - chain_id=self.chain_id, - total_jobs=total_jobs, - ) - created_projects = [] - - for skeleton_label_id, skeleton_label_tasks in tasks_by_skeleton_label.items(): - skeleton_label_filenames: list[list[str]] = [] - gt_skeleton_label_filenames: list[list[str]] = [] - - for skeleton_label_task in skeleton_label_tasks: - skeleton_label_filenames.append( - [ - compose_data_bucket_filename( - self.escrow_address, self.chain_id, self._roi_filenames[roi_id] - ) - for roi_id in skeleton_label_task.roi_ids - ], - ) - - gt_skeleton_label_filenames.append( - [ - compose_data_bucket_filename( - self.escrow_address, self.chain_id, self._roi_filenames[roi_id] - ) - for roi_id in skeleton_label_task.roi_gt_ids - ], - ) - - for point_label_spec in label_specs_by_skeleton[skeleton_label_id]: - point_label_name = point_label_spec["name"] - - # Create a project for each point label. - # CVAT doesn't support tasks with different labels in a project. - cvat_project = cvat_api.create_project( - name="{} ({} {})".format( - self.escrow_address, - self.manifest.annotation.labels[skeleton_label_id].name, - point_label_name, - ), - user_guide=self.manifest.annotation.user_guide, - labels=[point_label_spec], - # TODO: improve guide handling - split for different points - ) - - # Setup webhooks for the project - cvat_webhook = cvat_api.create_cvat_webhook(cvat_project.id) - - project_id = db_service.create_project( - session, - cvat_project.id, - cvat_cloud_storage.id, - self.manifest.annotation.type, - self.escrow_address, - self.chain_id, - oracle_bucket.to_url().rstrip("/") - + "/" - + compose_data_bucket_prefix(self.escrow_address, self.chain_id), - cvat_webhook_id=cvat_webhook.id, - ) - created_projects.append(project_id) - - db_service.get_project_by_id( - session, project_id, for_update=True - ) # lock the row - db_service.add_project_images( - session, - cvat_project.id, - list(set(chain.from_iterable(skeleton_label_filenames))), - ) - - for point_label_filenames, gt_point_label_filenames in zip( - skeleton_label_filenames, gt_skeleton_label_filenames, strict=False - ): - cvat_task = cvat_api.create_task( - cvat_project.id, - name=cvat_project.name, - segment_size=segment_size, - ) - - task_id = db_service.create_task( - session, cvat_task.id, cvat_project.id, TaskStatuses[cvat_task.status] - ) - db_service.get_task_by_id(session, task_id, for_update=True) # lock the row - - # The task is fully created once 'update:task' webhook is received. - cvat_api.put_task_data( - cvat_task.id, - cvat_cloud_storage.id, - filenames=point_label_filenames + gt_point_label_filenames, - validation_params={ - "gt_filenames": gt_point_label_filenames, - "gt_frames_per_job_count": self._job_val_frames_count, - }, - ) - - gt_point_dataset = self._prepare_gt_dataset_for_skeleton_point( - point_label_name=point_label_name, - skeleton_label_id=skeleton_label_id, - ) - - self._setup_gt_job_for_cvat_task( - cvat_task.id, gt_point_dataset, dm_export_format="cvat" - ) - self._setup_quality_settings( - cvat_task.id, oks_sigma=Config.cvat_config.oks_sigma - ) - - db_service.create_data_upload(session, cvat_task.id) - - db_service.touch(session, Project, created_projects) - - def build(self): - self._download_input_data() - self._parse_gt() - self._parse_boxes() - self._validate_gt() - self._validate_boxes() - - # Task configuration creation - self._prepare_gt() - self._prepare_roi_infos() - self._prepare_task_params() - self._mangle_filenames() - self._prepare_job_labels() - - # Data preparation - self._extract_and_upload_rois() - self._upload_task_meta() - self._prepare_gt_points_mapping() - - self._create_on_cvat() - - -def is_image(path: str) -> bool: - trunk, ext = os.path.splitext(os.path.basename(path)) - return trunk and ext.lower() in IMAGE_EXTENSIONS - - -def filter_image_files(data_filenames: list[str]) -> list[str]: - return [fn for fn in data_filenames if is_image(fn)] - - -def strip_bucket_prefix(data_filenames: list[str], prefix: str) -> list[str]: - return [os.path.relpath(fn, prefix) for fn in data_filenames] - - -def make_label_configuration(manifest: TaskManifest) -> list[dict]: - return [ - { - "name": label.name, - "type": LABEL_TYPE_MAPPING[manifest.annotation.type].value, - } - for label in manifest.annotation.labels - ] - - -def _make_cvat_cloud_storage_params(bucket_info: BucketAccessInfo) -> dict: - CLOUD_PROVIDER_TO_CVAT_CLOUD_PROVIDER = { - CloudProviders.aws: "AWS_S3_BUCKET", - CloudProviders.gcs: "GOOGLE_CLOUD_STORAGE", - } - - params = { - "provider": CLOUD_PROVIDER_TO_CVAT_CLOUD_PROVIDER[bucket_info.provider], - "bucket_name": bucket_info.bucket_name, - "bucket_host": bucket_info.host_url, - } - - if bucket_info.credentials: - params["credentials"] = bucket_info.credentials.to_dict() - - return params - - -def create_task(escrow_address: str, chain_id: int) -> None: - logger = get_function_logger(module_logger) - - manifest = parse_manifest(get_escrow_manifest(chain_id, escrow_address)) - - if manifest.annotation.type in [TaskTypes.image_boxes, TaskTypes.image_label_binary]: - builder_type = SimpleTaskBuilder - elif manifest.annotation.type is TaskTypes.image_polygons: - builder_type = PolygonTaskBuilder - elif manifest.annotation.type in [TaskTypes.image_points]: - builder_type = PointsTaskBuilder - elif manifest.annotation.type in [TaskTypes.image_boxes_from_points]: - builder_type = BoxesFromPointsTaskBuilder - elif manifest.annotation.type in [TaskTypes.image_skeletons_from_boxes]: - builder_type = SkeletonsFromBoxesTaskBuilder - else: - raise Exception(f"Unsupported task type {manifest.annotation.type}") - - with builder_type(manifest, escrow_address, chain_id) as task_builder: - task_builder.set_logger(logger) - task_builder.build() diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/__init__.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/__init__.py new file mode 100644 index 0000000000..a74072dd7d --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/__init__.py @@ -0,0 +1,3 @@ +from src.handlers.job_creation.handlers import create_task + +__all__ = ["create_task"] diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/__init__.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/audio/__init__.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/audio/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/audio/transcription.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/audio/transcription.py new file mode 100644 index 0000000000..e71aaca248 --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/audio/transcription.py @@ -0,0 +1,814 @@ +from __future__ import annotations + +import csv +import io +import uuid +from collections import Counter +from datetime import timedelta +from math import ceil +from pathlib import Path, PurePosixPath +from tempfile import TemporaryDirectory +from typing import TYPE_CHECKING, TypeVar + +import numpy as np + +import src.cvat.api_calls as cvat_api +import src.services.cvat as db_service +from src.core.config import Config +from src.core.storage import compose_data_bucket_filename +from src.core.tasks import TaskTypes +from src.core.tasks.audio_transcription.meta import ( + Clip, + InputGtRegion, + InputRegion, + PlacedRegion, + PresentedRegion, + RegionKind, + TaskMetaLayout, + TaskMetaSerializer, + parse_gt_tsv, + parse_time, +) +from src.core.tasks.audio_transcription.spec import parse_audio_manifest +from src.core.types import TaskStatuses +from src.db import SessionLocal +from src.handlers.job_creation.builders.vision.base import TaskBuilderBase +from src.handlers.job_creation.exceptions import ( + DatasetValidationError, + ExcludedAnnotationsInfo, + TooFewSamples, +) +from src.handlers.job_creation.utils import ( + MaybeUnset, + get_assignment_bounty, + make_cvat_cloud_storage_params, + unset, +) +from src.models.cvat import Project +from src.services.cloud.utils import BucketAccessInfo +from src.utils.audio import RegionCut, cut_and_concat, probe_duration +from src.utils.logging import format_sequence + +if TYPE_CHECKING: + from collections.abc import Callable + + from src.core.manifest import ManifestBase + + +# --------------------------------------------------------------------------- # +# Clip construction +# --------------------------------------------------------------------------- # + + +_RegionT = TypeVar("_RegionT", bound=InputRegion | InputGtRegion) + + +def _bundle_regions( + regions: list[_RegionT], + *, + min_duration: timedelta, + max_duration: timedelta, + can_bundle: Callable[[_RegionT, _RegionT], bool] = lambda _a, _b: True, +) -> list[tuple[timedelta, timedelta, list[_RegionT]]]: + """ + Bundle consecutive input regions (sorted by start) into groups >= min_duration; + a region already >= min_duration stays alone. Returns (start, stop, members) per bundle. + + A bundle's span (first ROI start .. last ROI stop) includes the gaps between its members, so + two limits keep bundles from ballooning over sparse input: + - max_duration caps the presented span (a longer bundle would fail input validation anyway); + - the join gap is capped at min_duration, so we never bridge a long silence between ROIs. + + A custom ``can_bundle`` callback can be passed to specify additional constraints on the ROIs + that can be joined. + """ + + def can_append_region(bundle: list[_RegionT], region: _RegionT) -> bool: + if not can_bundle(bundle[-1], region): + return False + + gap = region.start - bundle[-1].stop + reach = region.stop - bundle[0].start + span = _get_span_duration(bundle) + return span < min_duration and gap <= min_duration and reach <= max_duration + + out: list[list[_RegionT]] = [] + bundle: list[_RegionT] | None = None + for region in regions: + if bundle is None: + bundle = [region] + elif can_append_region(bundle, region): + bundle.append(region) + else: + out.append(bundle) + bundle = [region] + + if bundle is not None: # trailing bundle may stay shorter than min_duration + out.append(bundle) + + return [(g[0].start, g[-1].stop, g) for g in out] + + +def select_honeypots( + regions: list[InputGtRegion], + *, + source_filename: str, + val_fraction: float, + min_duration: timedelta, + max_duration: timedelta, + random_seed: int = 0, +) -> list[PresentedRegion]: + """ + Pick GT regions for the honeypot pool. + + Bundle GT cues into >= min_duration groups, then pick ~val_fraction of the bundles (by count) + as honeypots. A bundle spans its first cue start to its last cue stop (including inter-cue + gaps); we never pad into unannotated media, so a bundle may stay shorter than min_duration when + the source GT does not provide enough context. + """ + + regions = sorted(regions, key=lambda r: r.start) + bundles = _bundle_regions( + regions, + min_duration=min_duration, + max_duration=max_duration, + can_bundle=( + # we can only bundle regions if they belong to the same span + lambda a, b: a.span_id == b.span_id + ), + ) + + rng = np.random.Generator(np.random.MT19937(random_seed)) # pin the rng used for stable results + idxs = list(range(len(bundles))) + rng.shuffle(idxs) + n_select = ceil(val_fraction * len(bundles)) + chosen = sorted(idxs[:n_select]) + + honeypots: list[PresentedRegion] = [] + for bundle_idx in chosen: + s, e, members = bundles[bundle_idx] + honeypots.append( + PresentedRegion( + source_filename=source_filename, + start=s.total_seconds(), + stop=e.total_seconds(), + kind=RegionKind.gt, + input_ids=[m.id for m in members], + ) + ) + return honeypots + + +def plan_assignments( + ds_regions: list[PresentedRegion], + honeypots: list[PresentedRegion], + *, + min_composition: tuple[int, int], + validation_overhead: float, + max_audio_duration: timedelta, + random_seed: int = 0, +) -> list[list[PresentedRegion]]: + """ + Mix DS and honeypots into assignments. Returns ordered region lists. + """ + + # 1. shuffle inputs + rng = np.random.Generator(np.random.MT19937(random_seed)) # pin the rng used for stable results + + def sort_key(r: PresentedRegion) -> tuple: + return (r.source_filename, r.start) + + ds_regions = sorted(ds_regions, key=sort_key) + rng.shuffle(ds_regions) + + honeypots = sorted(honeypots, key=sort_key) + rng.shuffle(honeypots) + + # 2. Reservoir-pack each assignment up to the DS budget (>= K_min), inject least-used honeypots + # up to the validation overhead (>= H_min), then shuffle region order. Deterministic. + ds_budget = max_audio_duration.total_seconds() * (1.0 - validation_overhead) + hp_target = validation_overhead * max_audio_duration.total_seconds() + h_min, k_min = min_composition + + hp_use: Counter = Counter() + assignments: list[list[PresentedRegion]] = [] + + ds_idx = 0 + while ds_idx < len(ds_regions): + pick: list[PresentedRegion] = [] + pick_duration = 0.0 + while ds_idx < len(ds_regions): + ds_region = ds_regions[ds_idx] + if len(pick) >= k_min and pick_duration + ds_region.duration > ds_budget: + break + + pick.append(ds_region) + pick_duration += ds_region.duration + ds_idx += 1 + + if not pick: + break # DS stream exhausted - nothing left to place + + # least-used honeypots first, randomized within each use-count tier + hp_duration = 0.0 + hp_ranked = sorted(range(len(honeypots)), key=lambda i: (hp_use[i], rng.random())) + for n_hp, i in enumerate(hp_ranked): + if (hp_duration >= hp_target and n_hp >= h_min) or n_hp >= len(honeypots): + break + pick.append(honeypots[i]) + hp_duration += honeypots[i].duration + hp_use[i] += 1 + + rng.shuffle(pick) + assignments.append(pick) + + return assignments + + +def place_regions( + regions: list[PresentedRegion], *, pause: timedelta +) -> tuple[list[PlacedRegion], float]: + """Clip-time placement of concatenated regions (region durations + inter-region pauses).""" + placed: list[PlacedRegion] = [] + t = 0.0 + n = len(regions) + for i, region in enumerate(regions): + dur = region.duration + placed.append( + PlacedRegion( + index=i, + source_filename=region.source_filename, + source_start=region.start, + source_stop=region.stop, + clip_start=t, + clip_stop=t + dur, + kind=region.kind, + input_ids=region.input_ids, + ) + ) + t += dur + if i < n - 1: + t += pause.total_seconds() + return placed, t + + +def _overlaps(a0: float, a1: float, b0: float, b1: float) -> bool: + return a0 < b1 and b0 < a1 + + +# --------------------------------------------------------------------------- # +# Builder +# --------------------------------------------------------------------------- # + + +class AudioTranscriptionTaskBuilder(TaskBuilderBase): + def __init__(self, manifest: ManifestBase, escrow_address: str, chain_id: int) -> None: + super().__init__(manifest=manifest, escrow_address=escrow_address, chain_id=chain_id) + + self.spec = parse_audio_manifest(self.manifest) + + self._media_dir: MaybeUnset[Path] = unset + self._media_paths: MaybeUnset[dict[str, Path]] = unset # source_filename -> local path + self._regions_by_file: MaybeUnset[dict[str, list[InputRegion]]] = unset + self._gt_by_file: MaybeUnset[dict[str, list[InputGtRegion]]] = unset + self._regions_tsv_data: MaybeUnset[bytes] = unset # raw input regions TSV + self._gt_tsv_data: MaybeUnset[bytes] = unset # raw input GT TSV + self._ds_regions: MaybeUnset[list[PresentedRegion]] = unset + self._honeypots: MaybeUnset[list[PresentedRegion]] = unset + self._assignments: MaybeUnset[list[Clip]] = unset + self._excluded_gt_info: MaybeUnset[ExcludedAnnotationsInfo] = unset + + self._meta_serializer = TaskMetaSerializer() + self._meta_layout = TaskMetaLayout() + + # -- input ------------------------------------------------------------- # + + def _download_input_data(self) -> None: + media_bucket = BucketAccessInfo.parse_obj(self.spec.data.media_url) + regions_bucket = BucketAccessInfo.parse_obj(self.spec.data.regions_url) + gt_bucket = BucketAccessInfo.parse_obj(self.spec.data.gt_url) + + media_client = self._make_cloud_storage_client(media_bucket) + regions_client = self._make_cloud_storage_client(regions_bucket) + gt_client = self._make_cloud_storage_client(gt_bucket) + + regions_tsv_data = regions_client.download_file(regions_bucket.path) + gt_tsv_data = gt_client.download_file(gt_bucket.path) + regions_by_file = _parse_regions_tsv(regions_tsv_data) + gt_by_file = _parse_gt_tsv(gt_tsv_data) + + # download only the referenced media files + referenced = set(regions_by_file) | set(gt_by_file) + media_dir = Path(self.exit_stack.enter_context(TemporaryDirectory())).resolve() + media_paths: dict[str, Path] = {} + for filename in sorted(referenced): + local_path = (media_dir / PurePosixPath(filename)).resolve() + local_path.relative_to(media_dir) # guard against path traversal attacks + local_path.parent.mkdir(parents=True, exist_ok=True) + + data = media_client.download_file(_bucket_key(media_bucket.path, filename)) + local_path.write_bytes(data) + media_paths[filename] = local_path + + self._media_dir = media_dir + self._media_paths = media_paths + self._regions_by_file = regions_by_file + self._gt_by_file = gt_by_file + self._regions_tsv_data = regions_tsv_data + self._gt_tsv_data = gt_tsv_data + + # -- region pools ------------------------------------------------------ # + + def _prepare_rois(self) -> None: + self._build_gt_regions() + self._build_ds_regions() + + def _build_gt_regions(self) -> None: + assert self._gt_by_file is not unset + assert self._media_paths is not unset + + excluded_gt = ExcludedAnnotationsInfo() + honeypots: list[PresentedRegion] = [] + + for filename in sorted(self._gt_by_file): + file_duration = probe_duration(self._media_paths[filename]) + valid_regions = _validate_gt_regions( + self._gt_by_file[filename], + filename=filename, + file_duration=file_duration, + max_duration=self.spec.details.roi_max_duration, + min_span_duration=self.spec.details.min_gt_span_duration, + excluded=excluded_gt, + ) + if not valid_regions: + continue + + honeypots.extend( + select_honeypots( + valid_regions, + source_filename=filename, + val_fraction=1.0, # use all spans, honeypot rotation is a future feature + min_duration=self.spec.details.roi_min_duration, + max_duration=self.spec.details.roi_max_duration, + random_seed=self.spec.details.random_seed, + ) + ) + + if excluded_gt.excluded_count: + self.logger.warning( + "Some GT regions were excluded due to errors found: \n{}".format( + format_sequence([m.message for m in excluded_gt.messages], separator="\n") + ) + ) + if excluded_gt.excluded_count > ceil( + excluded_gt.total_count * self.spec.details.max_discarded_gt + ): + raise TooFewSamples( + "Too many GT regions discarded, canceling job creation. Errors: {}".format( + format_sequence([m.message for m in excluded_gt.messages]) + ) + ) + + h_min = self.spec.details.min_composition[0] + if len(honeypots) < h_min: + raise TooFewSamples( + f"Too few ground-truth honeypots after filtering ({len(honeypots)}), " + f"at least {h_min} required." + ) + + self._honeypots = honeypots + self._excluded_gt_info = excluded_gt + + # -- dataset regions --------------------------------------------------- # + + def _build_ds_regions(self) -> None: + assert self._regions_by_file is not unset + assert self._gt_by_file is not unset + + # Regions and ground truth are should not normally overlap. + # Keep all DS regions regardless and only warn if overlaps are found. + gt_spans_by_file: dict[str, list[tuple[float, float]]] = {} + for filename, gt_regions in self._gt_by_file.items(): + gt_spans_by_file[filename] = [ + (gt.start.total_seconds(), gt.stop.total_seconds()) for gt in gt_regions + ] + + ds_regions: list[PresentedRegion] = [] + overlap_count = 0 + for filename in sorted(self._regions_by_file): + gt_spans = gt_spans_by_file.get(filename, []) + rows = sorted(self._regions_by_file[filename], key=lambda r: r.start) + overlap_count += sum( + any( + _overlaps(r.start.total_seconds(), r.stop.total_seconds(), gs, ge) + for gs, ge in gt_spans + ) + for r in rows + ) + bundled = _bundle_regions( + rows, + min_duration=self.spec.details.roi_min_duration, + max_duration=self.spec.details.roi_max_duration, + ) + for start, stop, members in bundled: + ds_regions.append( + PresentedRegion( + source_filename=filename, + start=start.total_seconds(), + stop=stop.total_seconds(), + kind=RegionKind.ds, + input_ids=[m.id for m in members], + ) + ) + + if overlap_count: + self.logger.warning( + f"{overlap_count} input region(s) overlap ground-truth regions; " + "regions and ground truth are expected to be disjoint." + ) + + self._ds_regions = ds_regions + + # -- assignments ------------------------------------------------------- # + + def _prepare_assignments(self) -> None: + assert self._ds_regions is not unset + assert self._honeypots is not unset + assert self._media_dir is not unset + assert self._media_paths is not unset + + region_lists = plan_assignments( + self._ds_regions, + self._honeypots, + min_composition=self.spec.details.min_composition, + validation_overhead=self.spec.details.validation_overhead, + max_audio_duration=self.spec.details.standard_assignment_duration, + random_seed=self.spec.details.random_seed, + ) + if not region_lists: + raise DatasetValidationError( + "No assignments could be formed from the provided regions and ground truth" + ) + + pause = self.spec.details.roi_join_pause + pause_ms = round(pause.total_seconds() * 1000) + assignments: list[Clip] = [] + for regions in region_lists: + assignment_id = uuid.uuid4().hex + clip_filename = f"{assignment_id}.wav" + clip_path = self._media_dir / clip_filename + + cuts = [ + RegionCut( + media=self._media_paths[r.source_filename], + start=timedelta(seconds=r.start), + stop=timedelta(seconds=r.stop), + ) + for r in regions + ] + cut_and_concat( + cuts, clip_path, pause_ms=pause_ms, sample_rate=self.spec.details.sample_rate + ) + + placed, clip_duration = place_regions(regions, pause=pause) + assignments.append( + Clip( + id=assignment_id, + clip_filename=clip_filename, + clip_duration=clip_duration, + placed=placed, + ) + ) + self._assignments = assignments + + # -- persistence ------------------------------------------------------- # + + def _upload_clips_and_meta(self) -> None: + assert self._assignments is not unset + assert self._media_dir is not unset + assert self._media_paths is not unset + assert self._ds_regions is not unset + assert self._honeypots is not unset + assert self._regions_tsv_data is not unset + assert self._gt_tsv_data is not unset + + storage_client = self._make_cloud_storage_client(self._oracle_data_bucket) + + for assignment in self._assignments: + clip_path = self._media_dir / assignment.clip_filename + storage_client.create_file( + compose_data_bucket_filename( + self.escrow_address, + self.chain_id, + f"{self._meta_layout.CLIPS_DIR}/{assignment.clip_filename}", + ), + clip_path.read_bytes(), + ) + + # copies of the raw inputs, for provenance / downstream scoring + storage_client.create_file( + compose_data_bucket_filename( + self.escrow_address, self.chain_id, self._meta_layout.REGIONS_TSV_FILENAME + ), + self._regions_tsv_data, + ) + storage_client.create_file( + compose_data_bucket_filename( + self.escrow_address, self.chain_id, self._meta_layout.GT_FILENAME + ), + self._gt_tsv_data, + ) + + pool = list(self._ds_regions) + list(self._honeypots) + storage_client.create_file( + compose_data_bucket_filename( + self.escrow_address, self.chain_id, self._meta_layout.REGIONS_FILENAME + ), + self._meta_serializer.serialize_regions(pool), + ) + storage_client.create_file( + compose_data_bucket_filename( + self.escrow_address, self.chain_id, self._meta_layout.CLIPS_FILENAME + ), + self._meta_serializer.serialize_clips(self._assignments), + ) + + if Config.debug: + self._upload_roi_cuts(storage_client) + + def _upload_roi_cuts(self, storage_client) -> None: + assert self._media_dir is not unset + assert self._media_paths is not unset + assert self._ds_regions is not unset + assert self._honeypots is not unset + + pairs = ( + (self._meta_layout.DS_CUTS_DIR, self._ds_regions), + (self._meta_layout.GT_CUTS_DIR, self._honeypots), + ) + for subdir, regions in pairs: + for i, region in enumerate(regions): + stem = PurePosixPath(region.source_filename).stem + cut_name = f"{i:04d}_{stem}_{region.start:.2f}-{region.stop:.2f}.wav" + cut_path = self._media_dir / cut_name + cut_and_concat( + [ + RegionCut( + media=self._media_paths[region.source_filename], + start=timedelta(seconds=region.start), + stop=timedelta(seconds=region.stop), + ) + ], + cut_path, + pause_ms=0, + sample_rate=self.spec.details.sample_rate, + ) + storage_client.create_file( + compose_data_bucket_filename( + self.escrow_address, self.chain_id, f"{subdir}/{cut_name}" + ), + cut_path.read_bytes(), + ) + + # -- CVAT + DB --------------------------------------------------------- # + + def _create_on_cvat(self) -> None: + assert self._assignments is not unset + + escrow_address = self.escrow_address + chain_id = self.chain_id + + label_configuration = _make_cvat_audio_label_configuration( + self.spec.labels, + transcription_attr_name=self.spec.details.transcription_attr_name, + shared_attributes=self.spec.shared_attributes, + ) + + cvat_project = cvat_api.create_project( + escrow_address, labels=label_configuration, user_guide=self.spec.user_guide + ) + cvat_webhook = cvat_api.create_cvat_webhook(cvat_project.id) + cloud_storage = cvat_api.create_cloudstorage( + **make_cvat_cloud_storage_params(self._oracle_data_bucket) + ) + + with SessionLocal.begin() as session: + self.logger.info( + "Task creation for escrow '%s': will create %s assignments", + escrow_address, + len(self._assignments), + ) + db_service.create_escrow_creation( + session, + escrow_address=escrow_address, + chain_id=chain_id, + total_jobs=len(self._assignments), + ) + + project_id = db_service.create_project( + session, + cvat_project.id, + cvat_cloudstorage_id=cloud_storage.id, + job_type=TaskTypes.audio_transcription, + escrow_address=escrow_address, + chain_id=chain_id, + bucket_url=self._oracle_data_bucket.to_url(), + cvat_webhook_id=cvat_webhook.id, + assignment_bounty=get_assignment_bounty( + self.manifest, + escrow_address=escrow_address, + chain_id=chain_id, + job_count=len(self._assignments), + ), + ) + db_service.get_project_by_id(session, project_id, for_update=True) # lock the row + + task_clips: dict[int, str] = {} # CVAT task id -> clip id + for assignment in self._assignments: + clip_key = compose_data_bucket_filename( + escrow_address, + chain_id, + f"{self._meta_layout.CLIPS_DIR}/{assignment.clip_filename}", + ) + cvat_task = cvat_api.create_task(cvat_project.id, escrow_address) + task_id = db_service.create_task( + session, cvat_task.id, cvat_project.id, TaskStatuses[cvat_task.status] + ) + db_service.get_task_by_id(session, task_id, for_update=True) # lock the row + + cvat_api.put_task_data(cvat_task.id, cloud_storage.id, filenames=[clip_key]) + db_service.create_data_upload(session, cvat_task.id) + + task_clips[cvat_task.id] = assignment.id + + db_service.touch(session, Project, [project_id]) + + # Persist the CVAT task -> clip mapping so the recording oracle can join each annotated job + # (keyed by its CVAT task id) back to its clip metadata for scoring. + storage_client = self._make_cloud_storage_client(self._oracle_data_bucket) + storage_client.create_file( + compose_data_bucket_filename( + escrow_address, chain_id, self._meta_layout.TASK_CLIPS_FILENAME + ), + self._meta_serializer.serialize_task_clips(task_clips), + ) + + # -- orchestration ----------------------------------------------------- # + + def build(self) -> None: + self._download_input_data() + + self._prepare_rois() + self._prepare_assignments() + + self._upload_clips_and_meta() + self._create_on_cvat() + + +# --------------------------------------------------------------------------- # +# TSV parsing +# --------------------------------------------------------------------------- # + + +def _read_tsv(data: bytes) -> list[dict[str, str]]: + reader = csv.DictReader(io.StringIO(data.decode("utf-8")), delimiter="\t") + return list(reader) + + +def _parse_regions_tsv(data: bytes) -> dict[str, list[InputRegion]]: + by_file: dict[str, list[InputRegion]] = {} + for row_idx, row in enumerate(_read_tsv(data)): + filename = row["filename"].strip() + by_file.setdefault(filename, []).append( + InputRegion( + filename=filename, + row_idx=row_idx, + start=parse_time(row["start"]), + stop=parse_time(row["stop"]), + label=(row.get("label") or "").strip() or None, + ) + ) + return by_file + + +def _parse_gt_tsv(data: bytes) -> dict[str, list[InputGtRegion]]: + by_file: dict[str, list[InputGtRegion]] = {} + for region in parse_gt_tsv(data): + by_file.setdefault(region.filename, []).append(region) + return by_file + + +# --------------------------------------------------------------------------- # +# Helpers +# --------------------------------------------------------------------------- # + + +def _validate_gt_regions( + regions: list[InputGtRegion], + *, + filename: str, + file_duration: timedelta, + max_duration: timedelta, + min_span_duration: timedelta, + excluded: ExcludedAnnotationsInfo, +) -> list[InputGtRegion]: + valid: list[InputGtRegion] = [] + for region in regions: + start = region.start.total_seconds() + stop = region.stop.total_seconds() + + excluded.total_count += 1 + + if not (0 <= start < stop <= file_duration.total_seconds() + 1e-6): + excluded.excluded_count += 1 + excluded.add_message( + f"GT region '{region.row_idx}' ({region.label}) [{start:.3f}, {stop:.3f}] " + "- invalid timestamps", + sample_id=filename, + sample_subset="", + ) + continue + + if stop - start > max_duration.total_seconds(): + excluded.excluded_count += 1 + excluded.add_message( + f"GT region '{region.row_idx}' ({region.label}) [{start:.3f}, {stop:.3f}] " + f"- longer than the maximum region duration ({max_duration.total_seconds():.3f}s)", + sample_id=filename, + sample_subset="", + ) + continue + + valid.append(region) + + by_span: dict[str, list[InputGtRegion]] = {} + for region in valid: + by_span.setdefault(region.span_id, []).append(region) + + valid.clear() + for span_id, span_members in by_span.items(): + span_duration = _get_span_duration(span_members) + + if span_duration < min_span_duration: + excluded.excluded_count += len(span_members) + excluded.add_message( + f"GT span '{span_id}' ({span_duration:.3f}s) - shorter " + f"than the minimum span duration ({min_span_duration.total_seconds():.3f}s)", + sample_id=filename, + sample_subset="", + ) + continue + + valid.extend(span_members) + + return valid + + +def _bucket_key(prefix: str, filename: str) -> str: + """Join a bucket prefix and a filename into a POSIX-style object key.""" + return str(PurePosixPath(prefix, filename)) + + +def _make_cvat_audio_label_configuration( + labels: list[str], + *, + transcription_attr_name: str, + shared_attributes: list | None = None, +) -> list[dict]: + """Interval labels (one per speaker) each carrying a mutable transcription text attribute, + plus any shared attributes. Used for audio_transcription tasks.""" + shared_attributes = shared_attributes or [] + + def _shared_attr_spec(attr) -> dict: + return { + "name": attr.name, + "mutable": True, + "input_type": attr.type or "text", + "values": list(attr.values), + "default_value": attr.default_value, + } + + label_config = [] + for name in labels: + attributes = [ + { + "name": transcription_attr_name, + "mutable": True, + "input_type": "text", + "values": [], + "default_value": "", + }, + *(_shared_attr_spec(a) for a in shared_attributes), + ] + label_config.append( + { + "name": name, + "type": cvat_api.LabelType.interval.value, + "attributes": attributes, + } + ) + return label_config + + +def _get_span_duration(group: list[InputRegion | InputGtRegion]) -> timedelta: + return group[-1].stop - group[0].start diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/factory.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/factory.py new file mode 100644 index 0000000000..a77a2370e5 --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/factory.py @@ -0,0 +1,49 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +from src.core.manifest import get_manifest_task_type +from src.core.tasks import TaskTypes +from src.handlers.job_creation.builders.audio.transcription import AudioTranscriptionTaskBuilder +from src.handlers.job_creation.builders.vision.basic import ( + BoxesTaskBuilder, + LabelBinaryTaskBuilder, + PointsTaskBuilder, + PolygonTaskBuilder, +) +from src.handlers.job_creation.builders.vision.boxes_from_points import BoxesFromPointsTaskBuilder +from src.handlers.job_creation.builders.vision.skeletons_from_boxes import ( + SkeletonsFromBoxesTaskBuilder, +) + +if TYPE_CHECKING: + from src.core.manifest import ManifestBase + from src.handlers.job_creation.builders.vision.base import TaskBuilderBase + + +def create_builder( + manifest: ManifestBase, + escrow_address: str, + chain_id: int, +) -> TaskBuilderBase: + task_type = get_manifest_task_type(manifest) + + match task_type: + case TaskTypes.image_boxes: + builder_type = BoxesTaskBuilder + case TaskTypes.image_label_binary: + builder_type = LabelBinaryTaskBuilder + case TaskTypes.image_polygons: + builder_type = PolygonTaskBuilder + case TaskTypes.image_points: + builder_type = PointsTaskBuilder + case TaskTypes.image_boxes_from_points: + builder_type = BoxesFromPointsTaskBuilder + case TaskTypes.image_skeletons_from_boxes: + builder_type = SkeletonsFromBoxesTaskBuilder + case TaskTypes.audio_transcription: + builder_type = AudioTranscriptionTaskBuilder + case _: + raise NotImplementedError(f"Unsupported task type '{task_type}'") + + return builder_type(manifest, escrow_address, chain_id) diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/vision/__init__.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/vision/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/vision/base.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/vision/base.py new file mode 100644 index 0000000000..b6ea00c4b5 --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/vision/base.py @@ -0,0 +1,155 @@ +from __future__ import annotations + +import random +from abc import ABCMeta, abstractmethod +from contextlib import ExitStack +from pathlib import Path +from tempfile import TemporaryDirectory +from time import sleep +from typing import TYPE_CHECKING + +from datumaro.util import take_by + +import src.cvat.api_calls as cvat_api +import src.services.cloud as cloud_service +from src.core.config import Config +from src.services.cloud import CloudProviders, StorageClient +from src.services.cloud.utils import BucketAccessInfo +from src.utils.logging import NullLogger +from src.utils.zip_archive import write_dir_to_zip_archive + +if TYPE_CHECKING: + from collections.abc import Generator + from logging import Logger + + import datumaro as dm + + from src.core.manifest import ManifestBase + + +class TaskBuilderBase(metaclass=ABCMeta): + def __init__(self, manifest: ManifestBase, escrow_address: str, chain_id: int) -> None: + self.exit_stack = ExitStack() + self.manifest = manifest + self.escrow_address = escrow_address + self.chain_id = chain_id + + self.logger: Logger = NullLogger() + + self._oracle_data_bucket = BucketAccessInfo.parse_obj(Config.storage_config) + + @property + def _task_segment_size(self) -> int: + return self.manifest.annotation.job_size + + @property + def _job_val_frames_count(self) -> int: + return self.manifest.validation.val_size + + def __enter__(self): + return self + + def __exit__(self, *args, **kwargs): + self.close() + + def close(self): + self.exit_stack.close() + + def set_logger(self, logger: Logger): + # TODO: add escrow info into messages + self.logger = logger + return self + + @classmethod + def _make_cloud_storage_client(cls, bucket_info: BucketAccessInfo) -> StorageClient: + extra_args = {} + + if bucket_info.provider == CloudProviders.aws: + import boto3.session + + extra_args["config"] = boto3.session.Config( + max_pool_connections=Config.features.max_data_storage_connections + ) + elif bucket_info.provider == CloudProviders.gcs: + pass # TODO: test and add connections if needed + + return cloud_service.make_client(bucket_info, **extra_args) + + def _save_cvat_gt_dataset_to_oracle_bucket( # noqa: B027 + self, + gt_dataset_path: Path, + *, + file_suffix: str = "", + ) -> None: + # method saves gt annotations that will be uploaded to CVAT + # into oracle bucket + pass + + def _wait_task_creation(self, task_id: int) -> cvat_api.RequestStatus: + # TODO: add a timeout or + # save gt datasets in the oracle bucket and upload in track_task_creation() + while True: + task_status, _ = cvat_api.get_task_upload_status(task_id) + if task_status not in [cvat_api.RequestStatus.STARTED, cvat_api.RequestStatus.QUEUED]: + return task_status + + sleep(Config.cvat_config.task_creation_check_interval) + + def _setup_gt_job_for_cvat_task( + self, task_id: int, gt_dataset: dm.Dataset, *, dm_export_format: str = "coco" + ) -> None: + task_status = self._wait_task_creation(task_id) + if task_status != cvat_api.RequestStatus.FINISHED: + return # will be handled in state_trackers.py::track_task_creation + + dm_format_to_cvat_format = { + "coco": "COCO 1.0", + "cvat": "CVAT 1.1", + "datumaro": "Datumaro 1.0", + } + + with TemporaryDirectory() as tmp_dir: + export_dir = Path(tmp_dir) / "export" + gt_dataset.export(save_dir=str(export_dir), save_media=False, format=dm_export_format) + + annotations_archive_path = Path(tmp_dir) / "annotations.zip" + with annotations_archive_path.open("wb") as annotations_archive: + write_dir_to_zip_archive(export_dir, annotations_archive) + + if Config.is_development_mode(): + self._save_cvat_gt_dataset_to_oracle_bucket( + gt_dataset_path=annotations_archive_path, file_suffix=f"for_task_{task_id}" + ) + + self._setup_gt_job( + task_id, + annotations_archive_path, + format_name=dm_format_to_cvat_format[dm_export_format], + ) + + def _setup_gt_job(self, task_id: int, dataset_path: Path, format_name: str) -> None: + gt_job = cvat_api.get_gt_job(task_id) + cvat_api.upload_gt_annotations(gt_job.id, dataset_path, format_name=format_name) + cvat_api.finish_gt_job(gt_job.id) + + def _setup_quality_settings(self, task_id: int, **overrides) -> None: + settings = cvat_api.get_quality_control_settings(task_id) + + values = { + "target_metric_threshold": self.manifest.validation.min_quality, + "empty_is_annotated": True, + } + values.update(**overrides) + cvat_api.update_quality_control_settings(settings.id, **values) + + def _split_dataset_per_task( + self, + data_filenames: list[str], + *, + subset_size: int, + ) -> Generator[str]: + random.shuffle(data_filenames) + yield from take_by(data_filenames, subset_size) + + @abstractmethod + def build(self) -> None: ... diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/vision/basic.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/vision/basic.py new file mode 100644 index 0000000000..b7fa30323f --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/vision/basic.py @@ -0,0 +1,345 @@ +from __future__ import annotations + +import math +import os +from abc import abstractmethod +from tempfile import TemporaryDirectory +from typing import TYPE_CHECKING + +import datumaro as dm +import numpy as np + +import src.core.tasks.points as points_task +import src.core.tasks.simple as simple_task +import src.cvat.api_calls as cvat_api +import src.services.cloud as cloud_service +import src.services.cvat as db_service +from src.core.config import Config +from src.core.storage import compose_data_bucket_filename +from src.core.types import TaskStatuses +from src.db import SessionLocal +from src.models.cvat import Project +from src.services.cloud.utils import BucketAccessInfo +from src.utils.logging import format_sequence + +if TYPE_CHECKING: + from src.core.manifest.v1 import JobManifest + +from src.core.tasks.cvat_formats import DM_GT_DATASET_FORMAT_MAPPING +from src.handlers.job_creation.builders.vision.base import TaskBuilderBase +from src.handlers.job_creation.exceptions import ( + DatasetValidationError, + TooFewSamples, +) +from src.handlers.job_creation.utils import ( + MaybeUnset, + filter_image_files, + get_assignment_bounty, + make_cvat_cloud_storage_params, + make_cvat_label_configuration, + unset, +) + + +class SimpleTaskBuilder(TaskBuilderBase): + """ + Base builder for simple image tasks with a single annotation type and no extra processing. + """ + + @abstractmethod + def _upload_task_meta(self, gt_dataset: dm.Dataset) -> None: ... + + def _parse_gt_dataset( + self, gt_file_data: bytes, *, add_prefix: str | None = None + ) -> dm.Dataset: + with TemporaryDirectory() as gt_temp_dir: + gt_filename = os.path.join(gt_temp_dir, "gt_annotations.json") + with open(gt_filename, "wb") as f: + f.write(gt_file_data) + + gt_dataset = dm.Dataset.import_from( + gt_filename, + format=DM_GT_DATASET_FORMAT_MAPPING[self.manifest.annotation.type], + ) + + if add_prefix: + gt_dataset = dm.Dataset.from_iterable( + [s.wrap(id=os.path.join(add_prefix, s.id)) for s in gt_dataset], + categories=gt_dataset.categories(), + media_type=gt_dataset.media_type(), + ) + + gt_dataset.init_cache() + + return gt_dataset + + def _get_gt_filenames( + self, gt_dataset: dm.Dataset, data_filenames: list[str], *, manifest: JobManifest + ) -> list[str]: + gt_filenames = set(s.id + s.media.ext for s in gt_dataset) + known_data_filenames = set(data_filenames) + matched_gt_filenames = gt_filenames.intersection(known_data_filenames) + + if len(gt_filenames) != len(matched_gt_filenames): + missing_gt = gt_filenames - matched_gt_filenames + raise DatasetValidationError( + "Failed to find several validation samples in the dataset files: {}".format( + format_sequence(list(missing_gt)) + ) + ) + + if len(gt_filenames) < manifest.validation.val_size: + raise TooFewSamples( + f"Too few validation samples provided ({len(gt_filenames)}), " + f"at least {manifest.validation.val_size} required." + ) + + return list(matched_gt_filenames) + + def _prepare_cvat_label_configuration(self) -> list[dict]: + return make_cvat_label_configuration(self.manifest) + + def build(self): + manifest = self.manifest + escrow_address = self.escrow_address + chain_id = self.chain_id + + data_bucket = BucketAccessInfo.parse_obj(manifest.data.data_url) + gt_bucket = BucketAccessInfo.parse_obj(manifest.validation.gt_url) + + data_bucket_client = cloud_service.make_client(data_bucket) + gt_bucket_client = cloud_service.make_client(gt_bucket) + + # Task configuration creation + data_filenames = data_bucket_client.list_files(prefix=data_bucket.path) + data_filenames = filter_image_files(data_filenames) + + gt_file_data = gt_bucket_client.download_file(gt_bucket.path) + + # Validate and parse GT + gt_dataset = self._parse_gt_dataset(gt_file_data, add_prefix=data_bucket.path) + + # Create task configuration + gt_filenames = self._get_gt_filenames(gt_dataset, data_filenames, manifest=manifest) + data_to_be_annotated = [f for f in data_filenames if f not in set(gt_filenames)] + label_configuration = self._prepare_cvat_label_configuration() + + self._upload_task_meta(gt_dataset) + + # Register cloud storage on CVAT to pass user dataset + cloud_storage = cvat_api.create_cloudstorage(**make_cvat_cloud_storage_params(data_bucket)) + + # Create a project + cvat_project = cvat_api.create_project( + escrow_address, + labels=label_configuration, + user_guide=manifest.annotation.user_guide, + ) + + # Setup webhooks for the project + cvat_webhook = cvat_api.create_cvat_webhook(cvat_project.id) + + with SessionLocal.begin() as session: + segment_size = self._task_segment_size + total_jobs = math.ceil(len(data_to_be_annotated) / segment_size) + + self.logger.info( + "Task creation for escrow '%s': will create %s assignments", + escrow_address, + total_jobs, + ) + db_service.create_escrow_creation( + session, escrow_address=escrow_address, chain_id=chain_id, total_jobs=total_jobs + ) + + project_id = db_service.create_project( + session, + cvat_project.id, + cvat_cloudstorage_id=cloud_storage.id, + job_type=manifest.annotation.type, + escrow_address=escrow_address, + chain_id=chain_id, + bucket_url=data_bucket.to_url(), + cvat_webhook_id=cvat_webhook.id, + assignment_bounty=get_assignment_bounty( + manifest, escrow_address=escrow_address, chain_id=chain_id, job_count=total_jobs + ), + ) + + db_service.get_project_by_id(session, project_id, for_update=True) # lock the row + db_service.add_project_images(session, cvat_project.id, data_filenames) + + for data_subset in self._split_dataset_per_task( + data_to_be_annotated, + subset_size=Config.cvat_config.max_jobs_per_task * segment_size, + ): + cvat_task = cvat_api.create_task( + cvat_project.id, escrow_address, segment_size=segment_size + ) + task_id = db_service.create_task( + session, cvat_task.id, cvat_project.id, TaskStatuses[cvat_task.status] + ) + db_service.get_task_by_id(session, task_id, for_update=True) # lock the row + + # The task is fully created once 'update:task' webhook is received. + cvat_api.put_task_data( + cvat_task.id, + cloud_storage.id, + filenames=data_subset, + validation_params={ + "gt_filenames": gt_filenames, # include whole GT dataset into each task + "gt_frames_per_job_count": self._job_val_frames_count, + }, + ) + + self._setup_gt_job_for_cvat_task(cvat_task.id, gt_dataset) + self._setup_quality_settings(cvat_task.id) + + db_service.create_data_upload(session, cvat_task.id) + db_service.touch(session, Project, [project_id]) + + +class LabelBinaryTaskBuilder(TaskBuilderBase): + def build(self): + raise NotImplementedError + + +class BoxesTaskBuilder(SimpleTaskBuilder): + def _upload_task_meta(self, gt_dataset: dm.Dataset): + layout = simple_task.TaskMetaLayout() + serializer = simple_task.TaskMetaSerializer() + + file_list = [] + file_list.append( + ( + serializer.serialize_gt_annotations(gt_dataset), + layout.GT_FILENAME, + ) + ) + + storage_client = self._make_cloud_storage_client(self._oracle_data_bucket) + for file_data, filename in file_list: + storage_client.create_file( + compose_data_bucket_filename(self.escrow_address, self.chain_id, filename), + file_data, + ) + + +class PointsTaskBuilder(SimpleTaskBuilder): + def __init__(self, manifest: JobManifest, escrow_address: str, chain_id: int) -> None: + super().__init__(manifest=manifest, escrow_address=escrow_address, chain_id=chain_id) + + self._mean_gt_bbox_radius_estimation: MaybeUnset[float] = unset + + def _parse_gt_dataset(self, gt_file_data, *, add_prefix=None): + gt_dataset = super()._parse_gt_dataset(gt_file_data, add_prefix=add_prefix) + + assert len(gt_dataset.categories()[dm.AnnotationType.label]) == 1 + label_id = 0 + + updated_gt_dataset = dm.Dataset(categories=gt_dataset.categories(), media_type=dm.Image) + + # Replace boxes with their center points + # Collect radius statistics + radiuses = [] + for gt_sample in gt_dataset: + image_size = gt_sample.media_as(dm.Image).size + image_half_diag = ((image_size[0] ** 2 + image_size[1] ** 2) ** 0.5) / 2 + + sample_points = [] + for gt_bbox in gt_sample.annotations: + if not isinstance(gt_bbox, dm.Bbox): + continue + + x, y, w, h = gt_bbox.get_bbox() + bbox_center = dm.Points([x + w / 2, y + h / 2], label=gt_bbox.label, id=gt_bbox.id) + + rel_int_bbox_radius = min(w, h) / 2 / image_half_diag + radiuses.append(rel_int_bbox_radius) + + sample_points.extend(bbox_center.points) + + # Join points into a single annotation for compatibility with CVAT capabilities + updated_anns = [] + if sample_points: + updated_anns.append(dm.Points(sample_points, label=label_id)) + + updated_gt_dataset.put(gt_sample.wrap(annotations=updated_anns)) + + self._mean_gt_bbox_radius_estimation = min(0.5, np.mean(radiuses).item()) + + return updated_gt_dataset + + def _upload_task_meta(self, gt_dataset: dm.Dataset): + layout = points_task.TaskMetaLayout() + serializer = points_task.TaskMetaSerializer() + + file_list = [] + file_list.append( + ( + serializer.serialize_gt_annotations(gt_dataset), + layout.GT_FILENAME, + ) + ) + + storage_client = self._make_cloud_storage_client(self._oracle_data_bucket) + for file_data, filename in file_list: + storage_client.create_file( + compose_data_bucket_filename(self.escrow_address, self.chain_id, filename), + file_data, + ) + + def _setup_gt_job_for_cvat_task( + self, task_id: int, gt_dataset: dm.Dataset, *, dm_export_format: str = "datumaro" + ) -> None: + super()._setup_gt_job_for_cvat_task( + task_id=task_id, gt_dataset=gt_dataset, dm_export_format=dm_export_format + ) + + def _setup_quality_settings(self, task_id: int, **overrides) -> None: + assert self._mean_gt_bbox_radius_estimation is not unset + + values = { + # We have at most 1 annotation per frame, so accuracy on each frame is either 0 or 1, + # regardless of the points count. For job accuracy we'll have: + # quality = mean frame accuracy = count of correct frames / validation frame count. + # If we set quality threshold from the manifest on this value, it can break quality + # requirements. + # Example: target quality is 80%, 6 frames, 1 has 20 points, 5 others have 1. + # Suppose the 5 frames with 1 point are annotated correctly and + # the one with 20 - is not annotated. The mean frame accuracy will be 5 / 6 ~ 83%, + # which is higher than the target quality, so the job will be accepted. + # The per-point mean (aka micro) accuracy will be 5 / (20 + 5) = 20%. + # + # Instead, we require that each frame matches with the required quality threshold, + # so the job accuracy is 1. This is a more strict requirement, from which + # follows that the job quality >= required. + # For each frame, as we have just 1 annotation, quality is computed as mean + # point quality on the frame with frame matching threshold. + # Point set accuracy is controlled by iou_threshold, + # so configure it with the requested quality value. + # + # TODO: consider adding a quality option to count points as separate, + # or implement and use the mean IoU as the target metric in CVAT. + "target_metric_threshold": 0.95, # some big number close to 1 + "iou_threshold": self.manifest.validation.min_quality, + "oks_sigma": self._mean_gt_bbox_radius_estimation, + "point_size_base": "image_size", + } + values.update(overrides) + super()._setup_quality_settings(task_id, **values) + + def build(self): + if len(self.manifest.annotation.labels) != 1: + # TODO: implement support for multiple labels + # Probably, need to split the whole task into projects per label + # for efficient annotation + raise NotImplementedError("Point annotation tasks can have only 1 label") + + return super().build() + + +class PolygonTaskBuilder(BoxesTaskBuilder): + def _setup_quality_settings(self, task_id: int, **overrides) -> None: + values = {"iou_threshold": Config.cvat_config.iou_threshold, **overrides} + super()._setup_quality_settings(task_id, **values) diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/vision/boxes_from_points.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/vision/boxes_from_points.py new file mode 100644 index 0000000000..19eaefe061 --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/vision/boxes_from_points.py @@ -0,0 +1,1153 @@ +from __future__ import annotations + +import math +import os +import uuid +from concurrent.futures import Future, ThreadPoolExecutor +from dataclasses import dataclass, field +from itertools import groupby +from math import ceil +from pathlib import Path +from queue import Queue +from tempfile import TemporaryDirectory +from typing import TYPE_CHECKING, cast + +import cv2 +import datumaro as dm +import numpy as np +from datumaro.util import filter_dict +from datumaro.util.image import decode_image, encode_image + +import src.core.tasks.boxes_from_points as boxes_from_points_task +import src.core.tasks.skeletons_from_boxes as skeletons_from_boxes_task +import src.cvat.api_calls as cvat_api +import src.services.cvat as db_service +from src.core.config import Config +from src.core.storage import compose_data_bucket_filename, compose_data_bucket_prefix +from src.core.types import TaskStatuses +from src.db import SessionLocal +from src.models.cvat import Project +from src.services.cloud.utils import BucketAccessInfo +from src.utils.annotations import ProjectLabels, is_point_in_bbox +from src.utils.logging import format_sequence +from src.utils.roi_uploader import BufferedRoiImageUploader + +if TYPE_CHECKING: + from collections.abc import Sequence + + from src.core.manifest.v1 import JobManifest + +from src.core.tasks.cvat_formats import DM_GT_DATASET_FORMAT_MAPPING +from src.handlers.job_creation.builders.vision.base import TaskBuilderBase +from src.handlers.job_creation.exceptions import ( + DatasetValidationError, + ExcludedAnnotationsInfo, + InvalidCategories, + InvalidCoordinates, + InvalidImageInfo, + MismatchingAnnotations, + TooFewSamples, +) +from src.handlers.job_creation.utils import ( + MaybeUnset, + filter_image_files, + get_assignment_bounty, + make_cvat_cloud_storage_params, + make_cvat_label_configuration, + strip_bucket_prefix, + unset, +) + + +@dataclass +class BoxesFromPointsConfig: + roi_file_ext: str = ".png" # supposed to be lossless and reasonably compressing + "File extension for RoI images, with leading dot (.) included" + + roi_size_mult: float = 1.1 + "Additional point ROI size multiplier" + + min_roi_size: tuple[int, int] = field( + default_factory=lambda: ( + Config.core_config.min_roi_size_w, + Config.core_config.min_roi_size_h, + ) + ) + "Minimum absolute ROI size, (w, h)" + + points_format: str = "coco_person_keypoints" + + embed_point_in_roi_image: bool = True + "Put a small point into the extracted RoI images for the original point" + + embedded_point_radius: int = 15 + min_embedded_point_radius_percent: float = 0.005 + max_embedded_point_radius_percent: float = 0.01 + embedded_point_color: tuple[int, int, int] = (0, 255, 255) + roi_background_color: tuple[int, int, int] = (245, 240, 242) # BGR - CVAT background color + + min_class_samples_for_roi_estimation: int = 25 + + max_class_roi_image_side_threshold: float = 0.5 + """ + The maximum allowed percent of the image for the estimated class RoI, + before the default RoI is used. Too big RoI estimations reduce the overall + prediction quality, making them unreliable. + """ + + max_discarded_threshold: float = 0.5 + """ + The maximum allowed percent of discarded + GT boxes, points, or samples for successful job launch + """ + + # TODO: consider adding an absolute number of minimum GT RoIs + + +class BoxesFromPointsTaskBuilder(TaskBuilderBase): + def __init__(self, manifest: JobManifest, escrow_address: str, chain_id: int) -> None: + super().__init__(manifest=manifest, escrow_address=escrow_address, chain_id=chain_id) + + self._input_gt_data: MaybeUnset[bytes] = unset + self._input_points_data: MaybeUnset[bytes] = unset + + self._data_filenames: MaybeUnset[Sequence[str]] = unset + self._input_gt_dataset: MaybeUnset[dm.Dataset] = unset + self._gt_dataset: MaybeUnset[dm.Dataset] = unset + self._gt_roi_dataset: MaybeUnset[dm.Dataset] = unset + self._points_dataset: MaybeUnset[dm.Dataset] = unset + + self._bbox_point_mapping: MaybeUnset[boxes_from_points_task.BboxPointMapping] = unset + "bbox_id -> point_id" + + self._roi_size_estimations: MaybeUnset[dict[int, tuple[float, float]]] = unset + "label_id -> (rel. w, rel. h)" + + self._rois: MaybeUnset[boxes_from_points_task.RoiInfos] = unset + self._roi_filenames: MaybeUnset[boxes_from_points_task.RoiFilenames] = unset + self._roi_filenames_to_be_annotated: MaybeUnset[Sequence[str]] = unset + self._gt_roi_filenames: MaybeUnset[Sequence[str]] = unset + + self._job_layout: MaybeUnset[Sequence[Sequence[str]]] = unset + "File lists per CVAT job" + + self._label_configuration: MaybeUnset[Sequence[dict]] = unset + + self._excluded_points_info: MaybeUnset[ExcludedAnnotationsInfo] = unset + self._excluded_gt_info: MaybeUnset[ExcludedAnnotationsInfo] = unset + + self.config = BoxesFromPointsConfig() + + def _download_input_data(self): + data_bucket = BucketAccessInfo.parse_obj(self.manifest.data.data_url) + gt_bucket = BucketAccessInfo.parse_obj(self.manifest.validation.gt_url) + points_bucket = BucketAccessInfo.parse_obj(self.manifest.data.points_url) + + data_storage_client = self._make_cloud_storage_client(data_bucket) + gt_storage_client = self._make_cloud_storage_client(gt_bucket) + points_storage_client = self._make_cloud_storage_client(points_bucket) + + data_filenames = data_storage_client.list_files(prefix=data_bucket.path) + data_filenames = strip_bucket_prefix(data_filenames, prefix=data_bucket.path) + self._data_filenames = filter_image_files(data_filenames) + + self._input_gt_data = gt_storage_client.download_file(gt_bucket.path) + self._input_gt_filename = Path(gt_bucket.path).name + + self._input_points_data = points_storage_client.download_file(points_bucket.path) + + def _parse_dataset(self, annotation_file_data: bytes, dataset_format: str) -> dm.Dataset: + temp_dir = self.exit_stack.enter_context(TemporaryDirectory()) + + annotation_filename = os.path.join(temp_dir, "annotations.json") + with open(annotation_filename, "wb") as f: + f.write(annotation_file_data) + + return dm.Dataset.import_from(annotation_filename, format=dataset_format) + + def _parse_gt(self): + assert self._input_gt_data is not unset + + self._input_gt_dataset = self._parse_dataset( + self._input_gt_data, + dataset_format=DM_GT_DATASET_FORMAT_MAPPING[self.manifest.annotation.type], + ) + + def _parse_points(self): + assert self._input_points_data is not unset + + self._points_dataset = self._parse_dataset( + self._input_points_data, dataset_format=self.config.points_format + ) + + def _validate_gt_labels(self): + gt_labels = set( + label.name + for label in self._input_gt_dataset.categories()[dm.AnnotationType.label] + if not label.parent + ) + manifest_labels = set(label.name for label in self.manifest.annotation.labels) + if gt_labels - manifest_labels: + raise DatasetValidationError( + "GT labels do not match job labels. Unknown labels: {}".format( + format_sequence(list(gt_labels - manifest_labels)), + ) + ) + + self._input_gt_dataset.transform( + ProjectLabels, dst_labels=[label.name for label in self.manifest.annotation.labels] + ) + self._input_gt_dataset.init_cache() + + def _validate_gt_filenames(self): + gt_filenames = set(s.id + s.media.ext for s in self._input_gt_dataset) + + known_data_filenames = set(self._data_filenames) + matched_gt_filenames = gt_filenames.intersection(known_data_filenames) + + if len(gt_filenames) != len(matched_gt_filenames): + extra_gt = list(map(os.path.basename, gt_filenames - matched_gt_filenames)) + + raise MismatchingAnnotations( + "Failed to find several validation samples in the dataset files: {}".format( + format_sequence(extra_gt) + ) + ) + + if len(gt_filenames) < self._job_val_frames_count: + raise TooFewSamples( + f"Too few validation samples provided ({len(gt_filenames)}), " + f"at least {self._job_val_frames_count} required." + ) + + def _validate_gt_annotations(self): + label_cat: dm.LabelCategories = self._input_gt_dataset.categories()[dm.AnnotationType.label] + + excluded_gt_info = ExcludedAnnotationsInfo() + excluded_samples = set() + visited_ids = set() + for gt_sample in self._input_gt_dataset: + # Could fail on this as well + img_h, img_w = gt_sample.media_as(dm.Image).size + + sample_boxes = [a for a in gt_sample.annotations if isinstance(a, dm.Bbox)] + valid_boxes = [] + for bbox in sample_boxes: + if not ( + (0 <= int(bbox.x) < int(bbox.x + bbox.w) <= img_w) + and (0 <= int(bbox.y) < int(bbox.y + bbox.h) <= img_h) + ): + excluded_gt_info.add_message( + "Sample '{}': GT bbox #{} ({}) - invalid coordinates".format( + gt_sample.id, bbox.id, label_cat[bbox.label].name + ), + sample_id=gt_sample.id, + sample_subset=gt_sample.subset, + ) + continue + + if bbox.id in visited_ids: + excluded_gt_info.add_message( + "Sample '{}': GT bbox #{} ({}) skipped - repeated annotation id {}".format( + gt_sample.id, bbox.id, label_cat[bbox.label].name, bbox.id + ), + sample_id=gt_sample.id, + sample_subset=gt_sample.subset, + ) + continue + + valid_boxes.append(bbox) + + excluded_gt_info.excluded_count += len(sample_boxes) - len(valid_boxes) + excluded_gt_info.total_count += len(sample_boxes) + + if len(valid_boxes) != len(sample_boxes): + if not valid_boxes: + excluded_samples.add((gt_sample.id, gt_sample.subset)) + else: + self._input_gt_dataset.put(gt_sample.wrap(annotations=valid_boxes)) + + for excluded_sample in excluded_samples: + self._input_gt_dataset.remove(*excluded_sample) + + if excluded_gt_info.excluded_count: + self.logger.warning( + "Some GT boxes were excluded due to the errors found: \n{}".format( + format_sequence([e.message for e in excluded_gt_info.messages], separator="\n") + ) + ) + + if excluded_gt_info.excluded_count > ceil( + excluded_gt_info.total_count * self.config.max_discarded_threshold + ): + raise TooFewSamples( + "Too many GT boxes discarded, canceling job creation. Errors: {}".format( + format_sequence( + [error_info.message for error_info in excluded_gt_info.messages] + ) + ) + ) + + self._excluded_gt_info = excluded_gt_info + + def _validate_gt(self): + assert self._data_filenames is not unset + assert self._input_gt_dataset is not unset + + self._validate_gt_filenames() + self._validate_gt_labels() + self._validate_gt_annotations() + + def _validate_points_categories(self): + invalid_point_categories_messages = [] + points_dataset_categories = self._points_dataset.categories() + points_dataset_label_cat: dm.LabelCategories = points_dataset_categories[ + dm.AnnotationType.label + ] + for category_id, category in points_dataset_categories[ + dm.AnnotationType.points + ].items.items(): + if len(category.labels) != 1: + invalid_point_categories_messages.append( + "Category '{}' (#{}): {}".format( + points_dataset_label_cat[category_id].name, + category_id, + f"too many skeleton points ({len(category.labels)}), only 1 expected", + ) + ) + + if invalid_point_categories_messages: + raise InvalidCategories( + "Invalid categories in the input point annotations: {}".format( + format_sequence(invalid_point_categories_messages, separator="; ") + ) + ) + + points_labels = set(label.name for label in points_dataset_label_cat if not label.parent) + manifest_labels = set(label.name for label in self.manifest.annotation.labels) + if manifest_labels != points_labels: + raise DatasetValidationError("Point labels do not match job labels") + + self._points_dataset.transform( + ProjectLabels, dst_labels=[label.name for label in self.manifest.annotation.labels] + ) + self._points_dataset.init_cache() + + def _validate_points_filenames(self): + points_filenames = set(sample.id + sample.media.ext for sample in self._points_dataset) + + known_data_filenames = set(self._data_filenames) + matched_points_filenames = points_filenames.intersection(known_data_filenames) + + if len(matched_points_filenames) != len(points_filenames): + extra_point_samples = list( + map(os.path.basename, points_filenames - matched_points_filenames) + ) + + raise MismatchingAnnotations( + "Failed to find several samples in the dataset files: {}".format( + format_sequence(extra_point_samples), + ) + ) + + def _validate_points_annotations(self): + def _validate_skeleton(skeleton: dm.Skeleton, *, sample_bbox: dm.Bbox): + if skeleton.id in visited_ids: + raise DatasetValidationError(f"repeated annotation id ({skeleton.id})") + + if len(skeleton.elements) != 1: + raise DatasetValidationError( + f"invalid points count ({len(skeleton.elements)}), expected 1" + ) + + point = skeleton.elements[0] + px, py = point.points[:2] + if not is_point_in_bbox(px, py, sample_bbox): + raise InvalidCoordinates("coordinates are outside image") + + label_cat: dm.LabelCategories = self._points_dataset.categories()[dm.AnnotationType.label] + + excluded_points_info = ExcludedAnnotationsInfo() + excluded_samples = set() + visited_ids = set() + for sample in self._points_dataset: + # Could fail on this as well + image_h, image_w = sample.image.size + sample_bbox = dm.Bbox(0, 0, w=image_w, h=image_h) + + sample_skeletons = [a for a in sample.annotations if isinstance(a, dm.Skeleton)] + valid_skeletons = [] + for skeleton in sample_skeletons: + # Here 1 skeleton describes 1 point + try: + _validate_skeleton(skeleton, sample_bbox=sample_bbox) + except InvalidCoordinates as error: + excluded_points_info.add_message( + "Sample '{}': point #{} ({}) skipped - {}".format( + sample.id, skeleton.id, label_cat[skeleton.label].name, error + ), + sample_id=sample.id, + sample_subset=sample.subset, + ) + continue + except DatasetValidationError as error: + excluded_points_info.add_message( + "Sample '{}': point #{} ({}) - {}".format( + sample.id, skeleton.id, label_cat[skeleton.label].name, error + ), + sample_id=sample.id, + sample_subset=sample.subset, + ) + continue + + valid_skeletons.append(skeleton) + + excluded_points_info.excluded_count += len(sample_skeletons) - len(valid_skeletons) + excluded_points_info.total_count += len(sample_skeletons) + + if len(valid_skeletons) != len(sample_skeletons): + if not valid_skeletons: + excluded_samples.add((sample.id, sample.subset)) + else: + self._points_dataset.put(sample.wrap(annotations=valid_skeletons)) + + for excluded_sample in excluded_samples: + self._points_dataset.remove(*excluded_sample) + + if excluded_points_info.excluded_count: + self.logger.warning( + "Some points were excluded due to the errors found: \n{}".format( + format_sequence( + [e.message for e in excluded_points_info.messages], separator="\n" + ) + ) + ) + + if excluded_points_info.excluded_count > ceil( + excluded_points_info.total_count * self.config.max_discarded_threshold + ): + raise TooFewSamples( + "Too many points discarded, canceling job creation. Errors: {}".format( + format_sequence( + [error_info.message for error_info in excluded_points_info.messages] + ) + ) + ) + + self._excluded_points_info = excluded_points_info + + def _validate_points(self): + assert self._data_filenames is not unset + assert self._points_dataset is not unset + + self._validate_points_categories() + self._validate_points_filenames() + self._validate_points_annotations() + + @staticmethod + def _is_point_in_bbox(px: float, py: float, bbox: dm.Bbox) -> bool: + return is_point_in_bbox(px, py, bbox) + + def _prepare_gt(self): + def _find_unambiguous_matches( + input_skeletons: list[dm.Skeleton], + gt_boxes: list[dm.Bbox], + ) -> list[tuple[dm.Skeleton, dm.Bbox]]: + matches = [ + [ + (input_skeleton.label == gt_bbox.label) + and ( + self._is_point_in_bbox( + *input_skeleton.elements[0].points[0:2], bbox=gt_bbox + ) + ) + for gt_bbox in gt_boxes + ] + for input_skeleton in input_skeletons + ] + + ambiguous_boxes: list[int] = set() + ambiguous_skeletons: list[int] = set() + for skeleton_idx, input_skeleton in enumerate(input_skeletons): + matched_boxes: list[dm.Bbox] = [ + gt_boxes[j] for j in range(len(gt_boxes)) if matches[skeleton_idx][j] + ] + + if len(matched_boxes) > 1: + # Handle ambiguous matches + excluded_points_info.add_message( + "Sample '{}': point #{} ({}) and overlapping boxes skipped - " + "too many matching boxes ({}) found".format( + points_sample.id, + input_skeleton.id, + points_label_cat[input_skeleton.label].name, + format_sequence([f"#{a.id}" for a in matched_boxes]), + ), + sample_id=points_sample.id, + sample_subset=points_sample.subset, + ) + # not an error, should not be counted as excluded for an error + ambiguous_skeletons.add(input_skeleton.id) + ambiguous_boxes.update(a.id for a in matched_boxes) + continue + + for gt_idx, gt_bbox in enumerate(gt_boxes): + matched_skeletons: list[dm.Skeleton] = [ + input_skeletons[i] for i in range(len(input_skeletons)) if matches[i][gt_idx] + ] + + if len(matched_skeletons) > 1: + # Handle ambiguous matches + excluded_gt_info.add_message( + "Sample '{}': GT bbox #{} ({}) and overlapping points skipped - " + "too many matching points ({}) found".format( + gt_sample.id, + gt_bbox.id, + gt_label_cat[gt_bbox.label].name, + format_sequence([f"#{a.id}" for a in matched_skeletons]), + ), + sample_id=gt_sample.id, + sample_subset=gt_sample.subset, + ) + # not an error, should not be counted as excluded for an error + ambiguous_boxes.add(gt_bbox.id) + ambiguous_skeletons.update(a.id for a in matched_skeletons) + continue + if not matched_skeletons: + # Handle unmatched skeletons + excluded_gt_info.add_message( + "Sample '{}': GT bbox #{} ({}) skipped - no matching points found".format( + gt_sample.id, + gt_bbox.id, + gt_label_cat[gt_bbox.label].name, + ), + sample_id=gt_sample.id, + sample_subset=gt_sample.subset, + ) + excluded_gt_info.excluded_count += 1 # an error + continue + + unambiguous_matches: list[tuple[dm.Bbox, dm.Skeleton]] = [] + for skeleton_idx, input_skeleton in enumerate(input_skeletons): + if input_skeleton.id in ambiguous_skeletons: + continue + + matched_bbox = None + for gt_idx, gt_bbox in enumerate(gt_boxes): + if gt_bbox.id in ambiguous_boxes: + continue + + if matches[skeleton_idx][gt_idx]: + matched_bbox = gt_bbox + break + + if matched_bbox: + unambiguous_matches.append((input_skeleton, matched_bbox)) + + return unambiguous_matches + + def _find_good_gt_boxes( + input_skeletons: list[dm.Skeleton], + gt_boxes: list[dm.Bbox], + ) -> list[dm.Bbox]: + matches = _find_unambiguous_matches(input_skeletons, gt_boxes) + + matched_boxes = [] + for input_skeleton, gt_bbox in matches: + gt_count_per_class[gt_bbox.label] = gt_count_per_class.get(gt_bbox.label, 0) + 1 + + matched_boxes.append(gt_bbox) + bbox_point_mapping[gt_bbox.id] = input_skeleton.id + + return matched_boxes + + assert self._data_filenames is not unset + assert self._points_dataset is not unset + assert self._input_gt_dataset is not unset + assert [ + label.name for label in self._input_gt_dataset.categories()[dm.AnnotationType.label] + ] == [label.name for label in self.manifest.annotation.labels] + assert [ + label.name + for label in self._points_dataset.categories()[dm.AnnotationType.label] + if not label.parent + ] == [label.name for label in self.manifest.annotation.labels] + + points_label_cat: dm.LabelCategories = self._points_dataset.categories()[ + dm.AnnotationType.label + ] + gt_label_cat: dm.LabelCategories = self._input_gt_dataset.categories()[ + dm.AnnotationType.label + ] + + updated_gt_dataset = dm.Dataset( + categories=self._input_gt_dataset.categories(), media_type=dm.Image + ) + + excluded_points_info = ExcludedAnnotationsInfo() # local for the function + excluded_gt_info = self._excluded_gt_info + gt_count_per_class = {} + bbox_point_mapping = {} # bbox id -> point id + for gt_sample in self._input_gt_dataset: + points_sample = self._points_dataset.get(gt_sample.id, gt_sample.subset) + assert points_sample + + gt_boxes = [a for a in gt_sample.annotations if isinstance(a, dm.Bbox)] + input_skeletons = [a for a in points_sample.annotations if isinstance(a, dm.Skeleton)] + + # Samples without boxes are allowed, so we just skip them without an error + if not gt_boxes: + continue + + matched_boxes = _find_good_gt_boxes(input_skeletons, gt_boxes) + if not matched_boxes: + continue + + updated_gt_dataset.put(gt_sample.wrap(annotations=matched_boxes)) + + if excluded_points_info.messages: + self.logger.warning( + "Some points were excluded from GT due to the problems found: \n{}".format( + format_sequence( + [e.message for e in excluded_points_info.messages], separator="\n" + ) + ) + ) + + if excluded_gt_info.messages: + self.logger.warning( + "Some GT annotations were excluded due to the problems found: \n{}".format( + format_sequence([e.message for e in excluded_gt_info.messages], separator="\n") + ) + ) + + if excluded_gt_info.excluded_count > ceil( + excluded_gt_info.total_count * self.config.max_discarded_threshold + ): + raise DatasetValidationError( + "Too many GT boxes discarded ({} out of {}). " + "Please make sure each GT box matches exactly 1 point".format( + excluded_gt_info.total_count - len(bbox_point_mapping), + excluded_gt_info.total_count, + ) + ) + + self.logger.info( + "GT counts per class to be used for validation: {}".format( + format_sequence( + [ + f"{gt_label_cat[label_id].name}: {count}" + for label_id, count in gt_count_per_class.items() + ] + ) + ) + ) + + gt_labels_without_anns = [ + gt_label_cat[label_id] + for label_id, label_count in gt_count_per_class.items() + if not label_count + ] + if gt_labels_without_anns: + raise DatasetValidationError( + "No matching GT boxes/points annotations found for some classes: {}".format( + format_sequence(gt_labels_without_anns) + ) + ) + + self._gt_dataset = updated_gt_dataset + self._bbox_point_mapping = bbox_point_mapping + + def _estimate_roi_sizes(self): + assert self._gt_dataset is not unset + assert [label.name for label in self._gt_dataset.categories()[dm.AnnotationType.label]] == [ + label.name for label in self.manifest.annotation.labels + ] + + bbox_sizes_per_label = {} + for sample in self._gt_dataset: + image_h, image_w = self._points_dataset.get(sample.id, sample.subset).image.size + + for gt_bbox in sample.annotations: + gt_bbox = cast("dm.Bbox", gt_bbox) + bbox_sizes_per_label.setdefault(gt_bbox.label, []).append( + ( + gt_bbox.w / image_w, + gt_bbox.h / image_h, + ) + ) + + # Consider bbox sides as normally-distributed random variables, estimate max + # For big enough datasets, it should be reasonable approximation + # (due to the central limit theorem). This can work bad for small datasets, + # so we only do this if there are enough class samples. + classes_with_default_roi: dict[int, str] = {} # label_id -> reason + roi_size_estimations_per_label = {} # label id -> (w, h) + default_roi_size = (2, 2) # 2 will yield just the image size after halving + for label_id, label_sizes in bbox_sizes_per_label.items(): + if len(label_sizes) < self.config.min_class_samples_for_roi_estimation: + estimated_size = default_roi_size + classes_with_default_roi[label_id] = "too few GT provided" + else: + max_bbox = np.max(label_sizes, axis=0) + if np.any(max_bbox > self.config.max_class_roi_image_side_threshold): + estimated_size = default_roi_size + classes_with_default_roi[label_id] = "estimated RoI is unreliable" + else: + estimated_size = 2 * max_bbox * self.config.roi_size_mult + + roi_size_estimations_per_label[label_id] = estimated_size + + if classes_with_default_roi: + label_cat = self._gt_dataset.categories()[dm.AnnotationType.label] + labels_by_reason = { + g_reason: [v[0] for v in g_items] + for g_reason, g_items in groupby( + sorted(classes_with_default_roi.items(), key=lambda v: v[1]), key=lambda v: v[1] + ) + } + self.logger.warning( + "Some classes will use the full image instead of RoI - {}".format( + "; ".join( + "{}: {}".format( + g_reason, + format_sequence([label_cat[label_id].name for label_id in g_labels]), + ) + for g_reason, g_labels in labels_by_reason.items() + ) + ) + ) + + self._roi_size_estimations = roi_size_estimations_per_label + + def _prepare_roi_info(self): + assert self._gt_dataset is not unset + assert self._roi_size_estimations is not unset + assert self._points_dataset is not unset + + rois: list[boxes_from_points_task.RoiInfo] = [] + for sample in self._points_dataset: + for skeleton in sample.annotations: + if not isinstance(skeleton, dm.Skeleton): + continue + + point_label_id = skeleton.label + original_point_x, original_point_y = skeleton.elements[0].points[:2] + original_point_x = int(original_point_x) + original_point_y = int(original_point_y) + + image_h, image_w = sample.image.size + + roi_est_w, roi_est_h = self._roi_size_estimations[point_label_id] + roi_est_w *= image_w + roi_est_h *= image_h + roi_est_w = max(roi_est_w, self.config.min_roi_size[0]) + roi_est_h = max(roi_est_h, self.config.min_roi_size[1]) + + roi_left = max(0, original_point_x - int(roi_est_w / 2)) + roi_top = max(0, original_point_y - int(roi_est_h / 2)) + roi_right = min(image_w, original_point_x + ceil(roi_est_w / 2)) + roi_bottom = min(image_h, original_point_y + ceil(roi_est_h / 2)) + + roi_w = roi_right - roi_left + roi_h = roi_bottom - roi_top + + new_point_x = original_point_x - roi_left + new_point_y = original_point_y - roi_top + + rois.append( + boxes_from_points_task.RoiInfo( + point_id=skeleton.id, + original_image_key=sample.attributes["id"], + point_x=new_point_x, + point_y=new_point_y, + roi_x=roi_left, + roi_y=roi_top, + roi_w=roi_w, + roi_h=roi_h, + ) + ) + + self._rois = rois + + def _mangle_filenames(self): + """ + Mangle filenames in the dataset to make them less recognizable by annotators + and hide private dataset info + """ + assert self._rois is not unset + + # TODO: maybe add different names for the same GT images in + # different jobs to make them even less recognizable + self._roi_filenames = { + roi.point_id: str(uuid.uuid4()) + self.config.roi_file_ext for roi in self._rois + } + + def _prepare_job_layout(self): + assert self._rois is not unset + assert self._bbox_point_mapping is not unset + assert self._input_gt_dataset is not unset + + # This list can be different from what is selected for validation + input_gt_filenames = set(sample.media.path for sample in self._input_gt_dataset) + original_image_id_to_filename = { + sample.attributes["id"]: sample.media.path for sample in self._points_dataset + } + point_id_to_original_image_id = {roi.point_id: roi.original_image_key for roi in self._rois} + + gt_point_ids = set(self._bbox_point_mapping.values()) + self._gt_roi_filenames = [self._roi_filenames[point_id] for point_id in gt_point_ids] + self._roi_filenames_to_be_annotated = [ + fn + for point_id, fn in self._roi_filenames.items() + if point_id not in gt_point_ids + if original_image_id_to_filename[point_id_to_original_image_id[point_id]] + not in input_gt_filenames + ] + + def _prepare_label_configuration(self): + self._label_configuration = make_cvat_label_configuration(self.manifest) + + def _upload_task_meta(self): + layout = boxes_from_points_task.TaskMetaLayout() + serializer = boxes_from_points_task.TaskMetaSerializer() + + file_list = [] + file_list.append((self._input_points_data, layout.POINTS_FILENAME)) + file_list.append( + ( + serializer.serialize_gt_annotations(self._gt_dataset), + layout.GT_FILENAME, + ) + ) + file_list.append( + ( + serializer.serialize_bbox_point_mapping(self._bbox_point_mapping), + layout.BBOX_POINT_MAPPING_FILENAME, + ) + ) + file_list.append((serializer.serialize_roi_info(self._rois), layout.ROI_INFO_FILENAME)) + file_list.append( + (serializer.serialize_roi_filenames(self._roi_filenames), layout.ROI_FILENAMES_FILENAME) + ) + + storage_client = self._make_cloud_storage_client(self._oracle_data_bucket) + for file_data, filename in file_list: + storage_client.create_file( + compose_data_bucket_filename(self.escrow_address, self.chain_id, filename), + file_data, + ) + + def _extract_roi( + self, source_pixels: np.ndarray, roi_info: boxes_from_points_task.RoiInfo + ) -> np.ndarray: + img_h, img_w, *_ = source_pixels.shape + + roi_pixels = source_pixels[ + max(0, roi_info.roi_y) : min(img_h, roi_info.roi_y + roi_info.roi_h), + max(0, roi_info.roi_x) : min(img_w, roi_info.roi_x + roi_info.roi_w), + ] + + if not ( + (0 <= roi_info.roi_x < roi_info.roi_x + roi_info.roi_w < img_w) + and (0 <= roi_info.roi_y < roi_info.roi_y + roi_info.roi_h < img_h) + ): + # Coords can be outside the original image + # In this case a border should be added to RoI, so that the image was centered on bbox + wrapped_roi_pixels = np.zeros((roi_info.roi_h, roi_info.roi_w, 3), dtype=np.float32) + wrapped_roi_pixels[:, :] = self.config.roi_background_color + + dst_y = max(-roi_info.roi_y, 0) + dst_x = max(-roi_info.roi_x, 0) + wrapped_roi_pixels[ + dst_y : dst_y + roi_pixels.shape[0], + dst_x : dst_x + roi_pixels.shape[1], + ] = roi_pixels + + roi_pixels = wrapped_roi_pixels + else: + roi_pixels = roi_pixels.copy() + + return roi_pixels + + def _draw_roi_point( + self, roi_pixels: np.ndarray, roi_info: boxes_from_points_task.RoiInfo + ) -> np.ndarray: + center = (roi_info.point_x, roi_info.point_y) + + roi_r = (roi_info.roi_w**2 + roi_info.roi_h**2) ** 0.5 / 2 + point_size = int( + min( + self.config.max_embedded_point_radius_percent * roi_r, + max( + self.config.embedded_point_radius, + self.config.min_embedded_point_radius_percent * roi_r, + ), + ) + ) + + roi_pixels = roi_pixels.copy() + roi_pixels = cv2.circle( + roi_pixels, + center, + point_size + 1, + (255, 255, 255), + cv2.FILLED, + ) + return cv2.circle( + roi_pixels, + center, + point_size, + self.config.embedded_point_color, + cv2.FILLED, + ) + + def _extract_and_upload_rois(self): + assert self._points_dataset is not unset + assert self._rois is not unset + assert self._data_filenames is not unset + assert self._roi_filenames is not unset + + src_bucket = BucketAccessInfo.parse_obj(self.manifest.data.data_url) + src_prefix = src_bucket.path + dst_bucket = self._oracle_data_bucket + + src_client = self._make_cloud_storage_client(src_bucket) + dst_client = self._make_cloud_storage_client(dst_bucket) + + image_id_to_filename = { + sample.attributes["id"]: sample.image.path for sample in self._points_dataset + } + + filename_to_sample = {sample.image.path: sample for sample in self._points_dataset} + + def _roi_key(e): + return e.original_image_key + + rois_by_image: dict[str, Sequence[boxes_from_points_task.RoiInfo]] = { + image_id_to_filename[image_id]: list(g) + for image_id, g in groupby(sorted(self._rois, key=_roi_key), key=_roi_key) + } + + def process_file(filename: str, image_pixels: np.ndarray): + image_roi_infos = rois_by_image.get(filename, []) + if not image_roi_infos: + return + + sample = filename_to_sample[filename] + if tuple(sample.image.size) != tuple(image_pixels.shape[:2]): + # TODO: maybe rois should be regenerated instead + # Option 2: accumulate errors, fail when some threshold is reached + # Option 3: add special handling for cases when image is only rotated (exif etc.) + raise InvalidImageInfo( + f"Sample '{filename}': invalid size provided in the point annotations" + ) + + image_rois = {} + for roi_info in image_roi_infos: + roi_pixels = self._extract_roi(image_pixels, roi_info) + + if self.config.embed_point_in_roi_image: + roi_pixels = self._draw_roi_point(roi_pixels, roi_info) + + roi_filename = self._roi_filenames[roi_info.point_id] + roi_bytes = encode_image(roi_pixels, os.path.splitext(roi_filename)[-1]) + + image_rois[roi_filename] = roi_bytes + + for roi_filename, roi_bytes in image_rois.items(): + dst_client.create_file( + compose_data_bucket_filename(self.escrow_address, self.chain_id, roi_filename), + roi_bytes, + ) + + def download_and_decode(key: str): + image_bytes = src_client.download_file(key) + return decode_image(image_bytes) + + pool_size = Config.features.max_data_storage_connections + download_queue_size = 4 * pool_size + download_queue = Queue[tuple[str, Future[np.ndarray]]](download_queue_size) + roi_uploader = BufferedRoiImageUploader(queue=download_queue) + with ThreadPoolExecutor(pool_size) as pool: + + def put_callback(filename: str): + image_roi_infos = rois_by_image.get(filename, []) + if not image_roi_infos: + return None + + return ( + filename, + pool.submit(download_and_decode, os.path.join(src_prefix, filename)), + ) + + def process_callback(result: tuple[str, Future]): + filename, task = result + process_file(filename, task.result()) + + roi_uploader.process_all( + self._data_filenames, put_callback=put_callback, process_callback=process_callback + ) + + def _prepare_gt_roi_dataset(self): + self._gt_roi_dataset = dm.Dataset( + categories=self._gt_dataset.categories(), media_type=dm.Image + ) + + roi_info_by_point_id: dict[int, skeletons_from_boxes_task.RoiInfo] = { + roi_info.point_id: roi_info for roi_info in self._rois + } + + for sample in self._gt_dataset: + for gt_bbox in sample.annotations: + assert isinstance(gt_bbox, dm.Bbox) + + point_id = self._bbox_point_mapping[gt_bbox.id] + gt_roi_filename = compose_data_bucket_filename( + self.escrow_address, self.chain_id, self._roi_filenames[point_id] + ) + + # update gt bbox coordinates to match RoI shift + roi_info = roi_info_by_point_id[point_id] + new_x = gt_bbox.points[0] - roi_info.roi_x + new_y = gt_bbox.points[1] - roi_info.roi_y + + self._gt_roi_dataset.put( + sample.wrap( + id=os.path.splitext(gt_roi_filename)[0], + annotations=[gt_bbox.wrap(x=new_x, y=new_y)], + media=dm.Image(path=gt_roi_filename, size=sample.media_as(dm.Image).size), + attributes=filter_dict(sample.attributes, exclude_keys=["id"]), + ) + ) + + assert len(self._gt_roi_dataset) == len(self._gt_roi_filenames) + + def _create_on_cvat(self): + assert self._roi_filenames_to_be_annotated is not unset + assert self._gt_roi_filenames is not unset + assert self._label_configuration is not unset + assert self._gt_roi_dataset is not unset + + oracle_bucket = self._oracle_data_bucket + + # Register cloud storage on CVAT to pass user dataset + cvat_cloud_storage = cvat_api.create_cloudstorage( + **make_cvat_cloud_storage_params(oracle_bucket) + ) + + # Create a project + cvat_project = cvat_api.create_project( + self.escrow_address, + labels=self._label_configuration, + user_guide=self.manifest.annotation.user_guide, + ) + + # Setup webhooks for the project + cvat_webhook = cvat_api.create_cvat_webhook(cvat_project.id) + + with SessionLocal.begin() as session: + segment_size = self._task_segment_size + total_jobs = math.ceil(len(self._roi_filenames_to_be_annotated) / segment_size) + self.logger.info( + "Task creation for escrow '%s': will create %s assignments", + self.escrow_address, + total_jobs, + ) + db_service.create_escrow_creation( + session, + escrow_address=self.escrow_address, + chain_id=self.chain_id, + total_jobs=total_jobs, + ) + + project_id = db_service.create_project( + session, + cvat_project.id, + cvat_cloudstorage_id=cvat_cloud_storage.id, + job_type=self.manifest.annotation.type, + escrow_address=self.escrow_address, + chain_id=self.chain_id, + bucket_url=oracle_bucket.to_url().rstrip("/") + + "/" + + compose_data_bucket_prefix(self.escrow_address, self.chain_id), + cvat_webhook_id=cvat_webhook.id, + assignment_bounty=get_assignment_bounty( + self.manifest, + escrow_address=self.escrow_address, + chain_id=self.chain_id, + job_count=total_jobs, + ), + ) + db_service.get_project_by_id(session, project_id, for_update=True) # lock the row + db_service.add_project_images( + session, + cvat_project.id, + [ + compose_data_bucket_filename(self.escrow_address, self.chain_id, fn) + for fn in self._roi_filenames.values() + ], + ) + + for data_subset in self._split_dataset_per_task( + self._roi_filenames_to_be_annotated, + subset_size=Config.cvat_config.max_jobs_per_task * segment_size, + ): + cvat_task = cvat_api.create_task( + cvat_project.id, self.escrow_address, segment_size=segment_size + ) + + task_id = db_service.create_task( + session, cvat_task.id, cvat_project.id, TaskStatuses[cvat_task.status] + ) + db_service.get_task_by_id(session, task_id, for_update=True) # lock the row + + filenames = [ + compose_data_bucket_filename(self.escrow_address, self.chain_id, fn) + for fn in data_subset + ] + gt_filenames = [ + compose_data_bucket_filename(self.escrow_address, self.chain_id, fn) + for fn in self._gt_roi_filenames + ] + + cvat_api.put_task_data( + cvat_task.id, + cvat_cloud_storage.id, + filenames=filenames, + validation_params={ + "gt_filenames": gt_filenames, + "gt_frames_per_job_count": self._job_val_frames_count, + }, + ) + + self._setup_gt_job_for_cvat_task( + cvat_task.id, self._gt_roi_dataset, dm_export_format="coco" + ) + self._setup_quality_settings(cvat_task.id) + + db_service.create_data_upload(session, cvat_task.id) + + db_service.touch(session, Project, [project_id]) + + def build(self): + self._download_input_data() + self._parse_gt() + self._parse_points() + self._validate_gt() + self._validate_points() + + # Task configuration creation + self._prepare_gt() + self._estimate_roi_sizes() + self._prepare_roi_info() + self._mangle_filenames() + self._prepare_label_configuration() + self._prepare_job_layout() + self._prepare_gt_roi_dataset() + + # Data preparation + self._extract_and_upload_rois() + self._upload_task_meta() + + self._create_on_cvat() diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/vision/skeletons_from_boxes.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/vision/skeletons_from_boxes.py new file mode 100644 index 0000000000..ce9a86fdcf --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/builders/vision/skeletons_from_boxes.py @@ -0,0 +1,1418 @@ +from __future__ import annotations + +import math +import os +import random +import uuid +from concurrent.futures import Future, ThreadPoolExecutor +from dataclasses import dataclass, field +from itertools import chain, groupby +from math import ceil +from queue import Queue +from tempfile import TemporaryDirectory +from typing import TYPE_CHECKING + +import cv2 +import datumaro as dm +import numpy as np +from datumaro.util import take_by +from datumaro.util.annotation_util import BboxCoords, bbox_iou, find_instances +from datumaro.util.image import decode_image, encode_image + +import src.core.tasks.skeletons_from_boxes as skeletons_from_boxes_task +import src.cvat.api_calls as cvat_api +import src.services.cvat as db_service +from src.core.config import Config +from src.core.storage import compose_data_bucket_filename, compose_data_bucket_prefix +from src.core.types import TaskStatuses +from src.db import SessionLocal +from src.models.cvat import Project +from src.services.cloud.utils import BucketAccessInfo +from src.utils.annotations import InstanceSegmentsToBbox, ProjectLabels, is_point_in_bbox +from src.utils.logging import format_sequence +from src.utils.roi_uploader import BufferedRoiImageUploader + +if TYPE_CHECKING: + from collections.abc import Sequence + from pathlib import Path + + from src.core.manifest.v1 import JobManifest + +from src.core.tasks.cvat_formats import DM_GT_DATASET_FORMAT_MAPPING +from src.handlers.job_creation.builders.vision.base import TaskBuilderBase +from src.handlers.job_creation.exceptions import ( + DatasetValidationError, + ExcludedAnnotationsInfo, + InvalidCoordinates, + InvalidImageInfo, + MismatchingAnnotations, + TooFewSamples, +) +from src.handlers.job_creation.utils import ( + MaybeUnset, + filter_image_files, + get_assignment_bounty, + make_cvat_cloud_storage_params, + strip_bucket_prefix, + unset, +) + + +@dataclass +class _TaskParams: + label_id: int + roi_ids: list[int] + roi_gt_ids: list[int] + + +@dataclass +class SkeletonsFromBoxesConfig: + job_size_mult: int = skeletons_from_boxes_task.DEFAULT_ASSIGNMENT_SIZE_MULTIPLIER + "Job size multiplier" + + roi_file_ext: str = ".png" # supposed to be lossless and reasonably compressing + "File extension for RoI images, with leading dot (.) included" + + roi_size_mult: float = 1.1 + "Additional point ROI size multiplier" + + min_roi_size: tuple[int, int] = field( + default_factory=lambda: ( + Config.core_config.min_roi_size_w, + Config.core_config.min_roi_size_h, + ) + ) + "Minimum absolute ROI size, (w, h)" + + boxes_format: str = "coco_person_keypoints" + + embed_bbox_in_roi_image: bool = True + "Put a bbox into the extracted skeleton RoI images" + + embed_tile_border: bool = True + + embedded_point_radius: int = 15 + min_embedded_point_radius_percent: float = 0.005 + max_embedded_point_radius_percent: float = 0.01 + embedded_point_color: tuple[int, int, int] = (0, 255, 255) + + roi_embedded_bbox_color: tuple[int, int, int] = (0, 255, 255) # BGR + roi_background_color: tuple[int, int, int] = (245, 240, 242) # BGR - CVAT background color + + min_label_gt_samples: int = 2 # TODO: find good threshold + + max_discarded_threshold: float = 0.5 + """ + The maximum allowed percent of discarded + GT annotations or samples for successful job launch + """ + + gt_id_attribute: str = "object_id" + "An additional way to match GT skeletons with input boxes" + + # TODO: consider adding an absolute number of minimum GT RoIs + + +class SkeletonsFromBoxesTaskBuilder(TaskBuilderBase): + def __init__(self, manifest: JobManifest, escrow_address: str, chain_id: int) -> None: + super().__init__(manifest=manifest, escrow_address=escrow_address, chain_id=chain_id) + + self._input_gt_data: MaybeUnset[bytes] = unset + self._input_boxes_data: MaybeUnset[bytes] = unset + + self._data_filenames: MaybeUnset[Sequence[str]] = unset + self._input_gt_dataset: MaybeUnset[dm.Dataset] = unset + self._gt_dataset: MaybeUnset[dm.Dataset] = unset + self._boxes_dataset: MaybeUnset[dm.Dataset] = unset + + self._skeleton_bbox_mapping: MaybeUnset[skeletons_from_boxes_task.SkeletonBboxMapping] = ( + unset + ) + self._roi_infos: MaybeUnset[skeletons_from_boxes_task.RoiInfos] = unset + self._roi_info_by_id: MaybeUnset[dict[int, skeletons_from_boxes_task.RoiInfo]] = unset + + self._gt_points_per_label: MaybeUnset[ + dict[tuple[int, str], Sequence[tuple[int, dm.Points]]] + ] = unset + "(skeleton_label_id, point_label_name) to [(skeleton_id, point), ...]" + + self._roi_filenames: MaybeUnset[dict[int, str]] = unset + + self._task_params: MaybeUnset[list[_TaskParams]] = unset + + self._excluded_gt_info: MaybeUnset[ExcludedAnnotationsInfo] = unset + self._excluded_boxes_info: MaybeUnset[ExcludedAnnotationsInfo] = unset + + self.config = SkeletonsFromBoxesConfig() + + def _download_input_data(self): + data_bucket = BucketAccessInfo.parse_obj(self.manifest.data.data_url) + gt_bucket = BucketAccessInfo.parse_obj(self.manifest.validation.gt_url) + boxes_bucket = BucketAccessInfo.parse_obj(self.manifest.data.boxes_url) + + data_storage_client = self._make_cloud_storage_client(data_bucket) + gt_storage_client = self._make_cloud_storage_client(gt_bucket) + boxes_storage_client = self._make_cloud_storage_client(boxes_bucket) + + data_filenames = data_storage_client.list_files(prefix=data_bucket.path) + data_filenames = strip_bucket_prefix(data_filenames, prefix=data_bucket.path) + self._data_filenames = filter_image_files(data_filenames) + + self._input_gt_data = gt_storage_client.download_file(gt_bucket.path) + + self._input_boxes_data = boxes_storage_client.download_file(boxes_bucket.path) + + def _parse_dataset(self, annotation_file_data: bytes, dataset_format: str) -> dm.Dataset: + temp_dir = self.exit_stack.enter_context(TemporaryDirectory()) + + annotation_filename = os.path.join(temp_dir, "annotations.json") + with open(annotation_filename, "wb") as f: + f.write(annotation_file_data) + + return dm.Dataset.import_from(annotation_filename, format=dataset_format) + + def _parse_gt(self): + assert self._input_gt_data is not unset + + self._input_gt_dataset = self._parse_dataset( + self._input_gt_data, + dataset_format=DM_GT_DATASET_FORMAT_MAPPING[self.manifest.annotation.type], + ) + + def _parse_boxes(self): + assert self._input_boxes_data is not unset + + self._boxes_dataset = self._parse_dataset( + self._input_boxes_data, dataset_format=self.config.boxes_format + ) + + def _validate_gt_labels(self): + gt_labels = set( + (label.name, label.parent) + for label in self._input_gt_dataset.categories()[dm.AnnotationType.label] + ) + + manifest_labels = set() + for skeleton_label in self.manifest.annotation.labels: + manifest_labels.add((skeleton_label.name, "")) + for node_label in skeleton_label.nodes: + manifest_labels.add((node_label, skeleton_label.name)) + + if manifest_labels - gt_labels: + raise DatasetValidationError( + "Could not find GT for labels {}".format( + format_sequence( + [ + label_name if not parent_name else f"{parent_name}.{label_name}" + for label_name, parent_name in manifest_labels - gt_labels + ] + ), + ) + ) + + # It should not be an issue that there are some extra GT labels - they should + # just be skipped. + if gt_labels - manifest_labels: + self.logger.info( + "Skipping unknown GT labels: {}".format( + format_sequence( + [ + label_name if not parent_name else f"{parent_name}.{label_name}" + for label_name, parent_name in gt_labels - manifest_labels + ] + ) + ) + ) + + # Reorder and filter labels to match the manifest + self._input_gt_dataset.transform( + ProjectLabels, dst_labels=[label.name for label in self.manifest.annotation.labels] + ) + self._input_gt_dataset.init_cache() + + def _validate_gt_filenames(self): + gt_filenames = set(s.id + s.media.ext for s in self._input_gt_dataset) + + known_data_filenames = set(self._data_filenames) + matched_gt_filenames = gt_filenames.intersection(known_data_filenames) + + if len(gt_filenames) != len(matched_gt_filenames): + extra_gt = list(map(os.path.basename, gt_filenames - matched_gt_filenames)) + + raise MismatchingAnnotations( + "Failed to find several validation samples in the dataset files: {}".format( + format_sequence(extra_gt) + ) + ) + + if len(gt_filenames) < self._job_val_frames_count: + raise TooFewSamples( + f"Too few validation samples provided ({len(gt_filenames)}), " + f"at least {self._job_val_frames_count} required." + ) + + def _validate_gt_annotations(self): + def _validate_skeleton(skeleton: dm.Skeleton, *, sample_bbox: dm.Bbox): + if skeleton.id in visited_ids: + raise DatasetValidationError(f"repeated annotation id {skeleton.id}") + + for element in skeleton.elements: + # This is what Datumaro is expected to parse + assert len(element.points) == 2 + assert len(element.visibility) == 1 + + if element.visibility[0] == dm.Points.Visibility.absent: + continue + + px, py = element.points[:2] + if not is_point_in_bbox(int(px), int(py), sample_bbox): + raise InvalidCoordinates("skeleton point is outside the image") + + label_cat: dm.LabelCategories = self._input_gt_dataset.categories()[dm.AnnotationType.label] + + excluded_gt_info = ExcludedAnnotationsInfo() + excluded_samples = set() + visited_ids = set() + for gt_sample in self._input_gt_dataset: + # Could fail on this as well + img_h, img_w = gt_sample.media_as(dm.Image).size + sample_bbox = dm.Bbox(0, 0, w=img_w, h=img_h) + + sample_skeletons = [a for a in gt_sample.annotations if isinstance(a, dm.Skeleton)] + valid_skeletons = [] + for skeleton in sample_skeletons: + try: + _validate_skeleton(skeleton, sample_bbox=sample_bbox) + except DatasetValidationError as error: + excluded_gt_info.add_message( + "Sample '{}': GT skeleton #{} ({}) skipped - {}".format( + gt_sample.id, skeleton.id, label_cat[skeleton.label].name, error + ), + sample_id=gt_sample.id, + sample_subset=gt_sample.subset, + ) + continue + + valid_skeletons.append(skeleton) + visited_ids.add(skeleton.id) + + excluded_gt_info.excluded_count += len(sample_skeletons) - len(valid_skeletons) + excluded_gt_info.total_count += len(sample_skeletons) + + if len(valid_skeletons) != len(sample_skeletons): + if not valid_skeletons: + excluded_samples.add((gt_sample.id, gt_sample.subset)) + else: + # Skeleton boxes can be in the list as well with the same ids / groups + skeleton_ids = set(a.id for a in valid_skeletons) - {0} + self._input_gt_dataset.put( + gt_sample.wrap( + annotations=[a for a in gt_sample.annotations if a.id in skeleton_ids] + ) + ) + + for excluded_sample in excluded_samples: + self._input_gt_dataset.remove(*excluded_sample) + + if excluded_gt_info.excluded_count: + self.logger.warning( + "Some GT skeletons were excluded due to the errors found: {}".format( + format_sequence([e.message for e in excluded_gt_info.messages], separator="\n") + ) + ) + + if excluded_gt_info.excluded_count > ceil( + excluded_gt_info.total_count * self.config.max_discarded_threshold + ): + raise TooFewSamples( + "Too many GT skeletons discarded, canceling job creation. Errors: {}".format( + format_sequence( + [error_info.message for error_info in excluded_gt_info.messages] + ) + ) + ) + + self._excluded_gt_info = excluded_gt_info + + def _validate_gt(self): + assert self._data_filenames is not unset + assert self._input_gt_dataset is not unset + + self._validate_gt_filenames() + self._validate_gt_labels() + self._validate_gt_annotations() + + def _validate_boxes_categories(self): + boxes_dataset_categories = self._boxes_dataset.categories() + boxes_dataset_label_cat: dm.LabelCategories = boxes_dataset_categories[ + dm.AnnotationType.label + ] + + boxes_labels = set(label.name for label in boxes_dataset_label_cat if not label.parent) + manifest_labels = set(label.name for label in self.manifest.annotation.labels) + if manifest_labels != boxes_labels: + raise DatasetValidationError("Bbox labels do not match job labels") + + # Reorder labels to match the manifest + self._boxes_dataset.transform( + ProjectLabels, dst_labels=[label.name for label in self.manifest.annotation.labels] + ) + self._boxes_dataset.init_cache() + + def _validate_boxes_filenames(self): + boxes_filenames = set(sample.id + sample.media.ext for sample in self._boxes_dataset) + + known_data_filenames = set(self._data_filenames) + matched_boxes_filenames = boxes_filenames.intersection(known_data_filenames) + + if len(matched_boxes_filenames) != len(boxes_filenames): + extra_bbox_samples = list( + map(os.path.basename, boxes_filenames - matched_boxes_filenames) + ) + + raise MismatchingAnnotations( + "Failed to find several samples in the dataset files: {}".format( + format_sequence(extra_bbox_samples), + ) + ) + + def _validate_boxes_annotations(self): # noqa: PLR0912 + # Convert possible polygons and masks into boxes + self._boxes_dataset.transform(InstanceSegmentsToBbox) + self._boxes_dataset.init_cache() + + excluded_boxes_info = ExcludedAnnotationsInfo() + + label_cat: dm.LabelCategories = self._boxes_dataset.categories()[dm.AnnotationType.label] + + visited_ids = set() + for sample in self._boxes_dataset: + # Could fail on this as well + image_h, image_w = sample.media_as(dm.Image).size + + valid_instances: list[tuple[dm.Bbox, dm.Points]] = [] + instances = find_instances( + [a for a in sample.annotations if isinstance(a, dm.Bbox | dm.Skeleton)] + ) + for instance_anns in instances: + if len(instance_anns) != 2: + excluded_boxes_info.add_message( + "Sample '{}': object #{} ({}) skipped - unexpected group size ({})".format( + sample.id, + instance_anns[0].id, + label_cat[instance_anns[0].label].name, + len(instance_anns), + ), + sample_id=sample.id, + sample_subset=sample.subset, + ) + continue + + bbox = next((a for a in instance_anns if isinstance(a, dm.Bbox)), None) + if not bbox: + excluded_boxes_info.add_message( + "Sample '{}': object #{} ({}) skipped - no matching bbox".format( + sample.id, instance_anns[0].id, label_cat[instance_anns[0].label].name + ), + sample_id=sample.id, + sample_subset=sample.subset, + ) + continue + + skeleton = next((a for a in instance_anns if isinstance(a, dm.Skeleton)), None) + if not skeleton: + excluded_boxes_info.add_message( + "Sample '{}': object #{} ({}) skipped - no matching skeleton".format( + sample.id, instance_anns[0].id, label_cat[instance_anns[0].label].name + ), + sample_id=sample.id, + sample_subset=sample.subset, + ) + continue + + if len(skeleton.elements) != 1 or len(skeleton.elements[0].points) != 2: + excluded_boxes_info.add_message( + "Sample '{}': object #{} ({}) skipped - invalid skeleton points".format( + sample.id, skeleton.id, label_cat[skeleton.label].name + ), + sample_id=sample.id, + sample_subset=sample.subset, + ) + continue + + point = skeleton.elements[0] + if not is_point_in_bbox(point.points[0], point.points[1], (0, 0, image_w, image_h)): + excluded_boxes_info.add_message( + "Sample '{}': object #{} ({}) skipped - invalid point coordinates".format( + sample.id, skeleton.id, label_cat[skeleton.label].name + ), + sample_id=sample.id, + sample_subset=sample.subset, + ) + continue + + if not is_point_in_bbox(int(bbox.x), int(bbox.y), (0, 0, image_w, image_h)): + excluded_boxes_info.add_message( + "Sample '{}': object #{} ({}) skipped - invalid bbox coordinates".format( + sample.id, bbox.id, label_cat[bbox.label].name + ), + sample_id=sample.id, + sample_subset=sample.subset, + ) + continue + + if not is_point_in_bbox(point.points[0], point.points[1], bbox): + excluded_boxes_info.add_message( + "Sample '{}': object #{} ({}) skipped - point is outside the bbox".format( + sample.id, skeleton.id, label_cat[skeleton.label].name + ), + sample_id=sample.id, + sample_subset=sample.subset, + ) + continue + + if bbox.id in visited_ids: + excluded_boxes_info.add_message( + "Sample '{}': bbox #{} ({}) skipped - repeated annotation id {}".format( + sample.id, bbox.id, label_cat[bbox.label].name, bbox.id + ), + sample_id=sample.id, + sample_subset=sample.subset, + ) + continue + + valid_instances.append( + (bbox, point.wrap(group=bbox.group, id=bbox.id, attributes=bbox.attributes)) + ) + visited_ids.add(bbox.id) + + excluded_boxes_info.excluded_count += len(instances) - len(valid_instances) + excluded_boxes_info.total_count += len(instances) + + if len(valid_instances) != len(sample.annotations): + self._boxes_dataset.put( + sample.wrap(annotations=list(chain.from_iterable(valid_instances))) + ) + + if excluded_boxes_info.excluded_count > ceil( + excluded_boxes_info.total_count * self.config.max_discarded_threshold + ): + raise TooFewSamples( + "Too many boxes discarded, canceling job creation. Errors: {}".format( + format_sequence( + [error_info.message for error_info in excluded_boxes_info.messages] + ) + ) + ) + + excluded_samples = set((e.sample_id, e.sample_subset) for e in excluded_boxes_info.messages) + for excluded_sample in excluded_samples: + self._boxes_dataset.remove(*excluded_sample) + + if excluded_samples: + self.logger.warning( + "Some boxes were excluded due to the errors found: {}".format( + format_sequence( + [e.message for e in excluded_boxes_info.messages], separator="\n" + ) + ) + ) + + self._excluded_boxes_info = excluded_boxes_info + + def _validate_boxes(self): + assert self._data_filenames is not unset + assert self._boxes_dataset is not unset + + self._validate_boxes_categories() + self._validate_boxes_filenames() + self._validate_boxes_annotations() + + def _match_boxes(self, a: BboxCoords, b: BboxCoords) -> bool: + return bbox_iou(a, b) > 0 + + def _get_skeleton_bbox( + self, skeleton: dm.Skeleton, annotations: Sequence[dm.Annotation] + ) -> BboxCoords: + matching_bbox = None + if skeleton.group: + matching_bbox = next( + ( + bbox + for bbox in annotations + if isinstance(bbox, dm.Bbox) and bbox.group == skeleton.group + ), + None, + ) + + if matching_bbox: + bbox = matching_bbox.get_bbox() + else: + bbox = skeleton.get_bbox() + + if any( + v != dm.Points.Visibility.absent for e in skeleton.elements for v in e.visibility + ): + # If there's only 1 visible point, the bbox will have 0 w and h + bbox = [bbox[0], bbox[1], max(1, bbox[2]), max(1, bbox[3])] + + return bbox + + def _prepare_gt(self): + def _find_unambiguous_matches( + input_boxes: list[dm.Bbox], + gt_skeletons: list[dm.Skeleton], + *, + input_points: list[dm.Points], + gt_annotations: list[dm.Annotation], + ) -> list[tuple[dm.Bbox, dm.Skeleton]]: + bbox_point_mapping: dict[int, dm.Points] = { + bbox.id: next(p for p in input_points if p.group == bbox.group) + for bbox in input_boxes + } + + matches = [ + [ + (input_bbox.label == gt_skeleton.label) + and ( + self._match_boxes( + input_bbox.get_bbox(), + self._get_skeleton_bbox(gt_skeleton, gt_annotations), + ) + ) + and (input_point := bbox_point_mapping[input_bbox.id]) + and is_point_in_bbox( + input_point.points[0], + input_point.points[1], + self._get_skeleton_bbox(gt_skeleton, gt_annotations), + ) + and ( + # a way to customize matching if the default method is too rough + not (bbox_id := input_bbox.attributes.get(self.config.gt_id_attribute)) + or not ( + skeleton_id := gt_skeleton.attributes.get(self.config.gt_id_attribute) + ) + or bbox_id == skeleton_id + ) + for gt_skeleton in gt_skeletons + ] + for input_bbox in input_boxes + ] + + ambiguous_boxes: list[int] = set() + ambiguous_skeletons: list[int] = set() + for bbox_idx, input_bbox in enumerate(input_boxes): + matched_skeletons: list[dm.Skeleton] = [ + gt_skeletons[j] for j in range(len(gt_skeletons)) if matches[bbox_idx][j] + ] + + if len(matched_skeletons) > 1: + # Handle ambiguous matches + excluded_boxes_info.add_message( + "Sample '{}': bbox #{} ({}) and overlapping skeletons skipped - " + "too many matching skeletons ({}) found".format( + boxes_sample.id, + input_bbox.id, + boxes_label_cat[input_bbox.label].name, + format_sequence([f"#{a.id}" for a in matched_skeletons]), + ), + sample_id=boxes_sample.id, + sample_subset=boxes_sample.subset, + ) + # not an error, should not be counted as excluded for an error + ambiguous_boxes.add(input_bbox.id) + ambiguous_skeletons.update(s.id for s in matched_skeletons) + continue + + for skeleton_idx, gt_skeleton in enumerate(gt_skeletons): + matched_boxes: list[dm.Bbox] = [ + input_boxes[i] for i in range(len(input_boxes)) if matches[i][skeleton_idx] + ] + + if len(matched_boxes) > 1: + # Handle ambiguous matches + excluded_gt_info.add_message( + "Sample '{}': GT skeleton #{} ({}) and overlapping boxes skipped - " + "too many matching boxes ({}) found".format( + gt_sample.id, + gt_skeleton.id, + gt_label_cat[gt_skeleton.label].name, + format_sequence([f"#{a.id}" for a in matched_boxes]), + ), + sample_id=gt_sample.id, + sample_subset=gt_sample.subset, + ) + # not an error, should not be counted as excluded for an error + ambiguous_skeletons.add(gt_skeleton.id) + ambiguous_boxes.update(b.id for b in matched_boxes) + continue + if not matched_boxes: + # Handle unmatched skeletons + excluded_gt_info.add_message( + "Sample '{}': GT skeleton #{} ({}) skipped - " + "no matching boxes found".format( + gt_sample.id, + gt_skeleton.id, + gt_label_cat[gt_skeleton.label].name, + ), + sample_id=gt_sample.id, + sample_subset=gt_sample.subset, + ) + excluded_gt_info.excluded_count += 1 # an error + continue + + unambiguous_matches: list[tuple[dm.Bbox, dm.Skeleton]] = [] + for bbox_idx, input_bbox in enumerate(input_boxes): + if input_bbox.id in ambiguous_boxes: + continue + + matched_skeleton = None + for gt_idx, gt_skeleton in enumerate(gt_skeletons): + if gt_skeleton.id in ambiguous_skeletons: + continue + + if matches[bbox_idx][gt_idx]: + matched_skeleton = gt_skeleton + break + + if matched_skeleton: + unambiguous_matches.append((input_bbox, matched_skeleton)) + + return unambiguous_matches + + def _find_good_gt_skeletons( + input_boxes: list[dm.Bbox], + gt_skeletons: list[dm.Skeleton], + *, + input_points: list[dm.Points], + gt_annotations: list[dm.Annotation], + ) -> list[dm.Skeleton]: + matches = _find_unambiguous_matches( + input_boxes, gt_skeletons, input_points=input_points, gt_annotations=gt_annotations + ) + + matched_skeletons = [] + for input_bbox, gt_skeleton in matches: + gt_count_per_class[gt_skeleton.label] = ( + gt_count_per_class.get(gt_skeleton.label, 0) + 1 + ) + + matched_skeletons.append(gt_skeleton) + skeleton_bbox_mapping[gt_skeleton.id] = input_bbox.id + + return matched_skeletons + + assert self._data_filenames is not unset + assert self._boxes_dataset is not unset + assert self._input_gt_dataset is not unset + assert [ + label.name + for label in self._input_gt_dataset.categories()[dm.AnnotationType.label] + if not label.parent + ] == [label.name for label in self.manifest.annotation.labels] + assert [ + label.name + for label in self._boxes_dataset.categories()[dm.AnnotationType.label] + if not label.parent + ] == [label.name for label in self.manifest.annotation.labels] + + boxes_label_cat: dm.LabelCategories = self._boxes_dataset.categories()[ + dm.AnnotationType.label + ] + gt_label_cat: dm.LabelCategories = self._input_gt_dataset.categories()[ + dm.AnnotationType.label + ] + + updated_gt_dataset = dm.Dataset( + categories=self._input_gt_dataset.categories(), media_type=dm.Image + ) + + excluded_boxes_info = ExcludedAnnotationsInfo() # local for the function + excluded_gt_info = self._excluded_gt_info + gt_count_per_class = {} + skeleton_bbox_mapping = {} # skeleton id -> bbox id + for gt_sample in self._input_gt_dataset: + boxes_sample = self._boxes_dataset.get(gt_sample.id, gt_sample.subset) + # Samples could be discarded, so we just skip them without an error + if not boxes_sample: + continue + + gt_skeletons = [a for a in gt_sample.annotations if isinstance(a, dm.Skeleton)] + input_boxes = [a for a in boxes_sample.annotations if isinstance(a, dm.Bbox)] + input_points = [a for a in boxes_sample.annotations if isinstance(a, dm.Points)] + assert len(input_boxes) == len(input_points) + + # Samples without boxes are allowed, so we just skip them without an error + if not gt_skeletons: + continue + + matched_skeletons = _find_good_gt_skeletons( + input_boxes, + gt_skeletons, + input_points=input_points, + gt_annotations=gt_sample.annotations, + ) + if not matched_skeletons: + continue + + updated_gt_dataset.put(gt_sample.wrap(annotations=matched_skeletons)) + + if excluded_boxes_info.messages: + self.logger.warning( + "Some boxes were excluded from GT due to the problems found: {}".format( + format_sequence( + [e.message for e in excluded_boxes_info.messages], separator="\n" + ) + ) + ) + + if excluded_gt_info.messages: + self.logger.warning( + "Some GT annotations were excluded due to the errors found: {}".format( + format_sequence([e.message for e in excluded_gt_info.messages], separator="\n") + ) + ) + + if excluded_gt_info.excluded_count > ceil( + self.config.max_discarded_threshold * excluded_gt_info.total_count + ): + raise DatasetValidationError( + "Too many GT skeletons discarded ({} out of {}). " + "Please make sure each GT skeleton matches exactly 1 bbox " + "and has at least 1 visible point".format( + excluded_gt_info.total_count - len(skeleton_bbox_mapping), + excluded_gt_info.total_count, + ) + ) + + self.logger.info( + "GT counts per class to be used for validation: {}".format( + format_sequence( + [ + f"{gt_label_cat[label_id].name}: {count}" + for label_id, count in gt_count_per_class.items() + ] + ) + ) + ) + + labels_with_few_gt = [ + gt_label_cat[label_id] + for label_id, label_count in gt_count_per_class.items() + if label_count < self.config.min_label_gt_samples + ] + if labels_with_few_gt: + raise DatasetValidationError( + "Too few matching GT boxes/points annotations found for some classes: {}".format( + format_sequence(labels_with_few_gt) + ) + ) + + self._gt_dataset = updated_gt_dataset + self._skeleton_bbox_mapping = skeleton_bbox_mapping + + def _prepare_roi_infos(self): + assert self._gt_dataset is not unset + assert self._boxes_dataset is not unset + + rois: list[skeletons_from_boxes_task.RoiInfo] = [] + for sample in self._boxes_dataset: + instances = find_instances(sample.annotations) + for instance_anns in instances: + bbox = next(a for a in instance_anns if isinstance(a, dm.Bbox)) + point = next(a for a in instance_anns if isinstance(a, dm.Points)) + + # RoI is centered on bbox center + original_bbox_cx = int(bbox.x + bbox.w / 2) + original_bbox_cy = int(bbox.y + bbox.h / 2) + + roi_w = ceil(bbox.w * self.config.roi_size_mult) + roi_h = ceil(bbox.h * self.config.roi_size_mult) + roi_w = max(roi_w, self.config.min_roi_size[0]) + roi_h = max(roi_h, self.config.min_roi_size[1]) + + roi_x = original_bbox_cx - int(roi_w / 2) + roi_y = original_bbox_cy - int(roi_h / 2) + + new_bbox_x = bbox.x - roi_x + new_bbox_y = bbox.y - roi_y + + rois.append( + skeletons_from_boxes_task.RoiInfo( + original_image_key=sample.attributes["id"], + bbox_id=bbox.id, + bbox_label=bbox.label, + bbox_x=new_bbox_x, + bbox_y=new_bbox_y, + point_x=point.points[0] - roi_x, + point_y=point.points[1] - roi_y, + roi_x=roi_x, + roi_y=roi_y, + roi_w=roi_w, + roi_h=roi_h, + ) + ) + + self._roi_infos = rois + self._roi_info_by_id = {roi_info.bbox_id: roi_info for roi_info in self._roi_infos} + + def _mangle_filenames(self): + """ + Mangle filenames in the dataset to make them less recognizable by annotators + and hide private dataset info + """ + assert self._roi_infos is not unset + + # TODO: maybe add different names for the same GT images in + # different jobs to make them even less recognizable + self._roi_filenames = { + roi_info.bbox_id: str(uuid.uuid4()) + self.config.roi_file_ext + for roi_info in self._roi_infos + } + + @property + def _task_segment_size(self) -> int: + # Here we use a job size multiplier, because each image + # is supposed to be simple and the assignment is expected + # to take little time with the default job size. + # Then, we add a percent of job tiles for validation, keeping the requested ratio. + return super()._task_segment_size * self.config.job_size_mult + + @property + def _job_val_frames_count(self) -> int: + return super()._job_val_frames_count * self.config.job_size_mult + + def _prepare_task_params(self): + assert self._roi_infos is not unset + assert self._skeleton_bbox_mapping is not unset + assert self._input_gt_dataset is not unset + + # This list can be different from what is selected for validation + input_gt_filenames = set(sample.media.path for sample in self._input_gt_dataset) + image_id_to_filename = { + sample.attributes["id"]: sample.media.path for sample in self._boxes_dataset + } + + task_params: list[_TaskParams] = [] + segment_size = self._task_segment_size + for label_id, _ in enumerate(self.manifest.annotation.labels): + label_gt_roi_ids = set( + roi_id + for roi_id in self._skeleton_bbox_mapping.values() + if self._roi_info_by_id[roi_id].bbox_label == label_id + ) + + label_data_roi_ids = [ + roi_info.bbox_id + for roi_info in self._roi_infos + if roi_info.bbox_label == label_id + if roi_info.bbox_id not in label_gt_roi_ids + if image_id_to_filename[roi_info.original_image_key] not in input_gt_filenames + ] + random.shuffle(label_data_roi_ids) + + task_params.extend( + [ + _TaskParams( + label_id=label_id, roi_ids=task_data_roi_ids, roi_gt_ids=label_gt_roi_ids + ) + for task_data_roi_ids in take_by( + label_data_roi_ids, Config.cvat_config.max_jobs_per_task * segment_size + ) + ] + ) + + self._task_params = task_params + + def _prepare_job_labels(self): + self._point_labels = {} + + for skeleton_label in self.manifest.annotation.labels: + for point_name in skeleton_label.nodes: + self._point_labels[(skeleton_label.name, point_name)] = point_name + + def _prepare_gt_points_mapping(self): + assert self._gt_dataset is not unset + + self._gt_points_per_label = {} + + # GT should contain all GT images with only one point per skeleton node + for gt_sample in self._gt_dataset: + for gt_skeleton in gt_sample.annotations: + if not isinstance(gt_skeleton, dm.Skeleton): + continue + + for point in gt_skeleton.elements: + if point.visibility[0] in [ + dm.Points.Visibility.absent, + dm.Points.Visibility.hidden, + ]: + continue + + point_label_name = ( + self._gt_dataset.categories()[dm.AnnotationType.label] + .items[point.label] + .name + ) + + self._gt_points_per_label.setdefault( + (gt_skeleton.label, point_label_name), [] + ).append((gt_skeleton.id, point)) + + def _upload_task_meta(self): + layout = skeletons_from_boxes_task.TaskMetaLayout() + serializer = skeletons_from_boxes_task.TaskMetaSerializer() + + file_list = [] + file_list.append( + (serializer.serialize_bbox_annotations(self._boxes_dataset), layout.BOXES_FILENAME) + ) + file_list.append( + ( + serializer.serialize_gt_annotations(self._gt_dataset), + layout.GT_FILENAME, + ) + ) + file_list.append( + ( + serializer.serialize_skeleton_bbox_mapping(self._skeleton_bbox_mapping), + layout.SKELETON_BBOX_MAPPING_FILENAME, + ) + ) + file_list.append((serializer.serialize_roi_info(self._roi_infos), layout.ROI_INFO_FILENAME)) + file_list.append( + (serializer.serialize_roi_filenames(self._roi_filenames), layout.ROI_FILENAMES_FILENAME) + ) + file_list.append( + (serializer.serialize_point_labels(self._point_labels), layout.POINT_LABELS_FILENAME) + ) + + storage_client = self._make_cloud_storage_client(self._oracle_data_bucket) + for file_data, filename in file_list: + storage_client.create_file( + compose_data_bucket_filename(self.escrow_address, self.chain_id, filename), + file_data, + ) + + def _extract_roi( + self, source_pixels: np.ndarray, roi_info: skeletons_from_boxes_task.RoiInfo + ) -> np.ndarray: + img_h, img_w, *_ = source_pixels.shape + + roi_pixels = source_pixels[ + max(0, roi_info.roi_y) : min(img_h, roi_info.roi_y + roi_info.roi_h), + max(0, roi_info.roi_x) : min(img_w, roi_info.roi_x + roi_info.roi_w), + ] + + if not ( + (0 <= roi_info.roi_x < roi_info.roi_x + roi_info.roi_w < img_w) + and (0 <= roi_info.roi_y < roi_info.roi_y + roi_info.roi_h < img_h) + ): + # Coords can be outside the original image + # In this case a border should be added to RoI, so that the image was centered on bbox + wrapped_roi_pixels = np.zeros((roi_info.roi_h, roi_info.roi_w, 3), dtype=np.float32) + wrapped_roi_pixels[:, :] = self.config.roi_background_color + + dst_y = max(-roi_info.roi_y, 0) + dst_x = max(-roi_info.roi_x, 0) + wrapped_roi_pixels[ + dst_y : dst_y + roi_pixels.shape[0], + dst_x : dst_x + roi_pixels.shape[1], + ] = roi_pixels + + roi_pixels = wrapped_roi_pixels + else: + roi_pixels = roi_pixels.copy() + + return roi_pixels + + def _draw_roi_bbox(self, roi_image: np.ndarray, bbox: dm.Bbox) -> np.ndarray: + roi_cy = roi_image.shape[0] // 2 + roi_cx = roi_image.shape[1] // 2 + return cv2.rectangle( + roi_image, + tuple(map(int, (roi_cx - bbox.w / 2, roi_cy - bbox.h / 2))), + tuple(map(int, (roi_cx + bbox.w / 2, roi_cy + bbox.h / 2))), + self.config.roi_embedded_bbox_color, + 1, + cv2.LINE_4, + ) + + def _draw_roi_point(self, roi_image: np.ndarray, point: tuple[float, float]) -> np.ndarray: + roi_r = (roi_image.shape[0] ** 2 + roi_image.shape[1] ** 2) ** 0.5 / 2 + radius = int( + min( + self.config.max_embedded_point_radius_percent * roi_r, + max( + self.config.embedded_point_radius, + self.config.min_embedded_point_radius_percent * roi_r, + ), + ) + ) + + roi_image = cv2.circle( + roi_image, + tuple(map(int, (point[0], point[1]))), + radius + 1, + (255, 255, 255), + -1, + cv2.LINE_4, + ) + return cv2.circle( + roi_image, + tuple(map(int, (point[0], point[1]))), + radius, + self.config.embedded_point_color, + -1, + cv2.LINE_4, + ) + + def _extract_and_upload_rois(self): + assert self._roi_filenames is not unset + assert self._roi_infos is not unset + + src_bucket = BucketAccessInfo.parse_obj(self.manifest.data.data_url) + src_prefix = src_bucket.path + dst_bucket = self._oracle_data_bucket + + src_client = self._make_cloud_storage_client(src_bucket) + dst_client = self._make_cloud_storage_client(dst_bucket) + + image_id_to_filename = { + sample.attributes["id"]: sample.image.path for sample in self._boxes_dataset + } + + filename_to_sample = {sample.image.path: sample for sample in self._boxes_dataset} + + def _roi_info_key(e): + return e.original_image_key + + roi_info_by_image: dict[str, Sequence[skeletons_from_boxes_task.RoiInfo]] = { + image_id_to_filename[image_id]: list(g) + for image_id, g in groupby( + sorted(self._roi_infos, key=_roi_info_key), key=_roi_info_key + ) + } + + bbox_by_id = { + bbox.id: bbox + for sample in self._boxes_dataset + for bbox in sample.annotations + if isinstance(bbox, dm.Bbox) + } + + def process_file(filename: str, image_pixels: np.ndarray): + image_roi_infos = roi_info_by_image.get(filename, []) + if not image_roi_infos: + return + + sample = filename_to_sample[filename] + if tuple(sample.image.size) != tuple(image_pixels.shape[:2]): + # TODO: maybe rois should be regenerated instead + # Option 2: accumulate errors, fail when some threshold is reached + # Option 3: add special handling for cases when image is only rotated (exif etc.) + raise InvalidImageInfo( + f"Sample '{filename}': invalid size provided in the point annotations" + ) + + for roi_info in image_roi_infos: + roi_pixels = self._extract_roi(image_pixels, roi_info) + + if self.config.embed_bbox_in_roi_image: + roi_pixels = self._draw_roi_bbox(roi_pixels, bbox_by_id[roi_info.bbox_id]) + roi_pixels = self._draw_roi_point( + roi_pixels, (roi_info.point_x, roi_info.point_y) + ) + + filename = self._roi_filenames[roi_info.bbox_id] + roi_bytes = encode_image(roi_pixels, os.path.splitext(filename)[-1]) + + dst_client.create_file( + compose_data_bucket_filename(self.escrow_address, self.chain_id, filename), + data=roi_bytes, + ) + + def download_and_decode(key: str): + image_bytes = src_client.download_file(key) + return decode_image(image_bytes) + + pool_size = Config.features.max_data_storage_connections + download_queue_size = 4 * pool_size + download_queue = Queue[tuple[str, Future[np.ndarray]]](download_queue_size) + roi_uploader = BufferedRoiImageUploader(queue=download_queue) + with ThreadPoolExecutor(pool_size) as pool: + + def put_callback(filename: str): + image_roi_infos = roi_info_by_image.get(filename, []) + if not image_roi_infos: + return None + + return ( + filename, + pool.submit(download_and_decode, os.path.join(src_prefix, filename)), + ) + + def process_callback(result: tuple[str, Future]): + filename, task = result + process_file(filename, task.result()) + + roi_uploader.process_all( + self._data_filenames, put_callback=put_callback, process_callback=process_callback + ) + + def _prepare_gt_dataset_for_skeleton_point( + self, + *, + point_label_name: str, + skeleton_label_id: int, + ) -> dm.Dataset: + assert self._gt_points_per_label is not unset + + # Change annotations to Points for validation in CVAT, + # as annotators will use this annotation type + point_dataset = dm.Dataset( + categories={ + dm.AnnotationType.label: dm.LabelCategories.from_iterable([point_label_name]), + }, + media_type=dm.Image, + ) + + for gt_skeleton_id, gt_point in self._gt_points_per_label[ + (skeleton_label_id, point_label_name) + ]: + roi_key = self._skeleton_bbox_mapping[gt_skeleton_id] + roi_info = self._roi_info_by_id[roi_key] + + mangled_cvat_sample_id = compose_data_bucket_filename( + self.escrow_address, + self.chain_id, + os.path.splitext(self._roi_filenames[roi_key])[0], + ) + + # update points coordinates in accordance with roi coordinates + updated_points = [ + gt_point.points[0] - roi_info.roi_x, + gt_point.points[1] - roi_info.roi_y, + ] + + point_dataset.put( + dm.DatasetItem( + id=mangled_cvat_sample_id, + annotations=[dm.Points(id=gt_skeleton_id, points=updated_points, label=0)], + ) + ) + + return point_dataset + + def _save_cvat_gt_dataset_to_oracle_bucket( + self, + gt_dataset_path: Path, + *, + file_suffix: str = "", + ) -> None: + layout = skeletons_from_boxes_task.TaskMetaLayout() + + base_gt_filename = layout.GT_FILENAME.split(".", maxsplit=1)[0] + final_gt_filename = f"{base_gt_filename}_{file_suffix}" + ".zip" + gt_dataset_key = compose_data_bucket_filename( + self.escrow_address, self.chain_id, final_gt_filename + ) + + storage_client = self._make_cloud_storage_client(self._oracle_data_bucket) + storage_client.create_file(gt_dataset_key, gt_dataset_path.read_bytes()) + + def _setup_quality_settings(self, task_id: int, **overrides) -> None: + values = { + "oks_sigma": Config.cvat_config.oks_sigma, + "point_size_base": "image_size", # we don't expect any boxes or groups, so ignore them + } + values.update(overrides) + super()._setup_quality_settings(task_id, **values) + + def _create_on_cvat(self): + assert self._task_params is not unset + assert self._point_labels is not unset + assert self._gt_points_per_label is not unset + + def _task_params_label_key(ts): + return ts.label_id + + tasks_by_skeleton_label = { + skeleton_label_id: list(g) + for skeleton_label_id, g in groupby( + sorted(self._task_params, key=_task_params_label_key), key=_task_params_label_key + ) + } + + label_specs_by_skeleton = { + skeleton_label_id: [ + { + "name": self._point_labels[(skeleton_label.name, skeleton_point)], + "type": "points", + } + for skeleton_point in skeleton_label.nodes + ] + for skeleton_label_id, skeleton_label in enumerate(self.manifest.annotation.labels) + } + + oracle_bucket = self._oracle_data_bucket + + # Register cloud storage on CVAT to pass user dataset + cvat_cloud_storage = cvat_api.create_cloudstorage( + **make_cvat_cloud_storage_params(oracle_bucket) + ) + + segment_size = self._task_segment_size + + total_jobs = sum( + len(self.manifest.annotation.labels[tp.label_id].nodes) + * (math.ceil(len(tp.roi_ids) / segment_size)) + for tp in self._task_params + ) + self.logger.info( + "Task creation for escrow '%s': will create %s assignments", + self.escrow_address, + total_jobs, + ) + + with SessionLocal.begin() as session: + db_service.create_escrow_creation( + session, + escrow_address=self.escrow_address, + chain_id=self.chain_id, + total_jobs=total_jobs, + ) + created_projects = [] + + for skeleton_label_id, skeleton_label_tasks in tasks_by_skeleton_label.items(): + skeleton_label_filenames: list[list[str]] = [] + gt_skeleton_label_filenames: list[list[str]] = [] + + for skeleton_label_task in skeleton_label_tasks: + skeleton_label_filenames.append( + [ + compose_data_bucket_filename( + self.escrow_address, self.chain_id, self._roi_filenames[roi_id] + ) + for roi_id in skeleton_label_task.roi_ids + ], + ) + + gt_skeleton_label_filenames.append( + [ + compose_data_bucket_filename( + self.escrow_address, self.chain_id, self._roi_filenames[roi_id] + ) + for roi_id in skeleton_label_task.roi_gt_ids + ], + ) + + for point_label_spec in label_specs_by_skeleton[skeleton_label_id]: + point_label_name = point_label_spec["name"] + + # Create a project for each point label. + # CVAT doesn't support tasks with different labels in a project. + cvat_project = cvat_api.create_project( + name="{} ({} {})".format( + self.escrow_address, + self.manifest.annotation.labels[skeleton_label_id].name, + point_label_name, + ), + user_guide=self.manifest.annotation.user_guide, + labels=[point_label_spec], + # TODO: improve guide handling - split for different points + ) + + # Setup webhooks for the project + cvat_webhook = cvat_api.create_cvat_webhook(cvat_project.id) + + project_id = db_service.create_project( + session, + cvat_project.id, + cvat_cloudstorage_id=cvat_cloud_storage.id, + job_type=self.manifest.annotation.type, + escrow_address=self.escrow_address, + chain_id=self.chain_id, + bucket_url=oracle_bucket.to_url().rstrip("/") + + "/" + + compose_data_bucket_prefix(self.escrow_address, self.chain_id), + cvat_webhook_id=cvat_webhook.id, + assignment_bounty=get_assignment_bounty( + self.manifest, + escrow_address=self.escrow_address, + chain_id=self.chain_id, + job_count=total_jobs, + ), + ) + created_projects.append(project_id) + + db_service.get_project_by_id( + session, project_id, for_update=True + ) # lock the row + db_service.add_project_images( + session, + cvat_project.id, + list(set(chain.from_iterable(skeleton_label_filenames))), + ) + + for point_label_filenames, gt_point_label_filenames in zip( + skeleton_label_filenames, gt_skeleton_label_filenames, strict=False + ): + cvat_task = cvat_api.create_task( + cvat_project.id, + name=cvat_project.name, + segment_size=segment_size, + ) + + task_id = db_service.create_task( + session, cvat_task.id, cvat_project.id, TaskStatuses[cvat_task.status] + ) + db_service.get_task_by_id(session, task_id, for_update=True) # lock the row + + # The task is fully created once 'update:task' webhook is received. + cvat_api.put_task_data( + cvat_task.id, + cvat_cloud_storage.id, + filenames=point_label_filenames + gt_point_label_filenames, + validation_params={ + "gt_filenames": gt_point_label_filenames, + "gt_frames_per_job_count": self._job_val_frames_count, + }, + ) + + gt_point_dataset = self._prepare_gt_dataset_for_skeleton_point( + point_label_name=point_label_name, + skeleton_label_id=skeleton_label_id, + ) + + self._setup_gt_job_for_cvat_task( + cvat_task.id, gt_point_dataset, dm_export_format="cvat" + ) + self._setup_quality_settings( + cvat_task.id, oks_sigma=Config.cvat_config.oks_sigma + ) + + db_service.create_data_upload(session, cvat_task.id) + + db_service.touch(session, Project, created_projects) + + def build(self): + self._download_input_data() + self._parse_gt() + self._parse_boxes() + self._validate_gt() + self._validate_boxes() + + # Task configuration creation + self._prepare_gt() + self._prepare_roi_infos() + self._prepare_task_params() + self._mangle_filenames() + self._prepare_job_labels() + + # Data preparation + self._extract_and_upload_rois() + self._upload_task_meta() + self._prepare_gt_points_mapping() + + self._create_on_cvat() diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/exceptions.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/exceptions.py new file mode 100644 index 0000000000..c1c5708ffb --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/exceptions.py @@ -0,0 +1,55 @@ +from __future__ import annotations + +from dataclasses import dataclass, field + + +class DatasetValidationError(Exception): + pass + + +class MismatchingAnnotations(DatasetValidationError): + pass + + +class TooFewSamples(DatasetValidationError): + pass + + +class InvalidCategories(DatasetValidationError): + pass + + +class InvalidImageInfo(DatasetValidationError): + pass + + +class InvalidCoordinates(DatasetValidationError): + pass + + +class InvisibleSkeletonError(DatasetValidationError): + pass + + +@dataclass +class ExcludedAnnotationInfo: + message: str + sample_id: str = field(kw_only=True) + sample_subset: str = field(kw_only=True) + + +@dataclass +class ExcludedAnnotationsInfo: + messages: list[ExcludedAnnotationInfo] = field(default_factory=list) + + excluded_count: int = 0 + "The number of excluded annotations. Can be different from len(messages)" + + total_count: int = 0 + + def add_message(self, message: str, *, sample_id: str, sample_subset: str): + self.messages.append( + ExcludedAnnotationInfo( + message=message, sample_id=sample_id, sample_subset=sample_subset + ) + ) diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/handlers.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/handlers.py new file mode 100644 index 0000000000..243f06122f --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/handlers.py @@ -0,0 +1,17 @@ +from src.chain.escrow import get_escrow_manifest +from src.core.manifest import parse_manifest +from src.handlers.job_creation.builders.factory import create_builder +from src.log import ROOT_LOGGER_NAME +from src.utils.logging import get_function_logger + +module_logger = f"{ROOT_LOGGER_NAME}.cron.cvat" + + +def create_task(escrow_address: str, chain_id: int) -> None: + logger = get_function_logger(module_logger) + + manifest = parse_manifest(get_escrow_manifest(chain_id, escrow_address)) + + with create_builder(manifest, escrow_address, chain_id) as task_builder: + task_builder.set_logger(logger) + task_builder.build() diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/utils.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/utils.py new file mode 100644 index 0000000000..5746ba5295 --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/utils.py @@ -0,0 +1,103 @@ +from __future__ import annotations + +import os +from decimal import Decimal +from typing import TYPE_CHECKING, TypeVar + +from datumaro.util.image import IMAGE_EXTENSIONS + +import src.cvat.api_calls as cvat_api +from src.chain.escrow import get_escrow +from src.core.tasks import TaskTypes +from src.services.cloud import CloudProviders + +if TYPE_CHECKING: + from src.core.manifest import ManifestBase + from src.core.manifest.v1 import JobManifest + from src.services.cloud.utils import BucketAccessInfo + +LABEL_TYPE_MAPPING = { + TaskTypes.image_label_binary: cvat_api.LabelType.tag, + TaskTypes.image_points: cvat_api.LabelType.points, + TaskTypes.image_boxes: cvat_api.LabelType.rectangle, + TaskTypes.image_polygons: cvat_api.LabelType.polygon, + TaskTypes.image_boxes_from_points: cvat_api.LabelType.rectangle, + TaskTypes.image_skeletons_from_boxes: cvat_api.LabelType.points, +} + + +T = TypeVar("T") + + +class _Undefined: + def __bool__(self) -> bool: + return False + + +unset = _Undefined() + +MaybeUnset = T | _Undefined + + +def get_assignment_bounty( + manifest: ManifestBase, escrow_address: str, chain_id: int, *, job_count: int +) -> str | None: + match manifest.version: + case 1: + return str(manifest.job_bounty) + case 2: + return _get_assignment_bounty_from_escrow(escrow_address, chain_id, job_count) + case _ as version: + raise NotImplementedError(f"Unexpected manifest version '{version}'") + + +def _get_assignment_bounty_from_escrow( + escrow_address: str, chain_id: int, job_count: int +) -> str | None: + # TODO: refine (fees, already-paid amount, token decimals). Rough split of the escrow's total + # funds across the jobs. + if not job_count: + return None + escrow = get_escrow(chain_id, escrow_address) + return str(Decimal(escrow.total_funded_amount) / job_count) + + +def is_image(path: str) -> bool: + trunk, ext = os.path.splitext(os.path.basename(path)) + return trunk and ext.lower() in IMAGE_EXTENSIONS + + +def filter_image_files(data_filenames: list[str]) -> list[str]: + return [fn for fn in data_filenames if is_image(fn)] + + +def strip_bucket_prefix(data_filenames: list[str], prefix: str) -> list[str]: + return [os.path.relpath(fn, prefix) for fn in data_filenames] + + +def make_cvat_label_configuration(manifest: JobManifest) -> list[dict]: + return [ + { + "name": label.name, + "type": LABEL_TYPE_MAPPING[manifest.annotation.type].value, + } + for label in manifest.annotation.labels + ] + + +def make_cvat_cloud_storage_params(bucket_info: BucketAccessInfo) -> dict: + CLOUD_PROVIDER_TO_CVAT_CLOUD_PROVIDER = { + CloudProviders.aws: "AWS_S3_BUCKET", + CloudProviders.gcs: "GOOGLE_CLOUD_STORAGE", + } + + params = { + "provider": CLOUD_PROVIDER_TO_CVAT_CLOUD_PROVIDER[bucket_info.provider], + "bucket_name": bucket_info.bucket_name, + "bucket_host": bucket_info.host_url, + } + + if bucket_info.credentials: + params["credentials"] = bucket_info.credentials.to_dict() + + return params diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_export/__init__.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_export/__init__.py new file mode 100644 index 0000000000..a109200e4e --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_export/__init__.py @@ -0,0 +1,3 @@ +from src.handlers.job_export.handlers import handle_escrow_export + +__all__ = ["handle_escrow_export"] diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_export/downloading.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_export/downloading.py new file mode 100644 index 0000000000..bf8674aec7 --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_export/downloading.py @@ -0,0 +1,117 @@ +"""CVAT annotation downloading for the escrow export flow.""" + +from __future__ import annotations + +from functools import partial +from typing import TYPE_CHECKING + +from datumaro.util import take_by + +import src.cvat.api_calls as cvat_api +from src.core.config import CronConfig +from src.handlers.job_export.results import FileDescriptor + +if TYPE_CHECKING: + import io + import logging + from collections.abc import Callable, Sequence + from typing import Any + + from src.models.cvat import Job + + +def download_with_retries( + logger: logging.Logger, + download_callback: Callable[[], io.RawIOBase], + retry_callback: Callable[[], Any], + *, + max_attempts: int | None = None, +) -> io.RawIOBase: + """ + Sometimes CVAT downloading can fail with the 500 error. + This function tries to repeat the export in such cases. + """ + + if max_attempts is None: + max_attempts = CronConfig.track_completed_escrows_max_downloading_retries + + attempt = 0 + while attempt < max_attempts: + try: + return download_callback() + except cvat_api.exceptions.ApiException as e: + if 500 <= e.status < 600 and attempt + 1 < max_attempts: + attempt += 1 + logger.info(f"Retrying downloading, attempt #{attempt} of {max_attempts}...") + retry_callback() + else: + raise + return None + + +def download_project_annotations( + logger: logging.Logger, annotation_format: str, project_cvat_id: int +) -> io.RawIOBase: + export_ids = [] + + def _request_export(cvat_id: int): + request_id = cvat_api.request_project_annotations(cvat_id, format_name=annotation_format) + export_ids.append(request_id) + return request_id + + def _download_export(): + request_id = export_ids.pop(0) + return cvat_api.get_project_annotations(request_id=request_id) + + _request_export(project_cvat_id) + + return download_with_retries( + logger, + download_callback=_download_export, + retry_callback=partial(_request_export, project_cvat_id), + ) + + +def download_job_annotations( + logger: logging.Logger, annotation_format: str, jobs: Sequence[Job] +) -> dict[int, FileDescriptor]: + # Collect raw annotations from CVAT, validate and convert them + # into a recording oracle suitable format + job_annotations: dict[int, FileDescriptor] = {} + + export_ids: list[tuple[Job, str]] = [] + + def _request_export(job: Job): + request_id = cvat_api.request_job_annotations(job.cvat_id, format_name=annotation_format) + export_ids.append((job, request_id)) + return request_id + + for jobs_batch in take_by( + jobs, count=CronConfig.track_completed_escrows_jobs_downloading_batch_size + ): + # Request jobs before downloading for faster batch downloading + for job in jobs_batch: + _request_export(job) + + while export_ids: + (job, request_id) = export_ids.pop(0) + + job_annotations_file = download_with_retries( + logger, + download_callback=partial(cvat_api.get_job_annotations, request_id=request_id), + retry_callback=partial(_request_export, job), + ) + + job_assignment = job.latest_assignment + job_annotations[job.cvat_id] = FileDescriptor( + filename="project_{}-task_{}-job_{}-user_{}-assignment_{}.zip".format( + job.cvat_project_id, + job.cvat_task_id, + job.cvat_id, + job_assignment.user.cvat_id, + job_assignment.id, + ), + file=job_annotations_file, + ) + + return job_annotations diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_export/exporters/__init__.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_export/exporters/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_export/exporters/audio.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_export/exporters/audio.py new file mode 100644 index 0000000000..930497fb23 --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_export/exporters/audio.py @@ -0,0 +1,144 @@ +from __future__ import annotations + +import csv +import io +from datetime import timedelta +from typing import TYPE_CHECKING + +import src.services.cvat as cvat_service +from src.core.config import Config +from src.core.storage import compose_data_bucket_filename +from src.core.tasks.audio_transcription.meta import ( + CVAT_EXPORT_FORMAT, + TaskMetaLayout, + TaskMetaSerializer, + TaskResultsLayout, + format_time, + parse_time, +) +from src.core.tasks.audio_transcription.spec import parse_audio_manifest +from src.handlers.job_export.downloading import download_job_annotations +from src.handlers.job_export.exporters.base import JobExporter +from src.handlers.job_export.results import ( + FileDescriptor, + prepare_annotation_metafile, + upload_escrow_results, +) +from src.services.cloud import make_client as make_cloud_client +from src.services.cloud.utils import BucketAccessInfo + +if TYPE_CHECKING: + from src.core.tasks.audio_transcription.meta import Clip, PlacedRegion + + +_LEADING_COLUMNS = ["id", "input_region_ids", "filename", "start", "stop", "label"] + + +class AudioTranscriptionJobExporter(JobExporter): + def export(self) -> None: + assert self.escrow_projects # unused, but must hold the lock + + jobs = cvat_service.get_jobs_by_escrow_address( + self.session, self.escrow_address, self.chain_id + ) + + spec = parse_audio_manifest(self.manifest) + attr_names = [ + spec.details.transcription_attr_name, + *(a.name for a in spec.shared_attributes), + ] + + assignments_by_clip = self._load_assignments() + + # TODO: use project export when CVAT supports it to speedup downloading + self.logger.debug(f"Downloading annotations for the escrow ({self.escrow_address=})") + job_annotations = download_job_annotations(self.logger, CVAT_EXPORT_FORMAT, jobs) + + rows: list[dict] = [] + for job in jobs: + rows.extend( + self._annotation_rows(job_annotations[job.cvat_id], assignments_by_clip, attr_names) + ) + rows.sort(key=lambda r: (r["filename"], r["_start_s"])) + merged = self._render_tsv([*_LEADING_COLUMNS, *attr_names], rows) + + self.logger.debug(f"Uploading merged annotations for the escrow ({self.escrow_address=})") + upload_escrow_results( + files=[ + FileDescriptor( + filename=TaskResultsLayout.ANNOTATIONS_FILENAME, file=io.BytesIO(merged) + ), + prepare_annotation_metafile(jobs=jobs), + ], + chain_id=self.chain_id, + escrow_address=self.escrow_address, + ) + + self._emit_escrow_recorded() + self.logger.info(f"The escrow ({self.escrow_address=}) is completed, annotations merged") + + def _load_assignments(self) -> dict[str, Clip]: + storage_client = make_cloud_client(BucketAccessInfo.parse_obj(Config.storage_config)) + assignments = TaskMetaSerializer().parse_clips( + storage_client.download_file( + compose_data_bucket_filename( + self.escrow_address, self.chain_id, TaskMetaLayout().CLIPS_FILENAME + ) + ) + ) + return {a.clip_filename: a for a in assignments} + + def _annotation_rows( + self, + annotations: FileDescriptor, + assignments_by_clip: dict[str, Clip], + attr_names: list[str], + ) -> list[dict]: + annotations.file.seek(0) + text_stream = io.TextIOWrapper(annotations.file, encoding="utf-8") + reader = csv.DictReader(text_stream, delimiter="\t") + + rows: list[dict] = [] + for interval in reader: + clip = interval["filename"].rsplit("/", 1)[-1] + assignment = assignments_by_clip.get(clip) + if assignment is None: + raise AssertionError(f"No assignment found for clip '{clip}'") + + start_s = parse_time(interval["start"]).total_seconds() + stop_s = parse_time(interval["stop"]).total_seconds() + + placed = self._placed_at(assignment, start_s) + if placed is None or placed.kind.value == "gt": + # outside any region, or a honeypot -> dropped + continue + + offset = placed.source_start - placed.clip_start + rows.append( + { + "filename": placed.source_filename, + "start": format_time(timedelta(seconds=start_s + offset)), + "stop": format_time(timedelta(seconds=stop_s + offset)), + "_start_s": start_s + offset, + "label": interval.get("label", ""), + "input_region_ids": ",".join(i.split(":")[-1] for i in placed.input_ids), + **{attr: interval.get(attr, "") or "" for attr in attr_names}, + } + ) + return rows + + @staticmethod + def _placed_at(assignment: Clip, clip_time_s: float) -> PlacedRegion | None: + return next( + (p for p in assignment.placed if p.clip_start <= clip_time_s < p.clip_stop), + None, + ) + + @staticmethod + def _render_tsv(columns: list[str], rows: list[dict]) -> bytes: + buffer = io.StringIO() + writer = csv.DictWriter(buffer, fieldnames=columns, delimiter="\t", extrasaction="ignore") + writer.writeheader() + for global_id, row in enumerate(rows): + writer.writerow({**row, "id": global_id}) + return buffer.getvalue().encode("utf-8") diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_export/exporters/base.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_export/exporters/base.py new file mode 100644 index 0000000000..43fb434b8d --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_export/exporters/base.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from abc import ABCMeta, abstractmethod +from contextlib import ExitStack +from typing import TYPE_CHECKING + +import src.services.webhook as oracle_db_service +from src.core.oracle_events import ExchangeOracleEvent_EscrowRecorded +from src.core.types import OracleWebhookTypes +from src.handlers.job_export.results import upload_escrow_results +from src.utils.logging import NullLogger + +if TYPE_CHECKING: + from collections.abc import Sequence + from logging import Logger + + from sqlalchemy.orm import Session + + from src.core.manifest import ManifestBase + from src.handlers.job_export.results import FileDescriptor + from src.models.cvat import Project + + +class JobExporter(metaclass=ABCMeta): + def __init__( + self, + manifest: ManifestBase, + escrow_address: str, + chain_id: int, + session: Session, + escrow_projects: Sequence[Project], + ) -> None: + self.exit_stack = ExitStack() + self.manifest = manifest + self.escrow_address = escrow_address + self.chain_id = chain_id + self.session = session + self.escrow_projects = escrow_projects + + self.logger: Logger = NullLogger() + + def __enter__(self): + return self + + def __exit__(self, *args, **kwargs): + self.close() + + def close(self): + self.exit_stack.close() + + def set_logger(self, logger: Logger): + self.logger = logger + return self + + @abstractmethod + def export(self) -> None: ... + + def _upload_results(self, files: Sequence[FileDescriptor]) -> None: + upload_escrow_results( + files=files, chain_id=self.chain_id, escrow_address=self.escrow_address + ) + + def _emit_escrow_recorded(self) -> None: + oracle_db_service.outbox.create_webhook( + self.session, + escrow_address=self.escrow_address, + chain_id=self.chain_id, + type=OracleWebhookTypes.recording_oracle, + event=ExchangeOracleEvent_EscrowRecorded(), + ) diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_export/exporters/factory.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_export/exporters/factory.py new file mode 100644 index 0000000000..7c5da50ffc --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_export/exporters/factory.py @@ -0,0 +1,54 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +from src.core.manifest import get_manifest_task_type +from src.core.tasks import TaskTypes +from src.handlers.job_export.exporters.audio import AudioTranscriptionJobExporter +from src.handlers.job_export.exporters.vision import ( + BoxesFromPointsJobExporter, + BoxesJobExporter, + LabelsJobExporter, + PointsJobExporter, + PolygonsJobExporter, + SkeletonsJobExporter, +) + +if TYPE_CHECKING: + from collections.abc import Sequence + + from sqlalchemy.orm import Session + + from src.core.manifest import ManifestBase + from src.handlers.job_export.exporters.base import JobExporter + from src.models.cvat import Project + + +def create_exporter( + manifest: ManifestBase, + escrow_address: str, + chain_id: int, + session: Session, + escrow_projects: Sequence[Project], +) -> JobExporter: + task_type = get_manifest_task_type(manifest) + + match task_type: + case TaskTypes.image_label_binary: + exporter_type = LabelsJobExporter + case TaskTypes.image_boxes: + exporter_type = BoxesJobExporter + case TaskTypes.image_polygons: + exporter_type = PolygonsJobExporter + case TaskTypes.image_points: + exporter_type = PointsJobExporter + case TaskTypes.image_boxes_from_points: + exporter_type = BoxesFromPointsJobExporter + case TaskTypes.image_skeletons_from_boxes: + exporter_type = SkeletonsJobExporter + case TaskTypes.audio_transcription: + exporter_type = AudioTranscriptionJobExporter + case _: + raise NotImplementedError(f"Unsupported task type '{task_type}'") + + return exporter_type(manifest, escrow_address, chain_id, session, escrow_projects) diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_export.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_export/exporters/vision.py similarity index 74% rename from packages/examples/cvat/exchange-oracle/src/handlers/job_export.py rename to packages/examples/cvat/exchange-oracle/src/handlers/job_export/exporters/vision.py index a3d67c7eb6..f3706b8693 100644 --- a/packages/examples/cvat/exchange-oracle/src/handlers/job_export.py +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_export/exporters/vision.py @@ -1,27 +1,48 @@ +"""Image task exporters. + +Each exporter owns both the orchestration (download annotations, upload results, notify the +recording oracle) and its task-specific datumaro postprocessing. ``ImageJobExporter`` holds the +shared export flow + the generic CVAT->datumaro conversion pipeline; per-task subclasses override +only the parts that differ. +""" + +from __future__ import annotations + import io import os import zipfile -from collections.abc import Sequence -from dataclasses import dataclass from tempfile import TemporaryDirectory +from typing import TYPE_CHECKING import datumaro as dm -from datumaro.components.dataset import Dataset import src.core.tasks.boxes_from_points as boxes_from_points_task import src.core.tasks.skeletons_from_boxes as skeletons_from_boxes_task +import src.services.cvat as cvat_service import src.utils.annotations as annotation_utils -from src.core.annotation_meta import ANNOTATION_RESULTS_METAFILE_NAME, AnnotationMeta, JobMeta +from src.core.annotation_meta import RESULTING_ANNOTATIONS_FILE from src.core.config import Config -from src.core.manifest import TaskManifest +from src.core.manifest import get_manifest_task_type from src.core.storage import compose_data_bucket_filename -from src.core.types import TaskTypes -from src.handlers.job_creation import DM_DATASET_FORMAT_MAPPING -from src.models.cvat import Image, Job +from src.core.tasks import TaskTypes +from src.core.tasks.cvat_formats import DM_DATASET_FORMAT_MAPPING +from src.handlers.job_export.downloading import ( + download_job_annotations, + download_project_annotations, +) +from src.handlers.job_export.exporters.base import JobExporter +from src.handlers.job_export.results import FileDescriptor, prepare_annotation_metafile from src.services.cloud import make_client as make_cloud_client from src.services.cloud.utils import BucketAccessInfo from src.utils.zip_archive import extract_zip_archive, write_dir_to_zip_archive +if TYPE_CHECKING: + from collections.abc import Sequence + + from datumaro.components.dataset import Dataset + + from src.models.cvat import Image + CVAT_EXPORT_FORMAT_MAPPING = { TaskTypes.image_label_binary: "CVAT for images 1.1", TaskTypes.image_points: "CVAT for images 1.1", @@ -37,65 +58,111 @@ } -@dataclass -class FileDescriptor: - filename: str - file: io.RawIOBase | None +class ImageJobExporter(JobExporter): + """Base image exporter: download the single project + per-job annotations, run the datumaro + conversion pipeline, upload the results, and notify the recording oracle.""" + + def export(self) -> None: + escrow_address = self.escrow_address + chain_id = self.chain_id + + escrow_creation = cvat_service.get_escrow_creation_by_escrow_address( + self.session, escrow_address, chain_id, active=False + ) + if not escrow_creation: + raise AssertionError(f"Can't find escrow creation for escrow '{escrow_address}'") + + jobs = cvat_service.get_jobs_by_escrow_address(self.session, escrow_address, chain_id) + if len(jobs) != escrow_creation.total_jobs: + raise AssertionError( + f"Unexpected number of jobs fetched for escrow " + f"'{escrow_address}': {len(jobs)}, expected {escrow_creation.total_jobs}" + ) + + self.logger.debug(f"Downloading results for the escrow ({escrow_address=})") + + annotation_format = self._annotation_format + # FUTURE-TODO: probably can be removed in the future since + # these annotations are no longer used in Recording Oracle + job_annotations = download_job_annotations(self.logger, annotation_format, jobs) + + project_annotations_file, project_images = self._collect_project_annotations( + annotation_format + ) + + resulting_annotations_file_desc = FileDescriptor( + filename=RESULTING_ANNOTATIONS_FILE, + file=project_annotations_file, + ) + annotations = (resulting_annotations_file_desc, *job_annotations.values()) + + self.logger.debug(f"Postprocessing results for the escrow ({escrow_address=})") + + self._merged_annotation_file = resulting_annotations_file_desc + self._project_images = project_images + self._prepare() + self._postprocess(annotations) + self.logger.debug(f"Uploading annotations for the escrow ({escrow_address=})") -def prepare_annotation_metafile(jobs: list[Job]) -> FileDescriptor: - """ - Prepares a task/project annotation descriptor file with annotator mapping. - """ + self._upload_results(files=(*annotations, prepare_annotation_metafile(jobs=jobs))) - meta = AnnotationMeta( - jobs=[ - JobMeta( - job_id=job.cvat_id, - annotator_wallet_address=job.latest_assignment.user_wallet_address, - assignment_id=job.latest_assignment.id, - task_id=job.cvat_task_id, - start_frame=job.start_frame, - stop_frame=job.stop_frame, + self._emit_escrow_recorded() + + self.logger.info( + f"The escrow ({escrow_address=}) is completed, " + f"resulting annotations are processed successfully" + ) + + # -- formats ----------------------------------------------------------- # + + @property + def _task_type(self) -> TaskTypes: + return get_manifest_task_type(self.manifest) + + @property + def _annotation_format(self) -> str: + return CVAT_EXPORT_FORMAT_MAPPING[self._task_type] + + @property + def _input_format(self) -> str: + return CVAT_EXPORT_FORMAT_TO_DM_MAPPING[self._annotation_format] + + @property + def _output_format(self) -> str: + return DM_DATASET_FORMAT_MAPPING[self._task_type] + + # -- project annotations ----------------------------------------------- # + + def _collect_project_annotations( + self, annotation_format: str + ) -> tuple[io.RawIOBase | None, list[Image] | None]: + # escrows with simple task types must have only one project + try: + (project,) = self.escrow_projects + except ValueError: + raise NotImplementedError( + f"{self._task_type} is expected to have exactly one project," + f" not {len(self.escrow_projects)}" ) - for job in jobs - ] - ) - - return FileDescriptor( - ANNOTATION_RESULTS_METAFILE_NAME, file=io.BytesIO(meta.model_dump_json().encode()) - ) - - -class _TaskProcessor: - def __init__( - self, - escrow_address: str, - chain_id: int, - annotations: Sequence[FileDescriptor], - merged_annotation: FileDescriptor, - *, - manifest: TaskManifest, - project_images: list[Image], - ) -> None: - self.escrow_address = escrow_address - self.chain_id = chain_id - self.annotation_files = annotations - self.merged_annotation_file = merged_annotation - self.manifest = manifest - self.project_images = project_images - - self.input_format = CVAT_EXPORT_FORMAT_TO_DM_MAPPING[ - CVAT_EXPORT_FORMAT_MAPPING[manifest.annotation.type] - ] - self.output_format = DM_DATASET_FORMAT_MAPPING[manifest.annotation.type] - def _is_merged_dataset(self, ann_descriptor: FileDescriptor) -> bool: - return ann_descriptor == self.merged_annotation_file + project_annotations_file = download_project_annotations( + self.logger, annotation_format, project.cvat_id + ) + project_images = cvat_service.get_project_images(self.session, project.cvat_id) + return project_annotations_file, project_images + + # -- datumaro conversion pipeline -------------------------------------- # + + def _prepare(self) -> None: + """Download any task-specific meta needed for postprocessing (default: nothing).""" - def process(self): + def _postprocess(self, annotations: Sequence[FileDescriptor]) -> None: + self._run_pipeline(annotations) + + def _run_pipeline(self, annotations: Sequence[FileDescriptor]) -> None: with TemporaryDirectory() as tempdir: - for ann_descriptor in self.annotation_files: + for ann_descriptor in annotations: if not zipfile.is_zipfile(ann_descriptor.file): raise ValueError("Annotation files must be zip files") ann_descriptor.file.seek(0) @@ -119,6 +186,9 @@ def process(self): ann_descriptor.file = converted_dataset_archive + def _is_merged_dataset(self, ann_descriptor: FileDescriptor) -> bool: + return ann_descriptor == self._merged_annotation_file + def _process_annotation_file( self, ann_descriptor: FileDescriptor, input_dir: str, output_dir: str ): @@ -127,10 +197,10 @@ def _process_annotation_file( self._export_dataset(output_dataset, output_dir) def _parse_dataset(self, ann_descriptor: FileDescriptor, dataset_dir: str) -> dm.Dataset: # noqa: ARG002 - return dm.Dataset.import_from(dataset_dir, self.input_format) + return dm.Dataset.import_from(dataset_dir, self._input_format) def _export_dataset(self, dataset: dm.Dataset, output_dir: str): - dataset.export(output_dir, self.output_format, save_media=False) + dataset.export(output_dir, self._output_format, save_media=False) def _process_dataset( self, dataset: dm.Dataset, *, ann_descriptor: FileDescriptor @@ -149,23 +219,23 @@ def _process_dataset( def _process_merged_dataset(self, input_dataset: dm.Dataset) -> dm.Dataset: return annotation_utils.remove_duplicated_gt_frames( input_dataset, - known_frames=[image.filename for image in self.project_images], + known_frames=[image.filename for image in self._project_images], ) -class _LabelsTaskProcessor(_TaskProcessor): +class LabelsJobExporter(ImageJobExporter): pass -class _BoxesTaskProcessor(_TaskProcessor): +class BoxesJobExporter(ImageJobExporter): pass -class _PolygonsTaskProcessor(_TaskProcessor): +class PolygonsJobExporter(ImageJobExporter): pass -class _PointsTaskProcessor(_TaskProcessor): +class PointsJobExporter(ImageJobExporter): def _parse_dataset(self, ann_descriptor: FileDescriptor, dataset_dir: str) -> Dataset: annotation_utils.prepare_cvat_annotations_for_dm(dataset_dir) return super()._parse_dataset(ann_descriptor, dataset_dir) @@ -182,10 +252,8 @@ def _process_dataset(self, dataset: Dataset, *, ann_descriptor: FileDescriptor) return super()._process_dataset(dataset, ann_descriptor=ann_descriptor) -class _BoxesFromPointsTaskProcessor(_TaskProcessor): - def __init__(self, *args, **kwargs) -> None: - super().__init__(*args, **kwargs) - +class BoxesFromPointsJobExporter(ImageJobExporter): + def _prepare(self) -> None: roi_filenames, roi_infos, points_dataset = self._download_task_meta() self.points_dataset = points_dataset @@ -288,10 +356,17 @@ def _process_merged_dataset(self, input_dataset: Dataset) -> Dataset: return merged_sample_dataset -class _SkeletonsFromBoxesTaskProcessor(_TaskProcessor): - def __init__(self, *args, **kwargs) -> None: - super().__init__(*args, **kwargs) +class SkeletonsJobExporter(ImageJobExporter): + # Reconstruct skeletons from per-point annotation jobs + def _collect_project_annotations( + self, annotation_format: str + ) -> tuple[io.RawIOBase | None, list[Image] | None]: + assert self.escrow_projects # unused, but must hold the lock + del annotation_format # the jobs are self-merged, no project export + return None, None + + def _prepare(self) -> None: roi_filenames, roi_infos, boxes_dataset, job_label_mapping = self._download_task_meta() self.boxes_dataset = boxes_dataset @@ -559,22 +634,19 @@ def _process_dataset(self, dataset: Dataset, *, ann_descriptor: FileDescriptor) def _process_merged_dataset(self, merged_dataset: Dataset) -> Dataset: return merged_dataset - def process(self): - assert self.merged_annotation_file.file is None + def _postprocess(self, annotations: Sequence[FileDescriptor]) -> None: + assert self._merged_annotation_file.file is None # Accumulate points from separate job annotations, then export the resulting dataset self._init_merged_dataset() - self.annotation_files = [ - fd for fd in self.annotation_files if not self._is_merged_dataset(fd) - ] - super().process() - self.annotation_files.append(self.merged_annotation_file) + job_files = [fd for fd in annotations if not self._is_merged_dataset(fd)] + self._run_pipeline(job_files) with TemporaryDirectory() as tempdir: export_dir = os.path.join( tempdir, - os.path.splitext(os.path.basename(self.merged_annotation_file.filename))[0] + os.path.splitext(os.path.basename(self._merged_annotation_file.filename))[0] + "_conv", ) @@ -585,37 +657,4 @@ def process(self): write_dir_to_zip_archive(export_dir, converted_dataset_archive) converted_dataset_archive.seek(0) - self.merged_annotation_file.file = converted_dataset_archive - - -def postprocess_annotations( - escrow_address: str, - chain_id: int, - annotations: Sequence[FileDescriptor], - merged_annotation: FileDescriptor, - *, - manifest: TaskManifest, - project_images: list[Image], -) -> None: - """ - Processes annotations and updates the files list inplace - """ - processor_classes: dict[TaskTypes, type[_TaskProcessor]] = { - TaskTypes.image_label_binary: _LabelsTaskProcessor, - TaskTypes.image_boxes: _BoxesTaskProcessor, - TaskTypes.image_polygons: _PolygonsTaskProcessor, - TaskTypes.image_points: _PointsTaskProcessor, - TaskTypes.image_boxes_from_points: _BoxesFromPointsTaskProcessor, - TaskTypes.image_skeletons_from_boxes: _SkeletonsFromBoxesTaskProcessor, - } - - task_type = manifest.annotation.type - processor = processor_classes[task_type]( - escrow_address=escrow_address, - chain_id=chain_id, - annotations=annotations, - merged_annotation=merged_annotation, - manifest=manifest, - project_images=project_images, - ) - processor.process() + self._merged_annotation_file.file = converted_dataset_archive diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_export/handlers.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_export/handlers.py new file mode 100644 index 0000000000..af6fc8006e --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_export/handlers.py @@ -0,0 +1,39 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +import src.services.cvat as cvat_service +from src.chain.escrow import get_escrow_manifest, validate_escrow +from src.core.manifest import parse_manifest +from src.db.utils import ForUpdateParams +from src.handlers.job_export.exporters.factory import create_exporter + +if TYPE_CHECKING: + import logging + + from sqlalchemy.orm import Session + + +def handle_escrow_export( + logger: logging.Logger, + session: Session, + escrow_address: str, + chain_id: int, +) -> None: + validate_escrow(chain_id, escrow_address) + + escrow_projects = cvat_service.get_projects_by_escrow_address( + session, escrow_address, limit=None, for_update=ForUpdateParams(nowait=True) + ) + + manifest = parse_manifest(get_escrow_manifest(chain_id, escrow_address)) + + with create_exporter( + manifest=manifest, + escrow_address=escrow_address, + chain_id=chain_id, + session=session, + escrow_projects=escrow_projects, + ) as exporter: + exporter.set_logger(logger) + exporter.export() diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_export/results.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_export/results.py new file mode 100644 index 0000000000..05ef3492ea --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_export/results.py @@ -0,0 +1,82 @@ +"""Shared result/metafile primitives for escrow export and validation flows.""" + +from __future__ import annotations + +import io +from dataclasses import dataclass +from typing import TYPE_CHECKING + +import src.services.cloud as cloud_service +from src.core.annotation_meta import ( + ANNOTATION_RESULTS_METAFILE_NAME, + RESULTING_ANNOTATIONS_FILE, + AnnotationMeta, + JobMeta, +) +from src.core.config import StorageConfig +from src.core.storage import compose_results_bucket_filename +from src.services.cloud.types import BucketAccessInfo + +if TYPE_CHECKING: + from collections.abc import Sequence + + from src.models.cvat import Job + + +@dataclass +class FileDescriptor: + filename: str + file: io.RawIOBase | None + + +def prepare_annotation_metafile(jobs: list[Job]) -> FileDescriptor: + """ + Prepares a task/project annotation descriptor file with annotator mapping. + """ + + meta = AnnotationMeta( + jobs=[ + JobMeta( + job_id=job.cvat_id, + annotator_wallet_address=job.latest_assignment.user_wallet_address, + assignment_id=job.latest_assignment.id, + task_id=job.cvat_task_id, + start_frame=job.start_frame, + stop_frame=job.stop_frame, + ) + for job in jobs + ] + ) + + return FileDescriptor( + ANNOTATION_RESULTS_METAFILE_NAME, file=io.BytesIO(meta.model_dump_json().encode()) + ) + + +def upload_escrow_results( + files: Sequence[FileDescriptor], chain_id: int, escrow_address: str +) -> None: + storage_info = BucketAccessInfo.parse_obj(StorageConfig) + storage_client = cloud_service.make_client(storage_info) + + # always update annotation meta and resulting annotations files + # to have actual data for the current epoch + existing_storage_files = set( + storage_client.list_files( + prefix=compose_results_bucket_filename(escrow_address, chain_id, ""), + trim_prefix=True, + ) + ) - {ANNOTATION_RESULTS_METAFILE_NAME, RESULTING_ANNOTATIONS_FILE} + + for file_descriptor in files: + if file_descriptor.filename in existing_storage_files: + continue + + storage_client.create_file( + compose_results_bucket_filename( + escrow_address, + chain_id, + file_descriptor.filename, + ), + file_descriptor.file.read(), + ) diff --git a/packages/examples/cvat/exchange-oracle/src/models/__init__.py b/packages/examples/cvat/exchange-oracle/src/models/__init__.py index e69de29bb2..fcb2784788 100644 --- a/packages/examples/cvat/exchange-oracle/src/models/__init__.py +++ b/packages/examples/cvat/exchange-oracle/src/models/__init__.py @@ -0,0 +1,27 @@ +from src.models.cvat import ( + Assignment, + CvatWebhook, + DataUpload, + EscrowCreation, + EscrowValidation, + Image, + Job, + Project, + Task, + User, +) +from src.models.webhook import Webhook + +__all__ = [ + "Assignment", + "CvatWebhook", + "DataUpload", + "EscrowCreation", + "EscrowValidation", + "Image", + "Job", + "Project", + "Task", + "User", + "Webhook", +] diff --git a/packages/examples/cvat/exchange-oracle/src/models/cvat.py b/packages/examples/cvat/exchange-oracle/src/models/cvat.py index dd0eb2d715..8d6dcfaae5 100644 --- a/packages/examples/cvat/exchange-oracle/src/models/cvat.py +++ b/packages/examples/cvat/exchange-oracle/src/models/cvat.py @@ -5,6 +5,7 @@ from sqlalchemy.orm import Mapped, relationship from sqlalchemy.sql import func +from src.core.tasks import TaskTypes from src.core.types import ( AssignmentStatuses, CvatWebhookStatuses, @@ -13,7 +14,6 @@ Networks, ProjectStatuses, TaskStatuses, - TaskTypes, ) from src.db import Base, BaseUUID, ChildOf from src.utils.time import utcnow @@ -30,6 +30,7 @@ class Project(BaseUUID): ) # TODO: extract into a separate model chain_id = Column(Integer, Enum(Networks), nullable=False) bucket_url = Column(String, nullable=False) + assignment_bounty = Column(String, nullable=True) created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) cvat_webhook_id = Column(Integer, nullable=True) diff --git a/packages/examples/cvat/exchange-oracle/src/schemas/exchange.py b/packages/examples/cvat/exchange-oracle/src/schemas/exchange.py index 73fde0d230..bd611a36dd 100644 --- a/packages/examples/cvat/exchange-oracle/src/schemas/exchange.py +++ b/packages/examples/cvat/exchange-oracle/src/schemas/exchange.py @@ -1,11 +1,10 @@ from datetime import datetime -from enum import Enum from pydantic import BaseModel, Field -from strenum import StrEnum # added in python 3.11 -from src.core.types import Networks, TaskTypes -from src.utils.enums import BetterEnumMeta +from src.core.tasks import TaskTypes +from src.core.types import Networks +from src.utils.enums import BetterEnumMeta, StrEnum class JobStatuses(StrEnum, metaclass=BetterEnumMeta): @@ -41,7 +40,7 @@ class AssignmentIdRequest(BaseModel): assignment_id: str -class AssignmentStatuses(str, Enum, metaclass=BetterEnumMeta): +class AssignmentStatuses(StrEnum, metaclass=BetterEnumMeta): active = "active" validation = "validation" completed = "completed" diff --git a/packages/examples/cvat/exchange-oracle/src/services/cloud/types.py b/packages/examples/cvat/exchange-oracle/src/services/cloud/types.py index 41ca984fa0..804032c6aa 100644 --- a/packages/examples/cvat/exchange-oracle/src/services/cloud/types.py +++ b/packages/examples/cvat/exchange-oracle/src/services/cloud/types.py @@ -10,8 +10,8 @@ import pydantic from httpx import URL -from src.core import manifest from src.core.config import Config, StorageConfig +from src.core.manifest.shared import BucketUrl, BucketUrlBase from src.services.cloud.gcs import DEFAULT_GCS_HOST from src.services.cloud.s3 import DEFAULT_S3_HOST from src.utils.enums import BetterEnumMeta @@ -174,14 +174,14 @@ def from_storage_config(cls, config: type[StorageConfig]) -> BucketAccessInfo: ) @classmethod - def from_bucket_url(cls, bucket_url: manifest.BucketUrl) -> BucketAccessInfo: + def from_bucket_url(cls, bucket_url: BucketUrl) -> BucketAccessInfo: return cls._from_dict(bucket_url.model_dump()) @classmethod def parse_obj( - cls, data: str | type[StorageConfig] | manifest.BucketUrl | pydantic.AnyUrl + cls, data: str | type[StorageConfig] | BucketUrl | pydantic.AnyUrl ) -> BucketAccessInfo: - if isinstance(data, manifest.BucketUrlBase): + if isinstance(data, BucketUrlBase): return cls.from_bucket_url(data) elif isinstance(data, str): return cls.from_url(data) diff --git a/packages/examples/cvat/exchange-oracle/src/services/cvat.py b/packages/examples/cvat/exchange-oracle/src/services/cvat.py index 083b1e8efc..18c31d7f9c 100644 --- a/packages/examples/cvat/exchange-oracle/src/services/cvat.py +++ b/packages/examples/cvat/exchange-oracle/src/services/cvat.py @@ -15,6 +15,7 @@ from sqlalchemy.sql.functions import coalesce from src.core.config import Config +from src.core.tasks import TaskTypes from src.core.types import ( AssignmentStatuses, CvatWebhookStatuses, @@ -22,7 +23,6 @@ JobStatuses, ProjectStatuses, TaskStatuses, - TaskTypes, ) from src.db import Base, ChildOf from src.db import engine as db_engine @@ -54,6 +54,7 @@ def batched(iterable: Iterable, *, batch_size: int) -> Iterable[Any]: def create_project( session: Session, cvat_id: int, + *, cvat_cloudstorage_id: int, job_type: str, escrow_address: str, @@ -61,6 +62,7 @@ def create_project( bucket_url: str, cvat_webhook_id: int | None = None, status: ProjectStatuses = ProjectStatuses.creation, + assignment_bounty: str | None = None, ) -> str: """ Create a project from CVAT. @@ -76,6 +78,7 @@ def create_project( chain_id=chain_id, bucket_url=bucket_url, cvat_webhook_id=cvat_webhook_id, + assignment_bounty=assignment_bounty, ) session.add(project) @@ -789,9 +792,9 @@ def put_user(session: Session, wallet_address: str, cvat_email: str, cvat_id: in """ Bind a CVAT username to a HUMAN App user """ - assert not ( - bool(cvat_email) ^ bool(cvat_id) - ), "cvat_email and cvat_id cannot be used separately" + assert not (bool(cvat_email) ^ bool(cvat_id)), ( + "cvat_email and cvat_id cannot be used separately" + ) user = User(wallet_address=wallet_address, cvat_email=cvat_email, cvat_id=cvat_id) @@ -1181,9 +1184,9 @@ def get_pending_webhooks( limit: int = 10, for_update: bool | ForUpdateParams = False, ) -> list[CvatWebhook]: - assert not ( - event_type_in and event_type_not_in - ), f"{event_type_in} and {event_type_not_in} cannot be used together" + assert not (event_type_in and event_type_not_in), ( + f"{event_type_in} and {event_type_not_in} cannot be used together" + ) return ( _maybe_for_update(session.query(CvatWebhook), enable=for_update) diff --git a/packages/examples/cvat/exchange-oracle/src/services/exchange.py b/packages/examples/cvat/exchange-oracle/src/services/exchange.py index 5fdf0c854b..540cc3942c 100644 --- a/packages/examples/cvat/exchange-oracle/src/services/exchange.py +++ b/packages/examples/cvat/exchange-oracle/src/services/exchange.py @@ -4,11 +4,12 @@ import src.cvat.api_calls as cvat_api import src.services.cvat as cvat_service from src.chain.escrow import get_escrow_manifest -from src.core.types import JobStatuses, Networks, ProjectStatuses, TaskTypes +from src.core.manifest import parse_manifest +from src.core.types import JobStatuses, Networks, ProjectStatuses from src.db import SessionLocal from src.db.utils import ForUpdateParams from src.models.cvat import Job -from src.utils.assignments import get_default_assignment_timeout, parse_manifest +from src.utils.assignments import get_assignment_timeout from src.utils.requests import get_or_404 from src.utils.time import utcnow @@ -16,8 +17,7 @@ class UserHasUnfinishedAssignmentError(Exception): def __str__(self) -> str: return ( - "There are unfinished assignments in this escrow. " - "Please complete or resign them first." + "There are unfinished assignments in this escrow. Please complete or resign them first." ) @@ -51,9 +51,7 @@ def create_assignment( "The user already has an unfinished assignment in this project" ) - # TODO: Try to put into 1 request. SQLAlchemy generates 2 queries with simple - # .options(selectinload(Job.project)) - project = get_or_404( + get_or_404( cvat_service.get_project_by_escrow_address( session, escrow_address, status_in=[ProjectStatuses.annotation] ), @@ -79,13 +77,7 @@ def create_assignment( session, wallet_address=user.wallet_address, cvat_job_id=unassigned_job.cvat_id, - expires_at=utcnow() - + timedelta( - seconds=get_default_assignment_timeout( - TaskTypes(project.job_type) - # TODO: need to update this if we have multiple job types per escrow - ) - ), + expires_at=utcnow() + timedelta(seconds=get_assignment_timeout(manifest)), ) cvat_service.update_job_status(session, unassigned_job.id, status=JobStatuses.in_progress) diff --git a/packages/examples/cvat/exchange-oracle/src/services/webhook.py b/packages/examples/cvat/exchange-oracle/src/services/webhook.py index 98e86d8f9e..ff9d1807bc 100644 --- a/packages/examples/cvat/exchange-oracle/src/services/webhook.py +++ b/packages/examples/cvat/exchange-oracle/src/services/webhook.py @@ -1,7 +1,6 @@ import datetime import uuid from collections.abc import Sequence -from enum import Enum from attrs import define from sqlalchemy import case, update @@ -14,11 +13,11 @@ from src.db.utils import ForUpdateParams from src.db.utils import maybe_for_update as _maybe_for_update from src.models.webhook import Webhook -from src.utils.enums import BetterEnumMeta +from src.utils.enums import BetterEnumMeta, StrEnum from src.utils.time import utcnow -class OracleWebhookDirectionTags(str, Enum, metaclass=BetterEnumMeta): +class OracleWebhookDirectionTags(StrEnum, metaclass=BetterEnumMeta): incoming = "incoming" outgoing = "outgoing" @@ -43,9 +42,9 @@ def create_webhook( Creates a webhook in a database """ assert not event_data or event_type, "'event_data' requires 'event_type'" - assert bool(event) ^ bool( - event_type - ), "'event' and 'event_type' cannot be used together. Please use only one of the fields" + assert bool(event) ^ bool(event_type), ( + "'event' and 'event_type' cannot be used together. Please use only one of the fields" + ) if event_type: if self.direction == OracleWebhookDirectionTags.incoming: @@ -97,9 +96,9 @@ def get_pending_webhooks( limit: int = 10, for_update: bool | ForUpdateParams = False, ) -> list[Webhook]: - assert not ( - event_type_in and event_type_not_in - ), f"{event_type_in} and {event_type_not_in} cannot be used together" + assert not (event_type_in and event_type_not_in), ( + f"{event_type_in} and {event_type_not_in} cannot be used together" + ) return ( _maybe_for_update(session.query(Webhook), enable=for_update) diff --git a/packages/examples/cvat/exchange-oracle/src/utils/annotations.py b/packages/examples/cvat/exchange-oracle/src/utils/annotations.py index 110ec2b069..c92d29e4c3 100644 --- a/packages/examples/cvat/exchange-oracle/src/utils/annotations.py +++ b/packages/examples/cvat/exchange-oracle/src/utils/annotations.py @@ -318,7 +318,7 @@ def _make_label_id_map(self, src_label_cat, dst_label_cat): src_id: dst_label_cat.find(src_label_cat[src_id].name, src_label_cat[src_id].parent)[0] for src_id in range(len(src_label_cat or ())) } - self._map_id = lambda src_id: id_mapping.get(src_id) + self._map_id = id_mapping.get def categories(self): return self._categories diff --git a/packages/examples/cvat/exchange-oracle/src/utils/assignments.py b/packages/examples/cvat/exchange-oracle/src/utils/assignments.py index 51c8fe9c7b..23292bdf78 100644 --- a/packages/examples/cvat/exchange-oracle/src/utils/assignments.py +++ b/packages/examples/cvat/exchange-oracle/src/utils/assignments.py @@ -1,14 +1,15 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING from urllib.parse import urljoin from src.core.config import Config -from src.core.manifest import TaskManifest, TaskTypes -from src.core.manifest import parse_manifest as _parse_manifest -from src.core.tasks import skeletons_from_boxes -from src.models.cvat import Project - +from src.core.manifest import get_manifest_task_type +from src.core.tasks import TaskTypes, skeletons_from_boxes -def parse_manifest(manifest: dict) -> TaskManifest: - return _parse_manifest(manifest) +if TYPE_CHECKING: + from src.core.manifest import ManifestBase + from src.models.cvat import Project def compose_assignment_url(task_id: int, job_id: int, *, project: Project) -> str: @@ -36,10 +37,13 @@ def get_default_assignment_timeout(task_type: TaskTypes) -> int: return timeout_seconds -def get_default_assignment_size(manifest: TaskManifest) -> int: - job_size = manifest.annotation.job_size + manifest.validation.val_size - - if job_size == TaskTypes.image_skeletons_from_boxes: - job_size *= skeletons_from_boxes.DEFAULT_ASSIGNMENT_SIZE_MULTIPLIER +def get_assignment_timeout(manifest: ManifestBase) -> int: + """ + Get assignment expiration timeout, in seconds. + """ + details = getattr(getattr(manifest, "annotation", None), "details", None) + max_time = getattr(details, "max_time", None) + if max_time is not None: + return max_time - return job_size + return get_default_assignment_timeout(get_manifest_task_type(manifest)) diff --git a/packages/examples/cvat/exchange-oracle/src/utils/audio.py b/packages/examples/cvat/exchange-oracle/src/utils/audio.py new file mode 100644 index 0000000000..68ba456246 --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/src/utils/audio.py @@ -0,0 +1,124 @@ +"""ffmpeg/ffprobe helpers for audio task creation. + +ffmpeg and ffprobe must be available on PATH (system dependency). +Ported from the asr-qa-research prototype (experiments/pipeline_test/oracle.py::cut_clip). +""" + +from __future__ import annotations + +import subprocess +from dataclasses import dataclass +from datetime import timedelta +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from pathlib import Path + + +class FfmpegError(RuntimeError): + pass + + +@dataclass(frozen=True) +class RegionCut: + """A slice [start, stop) to take from a source media file.""" + + media: Path + start: timedelta + stop: timedelta + + @property + def duration(self) -> timedelta: + return self.stop - self.start + + +def probe_duration(path: Path) -> timedelta: + """Return media duration in seconds""" + + cmd = [ + "ffprobe", + "-v", + "error", + "-show_entries", + "format=duration", + "-of", + "csv=p=0", + str(path), + ] + result = subprocess.run(cmd, capture_output=True, text=True, check=False) # noqa: S603 + if result.returncode != 0: + raise FfmpegError(f"ffprobe failed for {path}:\n{result.stderr[-800:]}") + + return timedelta(seconds=float(result.stdout.strip())) + + +def cut_and_concat( + regions: list[RegionCut], + out_path: Path, + *, + pause_ms: int, + sample_rate: int, +) -> None: + """ + Trim each region from its own media and concatenate them into a single mono clip, + separated by ``pause_ms`` of silence. Output is ``sample_rate`` Hz mono WAV. + + Assignments mix regions from multiple source files, so each region is trimmed from its + own input (distinct medias map to distinct ffmpeg input indices). + """ + if not regions: + raise ValueError("cut_and_concat requires at least one region") + + out_path.parent.mkdir(parents=True, exist_ok=True) + pause_s = pause_ms / 1000.0 + + # distinct source files -> ffmpeg input indices + medias: list[Path] = [] + idx_of: dict[str, int] = {} + for region in regions: + key = str(region.media) + if key not in idx_of: + idx_of[key] = len(medias) + medias.append(region.media) + + filter_parts: list[str] = [] + segment_labels: list[str] = [] + n = len(regions) + for i, region in enumerate(regions): + inp = idx_of[str(region.media)] + filter_parts.append( + f"[{inp}:a]atrim={region.start.total_seconds():.3f}:{region.stop.total_seconds():.3f}," + "asetpts=PTS-STARTPTS," + f"aresample={sample_rate},aformat=channel_layouts=mono[s{i}]" + ) + segment_labels.append(f"[s{i}]") + if i < n - 1: + filter_parts.append(f"aevalsrc=0:d={pause_s}:s={sample_rate}[g{i}]") + segment_labels.append(f"[g{i}]") + + filter_parts.append("".join(segment_labels) + f"concat=n={len(segment_labels)}:v=0:a=1[out]") + + inputs: list[str] = [] + for media in medias: + inputs += ["-i", str(media)] + + cmd = [ + "ffmpeg", + "-y", + "-hide_banner", + "-v", + "error", + *inputs, + "-filter_complex", + ";".join(filter_parts), + "-map", + "[out]", + "-ar", + str(sample_rate), + "-ac", + "1", + str(out_path), + ] + result = subprocess.run(cmd, capture_output=True, text=True, check=False) # noqa: S603 + if result.returncode != 0: + raise FfmpegError(f"ffmpeg cut/concat failed for {out_path}:\n{result.stderr[-800:]}") diff --git a/packages/examples/cvat/exchange-oracle/src/utils/enums.py b/packages/examples/cvat/exchange-oracle/src/utils/enums.py index d4c133b0e5..b069d48158 100644 --- a/packages/examples/cvat/exchange-oracle/src/utils/enums.py +++ b/packages/examples/cvat/exchange-oracle/src/utils/enums.py @@ -1,5 +1,12 @@ from enum import EnumMeta +from strenum import StrEnum # added in python 3.11 + +__all__ = [ + "BetterEnumMeta", + "StrEnum", +] + class BetterEnumMeta(EnumMeta): """ diff --git a/packages/examples/cvat/exchange-oracle/tests/api/test_cvat_webhook_api.py b/packages/examples/cvat/exchange-oracle/tests/api/test_cvat_webhook_api.py index e177648232..ce1e758d41 100644 --- a/packages/examples/cvat/exchange-oracle/tests/api/test_cvat_webhook_api.py +++ b/packages/examples/cvat/exchange-oracle/tests/api/test_cvat_webhook_api.py @@ -1,3 +1,4 @@ +import json from datetime import timedelta from fastapi.testclient import TestClient @@ -22,10 +23,14 @@ def test_ping_incoming_webhook(client: TestClient) -> None: # Should respond with 200 status to a "ping" event + body = json.dumps(PING_EVENT_DATA).encode() response = client.post( "/cvat-webhook", - headers={"X-Signature-256": generate_cvat_signature(PING_EVENT_DATA)}, - json=PING_EVENT_DATA, + headers={ + "X-Signature-256": generate_cvat_signature(body), + "Content-Type": "application/json", + }, + content=body, ) assert response.status_code == 200 @@ -59,10 +64,14 @@ def test_can_accept_incoming_job_update_webhook(client: TestClient) -> None: "webhook_id": 1, } + body = json.dumps(data).encode() response = client.post( "/cvat-webhook", - headers={"X-Signature-256": generate_cvat_signature(data)}, - json=data, + headers={ + "X-Signature-256": generate_cvat_signature(body), + "Content-Type": "application/json", + }, + content=body, ) assert response.status_code == 200 diff --git a/packages/examples/cvat/exchange-oracle/tests/api/test_exchange_api.py b/packages/examples/cvat/exchange-oracle/tests/api/test_exchange_api.py index 71c812bc52..511a971907 100644 --- a/packages/examples/cvat/exchange-oracle/tests/api/test_exchange_api.py +++ b/packages/examples/cvat/exchange-oracle/tests/api/test_exchange_api.py @@ -15,7 +15,8 @@ from sqlalchemy.orm import Session from src.core.config import Config -from src.core.types import AssignmentStatuses, JobStatuses, ProjectStatuses, TaskTypes +from src.core.tasks import TaskTypes +from src.core.types import AssignmentStatuses, JobStatuses, ProjectStatuses from src.models.cvat import Assignment, Job, Project, Task, User from src.schemas.exchange import AssignmentStatuses as APIAssignmentStatuses from src.schemas.exchange import JobStatuses as APIJobStatuses @@ -174,7 +175,7 @@ def validate_result( session.commit() with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.endpoints.serializers.get_escrow_manifest") as mock_get_manifest, patch( "src.endpoints.serializers.get_escrow_fund_token_symbol" @@ -239,7 +240,7 @@ def test_can_list_jobs_200_without_escrows_in_hidden_states( session.commit() with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.endpoints.serializers.get_escrow_manifest") as mock_get_manifest, patch( "src.endpoints.serializers.get_escrow_fund_token_symbol" @@ -297,7 +298,7 @@ def test_can_list_jobs_200_with_only_one_entry_per_escrow_address_if_several_pro session.commit() with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.endpoints.serializers.get_escrow_manifest") as mock_get_manifest, patch( "src.endpoints.serializers.get_escrow_fund_token_symbol" @@ -337,7 +338,7 @@ def test_can_list_jobs_200_with_fields(client: TestClient, session: Session) -> session.commit() with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.endpoints.serializers.get_escrow_manifest") as mock_get_manifest, patch( "src.endpoints.serializers.get_escrow_fund_token_symbol" @@ -420,7 +421,7 @@ def test_can_list_jobs_200_with_sorting(client: TestClient, session: Session) -> } == {(obj.__class__.__name__, obj.id): True for obj in cvat_jobs + cvat_tasks + cvat_projects} with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.endpoints.serializers.get_escrow_manifest") as mock_get_manifest, patch( "src.endpoints.serializers.get_escrow_fund_token_symbol" @@ -540,7 +541,7 @@ def test_can_list_jobs_200_with_filters(client: TestClient, session: Session): post_init_time = utcnow() + timedelta(seconds=1) with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.endpoints.serializers.get_escrow_manifest") as mock_get_manifest, patch( "src.endpoints.serializers.get_escrow_fund_token_symbol" @@ -631,7 +632,7 @@ def test_can_list_jobs_200_can_show_only_active_jobs_with_free_assignments( session.commit() with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.endpoints.serializers.get_escrow_manifest") as mock_get_manifest, patch( "src.endpoints.serializers.get_escrow_fund_token_symbol" @@ -680,7 +681,7 @@ def test_can_list_jobs_200_check_values(client: TestClient, session: Session) -> session.commit() with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.endpoints.serializers.get_escrow_manifest") as mock_get_manifest, patch( "src.endpoints.serializers.get_escrow_fund_token_symbol" @@ -739,7 +740,7 @@ def test_can_list_jobs_200_without_address(client: TestClient, session: Session) session.commit() with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.endpoints.serializers.get_escrow_manifest") as mock_get_manifest, patch( "src.endpoints.serializers.get_escrow_fund_token_symbol" @@ -874,7 +875,7 @@ def test_can_create_assignment_200(client: TestClient, session: Session) -> None session.commit() with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.endpoints.serializers.get_escrow_manifest") as mock_serializer_get_manifest, patch("src.services.exchange.get_escrow_manifest") as mock_exchange_get_manifest, patch( @@ -979,7 +980,7 @@ def test_cannot_create_assignment_400_when_has_unfinished_assignments( session.commit() with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.services.exchange.get_escrow_manifest") as mock_get_manifest, ): manifest = json.load(data) @@ -1074,7 +1075,7 @@ def test_can_list_assignments_200(client: TestClient, session: Session) -> None: post_init_time = utcnow() + timedelta(seconds=1) with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.endpoints.serializers.get_escrow_manifest") as mock_get_manifest, patch( "src.endpoints.serializers.get_escrow_fund_token_symbol" @@ -1155,7 +1156,7 @@ def test_can_list_assignments_200_with_sorting(client: TestClient, session: Sess session.commit() with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.endpoints.serializers.get_escrow_manifest") as mock_get_manifest, patch( "src.endpoints.serializers.get_escrow_fund_token_symbol" @@ -1512,7 +1513,7 @@ def test_can_list_jobs_200_check_updated_at(client: TestClient, session: Session session.commit() with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.endpoints.serializers.get_escrow_manifest") as mock_serializer_get_manifest, patch("src.services.exchange.get_escrow_manifest") as mock_exchange_get_manifest, patch( @@ -1540,9 +1541,9 @@ def test_can_list_jobs_200_check_updated_at(client: TestClient, session: Session "chain_id": cvat_project.chain_id, }, ) - assert ( - response.status_code == 200 - ), f"Status: {response.status_code}, reason: {response.text}" + assert response.status_code == 200, ( + f"Status: {response.status_code}, reason: {response.text}" + ) response = client.get( "/job", diff --git a/packages/examples/cvat/exchange-oracle/tests/assets/cloud/manifests/audio_manifest.json b/packages/examples/cvat/exchange-oracle/tests/assets/cloud/manifests/audio_manifest.json new file mode 100644 index 0000000000..1b72a7f8cb --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/tests/assets/cloud/manifests/audio_manifest.json @@ -0,0 +1,28 @@ +{ + "version": 2, + "job_type": "audio_transcription", + "data": { + "media_url": "https://invalid/", + "regions_url": "https://invalid/", + "gt_url": "https://invalid/" + }, + "annotation": { + "description": "Audio transcription task", + "user_guide_url": "https://invalid/audio-transcription-guide.md", + "labels": [{ "name": "speech" }], + "shared_attributes": [], + "validation": { + "target_score": 0.5, + "target_metric": "wer" + }, + "qualifications": [], + "details": { + "max_time": 1800, + "normalizer": "basic", + "max_segment_duration": 120, + "min_gt_span_duration": 20, + "min_composition": { "gt": 2, "ds": 2 }, + "validation_overhead": 20 + } + } +} diff --git a/packages/examples/cvat/exchange-oracle/tests/utils/manifest.json b/packages/examples/cvat/exchange-oracle/tests/assets/cloud/manifests/manifest-v1.json similarity index 100% rename from packages/examples/cvat/exchange-oracle/tests/utils/manifest.json rename to packages/examples/cvat/exchange-oracle/tests/assets/cloud/manifests/manifest-v1.json diff --git a/packages/examples/cvat/exchange-oracle/tests/utils/datasets/gt_annotations_coco.zip b/packages/examples/cvat/exchange-oracle/tests/assets/datasets/gt_annotations_coco.zip similarity index 100% rename from packages/examples/cvat/exchange-oracle/tests/utils/datasets/gt_annotations_coco.zip rename to packages/examples/cvat/exchange-oracle/tests/assets/datasets/gt_annotations_coco.zip diff --git a/packages/examples/cvat/exchange-oracle/tests/utils/datasets/gt_annotations_coco/annotations/instances_default.json b/packages/examples/cvat/exchange-oracle/tests/assets/datasets/gt_annotations_coco/annotations/instances_default.json similarity index 100% rename from packages/examples/cvat/exchange-oracle/tests/utils/datasets/gt_annotations_coco/annotations/instances_default.json rename to packages/examples/cvat/exchange-oracle/tests/assets/datasets/gt_annotations_coco/annotations/instances_default.json diff --git a/packages/examples/cvat/exchange-oracle/tests/utils/datasets/img1.jpg b/packages/examples/cvat/exchange-oracle/tests/assets/datasets/img1.jpg similarity index 100% rename from packages/examples/cvat/exchange-oracle/tests/utils/datasets/img1.jpg rename to packages/examples/cvat/exchange-oracle/tests/assets/datasets/img1.jpg diff --git a/packages/examples/cvat/exchange-oracle/tests/utils/datasets/img10.jpg b/packages/examples/cvat/exchange-oracle/tests/assets/datasets/img10.jpg similarity index 100% rename from packages/examples/cvat/exchange-oracle/tests/utils/datasets/img10.jpg rename to packages/examples/cvat/exchange-oracle/tests/assets/datasets/img10.jpg diff --git a/packages/examples/cvat/exchange-oracle/tests/utils/datasets/img11.jpg b/packages/examples/cvat/exchange-oracle/tests/assets/datasets/img11.jpg similarity index 100% rename from packages/examples/cvat/exchange-oracle/tests/utils/datasets/img11.jpg rename to packages/examples/cvat/exchange-oracle/tests/assets/datasets/img11.jpg diff --git a/packages/examples/cvat/exchange-oracle/tests/utils/datasets/img12.jpg b/packages/examples/cvat/exchange-oracle/tests/assets/datasets/img12.jpg similarity index 100% rename from packages/examples/cvat/exchange-oracle/tests/utils/datasets/img12.jpg rename to packages/examples/cvat/exchange-oracle/tests/assets/datasets/img12.jpg diff --git a/packages/examples/cvat/exchange-oracle/tests/utils/datasets/img13.jpg b/packages/examples/cvat/exchange-oracle/tests/assets/datasets/img13.jpg similarity index 100% rename from packages/examples/cvat/exchange-oracle/tests/utils/datasets/img13.jpg rename to packages/examples/cvat/exchange-oracle/tests/assets/datasets/img13.jpg diff --git a/packages/examples/cvat/exchange-oracle/tests/utils/datasets/img2.jpg b/packages/examples/cvat/exchange-oracle/tests/assets/datasets/img2.jpg similarity index 100% rename from packages/examples/cvat/exchange-oracle/tests/utils/datasets/img2.jpg rename to packages/examples/cvat/exchange-oracle/tests/assets/datasets/img2.jpg diff --git a/packages/examples/cvat/exchange-oracle/tests/utils/datasets/img3.jpg b/packages/examples/cvat/exchange-oracle/tests/assets/datasets/img3.jpg similarity index 100% rename from packages/examples/cvat/exchange-oracle/tests/utils/datasets/img3.jpg rename to packages/examples/cvat/exchange-oracle/tests/assets/datasets/img3.jpg diff --git a/packages/examples/cvat/exchange-oracle/tests/utils/datasets/img4.jpg b/packages/examples/cvat/exchange-oracle/tests/assets/datasets/img4.jpg similarity index 100% rename from packages/examples/cvat/exchange-oracle/tests/utils/datasets/img4.jpg rename to packages/examples/cvat/exchange-oracle/tests/assets/datasets/img4.jpg diff --git a/packages/examples/cvat/exchange-oracle/tests/utils/datasets/img5.jpg b/packages/examples/cvat/exchange-oracle/tests/assets/datasets/img5.jpg similarity index 100% rename from packages/examples/cvat/exchange-oracle/tests/utils/datasets/img5.jpg rename to packages/examples/cvat/exchange-oracle/tests/assets/datasets/img5.jpg diff --git a/packages/examples/cvat/exchange-oracle/tests/utils/datasets/img6.jpg b/packages/examples/cvat/exchange-oracle/tests/assets/datasets/img6.jpg similarity index 100% rename from packages/examples/cvat/exchange-oracle/tests/utils/datasets/img6.jpg rename to packages/examples/cvat/exchange-oracle/tests/assets/datasets/img6.jpg diff --git a/packages/examples/cvat/exchange-oracle/tests/utils/datasets/img7.jpg b/packages/examples/cvat/exchange-oracle/tests/assets/datasets/img7.jpg similarity index 100% rename from packages/examples/cvat/exchange-oracle/tests/utils/datasets/img7.jpg rename to packages/examples/cvat/exchange-oracle/tests/assets/datasets/img7.jpg diff --git a/packages/examples/cvat/exchange-oracle/tests/utils/datasets/img8.jpg b/packages/examples/cvat/exchange-oracle/tests/assets/datasets/img8.jpg similarity index 100% rename from packages/examples/cvat/exchange-oracle/tests/utils/datasets/img8.jpg rename to packages/examples/cvat/exchange-oracle/tests/assets/datasets/img8.jpg diff --git a/packages/examples/cvat/exchange-oracle/tests/utils/datasets/img9.jpg b/packages/examples/cvat/exchange-oracle/tests/assets/datasets/img9.jpg similarity index 100% rename from packages/examples/cvat/exchange-oracle/tests/utils/datasets/img9.jpg rename to packages/examples/cvat/exchange-oracle/tests/assets/datasets/img9.jpg diff --git a/packages/examples/cvat/exchange-oracle/tests/assets/utils/gen_audio_validation_fixture.py b/packages/examples/cvat/exchange-oracle/tests/assets/utils/gen_audio_validation_fixture.py new file mode 100644 index 0000000000..1602908a24 --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/tests/assets/utils/gen_audio_validation_fixture.py @@ -0,0 +1,152 @@ +"""Regenerate the recording-oracle audio-validation fixture. + +Recording Oracle validates audio-transcription assignments against the metadata the exchange oracle +produces during task creation. + +Run this script whenever the builder output layout or the shared audio task setup +(``tests.utils.audio_transcription``) changes. + +Easiest is to run it inside the test suite container. It reuses the test service, and writes the +fixture to a mounted output dir. Call from the exchange-oracle dir: + + docker compose -p eo-test \ + -f docker-compose.test.yml \\ -f docker-compose.test.head.yml \\ -f + docker-compose.test.head.dev.yml \\ run --rm \\ -v + "$(pwd)/../recording-oracle/tests/assets/cloud/audio_validation:/out" \\ test sh -c "alembic + upgrade head && PYTHONPATH=. \ + python tests/assets/utils/gen_audio_validation_fixture.py /out" + +If you want to run it directly, launch the test services, export the same env vars the test service +sets (see docker-compose.test.head.yml), apply migrations (``alembic upgrade head``), then: + + PYTHONPATH=. python tests/assets/utils/gen_audio_validation_fixture.py [OUTPUT_DIR] +""" + +from __future__ import annotations + +import tempfile +from pathlib import Path + +INPUT_BUCKET = "datasets" +INPUT_PREFIX = "audio_validation_fixture" + +# The manifest the fixture is built from, vendored alongside it for the RO test. +MANIFEST_FILENAME = "manifest.json" + +# Default output: the RO assets tree, resolved relative to this file +# (exchange-oracle/tests/assets/utils/ -> recording-oracle/). Override with a positional arg. +DEFAULT_OUTPUT_DIR = ( + Path(__file__).resolve().parents[4] + / "recording-oracle" + / "tests" + / "assets" + / "cloud" + / "audio_validation" +) + + +def main(output_dir: Path = DEFAULT_OUTPUT_DIR) -> None: + # Imported lazily: src.core.config reads storage env vars at import time, so keeping these out + # of module scope lets --help / the docstring be read without the test-suite env defined. + import json + from unittest.mock import patch + + from src.core.config import Config + from src.core.manifest import parse_manifest + from src.core.storage import compose_data_bucket_filename, compose_data_bucket_prefix + from src.core.tasks.audio_transcription.meta import TaskMetaLayout + from src.core.types import Networks + from src.handlers.job_creation import handlers + from src.services.cloud.utils import BucketAccessInfo, make_client + + from tests.unit.test_audio_task_creation import ( + MANIFEST_PATH, + _generate_wav, + _make_bucket_url, + _make_cvat_api_mock, + ) + from tests.utils.audio_transcription import ( + MEDIA_DURATION_S, + MEDIA_FILES, + build_gt_tsv, + build_regions_tsv, + ) + from tests.utils.constants import ESCROW_ADDRESS + + chain_id = Networks.localhost.value + + # The builder-produced metadata the RO validation consumes. + fixture_files = ( + TaskMetaLayout.GT_FILENAME, + TaskMetaLayout.CLIPS_FILENAME, + TaskMetaLayout.TASK_CLIPS_FILENAME, + ) + + def data_url(name: str): + return _make_bucket_url(f"{INPUT_PREFIX}/{name}", bucket_name=INPUT_BUCKET) + + def build_manifest(): + with open(MANIFEST_PATH) as f: + manifest = json.load(f) + manifest["data"] = { + "media_url": data_url("media"), + "regions_url": data_url("regions.tsv"), + "gt_url": data_url("gt.tsv"), + } + return manifest + + def upload_input(tmp_dir: Path): + manifest = build_manifest() + client = make_client(BucketAccessInfo.parse_obj(parse_manifest(manifest).data.media_url)) + for filename in MEDIA_FILES: + wav_path = tmp_dir / filename + _generate_wav(wav_path, duration_s=MEDIA_DURATION_S) + client.create_file(f"{INPUT_PREFIX}/media/{filename}", wav_path.read_bytes()) + client.create_file(f"{INPUT_PREFIX}/regions.tsv", build_regions_tsv().encode()) + client.create_file(f"{INPUT_PREFIX}/gt.tsv", build_gt_tsv().encode()) + return manifest, client + + output_dir.mkdir(parents=True, exist_ok=True) + + with tempfile.TemporaryDirectory() as tmp: + manifest, input_client = upload_input(Path(tmp)) + + cvat_api = _make_cvat_api_mock() + with ( + patch.object(handlers, "get_escrow_manifest", return_value=manifest), + patch("src.handlers.job_creation.builders.audio.transcription.cvat_api", cvat_api), + ): + handlers.create_task(ESCROW_ADDRESS, chain_id) + + oracle_client = make_client(BucketAccessInfo.parse_obj(Config.storage_config)) + try: + for filename in fixture_files: + data = oracle_client.download_file( + compose_data_bucket_filename(ESCROW_ADDRESS, chain_id, filename) + ) + (output_dir / filename).write_bytes(data) + print(f"wrote {output_dir / filename} ({len(data)} bytes)") + + # Vendor the manifest the fixture was built from, so the RO validation runs against the + # exact same task config (metric, normalizer, tolerances) that produced it. + manifest_out = output_dir / MANIFEST_FILENAME + manifest_out.write_bytes(Path(MANIFEST_PATH).read_bytes()) + print(f"wrote {manifest_out} ({manifest_out.stat().st_size} bytes)") + finally: + # Best-effort cleanup of the buckets this run touched. + input_client.remove_files(prefix=INPUT_PREFIX) + oracle_client.remove_files(prefix=compose_data_bucket_prefix(ESCROW_ADDRESS, chain_id)) + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "output_dir", + nargs="?", + type=Path, + default=DEFAULT_OUTPUT_DIR, + help="directory to write the fixture into (default: the recording-oracle assets tree)", + ) + main(parser.parse_args().output_dir) diff --git a/packages/examples/cvat/exchange-oracle/tests/conftest.py b/packages/examples/cvat/exchange-oracle/tests/conftest.py index c2b92ac0ed..cd3fc83a6c 100644 --- a/packages/examples/cvat/exchange-oracle/tests/conftest.py +++ b/packages/examples/cvat/exchange-oracle/tests/conftest.py @@ -7,14 +7,14 @@ os.environ["DEBUG"] = "1" import pytest +from alembic.config import Config from fastapi.testclient import TestClient from sqlalchemy import TextClause, inspect, text from sqlalchemy.orm import Session from sqlalchemy_utils import create_database, database_exists, drop_database from alembic import command as alembic_command -from alembic.config import Config -from src import app +from src.apps.exchange_oracle import app from src.db import Base, SessionLocal, engine alembic_config = Config(Path(__file__).parent.parent / "alembic.ini") diff --git a/packages/examples/cvat/exchange-oracle/tests/integration/chain/test_web3.py b/packages/examples/cvat/exchange-oracle/tests/integration/chain/test_web3.py index 13b04fa428..b6b7d7ebb4 100644 --- a/packages/examples/cvat/exchange-oracle/tests/integration/chain/test_web3.py +++ b/packages/examples/cvat/exchange-oracle/tests/integration/chain/test_web3.py @@ -1,4 +1,5 @@ import json +import re import unittest from unittest.mock import patch @@ -57,7 +58,9 @@ def test_get_web3_localhost(self): assert w3.manager._provider.endpoint_uri == LocalhostConfig.rpc_api def test_get_web3_invalid_chain_id(self): - with pytest.raises(ValueError, match="1234 is not in available list of networks."): + with pytest.raises( + ValueError, match=re.escape("1234 is not in available list of networks.") + ): get_web3(1234) def test_sign_message_polygon(self): @@ -83,7 +86,9 @@ def test_sign_message_amoy(self): assert serialized_message == json.dumps("message") def test_sign_message_invalid_chain_id(self): - with pytest.raises(ValueError, match="1234 is not in available list of networks."): + with pytest.raises( + ValueError, match=re.escape("1234 is not in available list of networks.") + ): sign_message(1234, "message") def test_recover_signer(self): diff --git a/packages/examples/cvat/exchange-oracle/tests/integration/cron/state_trackers/test_track_completed_escrows.py b/packages/examples/cvat/exchange-oracle/tests/integration/cron/state_trackers/test_track_completed_escrows.py index 574ae5983c..80870ecc89 100644 --- a/packages/examples/cvat/exchange-oracle/tests/integration/cron/state_trackers/test_track_completed_escrows.py +++ b/packages/examples/cvat/exchange-oracle/tests/integration/cron/state_trackers/test_track_completed_escrows.py @@ -13,6 +13,7 @@ import pytest from sqlalchemy import select +from src.core.tasks import TaskTypes from src.core.types import ( AssignmentStatuses, EscrowValidationStatuses, @@ -21,12 +22,11 @@ Networks, ProjectStatuses, TaskStatuses, - TaskTypes, ) from src.crons import track_completed_escrows from src.crons.cvat.state_trackers import track_escrow_validations from src.db import SessionLocal -from src.handlers.completed_escrows import handle_escrow_export +from src.handlers.job_export import handle_escrow_export from src.models.cvat import ( Assignment, EscrowCreation, @@ -263,8 +263,13 @@ def test_can_request_validation(self): self.session.commit() with ( - patch("src.handlers.completed_escrows.validate_escrow"), - patch("src.handlers.completed_escrows.cloud_service") as mock_cloud_service, + open("tests/assets/cloud/manifests/manifest-v1.json") as manifest_data, + patch("src.handlers.job_completion.handlers.validate_escrow"), + patch( + "src.handlers.job_completion.handlers.get_escrow_manifest", + return_value=json.load(manifest_data), + ), + patch("src.handlers.job_export.results.cloud_service") as mock_cloud_service, ): mock_storage_client = Mock() mock_storage_client.create_file = Mock() @@ -373,8 +378,13 @@ def test_request_validation_error_in_file_uploading_increases_attempts(self): self.session.commit() with ( - patch("src.handlers.completed_escrows.validate_escrow"), - patch("src.handlers.completed_escrows.cloud_service") as mock_cloud_service, + open("tests/assets/cloud/manifests/manifest-v1.json") as manifest_data, + patch("src.handlers.job_completion.handlers.validate_escrow"), + patch( + "src.handlers.job_completion.handlers.get_escrow_manifest", + return_value=json.load(manifest_data), + ), + patch("src.handlers.job_export.results.cloud_service") as mock_cloud_service, patch("src.services.cloud.make_client"), ): mock_cloud_service.make_client.return_value.create_file.side_effect = _TestException() @@ -466,8 +476,13 @@ def test_can_request_validation_multiple_projects_per_escrow_all_completed(self) self.session.commit() with ( - patch("src.handlers.completed_escrows.validate_escrow"), - patch("src.handlers.completed_escrows.cloud_service") as mock_cloud_service, + open("tests/assets/cloud/manifests/manifest-v1.json") as manifest_data, + patch("src.handlers.job_completion.handlers.validate_escrow"), + patch( + "src.handlers.job_completion.handlers.get_escrow_manifest", + return_value=json.load(manifest_data), + ), + patch("src.handlers.job_export.results.cloud_service") as mock_cloud_service, ): mock_storage_client = Mock() mock_storage_client.create_file = Mock() @@ -572,11 +587,11 @@ def test_can_export_escrow(self): self.session.commit() with ( - open("tests/utils/manifest.json") as data, - patch("src.handlers.completed_escrows.get_escrow_manifest") as mock_get_manifest, - patch("src.handlers.completed_escrows.validate_escrow"), - patch("src.handlers.completed_escrows.cvat_api") as mock_cvat_api, - patch("src.handlers.completed_escrows.cloud_service") as mock_cloud_service, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, + patch("src.handlers.job_export.handlers.get_escrow_manifest") as mock_get_manifest, + patch("src.handlers.job_export.handlers.validate_escrow"), + patch("src.handlers.job_export.downloading.cvat_api") as mock_cvat_api, + patch("src.handlers.job_export.results.cloud_service") as mock_cloud_service, ): manifest = json.load(data) mock_get_manifest.return_value = manifest @@ -700,13 +715,13 @@ def test_can_export_escrow_error_getting_annotations(self): self.session.commit() with ( - open("tests/utils/manifest.json") as data, - patch("src.handlers.completed_escrows.get_escrow_manifest") as mock_get_manifest, - patch("src.handlers.completed_escrows.validate_escrow"), + open("tests/assets/cloud/manifests/manifest-v1.json") as data, + patch("src.handlers.job_export.handlers.get_escrow_manifest") as mock_get_manifest, + patch("src.handlers.job_export.handlers.validate_escrow"), patch( - "src.handlers.completed_escrows.cvat_api.request_job_annotations" + "src.handlers.job_export.downloading.cvat_api.request_job_annotations" ) as mock_request_job_annotations, - patch("src.handlers.completed_escrows.cloud_service") as mock_cloud_service, + patch("src.handlers.job_export.results.cloud_service") as mock_cloud_service, ): manifest = json.load(data) mock_get_manifest.return_value = manifest @@ -823,11 +838,11 @@ def test_can_export_escrow_error_uploading_files(self): self.session.commit() with ( - open("tests/utils/manifest.json") as data, - patch("src.handlers.completed_escrows.get_escrow_manifest") as mock_get_manifest, - patch("src.handlers.completed_escrows.validate_escrow"), - patch("src.handlers.completed_escrows.cvat_api") as mock_cvat_api, - patch("src.handlers.completed_escrows.cloud_service") as mock_cloud_service, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, + patch("src.handlers.job_export.handlers.get_escrow_manifest") as mock_get_manifest, + patch("src.handlers.job_export.handlers.validate_escrow"), + patch("src.handlers.job_export.downloading.cvat_api") as mock_cvat_api, + patch("src.handlers.job_export.results.cloud_service") as mock_cloud_service, patch("src.services.cloud.make_client"), ): manifest = json.load(data) @@ -948,13 +963,15 @@ def test_can_export_multiple_projects_per_escrow(self): self.session.commit() with ( - open("tests/utils/manifest.json") as manifest_data, - patch("src.handlers.completed_escrows.get_escrow_manifest") as mock_get_manifest, - patch("src.handlers.completed_escrows.validate_escrow"), - patch("src.handlers.completed_escrows.cvat_api") as mock_cvat_api, - patch("src.handlers.completed_escrows.cloud_service") as mock_cloud_service, + open("tests/assets/cloud/manifests/manifest-v1.json") as manifest_data, + patch("src.handlers.job_export.handlers.get_escrow_manifest") as mock_get_manifest, + patch("src.handlers.job_export.handlers.validate_escrow"), + patch("src.handlers.job_export.downloading.cvat_api") as mock_cvat_api, + patch("src.handlers.job_export.results.cloud_service") as mock_cloud_service, + patch("src.handlers.job_export.exporters.vision.SkeletonsJobExporter._prepare"), patch( - "src.handlers.completed_escrows.postprocess_annotations" + "src.handlers.job_export.exporters.vision.SkeletonsJobExporter._postprocess", + autospec=True, ) as mock_postprocess_annotations, ): manifest = json.load(manifest_data) @@ -989,16 +1006,8 @@ def _fake_get_annotations(*args, **kwargs): mock_cvat_api.get_job_annotations.side_effect = _fake_get_annotations mock_cvat_api.get_project_annotations.side_effect = _fake_get_annotations - def _fake_postprocess_annotations( - escrow_address, - chain_id, - annotations, - merged_annotation, - *, - manifest, - project_images, - ): - merged_annotation.file = io.BytesIO() + def _fake_postprocess_annotations(self, annotations): + self._merged_annotation_file.file = io.BytesIO() mock_postprocess_annotations.side_effect = _fake_postprocess_annotations diff --git a/packages/examples/cvat/exchange-oracle/tests/integration/cron/state_trackers/test_track_completed_projects.py b/packages/examples/cvat/exchange-oracle/tests/integration/cron/state_trackers/test_track_completed_projects.py index 9adbf904dd..e325722683 100644 --- a/packages/examples/cvat/exchange-oracle/tests/integration/cron/state_trackers/test_track_completed_projects.py +++ b/packages/examples/cvat/exchange-oracle/tests/integration/cron/state_trackers/test_track_completed_projects.py @@ -3,7 +3,8 @@ from sqlalchemy.sql import select -from src.core.types import Networks, ProjectStatuses, TaskStatuses, TaskTypes +from src.core.tasks import TaskTypes +from src.core.types import Networks, ProjectStatuses, TaskStatuses from src.crons.cvat.state_trackers import track_completed_projects from src.db import SessionLocal from src.models.cvat import Project, Task diff --git a/packages/examples/cvat/exchange-oracle/tests/integration/cron/state_trackers/test_track_completed_tasks.py b/packages/examples/cvat/exchange-oracle/tests/integration/cron/state_trackers/test_track_completed_tasks.py index 98c77a9f18..682e4b6e48 100644 --- a/packages/examples/cvat/exchange-oracle/tests/integration/cron/state_trackers/test_track_completed_tasks.py +++ b/packages/examples/cvat/exchange-oracle/tests/integration/cron/state_trackers/test_track_completed_tasks.py @@ -3,7 +3,8 @@ from sqlalchemy.sql import select -from src.core.types import JobStatuses, Networks, ProjectStatuses, TaskStatuses, TaskTypes +from src.core.tasks import TaskTypes +from src.core.types import JobStatuses, Networks, ProjectStatuses, TaskStatuses from src.crons.cvat.state_trackers import track_completed_tasks from src.db import SessionLocal from src.models.cvat import Job, Project, Task diff --git a/packages/examples/cvat/exchange-oracle/tests/integration/cron/state_trackers/test_track_task_creation.py b/packages/examples/cvat/exchange-oracle/tests/integration/cron/state_trackers/test_track_task_creation.py index b860386bd4..9168b55a4b 100644 --- a/packages/examples/cvat/exchange-oracle/tests/integration/cron/state_trackers/test_track_task_creation.py +++ b/packages/examples/cvat/exchange-oracle/tests/integration/cron/state_trackers/test_track_task_creation.py @@ -87,7 +87,7 @@ def test_track_track_completed_task_creation(self): def test_track_track_completed_task_creation_error(self): escrow_address = "0x86e83d346041E8806e352681f3F14549C0d2BC67" - (_, cvat_task, cvat_job) = create_project_task_and_job(self.session, escrow_address, 1) + (_, cvat_task, _) = create_project_task_and_job(self.session, escrow_address, 1) upload = DataUpload( id=str(uuid.uuid4()), task_id=cvat_task.cvat_id, diff --git a/packages/examples/cvat/exchange-oracle/tests/integration/cron/test_process_job_launcher_webhooks.py b/packages/examples/cvat/exchange-oracle/tests/integration/cron/test_process_job_launcher_webhooks.py index 89b166425a..00e66e500e 100644 --- a/packages/examples/cvat/exchange-oracle/tests/integration/cron/test_process_job_launcher_webhooks.py +++ b/packages/examples/cvat/exchange-oracle/tests/integration/cron/test_process_job_launcher_webhooks.py @@ -7,6 +7,7 @@ from sqlalchemy.sql import select from src.core.storage import compose_data_bucket_prefix, compose_results_bucket_prefix +from src.core.tasks import TaskTypes from src.core.types import ( ExchangeOracleEventTypes, JobLauncherEventTypes, @@ -16,7 +17,6 @@ OracleWebhookTypes, ProjectStatuses, TaskStatuses, - TaskTypes, ) from src.crons.webhooks.job_launcher import ( process_incoming_job_launcher_webhooks, @@ -60,12 +60,18 @@ def test_process_incoming_job_launcher_webhooks_escrow_created_type(self): self.session.add(webhook) self.session.commit() + # The task builder is split across the `basic` and `base` modules, both of which import + # `cvat_api`; share a single mock across both so all CVAT calls are intercepted. + mock_cvat_api = MagicMock() with ( patch("src.chain.escrow.get_escrow") as mock_escrow, - open("tests/utils/manifest.json") as data, - patch("src.handlers.job_creation.get_escrow_manifest") as mock_get_manifest, - patch("src.handlers.job_creation.cvat_api") as mock_cvat_api, - patch("src.handlers.job_creation.cloud_service.make_client") as mock_make_cloud_client, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, + patch("src.handlers.job_creation.handlers.get_escrow_manifest") as mock_get_manifest, + patch("src.handlers.job_creation.builders.vision.basic.cvat_api", mock_cvat_api), + patch("src.handlers.job_creation.builders.vision.base.cvat_api", mock_cvat_api), + patch( + "src.handlers.job_creation.builders.vision.basic.cloud_service.make_client" + ) as mock_make_cloud_client, ): manifest = json.load(data) mock_get_manifest.return_value = manifest @@ -246,12 +252,14 @@ def test_process_incoming_job_launcher_webhooks_escrow_created_type_remove_when_ self.session.commit() with ( patch("src.chain.escrow.get_escrow") as mock_escrow, - open("tests/utils/manifest.json") as data, - patch("src.handlers.job_creation.get_escrow_manifest") as mock_get_manifest, - patch("src.handlers.job_creation.cvat_api") as mock_cvat_api, - patch("src.handlers.job_creation.cloud_service.make_client") as mock_make_cloud_client, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, + patch("src.handlers.job_creation.handlers.get_escrow_manifest") as mock_get_manifest, + patch("src.handlers.job_creation.builders.vision.basic.cvat_api") as mock_cvat_api, + patch( + "src.handlers.job_creation.builders.vision.basic.cloud_service.make_client" + ) as mock_make_cloud_client, patch( - "src.handlers.job_creation.db_service.add_project_images", + "src.handlers.job_creation.builders.vision.basic.db_service.add_project_images", side_effect=Exception("Error"), ), ): @@ -635,7 +643,7 @@ def test_process_outgoing_job_launcher_webhooks(self): "src.crons.webhooks.job_launcher.get_job_launcher_url", return_value=DEFAULT_MANIFEST_URL, ), - patch("httpx.Client.post") as mock_httpx_post, + patch("httpx2.Client.post") as mock_httpx_post, ): mock_response = MagicMock() mock_response.raise_for_status.return_value = None diff --git a/packages/examples/cvat/exchange-oracle/tests/integration/cron/test_process_recording_oracle_webhooks.py b/packages/examples/cvat/exchange-oracle/tests/integration/cron/test_process_recording_oracle_webhooks.py index 96c6f2931c..33c752b9e4 100644 --- a/packages/examples/cvat/exchange-oracle/tests/integration/cron/test_process_recording_oracle_webhooks.py +++ b/packages/examples/cvat/exchange-oracle/tests/integration/cron/test_process_recording_oracle_webhooks.py @@ -5,6 +5,7 @@ from sqlalchemy.sql import select +from src.core.tasks import TaskTypes from src.core.types import ( AssignmentStatuses, EscrowValidationStatuses, @@ -16,7 +17,6 @@ ProjectStatuses, RecordingOracleEventTypes, TaskStatuses, - TaskTypes, ) from src.crons.webhooks.recording_oracle import ( process_incoming_recording_oracle_webhook_job_completed, @@ -442,7 +442,7 @@ def test_process_outgoing_recording_oracle_webhooks(self): "src.crons.webhooks.recording_oracle.get_recording_oracle_url", return_value=DEFAULT_MANIFEST_URL, ), - patch("httpx.Client.post") as mock_httpx_post, + patch("httpx2.Client.post") as mock_httpx_post, ): mock_response = MagicMock() mock_response.raise_for_status.return_value = None diff --git a/packages/examples/cvat/exchange-oracle/tests/integration/cron/test_process_reputation_oracle_webhooks.py b/packages/examples/cvat/exchange-oracle/tests/integration/cron/test_process_reputation_oracle_webhooks.py index 380ed680b6..a1eff0585a 100644 --- a/packages/examples/cvat/exchange-oracle/tests/integration/cron/test_process_reputation_oracle_webhooks.py +++ b/packages/examples/cvat/exchange-oracle/tests/integration/cron/test_process_reputation_oracle_webhooks.py @@ -5,6 +5,7 @@ from sqlalchemy import select from src.core.storage import compose_data_bucket_prefix, compose_results_bucket_prefix +from src.core.tasks import TaskTypes from src.core.types import ( ExchangeOracleEventTypes, JobStatuses, @@ -14,7 +15,6 @@ ProjectStatuses, ReputationOracleEventTypes, TaskStatuses, - TaskTypes, ) from src.crons.webhooks.reputation_oracle import process_incoming_reputation_oracle_webhooks from src.cvat import api_calls diff --git a/packages/examples/cvat/exchange-oracle/tests/integration/services/test_cvat.py b/packages/examples/cvat/exchange-oracle/tests/integration/services/test_cvat.py index 65b07db6ae..bec48b955c 100644 --- a/packages/examples/cvat/exchange-oracle/tests/integration/services/test_cvat.py +++ b/packages/examples/cvat/exchange-oracle/tests/integration/services/test_cvat.py @@ -6,13 +6,13 @@ from sqlalchemy.orm.exc import UnmappedInstanceError import src.services.cvat as cvat_service +from src.core.tasks import TaskTypes from src.core.types import ( AssignmentStatuses, JobStatuses, Networks, ProjectStatuses, TaskStatuses, - TaskTypes, ) from src.db import SessionLocal from src.models.cvat import ( @@ -59,11 +59,11 @@ def test_create_project(self): p_id = cvat_service.create_project( self.session, cvat_id, - cvat_cloudstorage_id, - job_type, - escrow_address, - chain_id, - bucket_url, + cvat_cloudstorage_id=cvat_cloudstorage_id, + job_type=job_type, + escrow_address=escrow_address, + chain_id=chain_id, + bucket_url=bucket_url, ) project = self.session.query(Project).filter_by(id=p_id).first() @@ -87,22 +87,22 @@ def test_create_duplicated_project(self): cvat_service.create_project( self.session, cvat_id, - cvat_cloudstorage_id, - job_type, - escrow_address, - chain_id, - bucket_url, + cvat_cloudstorage_id=cvat_cloudstorage_id, + job_type=job_type, + escrow_address=escrow_address, + chain_id=chain_id, + bucket_url=bucket_url, ) self.session.commit() cvat_service.create_project( self.session, cvat_id, - cvat_cloudstorage_id, - job_type, - escrow_address, - chain_id, - bucket_url, + cvat_cloudstorage_id=cvat_cloudstorage_id, + job_type=job_type, + escrow_address=escrow_address, + chain_id=chain_id, + bucket_url=bucket_url, ) with pytest.raises(IntegrityError): self.session.commit() @@ -116,11 +116,11 @@ def test_create_project_none_cvat_id(self): cvat_service.create_project( self.session, None, - cvat_cloudstorage_id, - job_type, - escrow_address, - chain_id, - bucket_url, + cvat_cloudstorage_id=cvat_cloudstorage_id, + job_type=job_type, + escrow_address=escrow_address, + chain_id=chain_id, + bucket_url=bucket_url, ) with pytest.raises(IntegrityError): self.session.commit() @@ -134,11 +134,11 @@ def test_create_project_none_cvat_cloudstorage_id(self): cvat_service.create_project( self.session, cvat_id, - None, - job_type, - escrow_address, - chain_id, - bucket_url, + cvat_cloudstorage_id=None, + job_type=job_type, + escrow_address=escrow_address, + chain_id=chain_id, + bucket_url=bucket_url, ) with pytest.raises(IntegrityError): self.session.commit() @@ -152,11 +152,11 @@ def test_create_project_none_job_type(self): cvat_service.create_project( self.session, cvat_id, - cvat_cloudstorage_id, - None, - escrow_address, - chain_id, - bucket_url, + cvat_cloudstorage_id=cvat_cloudstorage_id, + job_type=None, + escrow_address=escrow_address, + chain_id=chain_id, + bucket_url=bucket_url, ) with pytest.raises(IntegrityError): self.session.commit() @@ -170,11 +170,11 @@ def test_create_project_none_escrow_address(self): cvat_service.create_project( self.session, cvat_id, - cvat_cloudstorage_id, - job_type, - None, - chain_id, - bucket_url, + cvat_cloudstorage_id=cvat_cloudstorage_id, + job_type=job_type, + escrow_address=None, + chain_id=chain_id, + bucket_url=bucket_url, ) with pytest.raises(IntegrityError): self.session.commit() @@ -189,11 +189,11 @@ def test_create_project_none_chain_id(self): cvat_service.create_project( self.session, cvat_id, - cvat_cloudstorage_id, - job_type, - escrow_address, - None, - bucket_url, + cvat_cloudstorage_id=cvat_cloudstorage_id, + job_type=job_type, + escrow_address=escrow_address, + chain_id=None, + bucket_url=bucket_url, ) with pytest.raises(IntegrityError): self.session.commit() @@ -207,11 +207,11 @@ def test_create_project_none_bucket_url(self): cvat_service.create_project( self.session, cvat_id, - cvat_cloudstorage_id, - job_type, - escrow_address, - chain_id, - None, + cvat_cloudstorage_id=cvat_cloudstorage_id, + job_type=job_type, + escrow_address=escrow_address, + chain_id=chain_id, + bucket_url=None, ) with pytest.raises(IntegrityError): self.session.commit() @@ -226,11 +226,11 @@ def test_get_project_by_id(self): p_id = cvat_service.create_project( self.session, cvat_id, - cvat_cloudstorage_id, - job_type, - escrow_address, - chain_id, - bucket_url, + cvat_cloudstorage_id=cvat_cloudstorage_id, + job_type=job_type, + escrow_address=escrow_address, + chain_id=chain_id, + bucket_url=bucket_url, status=ProjectStatuses.annotation, ) @@ -276,11 +276,11 @@ def test_get_project_by_escrow_address(self): p_id = cvat_service.create_project( self.session, cvat_id, - cvat_cloudstorage_id, - job_type, - escrow_address, - chain_id, - bucket_url, + cvat_cloudstorage_id=cvat_cloudstorage_id, + job_type=job_type, + escrow_address=escrow_address, + chain_id=chain_id, + bucket_url=bucket_url, status=ProjectStatuses.annotation, ) @@ -309,11 +309,11 @@ def test_get_projects_by_status(self): p_id = cvat_service.create_project( self.session, cvat_id, - cvat_cloudstorage_id, - job_type, - escrow_address, - chain_id, - bucket_url, + cvat_cloudstorage_id=cvat_cloudstorage_id, + job_type=job_type, + escrow_address=escrow_address, + chain_id=chain_id, + bucket_url=bucket_url, status=ProjectStatuses.annotation, ) @@ -325,11 +325,11 @@ def test_get_projects_by_status(self): cvat_service.create_project( self.session, cvat_id, - cvat_cloudstorage_id, - job_type, - escrow_address, - chain_id, - bucket_url, + cvat_cloudstorage_id=cvat_cloudstorage_id, + job_type=job_type, + escrow_address=escrow_address, + chain_id=chain_id, + bucket_url=bucket_url, status=ProjectStatuses.annotation, ) @@ -341,11 +341,11 @@ def test_get_projects_by_status(self): cvat_service.create_project( self.session, cvat_id, - cvat_cloudstorage_id, - job_type, - escrow_address, - chain_id, - bucket_url, + cvat_cloudstorage_id=cvat_cloudstorage_id, + job_type=job_type, + escrow_address=escrow_address, + chain_id=chain_id, + bucket_url=bucket_url, status=ProjectStatuses.annotation, ) @@ -366,7 +366,7 @@ def test_get_projects_by_status(self): def test_can_get_free_job_if_exists(self): escrow_address = "0x86e83d346041E8806e352681f3F14549C0d2BC67" - (cvat_project, cvat_task, cvat_job) = create_project_task_and_job( + (cvat_project, _, cvat_job) = create_project_task_and_job( self.session, escrow_address, cvat_id=1 ) chain_id = cvat_project.chain_id @@ -384,7 +384,7 @@ def test_can_get_free_job_if_exists(self): def test_cannot_get_free_job_if_all_completed_and_not_project_checked_yet(self): escrow_address = "0x86e83d346041E8806e352681f3F14549C0d2BC67" - (cvat_project, cvat_task, cvat_job) = create_project_task_and_job( + (cvat_project, _, cvat_job) = create_project_task_and_job( self.session, escrow_address, cvat_id=1 ) chain_id = cvat_project.chain_id @@ -494,11 +494,11 @@ def test_update_project_status(self): p_id = cvat_service.create_project( self.session, cvat_id, - cvat_cloudstorage_id, - job_type, - escrow_address, - chain_id, - bucket_url, + cvat_cloudstorage_id=cvat_cloudstorage_id, + job_type=job_type, + escrow_address=escrow_address, + chain_id=chain_id, + bucket_url=bucket_url, ) cvat_service.update_project_status(self.session, p_id, ProjectStatuses.completed) diff --git a/packages/examples/cvat/exchange-oracle/tests/integration/services/test_exchange.py b/packages/examples/cvat/exchange-oracle/tests/integration/services/test_exchange.py index e2a52815ce..560ec4b44e 100644 --- a/packages/examples/cvat/exchange-oracle/tests/integration/services/test_exchange.py +++ b/packages/examples/cvat/exchange-oracle/tests/integration/services/test_exchange.py @@ -1,4 +1,5 @@ import json +import re import unittest import uuid from datetime import datetime, timedelta @@ -8,7 +9,8 @@ from fastapi import HTTPException from pydantic import ValidationError -from src.core.types import AssignmentStatuses, JobStatuses, Networks, TaskTypes +from src.core.tasks import TaskTypes +from src.core.types import AssignmentStatuses, JobStatuses, Networks from src.db import SessionLocal from src.endpoints.serializers import serialize_job from src.models.cvat import Assignment, User @@ -39,7 +41,7 @@ def test_serialize_job(self): self.session.commit() with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.endpoints.serializers.get_escrow_manifest") as mock_get_manifest, patch( "src.endpoints.serializers.get_escrow_fund_token_symbol" @@ -98,7 +100,7 @@ def test_create_assignment(self): self.session.commit() with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.services.exchange.get_escrow_manifest") as mock_get_manifest, patch("src.services.exchange.cvat_api"), ): @@ -153,7 +155,7 @@ def test_create_assignment_many_jobs_1_completed(self): self.session.commit() with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.services.exchange.get_escrow_manifest") as mock_get_manifest, patch("src.services.exchange.cvat_api"), ): @@ -192,7 +194,7 @@ def test_create_assignment_invalid_project(self): self.session.commit() with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.services.exchange.get_escrow_manifest") as mock_get_manifest, ): manifest = json.load(data) @@ -211,13 +213,15 @@ def test_create_assignment_no_required_qualifications(self): self.session.commit() with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.services.exchange.get_escrow_manifest") as mock_get_manifest, ): manifest = json.load(data) manifest["annotation"]["qualifications"] = ["random_qualification"] mock_get_manifest.return_value = manifest - with pytest.raises(Exception, match="User doesn't have required qualifications."): + with pytest.raises( + Exception, match=re.escape("User doesn't have required qualifications.") + ): create_assignment(ESCROW_ADDRESS, Networks.localhost, user_address, []) def test_create_assignment_with_required_qualifications(self): @@ -239,7 +243,7 @@ def test_create_assignment_with_required_qualifications(self): self.session.commit() with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.services.exchange.get_escrow_manifest") as mock_get_manifest, patch("src.services.exchange.cvat_api"), ): @@ -292,7 +296,7 @@ def test_create_assignment_unfinished_assignment(self): self.session.commit() with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.services.exchange.get_escrow_manifest") as mock_get_manifest, patch("src.services.exchange.cvat_api"), ): @@ -330,7 +334,7 @@ def test_create_assignment_has_expired_assignment_and_available_jobs(self): self.session.commit() with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.services.exchange.get_escrow_manifest") as mock_get_manifest, patch("src.services.exchange.cvat_api"), ): @@ -380,7 +384,7 @@ def test_create_assignment_no_available_jobs_completed_assignment(self): self.session.commit() with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.services.exchange.get_escrow_manifest") as mock_get_manifest, patch("src.services.exchange.cvat_api"), ): @@ -425,7 +429,7 @@ def test_create_assignment_no_available_jobs_active_foreign_assignment(self): self.session.commit() with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.services.exchange.get_escrow_manifest") as mock_get_manifest, patch("src.services.exchange.cvat_api"), ): @@ -463,7 +467,7 @@ def test_create_assignment_wont_reassign_job_to_previous_user(self): self.session.commit() with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.services.exchange.get_escrow_manifest") as mock_get_manifest, patch("src.services.exchange.cvat_api"), ): @@ -510,7 +514,7 @@ def test_create_assignment_can_assign_job_to_new_user(self): self.session.commit() with ( - open("tests/utils/manifest.json") as data, + open("tests/assets/cloud/manifests/manifest-v1.json") as data, patch("src.services.exchange.get_escrow_manifest") as mock_get_manifest, patch("src.services.exchange.cvat_api"), ): diff --git a/packages/examples/cvat/exchange-oracle/tests/integration/services/test_webhook.py b/packages/examples/cvat/exchange-oracle/tests/integration/services/test_webhook.py index 957ca111fa..6adcc14c4d 100644 --- a/packages/examples/cvat/exchange-oracle/tests/integration/services/test_webhook.py +++ b/packages/examples/cvat/exchange-oracle/tests/integration/services/test_webhook.py @@ -83,10 +83,7 @@ def test_create_incoming_webhook_none_event_type(self): signature = "signature" with pytest.raises( AssertionError, - match=( - "'event' and 'event_type' cannot be used together. " - "Please use only one of the fields" - ), + match=r"'event' and 'event_type' cannot be used together. ", ): webhook_service.inbox.create_webhook( self.session, @@ -161,10 +158,7 @@ def test_create_outgoing_webhook_none_event_type(self): escrow_address = "0x1234567890123456789012345678901234567890" with pytest.raises( AssertionError, - match=( - "'event' and 'event_type' cannot be used together. " - "Please use only one of the fields" - ), + match=r"'event' and 'event_type' cannot be used together. ", ): webhook_service.outbox.create_webhook( self.session, diff --git a/packages/examples/cvat/exchange-oracle/tests/unit/helpers/predefined_annotations.py b/packages/examples/cvat/exchange-oracle/tests/unit/helpers/predefined_annotations.py deleted file mode 100644 index 657b695e76..0000000000 --- a/packages/examples/cvat/exchange-oracle/tests/unit/helpers/predefined_annotations.py +++ /dev/null @@ -1,36 +0,0 @@ -raw_binary_annotations = { - "image": [ - {"name": "1.jpg", "tag": {"label": "dummy_label"}}, - {"name": "2.jpg", "tag": {"label": "dummy_label"}}, - {"name": "3.jpg", "tag": {"label": "dummy_label"}}, - ] -} -binary_annotations = [ - { - "url": "https://test.storage.googleapis.com/1.jpg", - "answers": [ - { - "tag": "dummy_label", - "assignee": "0x86e83d346041E8806e352681f3F14549C0d2BC61", - } - ], - }, - { - "url": "https://test.storage.googleapis.com/2.jpg", - "answers": [ - { - "tag": "dummy_label", - "assignee": "0x86e83d346041E8806e352681f3F14549C0d2BC61", - } - ], - }, - { - "url": "https://test.storage.googleapis.com/3.jpg", - "answers": [ - { - "tag": "dummy_label", - "assignee": "0x86e83d346041E8806e352681f3F14549C0d2BC61", - } - ], - }, -] diff --git a/packages/examples/cvat/exchange-oracle/tests/unit/test_audio_task_creation.py b/packages/examples/cvat/exchange-oracle/tests/unit/test_audio_task_creation.py new file mode 100644 index 0000000000..2c853789f5 --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/tests/unit/test_audio_task_creation.py @@ -0,0 +1,268 @@ +import json +import subprocess +from pathlib import Path +from unittest.mock import Mock, patch + +import pytest + +import src.services.cvat as db_service +from src.core.config import Config +from src.core.manifest import parse_manifest +from src.core.storage import compose_data_bucket_prefix +from src.core.tasks import TaskTypes +from src.core.tasks.audio_transcription.meta import ( + RegionKind, + TaskMetaLayout, + TaskMetaSerializer, + parse_gt_tsv, +) +from src.core.types import Networks, TaskStatuses +from src.handlers.job_creation import handlers +from src.handlers.job_creation.builders.audio.transcription import _parse_regions_tsv +from src.services.cloud.utils import BucketAccessInfo, make_client + +from tests.utils.audio_transcription import ( + MEDIA_DURATION_S, + MEDIA_FILES, + build_gt_tsv, + build_regions_tsv, +) +from tests.utils.constants import ESCROW_ADDRESS +from tests.utils.setup_cvat import get_session + +CHAIN_ID = Networks.localhost.value + +MANIFEST_PATH = "tests/assets/cloud/manifests/audio_manifest.json" + + +def _generate_wav(path: Path, *, duration_s: int) -> None: + """Synthesize a mono sine-tone WAV on the fly (ffmpeg is present in the test image).""" + subprocess.run( + [ + "ffmpeg", + "-y", + "-loglevel", + "error", + "-f", + "lavfi", + "-i", + f"sine=frequency=440:duration={duration_s}", + "-ar", + "48000", + "-ac", + "1", + str(path), + ], + check=True, + ) + + +def _make_bucket_url(path: str, *, bucket_name: str) -> dict: + cfg = Config.storage_config + + return { + "provider": cfg.provider.upper(), + "host_url": f"{cfg.get_scheme()}{cfg.endpoint_url}", + "bucket_name": bucket_name, + "path": path, + "access_key": cfg.access_key, + "secret_key": cfg.secret_key, + } + + +@pytest.fixture +def fxt_audio_transcription_input(tmp_path: Path): + """Factory: generate the media recordings + region/GT TSVs, upload them to the input bucket, and + return a manifest whose data URLs embed the minio connection details. The region/GT layout is + caller-provided so tests exercising different assignment counts can reuse this.""" + + input_bucket = "datasets" + input_prefix = "audio_test" + + ds_rois_tsv = build_regions_tsv() + gt_tsv = build_gt_tsv() + + with open(MANIFEST_PATH) as f: + manifest = json.load(f) + + manifest["data"] = { + "media_url": _make_bucket_url(f"{input_prefix}/media", bucket_name=input_bucket), + "regions_url": _make_bucket_url(f"{input_prefix}/regions.tsv", bucket_name=input_bucket), + "gt_url": _make_bucket_url(f"{input_prefix}/gt.tsv", bucket_name=input_bucket), + } + + try: + client = make_client(BucketAccessInfo.parse_obj(parse_manifest(manifest).data.media_url)) + for filename in MEDIA_FILES: + wav_path = tmp_path / filename + _generate_wav(wav_path, duration_s=MEDIA_DURATION_S) + client.create_file(f"{input_prefix}/media/{filename}", wav_path.read_bytes()) + + client.create_file(f"{input_prefix}/regions.tsv", ds_rois_tsv.encode()) + client.create_file(f"{input_prefix}/gt.tsv", gt_tsv.encode()) + + yield manifest, ds_rois_tsv, gt_tsv + finally: + client.remove_files(prefix=input_prefix) + + +def _make_cvat_api_mock() -> Mock: + """A cvat_api stand-in returning integer ids so the DB inserts succeed, and a fresh + task id per create_task call so the unique cvat_id constraint holds.""" + cvat_api = Mock() + cvat_api.create_project.return_value = Mock(id=1) + cvat_api.create_cvat_webhook.return_value = Mock(id=10) + cvat_api.create_cloudstorage.return_value = Mock(id=100) + + task_ids = iter(range(1000, 2000)) + cvat_api.create_task.side_effect = lambda *_a, **_kw: Mock( + id=next(task_ids), status=TaskStatuses.annotation.value + ) + return cvat_api + + +def cleanup_oracle_bucket(prefix: str = ""): + storage_client = make_client(BucketAccessInfo.parse_obj(Config.storage_config)) + storage_client.remove_files(prefix=prefix) + + +@pytest.fixture +def post_cleanup_oracle_bucket(): + yield + cleanup_oracle_bucket() + + +@pytest.fixture +def pre_cleanup_oracle_bucket(): + cleanup_oracle_bucket() + + +@pytest.mark.usefixtures("pre_cleanup_oracle_bucket") +@pytest.mark.usefixtures("post_cleanup_oracle_bucket") +def test_create_audio_transcription_task(fxt_audio_transcription_input): + manifest, ds_rois_tsv, gt_tsv = fxt_audio_transcription_input + + cvat_api = _make_cvat_api_mock() + escrow = Mock(total_funded_amount="40") + with ( + patch.object(handlers, "get_escrow_manifest", return_value=manifest), + patch("src.handlers.job_creation.builders.audio.transcription.cvat_api", cvat_api), + patch("src.handlers.job_creation.utils.get_escrow", return_value=escrow) as mock_get_escrow, + ): + handlers.create_task(ESCROW_ADDRESS, CHAIN_ID) + + # v2 manifest → per-assignment bounty derived from escrow funds / job count + mock_get_escrow.assert_called_once_with(CHAIN_ID, ESCROW_ADDRESS) + + # Check CVAT API calls + cvat_api.create_project.assert_called_once() + cvat_api.create_cvat_webhook.assert_called_once() + cvat_api.create_cloudstorage.assert_called_once() + + assignment_count = cvat_api.create_task.call_count + assert assignment_count == 4 + assert cvat_api.put_task_data.call_count == assignment_count + + # Check DB records + with get_session() as session: + project = db_service.get_project_by_escrow_address(session, ESCROW_ADDRESS) + assert project is not None + assert project.cvat_id == 1 + assert project.cvat_webhook_id == 10 + assert project.cvat_cloudstorage_id == 100 + assert project.job_type == TaskTypes.audio_transcription.value + assert project.chain_id == CHAIN_ID + assert project.assignment_bounty == "10" # 40 escrow funds / 4 assignments + + tasks = db_service.get_tasks_by_cvat_project_id(session, project.cvat_id) + assert len(tasks) == assignment_count + + # create_task only registers the escrow creation; it is finished later by the cron once + # CVAT confirms the jobs, so it is still active (finished_at is None) at this point. + escrow_creation = db_service.get_escrow_creation_by_escrow_address( + session, ESCROW_ADDRESS, CHAIN_ID, active=True + ) + assert escrow_creation.total_jobs == assignment_count + + # Check oracle bucket + storage_client = make_client(BucketAccessInfo.parse_obj(Config.storage_config)) + storage_prefix = compose_data_bucket_prefix(ESCROW_ADDRESS, CHAIN_ID) + storage_keys = set(storage_client.list_files(prefix=storage_prefix, trim_prefix=True)) + + layout = TaskMetaLayout() + clips = [k for k in storage_keys if k.startswith(f"{layout.CLIPS_DIR}/") and k.endswith(".wav")] + assert len(clips) == assignment_count + + for meta_file in ( + layout.REGIONS_TSV_FILENAME, + layout.GT_FILENAME, + layout.REGIONS_FILENAME, + layout.CLIPS_FILENAME, + layout.TASK_CLIPS_FILENAME, + ): + assert meta_file in storage_keys, f"missing {meta_file} in {sorted(storage_keys)}" + + # task_clips maps each created CVAT task id to its assignment clip id + task_clips = json.loads( + storage_client.download_file(f"{storage_prefix}/{layout.TASK_CLIPS_FILENAME}") + ) + assert len(task_clips) == assignment_count + + # Verify the input regions & GT were consumed as expected + + # The raw region/GT TSVs are copied verbatim to the oracle bucket for provenance. + assert ( + storage_client.download_file(f"{storage_prefix}/{layout.REGIONS_TSV_FILENAME}").decode() + == ds_rois_tsv + ) + assert storage_client.download_file(f"{storage_prefix}/{layout.GT_FILENAME}").decode() == gt_tsv + + # Expected input ROI ids, reconstructed from the fixture TSVs with the production parsers. + regions_by_file = _parse_regions_tsv(ds_rois_tsv.encode()) + input_media = set(regions_by_file) + expected_ds_ids = sorted(r.id for regions in regions_by_file.values() for r in regions) + + gt_rois = parse_gt_tsv(gt_tsv.encode()) + expected_gt_ids = {r.id for r in gt_rois} + span_by_gt_id = {r.id: r.span_id for r in gt_rois} + + serializer = TaskMetaSerializer() + presented = serializer.parse_regions( + storage_client.download_file(f"{storage_prefix}/{layout.REGIONS_FILENAME}") + ) + ds_regions = [r for r in presented if r.kind == RegionKind.ds] + gt_regions = [r for r in presented if r.kind == RegionKind.gt] + + # Presented regions reference only the input media + assert {r.source_filename for r in presented} <= input_media + + # Every input DS ROI is presented for annotation exactly once + presented_ds_ids = [region_id for r in ds_regions for region_id in r.input_ids] + assert sorted(presented_ds_ids) == expected_ds_ids + + # val_fraction=1.0 -> all GT regions become honeypots, each used once, bundled within one span + presented_gt_ids = [region_id for r in gt_regions for region_id in r.input_ids] + assert sorted(presented_gt_ids) == sorted(expected_gt_ids) + for r in gt_regions: + assert len({span_by_gt_id[region_id] for region_id in r.input_ids}) == 1 + + # Verify the assignment composition + clips = serializer.parse_clips( + storage_client.download_file(f"{storage_prefix}/{layout.CLIPS_FILENAME}") + ) + assert len(clips) == assignment_count + + placed_ds_ids: list[str] = [] + placed_gt_ids: list[str] = [] + for clip in clips: + kinds = {p.kind for p in clip.placed} + assert RegionKind.ds in kinds, "assignment has no DS work" + assert RegionKind.gt in kinds, "assignment has no GT honeypot" + for p in clip.placed: + (placed_ds_ids if p.kind == RegionKind.ds else placed_gt_ids).extend(p.input_ids) + + # Each DS ROI is annotated exactly once across all assignments. + assert sorted(placed_ds_ids) == expected_ds_ids + # Honeypots are drawn from the presented GT pool (and may repeat across assignments). + assert placed_gt_ids + assert set(placed_gt_ids) <= expected_gt_ids diff --git a/packages/examples/cvat/exchange-oracle/tests/utils/audio_transcription.py b/packages/examples/cvat/exchange-oracle/tests/utils/audio_transcription.py new file mode 100644 index 0000000000..b799c9b01f --- /dev/null +++ b/packages/examples/cvat/exchange-oracle/tests/utils/audio_transcription.py @@ -0,0 +1,108 @@ +from __future__ import annotations + +import math +from typing import TYPE_CHECKING + +from src.core.tasks.audio_transcription.meta import ( + RegionKind, + parse_gt_tsv, +) + +if TYPE_CHECKING: + from src.core.tasks.audio_transcription.meta import Clip, InputGtRegion + +# Canonical audio task input, shared by the task-creation and validation tests so both exercise +# the same layout. DS_ROIS: per-file region start times (each ROI is DS_LEN seconds long). +DS_LEN = 10.0 +DS_ROIS = { + "audio1.wav": [30.0, 45.0, 60.0, 75.0], + "audio2.wav": [30.0, 45.0, 60.0], + "audio3.wav": [10.0, 25.0, 40.0, 55.0], + "audio4.wav": [10.0, 25.0, 40.0], + "audio5.wav": [10.0, 25.0], +} +# (span_id, filename, [(start, stop), ...]) -- 3 GT spans with 1, 2 and 3 cues. Each span covers +# >= min_gt_span_duration and sits after its recording's DS regions, so GT and DS stay disjoint. +GT_ROIS = [ + ("s1", "audio1.wav", [(90.0, 112.0)]), + ("s2", "audio2.wav", [(90.0, 98.0), (106.0, 112.0)]), + ("s3", "audio3.wav", [(80.0, 86.0), (92.0, 98.0), (104.0, 110.0)]), +] +TRANSCRIPTION_ATTR = "transcription" + +# Media, regions and GT share one layout: the recordings must contain every DS/GT cue, so the +# file set and duration are derived from DS_ROIS/GT_ROIS rather than pinned independently. +MEDIA_MARGIN_S = 8.0 + + +def _region_stops() -> list[float]: + ds_stops = [start + DS_LEN for starts in DS_ROIS.values() for start in starts] + gt_stops = [stop for _span_id, _filename, regions in GT_ROIS for _start, stop in regions] + return ds_stops + gt_stops + + +MEDIA_FILES = sorted({*DS_ROIS, *(filename for _span_id, filename, _regions in GT_ROIS)}) +MEDIA_DURATION_S = math.ceil(max(_region_stops()) + MEDIA_MARGIN_S) + + +def ts(seconds: float) -> str: + """Render seconds as an ``H:MM:SS.ffffff`` timestamp (the region/GT/annotation TSV format).""" + h = int(seconds // 3600) + m = int((seconds % 3600) // 60) + s = seconds - h * 3600 - m * 60 + return f"{h}:{m:02d}:{s:09.6f}" + + +def build_regions_tsv(ds_rois: dict[str, list[float]] = DS_ROIS, ds_len: float = DS_LEN) -> str: + return "filename\tstart\tstop\tlabel\n" + "".join( + f"{filename}\t{ts(start)}\t{ts(start + ds_len)}\tspeech\n" + for filename, starts in ds_rois.items() + for start in starts + ) + + +def build_gt_tsv(gt_rois: list = GT_ROIS) -> str: + return "filename\tstart\tstop\tlabel\ttext\tspan_id\n" + "".join( + f"{filename}\t{ts(start)}\t{ts(stop)}\tspeech\tgt {span_id} {roi_idx} text\t{span_id}\n" + for roi_idx, (span_id, filename, regions) in enumerate(gt_rois) + for start, stop in regions + ) + + +def gt_regions_by_id(gt_tsv: str) -> dict[str, InputGtRegion]: + return {region.id: region for region in parse_gt_tsv(gt_tsv.encode())} + + +def build_perfect_annotation( + clip: Clip, + gt: dict[str, InputGtRegion], + *, + transcription_attr: str = TRANSCRIPTION_ATTR, +) -> str: + """Produce an annotator submission TSV that perfectly transcribes every honeypot in ``clip``. + + Each GT cue's source-time window is mapped back to clip time via its placement offset and + emitted with the GT text, so validation aligns it exactly (WER/CER == 0). + """ + rows: list[tuple[float, float, str]] = [] + for placed in clip.placed: + if placed.kind != RegionKind.gt: + continue + offset = placed.source_start - placed.clip_start # clip_time = source_time - offset + for region_id in placed.input_ids: + cue = gt[region_id] + rows.append( + (cue.start.total_seconds() - offset, cue.stop.total_seconds() - offset, cue.text) + ) + rows.sort() + body = "".join(f"{ts(start)}\t{ts(stop)}\tspeech\t{text}\n" for start, stop, text in rows) + return build_empty_annotation(transcription_attr) + body + + +def build_empty_annotation(transcription_attr: str = TRANSCRIPTION_ATTR) -> str: + """An annotator submission with no transcribed intervals. + + Every presented honeypot is then unmatched, so validation scores each as a full deletion + (error rate 1.0) -- i.e. a failing assignment. + """ + return f"start\tstop\tlabel\t{transcription_attr}\n" diff --git a/packages/examples/cvat/exchange-oracle/tests/utils/constants.py b/packages/examples/cvat/exchange-oracle/tests/utils/constants.py index fb27694525..a8588d1a2b 100644 --- a/packages/examples/cvat/exchange-oracle/tests/utils/constants.py +++ b/packages/examples/cvat/exchange-oracle/tests/utils/constants.py @@ -25,7 +25,7 @@ WALLET_ADDRESS1 = "0x86e83d346041E8806e352681f3F14549C0d2BC69" WALLET_ADDRESS2 = "0x86e83d346041E8806e352681f3F14549C0d2BC70" -DEFAULT_MANIFEST_URL = "http://host.docker.internal:9000/manifests/manifest.json" +DEFAULT_MANIFEST_URL = "http://host.docker.internal:9000/manifests/manifest-v1.json" DEFAULT_HASH = "test" SIGNATURE = ( diff --git a/packages/examples/cvat/exchange-oracle/tests/utils/db_helper.py b/packages/examples/cvat/exchange-oracle/tests/utils/db_helper.py index 3fd5e6afe1..57bd5b58b8 100644 --- a/packages/examples/cvat/exchange-oracle/tests/utils/db_helper.py +++ b/packages/examples/cvat/exchange-oracle/tests/utils/db_helper.py @@ -2,7 +2,8 @@ from sqlalchemy.orm import Session -from src.core.types import JobStatuses, Networks, ProjectStatuses, TaskStatuses, TaskTypes +from src.core.tasks import TaskTypes +from src.core.types import JobStatuses, Networks, ProjectStatuses, TaskStatuses from src.models.cvat import Job, Project, Task diff --git a/packages/examples/cvat/exchange-oracle/tests/utils/setup_cvat.py b/packages/examples/cvat/exchange-oracle/tests/utils/setup_cvat.py index 77f657f98b..8f7faf8fc2 100644 --- a/packages/examples/cvat/exchange-oracle/tests/utils/setup_cvat.py +++ b/packages/examples/cvat/exchange-oracle/tests/utils/setup_cvat.py @@ -1,5 +1,4 @@ import hmac -import json import uuid from collections.abc import Generator, Sequence from contextlib import ExitStack, contextmanager @@ -10,21 +9,20 @@ from sqlalchemy.sql import select from src.core.config import CvatConfig -from src.core.types import AssignmentStatuses, JobStatuses, ProjectStatuses, TaskStatuses, TaskTypes +from src.core.tasks import TaskTypes +from src.core.types import AssignmentStatuses, JobStatuses, ProjectStatuses, TaskStatuses from src.db import SessionLocal from src.models.cvat import Assignment, Job, Project, Task, User from tests.utils.constants import ESCROW_ADDRESS -def generate_cvat_signature(data: dict): - b_data = json.dumps(data).encode("utf-8") - +def generate_cvat_signature(body: bytes) -> str: return ( "sha256=" + hmac.new( CvatConfig.webhook_secret.encode("utf-8"), - b_data, + body, digestmod=sha256, ).hexdigest() ) diff --git a/packages/examples/cvat/recording-oracle/.gitignore b/packages/examples/cvat/recording-oracle/.gitignore index a8457398f9..f54bfa1040 100644 --- a/packages/examples/cvat/recording-oracle/.gitignore +++ b/packages/examples/cvat/recording-oracle/.gitignore @@ -1,4 +1,5 @@ /.venv + # Byte-compiled / optimized / DLL files __pycache__/ .pytest_cache diff --git a/packages/examples/cvat/recording-oracle/.pre-commit-config.yaml b/packages/examples/cvat/recording-oracle/.pre-commit-config.yaml index 395275745a..3211dfbcc9 100644 --- a/packages/examples/cvat/recording-oracle/.pre-commit-config.yaml +++ b/packages/examples/cvat/recording-oracle/.pre-commit-config.yaml @@ -3,14 +3,14 @@ repos: hooks: - id: lint name: lint - entry: ruff check --fix --unsafe-fixes --show-fixes + entry: ruff check --force-exclude --fix --unsafe-fixes --show-fixes language: system require_serial: true files: "^packages/examples/cvat/recording-oracle/.*" types: [python] - id: format name: format - entry: ruff format + entry: ruff format --force-exclude require_serial: true language: system files: "^packages/examples/cvat/recording-oracle/.*" diff --git a/packages/examples/cvat/recording-oracle/Dockerfile b/packages/examples/cvat/recording-oracle/Dockerfile index bdc0dd597c..db360bf074 100644 --- a/packages/examples/cvat/recording-oracle/Dockerfile +++ b/packages/examples/cvat/recording-oracle/Dockerfile @@ -8,6 +8,8 @@ RUN apt-get update -y && \ RUN pip install --no-cache 'poetry==1.8.5' +COPY libs ./libs + COPY pyproject.toml poetry.lock ./ RUN --mount=type=cache,target=/root/.cache \ diff --git a/packages/examples/cvat/recording-oracle/README.md b/packages/examples/cvat/recording-oracle/README.md index 77bee0b36d..f9f3adc68f 100644 --- a/packages/examples/cvat/recording-oracle/README.md +++ b/packages/examples/cvat/recording-oracle/README.md @@ -4,14 +4,13 @@ Prerequisites: ``` -1. poetry shell +1. poetry config virtualenvs.in-project true # create .venv inside the project so editors/debuggers pick it up 2. poetry install 3. pre-commit install 4. Make sure you have postgres-devel packages installed on your OS. It is required for psycopg2 build phase. `libpq-dev` in Debian/Ubuntu, `libpq-devel` on Centos/Fedora/Cygwin/Babun.) `postgres` package in the homebrew for macOS -``` - +``` For deployment it is required to have PostgreSQL(v14.4) @@ -30,7 +29,7 @@ docker compose -f docker-compose.dev.yml up -d ./bin/start_debug.sh ``` -When running service from `./bin/start_debug.sh` (`debug.py`), simplified development flow is available: +When running service from `./bin/start_debug.sh`, simplified development flow is available: - When webhook signature is required, `{oracle_name}:unique_string` can be used - You can upload manifest.json to minio `manifests` bucket and use its filename as an escrow_address @@ -73,11 +72,11 @@ Available at `/docs` route A single command to build, run, and tear down the test suite: ```sh -docker compose -p "test" \ +docker compose -p ro-test \ -f docker-compose.test.yml \ -f docker-compose.test.head.yml \ up --build test --attach test --exit-code-from test; \ - docker compose -p "test" \ + docker compose -p ro-test \ -f docker-compose.test.yml \ -f docker-compose.test.head.yml down ``` @@ -91,19 +90,19 @@ commands allow running just the services, build, tear down, and run the test sui ```sh # run services -docker compose -p "test" \ +docker compose -p ro-test \ -f docker-compose.test.yml \ up -d --build # run the tests -docker compose -p "test" \ +docker compose -p ro-test \ -f docker-compose.test.yml \ -f docker-compose.test.head.yml \ -f docker-compose.test.head.dev.yml \ up --build test --attach test --exit-code-from test # tear down -docker compose -p "test" \ +docker compose -p ro-test \ -f docker-compose.test.yml \ -f docker-compose.test.head.yml \ -f docker-compose.test.head.dev.yml \ @@ -111,3 +110,19 @@ docker compose -p "test" \ ``` The dev setup mounts the local directory to speed the things up. + +#### Regenerating the test fixtures + +Recording Oracle tests run against the fixtures produced by the Exchange Oracle implementation. +Regenerate them whenever the builder output layout or the shared task setups change. + +```sh +cd ../exchange-oracle && docker compose -p eo-test \ + -f docker-compose.test.yml \ + -f docker-compose.test.head.yml \ + -f docker-compose.test.head.dev.yml \ + run --rm \ + -v "$(pwd)/../recording-oracle/tests/assets/cloud/audio_validation:/out" \ + test sh -c "alembic upgrade head && PYTHONPATH=. \ + python tests/assets/utils/gen_audio_validation_fixture.py /out" +``` diff --git a/packages/examples/cvat/recording-oracle/alembic.ini b/packages/examples/cvat/recording-oracle/alembic.ini index 2500f81f5e..ec9c8efd55 100644 --- a/packages/examples/cvat/recording-oracle/alembic.ini +++ b/packages/examples/cvat/recording-oracle/alembic.ini @@ -14,6 +14,10 @@ script_location = alembic # defaults to the current working directory. prepend_sys_path = . +# path separator (os = os.pathsep) used to split prepend_sys_path and version_locations; +# the unified key introduced in alembic 1.16, replacing version_path_separator. +path_separator = os + # timezone to use when rendering the date within the migration file # as well as the filename. # If specified, requires the python-dateutil library that can be diff --git a/packages/examples/cvat/recording-oracle/alembic/env.py b/packages/examples/cvat/recording-oracle/alembic/env.py index fde70d21e7..09bbefa476 100644 --- a/packages/examples/cvat/recording-oracle/alembic/env.py +++ b/packages/examples/cvat/recording-oracle/alembic/env.py @@ -18,13 +18,9 @@ disable_existing_loggers=config.attributes.get("disable_existing_loggers", True), ) +import src.models # noqa: E402, F401 (registers all models on Base.metadata for autogenerate) from src.db import Base # noqa: E402 -# add your model's MetaData object here -# for 'autogenerate' support -# from myapp import mymodel -# target_metadata = mymodel.Base.metadata - target_metadata = Base.metadata # other values from the config, defined by the needs of env.py, diff --git a/packages/examples/cvat/recording-oracle/bin/start_debug.sh b/packages/examples/cvat/recording-oracle/bin/start_debug.sh index ff93f4765c..a7d31fdc4f 100755 --- a/packages/examples/cvat/recording-oracle/bin/start_debug.sh +++ b/packages/examples/cvat/recording-oracle/bin/start_debug.sh @@ -1,4 +1,4 @@ export ENVIRONMENT=development alembic upgrade head -python debug.py \ No newline at end of file +python -m src.entrypoints.debug \ No newline at end of file diff --git a/packages/examples/cvat/recording-oracle/bin/start_dev.sh b/packages/examples/cvat/recording-oracle/bin/start_dev.sh index 64f2bd6fe1..66f642002c 100755 --- a/packages/examples/cvat/recording-oracle/bin/start_dev.sh +++ b/packages/examples/cvat/recording-oracle/bin/start_dev.sh @@ -1,4 +1,4 @@ export ENVIRONMENT=development alembic upgrade head -python run.py \ No newline at end of file +python -m src.entrypoints.run \ No newline at end of file diff --git a/packages/examples/cvat/recording-oracle/docker-compose.test.head.yml b/packages/examples/cvat/recording-oracle/docker-compose.test.head.yml index 044c537d3b..557bab8576 100644 --- a/packages/examples/cvat/recording-oracle/docker-compose.test.head.yml +++ b/packages/examples/cvat/recording-oracle/docker-compose.test.head.yml @@ -15,13 +15,13 @@ services: STORAGE_ENDPOINT_URL: 'host.docker.internal:9000' STORAGE_ACCESS_KEY: 'dev' STORAGE_SECRET_KEY: 'devdevdev' - STORAGE_RESULTS_BUCKET_NAME: 'results' + STORAGE_RESULTS_BUCKET_NAME: 'recor-data' STORAGE_PROVIDER: 'aws' STORAGE_USE_SSL: False EXCHANGE_ORACLE_STORAGE_ENDPOINT_URL: 'host.docker.internal:9000' EXCHANGE_ORACLE_STORAGE_ACCESS_KEY: 'dev' EXCHANGE_ORACLE_STORAGE_SECRET_KEY: 'devdevdev' - EXCHANGE_ORACLE_STORAGE_RESULTS_BUCKET_NAME: 'results' + EXCHANGE_ORACLE_STORAGE_RESULTS_BUCKET_NAME: 'excor-data' EXCHANGE_ORACLE_STORAGE_USE_SSL: False EXCHANGE_ORACLE_STORAGE_PROVIDER: 'aws' depends_on: diff --git a/packages/examples/cvat/recording-oracle/docker-compose.test.yml b/packages/examples/cvat/recording-oracle/docker-compose.test.yml index 82c78ff286..98aa584c28 100644 --- a/packages/examples/cvat/recording-oracle/docker-compose.test.yml +++ b/packages/examples/cvat/recording-oracle/docker-compose.test.yml @@ -13,16 +13,19 @@ services: minio: container_name: minio - image: minio/minio:RELEASE.2022-05-26T05-48-41Z + image: minio/minio:RELEASE.2025-09-07T16-13-09Z + ports: + - 9001:9001 + - 9000:9000 environment: MINIO_ROOT_USER: dev MINIO_ROOT_PASSWORD: devdevdev volumes: - - ./tests/utils/manifest.json:/tmp/manifests/manifest.json - - ./tests/utils/intermediate-results.json:/tmp/results/intermediate-results.json + # Each subdirectory under the shared assets dir seeds a same-named bucket. + - ./tests/assets/cloud:/tmp/cloud:ro entrypoint: 'sh' command: - -c "mkdir -p /data/manifests && cp /tmp/manifests/manifest.json /data/manifests/manifest.json && mkdir -p /data/results && cp /tmp/results/intermediate-results.json /data/results/intermediate-results.json && minio server /data --console-address ':9001'" + -c "mkdir -p /data && cp -r /tmp/cloud/. /data/ && minio server /data --console-address ':9001'" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] interval: 5s @@ -40,8 +43,11 @@ services: entrypoint: > /bin/sh -c " /usr/bin/mc config host add myminio http://minio:9000 dev devdevdev; + /usr/bin/mc mb -p myminio/datasets myminio/manifests myminio/excor-data myminio/recor-data; + /usr/bin/mc anonymous set public myminio/datasets; /usr/bin/mc anonymous set public myminio/manifests; - /usr/bin/mc anonymous set public myminio/results; + /usr/bin/mc anonymous set public myminio/excor-data; + /usr/bin/mc anonymous set public myminio/recor-data; " networks: - test-network diff --git a/packages/examples/cvat/recording-oracle/dockerfiles/test.ci.Dockerfile b/packages/examples/cvat/recording-oracle/dockerfiles/test.ci.Dockerfile index 1c39e52f2a..fb45f64890 100644 --- a/packages/examples/cvat/recording-oracle/dockerfiles/test.ci.Dockerfile +++ b/packages/examples/cvat/recording-oracle/dockerfiles/test.ci.Dockerfile @@ -8,6 +8,8 @@ RUN apt-get update -y && \ RUN pip install --no-cache 'poetry==1.8.5' +COPY libs ./libs + COPY pyproject.toml poetry.lock ./ RUN --mount=type=cache,target=/root/.cache \ diff --git a/packages/examples/cvat/recording-oracle/dockerfiles/test.dev.Dockerfile b/packages/examples/cvat/recording-oracle/dockerfiles/test.dev.Dockerfile index fe1143c473..6c8a6017eb 100644 --- a/packages/examples/cvat/recording-oracle/dockerfiles/test.dev.Dockerfile +++ b/packages/examples/cvat/recording-oracle/dockerfiles/test.dev.Dockerfile @@ -11,6 +11,8 @@ RUN apt-get update -y && \ RUN pip install --no-cache 'poetry==1.8.5' +COPY libs ./libs + COPY pyproject.toml poetry.lock ./ RUN --mount=type=cache,target=/root/.cache \ diff --git a/packages/examples/cvat/recording-oracle/libs/audio_qe/LICENSE b/packages/examples/cvat/recording-oracle/libs/audio_qe/LICENSE new file mode 100644 index 0000000000..b17d8e9073 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/libs/audio_qe/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (C) CVAT.ai Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/examples/cvat/recording-oracle/libs/audio_qe/README.md b/packages/examples/cvat/recording-oracle/libs/audio_qe/README.md new file mode 100644 index 0000000000..d1fba3a6f1 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/libs/audio_qe/README.md @@ -0,0 +1,67 @@ +# audio-qe + +Audio transcription quality estimation library for Recording Oracle. + +## Install + +Consumed by the recording oracle as an editable path dependency: + +```toml +audio-qe = {path = "libs/audio_qe", develop = true} +``` + +## Usage + +Inputs are `Interval` sequences (ground truth vs annotator); the transcription text lives in +`Interval.extra[req.text_attribute]`. + +```python +from audio_qe import Interval, TranscriptionRequirement, match_transcriptions + +gt = [Interval(id=0, start=0, stop=2000, label="speech", extra={"text": "hello world"})] +ds = [Interval(id=1, start=0, stop=2000, label="speech", extra={"text": "hello word"})] +req = TranscriptionRequirement(text_attribute="text") # WER, char-align, basic normalizer, join +report = match_transcriptions(gt, ds, req=req) +report.corpus_rate # aggregate error rate +``` + +Entrypoints: + +- `match_intervals(gs, ds, *, config)` - pairwise interval matching. +- `match_transcriptions(gt, ds, *, requirement)` - transcription matching. +- `compare(gt, ds, *, settings)` - interval and transcription matching. + +### Choosing settings + +`TranscriptionRequirement` has three orthogonal axes plus an optional binarizer: + +- **`granularity`** - the unit errors are reported in. `WORD` → WER; `CHARACTER` → CER + (use for CJK and other scripts without word boundaries). +- **`align`** - how the alignment runs. `CHAR` (default) aligns characters then rebuilds word + edits, so it tolerates word-boundary disagreements (`sunday` vs `sun day`); `WORD` is the classic, + word-level alignment with no boundary credit. +- **`metric`** - per-chunk cost. `EQUALITY` (default) is 0/1, i.e. classic WER/CER; `ERROR_RATE` + is recall-shaped (partial credit for near misses); `NORMALIZED_LEV` is symmetric and bounded + `[0, 1]` (use when neither side is the reference, e.g. inter-annotator agreement). +- **`threshold`** - binarizes a soft metric (`cost > threshold → 1`); no-op with `EQUALITY`. + Under `CHARACTER` granularity all metrics degenerate to equality (characters are atomic). + +**Normalizer presets** (applied to both texts before alignment): + +- `NormalizerConfig(mode=NONE)` - passthrough. +- `NormalizerConfig(mode=BASIC)` - universal Unicode + case + whitespace fold (language-agnostic). +- `lang_preset(code)` - language-specific preset (`BASIC` plus per-language rules). Supported codes: + `en, es, fr, de, it, pt, nl, pl, ru, tr, zh, ja, ko, hi, ar`. Unlisted languages fall back to + `BASIC`. + +`grouping.strategy`: +- `JOIN` (concatenate each group's text, then one alignment - default) +- `FILTER` (pair intervals by IoU first). + +Recommended default for annotator-vs-GT review: +`granularity=WORD, align=CHAR, metric=EQUALITY` - boundary-tolerant WER. + +## License + +MIT. Ported from [CVAT](https://github.com/cvat-ai/cvat). See [LICENSE](LICENSE); source files +retain their `SPDX-License-Identifier: MIT`. diff --git a/packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/__init__.py b/packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/__init__.py new file mode 100644 index 0000000000..965ca81eed --- /dev/null +++ b/packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/__init__.py @@ -0,0 +1,102 @@ +# Copyright (C) CVAT.ai Corporation +# +# SPDX-License-Identifier: MIT + +"""Public surface of the audio QE pipeline. + +Domain types, settings, reports, and algorithms are defined in the +thematic sub-modules; this file re-exports the names callers most +often need so they can write `from cvat.apps.quality_control import +audio` and then access everything via `audio.X`. +""" + +from .config import ( + GroupingConfig, + IntervalMatchingConfig, + NormalizerConfig, + QualitySettings, + StepConfig, + TranscriptionRequirement, +) +from .data import ( + AlignMode, + EditOp, + Granularity, + GroupingStrategy, + GroupKey, + Interval, + Metric, + NormalizerMode, +) +from .interval_matching import match_intervals +from .normalization import ( + BASIC_STACK, + LANG_PRESETS, + SUPPORTED_LANGS, + Normalizer, + lang_preset, + register_step, + step_available, +) +from .pipeline import compare +from .reports import ( + AlignmentEdit, + AlignmentResult, + BoundaryAgreement, + ComparisonReport, + FilterPairAlignment, + GroupAlignment, + IntervalPairMetrics, + IntervalReport, + TranscriptionReport, +) +from .transcription_matching import match_transcriptions + +__all__ = [ + # data + "Interval", + "Granularity", + "GroupKey", + "AlignMode", + "EditOp", + "GroupingStrategy", + "Metric", + "NormalizerMode", + # + # config + "StepConfig", + "NormalizerConfig", + "GroupingConfig", + "TranscriptionRequirement", + "IntervalMatchingConfig", + "QualitySettings", + # + # reports + "AlignmentEdit", + "AlignmentResult", + "BoundaryAgreement", + "ComparisonReport", + "FilterPairAlignment", + "GroupAlignment", + "IntervalPairMetrics", + "IntervalReport", + "TranscriptionReport", + # + # normalization + "Normalizer", + "BASIC_STACK", + "LANG_PRESETS", + "SUPPORTED_LANGS", + "lang_preset", + "register_step", + "step_available", + # + # interval matching + "match_intervals", + # + # transcription matching + "match_transcriptions", + # + # top-level + "compare", +] diff --git a/packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/config.py b/packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/config.py new file mode 100644 index 0000000000..79dcc19b40 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/config.py @@ -0,0 +1,90 @@ +# Copyright (C) CVAT.ai Corporation +# +# SPDX-License-Identifier: MIT + +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import Any + +from .data import AlignMode, Granularity, GroupingStrategy, Metric, NormalizerMode + + +@dataclass +class StepConfig: + """One layer in the normalization pipeline.""" + + name: str # registered step name + options: dict[str, Any] = field(default_factory=dict) + + +@dataclass +class NormalizerConfig: + """ + NormalizerMode selects the stack: + - NONE — passthrough + - BASIC — universal Unicode/whitespace/case layer (language-agnostic) + - CUSTOM — explicit pipeline; caller provides `steps` + """ + + mode: NormalizerMode = NormalizerMode.BASIC + steps: list[StepConfig] = field(default_factory=list) + + +@dataclass +class GroupingConfig: + attribute: str | None = None # None → group by label only + strategy: GroupingStrategy = GroupingStrategy.JOIN + join_separator: str = " " + + +@dataclass +class TranscriptionRequirement: + name: str = "transcription" # human-readable, used in report headings + text_attribute: str = "transcription" # which column / attr holds text + + # Output unit of the reported rate (CER vs WER vs SER scope). + # WORD → WER-family + # CHARACTER → CER-family + granularity: Granularity = Granularity.WORD + + # Alignment regime. + # CHAR — char-level Levenshtein DP (default; handles arbitrary + # N-to-M boundary cases via natural char alignment) + # WORD — word-level (token) Levenshtein DP (faster, no boundary + # detection; equivalent to plain WER when granularity=word) + align: AlignMode = AlignMode.CHAR + + # Per-chunk cost function. Softness is a property of the metric + # itself rather than a side-channel knob. + # For granularity=CHARACTER (atomic units): all three metrics + # degenerate to EQUALITY. Only granularity=WORD makes the choice + # meaningful. + metric: Metric = Metric.EQUALITY + + # If set, per-chunk cost is rounded: cost > threshold → 1, else 0. + # Turns any soft metric into a binary one. With metric=EQUALITY the + # threshold is a no-op. + threshold: float | None = None + + normalizer: NormalizerConfig = field(default_factory=NormalizerConfig) + grouping: GroupingConfig = field(default_factory=GroupingConfig) + iou_threshold: float = 0.3 # used by FILTER strategy + enforce_overlap: bool = True # join: forbid token match between non-overlapping intervals + + # Gap (ms) by which the join overlap gate is relaxed: intervals separated by + # up to this much still count as overlapping. + overlap_tolerance_ms: float = 0.0 + + +@dataclass +class IntervalMatchingConfig: + iou_threshold: float = 0.3 + low_overlap_threshold: float = 0.5 + boundary_tolerance_ms: float = 200.0 # boundary-F1 timestamp tolerance + + +@dataclass +class QualitySettings: + interval_matching: IntervalMatchingConfig = field(default_factory=IntervalMatchingConfig) + transcriptions: list[TranscriptionRequirement] = field(default_factory=list) diff --git a/packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/data.py b/packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/data.py new file mode 100644 index 0000000000..bdd6defc0e --- /dev/null +++ b/packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/data.py @@ -0,0 +1,84 @@ +# Copyright (C) CVAT.ai Corporation +# +# SPDX-License-Identifier: MIT + +from __future__ import annotations + +from dataclasses import dataclass, field +from enum import Enum + + +@dataclass(frozen=True) +class Interval: + id: int + start: float # milliseconds + stop: float # milliseconds + label: str + source: str = "" + score: float = 1.0 + extra: dict[str, str] = field(default_factory=dict) + + @property + def duration(self) -> float: + return self.stop - self.start + + +class Granularity(str, Enum): + """Output unit of the reported rate (CER / WER / SER scope).""" + + WORD = "word" + CHARACTER = "character" + + +class AlignMode(str, Enum): + """Transcription alignment mode — what unit the DP operates on.""" + + CHAR = "char" + "char-level Levenshtein DP, word-edit reconstruction" + + WORD = "word" + "word-level Levenshtein DP, no boundary detection" + + +class Metric(str, Enum): + """Per-chunk cost function for L2 scoring.""" + + EQUALITY = "equality" + "0/1 strict per chunk" + + ERROR_RATE = "error-rate" + "char_edits / len(ref) — recall-shaped" + + NORMALIZED_LEV = "normalized-lev" + "char_edits / max(len) — bounded" + + +class NormalizerMode(str, Enum): + """Top-level normalizer mode selector.""" + + NONE = "none" # passthrough + BASIC = "basic" # universal Unicode / whitespace / case stack + CUSTOM = "custom" # caller-supplied `steps` + + +class GroupingStrategy(str, Enum): + """How to combine intervals within a (label, attr) group.""" + + FILTER = "filter" + "Match intervals by IoU and label, match text in pairs" + + JOIN = "join" + "Concatenate text per group key, align" + + +class EditOp(str, Enum): + """Per-chunk operation produced by the L2 aligner.""" + + EQUAL = "equal" + SUBSTITUTE = "substitute" + INSERT = "insert" + DELETE = "delete" + BOUNDARY = "boundary" # N-to-1 / 1-to-N word-boundary disagreement + + +GroupKey = tuple[str, str | None] # (label, attr_value_or_None) diff --git a/packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/interval_matching.py b/packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/interval_matching.py new file mode 100644 index 0000000000..78a14c545d --- /dev/null +++ b/packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/interval_matching.py @@ -0,0 +1,215 @@ +# Copyright (C) CVAT.ai Corporation +# +# SPDX-License-Identifier: MIT + +from __future__ import annotations + +from typing import Callable, Sequence + +from .config import IntervalMatchingConfig +from .data import Interval +from .reports import BoundaryAgreement, IntervalPairMetrics, IntervalReport + + +def iou(a: Interval, b: Interval) -> float: + lo = max(a.start, b.start) + hi = min(a.stop, b.stop) + inter = hi - lo + if inter <= 0: + return 0.0 + uni = max(a.stop, b.stop) - min(a.start, b.start) + return inter / uni if uni > 0 else 0.0 + + +def _label_eq(a: Interval, b: Interval) -> bool: + return a.label == b.label + + +def match_segments( + a_segms: Sequence[Interval], + b_segms: Sequence[Interval], + *, + distance: Callable[[Interval, Interval], float], + dist_thresh: float = 1.0, + label_matcher: Callable[[Interval, Interval], bool] = _label_eq, +) -> tuple[ + list[tuple[Interval, Interval]], + list[tuple[Interval, Interval]], + list[Interval], + list[Interval], +]: + # Ported verbatim from cvat.apps.quality_control.quality_reports.match_segments + # (numpy + scipy are imported lazily so the package imports without scipy when the + # Hungarian/FILTER path is unused). + import itertools + + import numpy as np + from scipy.optimize import linear_sum_assignment + + max_anns = max(len(a_segms), len(b_segms)) + distances = np.array( + [ + [ + 1 - distance(a, b) if a is not None and b is not None else 1 + for b, _ in itertools.zip_longest(b_segms, range(max_anns), fillvalue=None) + ] + for a, _ in itertools.zip_longest(a_segms, range(max_anns), fillvalue=None) + ] + ) + distances[~np.isfinite(distances)] = 1 + distances[distances > 1 - dist_thresh] = 1 + + if a_segms and b_segms: + a_matches, b_matches = linear_sum_assignment(distances) + else: + a_matches = [] + b_matches = [] + + matches = [] + mispred = [] + a_unmatched = [] + b_unmatched = [] + + for a_idx, b_idx in zip(a_matches, b_matches): + dist = distances[a_idx, b_idx] + if dist > 1 - dist_thresh or dist == 1: + if a_idx < len(a_segms): + a_unmatched.append(a_segms[a_idx]) + if b_idx < len(b_segms): + b_unmatched.append(b_segms[b_idx]) + else: + a_ann = a_segms[a_idx] + b_ann = b_segms[b_idx] + if label_matcher(a_ann, b_ann): + matches.append((a_ann, b_ann)) + else: + mispred.append((a_ann, b_ann)) + + if not len(a_matches) and not len(b_matches): + a_unmatched = list(a_segms) + b_unmatched = list(b_segms) + + return matches, mispred, a_unmatched, b_unmatched + + +def _hungarian_match( + gt: Sequence[Interval], + ds: Sequence[Interval], + *, + distance: Callable[[Interval, Interval], float], + iou_thresh: float, + label_matcher: Callable[[Interval, Interval], bool] = _label_eq, +) -> tuple[ + list[tuple[Interval, Interval]], + list[tuple[Interval, Interval]], + list[Interval], + list[Interval], +]: + return match_segments( + gt, ds, distance=distance, dist_thresh=iou_thresh, label_matcher=label_matcher + ) + + +def _two_stage_match(gt: Sequence[Interval], ds: Sequence[Interval], *, iou_thresh: float) -> tuple[ + list[tuple[Interval, Interval]], + list[tuple[Interval, Interval]], + list[Interval], + list[Interval], +]: + """Two-pass Hungarian: first pass prefers same-label pairs, second pass + picks up remaining different-label pairs. Keeps high-quality label + matches from getting outbid by IoU-only matches with the wrong label.""" + + def iou_with_label(a: Interval, b: Interval) -> float: + return iou(a, b) if _label_eq(a, b) else 0.0 + + matches, _, gt_u, ds_u = _hungarian_match( + gt, ds, distance=iou_with_label, iou_thresh=iou_thresh + ) + _, mispred, gt_u, ds_u = _hungarian_match(gt_u, ds_u, distance=iou, iou_thresh=iou_thresh) + return matches, mispred, gt_u, ds_u + + +def _collect_boundaries(intervals: Sequence[Interval]) -> list[float]: + pts: list[float] = [] + for iv in intervals: + pts.append(iv.start) + pts.append(iv.stop) + return sorted(pts) + + +def boundary_f1( + ref_boundaries: Sequence[float], + hyp_boundaries: Sequence[float], + *, + tolerance_ms: float, +) -> BoundaryAgreement: + """Greedy nearest-neighbor matching of boundary timestamps within a + fixed temporal tolerance. Returns precision / recall / F1 plus + raw tp / fp / fn counts.""" + + matched: set[int] = set() + tp = 0 + for r in ref_boundaries: + best_idx = -1 + best_d = tolerance_ms + 1e-9 + for i, h in enumerate(hyp_boundaries): + if i in matched: + continue + d = abs(r - h) + if d <= best_d: + best_idx, best_d = i, d + if best_idx >= 0 and best_d <= tolerance_ms: + matched.add(best_idx) + tp += 1 + fp = len(hyp_boundaries) - len(matched) + fn = len(ref_boundaries) - tp + precision = tp / (tp + fp) if (tp + fp) else 1.0 + recall = tp / (tp + fn) if (tp + fn) else 1.0 + f1 = 2 * precision * recall / (precision + recall) if (precision + recall) else 0.0 + return BoundaryAgreement(tp=tp, fp=fp, fn=fn, precision=precision, recall=recall, f1=f1) + + +def match_intervals( + gt: Sequence[Interval], ds: Sequence[Interval], *, config: IntervalMatchingConfig +) -> IntervalReport: + """ + Compare intervals at the boundary level. This function does not touch transcriptions. + + Pairs GT and DS intervals by IoU + label using a two-stage Hungarian + assignment, then derives per-pair spatial metrics (IoU, onset / offset + deltas, label match). Boundary-F1 also lives here because it is a + purely temporal metric — it cares where intervals start / stop, not + what they contain. + """ + + matches, mispred, gt_unmatched, ds_unmatched = _two_stage_match( + gt, ds, iou_thresh=config.iou_threshold + ) + + def to_metric(a: Interval, b: Interval) -> IntervalPairMetrics: + return IntervalPairMetrics( + gt=a, + ds=b, + iou=iou(a, b), + onset_delta=b.start - a.start, + offset_delta=b.stop - a.stop, + label_match=_label_eq(a, b), + ) + + boundary = boundary_f1( + _collect_boundaries(gt), + _collect_boundaries(ds), + tolerance_ms=config.boundary_tolerance_ms, + ) + + return IntervalReport( + matches=[to_metric(a, b) for a, b in matches], + label_mismatches=[to_metric(a, b) for a, b in mispred], + gt_unmatched=gt_unmatched, + ds_unmatched=ds_unmatched, + iou_threshold=config.iou_threshold, + low_overlap_threshold=config.low_overlap_threshold, + boundary_tolerance_ms=config.boundary_tolerance_ms, + boundary=boundary, + ) diff --git a/packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/normalization.py b/packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/normalization.py new file mode 100644 index 0000000000..acde781d22 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/normalization.py @@ -0,0 +1,553 @@ +# Copyright (C) CVAT.ai Corporation +# +# SPDX-License-Identifier: MIT + +""" +Text normalization for the audio QE pipeline. + +Pipeline of small composable steps. Pick a preset (`basic`) or build +custom pipelines (e.g. `[unicode, casefold, russian_yo, +collapse_whitespace]`). Layered design lets language-specific and +project-specific rules live next to universal Unicode / whitespace +cleanup without forking the normalizer code. +`step_available(name)` and fall back to DIY equivalents. +""" + +from __future__ import annotations + +import re +import unicodedata +from typing import Callable + +from .config import NormalizerConfig, StepConfig +from .data import NormalizerMode + +# English contractions — used by `expand_contractions_en` step. +# Specific patterns first; broad `\w+n't` last so it can't eat exceptions. +_EN_CONTRACTIONS = [ + (r"\bcan't\b", "can not"), + (r"\bwon't\b", "will not"), + (r"\bshan't\b", "shall not"), + (r"\bain't\b", "is not"), + (r"\bi'm\b", "i am"), + (r"\b(it|he|she|that|there|here|what|who|where|how|when|let)'s\b", r"\1 is"), + (r"\b(i|you|we|they|who)'ve\b", r"\1 have"), + (r"\b(i|you|he|she|it|we|they)'ll\b", r"\1 will"), + (r"\b(i|you|he|she|it|we|they)'d\b", r"\1 would"), + ( + r"\b(do|does|did|is|are|was|were|have|has|had|would|could|should|will|" + r"wouldn|shouldn|couldn|don|doesn|didn|isn|aren|wasn|weren|hasn|" + r"haven|hadn|mustn|needn)'t\b", + r"\1 not", + ), +] + +_ZERO_WIDTH_RE = re.compile(r"[​‌‍⁠­]") +_BRACKETED_RE = re.compile(r"\[[^\]]*\]|\([^\)]*\)|<[^>]*>") +_WS_RE = re.compile(r"\s+") + +NormalizationStep = Callable[[str], str] +_STEP_REGISTRY: dict[str, Callable[..., NormalizationStep]] = {} + + +def register_step(name: str): + def deco(factory: Callable[..., NormalizationStep]) -> Callable[..., NormalizationStep]: + _STEP_REGISTRY[name] = factory + return factory + + return deco + + +@register_step("unicode") +def _step_unicode(form: str = "NFKC") -> NormalizationStep: + return lambda t: unicodedata.normalize(form, t) + + +@register_step("zero_width_strip") +def _step_zero_width_strip() -> NormalizationStep: + return lambda t: _ZERO_WIDTH_RE.sub("", t) + + +@register_step("casefold") +def _step_casefold() -> NormalizationStep: + """Locale-independent lowercase. Beats `.lower()` for Turkish/Azeri/German.""" + return lambda t: t.casefold() + + +@register_step("strip_brackets") +def _step_strip_brackets() -> NormalizationStep: + """Remove [tags], (asides), . Useful for sound events / speaker tags.""" + return lambda t: _BRACKETED_RE.sub(" ", t) + + +@register_step("strip_punct") +def _step_strip_punct(preserve: list[str] | None = None) -> NormalizationStep: + preserve_set = set(preserve or []) + + def fn(t: str) -> str: + out = [] + for ch in t: + if ch.isalnum() or ch.isspace() or ch in preserve_set: + out.append(ch) + else: + cat = unicodedata.category(ch) + # Keep modifier letters etc.; only strip explicit punct/symbols. + if cat.startswith("P") or cat.startswith("S"): + out.append(" ") + else: + out.append(ch) + return "".join(out) + + return fn + + +@register_step("collapse_whitespace") +def _step_collapse_whitespace() -> NormalizationStep: + return lambda t: _WS_RE.sub(" ", t).strip() + + +@register_step("unify_apostrophes") +def _step_unify_apostrophes() -> NormalizationStep: + """Curly + modifier apostrophes → ASCII '. Run before contraction expansion.""" + return lambda t: t.replace("’", "'").replace("‘", "'").replace("ʼ", "'") + + +@register_step("unify_quotes") +def _step_unify_quotes() -> NormalizationStep: + return lambda t: (t.replace("“", '"').replace("”", '"').replace("«", '"').replace("»", '"')) + + +@register_step("substitutions") +def _step_substitutions(map: dict[str, str] | None = None) -> NormalizationStep: + items = list((map or {}).items()) + + def fn(t: str) -> str: + for src, dst in items: + t = t.replace(src, dst) + return t + + return fn + + +@register_step("regex_substitute") +def _step_regex_substitute( + patterns: list[tuple[str, str]] | None = None, flags: int = 0 +) -> NormalizationStep: + compiled = [(re.compile(p, flags), r) for p, r in (patterns or [])] + + def fn(t: str) -> str: + for p, r in compiled: + t = p.sub(r, t) + return t + + return fn + + +@register_step("expand_contractions_en") +def _step_expand_contractions_en() -> NormalizationStep: + compiled = [(re.compile(p, re.IGNORECASE), r) for p, r in _EN_CONTRACTIONS] + + def fn(t: str) -> str: + for p, r in compiled: + t = p.sub(r, t) + return t + + return fn + + +# Language-specific helpers — stdlib-only. Heavier ones (opencc, jaconv, pyarabic) +# live behind optional imports if/when needed. + + +@register_step("russian_yo") +def _step_russian_yo() -> NormalizationStep: + """Collapse ё→е (Russian) — same word, two spellings in practice.""" + return lambda t: t.replace("ё", "е").replace("Ё", "Е") + + +@register_step("german_eszett") +def _step_german_eszett() -> NormalizationStep: + """ß → ss. Common for Swiss-German compat or relaxed comparison.""" + return lambda t: t.replace("ß", "ss") + + +@register_step("arabic_alef_unify") +def _step_arabic_alef_unify() -> NormalizationStep: + """أ إ آ → ا (hamza-bearing alef variants → bare alef).""" + + def fn(t: str) -> str: + return t.replace("أ", "ا").replace("إ", "ا").replace("آ", "ا") + + return fn + + +@register_step("arabic_yaa_unify") +def _step_arabic_yaa_unify() -> NormalizationStep: + """ى → ي (alef maqsura → yaa).""" + return lambda t: t.replace("ى", "ي") + + +@register_step("strip_diacritics") +def _step_strip_diacritics() -> NormalizationStep: + """Strip combining marks (Mn). Useful for Arabic harakat, Hebrew niqqud, etc.""" + + def fn(t: str) -> str: + decomposed = unicodedata.normalize("NFD", t) + out = "".join(c for c in decomposed if unicodedata.category(c) != "Mn") + return unicodedata.normalize("NFC", out) + + return fn + + +@register_step("arabic_tatweel_strip") +def _step_arabic_tatweel_strip() -> NormalizationStep: + """Remove tatweel (ـ U+0640) — purely decorative elongation.""" + return lambda t: t.replace("ـ", "") + + +# Devanagari ----------------------------------------------------------------- + +# Precomposed nukta forms → canonical decomposed forms (via NFC after replace). +# Keep canonical NFC form to match modern data, but unify legacy variants. +_DEVANAGARI_NUKTA_MAP = { + "क़": "क़", # क़ → क + nukta + "ख़": "ख़", # ख़ + "ग़": "ग़", # ग़ + "ज़": "ज़", # ज़ + "ड़": "ड़", # ड़ + "ढ़": "ढ़", # ढ़ + "फ़": "फ़", # फ़ + "य़": "य़", # य़ +} + + +@register_step("hindi_danda") +def _step_hindi_danda() -> NormalizationStep: + """Danda । and double-danda ॥ → space.""" + return lambda t: t.replace("।", " ").replace("॥", " ") + + +@register_step("hindi_nukta_unify") +def _step_hindi_nukta_unify() -> NormalizationStep: + """Decompose precomposed nukta letters; NFC re-composes consistently downstream.""" + items = list(_DEVANAGARI_NUKTA_MAP.items()) + + def fn(t: str) -> str: + for src, dst in items: + t = t.replace(src, dst) + return t + + return fn + + +@register_step("hindi_chandrabindu") +def _step_hindi_chandrabindu() -> NormalizationStep: + """Chandrabindu ँ → anusvara ं (collapse marks treated equivalent in speech).""" + return lambda t: t.replace("ँ", "ं") + + +# CJK ------------------------------------------------------------------------ + +# Common Chinese / Japanese punctuation. NFKC already maps full-width ASCII +# punctuation; this catches genuinely-CJK punctuation that NFKC doesn't touch. +_CJK_PUNCT = ",。、;:?!…—·「」『』〈〉《》【】〖〗〔〕" + + +@register_step("cjk_punct_strip") +def _step_cjk_punct_strip() -> NormalizationStep: + tbl = str.maketrans({ch: " " for ch in _CJK_PUNCT}) + return lambda t: t.translate(tbl) + + +# Turkish -------------------------------------------------------------------- + + +@register_step("turkish_dotted_i") +def _step_turkish_dotted_i() -> NormalizationStep: + """Locale-correct İ/I → i/ı. Apply before casefold for Turkish/Azeri.""" + + def fn(t: str) -> str: + return t.replace("İ", "i").replace( # İ → i + "I", "ı" + ) # I → ı (intentional; pair with casefold) + + return fn + + +# Dutch ---------------------------------------------------------------------- + + +@register_step("dutch_ij_normalize") +def _step_dutch_ij_normalize() -> NormalizationStep: + """Ligature ij/IJ → i+j / I+J. NFKC also does this; explicit step for clarity.""" + return lambda t: t.replace("ij", "ij").replace("IJ", "IJ") + + +# Optional third-party steps ------------------------------------------------- +# +# Registered only when the matching package is importable. Calling +# `step_available(name)` lets presets fall back to DIY if missing. + + +def step_available(name: str) -> bool: + return name in _STEP_REGISTRY + + +try: # pragma: no cover - optional dependency + import inflect as _inflect # type: ignore + + _INFLECT_ENGINE = _inflect.engine() + _NUM_RE = re.compile(r"-?\d+(?:[.,]\d+)?") + + @register_step("expand_numerals_en") + def _step_expand_numerals_en() -> NormalizationStep: + """Replace numbers with English words (`23` → `twenty three`). + Requires `inflect` (MIT, ~250 KB). Skip step if not installed.""" + + def to_words(match: re.Match[str]) -> str: + raw = match.group(0).replace(",", ".") + return _INFLECT_ENGINE.number_to_words(raw).replace("-", " ") + + return lambda t: _NUM_RE.sub(to_words, t) + +except ImportError: # pragma: no cover + pass + + +try: # pragma: no cover - optional dependency + import ftfy as _ftfy # type: ignore + + @register_step("ftfy_fix") + def _step_ftfy_fix( + normalization: str = "NFC", + unescape_html: bool = True, + ) -> NormalizationStep: + """Robust input cleanup: mojibake, HTML entities, curly punct, ligatures, + zero-width chars, NBSP. Requires `ftfy` (MIT, ~1 MB).""" + + cfg = _ftfy.TextFixerConfig( + normalization=normalization, + unescape_html=unescape_html, + ) + return lambda t: _ftfy.fix_text(t, cfg) + +except ImportError: # pragma: no cover + pass + + +try: # pragma: no cover - optional dependency + import zhconv as _zhconv # type: ignore + + @register_step("zhconv_simplify") + def _step_zhconv_simplify(variant: str = "zh-cn") -> NormalizationStep: + """Convert Chinese to Simplified. variant: zh-cn (mainland), zh-sg, zh-my. + Requires `zhconv` (MIT, ~700 KB).""" + return lambda t: _zhconv.convert(t, variant) + + @register_step("zhconv_traditional") + def _step_zhconv_traditional(variant: str = "zh-tw") -> NormalizationStep: + """Convert Chinese to Traditional. variant: zh-tw (Taiwan), zh-hk (HK).""" + return lambda t: _zhconv.convert(t, variant) + +except ImportError: # pragma: no cover + pass + + +# Preset stacks -------------------------------------------------------------- + + +BASIC_STACK: list[StepConfig] = [ + StepConfig("unify_apostrophes"), + StepConfig("unify_quotes"), + StepConfig("unicode", {"form": "NFKC"}), + StepConfig("zero_width_strip"), + StepConfig("casefold"), + StepConfig("strip_brackets"), + StepConfig("strip_punct"), + StepConfig("collapse_whitespace"), +] + + +# Language presets. Each preset is built as: +# +# The prefix prefers `ftfy_fix` if available (handles mojibake / HTML / +# curly punct / zero-width / ligatures in one robust step). Otherwise it +# falls back to DIY apostrophe + quote + zero-width steps. + + +def _prefix_steps(use_ftfy: bool) -> list[StepConfig]: + if use_ftfy and step_available("ftfy_fix"): + return [ + StepConfig("ftfy_fix", {"normalization": "NFC", "unescape_html": True}), + StepConfig("strip_brackets"), + ] + return [ + StepConfig("unify_apostrophes"), + StepConfig("unify_quotes"), + StepConfig("zero_width_strip"), + StepConfig("strip_brackets"), + ] + + +_SUFFIX_STEPS: list[StepConfig] = [ + StepConfig("strip_punct"), + StepConfig("collapse_whitespace"), +] + + +def _lang_body(code: str, *, use_zhconv: bool) -> list[StepConfig]: + if code == "en": + return [ + StepConfig("unicode", {"form": "NFKC"}), + StepConfig("casefold"), + StepConfig("expand_contractions_en"), + ] + if code in ("es", "fr", "it", "pt", "pl"): + return [StepConfig("unicode", {"form": "NFC"}), StepConfig("casefold")] + if code == "de": + return [ + StepConfig("unicode", {"form": "NFC"}), + StepConfig("casefold"), + StepConfig("german_eszett"), + ] + if code == "nl": + return [ + StepConfig("unicode", {"form": "NFC"}), + StepConfig("dutch_ij_normalize"), + StepConfig("casefold"), + ] + if code == "ru": + return [ + StepConfig("unicode", {"form": "NFC"}), + StepConfig("casefold"), + StepConfig("russian_yo"), + ] + if code == "tr": + return [ + StepConfig("unicode", {"form": "NFC"}), + StepConfig("turkish_dotted_i"), + StepConfig("casefold"), + ] + if code == "zh": + steps: list[StepConfig] = [ + StepConfig("unicode", {"form": "NFKC"}), + StepConfig("cjk_punct_strip"), + ] + if use_zhconv and step_available("zhconv_simplify"): + steps.append(StepConfig("zhconv_simplify", {"variant": "zh-cn"})) + return steps + if code == "ja": + return [ + StepConfig("unicode", {"form": "NFKC"}), + StepConfig("cjk_punct_strip"), + ] + if code == "ko": + return [ + StepConfig("unicode", {"form": "NFC"}), + StepConfig("cjk_punct_strip"), + ] + if code == "hi": + return [ + StepConfig("hindi_nukta_unify"), + StepConfig("unicode", {"form": "NFC"}), + StepConfig("hindi_danda"), + StepConfig("hindi_chandrabindu"), + ] + if code == "ar": + return [ + StepConfig("unicode", {"form": "NFC"}), + StepConfig("arabic_tatweel_strip"), + StepConfig("arabic_alef_unify"), + StepConfig("arabic_yaa_unify"), + StepConfig("strip_diacritics"), + ] + raise ValueError(f"no preset for language {code!r}") + + +SUPPORTED_LANGS: tuple[str, ...] = ( + "en", + "es", + "fr", + "de", + "it", + "pt", + "nl", + "pl", + "ru", + "tr", + "zh", + "ja", + "ko", + "hi", + "ar", +) + + +def lang_preset( + code: str, + *, + with_numerals: bool = False, + use_ftfy: bool = True, + use_zhconv: bool = True, +) -> NormalizerConfig: + """Build a NormalizerConfig for a language code. + + `use_ftfy` / `use_zhconv` are opt-out flags — when the optional libs are + installed they replace DIY steps; flip to False for fully-deterministic DIY + output regardless of installed packages. + """ + + if code not in SUPPORTED_LANGS: + raise ValueError(f"no preset for language {code!r}; available: {sorted(SUPPORTED_LANGS)}") + steps: list[StepConfig] = [ + *_prefix_steps(use_ftfy), + *_lang_body(code, use_zhconv=use_zhconv), + *_SUFFIX_STEPS, + ] + if with_numerals and code == "en" and step_available("expand_numerals_en"): + idx = next((i for i, s in enumerate(steps) if s.name == "strip_punct"), len(steps)) + steps.insert(idx, StepConfig("expand_numerals_en")) + return NormalizerConfig(mode=NormalizerMode.CUSTOM, steps=steps) + + +# Backward-compatible attribute for code that read LANG_PRESETS as a dict. +LANG_PRESETS: dict[str, list[StepConfig]] = { + code: lang_preset(code).steps for code in SUPPORTED_LANGS +} + + +def _build_step(cfg: StepConfig) -> NormalizationStep: + try: + factory = _STEP_REGISTRY[cfg.name] + except KeyError as exc: + raise ValueError( + f"unknown normalization step {cfg.name!r}; available: {sorted(_STEP_REGISTRY)}" + ) from exc + return factory(**cfg.options) + + +class Normalizer: + def __init__(self, cfg: NormalizerConfig) -> None: + self.cfg = cfg + if cfg.mode == NormalizerMode.NONE: + steps_cfg: list[StepConfig] = [] + elif cfg.mode == NormalizerMode.BASIC: + steps_cfg = BASIC_STACK + elif cfg.mode == NormalizerMode.CUSTOM: + steps_cfg = cfg.steps + else: + raise ValueError( + f"normalizer mode must be one of " + f"{[m.value for m in NormalizerMode]!r}, got {cfg.mode!r}" + ) + self._steps: list[NormalizationStep] = [_build_step(s) for s in steps_cfg] + self._step_names: list[str] = [s.name for s in steps_cfg] + + @property + def step_names(self) -> list[str]: + return list(self._step_names) + + def __call__(self, text: str) -> str: + for step in self._steps: + text = step(text) + return text diff --git a/packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/pipeline.py b/packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/pipeline.py new file mode 100644 index 0000000000..2b97200717 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/pipeline.py @@ -0,0 +1,24 @@ +# Copyright (C) CVAT.ai Corporation +# +# SPDX-License-Identifier: MIT + +from __future__ import annotations + +from typing import Sequence + +from .config import QualitySettings +from .data import Interval +from .interval_matching import match_intervals +from .reports import ComparisonReport +from .transcription_matching import match_transcriptions + + +def compare( + gt: Sequence[Interval], ds: Sequence[Interval], *, settings: QualitySettings +) -> ComparisonReport: + return ComparisonReport( + gt=list(gt), + ds=list(ds), + intervals=match_intervals(gt, ds, config=settings.interval_matching), + transcriptions=[match_transcriptions(gt, ds, req=req) for req in settings.transcriptions], + ) diff --git a/packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/reports.py b/packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/reports.py new file mode 100644 index 0000000000..d9c071eec7 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/reports.py @@ -0,0 +1,165 @@ +# Copyright (C) CVAT.ai Corporation +# +# SPDX-License-Identifier: MIT + +""" +Output / intermediate result shapes for the audio QE pipeline. + +`compare()` returns a `ComparisonReport`; the rest of the dataclasses +here capture intermediate alignment products used while building it. +The CVAT side (`cvat.apps.quality_control.quality_reports`) consumes +the top-level fields to fill its persisted `QualityReport.data` +JSON. +""" + +from __future__ import annotations + +from dataclasses import dataclass + +from .config import TranscriptionRequirement +from .data import EditOp, Granularity, GroupKey, Interval + +# ============================ Interval matching layer ============================ + + +@dataclass +class IntervalPairMetrics: + gt: Interval + ds: Interval + iou: float + onset_delta: float + offset_delta: float + label_match: bool + + +@dataclass +class BoundaryAgreement: + tp: int + fp: int + fn: int + precision: float + recall: float + f1: float + + +@dataclass +class IntervalReport: + matches: list[IntervalPairMetrics] + label_mismatches: list[IntervalPairMetrics] + gt_unmatched: list[Interval] + ds_unmatched: list[Interval] + iou_threshold: float + low_overlap_threshold: float + boundary_tolerance_ms: float + boundary: BoundaryAgreement | None = None + + @property + def low_overlap(self) -> list[IntervalPairMetrics]: + return [m for m in self.matches if m.iou < self.low_overlap_threshold] + + +# ============================ Transcription layer ================================ + + +# ============================ Transcription alignment ============================ + + +@dataclass +class AlignmentEdit: + op: EditOp + ref_start: int + ref_end: int # exclusive + hyp_start: int + hyp_end: int # exclusive + ref_units: list[str] + hyp_units: list[str] + + +@dataclass +class AlignmentResult: + granularity: Granularity + ref_normalized: str + hyp_normalized: str + ref_units: list[str] + hyp_units: list[str] + edits: list[AlignmentEdit] + error_rate: float # word error rate (WER) / CER (when granularity=character) + + substitutions: int + insertions: int + deletions: int + hits: int + + # Per-token source-interval index (within the group). None for the + # per-pair (filter) path, which aligns a single text pair and has no + # multi-interval origins to track. + ref_origins: list[int] | None = None + hyp_origins: list[int] | None = None + + +# ============================ Transcription report =============================== + + +@dataclass +class GroupAlignment: + key: GroupKey + gt_intervals: list[Interval] + ds_intervals: list[Interval] + alignment: AlignmentResult + + +@dataclass +class FilterPairAlignment: + gt: Interval + ds: Interval + iou: float + onset_delta: float + offset_delta: float + alignment: AlignmentResult + + +@dataclass +class TranscriptionReport: + requirement: TranscriptionRequirement + + # Filter mode outputs + pairs: list[FilterPairAlignment] + pair_gt_unmatched: list[Interval] + pair_ds_unmatched: list[Interval] + + # Join mode outputs + groups: list[GroupAlignment] + missing_groups: list[tuple[GroupKey, list[Interval]]] # only in GT + extra_groups: list[tuple[GroupKey, list[Interval]]] # only in DS + + @property + def alignments(self) -> list[AlignmentResult]: + if self.requirement.grouping.strategy == "join": + return [g.alignment for g in self.groups] + return [p.alignment for p in self.pairs] + + @property + def corpus_rate(self) -> float: + """Headline rate per `requirement.metric` aggregated across all + group / pair alignments. Lazy-imports the aggregator to avoid an + import cycle with `transcription_matching`.""" + from .transcription_matching import aggregate_metric + + _, rate = aggregate_metric( + self.alignments, + metric=self.requirement.metric, + threshold=self.requirement.threshold, + granularity=self.requirement.granularity, + ) + return rate + + +# ============================ Top-level ========================================== + + +@dataclass +class ComparisonReport: + gt: list[Interval] + ds: list[Interval] + intervals: IntervalReport + transcriptions: list[TranscriptionReport] diff --git a/packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/transcription_matching.py b/packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/transcription_matching.py new file mode 100644 index 0000000000..c553f2d9dc --- /dev/null +++ b/packages/examples/cvat/recording-oracle/libs/audio_qe/audio_qe/transcription_matching.py @@ -0,0 +1,1116 @@ +# Copyright (C) CVAT.ai Corporation +# +# SPDX-License-Identifier: MIT + +""" +Transcription quality estimation. + +Tokenize, group, align, score. Owns: + + * Tokenization (word / character) + * Per-chunk cost functions (equality / error-rate / normalized-lev) + and aggregation across alignments + * Levenshtein alignment over tokens, with an overlap-constrained + variant that forbids matches between tokens whose source intervals + don't temporally intersect + * Char-level DP with word-boundary reconstruction (handles N-to-M + boundary disagreements naturally as `boundary` edits) + * Group-level orchestration (join / filter strategies) — entry + point `run_transcription_qe()`. +""" + +from __future__ import annotations + +from collections import defaultdict +from collections.abc import Iterator +from typing import Callable, Sequence + +import numpy as np +import regex + +from .config import TranscriptionRequirement +from .data import ( + AlignMode, + EditOp, + Granularity, + GroupingStrategy, + GroupKey, + Interval, + Metric, +) +from .interval_matching import _two_stage_match, iou +from .normalization import Normalizer +from .reports import ( + AlignmentEdit, + AlignmentResult, + FilterPairAlignment, + GroupAlignment, + TranscriptionReport, +) + +# `\X` matches one extended grapheme cluster — keeps combining marks +# (Indic, Arabic diacritics) and emoji ZWJ sequences as a single unit. +_GRAPHEMES_RE = regex.compile(r"\X") + + +def _iter_graphemes(text: str) -> Iterator[str]: + """Yield each extended grapheme cluster in `text`. Single source of + truth for character-level iteration across char-granularity + tokenization and the char-stream alignment paths.""" + for m in _GRAPHEMES_RE.finditer(text): + yield m.group() + + +# ============================ Tokenization ==================================== + + +def tokenize(text: str, *, granularity: Granularity) -> list[str]: + if granularity == Granularity.WORD: + return text.split() + if granularity == Granularity.CHARACTER: + return list(_iter_graphemes(text)) + raise AssertionError(granularity) + + +# ============================ Per-chunk cost functions ======================= + + +def _char_edit_distance(a: str, b: str) -> int: + """Plain Levenshtein over characters. Short strings (typically <30 chars), + pure-Python is fine.""" + if a == b: + return 0 + if not a: + return len(b) + if not b: + return len(a) + prev = list(range(len(b) + 1)) + for i, ca in enumerate(a, 1): + cur = [i] + for j, cb in enumerate(b, 1): + cur.append( + min( + cur[-1] + 1, # insert + prev[j] + 1, # delete + prev[j - 1] + (0 if ca == cb else 1), # substitute + ) + ) + prev = cur + return prev[-1] + + +def _cost_equality(a: str, b: str) -> float: + return 0.0 if a == b else 1.0 + + +def _cost_error_rate(a: str, b: str) -> float: + """edits / len(ref). Recall-shaped; can exceed 1 when hyp is much longer.""" + + if a == b: + return 0.0 + denom = len(a) or 1 + return _char_edit_distance(a, b) / denom + + +def _cost_normalized_lev(a: str, b: str) -> float: + """ + edits / max(len). Bounded in [0, 1]; symmetric. + Standard name in the literature: normalized Levenshtein distance (NED). + """ + + if a == b: + return 0.0 + denom = max(len(a), len(b)) or 1 + return _char_edit_distance(a, b) / denom + + +_METRIC_FNS: dict[Metric, Callable[[str, str], float]] = { + Metric.EQUALITY: _cost_equality, + Metric.ERROR_RATE: _cost_error_rate, + Metric.NORMALIZED_LEV: _cost_normalized_lev, +} +_METRIC_NAMES = tuple(m.value for m in _METRIC_FNS) + +# A token-pair cost: substitution cost between a ref and a hyp token +TokenCost = Callable[[str, str], float] + + +def _unit_sub_cost(a: str, b: str) -> float: + """Default substitution cost: 1 for any non-identical pair (plain + Levenshtein). Identical pairs are handled as matches (cost 0) by the + caller, so this is only ever invoked for a != b.""" + return 1.0 + + +def make_token_cost(metric: Metric | str, threshold: float | None) -> TokenCost: + try: + metric = Metric(metric) + except ValueError as exc: + raise ValueError(f"unknown metric {metric!r}; choices: {list(_METRIC_NAMES)}") from exc + + metric_fn = _METRIC_FNS[metric] + if threshold is None: + return metric_fn + + def thresholded(a: str, b: str) -> float: + return 1.0 if metric_fn(a, b) > threshold else 0.0 + + return thresholded + + +def _metric_label( + metric: Metric, + granularity: Granularity, + *, + threshold: float | None = None, +) -> str: + """Display label = base unit (WER/CER) ± prefix per metric/threshold combo.""" + + unit = "CER" if granularity == Granularity.CHARACTER else "WER" + if metric == Metric.EQUALITY: + return unit + if threshold is not None: + return f"fuzzy-{unit}" + return f"soft-{unit}" + + +def _chunk_cost( + e: AlignmentEdit, + *, + granularity: Granularity, + token_cost: TokenCost, +) -> tuple[float, int]: + """Returns (errors_in_granularity_units, ref_units_consumed) for one chunk. + + Per-chunk semantics: + * granularity=char → errors = char-edit count, ref = char count + * granularity=word → errors = token_cost(ref, hyp), ref = word count + (boundary chunks: applied to concatenated forms) + Delete/insert chunks: 1 error per granularity unit, ref unchanged for inserts. + """ + + is_char = granularity == Granularity.CHARACTER + + if e.op == EditOp.EQUAL: + if is_char: + return 0.0, sum(len(u) for u in e.ref_units) + return 0.0, len(e.ref_units) + + if e.op == EditOp.SUBSTITUTE: + errs = 0.0 + refs = 0 + for a, b in zip(e.ref_units, e.hyp_units): + if is_char: + errs += _char_edit_distance(a, b) + refs += len(a) + else: + errs += token_cost(a, b) + refs += 1 + return errs, refs + + if e.op == EditOp.BOUNDARY: + ref_concat = " ".join(e.ref_units) + hyp_concat = " ".join(e.hyp_units) + if is_char: + return float(_char_edit_distance(ref_concat, hyp_concat)), len(ref_concat) + return token_cost(ref_concat, hyp_concat), len(e.ref_units) + + if e.op == EditOp.DELETE: + if is_char: + n = sum(len(u) for u in e.ref_units) + return float(n), n + n = len(e.ref_units) + return float(n), n + + if e.op == EditOp.INSERT: + if is_char: + return float(sum(len(u) for u in e.hyp_units)), 0 + return float(len(e.hyp_units)), 0 + + raise ValueError(f"unknown op {e.op}") + + +def aggregate_metric( + alignments: Sequence[AlignmentResult], + *, + metric: Metric | str, + threshold: float | None, + granularity: Granularity, +) -> tuple[str, float]: + """ + Aggregate the chosen metric across multiple alignments. + Returns (display_label, rate). + """ + + token_cost = make_token_cost(metric, threshold) # validates metric + metric = Metric(metric) + total_err: float = 0.0 + total_ref: int = 0 + for a in alignments: + for e in a.edits: + err, ref = _chunk_cost(e, granularity=granularity, token_cost=token_cost) + total_err += err + total_ref += ref + + rate = total_err / total_ref if total_ref else float("nan") + return _metric_label(metric, granularity, threshold=threshold), rate + + +# ============================ Alignment ======================================= + + +def _align_pair( + ref_text: str, + hyp_text: str, + *, + granularity: Granularity, + normalizer: Normalizer, + sub_cost: TokenCost = _unit_sub_cost, +) -> AlignmentResult: + ref_n = normalizer(ref_text) + hyp_n = normalizer(hyp_text) + + ref_units = tokenize(ref_n, granularity=granularity) + hyp_units = tokenize(hyp_n, granularity=granularity) + + # Degenerate cases — deterministic answers, skip the DP. + if not ref_units and not hyp_units: + return AlignmentResult(granularity, ref_n, hyp_n, [], [], [], 0.0, 0, 0, 0, 0) + if not ref_units: + return AlignmentResult( + granularity, + ref_n, + hyp_n, + [], + list(hyp_units), + [AlignmentEdit(EditOp.INSERT, 0, 0, 0, len(hyp_units), [], list(hyp_units))], + float("inf"), + 0, + len(hyp_units), + 0, + 0, + ) + if not hyp_units: + return AlignmentResult( + granularity, + ref_n, + hyp_n, + list(ref_units), + [], + [AlignmentEdit(EditOp.DELETE, 0, len(ref_units), 0, 0, list(ref_units), [])], + 1.0, + 0, + 0, + len(ref_units), + 0, + ) + + # Single pair → one notional interval per side → all-pass overlap. + overlap = np.ones((1, 1), dtype=bool) + edits, hits, subs, ins, dels, total_cost = _overlap_constrained_align( + ref_units, + [0] * len(ref_units), + hyp_units, + [0] * len(hyp_units), + overlap, + sub_cost=sub_cost, + ) + error_rate = total_cost / len(ref_units) + + return AlignmentResult( + granularity=granularity, + ref_normalized=ref_n, + hyp_normalized=hyp_n, + ref_units=list(ref_units), + hyp_units=list(hyp_units), + edits=edits, + error_rate=error_rate, + substitutions=subs, + insertions=ins, + deletions=dels, + hits=hits, + ) + + +# ============================ Transcription grouping + DP ======================== + + +def group_key(interval: Interval, *, attribute: str | None) -> GroupKey: + if attribute is None: + return (interval.label, None) + return (interval.label, interval.extra.get(attribute) or None) + + +def group_intervals( + intervals: Sequence[Interval], *, attribute: str | None +) -> dict[GroupKey, list[Interval]]: + out: dict[GroupKey, list[Interval]] = defaultdict(list) + for iv in intervals: + out[group_key(iv, attribute=attribute)].append(iv) + return out + + +def _join_group_text(intervals: Sequence[Interval], *, text_attr: str, separator: str) -> str: + in_order = sorted(intervals, key=lambda iv: (iv.start, iv.id)) + parts = [iv.extra.get(text_attr, "") for iv in in_order] + return separator.join(p for p in parts if p) + + +def _normalize_tokenize_per_interval( + intervals: Sequence[Interval], + *, + text_attr: str, + normalizer: Normalizer, + granularity: Granularity, + inter_interval_sep: str = " ", +) -> tuple[list[str], list[int], list[Interval], list[str]]: + """Returns (flat_units, per-unit interval index, sorted intervals, normalized text per interval). + + For char granularity, inserts inter_interval_sep tokens between adjacent + non-empty intervals so word boundaries that fall at interval splits stay + visible to the DP. For word granularity no separator is inserted: word DP + doesn't see whitespace between tokens.""" + in_order = sorted(intervals, key=lambda iv: (iv.start, iv.id)) + flat_units: list[str] = [] + origins: list[int] = [] + norm_texts: list[str] = [] + is_char = granularity == Granularity.CHARACTER + for idx, iv in enumerate(in_order): + raw = iv.extra.get(text_attr, "") + normed = normalizer(raw) + norm_texts.append(normed) + if is_char and flat_units and normed and inter_interval_sep: + for ch in _iter_graphemes(inter_interval_sep): + flat_units.append(ch) + origins.append(idx - 1) + for tok in tokenize(normed, granularity=granularity): + flat_units.append(tok) + origins.append(idx) + return flat_units, origins, in_order, norm_texts + + +def _normalize_to_chars_per_interval( + intervals: Sequence[Interval], + *, + text_attr: str, + normalizer: Normalizer, + inter_interval_sep: str = " ", +) -> tuple[list[str], list[int], list[Interval], list[str]]: + """Build flat char streams + per-char interval origin index. Spaces between + consecutive intervals get the previous interval's origin.""" + in_order = sorted(intervals, key=lambda iv: (iv.start, iv.id)) + chars: list[str] = [] + origins: list[int] = [] + norm_texts: list[str] = [] + for idx, interval in enumerate(in_order): + raw = interval.extra.get(text_attr, "") + normed = normalizer(raw) + norm_texts.append(normed) + if chars and inter_interval_sep and normed: + for ch in _iter_graphemes(inter_interval_sep): + chars.append(ch) + origins.append(idx - 1) + for ch in _iter_graphemes(normed): + chars.append(ch) + origins.append(idx) + return chars, origins, in_order, norm_texts + + +def _overlap_matrix( + gt_intervals: Sequence[Interval], + ds_intervals: Sequence[Interval], + *, + tolerance_ms: float = 0.0, +) -> np.ndarray: + """Boolean GTxDS matrix of temporally-overlapping interval pairs. With a + positive `tolerance_ms`, intervals separated by a gap of up to that many + milliseconds still count as overlapping, so the boundary tolerance relaxes + the alignment overlap gate the same way it relaxes interval matching.""" + if not gt_intervals or not ds_intervals: + return np.zeros((len(gt_intervals), len(ds_intervals)), dtype=bool) + g_start = np.array([iv.start for iv in gt_intervals]) + g_stop = np.array([iv.stop for iv in gt_intervals]) + d_start = np.array([iv.start for iv in ds_intervals]) + d_stop = np.array([iv.stop for iv in ds_intervals]) + lo = np.maximum(g_start[:, None], d_start[None, :]) + hi = np.minimum(g_stop[:, None], d_stop[None, :]) + return hi > lo - tolerance_ms + + +def _overlap_constrained_align( + ref_units: Sequence[str], + ref_origins: Sequence[int], + hyp_units: Sequence[str], + hyp_origins: Sequence[int], + overlap: np.ndarray, + *, + sub_cost: TokenCost = _unit_sub_cost, +) -> tuple[list[AlignmentEdit], int, int, int, int, int, float]: + """Levenshtein DP that forbids match/substitute between tokens whose source + intervals do not temporally overlap. + + `sub_cost(ref_token, hyp_token)` is the substitution cost folded into the + DP objective, so the alignment minimizes the *metric* cost rather than the + hard edit count. With the default unit cost this is plain Levenshtein. + Insert / delete stay at cost 1. Identical tokens always cost 0 (a match), + independent of `sub_cost`. + + Returns (edits, hits, substitutions, insertions, deletions, total_cost). + `total_cost` is the optimal DP cost — the metric-weighted error mass, used + to form the rate. The hits / subs / ins / dels are plain edit-op counts + (integers). This DP emits only EQUAL / SUBSTITUTE / INSERT / DELETE; it does + not produce BOUNDARY edits (N-to-M word merges are reconstructed separately + by `_reconstruct_word_edits_from_chars` on a char-level alignment). + """ + + n, m = len(ref_units), len(hyp_units) + INF = float("inf") + DEL, INS, MATCH, SUB = 1, 2, 3, 4 + + cost = np.full((n + 1, m + 1), INF, dtype=np.float32) + back = np.zeros((n + 1, m + 1), dtype=np.int8) + cost[0, 0] = 0.0 + for i in range(1, n + 1): + cost[i, 0] = i + back[i, 0] = DEL + for j in range(1, m + 1): + cost[0, j] = j + back[0, j] = INS + + for i in range(1, n + 1): + ru = ref_units[i - 1] + ri = ref_origins[i - 1] + for j in range(1, m + 1): + del_c = cost[i - 1, j] + 1 + ins_c = cost[i, j - 1] + 1 + best, op = del_c, DEL + if ins_c < best: + best, op = ins_c, INS + hj = hyp_origins[j - 1] + if overlap[ri, hj]: + if ru == hyp_units[j - 1]: + diag = cost[i - 1, j - 1] # exact match, cost 0 + cand_op = MATCH + else: + diag = cost[i - 1, j - 1] + sub_cost(ru, hyp_units[j - 1]) + cand_op = SUB + if diag < best: + best, op = diag, cand_op + + cost[i, j] = best + back[i, j] = op + + ops_rev: list[tuple[str, int, int, int, int]] = [] + i, j = n, m + while i > 0 or j > 0: + op = back[i, j] + if op == MATCH: + ops_rev.append((EditOp.EQUAL, i - 1, i, j - 1, j)) + i -= 1 + j -= 1 + elif op == SUB: + ops_rev.append((EditOp.SUBSTITUTE, i - 1, i, j - 1, j)) + i -= 1 + j -= 1 + elif op == DEL: + ops_rev.append((EditOp.DELETE, i - 1, i, j, j)) + i -= 1 + elif op == INS: + ops_rev.append((EditOp.INSERT, i, i, j - 1, j)) + j -= 1 + else: + break + ops = list(reversed(ops_rev)) + + edits: list[AlignmentEdit] = [] + for op_name, r_s, r_e, h_s, h_e in ops: + if ( + edits + and edits[-1].op == op_name + and op_name in (EditOp.EQUAL, EditOp.SUBSTITUTE) + and edits[-1].ref_end == r_s + and edits[-1].hyp_end == h_s + ): + last = edits[-1] + last.ref_end = r_e + last.hyp_end = h_e + last.ref_units += list(ref_units[r_s:r_e]) + last.hyp_units += list(hyp_units[h_s:h_e]) + elif ( + edits + and edits[-1].op == EditOp.DELETE + and op_name == EditOp.DELETE + and edits[-1].ref_end == r_s + ): + edits[-1].ref_end = r_e + edits[-1].ref_units += list(ref_units[r_s:r_e]) + elif ( + edits + and edits[-1].op == EditOp.INSERT + and op_name == EditOp.INSERT + and edits[-1].hyp_end == h_s + ): + edits[-1].hyp_end = h_e + edits[-1].hyp_units += list(hyp_units[h_s:h_e]) + else: + edits.append( + AlignmentEdit( + op=op_name, + ref_start=r_s, + ref_end=r_e, + hyp_start=h_s, + hyp_end=h_e, + ref_units=list(ref_units[r_s:r_e]), + hyp_units=list(hyp_units[h_s:h_e]), + ) + ) + + hits = sum(e.ref_end - e.ref_start for e in edits if e.op == EditOp.EQUAL) + subs = sum(e.ref_end - e.ref_start for e in edits if e.op == EditOp.SUBSTITUTE) + dels = sum(e.ref_end - e.ref_start for e in edits if e.op == EditOp.DELETE) + ins = sum(e.hyp_end - e.hyp_start for e in edits if e.op == EditOp.INSERT) + total_cost = float(cost[n, m]) + return edits, hits, subs, ins, dels, total_cost + + +def _tokenize_with_ranges(chars: Sequence[str]) -> tuple[list[tuple[int, int, str]], list[int]]: + """Walk a char stream, return word ranges + per-char word index (-1 for spaces).""" + words: list[tuple[int, int, str]] = [] + idx_per_char: list[int] = [-1] * len(chars) + i = 0 + word_idx = 0 + while i < len(chars): + if chars[i] == " ": + i += 1 + continue + start = i + while i < len(chars) and chars[i] != " ": + idx_per_char[i] = word_idx + i += 1 + words.append((start, i, "".join(chars[start:i]))) + word_idx += 1 + return words, idx_per_char + + +def _reconstruct_word_edits_from_chars( + ref_chars: Sequence[str], + hyp_chars: Sequence[str], + char_edits: list[AlignmentEdit], +) -> tuple[list[str], list[str], list[AlignmentEdit]]: + """Convert a char-level alignment into a word-level edit list. + + Strategy: + * Tokenize ref and hyp char streams into word ranges. + * For each ref char that aligned (equal or sub), record which hyp word + it landed in. Use that to choose each ref word's primary hyp + destination (the hyp word containing most of its aligned chars). + * Group consecutive ref words with the same primary destination → N-to-1 + boundary edit. Ref word spanning >1 hyp word → 1-to-N boundary. + * Unconsumed hyp words appear as inserts in their natural order. + """ + + ref_words, ref_w_of_char = _tokenize_with_ranges(ref_chars) + hyp_words, hyp_w_of_char = _tokenize_with_ranges(hyp_chars) + + ref_to_hyp_char: list[int | None] = [None] * len(ref_chars) + for e in char_edits: + if e.op in (EditOp.EQUAL, EditOp.SUBSTITUTE): + for k in range(e.ref_end - e.ref_start): + ref_to_hyp_char[e.ref_start + k] = e.hyp_start + k + + n_ref_words = len(ref_words) + ref_dest_lists: list[list[int]] = [[] for _ in range(n_ref_words)] + ref_primary: list[int | None] = [None] * n_ref_words + for r_idx, (rs, re_, _r_word) in enumerate(ref_words): + counts: dict[int, int] = {} + order: list[int] = [] + for k in range(rs, re_): + h_pos = ref_to_hyp_char[k] + if h_pos is None or h_pos >= len(hyp_w_of_char): + continue + hw = hyp_w_of_char[h_pos] + if hw < 0: + continue + if hw not in counts: + order.append(hw) + counts[hw] = counts.get(hw, 0) + 1 + ref_dest_lists[r_idx] = order + if counts: + ref_primary[r_idx] = max(counts, key=counts.get) + + hyp_will_be_used: list[bool] = [False] * len(hyp_words) + for dests in ref_dest_lists: + for hw in dests: + hyp_will_be_used[hw] = True + + word_edits: list[AlignmentEdit] = [] + hyp_consumed: list[bool] = [False] * len(hyp_words) + next_hyp_emit = 0 + + def emit_pending_inserts(up_to_hyp_idx: int) -> None: + nonlocal next_hyp_emit + while next_hyp_emit < up_to_hyp_idx: + if not hyp_consumed[next_hyp_emit] and not hyp_will_be_used[next_hyp_emit]: + h_word = hyp_words[next_hyp_emit][2] + ref_pos = word_edits[-1].ref_end if word_edits else 0 + word_edits.append( + AlignmentEdit( + op=EditOp.INSERT, + ref_start=ref_pos, + ref_end=ref_pos, + hyp_start=next_hyp_emit, + hyp_end=next_hyp_emit + 1, + ref_units=[], + hyp_units=[h_word], + ) + ) + hyp_consumed[next_hyp_emit] = True + next_hyp_emit += 1 + + r = 0 + while r < n_ref_words: + primary = ref_primary[r] + dests = ref_dest_lists[r] + r_word = ref_words[r][2] + + if primary is None: + hyp_pos = word_edits[-1].hyp_end if word_edits else next_hyp_emit + word_edits.append( + AlignmentEdit( + op=EditOp.DELETE, + ref_start=r, + ref_end=r + 1, + hyp_start=hyp_pos, + hyp_end=hyp_pos, + ref_units=[r_word], + hyp_units=[], + ) + ) + r += 1 + continue + + emit_pending_inserts(primary) + + group_end = r + while ( + group_end + 1 < n_ref_words + and ref_primary[group_end + 1] == primary + and len(ref_dest_lists[group_end + 1]) == 1 + and len(dests) == 1 + ): + group_end += 1 + + if group_end > r: + group_ref_words = [ref_words[k][2] for k in range(r, group_end + 1)] + h_word = hyp_words[primary][2] + hyp_consumed[primary] = True + word_edits.append( + AlignmentEdit( + op=EditOp.BOUNDARY, + ref_start=r, + ref_end=group_end + 1, + hyp_start=primary, + hyp_end=primary + 1, + ref_units=group_ref_words, + hyp_units=[h_word], + ) + ) + r = group_end + 1 + next_hyp_emit = max(next_hyp_emit, primary + 1) + continue + + if len(dests) > 1: + hyp_word_strs = [hyp_words[hw][2] for hw in dests] + first_hw, last_hw = dests[0], dests[-1] + for hw in dests: + hyp_consumed[hw] = True + word_edits.append( + AlignmentEdit( + op=EditOp.BOUNDARY, + ref_start=r, + ref_end=r + 1, + hyp_start=first_hw, + hyp_end=last_hw + 1, + ref_units=[r_word], + hyp_units=hyp_word_strs, + ) + ) + next_hyp_emit = max(next_hyp_emit, last_hw + 1) + else: + h_word = hyp_words[primary][2] + hyp_consumed[primary] = True + op = EditOp.EQUAL if r_word == h_word else EditOp.SUBSTITUTE + word_edits.append( + AlignmentEdit( + op=op, + ref_start=r, + ref_end=r + 1, + hyp_start=primary, + hyp_end=primary + 1, + ref_units=[r_word], + hyp_units=[h_word], + ) + ) + next_hyp_emit = max(next_hyp_emit, primary + 1) + + r += 1 + + emit_pending_inserts(len(hyp_words)) + + merged: list[AlignmentEdit] = [] + for e in word_edits: + if ( + merged + and merged[-1].op == EditOp.DELETE + and e.op == EditOp.DELETE + and merged[-1].ref_end == e.ref_start + ): + merged[-1].ref_end = e.ref_end + merged[-1].ref_units += e.ref_units + elif ( + merged + and merged[-1].op == EditOp.INSERT + and e.op == EditOp.INSERT + and merged[-1].hyp_end == e.hyp_start + ): + merged[-1].hyp_end = e.hyp_end + merged[-1].hyp_units += e.hyp_units + else: + merged.append(e) + + ref_word_strs = [w for _, _, w in ref_words] + hyp_word_strs = [w for _, _, w in hyp_words] + return ref_word_strs, hyp_word_strs, merged + + +def _align_group_via_chars( + gt_intervals: Sequence[Interval], + ds_intervals: Sequence[Interval], + *, + text_attr: str, + normalizer: Normalizer, + separator: str = " ", + sub_cost: TokenCost = _unit_sub_cost, + overlap_tolerance_ms: float = 0.0, +) -> AlignmentResult: + """Char-level overlap-constrained alignment with word-level edit + reconstruction. Resulting AlignmentResult looks like a word-mode + alignment from the caller's perspective. + + The key feature of this alignment mode is that it can allow flexibility + on word boundaries. Spaces are just characters in the char-level DP, so + any N-to-M boundary disagreement is captured naturally and reclassified + as a `boundary` edit when reconstructing the word view. + + The char DP itself stays unit-cost (graphemes are atomic). `sub_cost` + is the word-level cost applied when scoring the reconstructed word edits, + so the reported `error_rate` is consistent with the chosen metric. + """ + + ref_chars, ref_origins, gt_sorted, ref_norm_parts = _normalize_to_chars_per_interval( + gt_intervals, + text_attr=text_attr, + normalizer=normalizer, + inter_interval_sep=separator, + ) + hyp_chars, hyp_origins, ds_sorted, hyp_norm_parts = _normalize_to_chars_per_interval( + ds_intervals, + text_attr=text_attr, + normalizer=normalizer, + inter_interval_sep=separator, + ) + + ref_norm_joined = separator.join(p for p in ref_norm_parts if p) + hyp_norm_joined = separator.join(p for p in hyp_norm_parts if p) + + if not ref_chars and not hyp_chars: + return AlignmentResult( + Granularity.WORD, + ref_norm_joined, + hyp_norm_joined, + [], + [], + [], + 0.0, + 0, + 0, + 0, + 0, + ) + + overlaps = _overlap_matrix(gt_sorted, ds_sorted, tolerance_ms=overlap_tolerance_ms) + + # Char-level DP stays unit-cost: graphemes are atomic, so a word-level + # metric has no meaning here. Word-level cost weighting happens in the + # word-token path (`_align_group_with_overlap`). + char_edits, _ch_hits, _ch_subs, _ch_ins, _ch_dels, _ = _overlap_constrained_align( + ref_chars, + ref_origins, + hyp_chars, + hyp_origins, + overlaps, + ) + + ref_word_strs, hyp_word_strs, word_edits = _reconstruct_word_edits_from_chars( + ref_chars, + hyp_chars, + char_edits, + ) + + hits = sum(e.ref_end - e.ref_start for e in word_edits if e.op == EditOp.EQUAL) + subs = sum(e.ref_end - e.ref_start for e in word_edits if e.op == EditOp.SUBSTITUTE) + dels = sum(e.ref_end - e.ref_start for e in word_edits if e.op == EditOp.DELETE) + ins = sum(e.hyp_end - e.hyp_start for e in word_edits if e.op == EditOp.INSERT) + + # Score the reconstructed word edits with the chosen cost so error_rate + # matches the cost function (BOUNDARY edits handled by _chunk_cost). + total_err = 0.0 + total_ref = 0 + for e in word_edits: + err, ref = _chunk_cost(e, granularity=Granularity.WORD, token_cost=sub_cost) + total_err += err + total_ref += ref + error_rate = total_err / total_ref if total_ref else float("nan") + + ref_word_origins: list[int] = [] + for r_s, r_e, _ in _tokenize_with_ranges(ref_chars)[0]: + ref_word_origins.append(ref_origins[r_s] if r_s < len(ref_origins) else 0) + hyp_word_origins: list[int] = [] + for h_s, h_e, _ in _tokenize_with_ranges(hyp_chars)[0]: + hyp_word_origins.append(hyp_origins[h_s] if h_s < len(hyp_origins) else 0) + + return AlignmentResult( + granularity=Granularity.WORD, + ref_normalized=ref_norm_joined, + hyp_normalized=hyp_norm_joined, + ref_units=ref_word_strs, + hyp_units=hyp_word_strs, + edits=word_edits, + error_rate=error_rate, + substitutions=subs, + insertions=ins, + deletions=dels, + hits=hits, + ref_origins=ref_word_origins, + hyp_origins=hyp_word_origins, + ) + + +def _align_group_with_overlap( + gt_intervals: Sequence[Interval], + ds_intervals: Sequence[Interval], + *, + text_attr: str, + granularity: Granularity, + normalizer: Normalizer, + separator: str, + sub_cost: TokenCost = _unit_sub_cost, + overlap_tolerance_ms: float = 0.0, +) -> AlignmentResult: + """Join mode alignment that forbids token-level matches between intervals + whose time spans don't overlap. Catches the most obvious spurious matches + (e.g. "police" at t=24s ↔ "police" at t=180s). + + `sub_cost` weights the substitution cost inside the DP, so the alignment + minimizes the chosen cost rather than the hard edit count. With the default + unit cost the result matches plain Levenshtein. At char granularity the + tokens are single graphemes, where every metric degenerates to equality, so + the weighting is a no-op there.""" + + ref_units, ref_origins, gt_sorted, ref_norm_parts = _normalize_tokenize_per_interval( + gt_intervals, + text_attr=text_attr, + normalizer=normalizer, + granularity=granularity, + inter_interval_sep=separator, + ) + hyp_units, hyp_origins, ds_sorted, hyp_norm_parts = _normalize_tokenize_per_interval( + ds_intervals, + text_attr=text_attr, + normalizer=normalizer, + granularity=granularity, + inter_interval_sep=separator, + ) + + ref_norm_joined = separator.join(p for p in ref_norm_parts if p) + hyp_norm_joined = separator.join(p for p in hyp_norm_parts if p) + + if not ref_units and not hyp_units: + return AlignmentResult( + granularity, ref_norm_joined, hyp_norm_joined, [], [], [], 0.0, 0, 0, 0, 0 + ) + if not ref_units: + return AlignmentResult( + granularity, + ref_norm_joined, + hyp_norm_joined, + [], + list(hyp_units), + [AlignmentEdit(EditOp.INSERT, 0, 0, 0, len(hyp_units), [], list(hyp_units))], + float("inf"), + 0, + len(hyp_units), + 0, + 0, + ) + if not hyp_units: + return AlignmentResult( + granularity, + ref_norm_joined, + hyp_norm_joined, + list(ref_units), + [], + [AlignmentEdit(EditOp.DELETE, 0, len(ref_units), 0, 0, list(ref_units), [])], + 1.0, + 0, + 0, + len(ref_units), + 0, + ) + + overlap = _overlap_matrix(gt_sorted, ds_sorted, tolerance_ms=overlap_tolerance_ms) + edits, hits, subs, ins, dels, total_cost = _overlap_constrained_align( + ref_units, + ref_origins, + hyp_units, + hyp_origins, + overlap, + sub_cost=sub_cost, + ) + # Rate uses the metric-weighted DP cost (total_cost), not the raw edit + # count, so it is consistent with the objective the alignment minimized. + error_rate = total_cost / len(ref_units) + return AlignmentResult( + granularity=granularity, + ref_normalized=ref_norm_joined, + hyp_normalized=hyp_norm_joined, + ref_units=list(ref_units), + hyp_units=list(hyp_units), + edits=edits, + error_rate=error_rate, + substitutions=subs, + insertions=ins, + deletions=dels, + hits=hits, + ref_origins=list(ref_origins), + hyp_origins=list(hyp_origins), + ) + + +# ============================ Entry point ======================================== + + +def match_transcriptions( + gt: Sequence[Interval], ds: Sequence[Interval], *, req: TranscriptionRequirement +) -> TranscriptionReport: + normalizer = Normalizer(req.normalizer) + token_cost = make_token_cost(req.metric, req.threshold) + + gt_groups = group_intervals(gt, attribute=req.grouping.attribute) + ds_groups = group_intervals(ds, attribute=req.grouping.attribute) + + groups: list[GroupAlignment] = [] + missing: list[tuple[GroupKey, list[Interval]]] = [] + extra: list[tuple[GroupKey, list[Interval]]] = [] + pairs: list[FilterPairAlignment] = [] + pair_gt_unmatched: list[Interval] = [] + pair_ds_unmatched: list[Interval] = [] + + all_keys = set(gt_groups) | set(ds_groups) + + match req.grouping.strategy: + case GroupingStrategy.JOIN: + for key in sorted(all_keys, key=lambda k: (k[0], k[1] or "")): + gt_group = gt_groups.get(key, []) + ds_group = ds_groups.get(key, []) + if not gt_group: + extra.append((key, ds_group)) + continue + if not ds_group: + missing.append((key, gt_group)) + continue + + if req.enforce_overlap: + aligner_params = { + "text_attr": req.text_attribute, + "normalizer": normalizer, + "separator": req.grouping.join_separator, + "sub_cost": token_cost, + "overlap_tolerance_ms": req.overlap_tolerance_ms, + } + + match (req.align, req.granularity): + case (AlignMode.CHAR, Granularity.WORD): + aligner = _align_group_via_chars + case (AlignMode.CHAR, Granularity.CHARACTER | Granularity.WORD) | ( + AlignMode.WORD, + Granularity.WORD, + ): + aligner = _align_group_with_overlap + aligner_params["granularity"] = req.granularity + case (align, granularity): + assert ( + False + ), f"Unknown alignment, granularity combination ({align, granularity})" + + alignment = aligner(gt_group, ds_group, **aligner_params) + else: + ref_text = _join_group_text( + gt_group, + text_attr=req.text_attribute, + separator=req.grouping.join_separator, + ) + hyp_text = _join_group_text( + ds_group, + text_attr=req.text_attribute, + separator=req.grouping.join_separator, + ) + alignment = _align_pair( + ref_text, + hyp_text, + granularity=req.granularity, + normalizer=normalizer, + sub_cost=token_cost, + ) + groups.append(GroupAlignment(key, gt_group, ds_group, alignment)) + + case GroupingStrategy.FILTER: + for key in sorted(all_keys, key=lambda k: (k[0], k[1] or "")): + gt_group = gt_groups.get(key, []) + ds_group = ds_groups.get(key, []) + matches, _, gt_unmatched, ds_unmatched = _two_stage_match( + gt_group, ds_group, iou_thresh=req.iou_threshold + ) + for gt_ann, ds_ann in matches: + ref_text = gt_ann.extra.get(req.text_attribute, "") + hyp_text = ds_ann.extra.get(req.text_attribute, "") + pairs.append( + FilterPairAlignment( + gt=gt_ann, + ds=ds_ann, + iou=iou(gt_ann, ds_ann), + onset_delta=ds_ann.start - gt_ann.start, + offset_delta=ds_ann.stop - gt_ann.stop, + alignment=_align_pair( + ref_text, + hyp_text, + granularity=req.granularity, + normalizer=normalizer, + sub_cost=token_cost, + ), + ) + ) + pair_gt_unmatched.extend(gt_unmatched) + pair_ds_unmatched.extend(ds_unmatched) + case grouping: + assert False, f"Unknown grouping '{grouping}'" + + return TranscriptionReport( + requirement=req, + groups=groups, + missing_groups=missing, + extra_groups=extra, + pairs=pairs, + pair_gt_unmatched=pair_gt_unmatched, + pair_ds_unmatched=pair_ds_unmatched, + ) diff --git a/packages/examples/cvat/recording-oracle/libs/audio_qe/pyproject.toml b/packages/examples/cvat/recording-oracle/libs/audio_qe/pyproject.toml new file mode 100644 index 0000000000..e9f7cf4d49 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/libs/audio_qe/pyproject.toml @@ -0,0 +1,18 @@ +[tool.poetry] +name = "audio-qe" +version = "0.1.0" +description = "Audio transcription quality estimation" +authors = ["CVAT.ai Corporation"] +license = "MIT" +readme = "README.md" +packages = [{include = "audio_qe"}] + +[tool.poetry.dependencies] +python = "^3.10, <3.13" +numpy = "^1.25.2" +regex = "^2024.11.6" +scipy = "^1.13.1" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/packages/examples/cvat/recording-oracle/poetry.lock b/packages/examples/cvat/recording-oracle/poetry.lock index d467345a9f..e8e1e77287 100644 --- a/packages/examples/cvat/recording-oracle/poetry.lock +++ b/packages/examples/cvat/recording-oracle/poetry.lock @@ -2,150 +2,202 @@ [[package]] name = "aiohappyeyeballs" -version = "2.4.6" +version = "2.7.1" description = "Happy Eyeballs for asyncio" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" files = [ - {file = "aiohappyeyeballs-2.4.6-py3-none-any.whl", hash = "sha256:147ec992cf873d74f5062644332c539fcd42956dc69453fe5204195e560517e1"}, - {file = "aiohappyeyeballs-2.4.6.tar.gz", hash = "sha256:9b05052f9042985d32ecbe4b59a77ae19c006a78f1344d7fdad69d28ded3d0b0"}, + {file = "aiohappyeyeballs-2.7.1-py3-none-any.whl", hash = "sha256:9243213661e29250eb41368e5daa826fc017156c3b8a11440826b2e3ed376472"}, + {file = "aiohappyeyeballs-2.7.1.tar.gz", hash = "sha256:065665c041c42a5938ed220bdcd7230f22527fbec085e1853d2402c8a3615d9d"}, ] [[package]] name = "aiohttp" -version = "3.11.12" +version = "3.14.1" description = "Async http client/server framework (asyncio)" optional = false -python-versions = ">=3.9" -files = [ - {file = "aiohttp-3.11.12-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:aa8a8caca81c0a3e765f19c6953416c58e2f4cc1b84829af01dd1c771bb2f91f"}, - {file = "aiohttp-3.11.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:84ede78acde96ca57f6cf8ccb8a13fbaf569f6011b9a52f870c662d4dc8cd854"}, - {file = "aiohttp-3.11.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:584096938a001378484aa4ee54e05dc79c7b9dd933e271c744a97b3b6f644957"}, - {file = "aiohttp-3.11.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:392432a2dde22b86f70dd4a0e9671a349446c93965f261dbaecfaf28813e5c42"}, - {file = "aiohttp-3.11.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:88d385b8e7f3a870146bf5ea31786ef7463e99eb59e31db56e2315535d811f55"}, - {file = "aiohttp-3.11.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b10a47e5390c4b30a0d58ee12581003be52eedd506862ab7f97da7a66805befb"}, - {file = "aiohttp-3.11.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b5263dcede17b6b0c41ef0c3ccce847d82a7da98709e75cf7efde3e9e3b5cae"}, - {file = "aiohttp-3.11.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50c5c7b8aa5443304c55c262c5693b108c35a3b61ef961f1e782dd52a2f559c7"}, - {file = "aiohttp-3.11.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d1c031a7572f62f66f1257db37ddab4cb98bfaf9b9434a3b4840bf3560f5e788"}, - {file = "aiohttp-3.11.12-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:7e44eba534381dd2687be50cbd5f2daded21575242ecfdaf86bbeecbc38dae8e"}, - {file = "aiohttp-3.11.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:145a73850926018ec1681e734cedcf2716d6a8697d90da11284043b745c286d5"}, - {file = "aiohttp-3.11.12-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:2c311e2f63e42c1bf86361d11e2c4a59f25d9e7aabdbdf53dc38b885c5435cdb"}, - {file = "aiohttp-3.11.12-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ea756b5a7bac046d202a9a3889b9a92219f885481d78cd318db85b15cc0b7bcf"}, - {file = "aiohttp-3.11.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:526c900397f3bbc2db9cb360ce9c35134c908961cdd0ac25b1ae6ffcaa2507ff"}, - {file = "aiohttp-3.11.12-cp310-cp310-win32.whl", hash = "sha256:b8d3bb96c147b39c02d3db086899679f31958c5d81c494ef0fc9ef5bb1359b3d"}, - {file = "aiohttp-3.11.12-cp310-cp310-win_amd64.whl", hash = "sha256:7fe3d65279bfbee8de0fb4f8c17fc4e893eed2dba21b2f680e930cc2b09075c5"}, - {file = "aiohttp-3.11.12-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:87a2e00bf17da098d90d4145375f1d985a81605267e7f9377ff94e55c5d769eb"}, - {file = "aiohttp-3.11.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b34508f1cd928ce915ed09682d11307ba4b37d0708d1f28e5774c07a7674cac9"}, - {file = "aiohttp-3.11.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:936d8a4f0f7081327014742cd51d320296b56aa6d324461a13724ab05f4b2933"}, - {file = "aiohttp-3.11.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2de1378f72def7dfb5dbd73d86c19eda0ea7b0a6873910cc37d57e80f10d64e1"}, - {file = "aiohttp-3.11.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9d45dbb3aaec05cf01525ee1a7ac72de46a8c425cb75c003acd29f76b1ffe94"}, - {file = "aiohttp-3.11.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:930ffa1925393381e1e0a9b82137fa7b34c92a019b521cf9f41263976666a0d6"}, - {file = "aiohttp-3.11.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8340def6737118f5429a5df4e88f440746b791f8f1c4ce4ad8a595f42c980bd5"}, - {file = "aiohttp-3.11.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4016e383f91f2814e48ed61e6bda7d24c4d7f2402c75dd28f7e1027ae44ea204"}, - {file = "aiohttp-3.11.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3c0600bcc1adfaaac321422d615939ef300df81e165f6522ad096b73439c0f58"}, - {file = "aiohttp-3.11.12-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:0450ada317a65383b7cce9576096150fdb97396dcfe559109b403c7242faffef"}, - {file = "aiohttp-3.11.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:850ff6155371fd802a280f8d369d4e15d69434651b844bde566ce97ee2277420"}, - {file = "aiohttp-3.11.12-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:8fd12d0f989c6099e7b0f30dc6e0d1e05499f3337461f0b2b0dadea6c64b89df"}, - {file = "aiohttp-3.11.12-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:76719dd521c20a58a6c256d058547b3a9595d1d885b830013366e27011ffe804"}, - {file = "aiohttp-3.11.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:97fe431f2ed646a3b56142fc81d238abcbaff08548d6912acb0b19a0cadc146b"}, - {file = "aiohttp-3.11.12-cp311-cp311-win32.whl", hash = "sha256:e10c440d142fa8b32cfdb194caf60ceeceb3e49807072e0dc3a8887ea80e8c16"}, - {file = "aiohttp-3.11.12-cp311-cp311-win_amd64.whl", hash = "sha256:246067ba0cf5560cf42e775069c5d80a8989d14a7ded21af529a4e10e3e0f0e6"}, - {file = "aiohttp-3.11.12-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e392804a38353900c3fd8b7cacbea5132888f7129f8e241915e90b85f00e3250"}, - {file = "aiohttp-3.11.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8fa1510b96c08aaad49303ab11f8803787c99222288f310a62f493faf883ede1"}, - {file = "aiohttp-3.11.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:dc065a4285307607df3f3686363e7f8bdd0d8ab35f12226362a847731516e42c"}, - {file = "aiohttp-3.11.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddb31f8474695cd61fc9455c644fc1606c164b93bff2490390d90464b4655df"}, - {file = "aiohttp-3.11.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9dec0000d2d8621d8015c293e24589d46fa218637d820894cb7356c77eca3259"}, - {file = "aiohttp-3.11.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3552fe98e90fdf5918c04769f338a87fa4f00f3b28830ea9b78b1bdc6140e0d"}, - {file = "aiohttp-3.11.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6dfe7f984f28a8ae94ff3a7953cd9678550dbd2a1f9bda5dd9c5ae627744c78e"}, - {file = "aiohttp-3.11.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a481a574af914b6e84624412666cbfbe531a05667ca197804ecc19c97b8ab1b0"}, - {file = "aiohttp-3.11.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1987770fb4887560363b0e1a9b75aa303e447433c41284d3af2840a2f226d6e0"}, - {file = "aiohttp-3.11.12-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a4ac6a0f0f6402854adca4e3259a623f5c82ec3f0c049374133bcb243132baf9"}, - {file = "aiohttp-3.11.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c96a43822f1f9f69cc5c3706af33239489a6294be486a0447fb71380070d4d5f"}, - {file = "aiohttp-3.11.12-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a5e69046f83c0d3cb8f0d5bd9b8838271b1bc898e01562a04398e160953e8eb9"}, - {file = "aiohttp-3.11.12-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:68d54234c8d76d8ef74744f9f9fc6324f1508129e23da8883771cdbb5818cbef"}, - {file = "aiohttp-3.11.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c9fd9dcf9c91affe71654ef77426f5cf8489305e1c66ed4816f5a21874b094b9"}, - {file = "aiohttp-3.11.12-cp312-cp312-win32.whl", hash = "sha256:0ed49efcd0dc1611378beadbd97beb5d9ca8fe48579fc04a6ed0844072261b6a"}, - {file = "aiohttp-3.11.12-cp312-cp312-win_amd64.whl", hash = "sha256:54775858c7f2f214476773ce785a19ee81d1294a6bedc5cc17225355aab74802"}, - {file = "aiohttp-3.11.12-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:413ad794dccb19453e2b97c2375f2ca3cdf34dc50d18cc2693bd5aed7d16f4b9"}, - {file = "aiohttp-3.11.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4a93d28ed4b4b39e6f46fd240896c29b686b75e39cc6992692e3922ff6982b4c"}, - {file = "aiohttp-3.11.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d589264dbba3b16e8951b6f145d1e6b883094075283dafcab4cdd564a9e353a0"}, - {file = "aiohttp-3.11.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5148ca8955affdfeb864aca158ecae11030e952b25b3ae15d4e2b5ba299bad2"}, - {file = "aiohttp-3.11.12-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:525410e0790aab036492eeea913858989c4cb070ff373ec3bc322d700bdf47c1"}, - {file = "aiohttp-3.11.12-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bd8695be2c80b665ae3f05cb584093a1e59c35ecb7d794d1edd96e8cc9201d7"}, - {file = "aiohttp-3.11.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0203433121484b32646a5f5ea93ae86f3d9559d7243f07e8c0eab5ff8e3f70e"}, - {file = "aiohttp-3.11.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40cd36749a1035c34ba8d8aaf221b91ca3d111532e5ccb5fa8c3703ab1b967ed"}, - {file = "aiohttp-3.11.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a7442662afebbf7b4c6d28cb7aab9e9ce3a5df055fc4116cc7228192ad6cb484"}, - {file = "aiohttp-3.11.12-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:8a2fb742ef378284a50766e985804bd6adb5adb5aa781100b09befdbfa757b65"}, - {file = "aiohttp-3.11.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2cee3b117a8d13ab98b38d5b6bdcd040cfb4181068d05ce0c474ec9db5f3c5bb"}, - {file = "aiohttp-3.11.12-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f6a19bcab7fbd8f8649d6595624856635159a6527861b9cdc3447af288a00c00"}, - {file = "aiohttp-3.11.12-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e4cecdb52aaa9994fbed6b81d4568427b6002f0a91c322697a4bfcc2b2363f5a"}, - {file = "aiohttp-3.11.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:30f546358dfa0953db92ba620101fefc81574f87b2346556b90b5f3ef16e55ce"}, - {file = "aiohttp-3.11.12-cp313-cp313-win32.whl", hash = "sha256:ce1bb21fc7d753b5f8a5d5a4bae99566386b15e716ebdb410154c16c91494d7f"}, - {file = "aiohttp-3.11.12-cp313-cp313-win_amd64.whl", hash = "sha256:f7914ab70d2ee8ab91c13e5402122edbc77821c66d2758abb53aabe87f013287"}, - {file = "aiohttp-3.11.12-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7c3623053b85b4296cd3925eeb725e386644fd5bc67250b3bb08b0f144803e7b"}, - {file = "aiohttp-3.11.12-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:67453e603cea8e85ed566b2700efa1f6916aefbc0c9fcb2e86aaffc08ec38e78"}, - {file = "aiohttp-3.11.12-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6130459189e61baac5a88c10019b21e1f0c6d00ebc770e9ce269475650ff7f73"}, - {file = "aiohttp-3.11.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9060addfa4ff753b09392efe41e6af06ea5dd257829199747b9f15bfad819460"}, - {file = "aiohttp-3.11.12-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34245498eeb9ae54c687a07ad7f160053911b5745e186afe2d0c0f2898a1ab8a"}, - {file = "aiohttp-3.11.12-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8dc0fba9a74b471c45ca1a3cb6e6913ebfae416678d90529d188886278e7f3f6"}, - {file = "aiohttp-3.11.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a478aa11b328983c4444dacb947d4513cb371cd323f3845e53caeda6be5589d5"}, - {file = "aiohttp-3.11.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c160a04283c8c6f55b5bf6d4cad59bb9c5b9c9cd08903841b25f1f7109ef1259"}, - {file = "aiohttp-3.11.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:edb69b9589324bdc40961cdf0657815df674f1743a8d5ad9ab56a99e4833cfdd"}, - {file = "aiohttp-3.11.12-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:4ee84c2a22a809c4f868153b178fe59e71423e1f3d6a8cd416134bb231fbf6d3"}, - {file = "aiohttp-3.11.12-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:bf4480a5438f80e0f1539e15a7eb8b5f97a26fe087e9828e2c0ec2be119a9f72"}, - {file = "aiohttp-3.11.12-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:e6b2732ef3bafc759f653a98881b5b9cdef0716d98f013d376ee8dfd7285abf1"}, - {file = "aiohttp-3.11.12-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f752e80606b132140883bb262a457c475d219d7163d996dc9072434ffb0784c4"}, - {file = "aiohttp-3.11.12-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ab3247d58b393bda5b1c8f31c9edece7162fc13265334217785518dd770792b8"}, - {file = "aiohttp-3.11.12-cp39-cp39-win32.whl", hash = "sha256:0d5176f310a7fe6f65608213cc74f4228e4f4ce9fd10bcb2bb6da8fc66991462"}, - {file = "aiohttp-3.11.12-cp39-cp39-win_amd64.whl", hash = "sha256:74bd573dde27e58c760d9ca8615c41a57e719bff315c9adb6f2a4281a28e8798"}, - {file = "aiohttp-3.11.12.tar.gz", hash = "sha256:7603ca26d75b1b86160ce1bbe2787a0b706e592af5b2504e12caa88a217767b0"}, +python-versions = ">=3.10" +files = [ + {file = "aiohttp-3.14.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8f6bb621e5863cfe8fe5ff5468002d200ec31f30f1280b259dc505b02595099e"}, + {file = "aiohttp-3.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4f7215cb3933784f79ed20e5f050e15984f390424339b22375d5a53c933a0491"}, + {file = "aiohttp-3.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d9d4e294455b23a68c9b8f042d0e8e377a265bcb15332753695f6e5b6819e0ce"}, + {file = "aiohttp-3.14.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b238af795833d5731d049d82bc84b768ae6f8f97f0495963b3ed9935c5901cc3"}, + {file = "aiohttp-3.14.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e4e5e0ae56914ecdbf446493addefc0159053dd53962cef37d7839f37f73d505"}, + {file = "aiohttp-3.14.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:092e4ce3619a7c6dee52a6bdabda973d9b34b66781f840ce93c7e0cec30cf521"}, + {file = "aiohttp-3.14.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bb33777ea21e8b7ecde0e6fc84f598be0a1192eab1a63bc746d75aa75d38e7bd"}, + {file = "aiohttp-3.14.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23119f8fd4f5d16902ed459b63b100bcd269628075162bddac56cc7b5273b3fb"}, + {file = "aiohttp-3.14.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:57fc6745a4b7d0f5a9eb4f40a69718be6c0bc1b8368cc9fe89e90118719f4f42"}, + {file = "aiohttp-3.14.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6fd35beba67c4183b09375c5fff9accb47524191a244a99f95fd4472f5402c2b"}, + {file = "aiohttp-3.14.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:672b9d65f42eb877f5c3f234a4547e4e1a226ca8c2eed879bb34670a0ce51192"}, + {file = "aiohttp-3.14.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:24ba13339fed9251d9b1a1bec8c7ab84c0d1675d79d33501e11f94f8b9a84e05"}, + {file = "aiohttp-3.14.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:94da27378da0610e341c4d30de29a191672683cc82b8f9556e8f7c7212a020fe"}, + {file = "aiohttp-3.14.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:52cdac9432d8b4a719f35094a818d95adcae0f0b4fe9b9b921909e0c87de9e7d"}, + {file = "aiohttp-3.14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:672ac254412a24d0d0cf00a9e6c238877e4be5e5fa2d188832c1244f45f31966"}, + {file = "aiohttp-3.14.1-cp310-cp310-win32.whl", hash = "sha256:2fe3607e71acc6ebb0ec8e492a247bf7a291226192dc0084236dfc12478916f6"}, + {file = "aiohttp-3.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:30099eda75a53c32efb0920e9c33c195314d2cc1c680fbfd30894932ac5f27df"}, + {file = "aiohttp-3.14.1-cp310-cp310-win_arm64.whl", hash = "sha256:5a837f49d901f9e368651b676912bff1104ed8c1a83b280bcd7b29adccef5c9c"}, + {file = "aiohttp-3.14.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:aa00140699487bd435fde4342d85c94cb256b7cd3a5b9c3396c67f19922afda2"}, + {file = "aiohttp-3.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1c1af67559445498b502030c35c59db59966f47041ca9de5b4e707f86bd10b5f"}, + {file = "aiohttp-3.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d44ec478e713ee7f29b439f7eb8dc2b9d4079e11ae114d2c2ac3d5daf30516c8"}, + {file = "aiohttp-3.14.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d3b1a184a9a8f548a6b73f1e26b96b052193e4b3175ed7342aaf1151a1f00a04"}, + {file = "aiohttp-3.14.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5f2504bc0322437c9a1ff6d3333ca56c7477b727c995f036b976ae17b98372c8"}, + {file = "aiohttp-3.14.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:73f05ea02013e02512c3bf42714f1208c57168c779cc6fe23516e4543089d0a6"}, + {file = "aiohttp-3.14.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:797457503c2d426bee06eef808d07b31ede30b65e054444e7de64cad0061b7af"}, + {file = "aiohttp-3.14.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b821a1f7dedf7e37450654e620038ac3b2e81e8fa6ea269337e97101978ec730"}, + {file = "aiohttp-3.14.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4cd96b5ba05d67ed0cf00b5b405c8cd99586d8e3481e8ee0a831057591af7621"}, + {file = "aiohttp-3.14.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d459b98a932296c6f0e94f87511a0b1b90a8a02c30a50e60a297619cd5a58ee"}, + {file = "aiohttp-3.14.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:764457a7be60825fb770a644852ff717bcbb5042f189f2bd16df61a81b3f6573"}, + {file = "aiohttp-3.14.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f7a16ef45b081454ef844502d87a848876c490c4cb5c650c230f6ec79ed2c1e7"}, + {file = "aiohttp-3.14.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2fbc3ed048b3475b9f0cbcb9978e9d2d3511acd91ead203af26ed9f0056004cf"}, + {file = "aiohttp-3.14.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bedb0cd073cc2dc035e30aeb99444389d3cd2113afe4ef9fcd23d439f5bade85"}, + {file = "aiohttp-3.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b6feea921016eb3d4e04d65fc4e9ca402d1a3801f562aef94989f54694917af3"}, + {file = "aiohttp-3.14.1-cp311-cp311-win32.whl", hash = "sha256:313701e488100074ce99850404ee36e741abf6330179fec908a1944ecf570126"}, + {file = "aiohttp-3.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:03ab4530fdcb3a543a122ba4b65ac9919da9fe9f78a03d328a6e38ff962f7aa5"}, + {file = "aiohttp-3.14.1-cp311-cp311-win_arm64.whl", hash = "sha256:486f7d16ed54c39c2cbd7ca71fd8ba2b8bb7860df65bd7b6ed640bab96a38a8b"}, + {file = "aiohttp-3.14.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d35143e27778b4bb0fb189562d7f275bff79c62ab8e98459717c0ea617ff2480"}, + {file = "aiohttp-3.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bcfb80a2cc36fba2534e5e5b5264dc7ae6fcd9bf15256da3e53d2f499e6fa29d"}, + {file = "aiohttp-3.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27fd7c91e51729b4f7e1577865fa6d34c9adccbc39aabe9000285b48af9f0ec2"}, + {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:64c567bf9eaf664280116a8688f63016e6b32db2505908e2bdaca1b6438142f2"}, + {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f5e6ff2bdbb8f4cd3fbe41f99e25bbcd58e3bf9f13d3dd31a11e7917251cc77a"}, + {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2f73e01dc37122325caf079982621262f96d74823c179038a82fddfc50359264"}, + {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bb2c0c80d431c0d03f2c7dbf125150fedd4f0de17366a7ca33f7ccb822391842"}, + {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3e6fc1a85fa7194a1a7d19f44e8609180f4a8eb5fa4c7ed8b4355f080fad235c"}, + {file = "aiohttp-3.14.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:686b6c0d3911ec387b444ddf5dc62fb7f7c0a7d5186a7861626496a5ab4aff95"}, + {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c6fa4dc7ad6f8109c70bb1499e589f76b0b792baf39f9b017eb92c8a81d0a199"}, + {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:87a5eea1b2a5e21e1ebdbb33ad4165359189327e63fc4e4894693e7f821ac817"}, + {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1c1421eb01d4fd608d88cc8290211d177a58532b55ad94076fb349c5bf467f0a"}, + {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:34b257ec41345c1e8f2df68fa908a7952f5de932723871eb633ecbbff396c9a4"}, + {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:de538791a80e5d862addbc183f70f0158ac9b9bb872bb147f1fd2a683691e087"}, + {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f71173be42d3241d428f760122febb748de0623f44308a6f120d0dd9ec572e3"}, + {file = "aiohttp-3.14.1-cp312-cp312-win32.whl", hash = "sha256:ec8dc383ee57ea3e883477dcca3f11b65d58199f1080acaf4cd6ad9a99698be4"}, + {file = "aiohttp-3.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:2aa92c87868cd13674989f9ee83e5f9f7ea4237589b728048e1f0c8f6caa3271"}, + {file = "aiohttp-3.14.1-cp312-cp312-win_arm64.whl", hash = "sha256:2c840c90759922cb5e6dda94596e079a30fb5a5ba548e7e0dc00574703940847"}, + {file = "aiohttp-3.14.1-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:b3a03285a7f9c7b016324574a6d92a1c895da6b978cb8f1deee3ac72bc6da178"}, + {file = "aiohttp-3.14.1-cp313-cp313-android_21_x86_64.whl", hash = "sha256:2a73f487ab8ef5abbb24b7aa9b73e98eaba9e9e031804ff2416f02eca315ccaf"}, + {file = "aiohttp-3.14.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:915fbb7b41b115192259f8c9ae58f3ddc444d2b5579917270211858e606a4afd"}, + {file = "aiohttp-3.14.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:7fb4bdf95b0561a79f259f9d28fbc109728c5ee7f27aff6391f0ca703a329abe"}, + {file = "aiohttp-3.14.1-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:1b9748363260121d2927704f5d4fc498150669ca3ae93625986ee89c8f80dcd4"}, + {file = "aiohttp-3.14.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:86a6dab78b0e43e2897a3bbe15745aa60dc5423ca437b7b0b164c069bf91b876"}, + {file = "aiohttp-3.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4dfd6e47d3c44c2279907607f73a4240b88c69eb8b90da7e2441a8045dfd21da"}, + {file = "aiohttp-3.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:317acd9f8602858dc7d59679812c376c7f0b97bcbbf16e0d6237f54141d8a8a6"}, + {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd869c427324e5cb15195793de951295710db28be7d818247f3097b4ab5d4b96"}, + {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:93b032b5ec3255473c143627d21a69ac74ae12f7f33974cb587c564d11b1066f"}, + {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f234b4deb12f3ad59127e037bc57c40c21e45b45282df7d3a55a0f409f595296"}, + {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9af6779bfb46abf124068327abcdf9ce95c9ef8287a3e8da76ccf2d0f16c28fa"}, + {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:faccab372e66bc76d5731525e7f1143c922271725b9d38c9f97edcc66266b451"}, + {file = "aiohttp-3.14.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f380468b09d2a81633ee863b0ec5648d364bd17bb8ecfb8c2f387f7ac1faf42c"}, + {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:97e704dcd26271f5bda3fa07c3ce0fb76d6d3f8659f4baa1a24442cc9ba177ca"}, + {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:269b76ac5394092b95bc4a098f4fc6c191c083c3bd12775d1e30e663132f6a09"}, + {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c0b3e614340c889d575451696374c9d17affd54cd607ca0babed8f8c37b9397"}, + {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:5663ee9257cfa1add7253a7da3035a02f31b6600ec48261585e1800a81533080"}, + {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:603a2c834142172ffddc054067f5ec0ca65d57a0aa98a71bc81952573208e345"}, + {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cb21957bb8aca671c1765e32f58164cf0c50e6bf41c0bbbd16da20732ecaf588"}, + {file = "aiohttp-3.14.1-cp313-cp313-win32.whl", hash = "sha256:e509a55f681e6158c20f70f102f9cf61fb20fbc382272bc6d94b7343f2582780"}, + {file = "aiohttp-3.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:1ac8531b638959718e18c2207fbfe297819875da46a740b29dfa29beba64355a"}, + {file = "aiohttp-3.14.1-cp313-cp313-win_arm64.whl", hash = "sha256:250d14af67f6b6a1a4a811049b1afa69d61d617fca6bf33149b3ab1a6dbcf7b8"}, + {file = "aiohttp-3.14.1-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:7c106c26852ca1c2047c6b80384f17100b4e439af276f21ef3d4e2f450ae7e15"}, + {file = "aiohttp-3.14.1-cp314-cp314-android_24_x86_64.whl", hash = "sha256:20205f7f5ade7aaec9f4b500549bbc071b046453aed72f9c06dcab87896a83e8"}, + {file = "aiohttp-3.14.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:62a759436b29e677181a9e76bab8b8f689a29cb9c535f45f7c48c9c830d3f8c3"}, + {file = "aiohttp-3.14.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:2964cbf553df4d7a57348da44d961d871895fc1ee4e8c322b2a95612c7b17fba"}, + {file = "aiohttp-3.14.1-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:237651caadc3a59badd39319c54642b5299e9cc98a3a194310e55d5bb9f5e397"}, + {file = "aiohttp-3.14.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:896e12dfdbbab9d8f7e16d2b28c6769a60126fa92095d1ebf9473d02593a2448"}, + {file = "aiohttp-3.14.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d03f281ed22579314ba00821ce20115a7c0ac430660b4cc05704a3f818b3e004"}, + {file = "aiohttp-3.14.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:07eabb979d236335fed927e137a928c9adfb7df3b9ec7aa31726f133a62be983"}, + {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4fe1f1087cbadb280b5e1bb054a4f00d1423c74d6626c5e48400d871d34ecefe"}, + {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:367a9314fdc79dab0fac96e216cb41dd73c85bdca85306ce8999118ba7e0f333"}, + {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a24f677ebe83749039e7bdf862ff0bbb16818ae4193d4ef96505e269375bcce0"}, + {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c83afe0ba876be7e943d2e0ba645809ad441575d2840c895c21ee5de93b9377a"}, + {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:634e385930fb6d2d479cf3aa66515955863b77a5e3c2b5894ca259a25b308602"}, + {file = "aiohttp-3.14.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eeea07c4397bbc57719c4eed8f9c284874d4f175f9b6d57f7a1546b976d455ca"}, + {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:335c0cc3e3545ce98dcb9cfcb836f40c3411f43fa03dab757597d80c89af8a35"}, + {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:ae6be797afdef264e8a84864a85b196ca06045586481b3df8a967322fd2fa844"}, + {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:8560b4d712474335d08907db7973f71912d3a9a8f1dee992ec06b5d2fe359496"}, + {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7edd08e0a5deb1e8564a2fcd8f4561014a3f05252334671bbf55ddd47db0e5"}, + {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:b6ff7fcee63287ae57b5df3e4f5957ce032122802509246dec1a5bcc55904c95"}, + {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6ffbb2f4ec1ceaff7e07d43922954da26b223d188bf30658e561b98e23089444"}, + {file = "aiohttp-3.14.1-cp314-cp314-win32.whl", hash = "sha256:a9875b46d910cff3ea2f5962f9d266b465459fe634e22556ab9bd6fc1192eea0"}, + {file = "aiohttp-3.14.1-cp314-cp314-win_amd64.whl", hash = "sha256:af8b4b81a960eeaf1234971ac3cd0ba5901f3cd42eae42a46b4d089a8b492719"}, + {file = "aiohttp-3.14.1-cp314-cp314-win_arm64.whl", hash = "sha256:cf4491381b1b57425c315a56a439251b1bdac07b2275f19a8c44bc57744532ec"}, + {file = "aiohttp-3.14.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:819c054312f1af92947e6a55883d1b66feefab11531a7fc45e0fb9b63880b5c2"}, + {file = "aiohttp-3.14.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:10ee9c1753a8f706345b22496c79fbddb5be0599e0823f3738b1534058e25340"}, + {file = "aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1601cc37baf5750ccacae618ec2daf020769581695550e3b654a911f859c563d"}, + {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4d6e0ac9da31c9c04c84e1c0182ad8d6df35965a85cae29cd71d089621b3ae94"}, + {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9e8f2d660c350b3d0e259c7a7e3d9b7fc8b41210cbcc3d4a7076ff0a5e5c2fdc"}, + {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4691802dda97be727f79d86818acaad7eb8e9252626a1d6b519fedbb92d5e251"}, + {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c389c482a7e9b9dc3ee2701ac46c4125297a3818875b9c305ddb603c04828fd1"}, + {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fc0cacab7ba4e56f0f81c82a98c09bed2f39c940107b03a34b168bdf7597edd3"}, + {file = "aiohttp-3.14.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:979ed4717f59b8bb12e3963378fa285d93d367e15bcd66c721311826d3c44a6c"}, + {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:38e1e7daaea81df51c952e18483f323d878499a1e2bfe564790e0f9701d6f203"}, + {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:4132e72c608fe9fecb8f409113567605915b83e9bdd3ea56538d2f9cd35002f1"}, + {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:eefd9cc9b6d4a2db5f00a26bc3e4f9acf71926a6ec557cd56c9c6f27c290b665"}, + {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:b165790117eea512d7f3fb22f1f6dad3d55a7189571993eb015591c1401276d1"}, + {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:ed09c7eb1c391271c2ed0314a51903e72a3acb653d5ccfc264cdf3ef11f8269d"}, + {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:99abd37084b82f5830c635fddd0b4993b9742a66eb746dacf433c8590e8f9e3c"}, + {file = "aiohttp-3.14.1-cp314-cp314t-win32.whl", hash = "sha256:47ddf841cdecc810749921d25606dee45857d12d2ad5ddb7b5bd7eab12e4b365"}, + {file = "aiohttp-3.14.1-cp314-cp314t-win_amd64.whl", hash = "sha256:5e78b522b7a6e27e0b25d19b247b75039ac4c94f99823e3c9e53ae1603a9f7e9"}, + {file = "aiohttp-3.14.1-cp314-cp314t-win_arm64.whl", hash = "sha256:90d53f1609c29ccc2193945ef732428382a28f78d0456ae4d3daf0d48b74f0f6"}, + {file = "aiohttp-3.14.1.tar.gz", hash = "sha256:307f2cff90a764d329e77040603fa032db89c5c24fdad50c4c15334cba744035"}, ] [package.dependencies] -aiohappyeyeballs = ">=2.3.0" -aiosignal = ">=1.1.2" +aiohappyeyeballs = ">=2.5.0" +aiosignal = ">=1.4.0" async-timeout = {version = ">=4.0,<6.0", markers = "python_version < \"3.11\""} attrs = ">=17.3.0" frozenlist = ">=1.1.1" multidict = ">=4.5,<7.0" propcache = ">=0.2.0" +typing_extensions = {version = ">=4.4", markers = "python_version < \"3.13\""} yarl = ">=1.17.0,<2.0" [package.extras] -speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] +speedups = ["Brotli (>=1.2)", "aiodns (>=3.3.0)", "backports.zstd", "brotlicffi (>=1.2)"] [[package]] name = "aiosignal" -version = "1.3.2" +version = "1.4.0" description = "aiosignal: a list of registered asynchronous callbacks" optional = false python-versions = ">=3.9" files = [ - {file = "aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5"}, - {file = "aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54"}, + {file = "aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e"}, + {file = "aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7"}, ] [package.dependencies] frozenlist = ">=1.1.0" +typing-extensions = {version = ">=4.2", markers = "python_version < \"3.13\""} [[package]] name = "alembic" -version = "1.13.1" +version = "1.18.5" description = "A database migration tool for SQLAlchemy." optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "alembic-1.13.1-py3-none-any.whl", hash = "sha256:2edcc97bed0bd3272611ce3a98d98279e9c209e7186e43e75bbb1b2bdfdbcc43"}, - {file = "alembic-1.13.1.tar.gz", hash = "sha256:4932c8558bf68f2ee92b9bbcb8218671c627064d5b08939437af6d77dc05e595"}, + {file = "alembic-1.18.5-py3-none-any.whl", hash = "sha256:06d8ba9d04558022f5395e9317de03d270f3dced49cee01f89fe7a13c26f14bc"}, + {file = "alembic-1.18.5.tar.gz", hash = "sha256:1554982221dd17e9a749b53902407578eb305e453f71999e8c7f0a48389fff8e"}, ] [package.dependencies] Mako = "*" -SQLAlchemy = ">=1.3.0" -typing-extensions = ">=4" +SQLAlchemy = ">=1.4.23" +tomli = {version = "*", markers = "python_version < \"3.11\""} +typing-extensions = ">=4.12" [package.extras] -tz = ["backports.zoneinfo"] +tz = ["tzdata"] + +[[package]] +name = "annotated-doc" +version = "0.0.4" +description = "Document parameters, class attributes, return types, and variables inline, with Annotated." +optional = false +python-versions = ">=3.8" +files = [ + {file = "annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320"}, + {file = "annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4"}, +] [[package]] name = "annotated-types" @@ -160,50 +212,46 @@ files = [ [[package]] name = "anyio" -version = "4.2.0" -description = "High level compatibility layer for multiple asynchronous event loop implementations" +version = "4.14.2" +description = "High-level concurrency and networking framework on top of asyncio or Trio" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "anyio-4.2.0-py3-none-any.whl", hash = "sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee"}, - {file = "anyio-4.2.0.tar.gz", hash = "sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f"}, + {file = "anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494"}, + {file = "anyio-4.14.2.tar.gz", hash = "sha256:cfa139f3ed1a23ee8f88a145ddb5ac7605b8bbfd8592baacd7ce3d8bb4313c7f"}, ] [package.dependencies] exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} idna = ">=2.8" -sniffio = ">=1.1" -typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} +typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] -doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] -trio = ["trio (>=0.23)"] +trio = ["trio (>=0.32.0)"] [[package]] name = "apscheduler" -version = "3.10.4" +version = "3.11.3" description = "In-process task scheduler with Cron-like capabilities" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "APScheduler-3.10.4-py3-none-any.whl", hash = "sha256:fb91e8a768632a4756a585f79ec834e0e27aad5860bac7eaa523d9ccefd87661"}, - {file = "APScheduler-3.10.4.tar.gz", hash = "sha256:e6df071b27d9be898e486bc7940a7be50b4af2e9da7c08f0744a96d4bd4cef4a"}, + {file = "apscheduler-3.11.3-py3-none-any.whl", hash = "sha256:bbeb2ec02d23d3c06a6c07ed7f0f3939ada6680eb121fae809a69bb42c537a30"}, + {file = "apscheduler-3.11.3.tar.gz", hash = "sha256:cd2fcc9330039a81a5893472ad49facf23a6d5604cbe1d918c835c6de7834d5a"}, ] [package.dependencies] -pytz = "*" -six = ">=1.4.0" -tzlocal = ">=2.0,<3.dev0 || >=4.dev0" +tzlocal = ">=3.0" [package.extras] -doc = ["sphinx", "sphinx-rtd-theme"] +doc = ["packaging", "sphinx", "sphinx-rtd-theme (>=1.3.0)"] +etcd = ["etcd3", "protobuf (<=3.21.0)"] gevent = ["gevent"] mongodb = ["pymongo (>=3.0)"] redis = ["redis (>=3.0)"] rethinkdb = ["rethinkdb (>=2.4.0)"] sqlalchemy = ["sqlalchemy (>=1.4)"] -testing = ["pytest", "pytest-asyncio", "pytest-cov", "pytest-tornado5"] +test = ["APScheduler[etcd,mongodb,redis,rethinkdb,sqlalchemy,tornado,zookeeper]", "PySide6", "anyio (>=4.5.2)", "gevent", "pytest", "pytest-timeout", "pytz", "twisted"] tornado = ["tornado (>=4.3)"] twisted = ["twisted"] zookeeper = ["kazoo"] @@ -221,512 +269,495 @@ files = [ [[package]] name = "attrs" -version = "23.2.0" +version = "26.1.0" description = "Classes Without Boilerplate" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" 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-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309"}, + {file = "attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32"}, ] -[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]"] +[[package]] +name = "audio-qe" +version = "0.1.0" +description = "Audio transcription quality estimation" +optional = false +python-versions = "^3.10, <3.13" +files = [] +develop = true + +[package.dependencies] +numpy = "^1.25.2" +regex = "^2024.11.6" +scipy = "^1.13.1" + +[package.source] +type = "directory" +url = "libs/audio_qe" [[package]] name = "bitarray" -version = "3.1.0" +version = "3.9.0" description = "efficient arrays of booleans -- C extension" optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "bitarray-3.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3c1fad6456993f604726dcb21d1f003430988d5138f858d79e5b8682f56dfad6"}, - {file = "bitarray-3.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0dc0f28340929fffa17fbd3eca5bfae5c1827f3000c0bd9312999d8c5b1464a0"}, - {file = "bitarray-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84de57891a80944e259956fd72bd542290b76c063182f0e85ce5380c49cfcfb6"}, - {file = "bitarray-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b3f4be402e7c611a0a7048f3d042b9e4d697ca6f721d08098118d1ae8bb8a69c"}, - {file = "bitarray-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eabaee3c7d411f6ed48f92752e61a409530a0ebf65498bd408432800a804e0b8"}, - {file = "bitarray-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cb6c270c49d6779af97586a955977493146626ae34710a4c1ec84cb0115f4d4"}, - {file = "bitarray-3.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:481a00d710c7811b38563f6fe22da20be2e6f722196f68873e12d23f4fdf82c1"}, - {file = "bitarray-3.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b81bbefe9d205af66a15a3097f8b66f29fe767fa9cb5dd5a7881f53d2505c2d5"}, - {file = "bitarray-3.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:506df7b12e1380f56cfa20b9c203518afe585f0b86e850a96e3691cf0175e4c0"}, - {file = "bitarray-3.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:43ec740770723de6c99f0a858807ef905664f31cf254e0b803f3dd2797537d7a"}, - {file = "bitarray-3.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:4deac3da54c3df136d6615a2410d5a6170353b4d08142273266296c376fb1889"}, - {file = "bitarray-3.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c58cbd0cc9f6347fffa36a6870fac695cd6e98c39fcfd8002d44a70fba03cd8c"}, - {file = "bitarray-3.1.0-cp310-cp310-win32.whl", hash = "sha256:e092a5c4cc9ae6bc757bc1fee8894cd0275f0a0689c8f57555b00e198cdbcecc"}, - {file = "bitarray-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:453395201790f16b22092c25bed6ecf3bafee7f36db840d4cfc07cd9b6f9628f"}, - {file = "bitarray-3.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a1cb97bdc51e3db8def039607ca42d12c6e55fb134a8d211cca2fcf0a7b3a986"}, - {file = "bitarray-3.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:92d8130efa6bebd4903b70f6d98832aabbd78c1031bc64c7c9d4e39b9db3bfa6"}, - {file = "bitarray-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37a9559ab050618902f8b8055c5b0b78dfc2a7974656fddee26b033ec56945f7"}, - {file = "bitarray-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2c57a4e8f0d9eb5cef7c83c8a4fd8bf06c35d641fc3cb24bf9511adb54e2d8a"}, - {file = "bitarray-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d9bcaa1764d0d302050a31b0f6879ea20e3900b2e73b4ea647ab570950c2062b"}, - {file = "bitarray-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:769184a57abfdfc24c37bb5d0f3836ffe65c7c5cdbeec431766520cd246a27c6"}, - {file = "bitarray-3.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8f247387bb58b8c626088be2fa4ca5869fb12638b45acd29fab21aee48529560"}, - {file = "bitarray-3.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1303604e4069699cef3e969f31d6c3e8e5a0bc637569d90b3647469eff91dc7b"}, - {file = "bitarray-3.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f238c2eb7a0a6a50537e5d182edb629901af94746854108483f0b11b0e3d1a78"}, - {file = "bitarray-3.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e43a96b9b63348d9e5cca70fc31b5d0f07a420a70ef89b376aa4148b87d24b39"}, - {file = "bitarray-3.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5255fb9e4e4879adea5fb61cbde347767d346e29822a51ca21816f28340f4cdb"}, - {file = "bitarray-3.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:68bab51a827abc6f037ea76bb374ec28804a47b51716f9eb3f7da3d754bc8431"}, - {file = "bitarray-3.1.0-cp311-cp311-win32.whl", hash = "sha256:7ff061c714ff62357ff3be23d96c73944ad9181b8b21d49c29ed82fb2fb0efa4"}, - {file = "bitarray-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:b2f8aed62de760be852e0dee0ad507e0fe17fc12f83b36cc0bfe4900e0a0e915"}, - {file = "bitarray-3.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4c298fefda9dfe2ef24aee8fe48acc3a1a063b266791a814330c6932248785c4"}, - {file = "bitarray-3.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e9211fb3a109ba76cb8bd0f76645d256f8a46e733693de22d0d7857941603cee"}, - {file = "bitarray-3.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b6bfe0a618301f0afed9004b8230a413ad399b58fef50a744a623461b96d8e3"}, - {file = "bitarray-3.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2db21d733e06d0d5b86fd3c848a84b8930e71250542aa7602e2c048b96fce163"}, - {file = "bitarray-3.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3807c38b37a500583eafd4ae866d2a051834acd4e11cd8557af9cf5379fa7e21"}, - {file = "bitarray-3.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcd15f43e846bfdaac8e5420006eba2d6adce29b6336492cf9d651e4a313ea86"}, - {file = "bitarray-3.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc2266e15f02d3192d1c2d29a790a4eccb230e23de0de6136815b32f9cdd5b4d"}, - {file = "bitarray-3.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:54a6a8525bc66228ed9cc69d562979319ef151dba2ed302bf7a21c7e124c137b"}, - {file = "bitarray-3.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ffb6b3a6efdabe6a4f3042b16a68499711a7835e950847a5643f60a43de3335f"}, - {file = "bitarray-3.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:430302c3ca7ed0dbb629db87e24a3be082851d71777787d4c8ad424624363780"}, - {file = "bitarray-3.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:d4277999453fa63e96ed8a31698c9ac64ee5f38bd5c63205d69d9b73780fa152"}, - {file = "bitarray-3.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f8fab5053ff281954718dc56c44ee7d1462ccc7e296b84da504b72b01c6c0c41"}, - {file = "bitarray-3.1.0-cp312-cp312-win32.whl", hash = "sha256:598072dbe456cc57270c6f34fa6b9aafd56bb5291e0d14f8509c1522f6d77f32"}, - {file = "bitarray-3.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:4fed8491a77f9fa5303bf6a24a76fcafbf1b496bb22d72b213b673ef8ce6e201"}, - {file = "bitarray-3.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ea4a888e45fdabc89705837b10030a990ec4879d14fccc3b9450ab56ca9d7ec"}, - {file = "bitarray-3.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2695c23b9857105631e9d4f8ebbcc8a4e55c6c9f31bc80d9e5e018e377d650d8"}, - {file = "bitarray-3.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:577a1ffc6318cdcbf91e8492596004bb1572ce3c703aa42c16c8ac1188625b8d"}, - {file = "bitarray-3.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1221d5d1255a74397f938ff822d8df4b0cc416b74e5659d21c3fe5f3d06590a1"}, - {file = "bitarray-3.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91e9309912700ab085cf78d162ad0bf0d3de35e5e084868400672b4ce3befbb0"}, - {file = "bitarray-3.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8c319f77118bac6aded58a0d2f172ac1b06e00bfa5391033848864e39bfd771"}, - {file = "bitarray-3.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:08004c22af11a234a73a8edf744524fb67e89ab4c80791f647c522687ddcb4b9"}, - {file = "bitarray-3.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:afb4d8876fff11cced4377f055498fd3c179e6e2bf7165fd055dabc494005252"}, - {file = "bitarray-3.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7c228c78bd20f2a46a2f3f2e349292c604ae26210dad56afe4b64ea65f72db75"}, - {file = "bitarray-3.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:139115998ffcffd8b883e1f21ced6f1d96947c5ace51f9656ceccedea5765557"}, - {file = "bitarray-3.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7e3ade382c9a5d5d77635041dd2aaa4e59326c8f62e1fb33ce28ddaeaa6ae7b6"}, - {file = "bitarray-3.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5efdb6403d206068d434caf9deb7ab936732c06e5617a63e213c94ac750303f4"}, - {file = "bitarray-3.1.0-cp313-cp313-win32.whl", hash = "sha256:69721fef0427a7f56ed7eef16ff9ddec96c64cee4d7abb5e7511c9aedebafc0f"}, - {file = "bitarray-3.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:34d75765b5c558e7bffa247493412831c6edb5c40e639a6ac94999bc6f40a6c8"}, - {file = "bitarray-3.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6b85d01d8cf30937d9f55d2029a0f7575e9b559d606e6fff17bb79c2830e0afb"}, - {file = "bitarray-3.1.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:acdac94fa2853e74503248b4079a30f3c09ab993f1b2a393fd88071824bdb0de"}, - {file = "bitarray-3.1.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f851a69521240418fc1ab6b313ef5ef6533e451a46184077b1f5e410441c7d9a"}, - {file = "bitarray-3.1.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf6be47880210416d3cd2405fd9a5f28b8fd1896b77acf729024f64b4ecd2676"}, - {file = "bitarray-3.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf4d0759d431953324de2ab251b954123bd4dfa83c990370814a88306f1ffc53"}, - {file = "bitarray-3.1.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a0e1e3836468b62c079a69dbbfcdb8f0abb8dc8540f5cfca48147a8178cc95ea"}, - {file = "bitarray-3.1.0-cp36-cp36m-musllinux_1_2_aarch64.whl", hash = "sha256:0b380164b3b2ff5aa833ee2cf00855645308f14694546ca02beca6b9069e3c75"}, - {file = "bitarray-3.1.0-cp36-cp36m-musllinux_1_2_i686.whl", hash = "sha256:de8ce30fb9e9d2fa063abf8f9443d7bdf77b5de52a5cffbfd007f6150e6bee96"}, - {file = "bitarray-3.1.0-cp36-cp36m-musllinux_1_2_ppc64le.whl", hash = "sha256:72b0f7cbc5c0bf008fde06b7777474a942cc0aa9c743dafc583a1dc430a07122"}, - {file = "bitarray-3.1.0-cp36-cp36m-musllinux_1_2_s390x.whl", hash = "sha256:ccd384e435d9c540c7e54c9149abbf462691e8a6c9287448d44da9f22230e09b"}, - {file = "bitarray-3.1.0-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:37d8da058472b2fedd27903781d5ea27264cde11dcb81a3237724427de83f241"}, - {file = "bitarray-3.1.0-cp36-cp36m-win32.whl", hash = "sha256:f78e2a4fd88b6fa383f44ca866cf6b5e1c0370de7ace7a0b4af7b3f11d806558"}, - {file = "bitarray-3.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:a394cfcd6d9f7fac71429df8e8c4b93b1f0db3ef7a06eb84d9f69d901b862ee4"}, - {file = "bitarray-3.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:756da43ac44b1cbf576a02b3e9710fa24f14823b38df95868ea8a3fea840c725"}, - {file = "bitarray-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:638026c90fb135f0014a47bc5e9d5ed8acff8bbc3283f05e811e9f84a1f32a0e"}, - {file = "bitarray-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f90b57ea9aa9c6159c4a9110e8f787194583ede08b6ff5a6ea36c17b8973b75"}, - {file = "bitarray-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:93cb9b8e2cda9006d489bfa8e7f4fe5680860b6ff45fa9081a6554a9e661fa97"}, - {file = "bitarray-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2225ce0383a2e6950865f178513d8939c89782e909cbcfe4dd7c4f572b1e5a1"}, - {file = "bitarray-3.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bf22a95774a3d04200605bef8f436867df3ec87a13033fc482cce7ce17f62644"}, - {file = "bitarray-3.1.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:226297bb0a9f6636c3b74cfa39a1feec7fbd26c6b59fd9d5b78c4066a87aa571"}, - {file = "bitarray-3.1.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f4c28344774fadb554489f3a8c7a9c75237a85996a8a6d5d91ffa781bdd7b1ff"}, - {file = "bitarray-3.1.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:ce05239a8422ca3ebb1f00cf3577a1d255f07f7dd4c2ab20e8e009da393b86f3"}, - {file = "bitarray-3.1.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:9ce0f80904644ddbdad42eb1eb3945c19bc274b8b0e0844c7f7b9effafd279d0"}, - {file = "bitarray-3.1.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:c467bf00939b162144862d167dd55a651e44c256805f25e44edbd547fc0b0922"}, - {file = "bitarray-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:90b714bc59a9dd11d1bba0d68dd395a3e51f275c8547e9b68af561763a61196e"}, - {file = "bitarray-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4cbbe82edbe2f93f2598042d208caa87969025537ddce34cf647e4da6c4f6af4"}, - {file = "bitarray-3.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:34dd123c69a7f8520c20b45351df1d169429b9e636425c3c8278fdde80151fe6"}, - {file = "bitarray-3.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:03ae745110d4e343d78f5c3836058d510222b17469b1eb64362cdba7cbdfa26a"}, - {file = "bitarray-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfef13ba01363e185f3c7ffd8dc84c109a2be7da4d035b289c8f8a94b02c8183"}, - {file = "bitarray-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:798a71af5e1cded785dabc2f03bf65cd021a7e0ea54d8874a49cbb64669694e2"}, - {file = "bitarray-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d5eb9d2389c76469c4f10d636a79bcd13142d863a5d07a962738ae55fa60dfa"}, - {file = "bitarray-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a0a9c6a9fe679cd48204c719329de0ce72dede6f8e862744adcaf85b1d0c4c6"}, - {file = "bitarray-3.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a97cb1a6cf3538ecda5ce537111f246f468919ca38ff6cfe188f99ee3353c8f2"}, - {file = "bitarray-3.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6d49b0748e9aa0b3bcec4074675405d6a1b19288fb0e8ad8bc6db95c66840747"}, - {file = "bitarray-3.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:b57959f7538b93cb058aa8c467cfd8b82c0af88a2168a4f382ff77e3a90274ee"}, - {file = "bitarray-3.1.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:752e2de8b0094d56a6e98516609f4d2b9a2027d1a9038de3f021a7d1d13d0599"}, - {file = "bitarray-3.1.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:5b90b46cc73fc2db871985ae93132c7945f264aea6000348a124ba84b48af980"}, - {file = "bitarray-3.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:491d5c5b34b00c971be98b36736e090c847b0e2904a1b097a32bb02226fb11ba"}, - {file = "bitarray-3.1.0-cp38-cp38-win32.whl", hash = "sha256:515d954219d9b81b6442ab270cb8142100f32eac06f00f0c588da6c1416c9a1f"}, - {file = "bitarray-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:40c3f234b515aa8cfce0adc1df2b9c3b45e4307f8b756c9f3069cbc3effb5acb"}, - {file = "bitarray-3.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6fdd73f8f563b1f0d106c09949bd90b1104464b5cd148c02b7dae4e3efdb1dcd"}, - {file = "bitarray-3.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0c609504ce985754867a91db78fb1d5110df589447233badb5a1d453fb2e1714"}, - {file = "bitarray-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff398a6850da105e5cf13e4297f1bd181d90c16a4db9ce20e0608e1edf9c81b0"}, - {file = "bitarray-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:39f32b9c1b03f2c2cec002513ef91a9818cf85e8da94069e430d71256c0b858c"}, - {file = "bitarray-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9d6e940dfefe604ecbd77849b107319c73f51dfb24ae18c80710dad9bdb59244"}, - {file = "bitarray-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19c3a7f80b286bd4df0fcbddbe97fd8b48028c0497678ee1f0bab820978295bd"}, - {file = "bitarray-3.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47b6cbbecd24d3b943cef3e704dbf9b510dec310251e1c279d10105cb40a33d8"}, - {file = "bitarray-3.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ab0063f8264cae001fc24238bf8b90a424be25b952951b749b647fd615011428"}, - {file = "bitarray-3.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:86544ffdf8d0cb7271acb5c3a560f4c7850f4c11057cc9c9acdadbea125aa68a"}, - {file = "bitarray-3.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:56ce6219922715fa8f9c65a40a504d4a5e64504ed7c4f3fac64071117559ef33"}, - {file = "bitarray-3.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:56fac415c19689b327f22ca6c02ffa908009f21aab931230d292d5239de40094"}, - {file = "bitarray-3.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e47bee13f43dfc5c5c3661e70b350a5dd37f62f25e196c9a20f504ca02774ac6"}, - {file = "bitarray-3.1.0-cp39-cp39-win32.whl", hash = "sha256:df4ea0d3035298716550b20396d831bc5871efbba7f9cc8e84eabd0906c0163e"}, - {file = "bitarray-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:7c96ecf342bf6093523477cf1eacd958df5206564aef347d3d2d8d4541a1c6a0"}, - {file = "bitarray-3.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c0790bbbe08b141d6a93061e68d1954c86374ca4982e5586becdf7dc0d61e95c"}, - {file = "bitarray-3.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:dde6268797d6e3f0639b1a5048eee5e42aa63fd00c4477741f9a5b1720f1aa8f"}, - {file = "bitarray-3.1.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea7791224248fe8ad6f5533877f94850b5636cf957f245a2f4854da21d0be766"}, - {file = "bitarray-3.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea7319e68ad1cb081dd7d1b2fe1242c12fe8f9ee3c78812db010b18e9753f7bb"}, - {file = "bitarray-3.1.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3aab1395cd4a23b1815f87120e59e1a66a5f3e92cbe42e4653b9fae1320e0eeb"}, - {file = "bitarray-3.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:729ede2a88c0b379080606f2dd6ff4b4fc1798683f1fb244d79e929b298784c4"}, - {file = "bitarray-3.1.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fe0998dfa82776c17c262b20c2ff735f310aed4c85dcc2614ed389815a6bb4ef"}, - {file = "bitarray-3.1.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19f7b08cabfeed0190fbfcf7aad2cd71bb6934f319bd9f195b138616ebc56edf"}, - {file = "bitarray-3.1.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ba0aede899cd78952977db93cf24f5845163efbe85e4220de95298976d3c54b"}, - {file = "bitarray-3.1.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6370b01839750fcb3aea8639344fb3898f73dac42abe344bc5e39669b93fe110"}, - {file = "bitarray-3.1.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:37901e3b417ae482858c29be7b963ef1e6cf0ac16f03f4852295aee1aa77ac18"}, - {file = "bitarray-3.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7eb06912a72f5728864808a68abc1e247bc24c9983a1f3e400f9954245715fac"}, - {file = "bitarray-3.1.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:b9fe9c40c13c0c796bee8d6416185c59f270eb9d22dfb7f6b1cadd0d8be3b4c8"}, - {file = "bitarray-3.1.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44b93406e302f1077c9b4c4b990a40a7afbebab66e4579dce2b06d7f55d8e7c7"}, - {file = "bitarray-3.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:984803aa15421f3bade7c05fd44ab6acdcebe16b646f3201f5ccf1a111ba7661"}, - {file = "bitarray-3.1.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d39a36b6b95889a4cbc1d3083053cebe3315c13ff9a8760c14a3fe9cd8a102b1"}, - {file = "bitarray-3.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:41282599c51e26bc491a3d1471a785a0158c529a2e99757a353a708a9df66655"}, - {file = "bitarray-3.1.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4653e4cab6001a97c6689a4bfe3517128a74656eaa5df22f6ce01fd9b264db30"}, - {file = "bitarray-3.1.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:8d6ef7906263c12a27361ec06e89180a01f8ac57ffa0e1cdf7953948505fea4e"}, - {file = "bitarray-3.1.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:868e0a4fc33333b9cfaa9a0c6b847ce64e7d2064162c2183608244a649487d0a"}, - {file = "bitarray-3.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c64123ae24065478a17d2c6ed08e7e9ea6131be054326a01c9b13f5e36ac1a95"}, - {file = "bitarray-3.1.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6dcceb74c288777e86dbf2497e0bfc444aecf1e710e8a030ea4dba13600ac066"}, - {file = "bitarray-3.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:244897669375d345fe67cd5c0701ec5ea81991a9193fa8cfa4bcb55277375eff"}, - {file = "bitarray-3.1.0.tar.gz", hash = "sha256:71757171a45eac58782861c49137ba3bed0da489155311857f69f4e9baf81fa4"}, + {file = "bitarray-3.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:af7906ffe12fa285014c85a89c165c8f1e6fd485438f08be84e7107d0acdd804"}, + {file = "bitarray-3.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dd5b6d915c21ab53d3f9e32c44335fd1fbcd948589634aba87926432c8897446"}, + {file = "bitarray-3.9.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:89d0e3de109ebc26d713c8c0ca7868d2ca8a2ad812a7dab587a6f4c7b3cf6908"}, + {file = "bitarray-3.9.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2f3c3252914a837a610f25f12a6bf88406fdfadba4de60dad75c20db93fb6b60"}, + {file = "bitarray-3.9.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:dc79aa810daabc3c5eb5f29b8425390e65dac04f02ddc84809eeaef7fc6569dc"}, + {file = "bitarray-3.9.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ae003034bcaba92e534e7237fc6b03e8b4c161ac2e4707155321ea2d9b2d1557"}, + {file = "bitarray-3.9.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8705d00a47326174f606e26d141faba6c0ca7b494f0989bc93d92b1b2527cb49"}, + {file = "bitarray-3.9.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:2ccc1f0f10167e118e965f5b56577445dcdf38bae43e6fdf802c124e518fee8c"}, + {file = "bitarray-3.9.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:bf4b4f57d37e27208298365abf7ee102e2137b29c82cf2f2b996efc08a960202"}, + {file = "bitarray-3.9.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d81d8f90603eaa4de9ae6342fa656e549aa4b510e2d7cde9d7f43d2482600818"}, + {file = "bitarray-3.9.0-cp310-cp310-win32.whl", hash = "sha256:5de49c9dbe5d60f704242ae5ccc35aafb161e61b229e3536b01b6dba58fde4c0"}, + {file = "bitarray-3.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:8863e0461ebed5ff39bfbc73ff9caac78f78834549c727b5f539f1bd3e80849c"}, + {file = "bitarray-3.9.0-cp310-cp310-win_arm64.whl", hash = "sha256:f3509e45507abf43dc584b30de1c9b1adcd5949a7307488ab5df8d9c2bc03181"}, + {file = "bitarray-3.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d66b965ab369284c187c38c9cd5d6e638e863db856ee244c739ad5ec07769645"}, + {file = "bitarray-3.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c019a95da22eca2793dd80db95758ff82cfc17f8813fd6a926cca5fd93b1bd7f"}, + {file = "bitarray-3.9.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b9d16a362f454abe9ef7d362fb9260b0a7945e64a53d35effb10c7fd64da415"}, + {file = "bitarray-3.9.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8f118e3f43a01d7326c30d95eafda951e0823596f1659f4a5a54ab032341d5f4"}, + {file = "bitarray-3.9.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bc6db5b0d52ab31136da48d2913aad14e5ba3bfd5522d75c4d9bda2700c66768"}, + {file = "bitarray-3.9.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:19b6cbca02cdfb27a6fb6e0d4f9170a53da2c37fce70bc5afa6d58aab6d1f1af"}, + {file = "bitarray-3.9.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9c45b31ddef2d4f50224cb5cbe1ac0af4909555340fdf88e65da5c9c7e912cb3"}, + {file = "bitarray-3.9.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:cc9cc3025e9453239843d1c4431c5aca700bec246e9071596b8240193e91af2f"}, + {file = "bitarray-3.9.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e79e4c283ed834b0587b0fde21ced22251a569255b338de1e466d901c8d07d5e"}, + {file = "bitarray-3.9.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4e52b54a8e639da6e80ddeaca9aa3ca324ca20bdcd4cd51f6070ca4b334113a1"}, + {file = "bitarray-3.9.0-cp311-cp311-win32.whl", hash = "sha256:b664bd8174795df4f0353c9ff3d997f5ae764285753c785bf6aa0afab75a357a"}, + {file = "bitarray-3.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:eb5e65d4c2da36446a4592f50e0393a0255e832bdd5d519391a216728cface15"}, + {file = "bitarray-3.9.0-cp311-cp311-win_arm64.whl", hash = "sha256:2d7b0167098b7a423e8b8fcd2d4291aa99b97589e53b6b182c0b456a79a78cd5"}, + {file = "bitarray-3.9.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:541890dd453021a6f8155e7d091a6589652f703832a41c959eb139b487b67ad2"}, + {file = "bitarray-3.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c5f11802751285f982a333192f1336ce94017eedb6ea5f8e05039484ca00b24d"}, + {file = "bitarray-3.9.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1acbb40c630d0429d5a7e8879896f43ddb998625d380d94664239dae9bb4978d"}, + {file = "bitarray-3.9.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e55a6e8e5c14546a90db3c5c93d68dc73c8d86ed19556aa58cd6d558286ae620"}, + {file = "bitarray-3.9.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1f2d47d0f451f42c328544e9a8968d168e452934eef218e6e68e5b14b6711a3a"}, + {file = "bitarray-3.9.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:353430288ff7e2a97029dea750d3095bf85089f8d7757dff52b46d71c0b635ff"}, + {file = "bitarray-3.9.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:63e934aecbad62ed3b591877b7f4ce2c9b7b28376ef70448cb657338911350c1"}, + {file = "bitarray-3.9.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6272808ed86948389e3fb6723474691f4dd3475ccbd2f8b1232feec517b2c394"}, + {file = "bitarray-3.9.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2c0aceb582baabb97612647193fd6160f9766250b7d1f034d1be7d5f2b2d88ca"}, + {file = "bitarray-3.9.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6e3fe6fc6bf914e1a538e955c1260f64ccb174136ac798811f2a5f904e437def"}, + {file = "bitarray-3.9.0-cp312-cp312-win32.whl", hash = "sha256:7ad4eb391e138958b69d9f1521e45e537ad4a66eba9ba90bb4a99ada6fa1fc90"}, + {file = "bitarray-3.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:71070085c168cb5cb0972c09c9f36995a34fab2807c15f2f64f0dee6014f1008"}, + {file = "bitarray-3.9.0-cp312-cp312-win_arm64.whl", hash = "sha256:3075370a7aaec476b0f3ce501f83cfa1797fa722619f7f130981403978b1ad89"}, + {file = "bitarray-3.9.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:62e5a7520f3d2b632438f94c9b9bddf1b2c0e9154e69c8c62e32accf680b3fdc"}, + {file = "bitarray-3.9.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:867994fb56cbfe40c77b1c5d0527e4d6ef4141b3ea2aca2aa02bd89ca08ae2d2"}, + {file = "bitarray-3.9.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:255090e32993dc0b10cd29ad49e21cd7349ed9cdb44d61ad970b4a698b7bd1e7"}, + {file = "bitarray-3.9.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:21facaa003c1a6487eaada863fc93059ee2f542a9ca589f7c5716a1e4ceddfd0"}, + {file = "bitarray-3.9.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c5636104b949b937ef47bcc700665befc2f5a1e906036cba6fdb978501adca11"}, + {file = "bitarray-3.9.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:17e721ed7695257f5f0a8147633f96a60b5ac13735c73d29b2409d1b5a484062"}, + {file = "bitarray-3.9.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:68f66a71bcfbedd1144b8d21b54fa77e32f90067fc3e49abc0a479392697c3cd"}, + {file = "bitarray-3.9.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e780526164e5c4051cf8618e73ecaf0c900c7c3ea2cdd99558b486e47cbe28c9"}, + {file = "bitarray-3.9.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f6abac81451d0d0ce5ee553b9c7e6b9de165642ffe949c1379e6f553f482066e"}, + {file = "bitarray-3.9.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:db0a55d52d9056187670e8e7e525a2aa5f4a74a4459e9455aa68c0198b4ac2fc"}, + {file = "bitarray-3.9.0-cp313-cp313-win32.whl", hash = "sha256:e5799c01e961273136d95ade2164c689714bdfcdc443f9e2568b45df620248d2"}, + {file = "bitarray-3.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:eba091b89bfaf931709e09b8bc564101c7c834d2978019784dd97e017e84d060"}, + {file = "bitarray-3.9.0-cp313-cp313-win_arm64.whl", hash = "sha256:c13cb765f5dd30eefec0046cde1c2eee11b76cd749b045e54f1aa0a15057d219"}, + {file = "bitarray-3.9.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:988ab837bb55951dbddb8b26db0d4a2e9eb3fd2bcf1dfd29ab96b046ff96dd2a"}, + {file = "bitarray-3.9.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d3d27fa77487455de1a3aa6b593dd23eeb5971357b96453daf60307e7a623188"}, + {file = "bitarray-3.9.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4213db72d8ee547df486dce28cde286346bc7a01f8e22fdeea1f8f0c18d1c9eb"}, + {file = "bitarray-3.9.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:212559f1a69c89cdd4ebd487f1581818b67939a3ac157a32f26ab29d29414b84"}, + {file = "bitarray-3.9.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:080e8530a7b56ba843bdad6c4cf9887506944be180222e6691d7aee13f977868"}, + {file = "bitarray-3.9.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05dc8db96a184eeb4e9d51f558602fa51eaa651790aa5d50f7fd2c5306e1bc16"}, + {file = "bitarray-3.9.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:64ccb1873db36d71c90de7611f3bfcad5cae889293bfe81c28d5c0eefa1065d3"}, + {file = "bitarray-3.9.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:eea7a98b277e6a19cdf2e74908a534826f552d7a0d75c17b8fc6f4d886653695"}, + {file = "bitarray-3.9.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:1608a8f62d17323f4b7a92dd731fff8e30562f8a18bab4758aba5fb1d7df9d78"}, + {file = "bitarray-3.9.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:21ab3b432cc4d73fdac310bd500bc54473116c85107acecb27b9d6805ff8b48b"}, + {file = "bitarray-3.9.0-cp314-cp314-win32.whl", hash = "sha256:a1774b7f06b2d705cc0332245b71e18c6f0ddaf6925cce2d0b8eaa30c58b5164"}, + {file = "bitarray-3.9.0-cp314-cp314-win_amd64.whl", hash = "sha256:fc8c5da04dfce44a9446d3e2348924252b72db98a22d1576b2ce66f34dc7fb99"}, + {file = "bitarray-3.9.0-cp314-cp314-win_arm64.whl", hash = "sha256:784d4180c38a0db82fa4a0c7ac54e92cbb9137b0336f7d5f9f433179fab0e56a"}, + {file = "bitarray-3.9.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:737230129bae3649dedfccc4b20040b76805c8a5ff9b3c7f0564775850bcdf58"}, + {file = "bitarray-3.9.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:caaecd574c5ea9c3168654779c0633b08a4c346fe97b38c2896d7846dcfd85cb"}, + {file = "bitarray-3.9.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b3123de3aee13dad947e4e30e1f580cb78fa24c2d103fd5a11e429ea2d55dc0f"}, + {file = "bitarray-3.9.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:513007e9a05ab9247ff5bba5c5bd43557fc40c8fe80fd50be3570760ef449601"}, + {file = "bitarray-3.9.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c9fac669b0c19362b69818eb04358d912ffdaf2b6ee039e4f358271ba8095dc"}, + {file = "bitarray-3.9.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24cbd77670da7e6fe2218b2905a88ecaafd456017673cc7b47b06caf47ff0d77"}, + {file = "bitarray-3.9.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:918a29d788a5a29001dcf20b25da00c0cda6998861d1346358a0a1611dcf2be7"}, + {file = "bitarray-3.9.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:496d8ae6fbc1f870a04d40148ff6daa1357c94543498de5c33612d5969aed074"}, + {file = "bitarray-3.9.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:52b8690da0334d0d1b0907a5011dc08415d0514468296233dd2296b50be2dcc8"}, + {file = "bitarray-3.9.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:41807c5be6b3c0730d2472fd5973d44e22498c610f60a3c00aefe41bb3caa2e2"}, + {file = "bitarray-3.9.0-cp314-cp314t-win32.whl", hash = "sha256:81c12f37cd31e254be3a12454e2933d5668d811ecfc5bbf7cd6f9c54cb5fda60"}, + {file = "bitarray-3.9.0-cp314-cp314t-win_amd64.whl", hash = "sha256:feec62af25b9d81c5013280e44d512a2991784c3f9969fde3ca7327016cc1ab0"}, + {file = "bitarray-3.9.0-cp314-cp314t-win_arm64.whl", hash = "sha256:6334497cd63bf03c5a7c8b58b2b701a3d9aca692e3d82c722a577fe97f7d085f"}, + {file = "bitarray-3.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a3e61827396b12ca67ec7752fef1ca5791cdc019c273bc3c1eb66912b5e8161e"}, + {file = "bitarray-3.9.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6f71689369b38d21ab8d1800f1e6cdbaeeb40c0384bafbd2aa062ba181b96e0c"}, + {file = "bitarray-3.9.0-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:535191f9f5250f044f701461a0a5e86028383c7531cd6554858a402fd8af34a4"}, + {file = "bitarray-3.9.0-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:df8451534b06c8c64801a317d7e4f91889cadaf0a02b74dd2f1cb4955f3fbd46"}, + {file = "bitarray-3.9.0-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:dcd69e150af52ce706ad436b6350c6783ce111aee33e6114806c56933c0c05a0"}, + {file = "bitarray-3.9.0-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2a055a3d80e113d644bc067a40787e6bbce216f896b8767136700fb35522718c"}, + {file = "bitarray-3.9.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:0e95b101a31f3655ac37548a0b3239fdcde87e745881c3ccef7192e2711e9e41"}, + {file = "bitarray-3.9.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:af29f1c1b47e68b921099cfb7744a9e875d79087b6d15fbed918559d8629794f"}, + {file = "bitarray-3.9.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:8fd928a528300f6b9e69d5e00145ceb81e81009749950cdc2f5f7ab7e704de85"}, + {file = "bitarray-3.9.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:3edab70dd2b35240526d3fa0ece098335758173a5ab3582970069ac2dd2f7d6e"}, + {file = "bitarray-3.9.0-cp38-cp38-win32.whl", hash = "sha256:e0dc39f7d0df33c390793716180cb1f1b0adbd5f9701d0adaa608b1ec8867d6e"}, + {file = "bitarray-3.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:2faf64e69dcb308efa0cfa2618552a05c0197e2ee5858facfa47678e5a571fd9"}, + {file = "bitarray-3.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1f5c17c55630255ece343964306070d713559e4f32cd6c394235b64ece6e1b34"}, + {file = "bitarray-3.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8c999433dbe25b3fe8514f1deb2552c9d8d0bdc2b7d7c66c81234894f3254e05"}, + {file = "bitarray-3.9.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:27571ac93c8dbf9bc5f3594257a1d3f2591da08a91fb972083cee334d5828f4a"}, + {file = "bitarray-3.9.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:43569be23ff90190ce7b1b05c2c5072a5ee8d3d09fb076a4ac0a846043179758"}, + {file = "bitarray-3.9.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c16e0377c0a96cdc8eb072e3e31cedfec0dc29fd7d2bb58d63f796771578d49d"}, + {file = "bitarray-3.9.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a6e7134f857a3ab0fe52a6b84b387e31ee2a7c5af77945172221978deda8c7e7"}, + {file = "bitarray-3.9.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f3a90ff32822d70fedf93bd9c057ae88176372fb478c2c376c5257eacfecf27c"}, + {file = "bitarray-3.9.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:2f2749855f3a60ab8d7250f9b549cc7ce77883fb52a7ccac82cdab322f92e305"}, + {file = "bitarray-3.9.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:0e0099dc02f63383c06602e9c73fe0d347d760c7ba23940328e9075cabedc71f"}, + {file = "bitarray-3.9.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0eb630289dad8930a4ad8a634a03a962545c1015b0d90425e1b36a900fc36277"}, + {file = "bitarray-3.9.0-cp39-cp39-win32.whl", hash = "sha256:83943314d6605f7cdc9272937f91f5d9a3446a927cfae89e77502611dfb37d5d"}, + {file = "bitarray-3.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:56315f6d8f967555999d00920ada3712a60af17c4862853162cc837ce7fd635c"}, + {file = "bitarray-3.9.0-cp39-cp39-win_arm64.whl", hash = "sha256:e9d0dfc81d27b44045bdda606dda40452c53e19e2755f56407dfa393980e91c5"}, + {file = "bitarray-3.9.0.tar.gz", hash = "sha256:af5f91e61d868c8f457f66cd726ef31d69264f71edbaccd70fdbb13548c1d652"}, ] [[package]] name = "boto3" -version = "1.34.30" +version = "1.43.50" description = "The AWS SDK for Python" optional = false -python-versions = ">= 3.8" +python-versions = ">=3.10" files = [ - {file = "boto3-1.34.30-py3-none-any.whl", hash = "sha256:cd6173380768faaecf6236dbdcec15d8d032cbb162ce354fdb111056a74fc298"}, - {file = "boto3-1.34.30.tar.gz", hash = "sha256:9e1476ce2b26437881a0381bf2daa54de619ac74ab4bd74278668acda6004a64"}, + {file = "boto3-1.43.50-py3-none-any.whl", hash = "sha256:779eb5cfa8bd1d615f36051465f8182860219eef78b4ab8ca2c666bb56702325"}, + {file = "boto3-1.43.50.tar.gz", hash = "sha256:a6865b9cd1d15511f6aad89cef964105acecff2160a3e29ae53c10d9821416af"}, ] [package.dependencies] -botocore = ">=1.34.30,<1.35.0" +botocore = ">=1.43.50,<1.44.0" jmespath = ">=0.7.1,<2.0.0" -s3transfer = ">=0.10.0,<0.11.0" +s3transfer = ">=0.19.0,<0.20.0" [package.extras] crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.34.30" +version = "1.43.50" description = "Low-level, data-driven core of boto 3." optional = false -python-versions = ">= 3.8" +python-versions = ">=3.10" files = [ - {file = "botocore-1.34.30-py3-none-any.whl", hash = "sha256:caf82d91c2ff61235284a07ffdfba006873e0752e00896052f901a37720cefa4"}, - {file = "botocore-1.34.30.tar.gz", hash = "sha256:e071a9766e7fc2221ca42ec01dfc54368a7518610787342ea622f6edc57f7891"}, + {file = "botocore-1.43.50-py3-none-any.whl", hash = "sha256:4a57a1e0dd4a8be855c29183fc0e029c18e9ec84cd4ac172869f3e800f972528"}, + {file = "botocore-1.43.50.tar.gz", hash = "sha256:7b07c423c44b1ab3815af103f11fa28ea317e28dda1335718a02ecde371a25e9"}, ] [package.dependencies] jmespath = ">=0.7.1,<2.0.0" python-dateutil = ">=2.1,<3.0.0" -urllib3 = {version = ">=1.25.4,<2.1", markers = "python_version >= \"3.10\""} +urllib3 = ">=1.25.4,<2.2.0 || >2.2.0,<3" [package.extras] -crt = ["awscrt (==0.19.19)"] - -[[package]] -name = "cachetools" -version = "5.3.2" -description = "Extensible memoizing collections and decorators" -optional = false -python-versions = ">=3.7" -files = [ - {file = "cachetools-5.3.2-py3-none-any.whl", hash = "sha256:861f35a13a451f94e301ce2bec7cac63e881232ccce7ed67fab9b5df4d3beaa1"}, - {file = "cachetools-5.3.2.tar.gz", hash = "sha256:086ee420196f7b2ab9ca2db2520aca326318b68fe5ba8bc4d49cca91add450f2"}, -] +crt = ["awscrt (==0.32.2)"] [[package]] name = "certifi" -version = "2023.11.17" +version = "2026.6.17" description = "Python package for providing Mozilla's CA Bundle." optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, - {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, + {file = "certifi-2026.6.17-py3-none-any.whl", hash = "sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db"}, + {file = "certifi-2026.6.17.tar.gz", hash = "sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432"}, ] [[package]] name = "cffi" -version = "1.16.0" +version = "2.1.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"}, +python-versions = ">=3.10" +files = [ + {file = "cffi-2.1.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:b65f590ef2a44640f9a05dbb548a429b4ade77913ce683ac8b1480777658a6c0"}, + {file = "cffi-2.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164bff1657b2a74f0b6d54e11c9b375bc97b931f2ca9c43fcf875838da1570dd"}, + {file = "cffi-2.1.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:c941bb58d5a6e1c3892d86e42927ed6c180302f07e6d395d08c416e594b98b46"}, + {file = "cffi-2.1.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a016194dbe13d14ee9556e734b772d8d67b947092b268d757fd4290e3ba2dfc2"}, + {file = "cffi-2.1.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:03e9810d18c646077e501f661b682fbf5dee4676048527ca3cffe66faa9960dd"}, + {file = "cffi-2.1.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:19c54ac121cad98450b4896fa9a43ee0180d57bc4bc911a33db6cab1efab6cd3"}, + {file = "cffi-2.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d433a51f1870e43a13b6732f92aaf540ff77c2015097c78556f75a2d6c030e0"}, + {file = "cffi-2.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3d7f118b5adbfdfead90c25822690b02bc8074fba949bb7858bec4ebd55adb43"}, + {file = "cffi-2.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c5f5df567f6eb216de69be06ce55c8b714090fae02b18a3b40da8163b8c5fa9c"}, + {file = "cffi-2.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:11b3fb55f4f8ad92274ed26705f65d8f91457de71f5380061eb6d125a768fecd"}, + {file = "cffi-2.1.0-cp310-cp310-win32.whl", hash = "sha256:9d72af0cf10a76a600a9690078fe31c63b9588c8e86bf9fd353f713c84b5db0f"}, + {file = "cffi-2.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb62edb5bb52cca65fab91a63afa7561607120d26090a7e8fda6fb9f064726da"}, + {file = "cffi-2.1.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:02cb7ff33ded4f1532476731f89ede53e2e488a8e6205515a82144246ffa7dcc"}, + {file = "cffi-2.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f5bce581e6b8c235e566a14768a943b172ada3ed73537bb0c0be1edee312d4e7"}, + {file = "cffi-2.1.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:30b65779d598c370374fefabf138d456fd6f3216bfa7bedfab1ba82025b0cd93"}, + {file = "cffi-2.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88023dfe18799507b73f1dbb0d14326a17465de1bc9c9c7655c22845e9ddc3a2"}, + {file = "cffi-2.1.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:0a96b74cda968eebbad56d973efe5098974f0a9fb323865bf99ea1fd24e3e64c"}, + {file = "cffi-2.1.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:a5781494d4d400a3f47f8f1da94b324f6e6b440a53387774002890a2a2f4b50f"}, + {file = "cffi-2.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aa7a1b53a2a4452ada2d1b5dade9960b2522f1e61293a811a077439e39029565"}, + {file = "cffi-2.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9d8272c0e483b024e1b9ad029821470ed8ec65631dbd90217469da0e7cd89f1c"}, + {file = "cffi-2.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7762faa47e8ff7eb80bd261d9a7d8eea2d8baa69de5e95b70c1f338bbe712f02"}, + {file = "cffi-2.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:89095c1968b4ba8285840e131bf2891b09ae137fe2146905acae0354fbce1b5e"}, + {file = "cffi-2.1.0-cp311-cp311-win32.whl", hash = "sha256:64c753a0f87a256020004f37a1c8c02c480e725f910f0b2a0f3f07debd1b2479"}, + {file = "cffi-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:4f26194e3d95e06501b942642855aed4f953d55e95d7d01b7c4483db3ecff458"}, + {file = "cffi-2.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:35aaea0c7ee0e58a5cd8c2fd1a48fdf7ece0d2699b7ecdda08194e9ce5dd9b3d"}, + {file = "cffi-2.1.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:df2b82571a1b30f58a87bf4e5a9e78d2b1eff6c6ce8fd3aa3757221f93f0863f"}, + {file = "cffi-2.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78474632761faa0fb96f30b1c928c84ebcf68713cbb80d15bab09dfe61640fde"}, + {file = "cffi-2.1.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:5972433ad71a9e46516584ef60a0fda12d9dc459938d1539c3ddecf9bdc1368d"}, + {file = "cffi-2.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b6422532152adf4e59b110cb2808cee7a033800952f5c036b4af047ee43199e7"}, + {file = "cffi-2.1.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:46b1c8db8f6122420f32d02fffb924c2fe9bc772d228c7c711748fff56aabb2b"}, + {file = "cffi-2.1.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9fafc5aa2e2a39aaf7f8cc0c1f044a9b07fca12e558dca53a3cc5c654ad67a7"}, + {file = "cffi-2.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1e9f50d192a3e525b15a75ab5114e442d83d657b7ec29182a991bc9a88fd3a66"}, + {file = "cffi-2.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:98fff996e983a36d3aa2eca83af40c5821202e7e6f32d13ae94e3d2286f10cfe"}, + {file = "cffi-2.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:379de10ce1ba048b1448599d1b37b24caee16309d1ac98d3982fc997f768700b"}, + {file = "cffi-2.1.0-cp312-cp312-win32.whl", hash = "sha256:9b8f0f26ca4e7513c534d351eca551947d053fac438f2a04ac96d882909b0d3a"}, + {file = "cffi-2.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:c97f080ea627e2863524c5af3836e2270b5f5dfff1f104392b959f8df0c5d384"}, + {file = "cffi-2.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:6d194185eabd279f1c05ebe3504265ddfc5ad2b58d0714f7db9f01da592e9eb6"}, + {file = "cffi-2.1.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:10537b1df4967ca26d21e5072d7d54188354483b91dc75058968d3f0cf13fbda"}, + {file = "cffi-2.1.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:a95b05f9baf29b91171b3a8bd2020b028835243e7b0ff6bb23e2a3c228518b1b"}, + {file = "cffi-2.1.0-cp313-cp313-macosx_10_15_x86_64.whl", hash = "sha256:15faec4adfff450819f3aee0e2e02c812de6edb88203aa58807955db2003472a"}, + {file = "cffi-2.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:716ff8ec22f20b4d988b12884086bcef0fc99737043e503f7a3935a6be99b1ea"}, + {file = "cffi-2.1.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:63960549e4f8dc41e31accb97b975abaecfc44c03e396c093a6436763c2ea7db"}, + {file = "cffi-2.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ff067a8d8d880e7809e4ac88eb009bb848870115317b306666502ccad30b147f"}, + {file = "cffi-2.1.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:3b926723c13eba9f81d2ef3820d63aeceec3b2d4639906047bf675cb8a7a500d"}, + {file = "cffi-2.1.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:47ff3a8bfd8cb9da1af7524b965127095055654c177fcfc7578debcb015eecd0"}, + {file = "cffi-2.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:799416bae98336e400981ff6e532d67d5c709cfb30afb79865a1315f94b0e224"}, + {file = "cffi-2.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:961be50688f7fba2fa65f63712d3b9b341a22311f5253460ce933f52f0de1c8c"}, + {file = "cffi-2.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bf5c6cf48238b0eb4c086978c492ad1cbc22373fc5b2d7353b3a598ce6db887a"}, + {file = "cffi-2.1.0-cp313-cp313-win32.whl", hash = "sha256:db3eb7d46527159a878ec3460e9d40615bc25ba337d477db681aea6e4f05c5d2"}, + {file = "cffi-2.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:8e74a6135550c4748af665b1b1118b6aab33b1fc6a16f9aff630af107c3b4512"}, + {file = "cffi-2.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:2282cd5e38aa8accd03e99d1256af8411c84cdbee6a89d841b563fdbd1f3e50f"}, + {file = "cffi-2.1.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:d2117334c3af3bdcb9a88522b844a2bdb5efdc4f71c6c822df55486ae1c3347a"}, + {file = "cffi-2.1.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:702c436735fbe99d59ada02a1f65cfc0d31c0ee8b7290912f8fbc5cd1e4b16c3"}, + {file = "cffi-2.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1ff3456eab0d889592d1936d6125bbfbc7ae4d3354a700f8bd80450a66445d4d"}, + {file = "cffi-2.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c4165821e131d6d4ca444347c2b694e2311bcfa3fe5a861cc72968f28867beac"}, + {file = "cffi-2.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:276f20fffd7b396e12516ba8edf9509210ac248cbbc5acbc39cd512f9f59ebe6"}, + {file = "cffi-2.1.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7d5980a3433d4b71a5e120f9dd551403d7824e31e2e67124fe2769c404c06913"}, + {file = "cffi-2.1.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:6ca4919c6e4f89aa99c42510b42cf54596892c00b3f9077f6bdd1505e24b9c8d"}, + {file = "cffi-2.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d53d10f7da99ae46f7373b9150393e9c5eab9b224909982b43832668de4779f5"}, + {file = "cffi-2.1.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c351efb95e832a853a29361675f33a7ce53de1a109cd73fd47af0712213aa4ce"}, + {file = "cffi-2.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:dbf7c7a88e2bac086f06d14577332760bdeecc42bdec8ac4077f6260557d9326"}, + {file = "cffi-2.1.0-cp314-cp314-win32.whl", hash = "sha256:1854b724d00f6654c742097d5387569021be12d3a0f770eae1df8f8acfcc6acd"}, + {file = "cffi-2.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:1b96bfe2c4bd825681b7d311ad6d9b7280a091f43e8f63da5729638083cd3bfb"}, + {file = "cffi-2.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:7d28dff1db6764108bc30788d85d61c876beff416d9a49cb9dd7c5a9f34f5804"}, + {file = "cffi-2.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:7ea6b3e2c4250ff1de21c630fe72d0f63eb95c2c32ffbf64a358cf4a8836d714"}, + {file = "cffi-2.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6af371f3767faeffc6ac1ef57cdfd25844403e9d3f476c5537caee499de96376"}, + {file = "cffi-2.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb4e8997a49aa2c08a3e43c9045d224448b8941d88e7ac163c7d383e560cbf98"}, + {file = "cffi-2.1.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:bf01d8c84cbea96b944c73b22182e6c7c432b3475632b8111dbfdc95ddad6e13"}, + {file = "cffi-2.1.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:33eb1ad83ebe8f313e0df035c406227d55a79456704a863fad9842136af5ad7d"}, + {file = "cffi-2.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ac0f1a2d0cfa7eea3f2aaf006ab6e70e8feeb16b75d65b7e5939982ca2f11056"}, + {file = "cffi-2.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c16914df9fb7f500e440e6875fa23ff5e0b31db01fa9c06af98d59a91f0dc2e4"}, + {file = "cffi-2.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5ecbd0499275d57506d397eebe1981cee87b47fcd9ef5c22cab7ed7644a39a94"}, + {file = "cffi-2.1.0-cp314-cp314t-win32.whl", hash = "sha256:7d034dcffa09e9a46c93fa3a3be402096cb5354ac6e41ab8e5cc9cd8b642ad76"}, + {file = "cffi-2.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0582a58f3051372229ca8e7f5f589f9e5632678208d8636fea3676711fdf7fe5"}, + {file = "cffi-2.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:510aeeeac94811b138077451da1fb18b308a5feab47dd2b603af55804155e1c8"}, + {file = "cffi-2.1.0-cp315-cp315-ios_13_0_arm64_iphoneos.whl", hash = "sha256:2e9dabb9abcb7ad15938c7196ad5c1718a4e6d33cc79b4c0209bdb64c4a54a5c"}, + {file = "cffi-2.1.0-cp315-cp315-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:37f525a7e7e50c017fdebe58b787be310ad59357ae43a053943a6e1a6c526001"}, + {file = "cffi-2.1.0-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:95f2954c2c9473d892eca6e0409f3568b37ab62a8eedb122461f73cc273476e3"}, + {file = "cffi-2.1.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:cdf2448aab5f661c9315308ec8b93f4e8a1a67a3c733f8631067a2b67d5913dc"}, + {file = "cffi-2.1.0-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:90bec57cf82089383bd06a605b3eb8daebf7e5a668520beaf6e327a83a947699"}, + {file = "cffi-2.1.0-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6274dcb2d15cef48daa73ed1be5a40d501d74dccd0cd6db364776d12cb6ba022"}, + {file = "cffi-2.1.0-cp315-cp315-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:2b71d409cccee78310ab5dec549aed052aaea483346e282c7b02362596e01bb0"}, + {file = "cffi-2.1.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7d3538f9c0e50670f4deb93dbb696576e60590369cae2faf7de681e597a8a1f1"}, + {file = "cffi-2.1.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:8f9ec95b8a043d3dfbc74d9abc6f7baf524dd27a8dc160b0a32ff9cdab650c28"}, + {file = "cffi-2.1.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:af5e2915d41fe6c961694d7bfdc8562942638200f3ce2765dfb8b745cf997629"}, + {file = "cffi-2.1.0-cp315-cp315-win32.whl", hash = "sha256:0a42c688d19fca6e095a53c6a6e2295a5b050a8b289f109adab02a9e61a25de6"}, + {file = "cffi-2.1.0-cp315-cp315-win_amd64.whl", hash = "sha256:bccbbb5ee76a61f9d99b5bf3846a51d7fca4b6a732fe46f89295610edaf41853"}, + {file = "cffi-2.1.0-cp315-cp315-win_arm64.whl", hash = "sha256:8d35c139744adb3e727cd51b1a18324bbe44b8bd41bf8322bca4d41289f48eda"}, + {file = "cffi-2.1.0-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:f9912624a0c0b834b7520d7769b3644453aabc0a7e1c839da7359f050750e9bc"}, + {file = "cffi-2.1.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:df92f2aba50eb4d96718b68ef76f2e57a57b54f2fa62333496d16c6d585a85ca"}, + {file = "cffi-2.1.0-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0520e1f4c35f44e209cbbb421b67eec42e6a157f59444dfb6058874ff3610e5d"}, + {file = "cffi-2.1.0-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:3681e031db29958a7502f5c0c9d6bbc4c36cb20f7b104086fa642d1799631ff8"}, + {file = "cffi-2.1.0-cp315-cp315t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:762f99479dcb369f60ab9017ad4ab97a36a1dd7c1ee5a3b15db0f4b8659120cd"}, + {file = "cffi-2.1.0-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0611e7ebf90573a535ebdc33ae9da222d037853983e13359f580fab781ca017f"}, + {file = "cffi-2.1.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:86cf8755a791f72c85dc287128cc62d4f24d392e3f1e15837245623f4a33cccc"}, + {file = "cffi-2.1.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:ba00f661f8ba35d075c937174e27c2c421cec3942fd2e0ea3e66996757c0fdd9"}, + {file = "cffi-2.1.0-cp315-cp315t-win32.whl", hash = "sha256:cb96698e3c7413d906ce83f8ffd245ec1bd94707541f299d0ce4d6b0193e982b"}, + {file = "cffi-2.1.0-cp315-cp315t-win_amd64.whl", hash = "sha256:f146d154428a2523f9cc7936c02353c2459b8f6cf07d3cd1ee1c0a611109c5d5"}, + {file = "cffi-2.1.0-cp315-cp315t-win_arm64.whl", hash = "sha256:cbb7640ce37159548d2147b5b8c241f962143d4c71231431820783f4dc78f210"}, + {file = "cffi-2.1.0.tar.gz", hash = "sha256:efc1cdd798b1aaf39b4610bba7aad28c9bea9b910f25c784ccf9ec1fa719d1f9"}, ] [package.dependencies] -pycparser = "*" +pycparser = {version = "*", markers = "implementation_name != \"PyPy\""} [[package]] name = "cfgv" -version = "3.4.0" +version = "3.5.0" description = "Validate configuration and produce human readable error messages." optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, - {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, + {file = "cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0"}, + {file = "cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132"}, ] [[package]] name = "charset-normalizer" -version = "3.3.2" +version = "3.4.9" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false -python-versions = ">=3.7.0" -files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +python-versions = ">=3.7" +files = [ + {file = "charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd6280cf040f233bd7d3407b743b4b4c74f70e8e1c4199cb112a62c941c0772a"}, + {file = "charset_normalizer-3.4.9-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa99adc8f081b475a12843953db36831eaf83ec33eb46a90629ca6a5de45a616"}, + {file = "charset_normalizer-3.4.9-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c1225416b463483160e4af85d5fc3a9690ccb53fd4b1865a6437825f5ede3209"}, + {file = "charset_normalizer-3.4.9-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:16d10d789dd9bcca1173c95af82c58433122564b7bc39385124be735a35cbe99"}, + {file = "charset_normalizer-3.4.9-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9bb41182d93ea91f60b4bc8fbf4c820c69ef8a12ab2d917f3f1834f1acad07e8"}, + {file = "charset_normalizer-3.4.9-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:bcf74c1df76758a395bf0af608c04c82257523f55c9868b334f06270d0f2112b"}, + {file = "charset_normalizer-3.4.9-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b5314963fce9b0b12743891de876e724997864ee22aa496f903f426c7e2fa5b2"}, + {file = "charset_normalizer-3.4.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e9701d0049d92c16703a42771b98d560b95248949f23f8cf7b4eddd201814fb9"}, + {file = "charset_normalizer-3.4.9-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:65a7ff3f705e57d392f7261b6d0550fe137c3019477431f1c355e0db0a7d3e15"}, + {file = "charset_normalizer-3.4.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79580094b00d1789d1f93ea55bc43cb2f611910c72235b7657f3482ddcc1b22d"}, + {file = "charset_normalizer-3.4.9-cp310-cp310-win32.whl", hash = "sha256:432786d3561e69aeeae6c7e8648964ce0ad05736120135601f87ac26b9c83381"}, + {file = "charset_normalizer-3.4.9-cp310-cp310-win_amd64.whl", hash = "sha256:8c041122946b7ba21bb32c45b1aa57b1be35527690aeb3c5c234521085632eee"}, + {file = "charset_normalizer-3.4.9-cp310-cp310-win_arm64.whl", hash = "sha256:375b83ed0aecfce76c16d198fbc21f3b11b337d68662bea0a995046682a11419"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0e94703ec9684807f20cfb5eed95c70f67f2a8f21ad620146d7b5a13677b93e5"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a441ea71902098ffe78c5abe6c494f44160b4af614ed16c3d9a3b1d17fd8ee2"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:304b13570067b2547562e308af560b3963857b1fa90bd6afd978130130fe2d6a"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4773092f8019072343a7447203308b176e10199920eb02d6195e81bbb3274c29"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:04ce310cb89c15df659582aee80a0603788732a5e017d5bd5c81158106ce249c"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:c0323c9daef75ef2e5083624b4585018a0c9d5e3b40f607eed81a311270b934b"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:871ff67ea1aad4dfd91736464934d56b32dac49f9fbe16cddba36198a7b3a0db"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:67830fc78e67501f47bb950471b2dcb9b35b140084429318e862895a8e89c993"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:3d92613ec25e43b05f042302531ec0f00b8445190e43325880cbd6ab7c2581da"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:280081916dc341820640489a66e4696049401ef1cf6dd672f672e70ad915aca3"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-win32.whl", hash = "sha256:ac351b3b8014eead140e77e9717e2992c6bbe30b63bc3422422eb84865412e3d"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-win_amd64.whl", hash = "sha256:6366a16e1a25018694d6a5d784d09b046edc9eac40ea2b54065c3052672516a1"}, + {file = "charset_normalizer-3.4.9-cp311-cp311-win_arm64.whl", hash = "sha256:1d22856ffbe153a602df38e4a5464f0b748a54002e0d69ac6d2ad0a197cc99ec"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:45b0cc4e3556cd875e09102988d1ab8356c998b596c9fced84547c8138b487a0"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b2aff1c7b3884512b9512c3eaadd9bab39fb45042ffaaa1dd08ff2b9f8109d9"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9104ed0bd76a429d46f9ec0dbc9b08ad1d2dcdf2b00a5a0daa1c145329b35b44"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7b86a2b16095d250c6f58b3d9b2eee6f4147754344f3dab0922f7c9bf7d226c9"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e226f6218febc71f6c1fc2fafb91c226f75bdc1d8fb12d66823716e891608fd"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:90c44bc373b7687f6948b693cceaea1348ae0975d7474746559494468e3c1d84"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cdef90ae47919cae358d8ab15797a800ed41da7aba5d72419fb510729e2ed4b"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:60f44ade2cf573dad7a277e6f8ca9a51a21dda572b13bd7d8539bb3cd5dbedde"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a1786910334ed46ab1dd73222f2cd1e05c2c3bb39f6dddb4f8b36fc382058a39"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:03d07803992c6c7bbc976327f34b18b6160327fc81cb82c9d504720ac0be3b62"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-win32.whl", hash = "sha256:78841cccf1af7b40f6f716338d50c0902dbe88d9f800b3c973b7a9a0a693a642"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-win_amd64.whl", hash = "sha256:4b3dac63058cc36820b0dd072f89898604e2d39686fe05321729d00d8ac185a0"}, + {file = "charset_normalizer-3.4.9-cp312-cp312-win_arm64.whl", hash = "sha256:78fa18e436a1a0e58dbd7e02fc4473f3f32cceb12df9dfca542d075961c307d2"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:440eede837960000d74978f0eba527be106b5b9aee0daf779d395276ed0b0614"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21e764fd1e70b6a3e205a0e46f3051701f98a8cb3fad66eeb80e48bb502f8698"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e4fd89cc178bced6ad29cb3e6dd4aa63fa5017c3524dbd0b25998fb64a87cc8b"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bd47ba7fc3ca94896759ea0109775132d3e7ab921fbf54038e1bab2e46c313c9"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:84fd18bcc17526fc2b3c1af7d2b9217d32c9c04448c16ec693b9b4f1985c3d33"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:5b10cd92fc5c498b35a8635df6d5a100207f88b63a4dc1de7ef9a548e1e2cd63"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a4fbdde9dd4a9ce5fd52c2b3a347bb50cc89483ef783f1cb00d408c13f7a96c0"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:416c229f77e5ea25b3dfd4b582f8d73d7e43c22320302b9ab128a2d3a0b38efe"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:75286256590a6320cf106a0d28970d3560aad9ee09aa7b34fb40524792436d35"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:69b157c5d3292bcd443faca052f3096f637f1e074b98212a933c074ae23dc3b8"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-win32.whl", hash = "sha256:51307f5c71007673a2bf8232ad973483d281e74cb99c8c5a990af1eefa6277d9"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-win_amd64.whl", hash = "sha256:fe2c7201c642b7c308f1675355ad7ff7b66acfe3541625efe5a3ad38f29d6115"}, + {file = "charset_normalizer-3.4.9-cp313-cp313-win_arm64.whl", hash = "sha256:611057cc5d5c0afc743ba8be6bd828c17e0aaa8643f9d0a9b9bb7dea80eb8012"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:0327fcd59a935777d83410750c50600ee9571af2846f71ce40f25b13da1ef380"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a79d9f4d8001473a30c163556b3c3bfebec837495a412dde78b51672f6134f9"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:33bdcc2a32c0a0e861f60841a512c8acc658c87c2ac59d89e3a46dacf7d866e4"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f840ed6d8ecba8255df8c42b87fadeda98ddfc6eeec05e2dc66e26d46dd6f58a"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c25fe15c70c59eb7c5ce8c06a1f3fa1da0ecc5ea1e7a5922c40fd2fa9b0d5046"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:f7fb7d750cfa0a070d2c24e831fd3481019a60dd317ea2b39acbcebc08b6ed81"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4d1c96a7a18b9690a4d46df09e3e3382406ae3213727cd1019ebade1c4a81917"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a4cfde78a9f2880208d16a93b795726a3017d5977e08d1e162a7a31322479c41"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d4d6fcde76f94f5cb9e43e9e9a61f16dacefd228cbbf6f1a09bd9b219a92f1a1"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:898f0e9068ca27d37f8e83a5b962821df851532e6c4a7d615c1c033f9da6eedf"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-win32.whl", hash = "sha256:c1c948747b03be832dceed96ca815cef7360de9aa19d37c730f8e3f6101aca48"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-win_amd64.whl", hash = "sha256:16b65ea0f2465b6fb52aa22de5eca612aa964ddfec00a912e26f4656cbef890b"}, + {file = "charset_normalizer-3.4.9-cp314-cp314-win_arm64.whl", hash = "sha256:40a126142a56b2dfc0aacbad1de8310cbf60da7656db0e6b16eebd48e3e93519"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:609b3ba8fcc0fb5ab7af00719d0fb6ad0cb518e48e7712d12fd68f1327951198"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51447e9aa2684679af07ca5021c3db526e0284347ebf4ffcec1154c3350cfe32"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cc1b0fff8ead343dae06305f954eb8468ba0ec1a97881f42489d198e4ce3c632"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fa36ec09ef71d158186bc79e359ff5fdd6e7996fe8ab638f00d6b93139ba4fcf"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:df115d4d83168fdf2cae48ef1ff6d1cb4c466364e30861b37121de0f3bf1b990"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:f86c6358749bd4fda175388691e3ba8c46e24c5347d0afd20f9b7edfc9faf07d"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:32286a2c8d167e897177b673176c1e3e00d4057caf5d2b64eef9a3666b03018e"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:83aed2c10721ddd90f68140685391b50811a880af20654c59af6b6c66c40513c"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cd6c3d4b783c556fa00bf540854e42f135e2f256abd29669fcd0da0f2dec79c2"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ee2f2a527e3c1a6e6411eb4209642e138b544a2d72fe5d0d76daf77b24063534"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-win32.whl", hash = "sha256:0d861473f743244d349b50f850d10eb87aeb22bbdcc8e64f79273c94af5a8226"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-win_amd64.whl", hash = "sha256:9b8e0f3107e2200b76f6054de99016eac3ee6762713587b36baaa7e4bd2ae177"}, + {file = "charset_normalizer-3.4.9-cp314-cp314t-win_arm64.whl", hash = "sha256:19ac87f93086ce37b86e098888555c4b4bc48102279bae3350098c0ed664b501"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:253a4a220747e8b5faf57ec320c4f5efb0cef05f647420bf267143ec15dba10a"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:68ce9f4d6b26d5ccbf7fd4459bf75f74a0a146677ebba80597df60cbdb20e6f4"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:58150c9f9b9a552505912d182ccdf26f6396fb6094816ceebcbb20eecabaed94"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:df7276909358e5635ae203673ab7e509ddd224225a8d6b0790bf13eb2bde1cc5"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3c09a49d6cde137258beb3d551994a2927fd35ad5cf96aed573f61bbd67c5f84"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-manylinux_2_31_armv7l.whl", hash = "sha256:231ddcbb35e2ff8973e1365db41fe0572662893b99a05deb183b68ad4c0c8bd4"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:920079c3f7456fa213e0829ed2073aaa727fd39d889ead5b4f35d0de5460d04f"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0fa1aec2d32bcc03c8fa0f6f1712caad1adc38509f31142112e5c9daf5b9c833"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:ad41ba96094304aa090f5a30cb6e4fb3b3f1c264c523394b4c39bbacc4dc92ba"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:43b9e366a31fdd1c87d0eb08f579b4a82b723ea54338f040d6b4e518a026ea29"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-win32.whl", hash = "sha256:93d59d504b230e83c7a843251681959a0b6a9cd76f6e146ce1b8a80eb8739af9"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-win_amd64.whl", hash = "sha256:ddf4af30b417d9fe16481e9b81c27ab2a7cde1ff7ba3e85653b02db7d145dc7b"}, + {file = "charset_normalizer-3.4.9-cp39-cp39-win_arm64.whl", hash = "sha256:476743fe6dfe14a2da12e3ac79125dc84a3b2cf8094369a47a1529b0cd8549fe"}, + {file = "charset_normalizer-3.4.9-py3-none-any.whl", hash = "sha256:68e5f26a1ad57ded6d1cfb85331d1c1a195314756471d97758c48498bb4dcdf5"}, + {file = "charset_normalizer-3.4.9.tar.gz", hash = "sha256:673611bbd43f0810bec0b0f028ddeaaa501190339cac411f347ac76917c3ae7b"}, ] [[package]] name = "ckzg" -version = "2.0.1" +version = "2.1.8" description = "Python bindings for C-KZG-4844" optional = false python-versions = "*" files = [ - {file = "ckzg-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b7f9ba6d215f8981c5545f952aac84875bd564a63da02fb22a3d1321662ecdc0"}, - {file = "ckzg-2.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8fdec3ff96399acba9baeef9e1b0b5258c08f73245780e6c69f7b73def5e8d0a"}, - {file = "ckzg-2.0.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1644369af9900a9f109d417d6760693edf134118f3100d0c68f56667de775b80"}, - {file = "ckzg-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0a2146f122d489ac7e67ae0c0743f8d0db1718e6aeed8f05717340594fe07dd"}, - {file = "ckzg-2.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:979841be50f2782b447762db38e9bc927ae251f6ca86c54a26561a52068ee779"}, - {file = "ckzg-2.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4516d86647ee4e8ea9470f4adf68fbebb6dc1bdedff7d9592c2504fe53145908"}, - {file = "ckzg-2.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:91866fc58a29b4829201efd9ffadfac3ffeca6359254a54a360ff6a189c34bf5"}, - {file = "ckzg-2.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ed35508dac059b2c0a7994383bc7a92eaf35d0b9ce790016819e2619e0f4b8a9"}, - {file = "ckzg-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:449c4fe38017351eca362106420eeb2d28d50b7e54aa8668b3af29a8ab780132"}, - {file = "ckzg-2.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:260608a22e2f2cadcd31f4495832d45d6460438c38faba9761b92df885a99d88"}, - {file = "ckzg-2.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e1015f99c50215098751b07d7e459ba9a2790d3692ca81552eed29996128e90d"}, - {file = "ckzg-2.0.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dd350d97554c161dc5b8c7b32c2dc8e659632c374f60e2669fb3c9b5b294827"}, - {file = "ckzg-2.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eec7724fa8dc4ae95757efe4a87e7b2d4b880cb348c72ce7355fc0c4f64bc298"}, - {file = "ckzg-2.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3fa0f4398fa67fb71f0a2b34a652cc89e6e0e6af1340b0dc771db1a5f3e089c"}, - {file = "ckzg-2.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f865a0297aabeeb638187a46f7df445763360417b9df4dea60560d512c2cda09"}, - {file = "ckzg-2.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b6ec738350771dbf5974fb70cc8bbb20a4df784af770f7e655922adc08a2171"}, - {file = "ckzg-2.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9b4b669fc77edeb16adc182efc32b3737b36f741a2e33a170d40619e8b171a94"}, - {file = "ckzg-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:decb97f4a17c7338b2130dcc4b045df4cc0e7785ece872c764b554c7c73a99ff"}, - {file = "ckzg-2.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:285cf3121b8a8c5609c5b706314f68d2ba2784ab02c5bb7487c6ae1714ecb27f"}, - {file = "ckzg-2.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f927bc41c2551b0ef0056a649a7ebed29d9665680a10795f4cee5002c69ddb7"}, - {file = "ckzg-2.0.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fd9fb690c88919f30c9f3ab7cc46a7ecd734d5ff4c9ccea383c119b9b7cc4da"}, - {file = "ckzg-2.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fabc3bd41b306d1c7025d561c3281a007c2aca8ceaf998582dc3894904d9c73e"}, - {file = "ckzg-2.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2eb50c53efdb9c34f762bd0c8006cf79bc92a9daf47aa6b541e496988484124f"}, - {file = "ckzg-2.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7960cc62f959403293fb53a3c2404778369ae7cefc6d7f202e5e00567cf98c4b"}, - {file = "ckzg-2.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d721bcd492294c70eca39da0b0a433c29b6a571dbac2f7084bab06334904af06"}, - {file = "ckzg-2.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dde2391d025b5033ef0eeacf62b11ecfe446aea25682b5f547a907766ad0a8cb"}, - {file = "ckzg-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fab8859d9420f6f7df4e094ee3639bc49d18c8dab0df81bee825e2363dd67a09"}, - {file = "ckzg-2.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9747d92883199d4f8f3a3d7018134745fddcf692dfe67115434e4b32609ea785"}, - {file = "ckzg-2.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b2cf58fb9e165da97f0ffe9f4a6efb73992645fac8e0fa223a6cc7ec486a434a"}, - {file = "ckzg-2.0.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d25d006899d76bb8c9d3e8b27981dd6b66a78f9826e33c1bf981af6577a69a19"}, - {file = "ckzg-2.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a04bf0b32f04f5ea5e4b8518e292d3321bc05596fde95f9c3b4f504e5e4bc780"}, - {file = "ckzg-2.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d0cf3dccd72376bff10e1833641cc9d642f34f60ca63972626d9dfcfdc8e77f"}, - {file = "ckzg-2.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:770809c7e93087470cc524724419b0f85590edb033c7c73ba94aef70b36ca18b"}, - {file = "ckzg-2.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e31b59b8124148d5e21f7e41b35532d7af98260c44a77c3917958adece84296d"}, - {file = "ckzg-2.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:174f0c356df644d6e349ce03b7284d83dbec859e11ca5d1b1b3bace8b8fbc65d"}, - {file = "ckzg-2.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:30e375cd45142e56b5dbfdec05ce4deb2368d7f7dedfc7408ba37d5639af05ff"}, - {file = "ckzg-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:abdee71958b214730a8341b16bdd413d0fab1b1a2504fbdb7b0ef2aeee9f9d22"}, - {file = "ckzg-2.0.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b4442667058db791325fe231f22e4fc7aaa3495d535d75af5595bc5f4f86036"}, - {file = "ckzg-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c3c9aa9d4477ad52f3561b717e776c1a8a442d9d8b06600c7d8a2857d1ecf05"}, - {file = "ckzg-2.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68e0a9cde35f11e80b4e560d22990f2f29dd200a95d3141acde137cb6c883f9a"}, - {file = "ckzg-2.0.1-cp36-cp36m-musllinux_1_2_aarch64.whl", hash = "sha256:4508a089e53330866d3360000d76483400eeab5f8057b8e1f3e344ce2cc0097b"}, - {file = "ckzg-2.0.1-cp36-cp36m-musllinux_1_2_i686.whl", hash = "sha256:828cecee16ec576dcf4386beac4eedfd058fd32ee90827f2282e7156a53600be"}, - {file = "ckzg-2.0.1-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:bd437ec1dfb4f5609979328b5f465a74307f45d46d24234868c67d44da96903b"}, - {file = "ckzg-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:70406b10acf68469ac62110047044a6c1a998f5d5fcd6e27cb3ec2d5760d0490"}, - {file = "ckzg-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2f53fba88febac17e82a96eb83dc38ecf4b28abcdd15c0246534c358bd3b26c4"}, - {file = "ckzg-2.0.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be8e0d5015e7755af4ddaab9ae1a4084f72c84b2cbb53628f4366aeed46cc380"}, - {file = "ckzg-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:261414121091042d29f28fc319d7c9a7f950f91f8bf54c010b581ee6a0499473"}, - {file = "ckzg-2.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:524e1e66edd2be2c38b660824aa7b5d4525b41b30ac029d80738a8eee491aeb5"}, - {file = "ckzg-2.0.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:4a12a1d8ef8f475d9f0af9a538e1674057e007806cb1204bb269ea00d9f8c1e5"}, - {file = "ckzg-2.0.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:4cc4bb5f62417a58065deeaf124e178cb1787ef3228e6032600d1e0a2775765b"}, - {file = "ckzg-2.0.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:e7b015f5615bcb82fa0d935481a209fc1dcd9308fb52fb1a7e5400108df67a94"}, - {file = "ckzg-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:0518933ff3b9550f9dd60d833cdb74e8e97cc1cc58f0560b706916606dfd47d0"}, - {file = "ckzg-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ac0bca0795990076cde1930ecec307379b5303e34367c6e6e8a16bdba5a7ba5"}, - {file = "ckzg-2.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8086d23a41020ede312843bda7ea4ee0c9831265379027904106f99f2f8ed469"}, - {file = "ckzg-2.0.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:31d1b141d41fa51aeac9440c936b812e885aef5719adfbd3a27550d8dc433997"}, - {file = "ckzg-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60a58e4d8cb91bad669ca111b7ccdd05c32de6787fdb571bb599625b043ad75b"}, - {file = "ckzg-2.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:633e143385622d7a43fcb5c4f400ec5ec15df0b1c74ab7d6449a41a7abed24ad"}, - {file = "ckzg-2.0.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:4876313614ea01f9a0039b5ca2c754340ba40aa8405f8756912d90ae55718011"}, - {file = "ckzg-2.0.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:19c86c8102200484074afac06b3946b457ba9915636de187f63854522be2e3bd"}, - {file = "ckzg-2.0.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:564abf27878f129781e1df4d33b1c4e264e5b25f89c1bdf95b7d6256e4bceb6c"}, - {file = "ckzg-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:bc2da29bb970d3f5de04fb60797dbb4490c010ffc683cbc6016349dd6fa60d14"}, - {file = "ckzg-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9c1869671140ae7e698520b678b594ebd26fb59ef476711403541597d7d32c01"}, - {file = "ckzg-2.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1dd2aec2c61e8cc2ec815900f6768c6fe74b8fd29810e79b57c4150c6db32fb6"}, - {file = "ckzg-2.0.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9632ef17285dbdd3fcd9780f599c266da736d9b2897decc4ea02ba8690bdf72"}, - {file = "ckzg-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5747d7926873e3af0f6af5fca666feb0097d06cab525950e2664a6fbcb90165d"}, - {file = "ckzg-2.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75484ffb78aaebaeb3a30f1194a9143b904312b0f365fc4101e58e1bf5f89f66"}, - {file = "ckzg-2.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:b2f72bc861b8bee9bac3314c58586d1ab2d23530f932a8f0a8562c8a4a6a45f9"}, - {file = "ckzg-2.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6f85e5802fea5b77f52fc3a14c8dec18a3f2b7c7070c811a4608940834f563cc"}, - {file = "ckzg-2.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:583a0b6b531a16974676439b23e7defb3dfe9732f18d13d2316152019c538af1"}, - {file = "ckzg-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:fafb9ac36b3398f8091d40773d9a450e5f74883dad8ca4ee22d472e7a231ef4d"}, - {file = "ckzg-2.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a12e96f20dce35e5222f898a5c8355054ef7c5ee038eeb97dbb694640b57577b"}, - {file = "ckzg-2.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:4e0ebc55253addaa24dd2cd871bbe3b8f57855f32b5f74e70bf2cb76b6f7da54"}, - {file = "ckzg-2.0.1-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8f917a7bf363a3735db30559e1ed63cf1ccf414234433ba687fa72c007abd756"}, - {file = "ckzg-2.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30f08c984286853271d4adae219e9ba87275a15047dbaa262ab8dd6c01be97b0"}, - {file = "ckzg-2.0.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4fa1ea4888417e1f109fd5e57965788fb7f53b674329b937a65604a3c1ca1d03"}, - {file = "ckzg-2.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0b249914aeaf05cabc71c5c3797e3d6c126cb2c64192b7eb6755ef6aa5ab2f11"}, - {file = "ckzg-2.0.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a038e26baf650e1c733dcaa066ec948e75556b0c485e8c790c9a758875c71a93"}, - {file = "ckzg-2.0.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d6deb2c822122bdd32b555fa3b9216c86a355f24a2cc6a46b9b5743b412b60c"}, - {file = "ckzg-2.0.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50f6f2fbceba9ece3fbc1d2613a246f4e6ec4d787f542859e70c358928c0e4a1"}, - {file = "ckzg-2.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33ca40ef30129e2347bff3c95ad093403a0d5703476705ab92c92fbffe89bd5a"}, - {file = "ckzg-2.0.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:700b989c2f7089edc8fac6dfbd1b4677e85b966216ebedee8eb5e7894765c188"}, - {file = "ckzg-2.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f11933c007c3df02446a81957ac6e2488058b969e2eff5357c98ab569a0c7999"}, - {file = "ckzg-2.0.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:3dbc9580eccecbd485f22e48f6044c48cbe6d838a7b7514cce179c085c65a960"}, - {file = "ckzg-2.0.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad6eb83f343fea6dd9a13fd1bce87b9cd26abeeb72f0674a62d26e40fe0b8aca"}, - {file = "ckzg-2.0.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:269f82b992facbd20461310cf5784551c77d11017b7d4b85d741d70359be6794"}, - {file = "ckzg-2.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:895d67cfd43130652e1ae39b90465b392d9a72c7c7e6f250eaf14689bfda6351"}, - {file = "ckzg-2.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:369cf1aeaf336c31f2050a7f54ae21cf46f4b2db23ebb013fff621144ab361bb"}, - {file = "ckzg-2.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:24fda2637598a467e7b11ff664805ee7fdf4f6c7b0c043d6d0a6ccb69b5681ee"}, - {file = "ckzg-2.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ea27baabe5b22b92901c428768eacf93b992ac7681f93768ab24818ad26ccfed"}, - {file = "ckzg-2.0.1-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a33f71e382020f2bc4ead2bd6881a9bd3811d929f272da239ac01ad615a00802"}, - {file = "ckzg-2.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:926507c569727bb4c851a1eea702c5e902267de96e06ce2d685019f973f72968"}, - {file = "ckzg-2.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f5f29518b0a4555d8f2a28559209bd1d4080547aa629ff9ee51799346573b3f"}, - {file = "ckzg-2.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4595db84ce63c227e4448de0f7b39d3043e3477d78394ff651708c37fee6c486"}, - {file = "ckzg-2.0.1.tar.gz", hash = "sha256:62c5adc381637affa7e1df465c57750b356a761b8a3164c3106589b02532b9c9"}, + {file = "ckzg-2.1.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8dc23b189b5e061b5a2fcf609b6dc1f62098dd72cf9116e4721f995eb144b0ee"}, + {file = "ckzg-2.1.8-cp310-cp310-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:71e0e6d84a268c23c29d546a7ef4720a9d2aea597efe4def75205b6ef436900c"}, + {file = "ckzg-2.1.8-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8ccabbd5aea9cf98ae5301ec8b16119720d93f8f155a567e041e2f16b1fafc87"}, + {file = "ckzg-2.1.8-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a1dee4ec1d8e6702e6008a4d489638027cd640b5d9e5adca48a8c16aa193c6c7"}, + {file = "ckzg-2.1.8-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:697f5c4016a9f091bdf7e646be0d71e625b5106a9f78c6ab53e93e5f425aa513"}, + {file = "ckzg-2.1.8-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:50f6281f5c55240f1be254041e0c06d6348c91e21fccd0ed108151f880b6d087"}, + {file = "ckzg-2.1.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9371ac89c420beb6f6d236ce808c7990174dc21bde61032c39235982e4e65697"}, + {file = "ckzg-2.1.8-cp310-cp310-win_amd64.whl", hash = "sha256:c1f0f8e7a14bb4348f3ecaee92d929df3428be1f706034c961e11239d398bcdb"}, + {file = "ckzg-2.1.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:adb4868ec73547d040d8551538dc00ebc3822a758a7fb2b762735e097556c13b"}, + {file = "ckzg-2.1.8-cp311-cp311-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:5e42a07899e62cf8888bdefe1fa200e3248190953bacc1d872e13825b0b91a7f"}, + {file = "ckzg-2.1.8-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:369af9ec31248a942f2b249bee9f60dccfe6c8ac944095ad26c8083c9df04186"}, + {file = "ckzg-2.1.8-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dac8202240347c4af5cee9a3ebc62560ae629c8bac2b1ee313fa57cf1c9e4f0a"}, + {file = "ckzg-2.1.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:eff52513b32bc83e3b978cae991289cc932d801b6c08aa002d29e44a4290b2f0"}, + {file = "ckzg-2.1.8-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:23bef3d98c905152f4ff497a6243b6a14e916deef2d8a1d342175be90f6e6425"}, + {file = "ckzg-2.1.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:40e6e33672e474331519b7d07b8c8e0cbec3d817b6341e00fa728a94141fa8e8"}, + {file = "ckzg-2.1.8-cp311-cp311-win_amd64.whl", hash = "sha256:b84d698c81569381a3dd18a9848f8fca03273ae62045494cee5669a885697d8d"}, + {file = "ckzg-2.1.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:98abe138d79886e3e1fbbaf05cdf0702a4351f242ad1a8b4802343c7ba149faa"}, + {file = "ckzg-2.1.8-cp312-cp312-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:2fe01dad7c968bcdf3c063c5192bc7d7d59f66358afb5c99554e5ce2435a95aa"}, + {file = "ckzg-2.1.8-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9bdb7f51ee3cf8e45451bee8c6dce975fddadfe231174d8de9c27a3aa27741b8"}, + {file = "ckzg-2.1.8-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10339d23e36b8a0a4e6fda7f6c72d6b2fd4e1506f7b64a661ba8c706ee33f335"}, + {file = "ckzg-2.1.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a4456c9027f2edcb50a2279d6035ca971a511d8b0025e6659ff407b87ad841ba"}, + {file = "ckzg-2.1.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:88cbec7e2010f64988c249ebb5679b73ccae1c536f4c130d4708bf7b06a8cd69"}, + {file = "ckzg-2.1.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a4d2581df10bdfaec00fec6daefdeaa438e66582364e1d1b705710e9d749fc47"}, + {file = "ckzg-2.1.8-cp312-cp312-win_amd64.whl", hash = "sha256:a30f2b980929e898f0b28aa6bf9ae35e7afd5884e354376ad3744669b7cacf3e"}, + {file = "ckzg-2.1.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:26ed4c4d3acbfdb4bfdf1ab1029219657d4565e1c63d36f2695cdfdb5ec0b569"}, + {file = "ckzg-2.1.8-cp313-cp313-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:a6899908ca3a41e6d2aa19973b398de101a6d64b5189894077ea09a3f508d3fd"}, + {file = "ckzg-2.1.8-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3db1ca21685d567eea668925c9f85ebd723db41d24bbecaa2f78d8256e1ba9c6"}, + {file = "ckzg-2.1.8-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f27d7d16be9debf173369248ff06e97fc45826bfb0a743519b49b38539ab6c7"}, + {file = "ckzg-2.1.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dadf0cd0c3c19611e8a1188a2a10316b88fbae56d806f75a67cbe846b8b7ec86"}, + {file = "ckzg-2.1.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cde13789188b7bac6d5bee308532a7bd60ab5c2feeccdef2f1da41be761c7e04"}, + {file = "ckzg-2.1.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1f2737534458547ba8ce89663f833041925b104f7906f17b2338d1b36e6c7c4d"}, + {file = "ckzg-2.1.8-cp313-cp313-win_amd64.whl", hash = "sha256:10b483ad6937878f03d556d120a43d323dcb3891eb83313aa71087b54559594b"}, + {file = "ckzg-2.1.8-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2f3e4a3ae1ff3ec811b6d2aac7a246524f72a750af95fe7a01550cdd68677d6f"}, + {file = "ckzg-2.1.8-cp314-cp314-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:9afe50a28d8d6f130797f0861d4753f76294d983f1e6ead9c17dfa14f8118ad4"}, + {file = "ckzg-2.1.8-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:da197eef7014997b976ae7bc6e0ad42c02a9faa3a4221d6699e8b777761422f1"}, + {file = "ckzg-2.1.8-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fef164b9a0c7ed57935bf78bd23e701ba82efcca180e9b29814a94928a2d5880"}, + {file = "ckzg-2.1.8-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c56f588a57d419ac314880931122796e4331be395368c8887ca3ade5c27f539c"}, + {file = "ckzg-2.1.8-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:37eecbce59271040dfab736db490a28c0e59f189b404e5820e65531dadf84ddb"}, + {file = "ckzg-2.1.8-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:acc5d33e42ac852fec08ad1991020a958e2534ac6af346a83f579b553bd0bdfd"}, + {file = "ckzg-2.1.8-cp314-cp314-win_amd64.whl", hash = "sha256:5eb3b5327dd0cbaaa6551e01a42af9780e998640c57236e460830bf9a6e6f9b4"}, + {file = "ckzg-2.1.8-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:dbd7021cdc5616df5902ec04876b9af25d17facc39851b4d6630c9c2b209e30a"}, + {file = "ckzg-2.1.8-cp314-cp314t-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:5ecbcd887fa97988ddfc3ac4d1951367fa4f6bb25a6f72d449550ea4be45b938"}, + {file = "ckzg-2.1.8-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaeaed98d7be94f7c215373f90cd06536237d6ec08d48d2be74c630e03edf73c"}, + {file = "ckzg-2.1.8-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1030903bf9989957b73fe30a96516e75a8bc27efb65e1b6e9d3507447bfee06"}, + {file = "ckzg-2.1.8-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ff48587f541b625dd0e471ecc866cf91462100a4429e3c21cf4f099e7dff9150"}, + {file = "ckzg-2.1.8-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:0580e8a1780d44a85c6edaa44e30a6a85565ad26593becb320d7353bc05e8627"}, + {file = "ckzg-2.1.8-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:bc8a259bc3cc321413c3c8eb0789cbe35919f4f4bb32946b0e1a484d4303629c"}, + {file = "ckzg-2.1.8-cp314-cp314t-win_amd64.whl", hash = "sha256:f41377a2a63330df64ae6f7cd806a288b21c52aa346151fd8f0551b9e0742289"}, + {file = "ckzg-2.1.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c4ec8234a72cebe419330e13d580048fec25e63d9526a0a9bf65ed134b6ffa9a"}, + {file = "ckzg-2.1.8-cp39-cp39-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:036b8de43a07340609a3a4445d4da542cb9487c58dc0752c2d419c7be1f3dbdb"}, + {file = "ckzg-2.1.8-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9290e8d128921f1906ffa8e6229a878a9e967ea9937697bf90c894fe523e9d11"}, + {file = "ckzg-2.1.8-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ad90fe4e55aea73e3df744b97043c43cd3227725c3f8715fbae07b4eb0acbab0"}, + {file = "ckzg-2.1.8-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8d511e410956aa2fcde7d19f40cefcc166fa84ef3387b3c96083e3798bd21a44"}, + {file = "ckzg-2.1.8-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e523457f3a463214e2ae8aa37f8b35d519e1a51d772734d381dd090cf7391b5c"}, + {file = "ckzg-2.1.8-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:70b67a92373b834e910bc527d538c170757ebc70bc8f99beedbfd64d1913dc80"}, + {file = "ckzg-2.1.8-cp39-cp39-win_amd64.whl", hash = "sha256:d2e709e9701d6085d79cf5d2ed12d373beffae1d93d61b0387055a14818973c0"}, + {file = "ckzg-2.1.8.tar.gz", hash = "sha256:d7bef6b425dca6995457fc59fc5b30211d9b28cbbeee0e7a7bef1372e13f29ca"}, ] [[package]] name = "click" -version = "8.1.7" +version = "8.4.2" description = "Composable command line interface toolkit" optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, + {file = "click-8.4.2-py3-none-any.whl", hash = "sha256:e6f9f66136c816745b9d65817da91d61d957fb16e02e4dcd0552553c5a197b76"}, + {file = "click-8.4.2.tar.gz", hash = "sha256:9a6cea6e60b17ebe0a44c5cc636d94f09bd66142c1cd7d8b4cd731c4917a15f6"}, ] [package.dependencies] @@ -745,66 +776,79 @@ files = [ [[package]] name = "contourpy" -version = "1.2.0" +version = "1.3.2" description = "Python library for calculating contours of 2D quadrilateral grids" optional = false -python-versions = ">=3.9" -files = [ - {file = "contourpy-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0274c1cb63625972c0c007ab14dd9ba9e199c36ae1a231ce45d725cbcbfd10a8"}, - {file = "contourpy-1.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ab459a1cbbf18e8698399c595a01f6dcc5c138220ca3ea9e7e6126232d102bb4"}, - {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fdd887f17c2f4572ce548461e4f96396681212d858cae7bd52ba3310bc6f00f"}, - {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d16edfc3fc09968e09ddffada434b3bf989bf4911535e04eada58469873e28e"}, - {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c203f617abc0dde5792beb586f827021069fb6d403d7f4d5c2b543d87edceb9"}, - {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b69303ceb2e4d4f146bf82fda78891ef7bcd80c41bf16bfca3d0d7eb545448aa"}, - {file = "contourpy-1.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:884c3f9d42d7218304bc74a8a7693d172685c84bd7ab2bab1ee567b769696df9"}, - {file = "contourpy-1.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4a1b1208102be6e851f20066bf0e7a96b7d48a07c9b0cfe6d0d4545c2f6cadab"}, - {file = "contourpy-1.2.0-cp310-cp310-win32.whl", hash = "sha256:34b9071c040d6fe45d9826cbbe3727d20d83f1b6110d219b83eb0e2a01d79488"}, - {file = "contourpy-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:bd2f1ae63998da104f16a8b788f685e55d65760cd1929518fd94cd682bf03e41"}, - {file = "contourpy-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dd10c26b4eadae44783c45ad6655220426f971c61d9b239e6f7b16d5cdaaa727"}, - {file = "contourpy-1.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5c6b28956b7b232ae801406e529ad7b350d3f09a4fde958dfdf3c0520cdde0dd"}, - {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebeac59e9e1eb4b84940d076d9f9a6cec0064e241818bcb6e32124cc5c3e377a"}, - {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:139d8d2e1c1dd52d78682f505e980f592ba53c9f73bd6be102233e358b401063"}, - {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e9dc350fb4c58adc64df3e0703ab076f60aac06e67d48b3848c23647ae4310e"}, - {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18fc2b4ed8e4a8fe849d18dce4bd3c7ea637758c6343a1f2bae1e9bd4c9f4686"}, - {file = "contourpy-1.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:16a7380e943a6d52472096cb7ad5264ecee36ed60888e2a3d3814991a0107286"}, - {file = "contourpy-1.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8d8faf05be5ec8e02a4d86f616fc2a0322ff4a4ce26c0f09d9f7fb5330a35c95"}, - {file = "contourpy-1.2.0-cp311-cp311-win32.whl", hash = "sha256:67b7f17679fa62ec82b7e3e611c43a016b887bd64fb933b3ae8638583006c6d6"}, - {file = "contourpy-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:99ad97258985328b4f207a5e777c1b44a83bfe7cf1f87b99f9c11d4ee477c4de"}, - {file = "contourpy-1.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:575bcaf957a25d1194903a10bc9f316c136c19f24e0985a2b9b5608bdf5dbfe0"}, - {file = "contourpy-1.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9e6c93b5b2dbcedad20a2f18ec22cae47da0d705d454308063421a3b290d9ea4"}, - {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:464b423bc2a009088f19bdf1f232299e8b6917963e2b7e1d277da5041f33a779"}, - {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:68ce4788b7d93e47f84edd3f1f95acdcd142ae60bc0e5493bfd120683d2d4316"}, - {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d7d1f8871998cdff5d2ff6a087e5e1780139abe2838e85b0b46b7ae6cc25399"}, - {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e739530c662a8d6d42c37c2ed52a6f0932c2d4a3e8c1f90692ad0ce1274abe0"}, - {file = "contourpy-1.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:247b9d16535acaa766d03037d8e8fb20866d054d3c7fbf6fd1f993f11fc60ca0"}, - {file = "contourpy-1.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:461e3ae84cd90b30f8d533f07d87c00379644205b1d33a5ea03381edc4b69431"}, - {file = "contourpy-1.2.0-cp312-cp312-win32.whl", hash = "sha256:1c2559d6cffc94890b0529ea7eeecc20d6fadc1539273aa27faf503eb4656d8f"}, - {file = "contourpy-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:491b1917afdd8638a05b611a56d46587d5a632cabead889a5440f7c638bc6ed9"}, - {file = "contourpy-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5fd1810973a375ca0e097dee059c407913ba35723b111df75671a1976efa04bc"}, - {file = "contourpy-1.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:999c71939aad2780f003979b25ac5b8f2df651dac7b38fb8ce6c46ba5abe6ae9"}, - {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7caf9b241464c404613512d5594a6e2ff0cc9cb5615c9475cc1d9b514218ae8"}, - {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:266270c6f6608340f6c9836a0fb9b367be61dde0c9a9a18d5ece97774105ff3e"}, - {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbd50d0a0539ae2e96e537553aff6d02c10ed165ef40c65b0e27e744a0f10af8"}, - {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11f8d2554e52f459918f7b8e6aa20ec2a3bce35ce95c1f0ef4ba36fbda306df5"}, - {file = "contourpy-1.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ce96dd400486e80ac7d195b2d800b03e3e6a787e2a522bfb83755938465a819e"}, - {file = "contourpy-1.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6d3364b999c62f539cd403f8123ae426da946e142312a514162adb2addd8d808"}, - {file = "contourpy-1.2.0-cp39-cp39-win32.whl", hash = "sha256:1c88dfb9e0c77612febebb6ac69d44a8d81e3dc60f993215425b62c1161353f4"}, - {file = "contourpy-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:78e6ad33cf2e2e80c5dfaaa0beec3d61face0fb650557100ee36db808bfa6843"}, - {file = "contourpy-1.2.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:be16975d94c320432657ad2402f6760990cb640c161ae6da1363051805fa8108"}, - {file = "contourpy-1.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b95a225d4948b26a28c08307a60ac00fb8671b14f2047fc5476613252a129776"}, - {file = "contourpy-1.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0d7e03c0f9a4f90dc18d4e77e9ef4ec7b7bbb437f7f675be8e530d65ae6ef956"}, - {file = "contourpy-1.2.0.tar.gz", hash = "sha256:171f311cb758de7da13fc53af221ae47a5877be5a0843a9fe150818c51ed276a"}, +python-versions = ">=3.10" +files = [ + {file = "contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934"}, + {file = "contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989"}, + {file = "contourpy-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9be002b31c558d1ddf1b9b415b162c603405414bacd6932d031c5b5a8b757f0d"}, + {file = "contourpy-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8d2e74acbcba3bfdb6d9d8384cdc4f9260cae86ed9beee8bd5f54fee49a430b9"}, + {file = "contourpy-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e259bced5549ac64410162adc973c5e2fb77f04df4a439d00b478e57a0e65512"}, + {file = "contourpy-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad687a04bc802cbe8b9c399c07162a3c35e227e2daccf1668eb1f278cb698631"}, + {file = "contourpy-1.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cdd22595308f53ef2f891040ab2b93d79192513ffccbd7fe19be7aa773a5e09f"}, + {file = "contourpy-1.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4f54d6a2defe9f257327b0f243612dd051cc43825587520b1bf74a31e2f6ef2"}, + {file = "contourpy-1.3.2-cp310-cp310-win32.whl", hash = "sha256:f939a054192ddc596e031e50bb13b657ce318cf13d264f095ce9db7dc6ae81c0"}, + {file = "contourpy-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c440093bbc8fc21c637c03bafcbef95ccd963bc6e0514ad887932c18ca2a759a"}, + {file = "contourpy-1.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a37a2fb93d4df3fc4c0e363ea4d16f83195fc09c891bc8ce072b9d084853445"}, + {file = "contourpy-1.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b7cd50c38f500bbcc9b6a46643a40e0913673f869315d8e70de0438817cb7773"}, + {file = "contourpy-1.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6658ccc7251a4433eebd89ed2672c2ed96fba367fd25ca9512aa92a4b46c4f1"}, + {file = "contourpy-1.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:70771a461aaeb335df14deb6c97439973d253ae70660ca085eec25241137ef43"}, + {file = "contourpy-1.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65a887a6e8c4cd0897507d814b14c54a8c2e2aa4ac9f7686292f9769fcf9a6ab"}, + {file = "contourpy-1.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3859783aefa2b8355697f16642695a5b9792e7a46ab86da1118a4a23a51a33d7"}, + {file = "contourpy-1.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:eab0f6db315fa4d70f1d8ab514e527f0366ec021ff853d7ed6a2d33605cf4b83"}, + {file = "contourpy-1.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d91a3ccc7fea94ca0acab82ceb77f396d50a1f67412efe4c526f5d20264e6ecd"}, + {file = "contourpy-1.3.2-cp311-cp311-win32.whl", hash = "sha256:1c48188778d4d2f3d48e4643fb15d8608b1d01e4b4d6b0548d9b336c28fc9b6f"}, + {file = "contourpy-1.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:5ebac872ba09cb8f2131c46b8739a7ff71de28a24c869bcad554477eb089a878"}, + {file = "contourpy-1.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4caf2bcd2969402bf77edc4cb6034c7dd7c0803213b3523f111eb7460a51b8d2"}, + {file = "contourpy-1.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:82199cb78276249796419fe36b7386bd8d2cc3f28b3bc19fe2454fe2e26c4c15"}, + {file = "contourpy-1.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:106fab697af11456fcba3e352ad50effe493a90f893fca6c2ca5c033820cea92"}, + {file = "contourpy-1.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d14f12932a8d620e307f715857107b1d1845cc44fdb5da2bc8e850f5ceba9f87"}, + {file = "contourpy-1.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:532fd26e715560721bb0d5fc7610fce279b3699b018600ab999d1be895b09415"}, + {file = "contourpy-1.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b383144cf2d2c29f01a1e8170f50dacf0eac02d64139dcd709a8ac4eb3cfe"}, + {file = "contourpy-1.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c49f73e61f1f774650a55d221803b101d966ca0c5a2d6d5e4320ec3997489441"}, + {file = "contourpy-1.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3d80b2c0300583228ac98d0a927a1ba6a2ba6b8a742463c564f1d419ee5b211e"}, + {file = "contourpy-1.3.2-cp312-cp312-win32.whl", hash = "sha256:90df94c89a91b7362e1142cbee7568f86514412ab8a2c0d0fca72d7e91b62912"}, + {file = "contourpy-1.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:8c942a01d9163e2e5cfb05cb66110121b8d07ad438a17f9e766317bcb62abf73"}, + {file = "contourpy-1.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:de39db2604ae755316cb5967728f4bea92685884b1e767b7c24e983ef5f771cb"}, + {file = "contourpy-1.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3f9e896f447c5c8618f1edb2bafa9a4030f22a575ec418ad70611450720b5b08"}, + {file = "contourpy-1.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71e2bd4a1c4188f5c2b8d274da78faab884b59df20df63c34f74aa1813c4427c"}, + {file = "contourpy-1.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de425af81b6cea33101ae95ece1f696af39446db9682a0b56daaa48cfc29f38f"}, + {file = "contourpy-1.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:977e98a0e0480d3fe292246417239d2d45435904afd6d7332d8455981c408b85"}, + {file = "contourpy-1.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:434f0adf84911c924519d2b08fc10491dd282b20bdd3fa8f60fd816ea0b48841"}, + {file = "contourpy-1.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c66c4906cdbc50e9cba65978823e6e00b45682eb09adbb78c9775b74eb222422"}, + {file = "contourpy-1.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8b7fc0cd78ba2f4695fd0a6ad81a19e7e3ab825c31b577f384aa9d7817dc3bef"}, + {file = "contourpy-1.3.2-cp313-cp313-win32.whl", hash = "sha256:15ce6ab60957ca74cff444fe66d9045c1fd3e92c8936894ebd1f3eef2fff075f"}, + {file = "contourpy-1.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e1578f7eafce927b168752ed7e22646dad6cd9bca673c60bff55889fa236ebf9"}, + {file = "contourpy-1.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0475b1f6604896bc7c53bb070e355e9321e1bc0d381735421a2d2068ec56531f"}, + {file = "contourpy-1.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c85bb486e9be652314bb5b9e2e3b0d1b2e643d5eec4992c0fbe8ac71775da739"}, + {file = "contourpy-1.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:745b57db7758f3ffc05a10254edd3182a2a83402a89c00957a8e8a22f5582823"}, + {file = "contourpy-1.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:970e9173dbd7eba9b4e01aab19215a48ee5dd3f43cef736eebde064a171f89a5"}, + {file = "contourpy-1.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6c4639a9c22230276b7bffb6a850dfc8258a2521305e1faefe804d006b2e532"}, + {file = "contourpy-1.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc829960f34ba36aad4302e78eabf3ef16a3a100863f0d4eeddf30e8a485a03b"}, + {file = "contourpy-1.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d32530b534e986374fc19eaa77fcb87e8a99e5431499949b828312bdcd20ac52"}, + {file = "contourpy-1.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e298e7e70cf4eb179cc1077be1c725b5fd131ebc81181bf0c03525c8abc297fd"}, + {file = "contourpy-1.3.2-cp313-cp313t-win32.whl", hash = "sha256:d0e589ae0d55204991450bb5c23f571c64fe43adaa53f93fc902a84c96f52fe1"}, + {file = "contourpy-1.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:78e9253c3de756b3f6a5174d024c4835acd59eb3f8e2ca13e775dbffe1558f69"}, + {file = "contourpy-1.3.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fd93cc7f3139b6dd7aab2f26a90dde0aa9fc264dbf70f6740d498a70b860b82c"}, + {file = "contourpy-1.3.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:107ba8a6a7eec58bb475329e6d3b95deba9440667c4d62b9b6063942b61d7f16"}, + {file = "contourpy-1.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ded1706ed0c1049224531b81128efbd5084598f18d8a2d9efae833edbd2b40ad"}, + {file = "contourpy-1.3.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5f5964cdad279256c084b69c3f412b7801e15356b16efa9d78aa974041903da0"}, + {file = "contourpy-1.3.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49b65a95d642d4efa8f64ba12558fcb83407e58a2dfba9d796d77b63ccfcaff5"}, + {file = "contourpy-1.3.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8c5acb8dddb0752bf252e01a3035b21443158910ac16a3b0d20e7fed7d534ce5"}, + {file = "contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54"}, ] [package.dependencies] -numpy = ">=1.20,<2.0" +numpy = ">=1.23" [package.extras] bokeh = ["bokeh", "selenium"] docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] -mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.6.1)", "types-Pillow"] +mypy = ["bokeh", "contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.15.0)", "types-Pillow"] test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] -test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] +test-no-images = ["pytest", "pytest-cov", "pytest-rerunfailures", "pytest-xdist", "wurlitzer"] [[package]] name = "cryptography" @@ -857,13 +901,13 @@ test-randomorder = ["pytest-randomly"] [[package]] name = "cvat-sdk" -version = "2.37.0" -description = "CVAT REST API" +version = "2.70.0" +description = "Software Development Kit for CVAT" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" files = [ - {file = "cvat_sdk-2.37.0-py3-none-any.whl", hash = "sha256:faa94cfd6678089814179a8da828761dfa3daf08eb752490ee85551a1045dac5"}, - {file = "cvat_sdk-2.37.0.tar.gz", hash = "sha256:e990908a473c499eb6d7b84f7f2e640ea729ef027d4c4cc32a5a925752532689"}, + {file = "cvat_sdk-2.70.0-py3-none-any.whl", hash = "sha256:6098b01bda86433d96e177cfce5e28dce2c19f7c0bd3b0e814b8d7e45b8e1a46"}, + {file = "cvat_sdk-2.70.0.tar.gz", hash = "sha256:4d9304bd8334b05b5e5504466cedf1f538a667f5274544398dec78bba4b47e83"}, ] [package.dependencies] @@ -872,9 +916,7 @@ packaging = ">=21.3" Pillow = ">=10.3.0" platformdirs = ">=2.1.0" python_dateutil = ">=2.5.3" -setuptools = ">=21.0.0" tqdm = ">=4.64.0" -tuspy = "0.2.5" typing_extensions = ">=4.2.0" urllib3 = ">=1.25.3" @@ -899,118 +941,192 @@ tests = ["pytest", "pytest-cov", "pytest-xdist"] [[package]] name = "cytoolz" -version = "1.0.1" +version = "1.1.0" description = "Cython implementation of Toolz: High performance functional utilities" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "cytoolz-1.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cec9af61f71fc3853eb5dca3d42eb07d1f48a4599fa502cbe92adde85f74b042"}, - {file = "cytoolz-1.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:140bbd649dbda01e91add7642149a5987a7c3ccc251f2263de894b89f50b6608"}, - {file = "cytoolz-1.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e90124bdc42ff58b88cdea1d24a6bc5f776414a314cc4d94f25c88badb3a16d1"}, - {file = "cytoolz-1.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e74801b751e28f7c5cc3ad264c123954a051f546f2fdfe089f5aa7a12ccfa6da"}, - {file = "cytoolz-1.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:582dad4545ddfb5127494ef23f3fa4855f1673a35d50c66f7638e9fb49805089"}, - {file = "cytoolz-1.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd7bd0618e16efe03bd12f19c2a26a27e6e6b75d7105adb7be1cd2a53fa755d8"}, - {file = "cytoolz-1.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d74cca6acf1c4af58b2e4a89cc565ed61c5e201de2e434748c93e5a0f5c541a5"}, - {file = "cytoolz-1.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:823a3763828d8d457f542b2a45d75d6b4ced5e470b5c7cf2ed66a02f508ed442"}, - {file = "cytoolz-1.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:51633a14e6844c61db1d68c1ffd077cf949f5c99c60ed5f1e265b9e2966f1b52"}, - {file = "cytoolz-1.0.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f3ec9b01c45348f1d0d712507d54c2bfd69c62fbd7c9ef555c9d8298693c2432"}, - {file = "cytoolz-1.0.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1855022b712a9c7a5bce354517ab4727a38095f81e2d23d3eabaf1daeb6a3b3c"}, - {file = "cytoolz-1.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9930f7288c4866a1dc1cc87174f0c6ff4cad1671eb1f6306808aa6c445857d78"}, - {file = "cytoolz-1.0.1-cp310-cp310-win32.whl", hash = "sha256:a9baad795d72fadc3445ccd0f122abfdbdf94269157e6d6d4835636dad318804"}, - {file = "cytoolz-1.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:ad95b386a84e18e1f6136f6d343d2509d4c3aae9f5a536f3dc96808fcc56a8cf"}, - {file = "cytoolz-1.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2d958d4f04d9d7018e5c1850790d9d8e68b31c9a2deebca74b903706fdddd2b6"}, - {file = "cytoolz-1.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0f445b8b731fc0ecb1865b8e68a070084eb95d735d04f5b6c851db2daf3048ab"}, - {file = "cytoolz-1.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f546a96460a7e28eb2ec439f4664fa646c9b3e51c6ebad9a59d3922bbe65e30"}, - {file = "cytoolz-1.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0317681dd065532d21836f860b0563b199ee716f55d0c1f10de3ce7100c78a3b"}, - {file = "cytoolz-1.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0c0ef52febd5a7821a3fd8d10f21d460d1a3d2992f724ba9c91fbd7a96745d41"}, - {file = "cytoolz-1.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5ebaf419acf2de73b643cf96108702b8aef8e825cf4f63209ceb078d5fbbbfd"}, - {file = "cytoolz-1.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f7f04eeb4088947585c92d6185a618b25ad4a0f8f66ea30c8db83cf94a425e3"}, - {file = "cytoolz-1.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f61928803bb501c17914b82d457c6f50fe838b173fb40d39c38d5961185bd6c7"}, - {file = "cytoolz-1.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d2960cb4fa01ccb985ad1280db41f90dc97a80b397af970a15d5a5de403c8c61"}, - {file = "cytoolz-1.0.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b2b407cc3e9defa8df5eb46644f6f136586f70ba49eba96f43de67b9a0984fd3"}, - {file = "cytoolz-1.0.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:8245f929144d4d3bd7b972c9593300195c6cea246b81b4c46053c48b3f044580"}, - {file = "cytoolz-1.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e37385db03af65763933befe89fa70faf25301effc3b0485fec1c15d4ce4f052"}, - {file = "cytoolz-1.0.1-cp311-cp311-win32.whl", hash = "sha256:50f9c530f83e3e574fc95c264c3350adde8145f4f8fc8099f65f00cc595e5ead"}, - {file = "cytoolz-1.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:b7f6b617454b4326af7bd3c7c49b0fc80767f134eb9fd6449917a058d17a0e3c"}, - {file = "cytoolz-1.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fcb8f7d0d65db1269022e7e0428471edee8c937bc288ebdcb72f13eaa67c2fe4"}, - {file = "cytoolz-1.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:207d4e4b445e087e65556196ff472ff134370d9a275d591724142e255f384662"}, - {file = "cytoolz-1.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21cdf6bac6fd843f3b20280a66fd8df20dea4c58eb7214a2cd8957ec176f0bb3"}, - {file = "cytoolz-1.0.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a55ec098036c0dea9f3bdc021f8acd9d105a945227d0811589f0573f21c9ce1"}, - {file = "cytoolz-1.0.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a13ab79ff4ce202e03ab646a2134696988b554b6dc4b71451e948403db1331d8"}, - {file = "cytoolz-1.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e2d944799026e1ff08a83241f1027a2d9276c41f7a74224cd98b7df6e03957d"}, - {file = "cytoolz-1.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88ba85834cd523b91fdf10325e1e6d71c798de36ea9bdc187ca7bd146420de6f"}, - {file = "cytoolz-1.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a750b1af7e8bf6727f588940b690d69e25dc47cce5ce467925a76561317eaf7"}, - {file = "cytoolz-1.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:44a71870f7eae31d263d08b87da7c2bf1176f78892ed8bdade2c2850478cb126"}, - {file = "cytoolz-1.0.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c8231b9abbd8e368e036f4cc2e16902c9482d4cf9e02a6147ed0e9a3cd4a9ab0"}, - {file = "cytoolz-1.0.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:aa87599ccc755de5a096a4d6c34984de6cd9dc928a0c5eaa7607457317aeaf9b"}, - {file = "cytoolz-1.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:67cd16537df51baabde3baa770ab7b8d16839c4d21219d5b96ac59fb012ebd2d"}, - {file = "cytoolz-1.0.1-cp312-cp312-win32.whl", hash = "sha256:fb988c333f05ee30ad4693fe4da55d95ec0bb05775d2b60191236493ea2e01f9"}, - {file = "cytoolz-1.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:8f89c48d8e5aec55ffd566a8ec858706d70ed0c6a50228eca30986bfa5b4da8b"}, - {file = "cytoolz-1.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6944bb93b287032a4c5ca6879b69bcd07df46f3079cf8393958cf0b0454f50c0"}, - {file = "cytoolz-1.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e027260fd2fc5cb041277158ac294fc13dca640714527219f702fb459a59823a"}, - {file = "cytoolz-1.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88662c0e07250d26f5af9bc95911e6137e124a5c1ec2ce4a5d74de96718ab242"}, - {file = "cytoolz-1.0.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:309dffa78b0961b4c0cf55674b828fbbc793cf2d816277a5c8293c0c16155296"}, - {file = "cytoolz-1.0.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:edb34246e6eb40343c5860fc51b24937698e4fa1ee415917a73ad772a9a1746b"}, - {file = "cytoolz-1.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a54da7a8e4348a18d45d4d5bc84af6c716d7f131113a4f1cc45569d37edff1b"}, - {file = "cytoolz-1.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:241c679c3b1913c0f7259cf1d9639bed5084c86d0051641d537a0980548aa266"}, - {file = "cytoolz-1.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5bfc860251a8f280ac79696fc3343cfc3a7c30b94199e0240b6c9e5b6b01a2a5"}, - {file = "cytoolz-1.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c8edd1547014050c1bdad3ff85d25c82bd1c2a3c96830c6181521eb78b9a42b3"}, - {file = "cytoolz-1.0.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b349bf6162e8de215403d7f35f8a9b4b1853dc2a48e6e1a609a5b1a16868b296"}, - {file = "cytoolz-1.0.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1b18b35256219b6c3dd0fa037741b85d0bea39c552eab0775816e85a52834140"}, - {file = "cytoolz-1.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:738b2350f340ff8af883eb301054eb724997f795d20d90daec7911c389d61581"}, - {file = "cytoolz-1.0.1-cp313-cp313-win32.whl", hash = "sha256:9cbd9c103df54fcca42be55ef40e7baea624ac30ee0b8bf1149f21146d1078d9"}, - {file = "cytoolz-1.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:90e577e08d3a4308186d9e1ec06876d4756b1e8164b92971c69739ea17e15297"}, - {file = "cytoolz-1.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f3a509e4ac8e711703c368476b9bbce921fcef6ebb87fa3501525f7000e44185"}, - {file = "cytoolz-1.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a7eecab6373e933dfbf4fdc0601d8fd7614f8de76793912a103b5fccf98170cd"}, - {file = "cytoolz-1.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e55ed62087f6e3e30917b5f55350c3b6be6470b849c6566018419cd159d2cebc"}, - {file = "cytoolz-1.0.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43de33d99a4ccc07234cecd81f385456b55b0ea9c39c9eebf42f024c313728a5"}, - {file = "cytoolz-1.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:139bed875828e1727018aa0982aa140e055cbafccb7fd89faf45cbb4f2a21514"}, - {file = "cytoolz-1.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22c12671194b518aa8ce2f4422bd5064f25ab57f410ba0b78705d0a219f4a97a"}, - {file = "cytoolz-1.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79888f2f7dc25709cd5d37b032a8833741e6a3692c8823be181d542b5999128e"}, - {file = "cytoolz-1.0.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:51628b4eb41fa25bd428f8f7b5b74fbb05f3ae65fbd265019a0dd1ded4fdf12a"}, - {file = "cytoolz-1.0.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:1db9eb7179285403d2fb56ba1ff6ec35a44921b5e2fa5ca19d69f3f9f0285ea5"}, - {file = "cytoolz-1.0.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:08ab7efae08e55812340bfd1b3f09f63848fe291675e2105eab1aa5327d3a16e"}, - {file = "cytoolz-1.0.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:e5fdc5264f884e7c0a1711a81dff112708a64b9c8561654ee578bfdccec6be09"}, - {file = "cytoolz-1.0.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:90d6a2e6ab891043ee655ec99d5e77455a9bee9e1131bdfcfb745edde81200dd"}, - {file = "cytoolz-1.0.1-cp38-cp38-win32.whl", hash = "sha256:08946e083faa5147751b34fbf78ab931f149ef758af5c1092932b459e18dcf5c"}, - {file = "cytoolz-1.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:a91b4e10a9c03796c0dc93e47ebe25bb41ecc6fafc3cf5197c603cf767a3d44d"}, - {file = "cytoolz-1.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:980c323e626ba298b77ae62871b2de7c50b9d7219e2ddf706f52dd34b8be7349"}, - {file = "cytoolz-1.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:45f6fa1b512bc2a0f2de5123db932df06c7f69d12874fe06d67772b2828e2c8b"}, - {file = "cytoolz-1.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f93f42d9100c415155ad1f71b0de362541afd4ac95e3153467c4c79972521b6b"}, - {file = "cytoolz-1.0.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a76d20dec9c090cdf4746255bbf06a762e8cc29b5c9c1d138c380bbdb3122ade"}, - {file = "cytoolz-1.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:239039585487c69aa50c5b78f6a422016297e9dea39755761202fb9f0530fe87"}, - {file = "cytoolz-1.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c28307640ca2ab57b9fbf0a834b9bf563958cd9e038378c3a559f45f13c3c541"}, - {file = "cytoolz-1.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:454880477bb901cee3a60f6324ec48c95d45acc7fecbaa9d49a5af737ded0595"}, - {file = "cytoolz-1.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:902115d1b1f360fd81e44def30ac309b8641661150fcbdde18ead446982ada6a"}, - {file = "cytoolz-1.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e68e6b38473a3a79cee431baa22be31cac39f7df1bf23eaa737eaff42e213883"}, - {file = "cytoolz-1.0.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:32fba3f63fcb76095b0a22f4bdcc22bc62a2bd2d28d58bf02fd21754c155a3ec"}, - {file = "cytoolz-1.0.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:0724ba4cf41eb40b6cf75250820ab069e44bdf4183ff78857aaf4f0061551075"}, - {file = "cytoolz-1.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c42420e0686f887040d5230420ed44f0e960ccbfa29a0d65a3acd9ca52459209"}, - {file = "cytoolz-1.0.1-cp39-cp39-win32.whl", hash = "sha256:4ba8b16358ea56b1fe8e637ec421e36580866f2e787910bac1cf0a6997424a34"}, - {file = "cytoolz-1.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:92d27f84bf44586853d9562bfa3610ecec000149d030f793b4cb614fd9da1813"}, - {file = "cytoolz-1.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:83d19d55738ad9c60763b94f3f6d3c6e4de979aeb8d76841c1401081e0e58d96"}, - {file = "cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f112a71fad6ea824578e6393765ce5c054603afe1471a5c753ff6c67fd872d10"}, - {file = "cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a515df8f8aa6e1eaaf397761a6e4aff2eef73b5f920aedf271416d5471ae5ee"}, - {file = "cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92c398e7b7023460bea2edffe5fcd0a76029580f06c3f6938ac3d198b47156f3"}, - {file = "cytoolz-1.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3237e56211e03b13df47435b2369f5df281e02b04ad80a948ebd199b7bc10a47"}, - {file = "cytoolz-1.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ba0d1da50aab1909b165f615ba1125c8b01fcc30d606c42a61c42ea0269b5e2c"}, - {file = "cytoolz-1.0.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25b6e8dec29aa5a390092d193abd673e027d2c0b50774ae816a31454286c45c7"}, - {file = "cytoolz-1.0.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:36cd6989ebb2f18fe9af8f13e3c61064b9f741a40d83dc5afeb0322338ad25f2"}, - {file = "cytoolz-1.0.1-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a47394f8ab7fca3201f40de61fdeea20a2baffb101485ae14901ea89c3f6c95d"}, - {file = "cytoolz-1.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d00ac423542af944302e034e618fb055a0c4e87ba704cd6a79eacfa6ac83a3c9"}, - {file = "cytoolz-1.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a5ca923d1fa632f7a4fb33c0766c6fba7f87141a055c305c3e47e256fb99c413"}, - {file = "cytoolz-1.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:058bf996bcae9aad3acaeeb937d42e0c77c081081e67e24e9578a6a353cb7fb2"}, - {file = "cytoolz-1.0.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:69e2a1f41a3dad94a17aef4a5cc003323359b9f0a9d63d4cc867cb5690a2551d"}, - {file = "cytoolz-1.0.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67daeeeadb012ec2b59d63cb29c4f2a2023b0c4957c3342d354b8bb44b209e9a"}, - {file = "cytoolz-1.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:54d3d36bbf0d4344d1afa22c58725d1668e30ff9de3a8f56b03db1a6da0acb11"}, - {file = "cytoolz-1.0.1.tar.gz", hash = "sha256:89cc3161b89e1bb3ed7636f74ed2e55984fd35516904fc878cae216e42b2c7d6"}, + {file = "cytoolz-1.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:72d7043a88ea5e61ba9d17ea0d1c1eff10f645d7edfcc4e56a31ef78be287644"}, + {file = "cytoolz-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d759e9ed421bacfeb456d47af8d734c057b9912b5f2441f95b27ca35e5efab07"}, + {file = "cytoolz-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fdb5be8fbcc0396141189022724155a4c1c93712ac4aef8c03829af0c2a816d7"}, + {file = "cytoolz-1.1.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c8c0a513dc89bc05cc72893609118815bced5ef201f1a317b4cc3423b3a0e750"}, + {file = "cytoolz-1.1.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce94db4f8ebe842c30c0ece42ff5de977c47859088c2c363dede5a68f6906484"}, + {file = "cytoolz-1.1.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b622d4f54e370c853ded94a668f94fe72c6d70e06ac102f17a2746661c27ab52"}, + {file = "cytoolz-1.1.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:375a65baa5a5b4ff6a0c5ff17e170cf23312e4c710755771ca966144c24216b5"}, + {file = "cytoolz-1.1.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c0d51bcdb3203a062a78f66bbe33db5e3123048e24a5f0e1402422d79df8ee2d"}, + {file = "cytoolz-1.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1010869529bb05dc9802b6d776a34ca1b6d48b9deec70ad5e2918ae175be5c2f"}, + {file = "cytoolz-1.1.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:11a8f2e83295bdb33f35454d6bafcb7845b03b5881dcaed66ecbd726c7f16772"}, + {file = "cytoolz-1.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0499c5e0a8e688ed367a2e51cc13792ae8f08226c15f7d168589fc44b9b9cada"}, + {file = "cytoolz-1.1.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:87d44e6033d4c5e95a7d39ba59b8e105ba1c29b1ccd1d215f26477cc1d64be39"}, + {file = "cytoolz-1.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a68cef396a7de237f7b97422a6a450dfb111722296ba217ba5b34551832f1f6e"}, + {file = "cytoolz-1.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:06ad4c95b258141f138a93ebfdc1d76ac087afc1a82f1401100a1f44b44ba656"}, + {file = "cytoolz-1.1.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:ada59a4b3c59d4ac7162e0ed08667ffa78abf48e975c8a9f9d5b9bc50720f4fd"}, + {file = "cytoolz-1.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:a8957bcaea1ba01327a9b219d2adb84144377684f51444253890dab500ca171f"}, + {file = "cytoolz-1.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6d8cdc299d67eb0f3b9ecdafeeb55eb3b7b7470e2d950ac34b05ed4c7a5572b8"}, + {file = "cytoolz-1.1.0-cp310-cp310-win32.whl", hash = "sha256:d8e08464c5cdea4f6df31e84b11ed6bfd79cedb99fbcbfdc15eb9361a6053c5a"}, + {file = "cytoolz-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:7e49922a7ed54262d41960bf3b835a7700327bf79cff1e9bfc73d79021132ff8"}, + {file = "cytoolz-1.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:943a662d2e72ffc4438d43ab5a1de8d852237775a423236594a3b3e381b8032c"}, + {file = "cytoolz-1.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:dba8e5a8c6e3c789d27b0eb5e7ce5ed7d032a7a9aae17ca4ba5147b871f6e327"}, + {file = "cytoolz-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:44b31c05addb0889167a720123b3b497b28dd86f8a0aeaf3ae4ffa11e2c85d55"}, + {file = "cytoolz-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:653cb18c4fc5d8a8cfce2bce650aabcbe82957cd0536827367d10810566d5294"}, + {file = "cytoolz-1.1.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:853a5b4806915020c890e1ce70cc056bbc1dd8bc44f2d74d555cccfd7aefba7d"}, + {file = "cytoolz-1.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7b44e9de86bea013fe84fd8c399d6016bbb96c37c5290769e5c99460b9c53e5"}, + {file = "cytoolz-1.1.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:098d628a801dc142e9740126be5624eb7aef1d732bc7a5719f60a2095547b485"}, + {file = "cytoolz-1.1.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:779ee4096ed7a82cffab89372ffc339631c285079dbf33dbe7aff1f6174985df"}, + {file = "cytoolz-1.1.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f2ce18dd99533d077e9712f9faa852f389f560351b1efd2f2bdb193a95eddde2"}, + {file = "cytoolz-1.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ac266a34437812cf841cecbfe19f355ab9c3dd1ef231afc60415d40ff12a76e4"}, + {file = "cytoolz-1.1.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1920b9b9c13d60d0bb6cd14594b3bce0870022eccb430618c37156da5f2b7a55"}, + {file = "cytoolz-1.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47caa376dafd2bdc29f8a250acf59c810ec9105cd6f7680b9a9d070aae8490ec"}, + {file = "cytoolz-1.1.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:5ab2c97d8aaa522b038cca9187b1153347af22309e7c998b14750c6fdec7b1cb"}, + {file = "cytoolz-1.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4bce006121b120e8b359244ee140bb0b1093908efc8b739db8dbaa3f8fb42139"}, + {file = "cytoolz-1.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7fc0f1e4e9bb384d26e73c6657bbc26abdae4ff66a95933c00f3d578be89181b"}, + {file = "cytoolz-1.1.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:dd3f894ff972da1994d06ac6157d74e40dda19eb31fe5e9b7863ca4278c3a167"}, + {file = "cytoolz-1.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0846f49cf8a4496bd42659040e68bd0484ce6af819709cae234938e039203ba0"}, + {file = "cytoolz-1.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:16a3af394ade1973226d64bb2f9eb3336adbdea03ed5b134c1bbec5a3b20028e"}, + {file = "cytoolz-1.1.0-cp311-cp311-win32.whl", hash = "sha256:b786c9c8aeab76cc2f76011e986f7321a23a56d985b77d14f155d5e5514ea781"}, + {file = "cytoolz-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:ebf06d1c5344fb22fee71bf664234733e55db72d74988f2ecb7294b05e4db30c"}, + {file = "cytoolz-1.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:b63f5f025fac893393b186e132e3e242de8ee7265d0cd3f5bdd4dda93f6616c9"}, + {file = "cytoolz-1.1.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:99f8e134c9be11649342853ec8c90837af4089fc8ff1e8f9a024a57d1fa08514"}, + {file = "cytoolz-1.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0a6f44cf9319c30feb9a50aa513d777ef51efec16f31c404409e7deb8063df64"}, + {file = "cytoolz-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:945580dc158c557172fca899a35a99a16fbcebf6db0c77cb6621084bc82189f9"}, + {file = "cytoolz-1.1.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:257905ec050d04f2f856854620d1e25556fd735064cebd81b460f54939b9f9d5"}, + {file = "cytoolz-1.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:82779049f352fb3ab5e8c993ab45edbb6e02efb1f17f0b50f4972c706cc51d76"}, + {file = "cytoolz-1.1.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7d3e405e435320e08c5a1633afaf285a392e2d9cef35c925d91e2a31dfd7a688"}, + {file = "cytoolz-1.1.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:923df8f5591e0d20543060c29909c149ab1963a7267037b39eee03a83dbc50a8"}, + {file = "cytoolz-1.1.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:25db9e4862f22ea0ae2e56c8bec9fc9fd756b655ae13e8c7b5625d7ed1c582d4"}, + {file = "cytoolz-1.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c7a98deb11ccd8e5d9f9441ef2ff3352aab52226a2b7d04756caaa53cd612363"}, + {file = "cytoolz-1.1.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dce4ee9fc99104bc77efdea80f32ca5a650cd653bcc8a1d984a931153d3d9b58"}, + {file = "cytoolz-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:80d6da158f7d20c15819701bbda1c041f0944ede2f564f5c739b1bc80a9ffb8b"}, + {file = "cytoolz-1.1.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:3b5c5a192abda123ad45ef716ec9082b4cf7d95e9ada8291c5c2cc5558be858b"}, + {file = "cytoolz-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5b399ce7d967b1cb6280250818b786be652aa8ddffd3c0bb5c48c6220d945ab5"}, + {file = "cytoolz-1.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e7e29a1a03f00b4322196cfe8e2c38da9a6c8d573566052c586df83aacc5663c"}, + {file = "cytoolz-1.1.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:5291b117d71652a817ec164e7011f18e6a51f8a352cc9a70ed5b976c51102fda"}, + {file = "cytoolz-1.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:8caef62f846a9011676c51bda9189ae394cdd6bb17f2946ecaedc23243268320"}, + {file = "cytoolz-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:de425c5a8e3be7bb3a195e19191d28d9eb3c2038046064a92edc4505033ec9cb"}, + {file = "cytoolz-1.1.0-cp312-cp312-win32.whl", hash = "sha256:296440a870e8d1f2e1d1edf98f60f1532b9d3ab8dfbd4b25ec08cd76311e79e5"}, + {file = "cytoolz-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:07156987f224c6dac59aa18fb8bf91e1412f5463961862716a3381bf429c8699"}, + {file = "cytoolz-1.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:23e616b38f5b3160c7bb45b0f84a8f3deb4bd26b29fb2dfc716f241c738e27b8"}, + {file = "cytoolz-1.1.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:76c9b58555300be6dde87a41faf1f97966d79b9a678b7a526fcff75d28ef4945"}, + {file = "cytoolz-1.1.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:d1d638b10d3144795655e9395566ce35807df09219fd7cacd9e6acbdef67946a"}, + {file = "cytoolz-1.1.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:26801c1a165e84786a99e03c9c9973356caaca002d66727b761fb1042878ef06"}, + {file = "cytoolz-1.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2a9a464542912d3272f6dccc5142df057c71c6a5cbd30439389a732df401afb7"}, + {file = "cytoolz-1.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ed6104fa942aa5784bf54f339563de637557e3443b105760bc4de8f16a7fc79b"}, + {file = "cytoolz-1.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56161f0ab60dc4159ec343509abaf809dc88e85c7e420e354442c62e3e7cbb77"}, + {file = "cytoolz-1.1.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:832bd36cc9123535f1945acf6921f8a2a15acc19cfe4065b1c9b985a28671886"}, + {file = "cytoolz-1.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1842636b6e034f229bf084c2bcdcfd36c8437e752eefd2c74ce9e2f10415cb6e"}, + {file = "cytoolz-1.1.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:823df012ab90d2f2a0f92fea453528539bf71ac1879e518524cd0c86aa6df7b9"}, + {file = "cytoolz-1.1.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2f1fcf9e7e7b3487883ff3f815abc35b89dcc45c4cf81c72b7ee457aa72d197b"}, + {file = "cytoolz-1.1.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4cdb3fa1772116827f263f25b0cdd44c663b6701346a56411960534a06c082de"}, + {file = "cytoolz-1.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d1b5c95041741b81430454db65183e133976f45ac3c03454cfa8147952568529"}, + {file = "cytoolz-1.1.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b2079fd9f1a65f4c61e6278c8a6d4f85edf30c606df8d5b32f1add88cbbe2286"}, + {file = "cytoolz-1.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a92a320d72bef1c7e2d4c6d875125cf57fc38be45feb3fac1bfa64ea401f54a4"}, + {file = "cytoolz-1.1.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:06d1c79aa51e6a92a90b0e456ebce2288f03dd6a76c7f582bfaa3eda7692e8a5"}, + {file = "cytoolz-1.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e1d7be25f6971e986a52b6d3a0da28e1941850985417c35528f6823aef2cfec5"}, + {file = "cytoolz-1.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:964b248edc31efc50a65e9eaa0c845718503823439d2fa5f8d2c7e974c2b5409"}, + {file = "cytoolz-1.1.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c9ff2b3c57c79b65cb5be14a18c6fd4a06d5036fb3f33e973a9f70e9ac13ca28"}, + {file = "cytoolz-1.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:22290b73086af600042d99f5ce52a43d4ad9872c382610413176e19fc1d4fd2d"}, + {file = "cytoolz-1.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a2ade74fccd080ea793382968913ee38d7a35c921df435bbf0a6aeecf0d17574"}, + {file = "cytoolz-1.1.0-cp313-cp313-win32.whl", hash = "sha256:db5dbcfda1c00e937426cbf9bdc63c24ebbc358c3263bfcbc1ab4a88dc52aa8e"}, + {file = "cytoolz-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:9e2d3fe3b45c3eb7233746f7aca37789be3dceec3e07dcc406d3e045ea0f7bdc"}, + {file = "cytoolz-1.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:32c559f95ff44a9ebcbd934acaa1e6dc8f3e6ffce4762a79a88528064873d6d5"}, + {file = "cytoolz-1.1.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:9e2cd93b28f667c5870a070ab2b8bb4397470a85c4b204f2454b0ad001cd1ca3"}, + {file = "cytoolz-1.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:f494124e141a9361f31d79875fe7ea459a3be2b9dadd90480427c0c52a0943d4"}, + {file = "cytoolz-1.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:53a3262bf221f19437ed544bf8c0e1980c81ac8e2a53d87a9bc075dba943d36f"}, + {file = "cytoolz-1.1.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:47663e57d3f3f124921f38055e86a1022d0844c444ede2e8f090d3bbf80deb65"}, + {file = "cytoolz-1.1.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a5a8755c4104ee4e3d5ba434c543b5f85fdee6a1f1df33d93f518294da793a60"}, + {file = "cytoolz-1.1.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4d96ff3d381423af1b105295f97de86d1db51732c9566eb37378bab6670c5010"}, + {file = "cytoolz-1.1.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0ec96b3d537cdf47d4e76ded199f7440715f4c71029b45445cff92c1248808c2"}, + {file = "cytoolz-1.1.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:208e2f2ef90a32b0acbff3303d90d89b13570a228d491d2e622a7883a3c68148"}, + {file = "cytoolz-1.1.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0d416a81bb0bd517558668e49d30a7475b5445f9bbafaab7dcf066f1e9adba36"}, + {file = "cytoolz-1.1.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f32e94c91ffe49af04835ee713ebd8e005c85ebe83e7e1fdcc00f27164c2d636"}, + {file = "cytoolz-1.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:15d0c6405efc040499c46df44056a5c382f551a7624a41cf3e4c84a96b988a15"}, + {file = "cytoolz-1.1.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:bf069c5381d757debae891401b88b3a346ba3a28ca45ba9251103b282463fad8"}, + {file = "cytoolz-1.1.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7d5cf15892e63411ec1bd67deff0e84317d974e6ab2cdfefdd4a7cea2989df66"}, + {file = "cytoolz-1.1.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:3e3872c21170f8341656f8692f8939e8800dcee6549ad2474d4c817bdefd62cd"}, + {file = "cytoolz-1.1.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:b9ddeff8e8fd65eb1fcefa61018100b2b627e759ea6ad275d2e2a93ffac147bf"}, + {file = "cytoolz-1.1.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:02feeeda93e1fa3b33414eb57c2b0aefd1db8f558dd33fdfcce664a0f86056e4"}, + {file = "cytoolz-1.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d08154ad45349162b6c37f12d5d1b2e6eef338e657b85e1621e4e6a4a69d64cb"}, + {file = "cytoolz-1.1.0-cp313-cp313t-win32.whl", hash = "sha256:10ae4718a056948d73ca3e1bb9ab1f95f897ec1e362f829b9d37cc29ab566c60"}, + {file = "cytoolz-1.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:1bb77bc6197e5cb19784b6a42bb0f8427e81737a630d9d7dda62ed31733f9e6c"}, + {file = "cytoolz-1.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:563dda652c6ff52d215704fbe6b491879b78d7bbbb3a9524ec8e763483cb459f"}, + {file = "cytoolz-1.1.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:d542cee7c7882d2a914a33dec4d3600416fb336734df979473249d4c53d207a1"}, + {file = "cytoolz-1.1.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:31922849b701b0f24bb62e56eb2488dcd3aa6ae3057694bd6b3b7c4c2bc27c2f"}, + {file = "cytoolz-1.1.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:e68308d32afd31943314735c1335e4ab5696110e96b405f6bdb8f2a8dc771a16"}, + {file = "cytoolz-1.1.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fc4bb48b3b866e1867f7c6411a4229e5b44be3989060663713e10efc24c9bd5f"}, + {file = "cytoolz-1.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:456f77207d1445025d7ef262b8370a05492dcb1490cb428b0f3bf1bd744a89b0"}, + {file = "cytoolz-1.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:174ebc71ebb20a9baeffce6ee07ee2cd913754325c93f99d767380d8317930f7"}, + {file = "cytoolz-1.1.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8b3604fef602bcd53415055a4f68468339192fd17be39e687ae24f476d23d56e"}, + {file = "cytoolz-1.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3604b959a01f64c366e7d10ec7634d5f5cfe10301e27a8f090f6eb3b2a628a18"}, + {file = "cytoolz-1.1.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6db2127a3c1bc2f59f08010d2ae53a760771a9de2f67423ad8d400e9ba4276e8"}, + {file = "cytoolz-1.1.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56584745ac647993a016a21bc76399113b7595e312f8d0a1b140c9fcf9b58a27"}, + {file = "cytoolz-1.1.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:db2c4c3a7f7bd7e03bb1a236a125c8feb86c75802f4ecda6ecfaf946610b2930"}, + {file = "cytoolz-1.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:48cb8a692111a285d2b9acd16d185428176bfbffa8a7c274308525fccd01dd42"}, + {file = "cytoolz-1.1.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d2f344ba5eb17dcf38ee37fdde726f69053f54927db8f8a1bed6ac61e5b1890d"}, + {file = "cytoolz-1.1.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:abf76b1c1abd031f098f293b6d90ee08bdaa45f8b5678430e331d991b82684b1"}, + {file = "cytoolz-1.1.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:ddf9a38a5b686091265ff45b53d142e44a538cd6c2e70610d3bc6be094219032"}, + {file = "cytoolz-1.1.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:946786755274f07bb2be0400f28adb31d7d85a7c7001873c0a8e24a503428fb3"}, + {file = "cytoolz-1.1.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:d5b8f78b9fed79cf185ad4ddec099abeef45951bdcb416c5835ba05f0a1242c7"}, + {file = "cytoolz-1.1.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:fccde6efefdbc02e676ccb352a2ccc8a8e929f59a1c6d3d60bb78e923a49ca44"}, + {file = "cytoolz-1.1.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:717b7775313da5f51b0fbf50d865aa9c39cb241bd4cb605df3cf2246d6567397"}, + {file = "cytoolz-1.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5158744a09d0e0e4a4f82225e3a3c4ebf38f9ae74467aaa905467270e52f2794"}, + {file = "cytoolz-1.1.0-cp314-cp314-win32.whl", hash = "sha256:1ed534bdbbf063b2bb28fca7d0f6723a3e5a72b086e7c7fe6d74ae8c3e4d00e2"}, + {file = "cytoolz-1.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:472c1c9a085f5ad973ec0ad7f0b9ba0969faea6f96c9e397f6293d386f3a25ec"}, + {file = "cytoolz-1.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:a7ad7ca3386fa86bd301be3fa36e7f0acb024f412f665937955acfc8eb42deff"}, + {file = "cytoolz-1.1.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:64b63ed4b71b1ba813300ad0f06b8aff19a12cf51116e0e4f1ed837cea4debcf"}, + {file = "cytoolz-1.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:a60ba6f2ed9eb0003a737e1ee1e9fa2258e749da6477946008d4324efa25149f"}, + {file = "cytoolz-1.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1aa58e2434d732241f7f051e6f17657e969a89971025e24578b5cbc6f1346485"}, + {file = "cytoolz-1.1.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6965af3fc7214645970e312deb9bd35a213a1eaabcfef4f39115e60bf2f76867"}, + {file = "cytoolz-1.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ddd2863f321d67527d3b67a93000a378ad6f967056f68c06467fe011278a6d0e"}, + {file = "cytoolz-1.1.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4e6b428e9eb5126053c2ae0efa62512ff4b38ed3951f4d0888ca7005d63e56f5"}, + {file = "cytoolz-1.1.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d758e5ef311d2671e0ae8c214c52e44617cf1e58bef8f022b547b9802a5a7f30"}, + {file = "cytoolz-1.1.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a95416eca473e6c1179b48d86adcf528b59c63ce78f4cb9934f2e413afa9b56b"}, + {file = "cytoolz-1.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:36c8ede93525cf11e2cc787b7156e5cecd7340193ef800b816a16f1404a8dc6d"}, + {file = "cytoolz-1.1.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c949755b6d8a649c5fbc888bc30915926f1b09fe42fea9f289e297c2f6ddd3"}, + {file = "cytoolz-1.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e1b6d37545816905a76d9ed59fa4e332f929e879f062a39ea0f6f620405cdc27"}, + {file = "cytoolz-1.1.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:05332112d4087904842b36954cd1d3fc0e463a2f4a7ef9477bd241427c593c3b"}, + {file = "cytoolz-1.1.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:31538ca2fad2d688cbd962ccc3f1da847329e2258a52940f10a2ac0719e526be"}, + {file = "cytoolz-1.1.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:747562aa70abf219ea16f07d50ac0157db856d447f7f498f592e097cbc77df0b"}, + {file = "cytoolz-1.1.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:3dc15c48b20c0f467e15e341e102896c8422dccf8efc6322def5c1b02f074629"}, + {file = "cytoolz-1.1.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:3c03137ee6103ba92d5d6ad6a510e86fded69cd67050bd8a1843f15283be17ac"}, + {file = "cytoolz-1.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:be8e298d88f88bd172b59912240558be3b7a04959375646e7fd4996401452941"}, + {file = "cytoolz-1.1.0-cp314-cp314t-win32.whl", hash = "sha256:3d407140f5604a89578285d4aac7b18b8eafa055cf776e781aabb89c48738fad"}, + {file = "cytoolz-1.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:56e5afb69eb6e1b3ffc34716ee5f92ffbdb5cb003b3a5ca4d4b0fe700e217162"}, + {file = "cytoolz-1.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:27b19b4a286b3ff52040efa42dbe403730aebe5fdfd2def704eb285e2125c63e"}, + {file = "cytoolz-1.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:08a63935c66488511b7b29b06233be0be5f4123622fc8fd488f28dc1b7e4c164"}, + {file = "cytoolz-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:93bd0afcc4cc05794507084afaefb161c3639f283ee629bd0e8654b5c0327ba8"}, + {file = "cytoolz-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8f3d4da470cfd5cf44f6d682c6eb01363066e0af53ebe111225e44a618f9453d"}, + {file = "cytoolz-1.1.0-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ba6c12d0e6a67399f4102b4980f4f1bebdbf226ed0a68e84617709d4009b4e71"}, + {file = "cytoolz-1.1.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b557071405b4aeeaa7cbec1a95d15d6c8f37622fe3f4b595311e0e226ce772c"}, + {file = "cytoolz-1.1.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:cdb406001474726a47fbe903f3aba0de86f5c0b9c9861f55c09c366368225ae0"}, + {file = "cytoolz-1.1.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b6072876ba56446d9ac29d349983677d6f44c6d1c6c1c6be44e66e377c57c767"}, + {file = "cytoolz-1.1.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8c3784c965c9a6822d315d099c3a85b0884ac648952815891c667b469116f1d0"}, + {file = "cytoolz-1.1.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cc537ad78981df1a827773069fd3b7774f4478db43f518b1616efaf87d7d8f9"}, + {file = "cytoolz-1.1.0-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:574ee9dfdc632db8bf9237f27f2a687d1a0b90d29d5e96cab2b21fd2b419c17d"}, + {file = "cytoolz-1.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6594efbaea72dc58b368b53e745ad902c8d8cc41286f00b3743ceac464d5ef3f"}, + {file = "cytoolz-1.1.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:7c849f9ddaf3c7faba938440f9c849235a2908b303063d49da3092a93acd695b"}, + {file = "cytoolz-1.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1fef0296fb3577d0a08ad9b70344ee418f728f1ec21a768ffe774437d67ac859"}, + {file = "cytoolz-1.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:1dce1e66fdf72cc474367bd7a7f2b90ec67bb8197dc3fe8ecd08f4ce3ab950a1"}, + {file = "cytoolz-1.1.0-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:202fe9975efaec0085cab14a6a6050418bc041f5316f2cf098c0cd2aced4c50e"}, + {file = "cytoolz-1.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:528349434601b9d55e65c6a495494de0001c9a06b431547fea4c60b5edc7d5b3"}, + {file = "cytoolz-1.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3e248cdbf2a54bafdadf4486ddd32e8352f816d3caa2014e44de99f8c525d4a8"}, + {file = "cytoolz-1.1.0-cp39-cp39-win32.whl", hash = "sha256:e63f2b70f4654648a5c6a176ae80897c0de6401f385540dce8e365019e800cfe"}, + {file = "cytoolz-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:f731c53ed29959f105ae622b62e39603c207ed8e8cb2a40cd4accb63d9f92901"}, + {file = "cytoolz-1.1.0-cp39-cp39-win_arm64.whl", hash = "sha256:5a2120bf9e6e8f25e1b32748424a5571e319ef03a995a8fde663fd2feec1a696"}, + {file = "cytoolz-1.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f32e93a55681d782fc6af939f6df36509d65122423cbc930be39b141064adff8"}, + {file = "cytoolz-1.1.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:5d9bc596751cbda8073e65be02ca11706f00029768fbbbc81e11a8c290bb41aa"}, + {file = "cytoolz-1.1.0-pp311-pypy311_pp73-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9b16660d01c3931951fab49db422c627897c38c1a1f0393a97582004019a4887"}, + {file = "cytoolz-1.1.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b7de5718e2113d4efccea3f06055758cdbc17388ecc3341ba4d1d812837d7c1a"}, + {file = "cytoolz-1.1.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a12a2a1a6bc44099491c05a12039efa08cc33a3d0f8c7b0566185e085e139283"}, + {file = "cytoolz-1.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:047defa7f5f9a32f82373dbc3957289562e8a3fa58ae02ec8e4dca4f43a33a21"}, + {file = "cytoolz-1.1.0.tar.gz", hash = "sha256:13a7bf254c3c0d28b12e2290b82aed0f0977a4c2a2bf84854fcdc7796a29f3b0"}, ] [package.dependencies] toolz = ">=0.8.0" [package.extras] -cython = ["cython"] +cython = ["cython (>=0.29)"] +test = ["pytest"] [[package]] name = "datumaro" @@ -1065,46 +1181,57 @@ files = [ {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, ] +[[package]] +name = "detect-installer" +version = "0.1.0" +description = "Detect how a Python package was installed and get the correct upgrade command" +optional = false +python-versions = ">=3.10" +files = [ + {file = "detect_installer-0.1.0-py3-none-any.whl", hash = "sha256:034fb20fd665c36e6ba52b8821525ea07fb4f7f938cac459df889fb33801528a"}, + {file = "detect_installer-0.1.0.tar.gz", hash = "sha256:00ad7ba0a36e3cf7d08a40d3643011746dbc112597c7d475cc91c416710ca4e7"}, +] + [[package]] name = "distlib" -version = "0.4.0" +version = "0.4.3" description = "Distribution utilities" optional = false python-versions = "*" files = [ - {file = "distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16"}, - {file = "distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d"}, + {file = "distlib-0.4.3-py2.py3-none-any.whl", hash = "sha256:4b0ce306c966eb73bc3a7b6abad017c556dadd92c44701562cd528ac7fde4d5b"}, + {file = "distlib-0.4.3.tar.gz", hash = "sha256:f152097224a0ae24be5a0f6bae1b9359af82133bce63f98a95f86cae1aede9ed"}, ] [[package]] name = "dnspython" -version = "2.7.0" +version = "2.8.0" description = "DNS toolkit" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" files = [ - {file = "dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86"}, - {file = "dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1"}, + {file = "dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af"}, + {file = "dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f"}, ] [package.extras] -dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "hypercorn (>=0.16.0)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "quart-trio (>=0.11.0)", "sphinx (>=7.2.0)", "sphinx-rtd-theme (>=2.0.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"] -dnssec = ["cryptography (>=43)"] -doh = ["h2 (>=4.1.0)", "httpcore (>=1.0.0)", "httpx (>=0.26.0)"] -doq = ["aioquic (>=1.0.0)"] -idna = ["idna (>=3.7)"] -trio = ["trio (>=0.23)"] +dev = ["black (>=25.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "hypercorn (>=0.17.0)", "mypy (>=1.17)", "pylint (>=3)", "pytest (>=8.4)", "pytest-cov (>=6.2.0)", "quart-trio (>=0.12.0)", "sphinx (>=8.2.0)", "sphinx-rtd-theme (>=3.0.0)", "twine (>=6.1.0)", "wheel (>=0.45.0)"] +dnssec = ["cryptography (>=45)"] +doh = ["h2 (>=4.2.0)", "httpcore (>=1.0.0)", "httpx (>=0.28.0)"] +doq = ["aioquic (>=1.2.0)"] +idna = ["idna (>=3.10)"] +trio = ["trio (>=0.30)"] wmi = ["wmi (>=1.5.1)"] [[package]] name = "email-validator" -version = "2.2.0" +version = "2.3.0" description = "A robust email address syntax and deliverability validation library." optional = false python-versions = ">=3.8" files = [ - {file = "email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631"}, - {file = "email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7"}, + {file = "email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4"}, + {file = "email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426"}, ] [package.dependencies] @@ -1135,13 +1262,13 @@ tools = ["hypothesis (>=6.22.0,<6.108.7)"] [[package]] name = "eth-account" -version = "0.13.5" +version = "0.13.7" description = "eth-account: Sign Ethereum transactions and messages with local private keys" optional = false python-versions = "<4,>=3.8" files = [ - {file = "eth_account-0.13.5-py3-none-any.whl", hash = "sha256:e43fd30c9a7fabb882b50e8c4c41d4486d2f3478ad97c66bb18cfcc872fdbec8"}, - {file = "eth_account-0.13.5.tar.gz", hash = "sha256:010c9ce5f3d2688106cf9bfeb711bb8eaf0154ea6f85325f54fecea85c2b3759"}, + {file = "eth_account-0.13.7-py3-none-any.whl", hash = "sha256:39727de8c94d004ff61d10da7587509c04d2dc7eac71e04830135300bdfc6d24"}, + {file = "eth_account-0.13.7.tar.gz", hash = "sha256:5853ecbcbb22e65411176f121f5f24b8afeeaf13492359d254b16d8b18c77a46"}, ] [package.dependencies] @@ -1163,20 +1290,20 @@ test = ["coverage", "hypothesis (>=6.22.0,<6.108.7)", "pytest (>=7.0.0)", "pytes [[package]] name = "eth-hash" -version = "0.7.1" +version = "0.8.0" description = "eth-hash: The Ethereum hashing function, keccak256, sometimes (erroneously) called sha3" optional = false -python-versions = "<4,>=3.8" +python-versions = "<4,>=3.10" files = [ - {file = "eth_hash-0.7.1-py3-none-any.whl", hash = "sha256:0fb1add2adf99ef28883fd6228eb447ef519ea72933535ad1a0b28c6f65f868a"}, - {file = "eth_hash-0.7.1.tar.gz", hash = "sha256:d2411a403a0b0a62e8247b4117932d900ffb4c8c64b15f92620547ca5ce46be5"}, + {file = "eth_hash-0.8.0-py3-none-any.whl", hash = "sha256:523718a51b369ab89866b929a5c93c52978cd866ea309192ad980dd8271f9fac"}, + {file = "eth_hash-0.8.0.tar.gz", hash = "sha256:b009752b620da2e9c7668014849d1f5fadbe4f138603f1871cc5d4ca706896b1"}, ] [package.dependencies] pycryptodome = {version = ">=3.6.6,<4", optional = true, markers = "extra == \"pycryptodome\""} [package.extras] -dev = ["build (>=0.9.0)", "bump_my_version (>=0.19.0)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)", "tox (>=4.0.0)", "twine", "wheel"] +dev = ["build (>=0.9.0)", "bump_my_version (>=0.19.0)", "ipython", "mypy (==1.18.2)", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)", "tox (>=4.0.0)", "twine", "wheel (>=0.38.1)"] docs = ["sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)"] pycryptodome = ["pycryptodome (>=3.6.6,<4)"] pysha3 = ["pysha3 (>=1.0.0,<2.0.0)", "safe-pysha3 (>=1.0.0)"] @@ -1205,13 +1332,13 @@ test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] [[package]] name = "eth-keys" -version = "0.6.1" +version = "0.7.0" description = "eth-keys: Common API for Ethereum key operations" optional = false python-versions = "<4,>=3.8" files = [ - {file = "eth_keys-0.6.1-py3-none-any.whl", hash = "sha256:7deae4cd56e862e099ec58b78176232b931c4ea5ecded2f50c7b1ccbc10c24cf"}, - {file = "eth_keys-0.6.1.tar.gz", hash = "sha256:a43e263cbcabfd62fa769168efc6c27b1f5603040e4de22bb84d12567e4fd962"}, + {file = "eth_keys-0.7.0-py3-none-any.whl", hash = "sha256:b0cdda8ffe8e5ba69c7c5ca33f153828edcace844f67aabd4542d7de38b159cf"}, + {file = "eth_keys-0.7.0.tar.gz", hash = "sha256:79d24fd876201df67741de3e3fefb3f4dbcbb6ace66e47e6fe662851a4547814"}, ] [package.dependencies] @@ -1219,8 +1346,8 @@ eth-typing = ">=3" eth-utils = ">=2" [package.extras] -coincurve = ["coincurve (>=12.0.0)"] -dev = ["asn1tools (>=0.146.2)", "build (>=0.9.0)", "bump_my_version (>=0.19.0)", "coincurve (>=12.0.0)", "eth-hash[pysha3]", "factory-boy (>=3.0.1)", "hypothesis (>=5.10.3)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "pyasn1 (>=0.4.5)", "pytest (>=7.0.0)", "towncrier (>=24,<25)", "tox (>=4.0.0)", "twine", "wheel"] +coincurve = ["coincurve (>=17.0.0)"] +dev = ["asn1tools (>=0.146.2)", "build (>=0.9.0)", "bump_my_version (>=0.19.0)", "coincurve (>=17.0.0)", "eth-hash[pysha3]", "factory-boy (>=3.0.1)", "hypothesis (>=5.10.3)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "pyasn1 (>=0.4.5)", "pytest (>=7.0.0)", "towncrier (>=24,<25)", "tox (>=4.0.0)", "twine", "wheel"] docs = ["towncrier (>=24,<25)"] test = ["asn1tools (>=0.146.2)", "eth-hash[pysha3]", "factory-boy (>=3.0.1)", "hypothesis (>=5.10.3)", "pyasn1 (>=0.4.5)", "pytest (>=7.0.0)"] @@ -1248,729 +1375,1010 @@ test = ["eth-hash[pycryptodome]", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] [[package]] name = "eth-typing" -version = "5.2.0" +version = "6.0.0" description = "eth-typing: Common type annotations for ethereum python packages" optional = false -python-versions = "<4,>=3.8" +python-versions = "<4,>=3.10" files = [ - {file = "eth_typing-5.2.0-py3-none-any.whl", hash = "sha256:e1f424e97990fc3c6a1c05a7b0968caed4e20e9c99a4d5f4db3df418e25ddc80"}, - {file = "eth_typing-5.2.0.tar.gz", hash = "sha256:28685f7e2270ea0d209b75bdef76d8ecef27703e1a16399f6929820d05071c28"}, + {file = "eth_typing-6.0.0-py3-none-any.whl", hash = "sha256:ee74fb641eb36dd885e1c42c2a3055314efa532b3e71480816df70a94d35cfb9"}, + {file = "eth_typing-6.0.0.tar.gz", hash = "sha256:315dd460dc0b71c15a6cd51e3c0b70d237eec8771beb844144f3a1fb4adb2392"}, ] [package.dependencies] typing_extensions = ">=4.5.0" [package.extras] -dev = ["build (>=0.9.0)", "bump_my_version (>=0.19.0)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)", "tox (>=4.0.0)", "twine", "wheel"] +dev = ["build (>=0.9.0)", "bump_my_version (>=0.19.0)", "ipython", "mypy (==1.18.2)", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)", "tox (>=4.0.0)", "twine", "wheel (>=0.38.1)"] docs = ["sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)"] test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] [[package]] name = "eth-utils" -version = "5.2.0" +version = "6.0.0" description = "eth-utils: Common utility functions for python code that interacts with Ethereum" optional = false -python-versions = "<4,>=3.8" +python-versions = "<4,>=3.10" files = [ - {file = "eth_utils-5.2.0-py3-none-any.whl", hash = "sha256:4d43eeb6720e89a042ad5b28d4b2111630ae764f444b85cbafb708d7f076da10"}, - {file = "eth_utils-5.2.0.tar.gz", hash = "sha256:17e474eb654df6e18f20797b22c6caabb77415a996b3ba0f3cc8df3437463134"}, + {file = "eth_utils-6.0.0-py3-none-any.whl", hash = "sha256:63cf48ee32c45541cb5748751909a8345c470432fb6f0fed4bd7c53fd6400469"}, + {file = "eth_utils-6.0.0.tar.gz", hash = "sha256:eb54b2f82dd300d3142c49a89da195e823f5e5284d43203593f87c67bad92a96"}, ] [package.dependencies] cytoolz = {version = ">=0.10.1", markers = "implementation_name == \"cpython\""} eth-hash = ">=0.3.1" eth-typing = ">=5.0.0" +pydantic = ">=2.0.0,<3" toolz = {version = ">0.8.2", markers = "implementation_name == \"pypy\""} [package.extras] -dev = ["build (>=0.9.0)", "bump-my-version (>=0.19.0)", "eth-hash[pycryptodome]", "hypothesis (>=4.43.0)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=24,<25)", "tox (>=4.0.0)", "twine", "wheel"] -docs = ["sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=24,<25)"] -test = ["hypothesis (>=4.43.0)", "mypy (==1.10.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] +dev = ["build (>=0.9.0)", "bump_my_version (>=0.19.0)", "eth-hash[pycryptodome]", "hypothesis (>=4.43.0)", "ipython", "mypy (==1.18.2)", "mypy (==1.18.2)", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)", "tox (>=4.0.0)", "twine", "wheel (>=0.38.1)"] +docs = ["sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)"] +test = ["hypothesis (>=4.43.0)", "mypy (==1.18.2)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] [[package]] name = "exceptiongroup" -version = "1.2.0" +version = "1.3.1" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, - {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, + {file = "exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598"}, + {file = "exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219"}, ] +[package.dependencies] +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} + [package.extras] test = ["pytest (>=6)"] [[package]] name = "fastapi" -version = "0.115.4" +version = "0.136.3" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "fastapi-0.115.4-py3-none-any.whl", hash = "sha256:0b504a063ffb3cf96a5e27dc1bc32c80ca743a2528574f9cdc77daa2d31b4742"}, - {file = "fastapi-0.115.4.tar.gz", hash = "sha256:db653475586b091cb8b2fec2ac54a680ac6a158e07406e1abae31679e8826349"}, + {file = "fastapi-0.136.3-py3-none-any.whl", hash = "sha256:3d2a69bdf04b7e9f3afa292c3bc7a98816bbfafa10bc9b45f3f3700d2f761620"}, + {file = "fastapi-0.136.3.tar.gz", hash = "sha256:e487fae93ad408e6f47641ee4dfe389864fd7bec92e547ea8498fc13f43e83ab"}, ] [package.dependencies] +annotated-doc = ">=0.0.2" email-validator = {version = ">=2.0.0", optional = true, markers = "extra == \"standard\""} -fastapi-cli = {version = ">=0.0.5", extras = ["standard"], optional = true, markers = "extra == \"standard\""} -httpx = {version = ">=0.23.0", optional = true, markers = "extra == \"standard\""} -jinja2 = {version = ">=2.11.2", optional = true, markers = "extra == \"standard\""} -pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" -python-multipart = {version = ">=0.0.7", optional = true, markers = "extra == \"standard\""} -starlette = ">=0.40.0,<0.42.0" +fastapi-cli = {version = ">=0.0.8", extras = ["standard"], optional = true, markers = "extra == \"standard\""} +fastar = {version = ">=0.9.0", optional = true, markers = "extra == \"standard\""} +httpx = {version = ">=0.23.0,<1.0.0", optional = true, markers = "extra == \"standard\""} +jinja2 = {version = ">=3.1.5", optional = true, markers = "extra == \"standard\""} +pydantic = ">=2.9.0" +pydantic-extra-types = {version = ">=2.0.0", optional = true, markers = "extra == \"standard\""} +pydantic-settings = {version = ">=2.0.0", optional = true, markers = "extra == \"standard\""} +python-multipart = {version = ">=0.0.18", optional = true, markers = "extra == \"standard\""} +starlette = ">=0.46.0" typing-extensions = ">=4.8.0" +typing-inspection = ">=0.4.2" uvicorn = {version = ">=0.12.0", extras = ["standard"], optional = true, markers = "extra == \"standard\""} [package.extras] -all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] -standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "jinja2 (>=2.11.2)", "python-multipart (>=0.0.7)", "uvicorn[standard] (>=0.12.0)"] +all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=3.1.5)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "pyyaml (>=5.3.1)", "uvicorn[standard] (>=0.12.0)"] +standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "fastar (>=0.9.0)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"] +standard-no-fastapi-cloud-cli = ["email-validator (>=2.0.0)", "fastapi-cli[standard-no-fastapi-cloud-cli] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"] [[package]] name = "fastapi-cli" -version = "0.0.5" +version = "0.0.32" description = "Run and manage FastAPI apps from the command line with FastAPI CLI. 🚀" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "fastapi_cli-0.0.5-py3-none-any.whl", hash = "sha256:e94d847524648c748a5350673546bbf9bcaeb086b33c24f2e82e021436866a46"}, - {file = "fastapi_cli-0.0.5.tar.gz", hash = "sha256:d30e1239c6f46fcb95e606f02cdda59a1e2fa778a54b64686b3ff27f6211ff9f"}, + {file = "fastapi_cli-0.0.32-py3-none-any.whl", hash = "sha256:8dcc286fa32f01bbd3f65dd09cfd5a2540ed5f2230b77db7fd30978d6165f3c4"}, + {file = "fastapi_cli-0.0.32.tar.gz", hash = "sha256:38024d2345275e1b37ce8848727a580d84901b570e96b3256d9d36a9a5039424"}, ] [package.dependencies] -typer = ">=0.12.3" +fastapi-cloud-cli = {version = ">=0.1.1", optional = true, markers = "extra == \"standard\""} +rich-toolkit = ">=0.14.8" +tomli = {version = ">=2.0.0", markers = "python_version < \"3.11\""} +typer = ">=0.16.0" uvicorn = {version = ">=0.15.0", extras = ["standard"]} +[package.extras] +new = ["fastapi-new (>=0.0.2)"] +standard = ["fastapi-cloud-cli (>=0.1.1)", "uvicorn[standard] (>=0.15.0)"] +standard-no-fastapi-cloud-cli = ["uvicorn[standard] (>=0.15.0)"] + +[[package]] +name = "fastapi-cloud-cli" +version = "0.22.2" +description = "Deploy and manage FastAPI Cloud apps from the command line 🚀" +optional = false +python-versions = ">=3.10" +files = [ + {file = "fastapi_cloud_cli-0.22.2-py3-none-any.whl", hash = "sha256:37c6b05adb94a4c9f59916a559d041c565db36b5f3dddeed420bf0a51182c363"}, + {file = "fastapi_cloud_cli-0.22.2.tar.gz", hash = "sha256:7ec78c1fed58f578af5eb1fb54ec4b456eba4dc1eaca1c3a93cf499a7cbc7ab3"}, +] + +[package.dependencies] +detect-installer = ">=0.1.0" +fastar = ">=0.10.0" +httpx = ">=0.27.0" +pydantic = {version = ">=2.7.4", extras = ["email"], markers = "python_version < \"3.13\""} +rich-toolkit = ">=0.20.3" +rignore = ">=0.5.1" +sentry-sdk = ">=2.20.0" +typer = ">=0.16.0" +uvicorn = {version = ">=0.17.6", extras = ["standard"]} + [package.extras] standard = ["uvicorn[standard] (>=0.15.0)"] [[package]] -name = "filelock" -version = "3.13.1" -description = "A platform independent file lock." +name = "fastar" +version = "0.11.0" +description = "High-level bindings for the Rust tar crate" optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, - {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, + {file = "fastar-0.11.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:e7c906ad371ca365591ebcb7630009923f3eceb20956814494d15591a78e9e46"}, + {file = "fastar-0.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6919497b35fa5bd978d2c26ee117cf1771b90ee5073f7518e44b9bc364b57715"}, + {file = "fastar-0.11.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:56b50206aeedd99e22b83289e6fb3ff8f7d7da4407d2419902e4716b4f90585a"}, + {file = "fastar-0.11.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a1811a69ae81d469720df0c8af3f84f834a93b5e4f8be0e0e8bde6a52fa11f2"}, + {file = "fastar-0.11.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:10486238c55589a3947c38f9cfb88a67d8a608eb8dddc722038237d0278a41d7"}, + {file = "fastar-0.11.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1555ef9992d368a6ec39092276990cef8d329c39a1d86ebd847eaa3b10efd472"}, + {file = "fastar-0.11.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b1f4aca0a9620b76988bbf6225cdea6678a392902444ca18bb8a51495b165a89"}, + {file = "fastar-0.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75beeecac7d11a666a6c4a0b7f7e80842ae5cf523f2f890b99c78fc82b403545"}, + {file = "fastar-0.11.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:a08cdf5d16daa401c65c9c7493a18db7dc515c52155a17071ec7098bb07da9d3"}, + {file = "fastar-0.11.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6e210375e5a7ba53586cbd6017aa417d2d2ceacbe8671682470281bd0a15e8ef"}, + {file = "fastar-0.11.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a2988eb2604b8e15670f355425e8c800e4dcd4edfbcbfe194397f8f17b7eb19e"}, + {file = "fastar-0.11.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:34abc857b46068fdf91d157bd0203bfd6791dc7a432d1ed180f5af6c2f5bcce9"}, + {file = "fastar-0.11.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0d884be84e37a01053776395441fc960031974e0265801ce574efc3d05e0cdaf"}, + {file = "fastar-0.11.0-cp310-cp310-win32.whl", hash = "sha256:c721c1ad758e3e4c2c1fd9e96911a0fa58c0a6be5668f1bcfd0b741e72c7cb63"}, + {file = "fastar-0.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:ba4180b7c3080f55f9035fdd7d8c39fe0e1485087a68ff615bb4784a10b8106b"}, + {file = "fastar-0.11.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b82fd6f996e65a86f67a6bd64dd22ef3e8ae2dcaed0ae3b550e71f7e1bbb1df5"}, + {file = "fastar-0.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27eed386fd0558e6daa29211111bbd7b740f7c7e881197f8a00ac7c0f3cdb1d7"}, + {file = "fastar-0.11.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a6931bebc1d8e95ddeef55732c195449e6b44ef33aa31b325505097ed3b4d6aa"}, + {file = "fastar-0.11.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:891f72ce42a5e28a74fbd4d5fbf1a3ac1a1163d13cbc200cbd005fb0fabc54bd"}, + {file = "fastar-0.11.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5b83c1f61f7017d6e1498568038f8745440cfc16ca2f697ec81bac83050108f6"}, + {file = "fastar-0.11.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db73a9b765a516e73983b25341e7b5e0189733878279e278b2295131b0e3a21e"}, + {file = "fastar-0.11.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:625827d52eb4e8fec942e0233f125ff8010fcf6a67c0a974a8e5f4666b771e3c"}, + {file = "fastar-0.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7f5fd8fa21ec0a88296a38dc5d7fc35efd3b26d46a17b8b7c73c5563925ca15"}, + {file = "fastar-0.11.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:8c15af91b8cd87ddf23ea55355ae513c1de3ab67178f26dad017c9e9c0af6096"}, + {file = "fastar-0.11.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:03a112395a8b0bff251423bd1564c012f0cc058ad8b6bd8fba96f3d7fc117e44"}, + {file = "fastar-0.11.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f2994bb8f5f8c11eb12beae1e6e77a907173c9819236b8a4c8f0573652ceccce"}, + {file = "fastar-0.11.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:dcf99e4b5973d842c7f19c776c3a83cdc0977d505edce6206438505c0456b517"}, + {file = "fastar-0.11.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:29c9c386dc0d5dda78845a8e6b1480d26ab861c1e0b68f42ae5735cb70ca07f1"}, + {file = "fastar-0.11.0-cp311-cp311-win32.whl", hash = "sha256:030b2580fc394f2c9b7890b6735810404e9b9ed5e0344db150b945965b5482b7"}, + {file = "fastar-0.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:83ab57ae067969cd0b483ac3b6dccc4b595fc77f5c820760998648d4c42822b5"}, + {file = "fastar-0.11.0-cp311-cp311-win_arm64.whl", hash = "sha256:27b1a4cee2298b704de8151d310462ee7335ed036011ca9aa6e784b30b6c73a9"}, + {file = "fastar-0.11.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3c51f1c2cdddbd1420d2897ace7738e36c65e17f6ae84e0bfe763f8d1068bb97"}, + {file = "fastar-0.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0d9d6b052baf5380baea866675dab6ccd04ec2460d12b1c46f10ce3f4ee6a820"}, + {file = "fastar-0.11.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:bd2f05666d4df7e14885b5c38fefd92a785917387513d33d837ff42ec143a22f"}, + {file = "fastar-0.11.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1e6e74aba1ae77ca4aedcaf1697cd413319f4c88a5ccbe5b42c709517c5097e"}, + {file = "fastar-0.11.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:38ef77fe940bbc9b37a98bd838727f844b11731cd39358a2640ff864fb385086"}, + {file = "fastar-0.11.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8955e61b32d6aff82c983217abf80933fd823b0e727586fc72f08043d996fd59"}, + {file = "fastar-0.11.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:483532442cdb08fbff0169510224eae0836f2f672cea6aacb52847d90fefdc46"}, + {file = "fastar-0.11.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef5a6071121e05d8287fc75bccb054bcbac8bb0501200a0c0a8feeace5303ea4"}, + {file = "fastar-0.11.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:e45e598af5afe8412197d4786efd6cf29be02e7d3d4f6a3461149eae5d7e94f1"}, + {file = "fastar-0.11.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2e160919b1c47ddb8538e7e8eb4cd527281b40f0bf75110a75993838ef61f286"}, + {file = "fastar-0.11.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:4bb4dc0fc8f7a6807febcebce8a2f3626ba4955a9263d81ecc630aad83be84c0"}, + {file = "fastar-0.11.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4ec95af56aa173f6e320e1183001bf108ba59beaf13edd1fc8200648db203588"}, + {file = "fastar-0.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:136cf342735464091c39dc3708168f9fdeb9ebea40b1ead937c61afaf46143d9"}, + {file = "fastar-0.11.0-cp312-cp312-win32.whl", hash = "sha256:35f23c11b556cc4d3704587faacbc0037f7bdf6c4525cd1d09c70bda4b1c6809"}, + {file = "fastar-0.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:920bc56c3c0b8a8ca492904941d1883c1c947c858cd93343356c29122a38f44c"}, + {file = "fastar-0.11.0-cp312-cp312-win_arm64.whl", hash = "sha256:395248faf89e8a6bd5dc1fd544c8465113b627cb6d7c8b296796b60ebea33593"}, + {file = "fastar-0.11.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:33f544b08b4541b678e53749b4552a44720d96761fb79c172b005b1089c443ed"}, + {file = "fastar-0.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:91c1c792447e4a642745f347ff9847c52af39633071c57ee67ed53c157fc3506"}, + {file = "fastar-0.11.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:881247e6b6eaea59fc6569f9b61447aa6b9fc2ee864e048b4643d69c52745805"}, + {file = "fastar-0.11.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:863b7929845c9fec92ef6c8d59579cf46af5136655e5342f8df5cebe46cab06c"}, + {file = "fastar-0.11.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:96b4a57df12bf3211662627a3ea29d62ecb314a2434a0d0843f9fc23e47536e5"}, + {file = "fastar-0.11.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ceef1c2c4df7b7b8ebd3f5d718bbf457b9bbdf25ce0bd07870211ec4fbd9aff4"}, + {file = "fastar-0.11.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8e545918441910a779659d4759ad0eef349e935fbdb4668a666d3681567eb05"}, + {file = "fastar-0.11.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28095bb8f821e85fc2764e1a55f03e5e2876dee2abe7cd0ee9420d929905d643"}, + {file = "fastar-0.11.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0fafb95ecbe70f666a5e9b35dd63974ccdc9bb3d99ccdbd4014a823ec3e659b5"}, + {file = "fastar-0.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:af48fed039b94016629dcdad1c95c90c486326dd068de2b0a4df419ee09b6821"}, + {file = "fastar-0.11.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:74cd96163f39b8638ab4e8d49708ca887959672a22871d8170d01f067319533b"}, + {file = "fastar-0.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4e8b993cb5613bab495ed482810bedc0986633fcb9a3b55c37ec88e0d6714f6a"}, + {file = "fastar-0.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dfe39d91fc28e37e06162d94afe01050220edb7df554acb5b702b5503e564816"}, + {file = "fastar-0.11.0-cp313-cp313-win32.whl", hash = "sha256:c5f63d4d99ff4bfb37c659982ec413358bdee747005348756cc50a04d412d989"}, + {file = "fastar-0.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:8690ed1928d31ded3ada308e1086525fb3871f5fa81e1b69601a3f7774004583"}, + {file = "fastar-0.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:d977ded9d98a0719a305e0a4d5ee811f1d3e856d853a50acb8ae833c3cd6d5d2"}, + {file = "fastar-0.11.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:71375bd6f03c2a43eb47bd949ea38ff45434917f9cdac79675c5b9f60de4fa73"}, + {file = "fastar-0.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:eddfd9cab16e19ae247fe44bf992cb403ccfe27d3931d6de29a4695d95ad386c"}, + {file = "fastar-0.11.0-cp314-cp314-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:7c371f1d4386c699018bb64eb2fa785feacf32785559049d2bb72fe4af023f53"}, + {file = "fastar-0.11.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cad7fa41e3e66554387481c1a09365e4638becd322904932674159d5f4046728"}, + {file = "fastar-0.11.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cf36652fa71b83761717c9899b98732498f8a2cb6327ff16bbf07f6be85c3437"}, + {file = "fastar-0.11.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f68ff8c17833053da4841720e95edde80ce45bb994b6b7d51418dddaac70ee47"}, + {file = "fastar-0.11.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4563ed37a12ea1cdc398af8571258d24b988bf342b7b3bf5451bd5891243280c"}, + {file = "fastar-0.11.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cee63c9875cba3b70dc44338c560facc5d6e763047dcc4a30501f9a68cf5f890"}, + {file = "fastar-0.11.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:bd76bfffae6d0a91f4ac4a612f721e7aec108db97dccdd120ae063cd66959f27"}, + {file = "fastar-0.11.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8f5b707501ec01c1bc0518f741f01d322e50c9adc19a451aa24f67a2316e9397"}, + {file = "fastar-0.11.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:37c0b5a88a657839aad98b0a6c9e4ac4c2c15d6b49c44ee3935c6b08e9d3e479"}, + {file = "fastar-0.11.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:6c55f536c62a6efb180c1af0d5182948bff576bbfe6276e8e1359c9c7d2215d8"}, + {file = "fastar-0.11.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3082eeca59e189b9039335862f4c2780c0c8871d656bfdf559db4414a105b251"}, + {file = "fastar-0.11.0-cp314-cp314-win32.whl", hash = "sha256:b201a0a4e29f9fec2a177e13154b8725ec65ab9f83bd6415483efaa2aa18344b"}, + {file = "fastar-0.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:868fddb26072a43e870a8819134b9f80ee602931be5a76e6fb873e04da343637"}, + {file = "fastar-0.11.0-cp314-cp314-win_arm64.whl", hash = "sha256:3db39c9cc42abb0c780a26b299f24dfbc8be455985e969e15336d70d7b2f833b"}, + {file = "fastar-0.11.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:49c3299dec5e125e7ebaa27545714da9c7391777366015427e0ae62d548b442b"}, + {file = "fastar-0.11.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3328ed1ed56d31f5198350b17dd60449b8d6b9d47abb4688bab6aef4450a165b"}, + {file = "fastar-0.11.0-cp314-cp314t-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:bd3eca3bbfec84a614bcb4143b4ad4f784d0895babc26cfc88436af88ca23c7a"}, + {file = "fastar-0.11.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff86a967acb0d621dd24063dda090daa67bf4993b9570e97fe156de88a9006ca"}, + {file = "fastar-0.11.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:86eaf7c0e985d93a7734168be2fb232b2a8cca53e41431c2782d7c12b12c03b1"}, + {file = "fastar-0.11.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91f07b0b8eb67e2f177733a1f884edad7dfb9f8977ffef15927b20cb9604027d"}, + {file = "fastar-0.11.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f85c896885eb4abf1a635d54dea22cac6ae48d04fc2ea26ae652fcf1febe1220"}, + {file = "fastar-0.11.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:075c07095c8de4b774ba8f28b9c0a02b1a2cd254da50cbe464dd3bb2432e9158"}, + {file = "fastar-0.11.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:07f028933820c65750baf3383b807ecce1cd9385cf00ce192b79d263ad6b856c"}, + {file = "fastar-0.11.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:039f875efa0f01fa43c20bf4e2fc7305489c61d0ac76eda991acfba7820a0e63"}, + {file = "fastar-0.11.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:fff12452a9a5c6814a012445f26365541cc3d99dcca61f09762e6a389f7a32ea"}, + {file = "fastar-0.11.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:2bf733e09f942b6fa876efe30a90508d1f4caef5630c00fb2a84fba355873712"}, + {file = "fastar-0.11.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d1531fa848fdd3677d2dce0a4b436ea64d9ae38fb8babe2ddbc180dd153cb7a3"}, + {file = "fastar-0.11.0-cp314-cp314t-win32.whl", hash = "sha256:5744551bc67c6fc6581cbd0e34a0fd6e2cd0bd30b43e94b1c3119cf35064b162"}, + {file = "fastar-0.11.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f4ce44e3b56c47cf38244b98d29f269b259740a580c47a2552efa5b96a5458fb"}, + {file = "fastar-0.11.0-cp314-cp314t-win_arm64.whl", hash = "sha256:76c1359314355eafbc6989f20fb1ad565a3d10200117923b9da765a17e2f6f11"}, + {file = "fastar-0.11.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:a2cbcd0dde5548a8b2fc37a24b4bd957daf168973e63ba6dd1cbc2279964631d"}, + {file = "fastar-0.11.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f7d361813a881fef5ab97945ae89ebda7f6fa5ef74ee75871047f88bb2eac471"}, + {file = "fastar-0.11.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6dac5916958156c067ee0f678b4af9a1918aeca80d3c9ac0f81a2dc7a9af0451"}, + {file = "fastar-0.11.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:207b01117a770c0720415c19a43177cc701d458db411f0a8e1c9003138121a9d"}, + {file = "fastar-0.11.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:096f52102b5401b2f60fdca6f417f9b2fae146c644846eda123fe42cbd392178"}, + {file = "fastar-0.11.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:492487d8d2209b71f5f768644a30fced192acf32af287c9ee219a6331ad08097"}, + {file = "fastar-0.11.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d20fbd0fae43453de998027b13646e3376e59077ef7e2c9fbde4e9d65a951e91"}, + {file = "fastar-0.11.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:353db755d840bb2ce4c54d3f889c4d4e17680a9c18e676ff558b45943d4af1bf"}, + {file = "fastar-0.11.0-cp38-cp38-manylinux_2_31_riscv64.whl", hash = "sha256:0881f68bead037eb2bb0e7832ba8bb3b014c67a9fcc1a085dd81f968c611c9da"}, + {file = "fastar-0.11.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:65b38e1a47e6f15585ecb02d7bec27d4cbf1b39d4e030a4159bfee32d275deeb"}, + {file = "fastar-0.11.0-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:9c6157c5df39f3283cfa0f1d0c466ce2cc9375a66d8d451eab5786574a7baa55"}, + {file = "fastar-0.11.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:a84b8d5457b9d378912fb9220548e8a816f35ec952decdc8df8bd5bdb1b28c66"}, + {file = "fastar-0.11.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aab189c0ff354bc246ea540187901daf8527a71e83c9a506a512e693c4bb68ad"}, + {file = "fastar-0.11.0-cp38-cp38-win32.whl", hash = "sha256:2f3da9d75b9aa2e936d410a81eef5303f3d97356748d7079545c32a23837292f"}, + {file = "fastar-0.11.0-cp38-cp38-win_amd64.whl", hash = "sha256:9d0bbd6a34eedd44aa72e7cd7fd9828b4e35fe212e4524a45299288544527991"}, + {file = "fastar-0.11.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:6ced901e08b81514d141b8820857d51be4b0cc881a58edc555fff21ce3b16d8e"}, + {file = "fastar-0.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9277b377ac7dce7d927baf8460ac59248769cd3f5099b547b329b8ecaf2ed3ae"}, + {file = "fastar-0.11.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cb0009f9dd263261be455f8f2a38c0814370ab4febb90adf33e6dc54740438f6"}, + {file = "fastar-0.11.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec9de5c99c01de7be04e332a57dda9dceb98f4b2424c5bea4d4b899732483219"}, + {file = "fastar-0.11.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:628073cfc782f383ef2fa3ce2598fff9ff344d74d7d1e8dd5cff31b7675be1e7"}, + {file = "fastar-0.11.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50194636d86af5317f8a3b4a7cfbb45c14efe2045c7a099b6760785470a57bc9"}, + {file = "fastar-0.11.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88f665ac38c976146fa1f87a9151e6ff3a3e7d423a52e88ab35e9d49da2f4b2f"}, + {file = "fastar-0.11.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78ee04e4b6f94a42b889040ab310f446fc477fd0e71ec3592c1d0e5446f24737"}, + {file = "fastar-0.11.0-cp39-cp39-manylinux_2_31_riscv64.whl", hash = "sha256:9177d62f253b3fa2f4304ffaddab5fc3063c13e2fd481c032631437a2850f99f"}, + {file = "fastar-0.11.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a5b4399806d77e5172b1a37a0a7954e220f84e388cdbfbf80bd1de90fed70aa4"}, + {file = "fastar-0.11.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:e74cbb513f32a5b4499d49fb7a436713cb7a66a3498b002ec1de933650afb447"}, + {file = "fastar-0.11.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:d95530421ef5ea46d37c38509932c52a5862480515f599f5b0eb2e951d04de1b"}, + {file = "fastar-0.11.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2ef4691d57ce8f55e4696235fa98cf86f3f00916e4571838ad2041d1334d6cb0"}, + {file = "fastar-0.11.0-cp39-cp39-win32.whl", hash = "sha256:f3a3dc706fd59fb3566f34597656bdfdabecb563fbefdc41441a85b431fe96cf"}, + {file = "fastar-0.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:1a08582519c2564ecb2d034f1be7a73ceb309c4891d01f4d19ce712c72420fa5"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1266d6a004f427b0d61bd6c7b544d84cc964691b2232c2f4d635a1b75f2f6d5e"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:298a827ec04ade43733f6ca960d0faec38706aa1494175869ea7ea17f5bad5d3"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8800e2387e463a0e5799416a1cbe72dd0fde7270a20e4bde684145e7878f6516"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7496def0a2befd82d429cb004ef7ca831585cc887947bd6b9abb68a5ef852b0b"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:878eaf15463eb572e3538af7ca3a8534e5e279cf8196db902d24e5725c4af86e"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0324ed1d1ef0186e1bbd843b17807d6d837d0906899d4c99378b02c5d86bdd9c"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bdf9bd863205590beaf8ef6e66f315310196632180dceaf674985d01a876cac3"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59af8dbb683b24b90fb5b506de080faeab0a17a908e6c2a5d93a97260ed75d7b"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:9f3df73a3c4292cfe15696cdf59cdb6c309ab59d30b34c733be13c6e32d9a264"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:aa3762cbb16e41a76b61f4a6914937a71aab3a7b6c2d82ca233bc686ebaf756b"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:a8c7bc8ac74cb359bb546b199288c83236372d094b402e557c197e85527495cd"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:587cbd060a2699c5f66281081395bb4657b2b1e0eef5c206b1aabf740019d670"}, + {file = "fastar-0.11.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6a1c56957ac82408be37a3f63594bc83e0919e8760492a4475e542f9f1828778"}, + {file = "fastar-0.11.0.tar.gz", hash = "sha256:aa7f100f7313c03fdb20f1385927ba95671071ba308ad0c1763fef295e1895ce"}, ] -[package.extras] -docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] -typing = ["typing-extensions (>=4.8)"] +[[package]] +name = "filelock" +version = "3.30.2" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.10" +files = [ + {file = "filelock-3.30.2-py3-none-any.whl", hash = "sha256:a64b58f75048ec39589983e97f5117163f822261dcb6ba843e098f05aac9663f"}, + {file = "filelock-3.30.2.tar.gz", hash = "sha256:1ea7c857465c897a4a6e64c1aace28ff6b83f5bc66c1c06ea148efa65bc2ec5d"}, +] [[package]] name = "fonttools" -version = "4.47.2" +version = "4.63.0" description = "Tools to manipulate font files" optional = false -python-versions = ">=3.8" -files = [ - {file = "fonttools-4.47.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3b629108351d25512d4ea1a8393a2dba325b7b7d7308116b605ea3f8e1be88df"}, - {file = "fonttools-4.47.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c19044256c44fe299d9a73456aabee4b4d06c6b930287be93b533b4737d70aa1"}, - {file = "fonttools-4.47.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8be28c036b9f186e8c7eaf8a11b42373e7e4949f9e9f370202b9da4c4c3f56c"}, - {file = "fonttools-4.47.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f83a4daef6d2a202acb9bf572958f91cfde5b10c8ee7fb1d09a4c81e5d851fd8"}, - {file = "fonttools-4.47.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4a5a5318ba5365d992666ac4fe35365f93004109d18858a3e18ae46f67907670"}, - {file = "fonttools-4.47.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8f57ecd742545362a0f7186774b2d1c53423ed9ece67689c93a1055b236f638c"}, - {file = "fonttools-4.47.2-cp310-cp310-win32.whl", hash = "sha256:a1c154bb85dc9a4cf145250c88d112d88eb414bad81d4cb524d06258dea1bdc0"}, - {file = "fonttools-4.47.2-cp310-cp310-win_amd64.whl", hash = "sha256:3e2b95dce2ead58fb12524d0ca7d63a63459dd489e7e5838c3cd53557f8933e1"}, - {file = "fonttools-4.47.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:29495d6d109cdbabe73cfb6f419ce67080c3ef9ea1e08d5750240fd4b0c4763b"}, - {file = "fonttools-4.47.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0a1d313a415eaaba2b35d6cd33536560deeebd2ed758b9bfb89ab5d97dc5deac"}, - {file = "fonttools-4.47.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90f898cdd67f52f18049250a6474185ef6544c91f27a7bee70d87d77a8daf89c"}, - {file = "fonttools-4.47.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3480eeb52770ff75140fe7d9a2ec33fb67b07efea0ab5129c7e0c6a639c40c70"}, - {file = "fonttools-4.47.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0255dbc128fee75fb9be364806b940ed450dd6838672a150d501ee86523ac61e"}, - {file = "fonttools-4.47.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f791446ff297fd5f1e2247c188de53c1bfb9dd7f0549eba55b73a3c2087a2703"}, - {file = "fonttools-4.47.2-cp311-cp311-win32.whl", hash = "sha256:740947906590a878a4bde7dd748e85fefa4d470a268b964748403b3ab2aeed6c"}, - {file = "fonttools-4.47.2-cp311-cp311-win_amd64.whl", hash = "sha256:63fbed184979f09a65aa9c88b395ca539c94287ba3a364517698462e13e457c9"}, - {file = "fonttools-4.47.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4ec558c543609e71b2275c4894e93493f65d2f41c15fe1d089080c1d0bb4d635"}, - {file = "fonttools-4.47.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e040f905d542362e07e72e03612a6270c33d38281fd573160e1003e43718d68d"}, - {file = "fonttools-4.47.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6dd58cc03016b281bd2c74c84cdaa6bd3ce54c5a7f47478b7657b930ac3ed8eb"}, - {file = "fonttools-4.47.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32ab2e9702dff0dd4510c7bb958f265a8d3dd5c0e2547e7b5f7a3df4979abb07"}, - {file = "fonttools-4.47.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3a808f3c1d1df1f5bf39be869b6e0c263570cdafb5bdb2df66087733f566ea71"}, - {file = "fonttools-4.47.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ac71e2e201df041a2891067dc36256755b1229ae167edbdc419b16da78732c2f"}, - {file = "fonttools-4.47.2-cp312-cp312-win32.whl", hash = "sha256:69731e8bea0578b3c28fdb43dbf95b9386e2d49a399e9a4ad736b8e479b08085"}, - {file = "fonttools-4.47.2-cp312-cp312-win_amd64.whl", hash = "sha256:b3e1304e5f19ca861d86a72218ecce68f391646d85c851742d265787f55457a4"}, - {file = "fonttools-4.47.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:254d9a6f7be00212bf0c3159e0a420eb19c63793b2c05e049eb337f3023c5ecc"}, - {file = "fonttools-4.47.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eabae77a07c41ae0b35184894202305c3ad211a93b2eb53837c2a1143c8bc952"}, - {file = "fonttools-4.47.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a86a5ab2873ed2575d0fcdf1828143cfc6b977ac448e3dc616bb1e3d20efbafa"}, - {file = "fonttools-4.47.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13819db8445a0cec8c3ff5f243af6418ab19175072a9a92f6cc8ca7d1452754b"}, - {file = "fonttools-4.47.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4e743935139aa485fe3253fc33fe467eab6ea42583fa681223ea3f1a93dd01e6"}, - {file = "fonttools-4.47.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d49ce3ea7b7173faebc5664872243b40cf88814ca3eb135c4a3cdff66af71946"}, - {file = "fonttools-4.47.2-cp38-cp38-win32.whl", hash = "sha256:94208ea750e3f96e267f394d5588579bb64cc628e321dbb1d4243ffbc291b18b"}, - {file = "fonttools-4.47.2-cp38-cp38-win_amd64.whl", hash = "sha256:0f750037e02beb8b3569fbff701a572e62a685d2a0e840d75816592280e5feae"}, - {file = "fonttools-4.47.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3d71606c9321f6701642bd4746f99b6089e53d7e9817fc6b964e90d9c5f0ecc6"}, - {file = "fonttools-4.47.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:86e0427864c6c91cf77f16d1fb9bf1bbf7453e824589e8fb8461b6ee1144f506"}, - {file = "fonttools-4.47.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a00bd0e68e88987dcc047ea31c26d40a3c61185153b03457956a87e39d43c37"}, - {file = "fonttools-4.47.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5d77479fb885ef38a16a253a2f4096bc3d14e63a56d6246bfdb56365a12b20c"}, - {file = "fonttools-4.47.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5465df494f20a7d01712b072ae3ee9ad2887004701b95cb2cc6dcb9c2c97a899"}, - {file = "fonttools-4.47.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4c811d3c73b6abac275babb8aa439206288f56fdb2c6f8835e3d7b70de8937a7"}, - {file = "fonttools-4.47.2-cp39-cp39-win32.whl", hash = "sha256:5b60e3afa9635e3dfd3ace2757039593e3bd3cf128be0ddb7a1ff4ac45fa5a50"}, - {file = "fonttools-4.47.2-cp39-cp39-win_amd64.whl", hash = "sha256:7ee48bd9d6b7e8f66866c9090807e3a4a56cf43ffad48962725a190e0dd774c8"}, - {file = "fonttools-4.47.2-py3-none-any.whl", hash = "sha256:7eb7ad665258fba68fd22228a09f347469d95a97fb88198e133595947a20a184"}, - {file = "fonttools-4.47.2.tar.gz", hash = "sha256:7df26dd3650e98ca45f1e29883c96a0b9f5bb6af8d632a6a108bc744fa0bd9b3"}, +python-versions = ">=3.10" +files = [ + {file = "fonttools-4.63.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e3297a6a4059b4acc3a1e9a8b04741f240a80044eef08ebd32e8b5bcdddce75b"}, + {file = "fonttools-4.63.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b1cd75a03ad8cb5bc40c90bfde68c0c47de423aa19e5c0f362b43520645eea94"}, + {file = "fonttools-4.63.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0425b277a59cff3d80ca42162a8de360f318438a2ac83570842a678d826d579"}, + {file = "fonttools-4.63.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d7e5c9973aa04c95650c96e5f5ad865fbf42d62079163ecfab1e01cbc2504c22"}, + {file = "fonttools-4.63.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cb014d58140a38135f16064c74c652ed57aa0b75cbf8bb59cac821f7edb5334e"}, + {file = "fonttools-4.63.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:032038247a96c1690f9f31e377c389383c902531b085aa4e4dabd6f57f870e69"}, + {file = "fonttools-4.63.0-cp310-cp310-win32.whl", hash = "sha256:a8b33a82979e0a6a34ff435cc81317be1f95ec1ebb7a3a2d1c8a6a54f02ae44e"}, + {file = "fonttools-4.63.0-cp310-cp310-win_amd64.whl", hash = "sha256:0c18358a155d75034911c5ee397a5b44cd19dd325dbb8b35fb60bf421d6a72ac"}, + {file = "fonttools-4.63.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2b8ae05d9eacf6081414d759c0a352769ac28ce31280d6bb8e77b03f9e3c449f"}, + {file = "fonttools-4.63.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:79cdc9f567aec74a72918fd060283911406750cbc9fd28c1316023deb6ce31a9"}, + {file = "fonttools-4.63.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c14b4fd138c4bafcca294765c547914e1aa431ae1ca94ab99d8db08c958bd3b"}, + {file = "fonttools-4.63.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d76ac49f929aecaf82d83250b8347e099d7aecba0f4726c1d9b6df3b8bb5fe18"}, + {file = "fonttools-4.63.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dcf076a4474fe0d7367e5bbf5b052c7284fa1feca729c04176ce513521afd8a0"}, + {file = "fonttools-4.63.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7dd683fef0663e9f0f45cf541d788d24caa3ec9db50796b588e1757d8b3bc007"}, + {file = "fonttools-4.63.0-cp311-cp311-win32.whl", hash = "sha256:afefc1ed0a59785a7fb06ea7e1678e849c193e1e387db783579bc7b3056fcfcb"}, + {file = "fonttools-4.63.0-cp311-cp311-win_amd64.whl", hash = "sha256:063e08bd17bd5a90127a14123de0d6a952dbc847695fd98b63c043d58057f90c"}, + {file = "fonttools-4.63.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:37dd23e621e3b0aef1baa70a303b80aaf38449632cfc8fd2a55fb285bbccfc02"}, + {file = "fonttools-4.63.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a9faff9e0c1f76f9fd55899d2ce785832efebab37eb8ae13995853aef178bef0"}, + {file = "fonttools-4.63.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef3048ef05dbb552b89817713d9cac912e00d0fde4a3105c00d29e52e10c89af"}, + {file = "fonttools-4.63.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:58dc6bb86a78d782f00f9190ca02c119cf5bbe2807536e361e18d42019f877d8"}, + {file = "fonttools-4.63.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ee08ebfa58f6e1aeff5697ab9582105bb620008c1caafb681e4c557e7483027b"}, + {file = "fonttools-4.63.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:27fdc65af8da6f88b9c6121c47a464cbe359fcfff7ff6fc2d37a1f395d755b78"}, + {file = "fonttools-4.63.0-cp312-cp312-win32.whl", hash = "sha256:af2fd1664d00a397d75f806985ddb36282091c2131a73a6485c23b4a34722263"}, + {file = "fonttools-4.63.0-cp312-cp312-win_amd64.whl", hash = "sha256:59ac449f8cca9b4ffa08d2e7bbadad87ce710d69d1eda5c3c1ce579baa987272"}, + {file = "fonttools-4.63.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:cd7e9857e5e63738b9d9fd707bc1f59c8b09e5177726d23664db393c59bb08bd"}, + {file = "fonttools-4.63.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c2a2a42198b696a6f48fad91709afb55176e66a5e566131219dba372fb7f8c59"}, + {file = "fonttools-4.63.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e874792a8212b44583ea02189d9e693906b2f78b261f372f95d6c563210ac1d"}, + {file = "fonttools-4.63.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22135da48a348785c5e2d5d2d9d6bec5ed44adacbaeb9db12d9493bf6c6bfa68"}, + {file = "fonttools-4.63.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ccf41f2efdf56994d22d73bef4ced1052161958169428d06ba9724ea9e9a64be"}, + {file = "fonttools-4.63.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9ced0bd02ac751dd6319b0da88aaef24414e3b0dbc32bb4f24944821a3741a27"}, + {file = "fonttools-4.63.0-cp313-cp313-win32.whl", hash = "sha256:85be818f5506e8a7753153def2c9550178f0ecae6a47b5e0e8dbb23f7cc90380"}, + {file = "fonttools-4.63.0-cp313-cp313-win_amd64.whl", hash = "sha256:ba04cb5891d4c0c21b6da95eda8d7b090021508a294fff33464fc7d241e0856b"}, + {file = "fonttools-4.63.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fd1e3094f42d806d3d7c79162fc59e5910fcbe3a7360c385b8da969bc4493745"}, + {file = "fonttools-4.63.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:6e528da43bc3791085f8cb6141b1d13e459226790240340fcbb4625649238b03"}, + {file = "fonttools-4.63.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b2248c5decb223562f7902ff6325077a073f608ee8e33e88ad88db734eb9f49"}, + {file = "fonttools-4.63.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:308f957cdeaf8abe4e5f2f124902ef405448af92c90f80e302a3b771c2e6116b"}, + {file = "fonttools-4.63.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bf00f21eb5fb721dbaf73d1e9da6d02a1af7768f2ebcf9798be98beab8ba90f6"}, + {file = "fonttools-4.63.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c1aaa4b9c75798400ac043ce04d74e7830376c85095a5a6ed7cba2f17a266bf4"}, + {file = "fonttools-4.63.0-cp314-cp314-win32.whl", hash = "sha256:22693918177bd9ceabec4736d338045f357769416fc6b0b2508eefef75b08616"}, + {file = "fonttools-4.63.0-cp314-cp314-win_amd64.whl", hash = "sha256:7d782fac32985914c351556f68ac0855391572bcd87de50e05970d3cd4c96fc5"}, + {file = "fonttools-4.63.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:6db5140a60a5d731d21ec076745b40a310607731b0a565b50776393188649001"}, + {file = "fonttools-4.63.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:7d76edbff9014094dbf03bd2d074709dfa6ec7aba13d838c937a2b33d2d6a86e"}, + {file = "fonttools-4.63.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0eac00b9118c3c2f87d272e45341871c5b3066baa3c86897fa634a7c3fb59096"}, + {file = "fonttools-4.63.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:51394295f1a51de8b5f30bdb1e1b9a4231536c7064ef5c6e211eec19fa36036f"}, + {file = "fonttools-4.63.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9e12f105d2b6342c559c298afb674006bb2893afc7102dcf8a1b55b0486b4e40"}, + {file = "fonttools-4.63.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:796f27556dbe094c4824f75ca85267e4df776c79036c8441469a4df37038c196"}, + {file = "fonttools-4.63.0-cp314-cp314t-win32.whl", hash = "sha256:948428a275741f0b64b113c955425a953314f4b9ab9997f73a72c83e68e569c8"}, + {file = "fonttools-4.63.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6d4741eb179121cab9eea4cb2393d24492373a260d7945006358c08cfbf45419"}, + {file = "fonttools-4.63.0-py3-none-any.whl", hash = "sha256:445af2eab030a16b9171ea8bdda7ebf7d96bda2df88ee182a464252f6e05e20d"}, + {file = "fonttools-4.63.0.tar.gz", hash = "sha256:caeb583deeb5168e694b65cda8b4ee62abedfa66cf88488734466f2366b9c4e0"}, ] [package.extras] -all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] +all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.45.0)", "unicodedata2 (>=17.0.0)", "xattr", "zopfli (>=0.1.4)"] graphite = ["lz4 (>=1.7.4.2)"] interpolatable = ["munkres", "pycairo", "scipy"] -lxml = ["lxml (>=4.0,<5)"] +lxml = ["lxml (>=4.0)"] pathops = ["skia-pathops (>=0.5.0)"] plot = ["matplotlib"] -repacker = ["uharfbuzz (>=0.23.0)"] +repacker = ["uharfbuzz (>=0.45.0)"] symfont = ["sympy"] type1 = ["xattr"] -ufo = ["fs (>=2.2.0,<3)"] -unicode = ["unicodedata2 (>=15.1.0)"] +unicode = ["unicodedata2 (>=17.0.0)"] woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] [[package]] name = "frozenlist" -version = "1.5.0" +version = "1.8.0" description = "A list-like structure which implements collections.abc.MutableSequence" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a"}, - {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb"}, - {file = "frozenlist-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:15538c0cbf0e4fa11d1e3a71f823524b0c46299aed6e10ebb4c2089abd8c3bec"}, - {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e79225373c317ff1e35f210dd5f1344ff31066ba8067c307ab60254cd3a78ad5"}, - {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9272fa73ca71266702c4c3e2d4a28553ea03418e591e377a03b8e3659d94fa76"}, - {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:498524025a5b8ba81695761d78c8dd7382ac0b052f34e66939c42df860b8ff17"}, - {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:92b5278ed9d50fe610185ecd23c55d8b307d75ca18e94c0e7de328089ac5dcba"}, - {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f3c8c1dacd037df16e85227bac13cca58c30da836c6f936ba1df0c05d046d8d"}, - {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2ac49a9bedb996086057b75bf93538240538c6d9b38e57c82d51f75a73409d2"}, - {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e66cc454f97053b79c2ab09c17fbe3c825ea6b4de20baf1be28919460dd7877f"}, - {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3ba5f9a0dfed20337d3e966dc359784c9f96503674c2faf015f7fe8e96798c"}, - {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6321899477db90bdeb9299ac3627a6a53c7399c8cd58d25da094007402b039ab"}, - {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76e4753701248476e6286f2ef492af900ea67d9706a0155335a40ea21bf3b2f5"}, - {file = "frozenlist-1.5.0-cp310-cp310-win32.whl", hash = "sha256:977701c081c0241d0955c9586ffdd9ce44f7a7795df39b9151cd9a6fd0ce4cfb"}, - {file = "frozenlist-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:189f03b53e64144f90990d29a27ec4f7997d91ed3d01b51fa39d2dbe77540fd4"}, - {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fd74520371c3c4175142d02a976aee0b4cb4a7cc912a60586ffd8d5929979b30"}, - {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2f3f7a0fbc219fb4455264cae4d9f01ad41ae6ee8524500f381de64ffaa077d5"}, - {file = "frozenlist-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f47c9c9028f55a04ac254346e92977bf0f166c483c74b4232bee19a6697e4778"}, - {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0996c66760924da6e88922756d99b47512a71cfd45215f3570bf1e0b694c206a"}, - {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2fe128eb4edeabe11896cb6af88fca5346059f6c8d807e3b910069f39157869"}, - {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a8ea951bbb6cacd492e3948b8da8c502a3f814f5d20935aae74b5df2b19cf3d"}, - {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de537c11e4aa01d37db0d403b57bd6f0546e71a82347a97c6a9f0dcc532b3a45"}, - {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c2623347b933fcb9095841f1cc5d4ff0b278addd743e0e966cb3d460278840d"}, - {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cee6798eaf8b1416ef6909b06f7dc04b60755206bddc599f52232606e18179d3"}, - {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f5f9da7f5dbc00a604fe74aa02ae7c98bcede8a3b8b9666f9f86fc13993bc71a"}, - {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:90646abbc7a5d5c7c19461d2e3eeb76eb0b204919e6ece342feb6032c9325ae9"}, - {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bdac3c7d9b705d253b2ce370fde941836a5f8b3c5c2b8fd70940a3ea3af7f4f2"}, - {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03d33c2ddbc1816237a67f66336616416e2bbb6beb306e5f890f2eb22b959cdf"}, - {file = "frozenlist-1.5.0-cp311-cp311-win32.whl", hash = "sha256:237f6b23ee0f44066219dae14c70ae38a63f0440ce6750f868ee08775073f942"}, - {file = "frozenlist-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:0cc974cc93d32c42e7b0f6cf242a6bd941c57c61b618e78b6c0a96cb72788c1d"}, - {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:31115ba75889723431aa9a4e77d5f398f5cf976eea3bdf61749731f62d4a4a21"}, - {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7437601c4d89d070eac8323f121fcf25f88674627505334654fd027b091db09d"}, - {file = "frozenlist-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7948140d9f8ece1745be806f2bfdf390127cf1a763b925c4a805c603df5e697e"}, - {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feeb64bc9bcc6b45c6311c9e9b99406660a9c05ca8a5b30d14a78555088b0b3a"}, - {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:683173d371daad49cffb8309779e886e59c2f369430ad28fe715f66d08d4ab1a"}, - {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7d57d8f702221405a9d9b40f9da8ac2e4a1a8b5285aac6100f3393675f0a85ee"}, - {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c72000fbcc35b129cb09956836c7d7abf78ab5416595e4857d1cae8d6251a6"}, - {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e"}, - {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5d7f5a50342475962eb18b740f3beecc685a15b52c91f7d975257e13e029eca9"}, - {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:87f724d055eb4785d9be84e9ebf0f24e392ddfad00b3fe036e43f489fafc9039"}, - {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6e9080bb2fb195a046e5177f10d9d82b8a204c0736a97a153c2466127de87784"}, - {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b93d7aaa36c966fa42efcaf716e6b3900438632a626fb09c049f6a2f09fc631"}, - {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f"}, - {file = "frozenlist-1.5.0-cp312-cp312-win32.whl", hash = "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8"}, - {file = "frozenlist-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f"}, - {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953"}, - {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0"}, - {file = "frozenlist-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2"}, - {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f"}, - {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608"}, - {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b"}, - {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840"}, - {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439"}, - {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de"}, - {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641"}, - {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e"}, - {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9"}, - {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03"}, - {file = "frozenlist-1.5.0-cp313-cp313-win32.whl", hash = "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c"}, - {file = "frozenlist-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28"}, - {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:dd94994fc91a6177bfaafd7d9fd951bc8689b0a98168aa26b5f543868548d3ca"}, - {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0da8bbec082bf6bf18345b180958775363588678f64998c2b7609e34719b10"}, - {file = "frozenlist-1.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:73f2e31ea8dd7df61a359b731716018c2be196e5bb3b74ddba107f694fbd7604"}, - {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:828afae9f17e6de596825cf4228ff28fbdf6065974e5ac1410cecc22f699d2b3"}, - {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1577515d35ed5649d52ab4319db757bb881ce3b2b796d7283e6634d99ace307"}, - {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2150cc6305a2c2ab33299453e2968611dacb970d2283a14955923062c8d00b10"}, - {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a72b7a6e3cd2725eff67cd64c8f13335ee18fc3c7befc05aed043d24c7b9ccb9"}, - {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c16d2fa63e0800723139137d667e1056bee1a1cf7965153d2d104b62855e9b99"}, - {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:17dcc32fc7bda7ce5875435003220a457bcfa34ab7924a49a1c19f55b6ee185c"}, - {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:97160e245ea33d8609cd2b8fd997c850b56db147a304a262abc2b3be021a9171"}, - {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f1e6540b7fa044eee0bb5111ada694cf3dc15f2b0347ca125ee9ca984d5e9e6e"}, - {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:91d6c171862df0a6c61479d9724f22efb6109111017c87567cfeb7b5d1449fdf"}, - {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c1fac3e2ace2eb1052e9f7c7db480818371134410e1f5c55d65e8f3ac6d1407e"}, - {file = "frozenlist-1.5.0-cp38-cp38-win32.whl", hash = "sha256:b97f7b575ab4a8af9b7bc1d2ef7f29d3afee2226bd03ca3875c16451ad5a7723"}, - {file = "frozenlist-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:374ca2dabdccad8e2a76d40b1d037f5bd16824933bf7bcea3e59c891fd4a0923"}, - {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9bbcdfaf4af7ce002694a4e10a0159d5a8d20056a12b05b45cea944a4953f972"}, - {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1893f948bf6681733aaccf36c5232c231e3b5166d607c5fa77773611df6dc336"}, - {file = "frozenlist-1.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2b5e23253bb709ef57a8e95e6ae48daa9ac5f265637529e4ce6b003a37b2621f"}, - {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f253985bb515ecd89629db13cb58d702035ecd8cfbca7d7a7e29a0e6d39af5f"}, - {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04a5c6babd5e8fb7d3c871dc8b321166b80e41b637c31a995ed844a6139942b6"}, - {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9fe0f1c29ba24ba6ff6abf688cb0b7cf1efab6b6aa6adc55441773c252f7411"}, - {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:226d72559fa19babe2ccd920273e767c96a49b9d3d38badd7c91a0fdeda8ea08"}, - {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15b731db116ab3aedec558573c1a5eec78822b32292fe4f2f0345b7f697745c2"}, - {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:366d8f93e3edfe5a918c874702f78faac300209a4d5bf38352b2c1bdc07a766d"}, - {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1b96af8c582b94d381a1c1f51ffaedeb77c821c690ea5f01da3d70a487dd0a9b"}, - {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:c03eff4a41bd4e38415cbed054bbaff4a075b093e2394b6915dca34a40d1e38b"}, - {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:50cf5e7ee9b98f22bdecbabf3800ae78ddcc26e4a435515fc72d97903e8488e0"}, - {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1e76bfbc72353269c44e0bc2cfe171900fbf7f722ad74c9a7b638052afe6a00c"}, - {file = "frozenlist-1.5.0-cp39-cp39-win32.whl", hash = "sha256:666534d15ba8f0fda3f53969117383d5dc021266b3c1a42c9ec4855e4b58b9d3"}, - {file = "frozenlist-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:5c28f4b5dbef8a0d8aad0d4de24d1e9e981728628afaf4ea0792f5d0939372f0"}, - {file = "frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3"}, - {file = "frozenlist-1.5.0.tar.gz", hash = "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817"}, -] - -[[package]] -name = "future" -version = "1.0.0" -description = "Clean single-source support for Python 3 and 2" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -files = [ - {file = "future-1.0.0-py3-none-any.whl", hash = "sha256:929292d34f5872e70396626ef385ec22355a1fae8ad29e1a734c3e43f9fbc216"}, - {file = "future-1.0.0.tar.gz", hash = "sha256:bd2968309307861edae1458a4f8a4f3598c03be43b97521076aebf5d94c07b05"}, + {file = "frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011"}, + {file = "frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565"}, + {file = "frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7"}, + {file = "frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a"}, + {file = "frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6"}, + {file = "frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e"}, + {file = "frozenlist-1.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09474e9831bc2b2199fad6da3c14c7b0fbdd377cce9d3d77131be28906cb7d84"}, + {file = "frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17c883ab0ab67200b5f964d2b9ed6b00971917d5d8a92df149dc2c9779208ee9"}, + {file = "frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa47e444b8ba08fffd1c18e8cdb9a75db1b6a27f17507522834ad13ed5922b93"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2552f44204b744fba866e573be4c1f9048d6a324dfe14475103fd51613eb1d1f"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e7c38f250991e48a9a73e6423db1bb9dd14e722a10f6b8bb8e16a0f55f695"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8585e3bb2cdea02fc88ffa245069c36555557ad3609e83be0ec71f54fd4abb52"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edee74874ce20a373d62dc28b0b18b93f645633c2943fd90ee9d898550770581"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c9a63152fe95756b85f31186bddf42e4c02c6321207fd6601a1c89ebac4fe567"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6db2185db9be0a04fecf2f241c70b63b1a242e2805be291855078f2b404dd6b"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f4be2e3d8bc8aabd566f8d5b8ba7ecc09249d74ba3c9ed52e54dc23a293f0b92"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c8d1634419f39ea6f5c427ea2f90ca85126b54b50837f31497f3bf38266e853d"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a7fa382a4a223773ed64242dbe1c9c326ec09457e6b8428efb4118c685c3dfd"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:11847b53d722050808926e785df837353bd4d75f1d494377e59b23594d834967"}, + {file = "frozenlist-1.8.0-cp311-cp311-win32.whl", hash = "sha256:27c6e8077956cf73eadd514be8fb04d77fc946a7fe9f7fe167648b0b9085cc25"}, + {file = "frozenlist-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac913f8403b36a2c8610bbfd25b8013488533e71e62b4b4adce9c86c8cea905b"}, + {file = "frozenlist-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:d4d3214a0f8394edfa3e303136d0575eece0745ff2b47bd2cb2e66dd92d4351a"}, + {file = "frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1"}, + {file = "frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b"}, + {file = "frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa"}, + {file = "frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf"}, + {file = "frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746"}, + {file = "frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd"}, + {file = "frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a"}, + {file = "frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7"}, + {file = "frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed"}, + {file = "frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496"}, + {file = "frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231"}, + {file = "frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62"}, + {file = "frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94"}, + {file = "frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c"}, + {file = "frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41"}, + {file = "frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b"}, + {file = "frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888"}, + {file = "frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042"}, + {file = "frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0"}, + {file = "frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f"}, + {file = "frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7"}, + {file = "frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806"}, + {file = "frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0"}, + {file = "frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b"}, + {file = "frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d"}, + {file = "frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed"}, + {file = "frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e"}, + {file = "frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df"}, + {file = "frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd"}, + {file = "frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79"}, + {file = "frozenlist-1.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d8b7138e5cd0647e4523d6685b0eac5d4be9a184ae9634492f25c6eb38c12a47"}, + {file = "frozenlist-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a6483e309ca809f1efd154b4d37dc6d9f61037d6c6a81c2dc7a15cb22c8c5dca"}, + {file = "frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1b9290cf81e95e93fdf90548ce9d3c1211cf574b8e3f4b3b7cb0537cf2227068"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:59a6a5876ca59d1b63af8cd5e7ffffb024c3dc1e9cf9301b21a2e76286505c95"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6dc4126390929823e2d2d9dc79ab4046ed74680360fc5f38b585c12c66cdf459"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:332db6b2563333c5671fecacd085141b5800cb866be16d5e3eb15a2086476675"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9ff15928d62a0b80bb875655c39bf517938c7d589554cbd2669be42d97c2cb61"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7bf6cdf8e07c8151fba6fe85735441240ec7f619f935a5205953d58009aef8c6"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:48e6d3f4ec5c7273dfe83ff27c91083c6c9065af655dc2684d2c200c94308bb5"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:1a7607e17ad33361677adcd1443edf6f5da0ce5e5377b798fba20fae194825f3"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3a935c3a4e89c733303a2d5a7c257ea44af3a56c8202df486b7f5de40f37e1"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:940d4a017dbfed9daf46a3b086e1d2167e7012ee297fef9e1c545c4d022f5178"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b9be22a69a014bc47e78072d0ecae716f5eb56c15238acca0f43d6eb8e4a5bda"}, + {file = "frozenlist-1.8.0-cp39-cp39-win32.whl", hash = "sha256:1aa77cb5697069af47472e39612976ed05343ff2e84a3dcf15437b232cbfd087"}, + {file = "frozenlist-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:7398c222d1d405e796970320036b1b563892b65809d9e5261487bb2c7f7b5c6a"}, + {file = "frozenlist-1.8.0-cp39-cp39-win_arm64.whl", hash = "sha256:b4f3b365f31c6cd4af24545ca0a244a53688cad8834e32f56831c4923b50a103"}, + {file = "frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d"}, + {file = "frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad"}, ] [[package]] name = "google-api-core" -version = "2.17.1" +version = "2.32.0" description = "Google API client core library" optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" files = [ - {file = "google-api-core-2.17.1.tar.gz", hash = "sha256:9df18a1f87ee0df0bc4eea2770ebc4228392d8cc4066655b320e2cfccb15db95"}, - {file = "google_api_core-2.17.1-py3-none-any.whl", hash = "sha256:610c5b90092c360736baccf17bd3efbcb30dd380e7a6dc28a71059edb8bd0d8e"}, + {file = "google_api_core-2.32.0-py3-none-any.whl", hash = "sha256:ae1f0d58a6c8869350bf469f8eb3092e7f8c494a942d9525494afb6c162b0904"}, + {file = "google_api_core-2.32.0.tar.gz", hash = "sha256:2b33aad226b19272458c46abfe5c5a38d9531ece0c44502129a1463ce83674ac"}, ] [package.dependencies] -google-auth = ">=2.14.1,<3.0.dev0" -googleapis-common-protos = ">=1.56.2,<2.0.dev0" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0" -requests = ">=2.18.0,<3.0.0.dev0" +google-auth = ">=2.14.1,<3.0.0" +googleapis-common-protos = ">=1.63.2,<2.0.0" +proto-plus = ">=1.24.0,<2.0.0" +protobuf = ">=5.29.6,<8.0.0" +requests = ">=2.33.0,<3.0.0" [package.extras] -grpc = ["grpcio (>=1.33.2,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "grpcio-status (>=1.33.2,<2.0.dev0)", "grpcio-status (>=1.49.1,<2.0.dev0)"] -grpcgcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] -grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] +async-rest = ["aiohttp (>=3.13.4)", "google-auth[aiohttp] (>=2.14.1,<3.0.0)"] +grpc = ["grpcio (>=1.41.0,<2.0.0)", "grpcio (>=1.49.1,<2.0.0)", "grpcio (>=1.75.1,<2.0.0)", "grpcio-status (>=1.41.0,<2.0.0)", "grpcio-status (>=1.49.1,<2.0.0)", "grpcio-status (>=1.75.1,<2.0.0)"] [[package]] name = "google-auth" -version = "2.28.0" +version = "2.56.0" description = "Google Authentication Library" optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" files = [ - {file = "google-auth-2.28.0.tar.gz", hash = "sha256:3cfc1b6e4e64797584fb53fc9bd0b7afa9b7c0dba2004fa7dcc9349e58cc3195"}, - {file = "google_auth-2.28.0-py2.py3-none-any.whl", hash = "sha256:7634d29dcd1e101f5226a23cbc4a0c6cda6394253bf80e281d9c5c6797869c53"}, + {file = "google_auth-2.56.0-py3-none-any.whl", hash = "sha256:6e88c10217e07a92bfd01cac8ee99e32ccfb08414c3102e6c5b8d58f37a0d1e0"}, + {file = "google_auth-2.56.0.tar.gz", hash = "sha256:f90fa030b569a92654b9d690665a073841df33d57487be53db583a9a0867a553"}, ] [package.dependencies] -cachetools = ">=2.0.0,<6.0" +cryptography = {version = ">=38.0.3", markers = "python_version < \"3.14\""} pyasn1-modules = ">=0.2.1" -rsa = ">=3.1.4,<5" [package.extras] -aiohttp = ["aiohttp (>=3.6.2,<4.0.0.dev0)", "requests (>=2.20.0,<3.0.0.dev0)"] -enterprise-cert = ["cryptography (==36.0.2)", "pyopenssl (==22.0.0)"] -pyopenssl = ["cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] +aiohttp = ["aiohttp (>=3.8.0,<4.0.0)", "aiohttp (>=3.9.0,<4.0.0)", "requests (>=2.30.0,<3.0.0)"] +cryptography = ["cryptography (>=38.0.3)", "cryptography (>=41.0.5)"] +enterprise-cert = ["cryptography (>=38.0.3)", "cryptography (>=41.0.5)"] +grpc = ["grpcio (>=1.59.0,<2.0.0)", "grpcio (>=1.75.1,<2.0.0)"] +pyjwt = ["pyjwt (>=2.0)"] +pyopenssl = ["cryptography (>=38.0.3)", "cryptography (>=41.0.5)"] reauth = ["pyu2f (>=0.1.5)"] -requests = ["requests (>=2.20.0,<3.0.0.dev0)"] +requests = ["requests (>=2.30.0,<3.0.0)"] +rsa = ["rsa (>=4.0.0,<5)"] +testing = ["aiohttp (>=3.8.0,<4.0.0)", "aiohttp (>=3.9.0,<4.0.0)", "aioresponses", "flask", "freezegun", "grpcio (>=1.59.0,<2.0.0)", "grpcio (>=1.75.1,<2.0.0)", "packaging (>=20.0)", "pyjwt (>=2.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-localserver", "pyu2f (>=0.1.5)", "requests (>=2.30.0,<3.0.0)", "responses", "urllib3 (>=1.26.15,<3.0.0)"] +urllib3 = ["packaging (>=20.0)", "urllib3 (>=1.26.15,<3.0.0)"] [[package]] name = "google-cloud-core" -version = "2.4.1" +version = "2.6.0" description = "Google Cloud API client core library" optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" files = [ - {file = "google-cloud-core-2.4.1.tar.gz", hash = "sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073"}, - {file = "google_cloud_core-2.4.1-py2.py3-none-any.whl", hash = "sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61"}, + {file = "google_cloud_core-2.6.0-py3-none-any.whl", hash = "sha256:6d63ac8e5eca6d9e4319d0a1e2265fadcd7f1049904378caecfa01cf52dd869e"}, + {file = "google_cloud_core-2.6.0.tar.gz", hash = "sha256:e76149739f90fac1fc6757c09f47eaccb3145b54adbd7759b0f7c4b235f46c83"}, ] [package.dependencies] -google-api-core = ">=1.31.6,<2.0.dev0 || >2.3.0,<3.0.0dev" -google-auth = ">=1.25.0,<3.0dev" +google-api-core = ">=2.11.0,<3.0.0" +google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0" [package.extras] -grpc = ["grpcio (>=1.38.0,<2.0dev)", "grpcio-status (>=1.38.0,<2.0.dev0)"] +grpc = ["grpcio (>=1.47.0,<2.0.0)", "grpcio (>=1.75.1,<2.0.0)", "grpcio-status (>=1.47.0,<2.0.0)"] [[package]] name = "google-cloud-storage" -version = "2.14.0" +version = "2.19.0" description = "Google Cloud Storage API client library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-storage-2.14.0.tar.gz", hash = "sha256:2d23fcf59b55e7b45336729c148bb1c464468c69d5efbaee30f7201dd90eb97e"}, - {file = "google_cloud_storage-2.14.0-py2.py3-none-any.whl", hash = "sha256:8641243bbf2a2042c16a6399551fbb13f062cbc9a2de38d6c0bb5426962e9dbd"}, + {file = "google_cloud_storage-2.19.0-py2.py3-none-any.whl", hash = "sha256:aeb971b5c29cf8ab98445082cbfe7b161a1f48ed275822f59ed3f1524ea54fba"}, + {file = "google_cloud_storage-2.19.0.tar.gz", hash = "sha256:cd05e9e7191ba6cb68934d8eb76054d9be4562aa89dbc4236feee4d7d51342b2"}, ] [package.dependencies] -google-api-core = ">=1.31.5,<2.0.dev0 || >2.3.0,<3.0.0dev" -google-auth = ">=2.23.3,<3.0dev" +google-api-core = ">=2.15.0,<3.0.0dev" +google-auth = ">=2.26.1,<3.0dev" google-cloud-core = ">=2.3.0,<3.0dev" google-crc32c = ">=1.0,<2.0dev" -google-resumable-media = ">=2.6.0" +google-resumable-media = ">=2.7.2" requests = ">=2.18.0,<3.0.0dev" [package.extras] -protobuf = ["protobuf (<5.0.0dev)"] +protobuf = ["protobuf (<6.0.0dev)"] +tracing = ["opentelemetry-api (>=1.1.0)"] [[package]] name = "google-crc32c" -version = "1.5.0" +version = "1.8.0" description = "A python wrapper of the C library 'Google CRC32C'" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "google-crc32c-1.5.0.tar.gz", hash = "sha256:89284716bc6a5a415d4eaa11b1726d2d60a0cd12aadf5439828353662ede9dd7"}, - {file = "google_crc32c-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:596d1f98fc70232fcb6590c439f43b350cb762fb5d61ce7b0e9db4539654cc13"}, - {file = "google_crc32c-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:be82c3c8cfb15b30f36768797a640e800513793d6ae1724aaaafe5bf86f8f346"}, - {file = "google_crc32c-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:461665ff58895f508e2866824a47bdee72497b091c730071f2b7575d5762ab65"}, - {file = "google_crc32c-1.5.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2096eddb4e7c7bdae4bd69ad364e55e07b8316653234a56552d9c988bd2d61b"}, - {file = "google_crc32c-1.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:116a7c3c616dd14a3de8c64a965828b197e5f2d121fedd2f8c5585c547e87b02"}, - {file = "google_crc32c-1.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5829b792bf5822fd0a6f6eb34c5f81dd074f01d570ed7f36aa101d6fc7a0a6e4"}, - {file = "google_crc32c-1.5.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:64e52e2b3970bd891309c113b54cf0e4384762c934d5ae56e283f9a0afcd953e"}, - {file = "google_crc32c-1.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:02ebb8bf46c13e36998aeaad1de9b48f4caf545e91d14041270d9dca767b780c"}, - {file = "google_crc32c-1.5.0-cp310-cp310-win32.whl", hash = "sha256:2e920d506ec85eb4ba50cd4228c2bec05642894d4c73c59b3a2fe20346bd00ee"}, - {file = "google_crc32c-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:07eb3c611ce363c51a933bf6bd7f8e3878a51d124acfc89452a75120bc436289"}, - {file = "google_crc32c-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cae0274952c079886567f3f4f685bcaf5708f0a23a5f5216fdab71f81a6c0273"}, - {file = "google_crc32c-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1034d91442ead5a95b5aaef90dbfaca8633b0247d1e41621d1e9f9db88c36298"}, - {file = "google_crc32c-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c42c70cd1d362284289c6273adda4c6af8039a8ae12dc451dcd61cdabb8ab57"}, - {file = "google_crc32c-1.5.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8485b340a6a9e76c62a7dce3c98e5f102c9219f4cfbf896a00cf48caf078d438"}, - {file = "google_crc32c-1.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77e2fd3057c9d78e225fa0a2160f96b64a824de17840351b26825b0848022906"}, - {file = "google_crc32c-1.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f583edb943cf2e09c60441b910d6a20b4d9d626c75a36c8fcac01a6c96c01183"}, - {file = "google_crc32c-1.5.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:a1fd716e7a01f8e717490fbe2e431d2905ab8aa598b9b12f8d10abebb36b04dd"}, - {file = "google_crc32c-1.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:72218785ce41b9cfd2fc1d6a017dc1ff7acfc4c17d01053265c41a2c0cc39b8c"}, - {file = "google_crc32c-1.5.0-cp311-cp311-win32.whl", hash = "sha256:66741ef4ee08ea0b2cc3c86916ab66b6aef03768525627fd6a1b34968b4e3709"}, - {file = "google_crc32c-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:ba1eb1843304b1e5537e1fca632fa894d6f6deca8d6389636ee5b4797affb968"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:98cb4d057f285bd80d8778ebc4fde6b4d509ac3f331758fb1528b733215443ae"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd8536e902db7e365f49e7d9029283403974ccf29b13fc7028b97e2295b33556"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19e0a019d2c4dcc5e598cd4a4bc7b008546b0358bd322537c74ad47a5386884f"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02c65b9817512edc6a4ae7c7e987fea799d2e0ee40c53ec573a692bee24de876"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6ac08d24c1f16bd2bf5eca8eaf8304812f44af5cfe5062006ec676e7e1d50afc"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3359fc442a743e870f4588fcf5dcbc1bf929df1fad8fb9905cd94e5edb02e84c"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e986b206dae4476f41bcec1faa057851f3889503a70e1bdb2378d406223994a"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:de06adc872bcd8c2a4e0dc51250e9e65ef2ca91be023b9d13ebd67c2ba552e1e"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-win32.whl", hash = "sha256:d3515f198eaa2f0ed49f8819d5732d70698c3fa37384146079b3799b97667a94"}, - {file = "google_crc32c-1.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:67b741654b851abafb7bc625b6d1cdd520a379074e64b6a128e3b688c3c04740"}, - {file = "google_crc32c-1.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c02ec1c5856179f171e032a31d6f8bf84e5a75c45c33b2e20a3de353b266ebd8"}, - {file = "google_crc32c-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:edfedb64740750e1a3b16152620220f51d58ff1b4abceb339ca92e934775c27a"}, - {file = "google_crc32c-1.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84e6e8cd997930fc66d5bb4fde61e2b62ba19d62b7abd7a69920406f9ecca946"}, - {file = "google_crc32c-1.5.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:024894d9d3cfbc5943f8f230e23950cd4906b2fe004c72e29b209420a1e6b05a"}, - {file = "google_crc32c-1.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:998679bf62b7fb599d2878aa3ed06b9ce688b8974893e7223c60db155f26bd8d"}, - {file = "google_crc32c-1.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:83c681c526a3439b5cf94f7420471705bbf96262f49a6fe546a6db5f687a3d4a"}, - {file = "google_crc32c-1.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4c6fdd4fccbec90cc8a01fc00773fcd5fa28db683c116ee3cb35cd5da9ef6c37"}, - {file = "google_crc32c-1.5.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5ae44e10a8e3407dbe138984f21e536583f2bba1be9491239f942c2464ac0894"}, - {file = "google_crc32c-1.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:37933ec6e693e51a5b07505bd05de57eee12f3e8c32b07da7e73669398e6630a"}, - {file = "google_crc32c-1.5.0-cp38-cp38-win32.whl", hash = "sha256:fe70e325aa68fa4b5edf7d1a4b6f691eb04bbccac0ace68e34820d283b5f80d4"}, - {file = "google_crc32c-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:74dea7751d98034887dbd821b7aae3e1d36eda111d6ca36c206c44478035709c"}, - {file = "google_crc32c-1.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c6c777a480337ac14f38564ac88ae82d4cd238bf293f0a22295b66eb89ffced7"}, - {file = "google_crc32c-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:759ce4851a4bb15ecabae28f4d2e18983c244eddd767f560165563bf9aefbc8d"}, - {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f13cae8cc389a440def0c8c52057f37359014ccbc9dc1f0827936bcd367c6100"}, - {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e560628513ed34759456a416bf86b54b2476c59144a9138165c9a1575801d0d9"}, - {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1674e4307fa3024fc897ca774e9c7562c957af85df55efe2988ed9056dc4e57"}, - {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:278d2ed7c16cfc075c91378c4f47924c0625f5fc84b2d50d921b18b7975bd210"}, - {file = "google_crc32c-1.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d5280312b9af0976231f9e317c20e4a61cd2f9629b7bfea6a693d1878a264ebd"}, - {file = "google_crc32c-1.5.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8b87e1a59c38f275c0e3676fc2ab6d59eccecfd460be267ac360cc31f7bcde96"}, - {file = "google_crc32c-1.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7c074fece789b5034b9b1404a1f8208fc2d4c6ce9decdd16e8220c5a793e6f61"}, - {file = "google_crc32c-1.5.0-cp39-cp39-win32.whl", hash = "sha256:7f57f14606cd1dd0f0de396e1e53824c371e9544a822648cd76c034d209b559c"}, - {file = "google_crc32c-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:a2355cba1f4ad8b6988a4ca3feed5bff33f6af2d7f134852cf279c2aebfde541"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f314013e7dcd5cf45ab1945d92e713eec788166262ae8deb2cfacd53def27325"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b747a674c20a67343cb61d43fdd9207ce5da6a99f629c6e2541aa0e89215bcd"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8f24ed114432de109aa9fd317278518a5af2d31ac2ea6b952b2f7782b43da091"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8667b48e7a7ef66afba2c81e1094ef526388d35b873966d8a9a447974ed9178"}, - {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:1c7abdac90433b09bad6c43a43af253e688c9cfc1c86d332aed13f9a7c7f65e2"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6f998db4e71b645350b9ac28a2167e6632c239963ca9da411523bb439c5c514d"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c99616c853bb585301df6de07ca2cadad344fd1ada6d62bb30aec05219c45d2"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ad40e31093a4af319dadf503b2467ccdc8f67c72e4bcba97f8c10cb078207b5"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd67cf24a553339d5062eff51013780a00d6f97a39ca062781d06b3a73b15462"}, - {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:398af5e3ba9cf768787eef45c803ff9614cc3e22a5b2f7d7ae116df8b11e3314"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b1f8133c9a275df5613a451e73f36c2aea4fe13c5c8997e22cf355ebd7bd0728"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ba053c5f50430a3fcfd36f75aff9caeba0440b2d076afdb79a318d6ca245f88"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:272d3892a1e1a2dbc39cc5cde96834c236d5327e2122d3aaa19f6614531bb6eb"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:635f5d4dd18758a1fbd1049a8e8d2fee4ffed124462d837d1a02a0e009c3ab31"}, - {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c672d99a345849301784604bfeaeba4db0c7aae50b95be04dd651fd2a7310b93"}, + {file = "google_crc32c-1.8.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:0470b8c3d73b5f4e3300165498e4cf25221c7eb37f1159e221d1825b6df8a7ff"}, + {file = "google_crc32c-1.8.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:119fcd90c57c89f30040b47c211acee231b25a45d225e3225294386f5d258288"}, + {file = "google_crc32c-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6f35aaffc8ccd81ba3162443fabb920e65b1f20ab1952a31b13173a67811467d"}, + {file = "google_crc32c-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:864abafe7d6e2c4c66395c1eb0fe12dc891879769b52a3d56499612ca93b6092"}, + {file = "google_crc32c-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:db3fe8eaf0612fc8b20fa21a5f25bd785bc3cd5be69f8f3412b0ac2ffd49e733"}, + {file = "google_crc32c-1.8.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:014a7e68d623e9a4222d663931febc3033c5c7c9730785727de2a81f87d5bab8"}, + {file = "google_crc32c-1.8.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:86cfc00fe45a0ac7359e5214a1704e51a99e757d0272554874f419f79838c5f7"}, + {file = "google_crc32c-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:19b40d637a54cb71e0829179f6cb41835f0fbd9e8eb60552152a8b52c36cbe15"}, + {file = "google_crc32c-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:17446feb05abddc187e5441a45971b8394ea4c1b6efd88ab0af393fd9e0a156a"}, + {file = "google_crc32c-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:71734788a88f551fbd6a97be9668a0020698e07b2bf5b3aa26a36c10cdfb27b2"}, + {file = "google_crc32c-1.8.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:4b8286b659c1335172e39563ab0a768b8015e88e08329fa5321f774275fc3113"}, + {file = "google_crc32c-1.8.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:2a3dc3318507de089c5384cc74d54318401410f82aa65b2d9cdde9d297aca7cb"}, + {file = "google_crc32c-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:14f87e04d613dfa218d6135e81b78272c3b904e2a7053b841481b38a7d901411"}, + {file = "google_crc32c-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cb5c869c2923d56cb0c8e6bcdd73c009c36ae39b652dbe46a05eb4ef0ad01454"}, + {file = "google_crc32c-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:3cc0c8912038065eafa603b238abf252e204accab2a704c63b9e14837a854962"}, + {file = "google_crc32c-1.8.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:3ebb04528e83b2634857f43f9bb8ef5b2bbe7f10f140daeb01b58f972d04736b"}, + {file = "google_crc32c-1.8.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:450dc98429d3e33ed2926fc99ee81001928d63460f8538f21a5d6060912a8e27"}, + {file = "google_crc32c-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3b9776774b24ba76831609ffbabce8cdf6fa2bd5e9df37b594221c7e333a81fa"}, + {file = "google_crc32c-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:89c17d53d75562edfff86679244830599ee0a48efc216200691de8b02ab6b2b8"}, + {file = "google_crc32c-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:57a50a9035b75643996fbf224d6661e386c7162d1dfdab9bc4ca790947d1007f"}, + {file = "google_crc32c-1.8.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:e6584b12cb06796d285d09e33f63309a09368b9d806a551d8036a4207ea43697"}, + {file = "google_crc32c-1.8.0-cp314-cp314-macosx_12_0_x86_64.whl", hash = "sha256:f4b51844ef67d6cf2e9425983274da75f18b1597bb2c998e1c0a0e8d46f8f651"}, + {file = "google_crc32c-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b0d1a7afc6e8e4635564ba8aa5c0548e3173e41b6384d7711a9123165f582de2"}, + {file = "google_crc32c-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b3f68782f3cbd1bce027e48768293072813469af6a61a86f6bb4977a4380f21"}, + {file = "google_crc32c-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:d511b3153e7011a27ab6ee6bb3a5404a55b994dc1a7322c0b87b29606d9790e2"}, + {file = "google_crc32c-1.8.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:ba6aba18daf4d36ad4412feede6221414692f44d17e5428bdd81ad3fc1eee5dc"}, + {file = "google_crc32c-1.8.0-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:87b0072c4ecc9505cfa16ee734b00cd7721d20a0f595be4d40d3d21b41f65ae2"}, + {file = "google_crc32c-1.8.0-cp39-cp39-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3d488e98b18809f5e322978d4506373599c0c13e6c5ad13e53bb44758e18d215"}, + {file = "google_crc32c-1.8.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:01f126a5cfddc378290de52095e2c7052be2ba7656a9f0caf4bcd1bfb1833f8a"}, + {file = "google_crc32c-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:61f58b28e0b21fcb249a8247ad0db2e64114e201e2e9b4200af020f3b6242c9f"}, + {file = "google_crc32c-1.8.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:87fa445064e7db928226b2e6f0d5304ab4cd0339e664a4e9a25029f384d9bb93"}, + {file = "google_crc32c-1.8.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f639065ea2042d5c034bf258a9f085eaa7af0cd250667c0635a3118e8f92c69c"}, + {file = "google_crc32c-1.8.0.tar.gz", hash = "sha256:a428e25fb7691024de47fecfbff7ff957214da51eddded0da0ae0e0f03a2cf79"}, ] -[package.extras] -testing = ["pytest"] - [[package]] name = "google-resumable-media" -version = "2.7.0" +version = "2.10.0" description = "Utilities for Google Media Downloads and Resumable Uploads" optional = false -python-versions = ">= 3.7" +python-versions = ">=3.10" files = [ - {file = "google-resumable-media-2.7.0.tar.gz", hash = "sha256:5f18f5fa9836f4b083162064a1c2c98c17239bfda9ca50ad970ccf905f3e625b"}, - {file = "google_resumable_media-2.7.0-py2.py3-none-any.whl", hash = "sha256:79543cfe433b63fd81c0844b7803aba1bb8950b47bedf7d980c38fa123937e08"}, + {file = "google_resumable_media-2.10.0-py3-none-any.whl", hash = "sha256:88152884bee37b2bf36a0ab81ad8c7fd12212c9803dd981d77c1b35b02d34e7c"}, + {file = "google_resumable_media-2.10.0.tar.gz", hash = "sha256:e324bc9d0fdae4c52a08ae90456edc4e71ece858399e1217ac0eb3a51d6bc6ee"}, ] [package.dependencies] -google-crc32c = ">=1.0,<2.0dev" +google-crc32c = ">=1.0.0,<2.0.0" [package.extras] -aiohttp = ["aiohttp (>=3.6.2,<4.0.0dev)", "google-auth (>=1.22.0,<2.0dev)"] -requests = ["requests (>=2.18.0,<3.0.0dev)"] +aiohttp = ["aiohttp (>=3.6.2,<4.0.0)", "google-auth (>=1.22.0,<2.0.0)"] +requests = ["requests (>=2.18.0,<3.0.0)"] [[package]] name = "googleapis-common-protos" -version = "1.62.0" +version = "1.75.0" description = "Common protobufs used in Google APIs" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "googleapis-common-protos-1.62.0.tar.gz", hash = "sha256:83f0ece9f94e5672cced82f592d2a5edf527a96ed1794f0bab36d5735c996277"}, - {file = "googleapis_common_protos-1.62.0-py2.py3-none-any.whl", hash = "sha256:4750113612205514f9f6aa4cb00d523a94f3e8c06c5ad2fee466387dc4875f07"}, + {file = "googleapis_common_protos-1.75.0-py3-none-any.whl", hash = "sha256:961ed60399c457ceb0ee8f285a84c870aabc9c6a832b9d37bb281b5bebde43ed"}, + {file = "googleapis_common_protos-1.75.0.tar.gz", hash = "sha256:53a062ff3c32552fbd62c11fe23768b78e4ddf0494d5e5fd97d3f4689c75fbbd"}, ] [package.dependencies] -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0" +protobuf = ">=4.25.8,<8.0.0" [package.extras] -grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] +grpc = ["grpcio (>=1.44.0,<2.0.0)"] [[package]] name = "greenlet" -version = "3.0.3" +version = "3.5.3" description = "Lightweight in-process concurrent programming" optional = false -python-versions = ">=3.7" -files = [ - {file = "greenlet-3.0.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405"}, - {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f"}, - {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb"}, - {file = "greenlet-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9"}, - {file = "greenlet-3.0.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22"}, - {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3"}, - {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d"}, - {file = "greenlet-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728"}, - {file = "greenlet-3.0.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf"}, - {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305"}, - {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6"}, - {file = "greenlet-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2"}, - {file = "greenlet-3.0.3-cp37-cp37m-macosx_11_0_universal2.whl", hash = "sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41"}, - {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7"}, - {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6"}, - {file = "greenlet-3.0.3-cp37-cp37m-win32.whl", hash = "sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d"}, - {file = "greenlet-3.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67"}, - {file = "greenlet-3.0.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4"}, - {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5"}, - {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da"}, - {file = "greenlet-3.0.3-cp38-cp38-win32.whl", hash = "sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3"}, - {file = "greenlet-3.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf"}, - {file = "greenlet-3.0.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b"}, - {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6"}, - {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113"}, - {file = "greenlet-3.0.3-cp39-cp39-win32.whl", hash = "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e"}, - {file = "greenlet-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067"}, - {file = "greenlet-3.0.3.tar.gz", hash = "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491"}, +python-versions = ">=3.10" +files = [ + {file = "greenlet-3.5.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:c180d22d325fb613956b443c3c6f4406eb70e6defc70d3974da2a7b59e06f48c"}, + {file = "greenlet-3.5.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:483d08c11181c83a6ce1a7a61df0f624a208ec40817a3bb2302714592eee4f04"}, + {file = "greenlet-3.5.3-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1dae6e0091eae084317e411f047f0b7cb241c6db570f7c45fd6b900a274914ce"}, + {file = "greenlet-3.5.3-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0f6ff50ff8dbd51fae9b37f4101648b04ea0df19b3f50ab2beb5061e7716a5c8"}, + {file = "greenlet-3.5.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9bcd2d72ccd70a1ec68ba6ef93e7fbb4420ef9997dabc7010d893bd4015e0bec"}, + {file = "greenlet-3.5.3-cp310-cp310-manylinux_2_39_riscv64.whl", hash = "sha256:37bf9c538f5ae6e63d643f88dec37c0c83bdf0e2ebc62961dedcf458822f7b71"}, + {file = "greenlet-3.5.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:73f152c895e09907e0dbe24f6c2db37beb085cd63db91c3825a0fcd0064124a8"}, + {file = "greenlet-3.5.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8bdb43e1a1d1873721acab2be99c5befd4d2044ddfd52e4d610801019880a702"}, + {file = "greenlet-3.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:0909f9355a9f24845d3299f3112e266a06afb68302041989fd26bd68894933db"}, + {file = "greenlet-3.5.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:aca9b4ce85b152b5524ef7d88170efdff80dc0032aa8b75f9aaf7f3479ea95b4"}, + {file = "greenlet-3.5.3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f71be4920368fe1fabeeaa53d1e3548337e2b223d9565f8ad5e392a75ba23fc"}, + {file = "greenlet-3.5.3-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d77e67f65f98449e3fb83f795b5d0a8437aead2f874ca89c96576caf4be3af6"}, + {file = "greenlet-3.5.3-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e18619ba655ac05d78d80fc83cac4ba892bd6927b99e3b8237aee861aaacc8bb"}, + {file = "greenlet-3.5.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8540f1e6205bd13ca0ce685581037219ca54a1b41a0a15d228c6c9b8ad5903d7"}, + {file = "greenlet-3.5.3-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:d27c0c653a60d9535f690226474a5cc1036a8b0d7b57504d1c4f89c44a07a80c"}, + {file = "greenlet-3.5.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7ef56fe650f50575bf843acde967b9c567687f3c22340941a899b7bc56e956a8"}, + {file = "greenlet-3.5.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5121af01cf911e70056c00d4b46d5e9b5d1415550038573d744138bacb59e6b8"}, + {file = "greenlet-3.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:0f41e4a05a3c0cb31b17023eff28dd111e1d16bf7d7d00406cd7df23f31398a7"}, + {file = "greenlet-3.5.3-cp311-cp311-win_arm64.whl", hash = "sha256:ec6f1af59f6b5f3fc9678e2ea062d8377d22ac644f7844cb7a292910cf12ff44"}, + {file = "greenlet-3.5.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:719757059f5a53fd0dde23f78cffeafcdd97b21c850ddb7ca684a3c1a1f122e2"}, + {file = "greenlet-3.5.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:efa9f765dd09f9d0cdac651ffdf631ee59ec5dc6ee7a73e0c012ba9c52fbdf5b"}, + {file = "greenlet-3.5.3-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7faba15ac005376e02a0384504e0243be3370ce010296a44a820feb342b505ab"}, + {file = "greenlet-3.5.3-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5795cd1101371140551c645f2d408b8d3c01a5a29cf8a9bce6e759c983682d23"}, + {file = "greenlet-3.5.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:87142215824be6ac05e2e8e2786eec307ccbc27c36723c3881959df654af6861"}, + {file = "greenlet-3.5.3-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:af4923b3096e26a36d7e9cf24ab88083a20f97d191e3b97f253731ce9b41b28c"}, + {file = "greenlet-3.5.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:215275b1b49320987352e6c1b054acca0064f965a2c66992bed9a6f7d913f149"}, + {file = "greenlet-3.5.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6b1b0eed82364b0e32c4ea0f221452d33e6bb17ae094d9f72aed9851812747ea"}, + {file = "greenlet-3.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:cde8adafa2365676f74a979744629589999093bc86e2484214f58e61df08902c"}, + {file = "greenlet-3.5.3-cp312-cp312-win_arm64.whl", hash = "sha256:c4e7b79d83805475f0102008843f6eb45fd3bb0b2e88c774adab5fbaab27117d"}, + {file = "greenlet-3.5.3-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:c8d87c2134d871df96ecdea9cec7cbaab286dadab0f56476e57aaf9e8ac11550"}, + {file = "greenlet-3.5.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2d185dd1621757e70c3861cceffd5317ab4e7ed7eb09c82994828468527ade5"}, + {file = "greenlet-3.5.3-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1c514a468149bf8fbbab874188a3535cd8a48a3e353eb53a3d424296f8dbacd3"}, + {file = "greenlet-3.5.3-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9ad04dd75458c6300b047c61b8639092433d205a25a14e310d6582a480efcca1"}, + {file = "greenlet-3.5.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:915f887cf2682b66419b879423a2e072634aa7b7dce6f3ada4957cfced3f1e9a"}, + {file = "greenlet-3.5.3-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:afaabdd554cd7ae9bbb3ca070b0d7fdfd207dbf1d16865f7233837709d354bda"}, + {file = "greenlet-3.5.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:766cfd421c13e450feb340cd472a3ed9957d438727b7b4593ad7c76c5d2b0deb"}, + {file = "greenlet-3.5.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2ecda9ec22edf38fa389369eaed8c3d37c05f3c54e69f69438dbb2cc1de1458b"}, + {file = "greenlet-3.5.3-cp313-cp313-win_amd64.whl", hash = "sha256:c82304750f057167ff60d188df1d0cc1764ce9567eadf03e6a7443bcedd0b30b"}, + {file = "greenlet-3.5.3-cp313-cp313-win_arm64.whl", hash = "sha256:dc133a1569ee667b2a6ef56ce551084aeefd87a5acbc4736d336d1e2edc6cfc4"}, + {file = "greenlet-3.5.3-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:fd2e02fa07485778536a036222d616ab957b1d533f36b3ed98ce725d9c9d3117"}, + {file = "greenlet-3.5.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df0a0628d1597eb0897b62f55d1343f772405fd25f3b2a796c76874b0c2e22e8"}, + {file = "greenlet-3.5.3-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ebd933a6adabc298bab47731a130fe6bfb888bd934eee37810f151159544540d"}, + {file = "greenlet-3.5.3-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8d19fe6c39ebff9259f07bcc685d3290f8fa4ea2278e51dd0008e4d6b0f2d814"}, + {file = "greenlet-3.5.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4b9d501b40e80b70e32323c799dd9b420a5577a9601469d362ae1ffb690f3a7c"}, + {file = "greenlet-3.5.3-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:962c5df2db8cb446da51edf1ca5296c389d93b99c9d8aa2ee4c7d0d8f1218260"}, + {file = "greenlet-3.5.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a1fad1d11e7d6aab184107baa8e4ece11ccba3ec9599cd7efa5ff4d70d43256a"}, + {file = "greenlet-3.5.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:fad5aec764399f1b5cc347ad250a59660f20c8f8888ea6bae1f93b769cce1154"}, + {file = "greenlet-3.5.3-cp314-cp314-win_amd64.whl", hash = "sha256:7669aa24cf2a1041d6f7899575b494a3ab4cf68bfcc8609b1dc0be7272db835e"}, + {file = "greenlet-3.5.3-cp314-cp314-win_arm64.whl", hash = "sha256:5b4807c4082c9d1b6d9eed56fcd041863e37f2228106eef24c30ca096e238605"}, + {file = "greenlet-3.5.3-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:271a8ea7c1024e8a0d7dd2be66dd66dda8a07193f41a17b9e924f7600f5b62be"}, + {file = "greenlet-3.5.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:19131729ae0ddc3c2e1ef85e650169b5e37ee32e400f215f78b94d7b0d567310"}, + {file = "greenlet-3.5.3-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1540dd8e5fc2a5aec40fbb98ef8e149fa47c89a4b4a1cf2575a14d3d1869d7a8"}, + {file = "greenlet-3.5.3-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b897d97759425953f69a9c0fac67f8fe333ec0ce7377ef186fb2b0c3ad5e354d"}, + {file = "greenlet-3.5.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e81fa194a1d20967877bdf9c7794db2bc99063e5be36aee710c08f04c5bb087f"}, + {file = "greenlet-3.5.3-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:3236754d423955ea08e9bb5f6c04a7895f9e22c290b66aa7653fcb922d839eb0"}, + {file = "greenlet-3.5.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:55cf4d777485d43110e47133cbba6d74a8885a87ec1227ef0267f9ee80c5aa21"}, + {file = "greenlet-3.5.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:12a248ba75f6a9a236375f52296c498c89ff1d8badf32deb9eca7abd5853f7da"}, + {file = "greenlet-3.5.3-cp314-cp314t-win_amd64.whl", hash = "sha256:efc6bd60ea02e085862c74a3ef64b147ffc6f1a5ea7d9f26e7a939943f68c1e3"}, + {file = "greenlet-3.5.3-cp315-cp315-macosx_11_0_universal2.whl", hash = "sha256:ea03f2f04367845d6b58eeed276e1e56e51f0b97d8ad5a88a7d20a91dc9056cc"}, + {file = "greenlet-3.5.3-cp315-cp315-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78dbef602fda6d97d957eb7937f70c9ce9e9527330347f8f6b6f9e554a9e7a47"}, + {file = "greenlet-3.5.3-cp315-cp315-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f73857adb8fee13fa56c172bd11262f888c0c648f9fea113e777bb2c7904a81"}, + {file = "greenlet-3.5.3-cp315-cp315-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:cefa9cef4b371f9844c6053db71f1138bc6807bab1578b0dae5149c1f1141357"}, + {file = "greenlet-3.5.3-cp315-cp315-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:232fec92e823addaf02d9472cf7381e24a1d046a6ced1103c5caa4c21b9dfc1d"}, + {file = "greenlet-3.5.3-cp315-cp315-manylinux_2_39_riscv64.whl", hash = "sha256:6219b6d04dbf6ba6084d77dc609e8473060dc55f759cbf626d512122781fa128"}, + {file = "greenlet-3.5.3-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:2421c3564da9429d5586d46ca31ebb26516b5498a802cf65c041a8e8a8980d34"}, + {file = "greenlet-3.5.3-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:e0f0d160f0b2e558e6c75f7930967183255dc9735e5f5b8cae58ee09c9576d8b"}, + {file = "greenlet-3.5.3-cp315-cp315-win_amd64.whl", hash = "sha256:dd99329bbc15ca78dcc583dba05d0b1b0bae01ab6c2174989f5aaee3e41ac930"}, + {file = "greenlet-3.5.3-cp315-cp315-win_arm64.whl", hash = "sha256:499fef2acede88c1864a57bb586b4bf533c81e1b82df7ab93451cdb47dfec227"}, + {file = "greenlet-3.5.3-cp315-cp315t-macosx_11_0_universal2.whl", hash = "sha256:176bc16a721fa5fc294d70b87b4dfa5fbdd251b3da5d5372735ecef9bd7d6d0c"}, + {file = "greenlet-3.5.3-cp315-cp315t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:629b614d2b786e89c50440e246f33eea78f58a962d0bdbbcc809e6d13605903f"}, + {file = "greenlet-3.5.3-cp315-cp315t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2b2e857ae16f5f72142edf75f9f176fe7526ba19a2841df1420516f83831c9f2"}, + {file = "greenlet-3.5.3-cp315-cp315t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:16d192579ed281051396dddd7f7754dac6259e6b1fb26378c87b66622f8e3f91"}, + {file = "greenlet-3.5.3-cp315-cp315t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e515757e2e36bcbf1fad09a46e1557e8b1ae1797d4b44d09da7deed88ad28608"}, + {file = "greenlet-3.5.3-cp315-cp315t-manylinux_2_39_riscv64.whl", hash = "sha256:4399eb8d041f20b68d943918bc55502a93d6fdc0a37c14da7881c04139acee9d"}, + {file = "greenlet-3.5.3-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:b363d46ed1ea431825fdb01471bb024fc08399bad1572a616e853c7684415adb"}, + {file = "greenlet-3.5.3-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:e44da2f5bbdaabaf7d80b73dbb430c7035771e9f244e3c8b769715c9d8fa0a16"}, + {file = "greenlet-3.5.3-cp315-cp315t-win_amd64.whl", hash = "sha256:8ff8bed3e3baa20a3ea261ce00526f1898ad4801d4886fd2220580ee0ad8fadf"}, + {file = "greenlet-3.5.3-cp315-cp315t-win_arm64.whl", hash = "sha256:b7068bd09f761f3f5b4d214c2bed063186b2a86148c740b3873e3f56d79bac31"}, + {file = "greenlet-3.5.3.tar.gz", hash = "sha256:a61efc018fd3eb317eeca31aba90ee9e7f26f22884a79b6c6ec715bf71bb62f1"}, ] [package.extras] docs = ["Sphinx", "furo"] -test = ["objgraph", "psutil"] +test = ["objgraph", "psutil", "setuptools"] [[package]] name = "h11" -version = "0.14.0" +version = "0.16.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, - {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, + {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, + {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, ] [[package]] name = "h5py" -version = "3.10.0" +version = "3.16.0" description = "Read and write HDF5 files from Python" optional = false -python-versions = ">=3.8" -files = [ - {file = "h5py-3.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b963fb772964fc1d1563c57e4e2e874022ce11f75ddc6df1a626f42bd49ab99f"}, - {file = "h5py-3.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:012ab448590e3c4f5a8dd0f3533255bc57f80629bf7c5054cf4c87b30085063c"}, - {file = "h5py-3.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:781a24263c1270a62cd67be59f293e62b76acfcc207afa6384961762bb88ea03"}, - {file = "h5py-3.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f42e6c30698b520f0295d70157c4e202a9e402406f50dc08f5a7bc416b24e52d"}, - {file = "h5py-3.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:93dd840bd675787fc0b016f7a05fc6efe37312a08849d9dd4053fd0377b1357f"}, - {file = "h5py-3.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2381e98af081b6df7f6db300cd88f88e740649d77736e4b53db522d8874bf2dc"}, - {file = "h5py-3.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:667fe23ab33d5a8a6b77970b229e14ae3bb84e4ea3382cc08567a02e1499eedd"}, - {file = "h5py-3.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90286b79abd085e4e65e07c1bd7ee65a0f15818ea107f44b175d2dfe1a4674b7"}, - {file = "h5py-3.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c013d2e79c00f28ffd0cc24e68665ea03ae9069e167087b2adb5727d2736a52"}, - {file = "h5py-3.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:92273ce69ae4983dadb898fd4d3bea5eb90820df953b401282ee69ad648df684"}, - {file = "h5py-3.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c97d03f87f215e7759a354460fb4b0d0f27001450b18b23e556e7856a0b21c3"}, - {file = "h5py-3.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86df4c2de68257b8539a18646ceccdcf2c1ce6b1768ada16c8dcfb489eafae20"}, - {file = "h5py-3.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba9ab36be991119a3ff32d0c7cbe5faf9b8d2375b5278b2aea64effbeba66039"}, - {file = "h5py-3.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:2c8e4fda19eb769e9a678592e67eaec3a2f069f7570c82d2da909c077aa94339"}, - {file = "h5py-3.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:492305a074327e8d2513011fa9fffeb54ecb28a04ca4c4227d7e1e9616d35641"}, - {file = "h5py-3.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9450464b458cca2c86252b624279115dcaa7260a40d3cb1594bf2b410a2bd1a3"}, - {file = "h5py-3.10.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd6f6d1384a9f491732cee233b99cd4bfd6e838a8815cc86722f9d2ee64032af"}, - {file = "h5py-3.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3074ec45d3dc6e178c6f96834cf8108bf4a60ccb5ab044e16909580352010a97"}, - {file = "h5py-3.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:212bb997a91e6a895ce5e2f365ba764debeaef5d2dca5c6fb7098d66607adf99"}, - {file = "h5py-3.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5dfc65ac21fa2f630323c92453cadbe8d4f504726ec42f6a56cf80c2f90d6c52"}, - {file = "h5py-3.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d4682b94fd36ab217352be438abd44c8f357c5449b8995e63886b431d260f3d3"}, - {file = "h5py-3.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aece0e2e1ed2aab076c41802e50a0c3e5ef8816d60ece39107d68717d4559824"}, - {file = "h5py-3.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43a61b2c2ad65b1fabc28802d133eed34debcc2c8b420cb213d3d4ef4d3e2229"}, - {file = "h5py-3.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:ae2f0201c950059676455daf92700eeb57dcf5caaf71b9e1328e6e6593601770"}, - {file = "h5py-3.10.0.tar.gz", hash = "sha256:d93adc48ceeb33347eb24a634fb787efc7ae4644e6ea4ba733d099605045c049"}, +python-versions = ">=3.10" +files = [ + {file = "h5py-3.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e06f864bedb2c8e7c1358e6c73af48519e317457c444d6f3d332bb4e8fa6d7d9"}, + {file = "h5py-3.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ec86d4fffd87a0f4cb3d5796ceb5a50123a2a6d99b43e616e5504e66a953eca3"}, + {file = "h5py-3.16.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:86385ea895508220b8a7e45efa428aeafaa586bd737c7af9ee04661d8d84a10d"}, + {file = "h5py-3.16.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:8975273c2c5921c25700193b408e28d6bdd0111c37468b2d4e25dcec4cd1d84d"}, + {file = "h5py-3.16.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:1677ad48b703f44efc9ea0c3ab284527f81bc4f318386aaaebc5fede6bbae56f"}, + {file = "h5py-3.16.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c4dd4cf5f0a4e36083f73172f6cfc25a5710789269547f132a20975bfe2434c"}, + {file = "h5py-3.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:bdef06507725b455fccba9c16529121a5e1fbf56aa375f7d9713d9e8ff42454d"}, + {file = "h5py-3.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:719439d14b83f74eeb080e9650a6c7aa6d0d9ea0ca7f804347b05fac6fbf18af"}, + {file = "h5py-3.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c3f0a0e136f2e95dd0b67146abb6668af4f1a69c81ef8651a2d316e8e01de447"}, + {file = "h5py-3.16.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:a6fbc5367d4046801f9b7db9191b31895f22f1c6df1f9987d667854cac493538"}, + {file = "h5py-3.16.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:fb1720028d99040792bb2fb31facb8da44a6f29df7697e0b84f0d79aff2e9bd3"}, + {file = "h5py-3.16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:314b6054fe0b1051c2b0cb2df5cbdab15622fb05e80f202e3b6a5eee0d6fe365"}, + {file = "h5py-3.16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ffbab2fedd6581f6aa31cf1639ca2cb86e02779de525667892ebf4cc9fd26434"}, + {file = "h5py-3.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:17d1f1630f92ad74494a9a7392ab25982ce2b469fc62da6074c0ce48366a2999"}, + {file = "h5py-3.16.0-cp311-cp311-win_arm64.whl", hash = "sha256:85b9c49dd58dc44cf70af944784e2c2038b6f799665d0dcbbc812a26e0faa859"}, + {file = "h5py-3.16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c5313566f4643121a78503a473f0fb1e6dcc541d5115c44f05e037609c565c4d"}, + {file = "h5py-3.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:42b012933a83e1a558c673176676a10ce2fd3759976a0fedee1e672d1e04fc9d"}, + {file = "h5py-3.16.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:ff24039e2573297787c3063df64b60aab0591980ac898329a08b0320e0cf2527"}, + {file = "h5py-3.16.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:dfc21898ff025f1e8e67e194965a95a8d4754f452f83454538f98f8a3fcb207e"}, + {file = "h5py-3.16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:698dd69291272642ffda44a0ecd6cd3bda5faf9621452d255f57ce91487b9794"}, + {file = "h5py-3.16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2b2c02b0a160faed5fb33f1ba8a264a37ee240b22e049ecc827345d0d9043074"}, + {file = "h5py-3.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:96b422019a1c8975c2d5dadcf61d4ba6f01c31f92bbde6e4649607885fe502d6"}, + {file = "h5py-3.16.0-cp312-cp312-win_arm64.whl", hash = "sha256:39c2838fb1e8d97bcf1755e60ad1f3dd76a7b2a475928dc321672752678b96db"}, + {file = "h5py-3.16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:370a845f432c2c9619db8eed334d1e610c6015796122b0e57aa46312c22617d9"}, + {file = "h5py-3.16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:42108e93326c50c2810025aade9eac9d6827524cdccc7d4b75a546e5ab308edb"}, + {file = "h5py-3.16.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:099f2525c9dcf28de366970a5fb34879aab20491589fa89ce2863a84218bb524"}, + {file = "h5py-3.16.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:9300ad32dea9dfc5171f94d5f6948e159ed93e4701280b0f508773b3f582f402"}, + {file = "h5py-3.16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:171038f23bccddfc23f344cadabdfc9917ff554db6a0d417180d2747fe4c75a7"}, + {file = "h5py-3.16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7e420b539fb6023a259a1b14d4c9f6df8cf50d7268f48e161169987a57b737ff"}, + {file = "h5py-3.16.0-cp313-cp313-win_amd64.whl", hash = "sha256:18f2bbcd545e6991412253b98727374c356d67caa920e68dc79eab36bf5fedad"}, + {file = "h5py-3.16.0-cp313-cp313-win_arm64.whl", hash = "sha256:656f00e4d903199a1d58df06b711cf3ca632b874b4207b7dbec86185b5c8c7d4"}, + {file = "h5py-3.16.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:9c9d307c0ef862d1cd5714f72ecfafe0a5d7529c44845afa8de9f46e5ba8bd65"}, + {file = "h5py-3.16.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8c1eff849cdd53cbc73c214c30ebdb6f1bb8b64790b4b4fc36acdb5e43570210"}, + {file = "h5py-3.16.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:e2c04d129f180019e216ee5f9c40b78a418634091c8782e1f723a6ca3658b965"}, + {file = "h5py-3.16.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:e4360f15875a532bc7b98196c7592ed4fc92672a57c0a621355961cafb17a6dd"}, + {file = "h5py-3.16.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3fae9197390c325e62e0a1aa977f2f62d994aa87aab182abbea85479b791197c"}, + {file = "h5py-3.16.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:43259303989ac8adacc9986695b31e35dba6fd1e297ff9c6a04b7da5542139cc"}, + {file = "h5py-3.16.0-cp314-cp314-win_amd64.whl", hash = "sha256:fa48993a0b799737ba7fd21e2350fa0a60701e58180fae9f2de834bc39a147ab"}, + {file = "h5py-3.16.0-cp314-cp314-win_arm64.whl", hash = "sha256:1897a771a7f40d05c262fc8f37376ec37873218544b70216872876c627640f63"}, + {file = "h5py-3.16.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:15922e485844f77c0b9d275396d435db3baa58292a9c2176a386e072e0cf2491"}, + {file = "h5py-3.16.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:df02dd29bd247f98674634dfe41f89fd7c16ba3d7de8695ec958f58404a4e618"}, + {file = "h5py-3.16.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:0f456f556e4e2cebeebd9d66adf8dc321770a42593494a0b6f0af54a7567b242"}, + {file = "h5py-3.16.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:3e6cb3387c756de6a9492d601553dffea3fe11b5f22b443aac708c69f3f55e16"}, + {file = "h5py-3.16.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8389e13a1fd745ad2856873e8187fd10268b2d9677877bb667b41aebd771d8b7"}, + {file = "h5py-3.16.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:346df559a0f7dcb31cf8e44805319e2ab24b8957c45e7708ce503b2ec79ba725"}, + {file = "h5py-3.16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:4c6ab014ab704b4feaa719ae783b86522ed0bf1f82184704ed3c9e4e3228796e"}, + {file = "h5py-3.16.0-cp314-cp314t-win_arm64.whl", hash = "sha256:faca8fb4e4319c09d83337adc80b2ca7d5c5a343c2d6f1b6388f32cfecca13c1"}, + {file = "h5py-3.16.0.tar.gz", hash = "sha256:a0dbaad796840ccaa67a4c144a0d0c8080073c34c76d5a6941d6818678ef2738"}, ] [package.dependencies] -numpy = ">=1.17.3" +numpy = ">=1.21.2" [[package]] name = "hexbytes" -version = "1.2.1" +version = "1.3.1" description = "hexbytes: Python `bytes` subclass that decodes hex, with a readable console output" optional = false python-versions = "<4,>=3.8" files = [ - {file = "hexbytes-1.2.1-py3-none-any.whl", hash = "sha256:e64890b203a31f4a23ef11470ecfcca565beaee9198df623047df322b757471a"}, - {file = "hexbytes-1.2.1.tar.gz", hash = "sha256:515f00dddf31053db4d0d7636dd16061c1d896c3109b8e751005db4ca46bcca7"}, + {file = "hexbytes-1.3.1-py3-none-any.whl", hash = "sha256:da01ff24a1a9a2b1881c4b85f0e9f9b0f51b526b379ffa23832ae7899d29c2c7"}, + {file = "hexbytes-1.3.1.tar.gz", hash = "sha256:a657eebebdfe27254336f98d8af6e2236f3f83aed164b87466b6cf6c5f5a4765"}, ] [package.extras] -dev = ["build (>=0.9.0)", "bump-my-version (>=0.19.0)", "eth-utils (>=2.0.0)", "hypothesis (>=3.44.24,<=6.31.6)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] -docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] -test = ["eth-utils (>=2.0.0)", "hypothesis (>=3.44.24,<=6.31.6)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] +dev = ["build (>=0.9.0)", "bump_my_version (>=0.19.0)", "eth_utils (>=2.0.0)", "hypothesis (>=3.44.24)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)", "tox (>=4.0.0)", "twine", "wheel"] +docs = ["sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)"] +test = ["eth_utils (>=2.0.0)", "hypothesis (>=3.44.24)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] [[package]] name = "httpcore" -version = "0.17.3" +version = "1.0.9" description = "A minimal low-level HTTP client." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "httpcore-0.17.3-py3-none-any.whl", hash = "sha256:c2789b767ddddfa2a5782e3199b2b7f6894540b17b16ec26b2c4d8e103510b87"}, - {file = "httpcore-0.17.3.tar.gz", hash = "sha256:a6f30213335e34c1ade7be6ec7c47f19f50c56db36abef1a9dfa3815b1cb3888"}, + {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, + {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, ] [package.dependencies] -anyio = ">=3.0,<5.0" certifi = "*" -h11 = ">=0.13,<0.15" -sniffio = "==1.*" +h11 = ">=0.16" [package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<1.0)"] [[package]] -name = "httptools" -version = "0.6.4" -description = "A collection of framework independent HTTP protocol utils." +name = "httpcore2" +version = "2.7.0" +description = "A minimal low-level HTTP client." optional = false -python-versions = ">=3.8.0" -files = [ - {file = "httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0"}, - {file = "httptools-0.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:345c288418f0944a6fe67be8e6afa9262b18c7626c3ef3c28adc5eabc06a68da"}, - {file = "httptools-0.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deee0e3343f98ee8047e9f4c5bc7cedbf69f5734454a94c38ee829fb2d5fa3c1"}, - {file = "httptools-0.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca80b7485c76f768a3bc83ea58373f8db7b015551117375e4918e2aa77ea9b50"}, - {file = "httptools-0.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:90d96a385fa941283ebd231464045187a31ad932ebfa541be8edf5b3c2328959"}, - {file = "httptools-0.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:59e724f8b332319e2875efd360e61ac07f33b492889284a3e05e6d13746876f4"}, - {file = "httptools-0.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:c26f313951f6e26147833fc923f78f95604bbec812a43e5ee37f26dc9e5a686c"}, - {file = "httptools-0.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f47f8ed67cc0ff862b84a1189831d1d33c963fb3ce1ee0c65d3b0cbe7b711069"}, - {file = "httptools-0.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0614154d5454c21b6410fdf5262b4a3ddb0f53f1e1721cfd59d55f32138c578a"}, - {file = "httptools-0.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8787367fbdfccae38e35abf7641dafc5310310a5987b689f4c32cc8cc3ee975"}, - {file = "httptools-0.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b0f7fe4fd38e6a507bdb751db0379df1e99120c65fbdc8ee6c1d044897a636"}, - {file = "httptools-0.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40a5ec98d3f49904b9fe36827dcf1aadfef3b89e2bd05b0e35e94f97c2b14721"}, - {file = "httptools-0.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dacdd3d10ea1b4ca9df97a0a303cbacafc04b5cd375fa98732678151643d4988"}, - {file = "httptools-0.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:288cd628406cc53f9a541cfaf06041b4c71d751856bab45e3702191f931ccd17"}, - {file = "httptools-0.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2"}, - {file = "httptools-0.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44"}, - {file = "httptools-0.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1"}, - {file = "httptools-0.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2"}, - {file = "httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81"}, - {file = "httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f"}, - {file = "httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970"}, - {file = "httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660"}, - {file = "httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083"}, - {file = "httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3"}, - {file = "httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071"}, - {file = "httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5"}, - {file = "httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0"}, - {file = "httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8"}, - {file = "httptools-0.6.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:d3f0d369e7ffbe59c4b6116a44d6a8eb4783aae027f2c0b366cf0aa964185dba"}, - {file = "httptools-0.6.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:94978a49b8f4569ad607cd4946b759d90b285e39c0d4640c6b36ca7a3ddf2efc"}, - {file = "httptools-0.6.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40dc6a8e399e15ea525305a2ddba998b0af5caa2566bcd79dcbe8948181eeaff"}, - {file = "httptools-0.6.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab9ba8dcf59de5181f6be44a77458e45a578fc99c31510b8c65b7d5acc3cf490"}, - {file = "httptools-0.6.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:fc411e1c0a7dcd2f902c7c48cf079947a7e65b5485dea9decb82b9105ca71a43"}, - {file = "httptools-0.6.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:d54efd20338ac52ba31e7da78e4a72570cf729fac82bc31ff9199bedf1dc7440"}, - {file = "httptools-0.6.4-cp38-cp38-win_amd64.whl", hash = "sha256:df959752a0c2748a65ab5387d08287abf6779ae9165916fe053e68ae1fbdc47f"}, - {file = "httptools-0.6.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:85797e37e8eeaa5439d33e556662cc370e474445d5fab24dcadc65a8ffb04003"}, - {file = "httptools-0.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:db353d22843cf1028f43c3651581e4bb49374d85692a85f95f7b9a130e1b2cab"}, - {file = "httptools-0.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1ffd262a73d7c28424252381a5b854c19d9de5f56f075445d33919a637e3547"}, - {file = "httptools-0.6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:703c346571fa50d2e9856a37d7cd9435a25e7fd15e236c397bf224afaa355fe9"}, - {file = "httptools-0.6.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aafe0f1918ed07b67c1e838f950b1c1fabc683030477e60b335649b8020e1076"}, - {file = "httptools-0.6.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0e563e54979e97b6d13f1bbc05a96109923e76b901f786a5eae36e99c01237bd"}, - {file = "httptools-0.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:b799de31416ecc589ad79dd85a0b2657a8fe39327944998dea368c1d4c9e55e6"}, - {file = "httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c"}, +python-versions = ">=3.10" +files = [ + {file = "httpcore2-2.7.0-py3-none-any.whl", hash = "sha256:1452f589fe23f55b44546cd884294c41a29330af902bc0b71a761fd52d18f92b"}, + {file = "httpcore2-2.7.0.tar.gz", hash = "sha256:6dc0fedf329a52a990930a5579edfebaea81118ea700ea0dd7de2b5e5be49efc"}, ] +[package.dependencies] +h11 = ">=0.16" +truststore = ">=0.10" + [package.extras] -test = ["Cython (>=0.29.24)"] +asyncio = ["anyio (>=4.5.0,<5.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<1.0)"] + +[[package]] +name = "httptools" +version = "0.8.0" +description = "A collection of framework independent HTTP protocol utils." +optional = false +python-versions = ">=3.9" +files = [ + {file = "httptools-0.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:bf3b6f807c8541503cecfbb8a8dffb385640d0d96102f3d112aa8740f9b7c826"}, + {file = "httptools-0.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:da684f2e1aa2ee9bdcb083f3f3a68c5956750b375bc5df864d3a5f0c42a40b77"}, + {file = "httptools-0.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a6f21e2a3b0067bbe7f67e34cfd16276af556e5e52f4c7503be0cb5f90e905e4"}, + {file = "httptools-0.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea897f0c729581ebf72131a438a7932d9b14efef72d75ada966700cac3caaeb"}, + {file = "httptools-0.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c0d726cc107fceb7d45f978483b4b70dd8caa836f5914d3434bb18628eb73813"}, + {file = "httptools-0.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9878eb2785ba5eb70631ad269b37976f73d647955e26c91d490eb8a4edfda4ba"}, + {file = "httptools-0.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:b205e5f5523fa039679da0dfe5a10132b2a4abeae6a86fdd1ddc035f7f836557"}, + {file = "httptools-0.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ed377e64805bdba4943c82717333f8f8603a13b09aff9cead2717c6c817fb168"}, + {file = "httptools-0.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9518c406d7b310f05adb1a37f80acabac40504a575d7c0da6d3e365c695ac20d"}, + {file = "httptools-0.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:57278e6fa0424c42a8a3e454828ab4f0aff27b40cddf9679579b98c6dce6a376"}, + {file = "httptools-0.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bbb8caadb2b742d293169d2b458b5c001ef70e3158704aa3d3ef9597624c5d1d"}, + {file = "httptools-0.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:52dd695b865fe96d9d2b16b64a895f3f57bf3cb064e8383cd3b5713a069e8085"}, + {file = "httptools-0.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:20b4aac66ff65f7db06a375808b78f42a94970aa22e826b3cb2b43eb09174124"}, + {file = "httptools-0.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:a1b4c8e7a489a0d750d91894e9a8cdc295838f1924c0ca903ae993456fddec07"}, + {file = "httptools-0.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:880490234c10f70a9830743097e8958d6e4b9f5a0ffc24515023afeef984054d"}, + {file = "httptools-0.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5931891fb7b441b8a3853cf1b85c82c903defce084dd5f6771ca46e31bf862c5"}, + {file = "httptools-0.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b15fc622b0f869d19207c4089a501d9bcc63ca5e071ffdd2f03f922df882dcb2"}, + {file = "httptools-0.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:425f83884fd6343828d8c565f046cb72b6d19063f6924093e11bcd8e1548cd09"}, + {file = "httptools-0.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ef7c3c97f4311c7be57e2986629df89d49cb434dbff78eafcd48c2bff986b15a"}, + {file = "httptools-0.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a1afd7c9fbff0d9f5d489c4ce2768bd09c84a46ddefc7161e6aa82ae35c85745"}, + {file = "httptools-0.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:cd96f29b4bab1d42fa6e3d008711c75e0f79e94e06827330160e3a304227f150"}, + {file = "httptools-0.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:614ceea8ea606848bece2338ac03b3ce5324bcb4be8dc7d377ed708012fa4db8"}, + {file = "httptools-0.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2d689918c15a013c65ef52d9fd495d766893ab831a2c8d89f2ac5940a5df847c"}, + {file = "httptools-0.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:eb3028cca2fc0a6d720e52ef61d8ebb62fcbfeb1de56874546d858d3f25a26b7"}, + {file = "httptools-0.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:88bdd940f2b5d487b4d032c6afa5489a7dc4694410d43de3c38c4fb3af0dc45d"}, + {file = "httptools-0.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6a43c9dd399758ccc0531acb0a3c4a6c299ee893ee9400e9c893b7bdcfae0681"}, + {file = "httptools-0.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0770728beb05094c809b98e814edff5fef69d26ad7d21185f2f6d5884a0ba683"}, + {file = "httptools-0.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:7685df791fad561384bfb139e77fde27a1ffd93134e016f95a0db424ffbf77b1"}, + {file = "httptools-0.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:de242a49b5d18e0a8776e654e9f6bf6d89f3875a5c35b425a0e7ce940feb3fd6"}, + {file = "httptools-0.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:159e9ab5f701ccd42e555a12f1ad8ff69702910fc1c996cf2bb66e5fcb7a231b"}, + {file = "httptools-0.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c4a9f1707e4823d54dfec6c33fa3697d302aed536ed352a7ebb5a061ddb869d0"}, + {file = "httptools-0.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d76ad7b951387e3632c8716a9bb03ac5b45c5f16119aa409db0459520887944e"}, + {file = "httptools-0.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a3b7387147361c3fd47a0bde763c5c91b5b4cd4dc9989b8ece84ff436c99843b"}, + {file = "httptools-0.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f256d6ce930c52ca1cb2a960b7da03548c454e7d28b06059ad41bfe789036ce0"}, + {file = "httptools-0.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:19d1ee275bb59ba2643ba9a3a1e51cc0c788caf2b8df506368e03f56fdd08527"}, + {file = "httptools-0.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:de1ed58a974e75d56560acc7e7fed01a454994429456f65209789992e41f2568"}, + {file = "httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e93c227b595c6926c1acee96891dd9da4be338cfbe82e5cd3bb9d8dd7dc4ac0b"}, + {file = "httptools-0.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2a021c3a8e65cc125390d72f59b968afca3bdcaff25bd67965e0a055a14946ca"}, + {file = "httptools-0.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48774d39cbb70e2b1f71f88852a3087ae1d3a1eb80482bb48c13067ab080c14f"}, + {file = "httptools-0.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:88eead8ec8680a9f146c655bc88445a325bd7921cfd8194c7337e9467282427d"}, + {file = "httptools-0.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2c032fa028f46871ec7e1fc59fc15e8023eab3e6bbe6ece786a1611719a5d081"}, + {file = "httptools-0.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:384c17174464c8e873398b7af24f0b1f44d992c820328413951a625323155d77"}, + {file = "httptools-0.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:df31ef5494f406ab6cf827b7e64a22841c6e2d654100e6a116ea15b46d02d5e8"}, + {file = "httptools-0.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5eb911c515b96ee44bbd861e42cbefc488681d450545b1d02127f6136e3a86f5"}, + {file = "httptools-0.8.0-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c08ffe3e79756e0963cbc8fe410139f38a5884874b6f2e17761bef6563fdcd9b"}, + {file = "httptools-0.8.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fe2a4c95aeba2209434e7b31172da572846cae8ca0bf1e7013e61b99fbbf5e72"}, + {file = "httptools-0.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7b71e7d7031928c650e1006e6c03e911bf967f7c69c011d37d541c3e7bf55005"}, + {file = "httptools-0.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9fc1644f415372cec4f8a5be3a64183737398f10dbb1263602a036427fe75247"}, + {file = "httptools-0.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:5d7fa4ba7292c1139c0526f0b5aad507c6263c948206ea1b1cbca015c8af1b62"}, + {file = "httptools-0.8.0.tar.gz", hash = "sha256:6b2a32f18d97e16e90827d7a819ffa8dbd8cc245fc4e1fa9d1095b54ef4bd999"}, +] [[package]] name = "httpx" -version = "0.24.1" +version = "0.28.1" description = "The next generation HTTP client." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "httpx-0.24.1-py3-none-any.whl", hash = "sha256:06781eb9ac53cde990577af654bd990a4949de37a28bdb4a230d434f3a30b9bd"}, - {file = "httpx-0.24.1.tar.gz", hash = "sha256:5853a43053df830c20f8110c5e69fe44d035d850b2dfe795e196f00fdb774bdd"}, + {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"}, + {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"}, ] [package.dependencies] +anyio = "*" certifi = "*" -httpcore = ">=0.15.0,<0.18.0" +httpcore = "==1.*" idna = "*" -sniffio = "*" [package.extras] brotli = ["brotli", "brotlicffi"] cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "httpx2" +version = "2.7.0" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.10" +files = [ + {file = "httpx2-2.7.0-py3-none-any.whl", hash = "sha256:ed2a2719c696789e09493bd8e2bec3d8bd925cc6e26b68389ec25ade132f7bf4"}, + {file = "httpx2-2.7.0.tar.gz", hash = "sha256:8b30709aed5c8465b0dd3b95c09ce301c8f79e7e7a2d00ab0af551e0d0375b07"}, +] + +[package.dependencies] +anyio = ">=4.10" +httpcore2 = "2.7.0" +idna = ">=3.18" +truststore = ">=0.10" +typing-extensions = {version = ">=4.5.0", markers = "python_version < \"3.13\""} + +[package.extras] +brotli = ["brotli", "brotlicffi"] +cli = ["click (>=8.4)", "pygments (==2.*)", "rich (>=10,<16)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +ws = ["wsproto (>=1.2)"] +zstd = ["zstandard (>=0.18.0)"] [[package]] name = "human-protocol-sdk" @@ -1996,13 +2404,13 @@ agreement = ["numpy", "pyerf"] [[package]] name = "identify" -version = "2.5.33" +version = "2.6.19" description = "File identification library for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "identify-2.5.33-py2.py3-none-any.whl", hash = "sha256:d40ce5fcd762817627670da8a7d8d8e65f24342d14539c59488dc603bf662e34"}, - {file = "identify-2.5.33.tar.gz", hash = "sha256:161558f9fe4559e1557e1bff323e8631f6a0e4837f7497767c1782832f16b62d"}, + {file = "identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a"}, + {file = "identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842"}, ] [package.extras] @@ -2010,35 +2418,57 @@ license = ["ukkonen"] [[package]] name = "idna" -version = "3.6" +version = "3.18" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.5" +python-versions = ">=3.9" files = [ - {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, - {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, + {file = "idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2"}, + {file = "idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848"}, ] +[package.extras] +all = ["mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + +[[package]] +name = "importlib-resources" +version = "7.1.0" +description = "Read resources from Python packages" +optional = false +python-versions = ">=3.10" +files = [ + {file = "importlib_resources-7.1.0-py3-none-any.whl", hash = "sha256:1bd7b48b4088eddb2cd16382150bb515af0bd2c70128194392725f82ad2c96a1"}, + {file = "importlib_resources-7.1.0.tar.gz", hash = "sha256:0722d4c6212489c530f2a145a34c0a7a3b4721bc96a15fada5930e2a0b760708"}, +] + +[package.extras] +check = ["pytest-checkdocs (>=2.14)", "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"] +enabler = ["pytest-enabler (>=3.4)"] +test = ["jaraco.test (>=5.4)", "pytest (>=6,!=8.1.*)", "zipp (>=3.17)"] +type = ["pytest-mypy (>=1.0.1)"] + [[package]] name = "iniconfig" -version = "2.0.0" +version = "2.3.0" description = "brain-dead simple config-ini parsing" optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, + {file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"}, + {file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"}, ] [[package]] name = "jinja2" -version = "3.1.4" +version = "3.1.6" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" files = [ - {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, - {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, + {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, + {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, ] [package.dependencies] @@ -2049,230 +2479,299 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "jmespath" -version = "1.0.1" +version = "1.1.0" description = "JSON Matching Expressions" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, - {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, + {file = "jmespath-1.1.0-py3-none-any.whl", hash = "sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64"}, + {file = "jmespath-1.1.0.tar.gz", hash = "sha256:472c87d80f36026ae83c6ddd0f1d05d4e510134ed462851fd5f754c8c3cbb88d"}, ] [[package]] name = "kiwisolver" -version = "1.4.5" +version = "1.5.0" description = "A fast implementation of the Cassowary constraint solver" optional = false -python-versions = ">=3.7" -files = [ - {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af"}, - {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3"}, - {file = "kiwisolver-1.4.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b"}, - {file = "kiwisolver-1.4.5-cp310-cp310-win32.whl", hash = "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238"}, - {file = "kiwisolver-1.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276"}, - {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5"}, - {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90"}, - {file = "kiwisolver-1.4.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f"}, - {file = "kiwisolver-1.4.5-cp311-cp311-win32.whl", hash = "sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac"}, - {file = "kiwisolver-1.4.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355"}, - {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a"}, - {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192"}, - {file = "kiwisolver-1.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a"}, - {file = "kiwisolver-1.4.5-cp312-cp312-win32.whl", hash = "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20"}, - {file = "kiwisolver-1.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-win32.whl", hash = "sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-win_amd64.whl", hash = "sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a"}, - {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71"}, - {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93"}, - {file = "kiwisolver-1.4.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250"}, - {file = "kiwisolver-1.4.5-cp38-cp38-win32.whl", hash = "sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e"}, - {file = "kiwisolver-1.4.5-cp38-cp38-win_amd64.whl", hash = "sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced"}, - {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d"}, - {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9"}, - {file = "kiwisolver-1.4.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77"}, - {file = "kiwisolver-1.4.5-cp39-cp39-win32.whl", hash = "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f"}, - {file = "kiwisolver-1.4.5-cp39-cp39-win_amd64.whl", hash = "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee"}, - {file = "kiwisolver-1.4.5.tar.gz", hash = "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec"}, +python-versions = ">=3.10" +files = [ + {file = "kiwisolver-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:32cc0a5365239a6ea0c6ed461e8838d053b57e397443c0ca894dcc8e388d4374"}, + {file = "kiwisolver-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cc0b66c1eec9021353a4b4483afb12dfd50e3669ffbb9152d6842eb34c7e29fd"}, + {file = "kiwisolver-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:86e0287879f75621ae85197b0877ed2f8b7aa57b511c7331dce2eb6f4de7d476"}, + {file = "kiwisolver-1.5.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:62f59da443c4f4849f73a51a193b1d9d258dcad0c41bc4d1b8fb2bcc04bfeb22"}, + {file = "kiwisolver-1.5.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9190426b7aa26c5229501fa297b8d0653cfd3f5a36f7990c264e157cbf886b3b"}, + {file = "kiwisolver-1.5.0-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c8277104ded0a51e699c8c3aff63ce2c56d4ed5519a5f73e0fd7057f959a2b9e"}, + {file = "kiwisolver-1.5.0-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8f9baf6f0a6e7571c45c8863010b45e837c3ee1c2c77fcd6ef423be91b21fedb"}, + {file = "kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cff8e5383db4989311f99e814feeb90c4723eb4edca425b9d5d9c3fefcdd9537"}, + {file = "kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ebae99ed6764f2b5771c522477b311be313e8841d2e0376db2b10922daebbba4"}, + {file = "kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:d5cd5189fc2b6a538b75ae45433140c4823463918f7b1617c31e68b085c0022c"}, + {file = "kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f42c23db5d1521218a3276bb08666dcb662896a0be7347cba864eca45ff64ede"}, + {file = "kiwisolver-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:94eff26096eb5395136634622515b234ecb6c9979824c1f5004c6e3c3c85ccd2"}, + {file = "kiwisolver-1.5.0-cp310-cp310-win_arm64.whl", hash = "sha256:dd952e03bfbb096cfe2dd35cd9e00f269969b67536cb4370994afc20ff2d0875"}, + {file = "kiwisolver-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9eed0f7edbb274413b6ee781cca50541c8c0facd3d6fd289779e494340a2b85c"}, + {file = "kiwisolver-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c4923e404d6bcd91b6779c009542e5647fef32e4a5d75e115e3bbac6f2335eb"}, + {file = "kiwisolver-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0df54df7e686afa55e6f21fb86195224a6d9beb71d637e8d7920c95cf0f89aac"}, + {file = "kiwisolver-1.5.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2517e24d7315eb51c10664cdb865195df38ab74456c677df67bb47f12d088a27"}, + {file = "kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff710414307fefa903e0d9bdf300972f892c23477829f49504e59834f4195398"}, + {file = "kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6176c1811d9d5a04fa391c490cc44f451e240697a16977f11c6f722efb9041db"}, + {file = "kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50847dca5d197fcbd389c805aa1a1cf32f25d2e7273dc47ab181a517666b68cc"}, + {file = "kiwisolver-1.5.0-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:01808c6d15f4c3e8559595d6d1fe6411c68e4a3822b4b9972b44473b24f4e679"}, + {file = "kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f1f9f4121ec58628c96baa3de1a55a4e3a333c5102c8e94b64e23bf7b2083309"}, + {file = "kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b7d335370ae48a780c6e6a6bbfa97342f563744c39c35562f3f367665f5c1de2"}, + {file = "kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:800ee55980c18545af444d93fdd60c56b580db5cc54867d8cbf8a1dc0829938c"}, + {file = "kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c438f6ca858697c9ab67eb28246c92508af972e114cac34e57a6d4ba17a3ac08"}, + {file = "kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8c63c91f95173f9c2a67c7c526b2cea976828a0e7fced9cdcead2802dc10f8a4"}, + {file = "kiwisolver-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:beb7f344487cdcb9e1efe4b7a29681b74d34c08f0043a327a74da852a6749e7b"}, + {file = "kiwisolver-1.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:ad4ae4ffd1ee9cd11357b4c66b612da9888f4f4daf2f36995eda64bd45370cac"}, + {file = "kiwisolver-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4e9750bc21b886308024f8a54ccb9a2cc38ac9fa813bf4348434e3d54f337ff9"}, + {file = "kiwisolver-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:72ec46b7eba5b395e0a7b63025490d3214c11013f4aacb4f5e8d6c3041829588"}, + {file = "kiwisolver-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ed3a984b31da7481b103f68776f7128a89ef26ed40f4dc41a2223cda7fb24819"}, + {file = "kiwisolver-1.5.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb5136fb5352d3f422df33f0c879a1b0c204004324150cc3b5e3c4f310c9049f"}, + {file = "kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2af221f268f5af85e776a73d62b0845fc8baf8ef0abfae79d29c77d0e776aaf"}, + {file = "kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b0f172dc8ffaccb8522d7c5d899de00133f2f1ca7b0a49b7da98e901de87bf2d"}, + {file = "kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6ab8ba9152203feec73758dad83af9a0bbe05001eb4639e547207c40cfb52083"}, + {file = "kiwisolver-1.5.0-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:cdee07c4d7f6d72008d3f73b9bf027f4e11550224c7c50d8df1ae4a37c1402a6"}, + {file = "kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7c60d3c9b06fb23bd9c6139281ccbdc384297579ae037f08ae90c69f6845c0b1"}, + {file = "kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e315e5ec90d88e140f57696ff85b484ff68bb311e36f2c414aa4286293e6dee0"}, + {file = "kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:1465387ac63576c3e125e5337a6892b9e99e0627d52317f3ca79e6930d889d15"}, + {file = "kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:530a3fd64c87cffa844d4b6b9768774763d9caa299e9b75d8eca6a4423b31314"}, + {file = "kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1d9daea4ea6b9be74fe2f01f7fbade8d6ffab263e781274cffca0dba9be9eec9"}, + {file = "kiwisolver-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:f18c2d9782259a6dc132fdc7a63c168cbc74b35284b6d75c673958982a378384"}, + {file = "kiwisolver-1.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:f7c7553b13f69c1b29a5bde08ddc6d9d0c8bfb84f9ed01c30db25944aeb852a7"}, + {file = "kiwisolver-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:fd40bb9cd0891c4c3cb1ddf83f8bbfa15731a248fdc8162669405451e2724b09"}, + {file = "kiwisolver-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c0e1403fd7c26d77c1f03e096dc58a5c726503fa0db0456678b8668f76f521e3"}, + {file = "kiwisolver-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dda366d548e89a90d88a86c692377d18d8bd64b39c1fb2b92cb31370e2896bbd"}, + {file = "kiwisolver-1.5.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:332b4f0145c30b5f5ad9374881133e5aa64320428a57c2c2b61e9d891a51c2f3"}, + {file = "kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c50b89ffd3e1a911c69a1dd3de7173c0cd10b130f56222e57898683841e4f96"}, + {file = "kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4db576bb8c3ef9365f8b40fe0f671644de6736ae2c27a2c62d7d8a1b4329f099"}, + {file = "kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0b85aad90cea8ac6797a53b5d5f2e967334fa4d1149f031c4537569972596cb8"}, + {file = "kiwisolver-1.5.0-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:d36ca54cb4c6c4686f7cbb7b817f66f5911c12ddb519450bbe86707155028f87"}, + {file = "kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:38f4a703656f493b0ad185211ccfca7f0386120f022066b018eb5296d8613e23"}, + {file = "kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3ac2360e93cb41be81121755c6462cff3beaa9967188c866e5fce5cf13170859"}, + {file = "kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c95cab08d1965db3d84a121f1c7ce7479bdd4072c9b3dafd8fecce48a2e6b902"}, + {file = "kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fc20894c3d21194d8041a28b65622d5b86db786da6e3cfe73f0c762951a61167"}, + {file = "kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7a32f72973f0f950c1920475d5c5ea3d971b81b6f0ec53b8d0a956cc965f22e0"}, + {file = "kiwisolver-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bf3acf1419fa93064a4c2189ac0b58e3be7872bf6ee6177b0d4c63dc4cea276"}, + {file = "kiwisolver-1.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:fa8eb9ecdb7efb0b226acec134e0d709e87a909fa4971a54c0c4f6e88635484c"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:db485b3847d182b908b483b2ed133c66d88d49cacf98fd278fadafe11b4478d1"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:be12f931839a3bdfe28b584db0e640a65a8bcbc24560ae3fdb025a449b3d754e"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:16b85d37c2cbb3253226d26e64663f755d88a03439a9c47df6246b35defbdfb7"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4432b835675f0ea7414aab3d37d119f7226d24869b7a829caeab49ebda407b0c"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b0feb50971481a2cc44d94e88bdb02cdd497618252ae226b8eb1201b957e368"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56fa888f10d0f367155e76ce849fa1166fc9730d13bd2d65a2aa13b6f5424489"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:940dda65d5e764406b9fb92761cbf462e4e63f712ab60ed98f70552e496f3bf1"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-manylinux_2_39_riscv64.whl", hash = "sha256:89fc958c702ee9a745e4700378f5d23fddbc46ff89e8fdbf5395c24d5c1452a3"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9027d773c4ff81487181a925945743413f6069634d0b122d0b37684ccf4f1e18"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:5b233ea3e165e43e35dba1d2b8ecc21cf070b45b65ae17dd2747d2713d942021"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ce9bf03dad3b46408c08649c6fbd6ca28a9fce0eb32fdfffa6775a13103b5310"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:fc4d3f1fb9ca0ae9f97b095963bc6326f1dbfd3779d6679a1e016b9baaa153d3"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f443b4825c50a51ee68585522ab4a1d1257fac65896f282b4c6763337ac9f5d2"}, + {file = "kiwisolver-1.5.0-cp313-cp313t-win_arm64.whl", hash = "sha256:893ff3a711d1b515ba9da14ee090519bad4610ed1962fbe298a434e8c5f8db53"}, + {file = "kiwisolver-1.5.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8df31fe574b8b3993cc61764f40941111b25c2d9fea13d3ce24a49907cd2d615"}, + {file = "kiwisolver-1.5.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1d49a49ac4cbfb7c1375301cd1ec90169dfeae55ff84710d782260ce77a75a02"}, + {file = "kiwisolver-1.5.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0cbe94b69b819209a62cb27bdfa5dc2a8977d8de2f89dfd97ba4f53ed3af754e"}, + {file = "kiwisolver-1.5.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:80aa065ffd378ff784822a6d7c3212f2d5f5e9c3589614b5c228b311fd3063ac"}, + {file = "kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e7f886f47ab881692f278ae901039a234e4025a68e6dfab514263a0b1c4ae05"}, + {file = "kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5060731cc3ed12ca3a8b57acd4aeca5bbc2f49216dd0bec1650a1acd89486bcd"}, + {file = "kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7a4aa69609f40fce3cbc3f87b2061f042eee32f94b8f11db707b66a26461591a"}, + {file = "kiwisolver-1.5.0-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:d168fda2dbff7b9b5f38e693182d792a938c31db4dac3a80a4888de603c99554"}, + {file = "kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:413b820229730d358efd838ecbab79902fe97094565fdc80ddb6b0a18c18a581"}, + {file = "kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5124d1ea754509b09e53738ec185584cc609aae4a3b510aaf4ed6aa047ef9303"}, + {file = "kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e4415a8db000bf49a6dd1c478bf70062eaacff0f462b92b0ba68791a905861f9"}, + {file = "kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d618fd27420381a4f6044faa71f46d8bfd911bd077c555f7138ed88729bfbe79"}, + {file = "kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5092eb5b1172947f57d6ea7d89b2f29650414e4293c47707eb499ec07a0ac796"}, + {file = "kiwisolver-1.5.0-cp314-cp314-win_amd64.whl", hash = "sha256:d76e2d8c75051d58177e762164d2e9ab92886534e3a12e795f103524f221dd8e"}, + {file = "kiwisolver-1.5.0-cp314-cp314-win_arm64.whl", hash = "sha256:fa6248cd194edff41d7ea9425ced8ca3a6f838bfb295f6f1d6e6bb694a8518df"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:d1ffeb80b5676463d7a7d56acbe8e37a20ce725570e09549fe738e02ca6b7e1e"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:bc4d8e252f532ab46a1de9349e2d27b91fce46736a9eedaa37beaca66f574ed4"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6783e069732715ad0c3ce96dbf21dbc2235ab0593f2baf6338101f70371f4028"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e7c4c09a490dc4d4a7f8cbee56c606a320f9dc28cf92a7157a39d1ce7676a657"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a075bd7bd19c70cf67c8badfa36cf7c5d8de3c9ddb8420c51e10d9c50e94920"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bdd3e53429ff02aa319ba59dfe4ceeec345bf46cf180ec2cf6fd5b942e7975e9"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cdcb35dc9d807259c981a85531048ede628eabcffb3239adf3d17463518992d"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:70d593af6a6ca332d1df73d519fddb5148edb15cd90d5f0155e3746a6d4fcc65"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:377815a8616074cabbf3f53354e1d040c35815a134e01d7614b7692e4bf8acfa"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0255a027391d52944eae1dbb5d4cc5903f57092f3674e8e544cdd2622826b3f0"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:012b1eb16e28718fa782b5e61dc6f2da1f0792ca73bd05d54de6cb9561665fc9"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0e3aafb33aed7479377e5e9a82e9d4bf87063741fc99fc7ae48b0f16e32bdd6f"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e7a116ae737f0000343218c4edf5bd45893bfeaff0993c0b215d7124c9f77646"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:1dd9b0b119a350976a6d781e7278ec7aca0b201e1a9e2d23d9804afecb6ca681"}, + {file = "kiwisolver-1.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:58f812017cd2985c21fbffb4864d59174d4903dd66fa23815e74bbc7a0e2dd57"}, + {file = "kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_10_13_x86_64.whl", hash = "sha256:5ae8e62c147495b01a0f4765c878e9bfdf843412446a247e28df59936e99e797"}, + {file = "kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f6764a4ccab3078db14a632420930f6186058750df066b8ea2a7106df91d3203"}, + {file = "kiwisolver-1.5.0-graalpy312-graalpy250_312_native-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c31c13da98624f957b0fb1b5bae5383b2333c2c3f6793d9825dd5ce79b525cb7"}, + {file = "kiwisolver-1.5.0-graalpy312-graalpy250_312_native-win_amd64.whl", hash = "sha256:1f1489f769582498610e015a8ef2d36f28f505ab3096d0e16b4858a9ec214f57"}, + {file = "kiwisolver-1.5.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:295d9ffe712caa9f8a3081de8d32fc60191b4b51c76f02f951fd8407253528f4"}, + {file = "kiwisolver-1.5.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:51e8c4084897de9f05898c2c2a39af6318044ae969d46ff7a34ed3f96274adca"}, + {file = "kiwisolver-1.5.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b83af57bdddef03c01a9138034c6ff03181a3028d9a1003b301eb1a55e161a3f"}, + {file = "kiwisolver-1.5.0-pp310-pypy310_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf4679a3d71012a7c2bf360e5cd878fbd5e4fcac0896b56393dec239d81529ed"}, + {file = "kiwisolver-1.5.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:41024ed50e44ab1a60d3fe0a9d15a4ccc9f5f2b1d814ff283c8d01134d5b81bc"}, + {file = "kiwisolver-1.5.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ec4c85dc4b687c7f7f15f553ff26a98bfe8c58f5f7f0ac8905f0ba4c7be60232"}, + {file = "kiwisolver-1.5.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:12e91c215a96e39f57989c8912ae761286ac5a9584d04030ceb3368a357f017a"}, + {file = "kiwisolver-1.5.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:be4a51a55833dc29ab5d7503e7bcb3b3af3402d266018137127450005cdfe737"}, + {file = "kiwisolver-1.5.0-pp311-pypy311_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:daae526907e262de627d8f70058a0f64acc9e2641c164c99c8f594b34a799a16"}, + {file = "kiwisolver-1.5.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:59cd8683f575d96df5bb48f6add94afc055012c29e28124fcae2b63661b9efb1"}, + {file = "kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a"}, ] [[package]] name = "lxml" -version = "5.1.0" +version = "6.1.1" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "lxml-5.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:704f5572ff473a5f897745abebc6df40f22d4133c1e0a1f124e4f2bd3330ff7e"}, - {file = "lxml-5.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9d3c0f8567ffe7502d969c2c1b809892dc793b5d0665f602aad19895f8d508da"}, - {file = "lxml-5.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5fcfbebdb0c5d8d18b84118842f31965d59ee3e66996ac842e21f957eb76138c"}, - {file = "lxml-5.1.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f37c6d7106a9d6f0708d4e164b707037b7380fcd0b04c5bd9cae1fb46a856fb"}, - {file = "lxml-5.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2befa20a13f1a75c751f47e00929fb3433d67eb9923c2c0b364de449121f447c"}, - {file = "lxml-5.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22b7ee4c35f374e2c20337a95502057964d7e35b996b1c667b5c65c567d2252a"}, - {file = "lxml-5.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bf8443781533b8d37b295016a4b53c1494fa9a03573c09ca5104550c138d5c05"}, - {file = "lxml-5.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:82bddf0e72cb2af3cbba7cec1d2fd11fda0de6be8f4492223d4a268713ef2147"}, - {file = "lxml-5.1.0-cp310-cp310-win32.whl", hash = "sha256:b66aa6357b265670bb574f050ffceefb98549c721cf28351b748be1ef9577d93"}, - {file = "lxml-5.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:4946e7f59b7b6a9e27bef34422f645e9a368cb2be11bf1ef3cafc39a1f6ba68d"}, - {file = "lxml-5.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:14deca1460b4b0f6b01f1ddc9557704e8b365f55c63070463f6c18619ebf964f"}, - {file = "lxml-5.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ed8c3d2cd329bf779b7ed38db176738f3f8be637bb395ce9629fc76f78afe3d4"}, - {file = "lxml-5.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:436a943c2900bb98123b06437cdd30580a61340fbdb7b28aaf345a459c19046a"}, - {file = "lxml-5.1.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:acb6b2f96f60f70e7f34efe0c3ea34ca63f19ca63ce90019c6cbca6b676e81fa"}, - {file = "lxml-5.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af8920ce4a55ff41167ddbc20077f5698c2e710ad3353d32a07d3264f3a2021e"}, - {file = "lxml-5.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cfced4a069003d8913408e10ca8ed092c49a7f6cefee9bb74b6b3e860683b45"}, - {file = "lxml-5.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9e5ac3437746189a9b4121db2a7b86056ac8786b12e88838696899328fc44bb2"}, - {file = "lxml-5.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f4c9bda132ad108b387c33fabfea47866af87f4ea6ffb79418004f0521e63204"}, - {file = "lxml-5.1.0-cp311-cp311-win32.whl", hash = "sha256:bc64d1b1dab08f679fb89c368f4c05693f58a9faf744c4d390d7ed1d8223869b"}, - {file = "lxml-5.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:a5ab722ae5a873d8dcee1f5f45ddd93c34210aed44ff2dc643b5025981908cda"}, - {file = "lxml-5.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9aa543980ab1fbf1720969af1d99095a548ea42e00361e727c58a40832439114"}, - {file = "lxml-5.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6f11b77ec0979f7e4dc5ae081325a2946f1fe424148d3945f943ceaede98adb8"}, - {file = "lxml-5.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a36c506e5f8aeb40680491d39ed94670487ce6614b9d27cabe45d94cd5d63e1e"}, - {file = "lxml-5.1.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f643ffd2669ffd4b5a3e9b41c909b72b2a1d5e4915da90a77e119b8d48ce867a"}, - {file = "lxml-5.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16dd953fb719f0ffc5bc067428fc9e88f599e15723a85618c45847c96f11f431"}, - {file = "lxml-5.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16018f7099245157564d7148165132c70adb272fb5a17c048ba70d9cc542a1a1"}, - {file = "lxml-5.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:82cd34f1081ae4ea2ede3d52f71b7be313756e99b4b5f829f89b12da552d3aa3"}, - {file = "lxml-5.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:19a1bc898ae9f06bccb7c3e1dfd73897ecbbd2c96afe9095a6026016e5ca97b8"}, - {file = "lxml-5.1.0-cp312-cp312-win32.whl", hash = "sha256:13521a321a25c641b9ea127ef478b580b5ec82aa2e9fc076c86169d161798b01"}, - {file = "lxml-5.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:1ad17c20e3666c035db502c78b86e58ff6b5991906e55bdbef94977700c72623"}, - {file = "lxml-5.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:24ef5a4631c0b6cceaf2dbca21687e29725b7c4e171f33a8f8ce23c12558ded1"}, - {file = "lxml-5.1.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d2900b7f5318bc7ad8631d3d40190b95ef2aa8cc59473b73b294e4a55e9f30f"}, - {file = "lxml-5.1.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:601f4a75797d7a770daed8b42b97cd1bb1ba18bd51a9382077a6a247a12aa38d"}, - {file = "lxml-5.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4b68c961b5cc402cbd99cca5eb2547e46ce77260eb705f4d117fd9c3f932b95"}, - {file = "lxml-5.1.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:afd825e30f8d1f521713a5669b63657bcfe5980a916c95855060048b88e1adb7"}, - {file = "lxml-5.1.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:262bc5f512a66b527d026518507e78c2f9c2bd9eb5c8aeeb9f0eb43fcb69dc67"}, - {file = "lxml-5.1.0-cp36-cp36m-win32.whl", hash = "sha256:e856c1c7255c739434489ec9c8aa9cdf5179785d10ff20add308b5d673bed5cd"}, - {file = "lxml-5.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:c7257171bb8d4432fe9d6fdde4d55fdbe663a63636a17f7f9aaba9bcb3153ad7"}, - {file = "lxml-5.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b9e240ae0ba96477682aa87899d94ddec1cc7926f9df29b1dd57b39e797d5ab5"}, - {file = "lxml-5.1.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a96f02ba1bcd330807fc060ed91d1f7a20853da6dd449e5da4b09bfcc08fdcf5"}, - {file = "lxml-5.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e3898ae2b58eeafedfe99e542a17859017d72d7f6a63de0f04f99c2cb125936"}, - {file = "lxml-5.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61c5a7edbd7c695e54fca029ceb351fc45cd8860119a0f83e48be44e1c464862"}, - {file = "lxml-5.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3aeca824b38ca78d9ee2ab82bd9883083d0492d9d17df065ba3b94e88e4d7ee6"}, - {file = "lxml-5.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8f52fe6859b9db71ee609b0c0a70fea5f1e71c3462ecf144ca800d3f434f0764"}, - {file = "lxml-5.1.0-cp37-cp37m-win32.whl", hash = "sha256:d42e3a3fc18acc88b838efded0e6ec3edf3e328a58c68fbd36a7263a874906c8"}, - {file = "lxml-5.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:eac68f96539b32fce2c9b47eb7c25bb2582bdaf1bbb360d25f564ee9e04c542b"}, - {file = "lxml-5.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ae15347a88cf8af0949a9872b57a320d2605ae069bcdf047677318bc0bba45b1"}, - {file = "lxml-5.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c26aab6ea9c54d3bed716b8851c8bfc40cb249b8e9880e250d1eddde9f709bf5"}, - {file = "lxml-5.1.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:342e95bddec3a698ac24378d61996b3ee5ba9acfeb253986002ac53c9a5f6f84"}, - {file = "lxml-5.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:725e171e0b99a66ec8605ac77fa12239dbe061482ac854d25720e2294652eeaa"}, - {file = "lxml-5.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d184e0d5c918cff04cdde9dbdf9600e960161d773666958c9d7b565ccc60c45"}, - {file = "lxml-5.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:98f3f020a2b736566c707c8e034945c02aa94e124c24f77ca097c446f81b01f1"}, - {file = "lxml-5.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6d48fc57e7c1e3df57be5ae8614bab6d4e7b60f65c5457915c26892c41afc59e"}, - {file = "lxml-5.1.0-cp38-cp38-win32.whl", hash = "sha256:7ec465e6549ed97e9f1e5ed51c657c9ede767bc1c11552f7f4d022c4df4a977a"}, - {file = "lxml-5.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:b21b4031b53d25b0858d4e124f2f9131ffc1530431c6d1321805c90da78388d1"}, - {file = "lxml-5.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:52427a7eadc98f9e62cb1368a5079ae826f94f05755d2d567d93ee1bc3ceb354"}, - {file = "lxml-5.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6a2a2c724d97c1eb8cf966b16ca2915566a4904b9aad2ed9a09c748ffe14f969"}, - {file = "lxml-5.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:843b9c835580d52828d8f69ea4302537337a21e6b4f1ec711a52241ba4a824f3"}, - {file = "lxml-5.1.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9b99f564659cfa704a2dd82d0684207b1aadf7d02d33e54845f9fc78e06b7581"}, - {file = "lxml-5.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f8b0c78e7aac24979ef09b7f50da871c2de2def043d468c4b41f512d831e912"}, - {file = "lxml-5.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9bcf86dfc8ff3e992fed847c077bd875d9e0ba2fa25d859c3a0f0f76f07f0c8d"}, - {file = "lxml-5.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:49a9b4af45e8b925e1cd6f3b15bbba2c81e7dba6dce170c677c9cda547411e14"}, - {file = "lxml-5.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:280f3edf15c2a967d923bcfb1f8f15337ad36f93525828b40a0f9d6c2ad24890"}, - {file = "lxml-5.1.0-cp39-cp39-win32.whl", hash = "sha256:ed7326563024b6e91fef6b6c7a1a2ff0a71b97793ac33dbbcf38f6005e51ff6e"}, - {file = "lxml-5.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:8d7b4beebb178e9183138f552238f7e6613162a42164233e2bda00cb3afac58f"}, - {file = "lxml-5.1.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9bd0ae7cc2b85320abd5e0abad5ccee5564ed5f0cc90245d2f9a8ef330a8deae"}, - {file = "lxml-5.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8c1d679df4361408b628f42b26a5d62bd3e9ba7f0c0e7969f925021554755aa"}, - {file = "lxml-5.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2ad3a8ce9e8a767131061a22cd28fdffa3cd2dc193f399ff7b81777f3520e372"}, - {file = "lxml-5.1.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:304128394c9c22b6569eba2a6d98392b56fbdfbad58f83ea702530be80d0f9df"}, - {file = "lxml-5.1.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d74fcaf87132ffc0447b3c685a9f862ffb5b43e70ea6beec2fb8057d5d2a1fea"}, - {file = "lxml-5.1.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:8cf5877f7ed384dabfdcc37922c3191bf27e55b498fecece9fd5c2c7aaa34c33"}, - {file = "lxml-5.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:877efb968c3d7eb2dad540b6cabf2f1d3c0fbf4b2d309a3c141f79c7e0061324"}, - {file = "lxml-5.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f14a4fb1c1c402a22e6a341a24c1341b4a3def81b41cd354386dcb795f83897"}, - {file = "lxml-5.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:25663d6e99659544ee8fe1b89b1a8c0aaa5e34b103fab124b17fa958c4a324a6"}, - {file = "lxml-5.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8b9f19df998761babaa7f09e6bc169294eefafd6149aaa272081cbddc7ba4ca3"}, - {file = "lxml-5.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e53d7e6a98b64fe54775d23a7c669763451340c3d44ad5e3a3b48a1efbdc96f"}, - {file = "lxml-5.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c3cd1fc1dc7c376c54440aeaaa0dcc803d2126732ff5c6b68ccd619f2e64be4f"}, - {file = "lxml-5.1.0.tar.gz", hash = "sha256:3eea6ed6e6c918e468e693c41ef07f3c3acc310b70ddd9cc72d9ef84bc9564ca"}, + {file = "lxml-6.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:09dd5b7075dc2f7709654a46543ba1ea3c2e217b2ed8fbd413a8a945a0f40f60"}, + {file = "lxml-6.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f6ac4ef4d82dff54670227a69c67782ae0b811b5cf6b17954f1e8f7502fc0d1d"}, + {file = "lxml-6.1.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:556e94a63c9b04716f8e4de2abb65775061f846e89331b6c5be79183a24f98ea"}, + {file = "lxml-6.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5c6bf403fbb3b3e348a561a5f4f0b9961835657981c802a1df03653eef8a9074"}, + {file = "lxml-6.1.1-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1dde6131244bba38a17c745836ba190bc753fd73c9291666287fd0a3fa3dcf30"}, + {file = "lxml-6.1.1-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:98fc784c2c1440667aeedf8465bdfe10208acf0ead656a2c68627299f546b315"}, + {file = "lxml-6.1.1-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:add8cf6ddf9a65116119a28ece0f7886e30af27ba724a7594305f1d1b58a92a1"}, + {file = "lxml-6.1.1-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:cf9d57306d848218f3601fee7601fab1a327c942d56e2e97610583cb4dd74206"}, + {file = "lxml-6.1.1-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:88136950da4d13c318bde414ce10219931937851327f44328f2df4d2c4614067"}, + {file = "lxml-6.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cecdd5dfdc87b1fd87dbf81d4b037a544f47f4c744200a67013771682d67686a"}, + {file = "lxml-6.1.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:cd312b9692e831d2ffcad61eab31d91d4b4655a962e61de8fb410472cbcd37aa"}, + {file = "lxml-6.1.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:5b7328b46d49fc9477d91ae8f6d55340347d827b7734ba3ea33faae0efef1383"}, + {file = "lxml-6.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:37a58976370f36d9329d118ad0b953c5aeb9119ac9c6a4e258942a225d0573a1"}, + {file = "lxml-6.1.1-cp310-cp310-win32.whl", hash = "sha256:cea3f4c1af79af13cdb2da0c028111d8f8522d4f22a000c82385535f24e5cf3a"}, + {file = "lxml-6.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:3abf332af33a74288675d936fe861fd4344da0dd6622193fbc4f2bfbb35536b5"}, + {file = "lxml-6.1.1-cp310-cp310-win_arm64.whl", hash = "sha256:8dadbe5b217ff35b6a8d16610dd710219b59b76d13f0e3f0d9f36786206e4485"}, + {file = "lxml-6.1.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:53b7d2b7a10b1c35c0a5e21e9224accf60c1bbfba523990732e521b2b73adef2"}, + {file = "lxml-6.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ff3f333630ab480244a1bff72043e511a91eb22e7595dead8653ee5612dd8f3d"}, + {file = "lxml-6.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a4bbea04c97f6d78a48e3fbc1cb9116d2780b1b39e03a23f6eb9b603fd61f510"}, + {file = "lxml-6.1.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:db1d75f6617a49c1c01bc7023713e0ff59ab32c9579ae62a7674c0e34f3b0b0a"}, + {file = "lxml-6.1.1-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a12689be69a28ddaa0ab99a5a1137da2afd5f8f16df7b5680b66f616d3eda1d"}, + {file = "lxml-6.1.1-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b73c339ae29b90fd2d06e58ebd555a751bde9cd6bbd36cc0281b9a2c94e9d8"}, + {file = "lxml-6.1.1-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:752d3bbfe874715ccd0aec7f88d7fc623c0f1fd7aa7b3238a084e017bad2a009"}, + {file = "lxml-6.1.1-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:6b1761fbf9ec984e2e9d9c589ef5f5fd684b7c19f92aadd567a26c5224958db6"}, + {file = "lxml-6.1.1-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d680fbcb768404c601ecb43519ecd8461f6954cb11c06a78962f666832ccfca8"}, + {file = "lxml-6.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:162af1091cd785f2f27e62d3547ae9bc58ec5c86dd314d67021fd02463708d83"}, + {file = "lxml-6.1.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:e9308ff8241c532df3f3e570f9a5aeed6c853f888512ba4b75638d7c11c95ef6"}, + {file = "lxml-6.1.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:5f6994074ebae6ffb04447268e37dc16edc304f9859cf91acb86e0af6c1b395c"}, + {file = "lxml-6.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:80c2dfadb855da477cf73373ad29a333535dedb9b12bad02c9814c8e2b43bf08"}, + {file = "lxml-6.1.1-cp311-cp311-win32.whl", hash = "sha256:30a89d3ac8faec007453fb541f3f46807eeec88edd5826f6e3fe001752a2c621"}, + {file = "lxml-6.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:abbefa31eee84842140f67acef1c828e28bba8bbf0c3bc6e5492a9af88152c28"}, + {file = "lxml-6.1.1-cp311-cp311-win_arm64.whl", hash = "sha256:dcb292aa7fe485ceff7af4f92e46c5af397daec5dff64871a528f0fc47a3cc5b"}, + {file = "lxml-6.1.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:104c09bda8d2a562824c0e319d0768ce26a779b7601e0931d33b09b53c392ef7"}, + {file = "lxml-6.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:25c6997a9a534e016695a0ba06b2f07945de682731ff01065b6d5a4474179da1"}, + {file = "lxml-6.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c921ba5c51e4e9f63b8b00267d06566e1f63407408a0496da2d1d0bfc819c7fc"}, + {file = "lxml-6.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:54a7f95e4de5fb94e2f9f4b9055c6ba33bf3d628fd77a1d647c5923caa2cdcdc"}, + {file = "lxml-6.1.1-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f2ec43df44b1f76249ee0a615334f9b5b060e1c8bd90e706dad2d14d02f383"}, + {file = "lxml-6.1.1-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:70ef8a7e102a1508f8121aae5b0867abd663f72c14f0a9c937e6554cb4587b7b"}, + {file = "lxml-6.1.1-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ebe6af670449830d6d9b752c256a983291c766a1365ba5d5460048f9e33a7818"}, + {file = "lxml-6.1.1-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:27acc820660aaffa4f7c087f29120e12980f7779d56d8492d263170111284740"}, + {file = "lxml-6.1.1-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:1db753c9115ec7100d073b744d17e25e88a8f90f5c39b2f5dd878149af59671f"}, + {file = "lxml-6.1.1-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c4f469aebd783bb741c2ecb2a681008fd26bfe5c16a9a72ed5467f834e810df2"}, + {file = "lxml-6.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:766b010012d59470072c1816b5b6c69f1d243e5db36ea5968e94accf430a4635"}, + {file = "lxml-6.1.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b8d812c6011c08b8111a15e54dd990b8923692d80adf35488bee34026c35accf"}, + {file = "lxml-6.1.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:fe0306bd29505a9177aac19f1877174b0e7422c222a59f70b2cd41633448c3dc"}, + {file = "lxml-6.1.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:5ba186ad207446c65d3bb3d3e0412b032b1d9f595e59861e2354798c5703d955"}, + {file = "lxml-6.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aa366a1e55b8ebfe8ca8ddc3cfe75c8ebade181aeb0f661d0cb05986b647f72a"}, + {file = "lxml-6.1.1-cp312-cp312-win32.whl", hash = "sha256:126c93f7f56f0eda92f6d8c619edc463a4f23d9252f1c9d0405a76f25fa9f11a"}, + {file = "lxml-6.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:26e6eda8d38c1fcab1090dd196ee87cbd13788e531937610e2589085de074e77"}, + {file = "lxml-6.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:6540377fbd53fe1b629172288c464fb18db11ce1fa7dc15891da10aa9dcc3e7f"}, + {file = "lxml-6.1.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:68a9198d0fc122d14bb76837de9aa80cf84caed990b5b237f532ed87d3706736"}, + {file = "lxml-6.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7d47866cb32fb503450b6edc9df355d10dc49836af2e89901bd6ac6b0896d9d9"}, + {file = "lxml-6.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb7c9811bfaa8b1ed5ed319f5d370dfbcaa59d52ea64be2a5a85e18195930354"}, + {file = "lxml-6.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:762ff394d5bd56da0cf034a23dcce4e13923f15321a2adfa2ac00201dc6d3fca"}, + {file = "lxml-6.1.1-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a088f287f7d8275a33c07f2cac6c50b9319309a0200a39e7e75d80c707723099"}, + {file = "lxml-6.1.1-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e902da4b04e6b52e5893900d4b8ab46068f75f3561f01bf1080957f9fd932ed6"}, + {file = "lxml-6.1.1-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1d4962d4c66bf830a7e59ed6cfc17d148149898a3aefa8ec6e59763e6e3ed085"}, + {file = "lxml-6.1.1-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:581d4c8ae690a6609e64862dd6b7c2489635c2d13907fc2b20f2bc200ff1d21e"}, + {file = "lxml-6.1.1-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:876e1ff5930ed8bf295ec5ef9a8155e9b6b1876bbf1deed8b3a8069311875a8f"}, + {file = "lxml-6.1.1-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9eb9b5a968f6e0f6d640092a567e14529ff8cea2e29d00da6f78a79fa49f013c"}, + {file = "lxml-6.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:aa49e06d94aba782c6a02eecb7e507969e7e7a41b267f1b359bb35585f295d5b"}, + {file = "lxml-6.1.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:70cdfd80589d59e43e18005dd7244e8895e93db8ab6a620b7e23df5445a4e3d2"}, + {file = "lxml-6.1.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:aad9aa39483ed8ec44d6d2e59e5b98a0d80676ef0d92f44bfc374836111f62f5"}, + {file = "lxml-6.1.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:d49514be2f28d895c38cf9d2b72d7b9a07d00314519f456c0b50b53cfcf4c785"}, + {file = "lxml-6.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:47402e62c52ff5988c1e8c6c63177f5708bccf48e366dea4e3dcf1e645e04947"}, + {file = "lxml-6.1.1-cp313-cp313-win32.whl", hash = "sha256:3483644525531e1d5762b0c44a8e18b6efba321b6dcf8a8952de10b037618bca"}, + {file = "lxml-6.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:a10bd2fd62e8ce916ececb342f348f190724a098c1faa056fdfb2a22ad5e8660"}, + {file = "lxml-6.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:424aa57aca0897eb922aef34395bd1289b3b6f04e6bae20ea123c0c7e333cffc"}, + {file = "lxml-6.1.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:19b7ab10b210b0b3ad7985d9ac4eb66ab09a90b20fe6e2f7ba55d01a234345d0"}, + {file = "lxml-6.1.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:c08e5c694306507275f2290073350c4f32e383db15213b2c69e7ff39c1193840"}, + {file = "lxml-6.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:74a9717fd0d82effef5c2854f0d917231d5324b5a3eb7275c43ac9fa32f97a14"}, + {file = "lxml-6.1.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:efe0374196335f93b53269acd811b944f2e6bdc88e8894f214bd636455484909"}, + {file = "lxml-6.1.1-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac931cdc9442c1763b8a8f6cd62c0c938737eafc5be75eff88df55fc73bc0d00"}, + {file = "lxml-6.1.1-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:aee395f5d0927f947758b4ec119fd5fc8ec71f07a1c5c52077b30b04c0fa6955"}, + {file = "lxml-6.1.1-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9395002973c827b3ed67db77e6ec09f092919a587022174554096a269378fb13"}, + {file = "lxml-6.1.1-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:73bc2086f141224ebddb7fc5c6a36ca58b31b94b561e1dfe8e073e3270fad1e7"}, + {file = "lxml-6.1.1-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:3779def59032b81e44a5f70096ef6bf2082f8d901937dca354474ba09782e245"}, + {file = "lxml-6.1.1-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:86c89b9d55ebf820ad7c90bc533410f0d098054f293351f10603c0c46ff598f5"}, + {file = "lxml-6.1.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:19607c6bbff2a44cf3fe8250abccd20942d3462473e0a721d01d379ed017e462"}, + {file = "lxml-6.1.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:c6ed5141a5c7507cf3ee76bd363b0d6f801e3321adc35b5d825a23115faa5465"}, + {file = "lxml-6.1.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:62aeb7e85b5d60320b9d77eef2e773994e2c0ce10121b277e0a19804e1654a5a"}, + {file = "lxml-6.1.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:b1b963fd8f5caa68e99dfae060d54de1fe9cba899b8718b44a00cdca53c3e590"}, + {file = "lxml-6.1.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:63876be28efefa04a1df615b46770e82042cce445cfdce55160522f57b231ccb"}, + {file = "lxml-6.1.1-cp314-cp314-win32.whl", hash = "sha256:7f7a92e8583f06b1fd49d01158143b8461cfcd135dcb10ec807270a3051bd603"}, + {file = "lxml-6.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:b2d444f2e66624d68e9c6b211e28a76e22fff5fcabcfff4deac18b529b7d4137"}, + {file = "lxml-6.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:3fd9728a2735fda14f4e8235830c86b539e9661e849665bf926d3f867943b4bf"}, + {file = "lxml-6.1.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:787b2496d0dbe8cd180984e8d29e3a6f76e7ea34db781cb3bd55e4ba1ef8b4ee"}, + {file = "lxml-6.1.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:2c8daa471358dc2d6fcf02165e80ec68f77871a286df95bc5cc3816153b0fd2c"}, + {file = "lxml-6.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:acd7d70b64c0aae0c7922cca83d288a16f5f6da523637697872253415269baef"}, + {file = "lxml-6.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4f0dd2f01f9f8a89f565d000e03abcf0a13d692a346c8d22f628d49af098777a"}, + {file = "lxml-6.1.1-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b7e8a14c8634bf6f7a568634cb395305a6d964aeb5b7ee32248094bed3a7e2c"}, + {file = "lxml-6.1.1-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:86281fbdd6a8162756f8d603f37e3435bfa38043adb79c6dc6a2dfee065e7525"}, + {file = "lxml-6.1.1-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5d7152ec39ca7c402d8fb9bad86140a15b9503bd0c54484e3f1bbe3dd37ceca"}, + {file = "lxml-6.1.1-cp314-cp314t-manylinux_2_28_i686.whl", hash = "sha256:88d8cb75b9d82858497a5393e3c63cfbf03035225e4b35a49ed7ccb151e4dc0e"}, + {file = "lxml-6.1.1-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:f64ec5397ea6a41fc1b4af0380d79b44a755b5531dcaccd9940fb260dca93038"}, + {file = "lxml-6.1.1-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d34bbf07dbc7ca5970671b1512e928991fb5e9d95365636c9b2d8b4f53af405e"}, + {file = "lxml-6.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:17e0e18d4ad8adbd0399291bc44845b69d9dd68439a3cdebdf35ff902ec05072"}, + {file = "lxml-6.1.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:3ab541146f1f6968c462d6c2ac495148e8cdba2f8347700b2141b6ec5a75bf52"}, + {file = "lxml-6.1.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:2a0217714657e023ef4293500f65aa20fce6164c8fd6b08fa5bd4a859fb14b9b"}, + {file = "lxml-6.1.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:05a82eb6e1530a64f26225b55cbd178113bd0b5af1c2b625f25e5296742c26d2"}, + {file = "lxml-6.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9e36f163528fc50cbef305f02a5fd66d404edf7049cdaff211dbc2cba5a7013e"}, + {file = "lxml-6.1.1-cp314-cp314t-win32.whl", hash = "sha256:649dda677cf3bd6ac9ae14007ba0c824ded8ce5808b53fc7431d9140399118c1"}, + {file = "lxml-6.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:793033d6c5cdf33a573f910d9bea14ef8f5771820411d118da8e1182edb53d5e"}, + {file = "lxml-6.1.1-cp314-cp314t-win_arm64.whl", hash = "sha256:58bb955caba94e467d2a96da17660d2d704e0675894cba21ab8a775b8621fd1c"}, + {file = "lxml-6.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6689e828a94eee4f139408c337bb198e014724bb8a8c26d3cfac49d119ed69a6"}, + {file = "lxml-6.1.1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bdebcc8a75d38c7598dfb2c9ed852d7a9eb4a10d6e2d0764b919b802bf32ac88"}, + {file = "lxml-6.1.1-cp38-cp38-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8be8ad51249698103d24b0571df35a10990fbe93dd043b6c024172189485f5e3"}, + {file = "lxml-6.1.1-cp38-cp38-manylinux_2_28_i686.whl", hash = "sha256:76447f65250ed2501ead1a1552f5ce8edff159a86f308348e6a9c4acb5e1f1b4"}, + {file = "lxml-6.1.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ffecec8eb889b58ba9be5b95fb1cc78e22ea8eedea38e8736a1568fe1979250e"}, + {file = "lxml-6.1.1-cp38-cp38-win32.whl", hash = "sha256:c674693f055fa2495de12292cb45e9944199d8eaef5a2dec45175c7c61cb73e3"}, + {file = "lxml-6.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:55b03549819867ea141c0202242c4816c82e52ec36e7e648db9d8da5a3dc3ed6"}, + {file = "lxml-6.1.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c9f79d5325907f13e1be0b3e4dacc1049d1dffc4aeee3c995284bea5fe0fab7d"}, + {file = "lxml-6.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:83b6b30eb131da7a75b601f28c5d6971e6ed3e887919bf6b6a1ad3c2df289080"}, + {file = "lxml-6.1.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:441dd227fa0690eb9fc81edabc63cdcefc212bba99b906dcf6e32cc1a9d3e533"}, + {file = "lxml-6.1.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e07c65f443c887bbcf31cc1771d932ecc192a5273943589b3c7572b749f1ffb2"}, + {file = "lxml-6.1.1-cp39-cp39-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5bec7d03d78d853597d6107854c2310ce3f761fd218fe9fe91d5101fcf6c2efe"}, + {file = "lxml-6.1.1-cp39-cp39-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9f76acfb5f68ba982635a53fd985a8044be98a35b43232c2a1ee235ffab3e1dd"}, + {file = "lxml-6.1.1-cp39-cp39-manylinux_2_28_i686.whl", hash = "sha256:8d43ca737b20e106e4aebc42b2f3ae19f00ba63d7eb731698ee083d72d15646f"}, + {file = "lxml-6.1.1-cp39-cp39-manylinux_2_31_armv7l.whl", hash = "sha256:32ab449a5486f6c758e849bb86710d0e45edc24a04e250c01555f8f5653958f8"}, + {file = "lxml-6.1.1-cp39-cp39-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:53c909b62a0532183542fed00c5a7218258c56292d409bc789886fe1cb04c438"}, + {file = "lxml-6.1.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:640f97d43d867bcb9c75b3af013b64850756b746cb6bce8ace83b70da3abba9d"}, + {file = "lxml-6.1.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:469e3618338bd7ab5beb412d2439825479fcf0dab99e394ca563dbc4eaf6c834"}, + {file = "lxml-6.1.1-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:aae97dfdb60715c164419ac2532a76d013c3918a665eb6cb7288098b5f349aaf"}, + {file = "lxml-6.1.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c9a4b821dc7055bf9e05ff5719e18ec501f75c0f0bbfabd573b277559780833d"}, + {file = "lxml-6.1.1-cp39-cp39-win32.whl", hash = "sha256:639f6c857d91d9be29bd7502348d6736dab168b54b5158cd899abf11684dc186"}, + {file = "lxml-6.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:34c2d737beabfe35baada43941ed519251e9a12e779031496bcd5d539fcfd730"}, + {file = "lxml-6.1.1-cp39-cp39-win_arm64.whl", hash = "sha256:07a4a68e286ee7a1ed7dfb8af83e615757c0ccfe9f18c6b4ea6771388d9ba8c9"}, + {file = "lxml-6.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:31033dc34636ea6b7d5cc11b1ddbda78a14de858ba9d3e1ed4b69a3085bc521e"}, + {file = "lxml-6.1.1-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3893c14c4b6ac5b2d54ba8cf03e99fe5104e592de491f19bd6b82756c09f8004"}, + {file = "lxml-6.1.1-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c07da4cebf6889f03ebac8d238f62318e29f495de0aa18a51ea14e61ae907e2e"}, + {file = "lxml-6.1.1-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f6f0ce10945fab9c4c06ce14e22af9059d1a87493a9af4501a5b0b9187e21cf2"}, + {file = "lxml-6.1.1-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f8844cd288697c6425c9beba919302241e3278871dc6519515e72b04e987abcf"}, + {file = "lxml-6.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:ed21202aec73cda4d55d1ce57b389aadb90ffb044e6cd1080b8347efe1b1ec84"}, + {file = "lxml-6.1.1.tar.gz", hash = "sha256:ba96ae44888e0185281e937633a743ea90d5a196c6000f82565ebb0580012d40"}, ] [package.extras] cssselect = ["cssselect (>=0.7)"] +html-clean = ["lxml_html_clean"] html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] -source = ["Cython (>=3.0.7)"] [[package]] name = "mako" -version = "1.3.2" +version = "1.3.12" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." optional = false python-versions = ">=3.8" files = [ - {file = "Mako-1.3.2-py3-none-any.whl", hash = "sha256:32a99d70754dfce237019d17ffe4a282d2d3351b9c476e90d8a60e63f133b80c"}, - {file = "Mako-1.3.2.tar.gz", hash = "sha256:2a0c8ad7f6274271b3bb7467dd37cf9cc6dab4bc19cb69a4ef10669402de698e"}, + {file = "mako-1.3.12-py3-none-any.whl", hash = "sha256:8f61569480282dbf557145ce441e4ba888be453c30989f879f0d652e39f53ea9"}, + {file = "mako-1.3.12.tar.gz", hash = "sha256:9f778e93289bd410bb35daadeb4fc66d95a746f0b75777b942088b7fd7af550a"}, ] [package.dependencies] @@ -2285,13 +2784,13 @@ testing = ["pytest"] [[package]] name = "markdown-it-py" -version = "3.0.0" +version = "4.2.0" description = "Python port of markdown-it. Markdown parsing, done right!" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, - {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, + {file = "markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a"}, + {file = "markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49"}, ] [package.dependencies] @@ -2299,118 +2798,173 @@ mdurl = ">=0.1,<1.0" [package.extras] benchmarking = ["psutil", "pytest", "pytest-benchmark"] -code-style = ["pre-commit (>=3.0,<4.0)"] -compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "markdown-it-pyrs", "mistletoe (>=1.0,<2.0)", "mistune (>=3.0,<4.0)", "panflute (>=2.3,<3.0)"] linkify = ["linkify-it-py (>=1,<3)"] -plugins = ["mdit-py-plugins"] +plugins = ["mdit-py-plugins (>=0.5.0)"] profiling = ["gprof2dot"] -rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] -testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] +rtd = ["ipykernel", "jupyter_sphinx", "mdit-py-plugins (>=0.5.0)", "myst-parser", "pyyaml", "sphinx", "sphinx-book-theme (>=1.0,<2.0)", "sphinx-copybutton", "sphinx-design"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions", "pytest-timeout", "requests"] [[package]] name = "markupsafe" -version = "2.1.4" +version = "3.0.3" description = "Safely add untrusted strings to HTML/XML markup." optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de8153a7aae3835484ac168a9a9bdaa0c5eee4e0bc595503c95d53b942879c84"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e888ff76ceb39601c59e219f281466c6d7e66bd375b4ec1ce83bcdc68306796b"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0b838c37ba596fcbfca71651a104a611543077156cb0a26fe0c475e1f152ee8"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac1ebf6983148b45b5fa48593950f90ed6d1d26300604f321c74a9ca1609f8e"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fbad3d346df8f9d72622ac71b69565e621ada2ce6572f37c2eae8dacd60385d"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5291d98cd3ad9a562883468c690a2a238c4a6388ab3bd155b0c75dd55ece858"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a7cc49ef48a3c7a0005a949f3c04f8baa5409d3f663a1b36f0eba9bfe2a0396e"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b83041cda633871572f0d3c41dddd5582ad7d22f65a72eacd8d3d6d00291df26"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-win32.whl", hash = "sha256:0c26f67b3fe27302d3a412b85ef696792c4a2386293c53ba683a89562f9399b0"}, - {file = "MarkupSafe-2.1.4-cp310-cp310-win_amd64.whl", hash = "sha256:a76055d5cb1c23485d7ddae533229039b850db711c554a12ea64a0fd8a0129e2"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9e9e3c4020aa2dc62d5dd6743a69e399ce3de58320522948af6140ac959ab863"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0042d6a9880b38e1dd9ff83146cc3c9c18a059b9360ceae207805567aacccc69"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55d03fea4c4e9fd0ad75dc2e7e2b6757b80c152c032ea1d1de487461d8140efc"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ab3a886a237f6e9c9f4f7d272067e712cdb4efa774bef494dccad08f39d8ae6"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abf5ebbec056817057bfafc0445916bb688a255a5146f900445d081db08cbabb"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e1a0d1924a5013d4f294087e00024ad25668234569289650929ab871231668e7"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e7902211afd0af05fbadcc9a312e4cf10f27b779cf1323e78d52377ae4b72bea"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c669391319973e49a7c6230c218a1e3044710bc1ce4c8e6eb71f7e6d43a2c131"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-win32.whl", hash = "sha256:31f57d64c336b8ccb1966d156932f3daa4fee74176b0fdc48ef580be774aae74"}, - {file = "MarkupSafe-2.1.4-cp311-cp311-win_amd64.whl", hash = "sha256:54a7e1380dfece8847c71bf7e33da5d084e9b889c75eca19100ef98027bd9f56"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a76cd37d229fc385738bd1ce4cba2a121cf26b53864c1772694ad0ad348e509e"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:987d13fe1d23e12a66ca2073b8d2e2a75cec2ecb8eab43ff5624ba0ad42764bc"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5244324676254697fe5c181fc762284e2c5fceeb1c4e3e7f6aca2b6f107e60dc"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78bc995e004681246e85e28e068111a4c3f35f34e6c62da1471e844ee1446250"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4d176cfdfde84f732c4a53109b293d05883e952bbba68b857ae446fa3119b4f"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f9917691f410a2e0897d1ef99619fd3f7dd503647c8ff2475bf90c3cf222ad74"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:f06e5a9e99b7df44640767842f414ed5d7bedaaa78cd817ce04bbd6fd86e2dd6"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:396549cea79e8ca4ba65525470d534e8a41070e6b3500ce2414921099cb73e8d"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-win32.whl", hash = "sha256:f6be2d708a9d0e9b0054856f07ac7070fbe1754be40ca8525d5adccdbda8f475"}, - {file = "MarkupSafe-2.1.4-cp312-cp312-win_amd64.whl", hash = "sha256:5045e892cfdaecc5b4c01822f353cf2c8feb88a6ec1c0adef2a2e705eef0f656"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7a07f40ef8f0fbc5ef1000d0c78771f4d5ca03b4953fc162749772916b298fc4"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d18b66fe626ac412d96c2ab536306c736c66cf2a31c243a45025156cc190dc8a"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:698e84142f3f884114ea8cf83e7a67ca8f4ace8454e78fe960646c6c91c63bfa"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a3b78a5af63ec10d8604180380c13dcd870aba7928c1fe04e881d5c792dc4e"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:15866d7f2dc60cfdde12ebb4e75e41be862348b4728300c36cdf405e258415ec"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6aa5e2e7fc9bc042ae82d8b79d795b9a62bd8f15ba1e7594e3db243f158b5565"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:54635102ba3cf5da26eb6f96c4b8c53af8a9c0d97b64bdcb592596a6255d8518"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-win32.whl", hash = "sha256:3583a3a3ab7958e354dc1d25be74aee6228938312ee875a22330c4dc2e41beb0"}, - {file = "MarkupSafe-2.1.4-cp37-cp37m-win_amd64.whl", hash = "sha256:d6e427c7378c7f1b2bef6a344c925b8b63623d3321c09a237b7cc0e77dd98ceb"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:bf1196dcc239e608605b716e7b166eb5faf4bc192f8a44b81e85251e62584bd2"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4df98d4a9cd6a88d6a585852f56f2155c9cdb6aec78361a19f938810aa020954"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b835aba863195269ea358cecc21b400276747cc977492319fd7682b8cd2c253d"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23984d1bdae01bee794267424af55eef4dfc038dc5d1272860669b2aa025c9e3"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c98c33ffe20e9a489145d97070a435ea0679fddaabcafe19982fe9c971987d5"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9896fca4a8eb246defc8b2a7ac77ef7553b638e04fbf170bff78a40fa8a91474"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b0fe73bac2fed83839dbdbe6da84ae2a31c11cfc1c777a40dbd8ac8a6ed1560f"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c7556bafeaa0a50e2fe7dc86e0382dea349ebcad8f010d5a7dc6ba568eaaa789"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-win32.whl", hash = "sha256:fc1a75aa8f11b87910ffd98de62b29d6520b6d6e8a3de69a70ca34dea85d2a8a"}, - {file = "MarkupSafe-2.1.4-cp38-cp38-win_amd64.whl", hash = "sha256:3a66c36a3864df95e4f62f9167c734b3b1192cb0851b43d7cc08040c074c6279"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:765f036a3d00395a326df2835d8f86b637dbaf9832f90f5d196c3b8a7a5080cb"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:21e7af8091007bf4bebf4521184f4880a6acab8df0df52ef9e513d8e5db23411"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5c31fe855c77cad679b302aabc42d724ed87c043b1432d457f4976add1c2c3e"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7653fa39578957bc42e5ebc15cf4361d9e0ee4b702d7d5ec96cdac860953c5b4"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47bb5f0142b8b64ed1399b6b60f700a580335c8e1c57f2f15587bd072012decc"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fe8512ed897d5daf089e5bd010c3dc03bb1bdae00b35588c49b98268d4a01e00"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:36d7626a8cca4d34216875aee5a1d3d654bb3dac201c1c003d182283e3205949"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b6f14a9cd50c3cb100eb94b3273131c80d102e19bb20253ac7bd7336118a673a"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-win32.whl", hash = "sha256:c8f253a84dbd2c63c19590fa86a032ef3d8cc18923b8049d91bcdeeb2581fbf6"}, - {file = "MarkupSafe-2.1.4-cp39-cp39-win_amd64.whl", hash = "sha256:8b570a1537367b52396e53325769608f2a687ec9a4363647af1cded8928af959"}, - {file = "MarkupSafe-2.1.4.tar.gz", hash = "sha256:3aae9af4cac263007fd6309c64c6ab4506dd2b79382d9d19a1994f9240b8db4f"}, + {file = "markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559"}, + {file = "markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1"}, + {file = "markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa"}, + {file = "markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8"}, + {file = "markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1"}, + {file = "markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad"}, + {file = "markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a"}, + {file = "markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19"}, + {file = "markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01"}, + {file = "markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c"}, + {file = "markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e"}, + {file = "markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b"}, + {file = "markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d"}, + {file = "markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c"}, + {file = "markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f"}, + {file = "markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795"}, + {file = "markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12"}, + {file = "markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed"}, + {file = "markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5"}, + {file = "markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485"}, + {file = "markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73"}, + {file = "markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287"}, + {file = "markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe"}, + {file = "markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe"}, + {file = "markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9"}, + {file = "markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581"}, + {file = "markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4"}, + {file = "markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab"}, + {file = "markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa"}, + {file = "markupsafe-3.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26"}, + {file = "markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d"}, + {file = "markupsafe-3.0.3-cp39-cp39-win32.whl", hash = "sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7"}, + {file = "markupsafe-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e"}, + {file = "markupsafe-3.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8"}, + {file = "markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698"}, ] [[package]] name = "matplotlib" -version = "3.8.2" +version = "3.10.9" description = "Python plotting package" optional = false -python-versions = ">=3.9" -files = [ - {file = "matplotlib-3.8.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:09796f89fb71a0c0e1e2f4bdaf63fb2cefc84446bb963ecdeb40dfee7dfa98c7"}, - {file = "matplotlib-3.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6f9c6976748a25e8b9be51ea028df49b8e561eed7809146da7a47dbecebab367"}, - {file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b78e4f2cedf303869b782071b55fdde5987fda3038e9d09e58c91cc261b5ad18"}, - {file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e208f46cf6576a7624195aa047cb344a7f802e113bb1a06cfd4bee431de5e31"}, - {file = "matplotlib-3.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:46a569130ff53798ea5f50afce7406e91fdc471ca1e0e26ba976a8c734c9427a"}, - {file = "matplotlib-3.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:830f00640c965c5b7f6bc32f0d4ce0c36dfe0379f7dd65b07a00c801713ec40a"}, - {file = "matplotlib-3.8.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d86593ccf546223eb75a39b44c32788e6f6440d13cfc4750c1c15d0fcb850b63"}, - {file = "matplotlib-3.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9a5430836811b7652991939012f43d2808a2db9b64ee240387e8c43e2e5578c8"}, - {file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9576723858a78751d5aacd2497b8aef29ffea6d1c95981505877f7ac28215c6"}, - {file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ba9cbd8ac6cf422f3102622b20f8552d601bf8837e49a3afed188d560152788"}, - {file = "matplotlib-3.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:03f9d160a29e0b65c0790bb07f4f45d6a181b1ac33eb1bb0dd225986450148f0"}, - {file = "matplotlib-3.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:3773002da767f0a9323ba1a9b9b5d00d6257dbd2a93107233167cfb581f64717"}, - {file = "matplotlib-3.8.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:4c318c1e95e2f5926fba326f68177dee364aa791d6df022ceb91b8221bd0a627"}, - {file = "matplotlib-3.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:091275d18d942cf1ee9609c830a1bc36610607d8223b1b981c37d5c9fc3e46a4"}, - {file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b0f3b8ea0e99e233a4bcc44590f01604840d833c280ebb8fe5554fd3e6cfe8d"}, - {file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7b1704a530395aaf73912be741c04d181f82ca78084fbd80bc737be04848331"}, - {file = "matplotlib-3.8.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:533b0e3b0c6768eef8cbe4b583731ce25a91ab54a22f830db2b031e83cca9213"}, - {file = "matplotlib-3.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:0f4fc5d72b75e2c18e55eb32292659cf731d9d5b312a6eb036506304f4675630"}, - {file = "matplotlib-3.8.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:deaed9ad4da0b1aea77fe0aa0cebb9ef611c70b3177be936a95e5d01fa05094f"}, - {file = "matplotlib-3.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:172f4d0fbac3383d39164c6caafd3255ce6fa58f08fc392513a0b1d3b89c4f89"}, - {file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7d36c2209d9136cd8e02fab1c0ddc185ce79bc914c45054a9f514e44c787917"}, - {file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5864bdd7da445e4e5e011b199bb67168cdad10b501750367c496420f2ad00843"}, - {file = "matplotlib-3.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ef8345b48e95cee45ff25192ed1f4857273117917a4dcd48e3905619bcd9c9b8"}, - {file = "matplotlib-3.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:7c48d9e221b637c017232e3760ed30b4e8d5dfd081daf327e829bf2a72c731b4"}, - {file = "matplotlib-3.8.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:aa11b3c6928a1e496c1a79917d51d4cd5d04f8a2e75f21df4949eeefdf697f4b"}, - {file = "matplotlib-3.8.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1095fecf99eeb7384dabad4bf44b965f929a5f6079654b681193edf7169ec20"}, - {file = "matplotlib-3.8.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:bddfb1db89bfaa855912261c805bd0e10218923cc262b9159a49c29a7a1c1afa"}, - {file = "matplotlib-3.8.2.tar.gz", hash = "sha256:01a978b871b881ee76017152f1f1a0cbf6bd5f7b8ff8c96df0df1bd57d8755a1"}, +python-versions = ">=3.10" +files = [ + {file = "matplotlib-3.10.9-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77210dce9cb8153dffc967efaae990543392563d5a376d4dd8539bebcb0ed217"}, + {file = "matplotlib-3.10.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1e7698ac9868428e84d2c967424803b2472ff7167d9d6590d4204ed775343c3b"}, + {file = "matplotlib-3.10.9-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1aa972116abb4c9d201bf245620b433726cb6856f3bef6a78f776a00f5c92d37"}, + {file = "matplotlib-3.10.9-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae2f11957b27ce53497dd4d7b235c4d4f1faf383dfb39d0c5beb833bff883294"}, + {file = "matplotlib-3.10.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b049278ddce116aaa1c1377ebf58adea909132dfce0281cf7e3a1ea9fc2e2c65"}, + {file = "matplotlib-3.10.9-cp310-cp310-win_amd64.whl", hash = "sha256:82834c3c292d24d3a8aae77cd2d20019de69d692a34a970e4fdb8d33e2ea3dda"}, + {file = "matplotlib-3.10.9-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:68cfdcede415f7c8f5577b03303dd94526cdb6d11036cecdc205e08733b2d2bb"}, + {file = "matplotlib-3.10.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfca0129678bd56379db26c52b5d77ed7de314c047492fbdc763aa7501710cfb"}, + {file = "matplotlib-3.10.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8e436d155fa8a3399dc62683f8f5d0e2e50d25d0144a73edd73f82eec8f4abfb"}, + {file = "matplotlib-3.10.9-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56fc0bd271b00025c6edfdc7c2dcd247372c8e1544971d62e1dc7c17367e8bf9"}, + {file = "matplotlib-3.10.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a5a6104ed666402ba5106d7f36e0e0cdca4e8d7fa4d39708ca88019e2835a2eb"}, + {file = "matplotlib-3.10.9-cp311-cp311-win_amd64.whl", hash = "sha256:d730e984eddf56974c3e72b6129c7ca462ac38dc624338f4b0b23eb23ecba00f"}, + {file = "matplotlib-3.10.9-cp311-cp311-win_arm64.whl", hash = "sha256:51bf0ddbdc598e060d46c16b5590708f81a1624cefbaaf62f6a81bf9285b8c80"}, + {file = "matplotlib-3.10.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f0c3c28d9fbcc1fe7a03be236d73430cf6409c41fb2383a7ac52fe932b072cb1"}, + {file = "matplotlib-3.10.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41cb28c2bd769aa3e98322c6ab09854cbcc52ab69d2759d681bba3e327b2b320"}, + {file = "matplotlib-3.10.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ae20801130378b82d647ff5047c07316295b68dc054ca6b3c13519d0ea624285"}, + {file = "matplotlib-3.10.9-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6c63ebcd8b4b169eb2f5c200552ae6b8be8999a005b6b507ed76fb8d7d674fe2"}, + {file = "matplotlib-3.10.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d75d11c949914165976c621b2324f9ef162af7ebf4b057ddf95dd1dba7e5edcf"}, + {file = "matplotlib-3.10.9-cp312-cp312-win_amd64.whl", hash = "sha256:d091f9d758b34aaaaa6331d13574bf01891d903b3dec59bfff458ef7551de5d6"}, + {file = "matplotlib-3.10.9-cp312-cp312-win_arm64.whl", hash = "sha256:10cc5ce06d10231c36f40e875f3c7e8050362a4ee8f0ee5d29a6b3277d57bb42"}, + {file = "matplotlib-3.10.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b580440f1ff81a0e34122051a3dfabb7e4b7f9e380629929bde0eff9af72165f"}, + {file = "matplotlib-3.10.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b1b745c489cd1a77a0dc1120a05dc87af9798faebc913601feb8c73d89bf2d1e"}, + {file = "matplotlib-3.10.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8f3bcac1ca5ed000a6f4337d47ba67dfddf37ed6a46c15fd7f014997f7bf865f"}, + {file = "matplotlib-3.10.9-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a8d66a55def891c33147ba3ba9bfcabf0b526a43764c818acbb4525e5ed0838"}, + {file = "matplotlib-3.10.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d843374407c4017a6403b59c6c81606773d136f3259d5b6da3131bc814542cc2"}, + {file = "matplotlib-3.10.9-cp313-cp313-win_amd64.whl", hash = "sha256:f4399f64b3e94cd500195490972ae1ee81170df1636fa15364d157d5bdd7b921"}, + {file = "matplotlib-3.10.9-cp313-cp313-win_arm64.whl", hash = "sha256:ba7b3b8ef09eab7df0e86e9ae086faa433efbfbdb46afcb3aa16aabf779469a8"}, + {file = "matplotlib-3.10.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:09218df8a93712bd6ea133e83a153c755448cf7868316c531cffcc43f69d1cc9"}, + {file = "matplotlib-3.10.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:82368699727bfb7b0182e1aa13082e3c08e092fa1a25d3e1fd92405bff96f6d4"}, + {file = "matplotlib-3.10.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3225f4e1edcb8c86c884ddf79ebe20ecd0a67d30188f279897554ccd8fded4dc"}, + {file = "matplotlib-3.10.9-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de2445a0c6690d21b7eb6ce071cebad6d40a2e9bdf10d039074a96ba19797b99"}, + {file = "matplotlib-3.10.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:b2b9516251cb89ff618d757daec0e2ed1bf21248013844a853d87ef85ab3081d"}, + {file = "matplotlib-3.10.9-cp313-cp313t-win_amd64.whl", hash = "sha256:e9fae004b941b23ff2edcf1567a857ed77bafc8086ffa258190462328434faf8"}, + {file = "matplotlib-3.10.9-cp313-cp313t-win_arm64.whl", hash = "sha256:6b63d9c7c769b88ab81e10dc86e4e0607cf56817b9f9e6cf24b2a5f1693b8e38"}, + {file = "matplotlib-3.10.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:172db52c9e683f5d12eaf57f0f54834190e12581fe1cc2a19595a8f5acb4e77d"}, + {file = "matplotlib-3.10.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:97e35e8d39ccc85859095e01a53847432ba9a53ddf7986f7a54a11b73d0e143f"}, + {file = "matplotlib-3.10.9-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aba1615dabe83188e19d4f75a253c6a08423e04c1425e64039f800050a69de6b"}, + {file = "matplotlib-3.10.9-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34cf8167e023ad956c15f36302911d5406bd99a9862c1a8499ea6f7c0e015dc2"}, + {file = "matplotlib-3.10.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:59476c6d29d612b8e9bb6ce8c5b631be6ba8f9e3a2421f22a02b192c7dd28716"}, + {file = "matplotlib-3.10.9-cp314-cp314-win_amd64.whl", hash = "sha256:336b9acc64d309063126edcdaca00db9373af3c476bb94388fe9c5a53ad13e6f"}, + {file = "matplotlib-3.10.9-cp314-cp314-win_arm64.whl", hash = "sha256:2dc9477819ffd78ad12a20df1d9d6a6bd4fec6aaa9072681465fddca052f1456"}, + {file = "matplotlib-3.10.9-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:da4e09638420548f31c354032a6250e473c68e5a4e96899b4844cf39ddea23fe"}, + {file = "matplotlib-3.10.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:345f6f68ecc8da0ca56fad2ea08fde1a115eda530079eca185d50a7bc3e146c6"}, + {file = "matplotlib-3.10.9-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4edcfbd8565339aa62f1cd4012f7180926fdbe71850f7b0d3c379c175cd6b66c"}, + {file = "matplotlib-3.10.9-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6be157fe17fc37cb95ac1d7374cf717ce9259616edec911a78d9d26dae8522d4"}, + {file = "matplotlib-3.10.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:4e42042d54db34fda4e95a7bd3e5789c2a995d2dad3eb8850232ee534092fbbf"}, + {file = "matplotlib-3.10.9-cp314-cp314t-win_amd64.whl", hash = "sha256:c27df8b3848f32a83d1767566595e43cfaa4460380974da06f4279a7ec143c39"}, + {file = "matplotlib-3.10.9-cp314-cp314t-win_arm64.whl", hash = "sha256:a49f1eadc84ca85fd72fa4e89e70e61bf86452df6f971af04b12c60761a0772c"}, + {file = "matplotlib-3.10.9-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1872fb212a05b729e649754a72d5da61d03e0554d76e80303b6f83d1d2c0552b"}, + {file = "matplotlib-3.10.9-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:985f2238880e2e69093f588f5fe2e46771747febf0649f3cf7f7b7480875317f"}, + {file = "matplotlib-3.10.9-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6640f75af2c6148293caa0a2b39dd806a492dd66c8a8b04035813e33d0fd2585"}, + {file = "matplotlib-3.10.9-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:42fb814efabe95c06c1994d8ab5a8385f43a249e23badd3ba931d4308e5bca20"}, + {file = "matplotlib-3.10.9-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f76e640a5268850bfda54b5131b1b1941cc685e42c5fa98ed9f2d64038308cba"}, + {file = "matplotlib-3.10.9-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3fc0364dfbe1d07f6d15c5ebd0c5bf89e126916e5a8667dd4a7a6e84c36653d4"}, + {file = "matplotlib-3.10.9.tar.gz", hash = "sha256:fd66508e8c6877d98e586654b608a0456db8d7e8a546eb1e2600efd957302358"}, ] [package.dependencies] @@ -2418,12 +2972,15 @@ contourpy = ">=1.0.1" cycler = ">=0.10" fonttools = ">=4.22.0" kiwisolver = ">=1.3.1" -numpy = ">=1.21,<2" +numpy = ">=1.23" packaging = ">=20.0" pillow = ">=8" -pyparsing = ">=2.3.1" +pyparsing = ">=3" python-dateutil = ">=2.7" +[package.extras] +dev = ["meson-python (>=0.13.1,<0.17.0)", "pybind11 (>=2.13.2,!=2.13.3)", "setuptools (>=64)", "setuptools_scm (>=7,<10)"] + [[package]] name = "mdurl" version = "0.1.2" @@ -2437,103 +2994,157 @@ files = [ [[package]] name = "multidict" -version = "6.1.0" +version = "6.7.1" description = "multidict implementation" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"}, - {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"}, - {file = "multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429"}, - {file = "multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160"}, - {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7"}, - {file = "multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0"}, - {file = "multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d"}, - {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6"}, - {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156"}, - {file = "multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351"}, - {file = "multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3"}, - {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753"}, - {file = "multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80"}, - {file = "multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926"}, - {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa"}, - {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436"}, - {file = "multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925"}, - {file = "multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6"}, - {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3"}, - {file = "multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133"}, - {file = "multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1"}, - {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008"}, - {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f"}, - {file = "multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44"}, - {file = "multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4"}, - {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6"}, - {file = "multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81"}, - {file = "multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774"}, - {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392"}, - {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a"}, - {file = "multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d"}, - {file = "multidict-6.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492"}, - {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd"}, - {file = "multidict-6.1.0-cp38-cp38-win32.whl", hash = "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167"}, - {file = "multidict-6.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef"}, - {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c"}, - {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1"}, - {file = "multidict-6.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255"}, - {file = "multidict-6.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972"}, - {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43"}, - {file = "multidict-6.1.0-cp39-cp39-win32.whl", hash = "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada"}, - {file = "multidict-6.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a"}, - {file = "multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506"}, - {file = "multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a"}, + {file = "multidict-6.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c93c3db7ea657dd4637d57e74ab73de31bccefe144d3d4ce370052035bc85fb5"}, + {file = "multidict-6.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:974e72a2474600827abaeda71af0c53d9ebbc3c2eb7da37b37d7829ae31232d8"}, + {file = "multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdea2e7b2456cfb6694fb113066fd0ec7ea4d67e3a35e1f4cbeea0b448bf5872"}, + {file = "multidict-6.7.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17207077e29342fdc2c9a82e4b306f1127bf1ea91f8b71e02d4798a70bb99991"}, + {file = "multidict-6.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4f49cb5661344764e4c7c7973e92a47a59b8fc19b6523649ec9dc4960e58a03"}, + {file = "multidict-6.7.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a9fc4caa29e2e6ae408d1c450ac8bf19892c5fca83ee634ecd88a53332c59981"}, + {file = "multidict-6.7.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c5f0c21549ab432b57dcc82130f388d84ad8179824cc3f223d5e7cfbfd4143f6"}, + {file = "multidict-6.7.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7dfb78d966b2c906ae1d28ccf6e6712a3cd04407ee5088cd276fe8cb42186190"}, + {file = "multidict-6.7.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9b0d9b91d1aa44db9c1f1ecd0d9d2ae610b2f4f856448664e01a3b35899f3f92"}, + {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dd96c01a9dcd4889dcfcf9eb5544ca0c77603f239e3ffab0524ec17aea9a93ee"}, + {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:067343c68cd6612d375710f895337b3a98a033c94f14b9a99eff902f205424e2"}, + {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5884a04f4ff56c6120f6ccf703bdeb8b5079d808ba604d4d53aec0d55dc33568"}, + {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8affcf1c98b82bc901702eb73b6947a1bfa170823c153fe8a47b5f5f02e48e40"}, + {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0d17522c37d03e85c8098ec8431636309b2682cf12e58f4dbc76121fb50e4962"}, + {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24c0cf81544ca5e17cfcb6e482e7a82cd475925242b308b890c9452a074d4505"}, + {file = "multidict-6.7.1-cp310-cp310-win32.whl", hash = "sha256:d82dd730a95e6643802f4454b8fdecdf08667881a9c5670db85bc5a56693f122"}, + {file = "multidict-6.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cf37cbe5ced48d417ba045aca1b21bafca67489452debcde94778a576666a1df"}, + {file = "multidict-6.7.1-cp310-cp310-win_arm64.whl", hash = "sha256:59bc83d3f66b41dac1e7460aac1d196edc70c9ba3094965c467715a70ecb46db"}, + {file = "multidict-6.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ff981b266af91d7b4b3793ca3382e53229088d193a85dfad6f5f4c27fc73e5d"}, + {file = "multidict-6.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:844c5bca0b5444adb44a623fb0a1310c2f4cd41f402126bb269cd44c9b3f3e1e"}, + {file = "multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f2a0a924d4c2e9afcd7ec64f9de35fcd96915149b2216e1cb2c10a56df483855"}, + {file = "multidict-6.7.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8be1802715a8e892c784c0197c2ace276ea52702a0ede98b6310c8f255a5afb3"}, + {file = "multidict-6.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e2d2ed645ea29f31c4c7ea1552fcfd7cb7ba656e1eafd4134a6620c9f5fdd9e"}, + {file = "multidict-6.7.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:95922cee9a778659e91db6497596435777bd25ed116701a4c034f8e46544955a"}, + {file = "multidict-6.7.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6b83cabdc375ffaaa15edd97eb7c0c672ad788e2687004990074d7d6c9b140c8"}, + {file = "multidict-6.7.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:38fb49540705369bab8484db0689d86c0a33a0a9f2c1b197f506b71b4b6c19b0"}, + {file = "multidict-6.7.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:439cbebd499f92e9aa6793016a8acaa161dfa749ae86d20960189f5398a19144"}, + {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6d3bc717b6fe763b8be3f2bee2701d3c8eb1b2a8ae9f60910f1b2860c82b6c49"}, + {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:619e5a1ac57986dbfec9f0b301d865dddf763696435e2962f6d9cf2fdff2bb71"}, + {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0b38ebffd9be37c1170d33bc0f36f4f262e0a09bc1aac1c34c7aa51a7293f0b3"}, + {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:10ae39c9cfe6adedcdb764f5e8411d4a92b055e35573a2eaa88d3323289ef93c"}, + {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:25167cc263257660290fba06b9318d2026e3c910be240a146e1f66dd114af2b0"}, + {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:128441d052254f42989ef98b7b6a6ecb1e6f708aa962c7984235316db59f50fa"}, + {file = "multidict-6.7.1-cp311-cp311-win32.whl", hash = "sha256:d62b7f64ffde3b99d06b707a280db04fb3855b55f5a06df387236051d0668f4a"}, + {file = "multidict-6.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:bdbf9f3b332abd0cdb306e7c2113818ab1e922dc84b8f8fd06ec89ed2a19ab8b"}, + {file = "multidict-6.7.1-cp311-cp311-win_arm64.whl", hash = "sha256:b8c990b037d2fff2f4e33d3f21b9b531c5745b33a49a7d6dbe7a177266af44f6"}, + {file = "multidict-6.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a90f75c956e32891a4eda3639ce6dd86e87105271f43d43442a3aedf3cddf172"}, + {file = "multidict-6.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fccb473e87eaa1382689053e4a4618e7ba7b9b9b8d6adf2027ee474597128cd"}, + {file = "multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0fa96985700739c4c7853a43c0b3e169360d6855780021bfc6d0f1ce7c123e7"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cb2a55f408c3043e42b40cc8eecd575afa27b7e0b956dfb190de0f8499a57a53"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb0ce7b2a32d09892b3dd6cc44877a0d02a33241fafca5f25c8b6b62374f8b75"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c3a32d23520ee37bf327d1e1a656fec76a2edd5c038bf43eddfa0572ec49c60b"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9c90fed18bffc0189ba814749fdcc102b536e83a9f738a9003e569acd540a733"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:da62917e6076f512daccfbbde27f46fed1c98fee202f0559adec8ee0de67f71a"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfde23ef6ed9db7eaee6c37dcec08524cb43903c60b285b172b6c094711b3961"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3758692429e4e32f1ba0df23219cd0b4fc0a52f476726fff9337d1a57676a582"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:398c1478926eca669f2fd6a5856b6de9c0acf23a2cb59a14c0ba5844fa38077e"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c102791b1c4f3ab36ce4101154549105a53dc828f016356b3e3bcae2e3a039d3"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a088b62bd733e2ad12c50dad01b7d0166c30287c166e137433d3b410add807a6"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3d51ff4785d58d3f6c91bdbffcb5e1f7ddfda557727043aa20d20ec4f65e324a"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc5907494fccf3e7d3f94f95c91d6336b092b5fc83811720fae5e2765890dfba"}, + {file = "multidict-6.7.1-cp312-cp312-win32.whl", hash = "sha256:28ca5ce2fd9716631133d0e9a9b9a745ad7f60bac2bccafb56aa380fc0b6c511"}, + {file = "multidict-6.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcee94dfbd638784645b066074b338bc9cc155d4b4bffa4adce1615c5a426c19"}, + {file = "multidict-6.7.1-cp312-cp312-win_arm64.whl", hash = "sha256:ba0a9fb644d0c1a2194cf7ffb043bd852cea63a57f66fbd33959f7dae18517bf"}, + {file = "multidict-6.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2b41f5fed0ed563624f1c17630cb9941cf2309d4df00e494b551b5f3e3d67a23"}, + {file = "multidict-6.7.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84e61e3af5463c19b67ced91f6c634effb89ef8bfc5ca0267f954451ed4bb6a2"}, + {file = "multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:935434b9853c7c112eee7ac891bc4cb86455aa631269ae35442cb316790c1445"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:432feb25a1cb67fe82a9680b4d65fb542e4635cb3166cd9c01560651ad60f177"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e82d14e3c948952a1a85503817e038cba5905a3352de76b9a465075d072fba23"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4cfb48c6ea66c83bcaaf7e4dfa7ec1b6bbcf751b7db85a328902796dfde4c060"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d540e51b7e8e170174555edecddbd5538105443754539193e3e1061864d444d"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:273d23f4b40f3dce4d6c8a821c741a86dec62cded82e1175ba3d99be128147ed"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d624335fd4fa1c08a53f8b4be7676ebde19cd092b3895c421045ca87895b429"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:12fad252f8b267cc75b66e8fc51b3079604e8d43a75428ffe193cd9e2195dfd6"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:03ede2a6ffbe8ef936b92cb4529f27f42be7f56afcdab5ab739cd5f27fb1cbf9"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:90efbcf47dbe33dcf643a1e400d67d59abeac5db07dc3f27d6bdeae497a2198c"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c4b9bfc148f5a91be9244d6264c53035c8a0dcd2f51f1c3c6e30e30ebaa1c84"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:401c5a650f3add2472d1d288c26deebc540f99e2fb83e9525007a74cd2116f1d"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:97891f3b1b3ffbded884e2916cacf3c6fc87b66bb0dde46f7357404750559f33"}, + {file = "multidict-6.7.1-cp313-cp313-win32.whl", hash = "sha256:e1c5988359516095535c4301af38d8a8838534158f649c05dd1050222321bcb3"}, + {file = "multidict-6.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:960c83bf01a95b12b08fd54324a4eb1d5b52c88932b5cba5d6e712bb3ed12eb5"}, + {file = "multidict-6.7.1-cp313-cp313-win_arm64.whl", hash = "sha256:563fe25c678aaba333d5399408f5ec3c383ca5b663e7f774dd179a520b8144df"}, + {file = "multidict-6.7.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:c76c4bec1538375dad9d452d246ca5368ad6e1c9039dadcf007ae59c70619ea1"}, + {file = "multidict-6.7.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:57b46b24b5d5ebcc978da4ec23a819a9402b4228b8a90d9c656422b4bdd8a963"}, + {file = "multidict-6.7.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e954b24433c768ce78ab7929e84ccf3422e46deb45a4dc9f93438f8217fa2d34"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3bd231490fa7217cc832528e1cd8752a96f0125ddd2b5749390f7c3ec8721b65"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:253282d70d67885a15c8a7716f3a73edf2d635793ceda8173b9ecc21f2fb8292"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b4c48648d7649c9335cf1927a8b87fa692de3dcb15faa676c6a6f1f1aabda43"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:98bc624954ec4d2c7cb074b8eefc2b5d0ce7d482e410df446414355d158fe4ca"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1b99af4d9eec0b49927b4402bcbb58dea89d3e0db8806a4086117019939ad3dd"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6aac4f16b472d5b7dc6f66a0d49dd57b0e0902090be16594dc9ebfd3d17c47e7"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:21f830fe223215dffd51f538e78c172ed7c7f60c9b96a2bf05c4848ad49921c3"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f5dd81c45b05518b9aa4da4aa74e1c93d715efa234fd3e8a179df611cc85e5f4"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:eb304767bca2bb92fb9c5bd33cedc95baee5bb5f6c88e63706533a1c06ad08c8"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c9035dde0f916702850ef66460bc4239d89d08df4d02023a5926e7446724212c"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:af959b9beeb66c822380f222f0e0a1889331597e81f1ded7f374f3ecb0fd6c52"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:41f2952231456154ee479651491e94118229844dd7226541788be783be2b5108"}, + {file = "multidict-6.7.1-cp313-cp313t-win32.whl", hash = "sha256:df9f19c28adcb40b6aae30bbaa1478c389efd50c28d541d76760199fc1037c32"}, + {file = "multidict-6.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:d54ecf9f301853f2c5e802da559604b3e95bb7a3b01a9c295c6ee591b9882de8"}, + {file = "multidict-6.7.1-cp313-cp313t-win_arm64.whl", hash = "sha256:5a37ca18e360377cfda1d62f5f382ff41f2b8c4ccb329ed974cc2e1643440118"}, + {file = "multidict-6.7.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8f333ec9c5eb1b7105e3b84b53141e66ca05a19a605368c55450b6ba208cb9ee"}, + {file = "multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a407f13c188f804c759fc6a9f88286a565c242a76b27626594c133b82883b5c2"}, + {file = "multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0e161ddf326db5577c3a4cc2d8648f81456e8a20d40415541587a71620d7a7d1"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1e3a8bb24342a8201d178c3b4984c26ba81a577c80d4d525727427460a50c22d"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97231140a50f5d447d3164f994b86a0bed7cd016e2682f8650d6a9158e14fd31"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6b10359683bd8806a200fd2909e7c8ca3a7b24ec1d8132e483d58e791d881048"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:283ddac99f7ac25a4acadbf004cb5ae34480bbeb063520f70ce397b281859362"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:538cec1e18c067d0e6103aa9a74f9e832904c957adc260e61cd9d8cf0c3b3d37"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eee46ccb30ff48a1e35bb818cc90846c6be2b68240e42a78599166722cea709"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa263a02f4f2dd2d11a7b1bb4362aa7cb1049f84a9235d31adf63f30143469a0"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2e1425e2f99ec5bd36c15a01b690a1a2456209c5deed58f95469ffb46039ccbb"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:497394b3239fc6f0e13a78a3e1b61296e72bf1c5f94b4c4eb80b265c37a131cd"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:233b398c29d3f1b9676b4b6f75c518a06fcb2ea0b925119fb2c1bc35c05e1601"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:93b1818e4a6e0930454f0f2af7dfce69307ca03cdcfb3739bf4d91241967b6c1"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f33dc2a3abe9249ea5d8360f969ec7f4142e7ac45ee7014d8f8d5acddf178b7b"}, + {file = "multidict-6.7.1-cp314-cp314-win32.whl", hash = "sha256:3ab8b9d8b75aef9df299595d5388b14530839f6422333357af1339443cff777d"}, + {file = "multidict-6.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:5e01429a929600e7dab7b166062d9bb54a5eed752384c7384c968c2afab8f50f"}, + {file = "multidict-6.7.1-cp314-cp314-win_arm64.whl", hash = "sha256:4885cb0e817aef5d00a2e8451d4665c1808378dc27c2705f1bf4ef8505c0d2e5"}, + {file = "multidict-6.7.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0458c978acd8e6ea53c81eefaddbbee9c6c5e591f41b3f5e8e194780fe026581"}, + {file = "multidict-6.7.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c0abd12629b0af3cf590982c0b413b1e7395cd4ec026f30986818ab95bfaa94a"}, + {file = "multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:14525a5f61d7d0c94b368a42cff4c9a4e7ba2d52e2672a7b23d84dc86fb02b0c"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17307b22c217b4cf05033dabefe68255a534d637c6c9b0cc8382718f87be4262"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a7e590ff876a3eaf1c02a4dfe0724b6e69a9e9de6d8f556816f29c496046e59"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5fa6a95dfee63893d80a34758cd0e0c118a30b8dcb46372bf75106c591b77889"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a0543217a6a017692aa6ae5cc39adb75e587af0f3a82288b1492eb73dd6cc2a4"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f99fe611c312b3c1c0ace793f92464d8cd263cc3b26b5721950d977b006b6c4d"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9004d8386d133b7e6135679424c91b0b854d2d164af6ea3f289f8f2761064609"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e628ef0e6859ffd8273c69412a2465c4be4a9517d07261b33334b5ec6f3c7489"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:841189848ba629c3552035a6a7f5bf3b02eb304e9fea7492ca220a8eda6b0e5c"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ce1bbd7d780bb5a0da032e095c951f7014d6b0a205f8318308140f1a6aba159e"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b26684587228afed0d50cf804cc71062cc9c1cdf55051c4c6345d372947b268c"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9f9af11306994335398293f9958071019e3ab95e9a707dc1383a35613f6abcb9"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b4938326284c4f1224178a560987b6cf8b4d38458b113d9b8c1db1a836e640a2"}, + {file = "multidict-6.7.1-cp314-cp314t-win32.whl", hash = "sha256:98655c737850c064a65e006a3df7c997cd3b220be4ec8fe26215760b9697d4d7"}, + {file = "multidict-6.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:497bde6223c212ba11d462853cfa4f0ae6ef97465033e7dc9940cdb3ab5b48e5"}, + {file = "multidict-6.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:2bbd113e0d4af5db41d5ebfe9ccaff89de2120578164f86a5d17d5a576d1e5b2"}, + {file = "multidict-6.7.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:65573858d27cdeaca41893185677dc82395159aa28875a8867af66532d413a8f"}, + {file = "multidict-6.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c524c6fb8fc342793708ab111c4dbc90ff9abd568de220432500e47e990c0358"}, + {file = "multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:aa23b001d968faef416ff70dc0f1ab045517b9b42a90edd3e9bcdb06479e31d5"}, + {file = "multidict-6.7.1-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6704fa2b7453b2fb121740555fa1ee20cd98c4d011120caf4d2b8d4e7c76eec0"}, + {file = "multidict-6.7.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:121a34e5bfa410cdf2c8c49716de160de3b1dbcd86b49656f5681e4543bcd1a8"}, + {file = "multidict-6.7.1-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:026d264228bcd637d4e060844e39cdc60f86c479e463d49075dedc21b18fbbe0"}, + {file = "multidict-6.7.1-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0e697826df7eb63418ee190fd06ce9f1803593bb4b9517d08c60d9b9a7f69d8f"}, + {file = "multidict-6.7.1-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bb08271280173720e9fea9ede98e5231defcbad90f1624bea26f32ec8a956e2f"}, + {file = "multidict-6.7.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6b3228e1d80af737b72925ce5fb4daf5a335e49cd7ab77ed7b9fdfbf58c526e"}, + {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3943debf0fbb57bdde5901695c11094a9a36723e5c03875f87718ee15ca2f4d2"}, + {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:98c5787b0a0d9a41d9311eae44c3b76e6753def8d8870ab501320efe75a6a5f8"}, + {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:08ccb2a6dc72009093ebe7f3f073e5ec5964cba9a706fa94b1a1484039b87941"}, + {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb351f72c26dc9abe338ca7294661aa22969ad8ffe7ef7d5541d19f368dc854a"}, + {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ac1c665bad8b5d762f5f85ebe4d94130c26965f11de70c708c75671297c776de"}, + {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fa6609d0364f4f6f58351b4659a1f3e0e898ba2a8c5cac04cb2c7bc556b0bc5"}, + {file = "multidict-6.7.1-cp39-cp39-win32.whl", hash = "sha256:6f77ce314a29263e67adadc7e7c1bc699fcb3a305059ab973d038f87caa42ed0"}, + {file = "multidict-6.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:f537b55778cd3cbee430abe3131255d3a78202e0f9ea7ffc6ada893a4bcaeea4"}, + {file = "multidict-6.7.1-cp39-cp39-win_arm64.whl", hash = "sha256:749aa54f578f2e5f439538706a475aa844bfa8ef75854b1401e6e528e4937cf9"}, + {file = "multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56"}, + {file = "multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d"}, ] [package.dependencies] @@ -2541,247 +3152,294 @@ typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} [[package]] name = "networkx" -version = "3.2.1" +version = "3.4.2" description = "Python package for creating and manipulating graphs and networks" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" files = [ - {file = "networkx-3.2.1-py3-none-any.whl", hash = "sha256:f18c69adc97877c42332c170849c96cefa91881c99a7cb3e95b7c659ebdc1ec2"}, - {file = "networkx-3.2.1.tar.gz", hash = "sha256:9f1bb5cf3409bf324e0a722c20bdb4c20ee39bf1c30ce8ae499c8502b0b5e0c6"}, + {file = "networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f"}, + {file = "networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1"}, ] [package.extras] -default = ["matplotlib (>=3.5)", "numpy (>=1.22)", "pandas (>=1.4)", "scipy (>=1.9,!=1.11.0,!=1.11.1)"] -developer = ["changelist (==0.4)", "mypy (>=1.1)", "pre-commit (>=3.2)", "rtoml"] -doc = ["nb2plots (>=0.7)", "nbconvert (<7.9)", "numpydoc (>=1.6)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.14)", "sphinx (>=7)", "sphinx-gallery (>=0.14)", "texext (>=0.6.7)"] -extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.11)", "sympy (>=1.10)"] +default = ["matplotlib (>=3.7)", "numpy (>=1.24)", "pandas (>=2.0)", "scipy (>=1.10,!=1.11.0,!=1.11.1)"] +developer = ["changelist (==0.5)", "mypy (>=1.1)", "pre-commit (>=3.2)", "rtoml"] +doc = ["intersphinx-registry", "myst-nb (>=1.1)", "numpydoc (>=1.8.0)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.15)", "sphinx (>=7.3)", "sphinx-gallery (>=0.16)", "texext (>=0.6.7)"] +example = ["cairocffi (>=1.7)", "contextily (>=1.6)", "igraph (>=0.11)", "momepy (>=0.7.2)", "osmnx (>=1.9)", "scikit-learn (>=1.5)", "seaborn (>=0.13)"] +extra = ["lxml (>=4.6)", "pydot (>=3.0.1)", "pygraphviz (>=1.14)", "sympy (>=1.10)"] test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] [[package]] name = "nibabel" -version = "5.2.0" +version = "5.4.2" description = "Access a multitude of neuroimaging data formats" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "nibabel-5.2.0-py3-none-any.whl", hash = "sha256:77724af6e29fd9c4173702e4d031e7d8c45b5963887905a0f90edab880381b7f"}, - {file = "nibabel-5.2.0.tar.gz", hash = "sha256:3df8f1ab981d1bd92f4331d565528d126ab9717fdbd4cfe68f43fcd1c2bf3f52"}, + {file = "nibabel-5.4.2-py3-none-any.whl", hash = "sha256:553482c5f1e1034fc312edf6fb7f32236c0056439845d1c29293b7e8c98d4854"}, + {file = "nibabel-5.4.2.tar.gz", hash = "sha256:d5f4b9076a13178ae7f7acf18c8dbd503ee1c4d5c0c23b85df7be87efcbb49da"}, ] [package.dependencies] -numpy = ">=1.20" -packaging = ">=17" +importlib-resources = {version = ">=5.12", markers = "python_version < \"3.12\""} +numpy = ">=1.25" +packaging = ">=20" +typing-extensions = {version = ">=4.6", markers = "python_version < \"3.13\""} [package.extras] -all = ["nibabel[dicomfs,minc2,spm,zstd]"] -dev = ["tox"] -dicom = ["pydicom (>=1.0.0)"] -dicomfs = ["nibabel[dicom]", "pillow"] -doc = ["matplotlib (>=1.5.3)", "numpydoc", "sphinx", "texext", "tomli"] -doctest = ["tox"] -minc2 = ["h5py"] -spm = ["scipy"] -style = ["tox"] -test = ["pytest", "pytest-cov", "pytest-doctestplus", "pytest-httpserver", "pytest-xdist"] -typing = ["tox"] -zstd = ["pyzstd (>=0.14.3)"] +all = ["backports-zstd (>=1.1)", "h5py (>=3.8)", "indexed-gzip (>=1.6)", "pillow (>=8.4)", "pydicom (>=2.3)", "scipy (>=1.11)"] +dicom = ["pydicom (>=2.3)"] +dicomfs = ["pillow (>=8.4)", "pydicom (>=2.3)"] +indexed-gzip = ["indexed-gzip (>=1.6)"] +minc2 = ["h5py (>=3.8)"] +spm = ["scipy (>=1.11)"] +test = ["coverage[toml] (>=7.2)", "pytest (>=8)", "pytest-cov (>=6)", "pytest-doctestplus (>=1.4)", "pytest-httpserver (>=1.0.7)", "pytest-xdist (>=3.5)"] +viewers = ["matplotlib (>=3.7)"] +zstd = ["backports-zstd (>=1.1)"] [[package]] name = "nodeenv" -version = "1.8.0" +version = "1.10.0" description = "Node.js virtual environment builder" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ - {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, - {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, + {file = "nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827"}, + {file = "nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb"}, ] -[package.dependencies] -setuptools = "*" - [[package]] name = "numpy" -version = "1.26.3" +version = "1.26.4" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.9" files = [ - {file = "numpy-1.26.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:806dd64230dbbfaca8a27faa64e2f414bf1c6622ab78cc4264f7f5f028fee3bf"}, - {file = "numpy-1.26.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02f98011ba4ab17f46f80f7f8f1c291ee7d855fcef0a5a98db80767a468c85cd"}, - {file = "numpy-1.26.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d45b3ec2faed4baca41c76617fcdcfa4f684ff7a151ce6fc78ad3b6e85af0a6"}, - {file = "numpy-1.26.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdd2b45bf079d9ad90377048e2747a0c82351989a2165821f0c96831b4a2a54b"}, - {file = "numpy-1.26.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:211ddd1e94817ed2d175b60b6374120244a4dd2287f4ece45d49228b4d529178"}, - {file = "numpy-1.26.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b1240f767f69d7c4c8a29adde2310b871153df9b26b5cb2b54a561ac85146485"}, - {file = "numpy-1.26.3-cp310-cp310-win32.whl", hash = "sha256:21a9484e75ad018974a2fdaa216524d64ed4212e418e0a551a2d83403b0531d3"}, - {file = "numpy-1.26.3-cp310-cp310-win_amd64.whl", hash = "sha256:9e1591f6ae98bcfac2a4bbf9221c0b92ab49762228f38287f6eeb5f3f55905ce"}, - {file = "numpy-1.26.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b831295e5472954104ecb46cd98c08b98b49c69fdb7040483aff799a755a7374"}, - {file = "numpy-1.26.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9e87562b91f68dd8b1c39149d0323b42e0082db7ddb8e934ab4c292094d575d6"}, - {file = "numpy-1.26.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c66d6fec467e8c0f975818c1796d25c53521124b7cfb760114be0abad53a0a2"}, - {file = "numpy-1.26.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f25e2811a9c932e43943a2615e65fc487a0b6b49218899e62e426e7f0a57eeda"}, - {file = "numpy-1.26.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:af36e0aa45e25c9f57bf684b1175e59ea05d9a7d3e8e87b7ae1a1da246f2767e"}, - {file = "numpy-1.26.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:51c7f1b344f302067b02e0f5b5d2daa9ed4a721cf49f070280ac202738ea7f00"}, - {file = "numpy-1.26.3-cp311-cp311-win32.whl", hash = "sha256:7ca4f24341df071877849eb2034948459ce3a07915c2734f1abb4018d9c49d7b"}, - {file = "numpy-1.26.3-cp311-cp311-win_amd64.whl", hash = "sha256:39763aee6dfdd4878032361b30b2b12593fb445ddb66bbac802e2113eb8a6ac4"}, - {file = "numpy-1.26.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a7081fd19a6d573e1a05e600c82a1c421011db7935ed0d5c483e9dd96b99cf13"}, - {file = "numpy-1.26.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12c70ac274b32bc00c7f61b515126c9205323703abb99cd41836e8125ea0043e"}, - {file = "numpy-1.26.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f784e13e598e9594750b2ef6729bcd5a47f6cfe4a12cca13def35e06d8163e3"}, - {file = "numpy-1.26.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f24750ef94d56ce6e33e4019a8a4d68cfdb1ef661a52cdaee628a56d2437419"}, - {file = "numpy-1.26.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:77810ef29e0fb1d289d225cabb9ee6cf4d11978a00bb99f7f8ec2132a84e0166"}, - {file = "numpy-1.26.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8ed07a90f5450d99dad60d3799f9c03c6566709bd53b497eb9ccad9a55867f36"}, - {file = "numpy-1.26.3-cp312-cp312-win32.whl", hash = "sha256:f73497e8c38295aaa4741bdfa4fda1a5aedda5473074369eca10626835445511"}, - {file = "numpy-1.26.3-cp312-cp312-win_amd64.whl", hash = "sha256:da4b0c6c699a0ad73c810736303f7fbae483bcb012e38d7eb06a5e3b432c981b"}, - {file = "numpy-1.26.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1666f634cb3c80ccbd77ec97bc17337718f56d6658acf5d3b906ca03e90ce87f"}, - {file = "numpy-1.26.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:18c3319a7d39b2c6a9e3bb75aab2304ab79a811ac0168a671a62e6346c29b03f"}, - {file = "numpy-1.26.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b7e807d6888da0db6e7e75838444d62495e2b588b99e90dd80c3459594e857b"}, - {file = "numpy-1.26.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4d362e17bcb0011738c2d83e0a65ea8ce627057b2fdda37678f4374a382a137"}, - {file = "numpy-1.26.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b8c275f0ae90069496068c714387b4a0eba5d531aace269559ff2b43655edd58"}, - {file = "numpy-1.26.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cc0743f0302b94f397a4a65a660d4cd24267439eb16493fb3caad2e4389bccbb"}, - {file = "numpy-1.26.3-cp39-cp39-win32.whl", hash = "sha256:9bc6d1a7f8cedd519c4b7b1156d98e051b726bf160715b769106661d567b3f03"}, - {file = "numpy-1.26.3-cp39-cp39-win_amd64.whl", hash = "sha256:867e3644e208c8922a3be26fc6bbf112a035f50f0a86497f98f228c50c607bb2"}, - {file = "numpy-1.26.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3c67423b3703f8fbd90f5adaa37f85b5794d3366948efe9a5190a5f3a83fc34e"}, - {file = "numpy-1.26.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46f47ee566d98849323f01b349d58f2557f02167ee301e5e28809a8c0e27a2d0"}, - {file = "numpy-1.26.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a8474703bffc65ca15853d5fd4d06b18138ae90c17c8d12169968e998e448bb5"}, - {file = "numpy-1.26.3.tar.gz", hash = "sha256:697df43e2b6310ecc9d95f05d5ef20eacc09c7c4ecc9da3f235d39e71b7da1e4"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, + {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, + {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, + {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, + {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, + {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, + {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, + {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, + {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, + {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, ] [[package]] name = "opencv-python" -version = "4.9.0.80" +version = "4.11.0.86" description = "Wrapper package for OpenCV python bindings." optional = false python-versions = ">=3.6" files = [ - {file = "opencv-python-4.9.0.80.tar.gz", hash = "sha256:1a9f0e6267de3a1a1db0c54213d022c7c8b5b9ca4b580e80bdc58516c922c9e1"}, - {file = "opencv_python-4.9.0.80-cp37-abi3-macosx_10_16_x86_64.whl", hash = "sha256:7e5f7aa4486651a6ebfa8ed4b594b65bd2d2f41beeb4241a3e4b1b85acbbbadb"}, - {file = "opencv_python-4.9.0.80-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:71dfb9555ccccdd77305fc3dcca5897fbf0cf28b297c51ee55e079c065d812a3"}, - {file = "opencv_python-4.9.0.80-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b34a52e9da36dda8c151c6394aed602e4b17fa041df0b9f5b93ae10b0fcca2a"}, - {file = "opencv_python-4.9.0.80-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4088cab82b66a3b37ffc452976b14a3c599269c247895ae9ceb4066d8188a57"}, - {file = "opencv_python-4.9.0.80-cp37-abi3-win32.whl", hash = "sha256:dcf000c36dd1651118a2462257e3a9e76db789a78432e1f303c7bac54f63ef6c"}, - {file = "opencv_python-4.9.0.80-cp37-abi3-win_amd64.whl", hash = "sha256:3f16f08e02b2a2da44259c7cc712e779eff1dd8b55fdb0323e8cab09548086c0"}, + {file = "opencv-python-4.11.0.86.tar.gz", hash = "sha256:03d60ccae62304860d232272e4a4fda93c39d595780cb40b161b310244b736a4"}, + {file = "opencv_python-4.11.0.86-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:432f67c223f1dc2824f5e73cdfcd9db0efc8710647d4e813012195dc9122a52a"}, + {file = "opencv_python-4.11.0.86-cp37-abi3-macosx_13_0_x86_64.whl", hash = "sha256:9d05ef13d23fe97f575153558653e2d6e87103995d54e6a35db3f282fe1f9c66"}, + {file = "opencv_python-4.11.0.86-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b92ae2c8852208817e6776ba1ea0d6b1e0a1b5431e971a2a0ddd2a8cc398202"}, + {file = "opencv_python-4.11.0.86-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b02611523803495003bd87362db3e1d2a0454a6a63025dc6658a9830570aa0d"}, + {file = "opencv_python-4.11.0.86-cp37-abi3-win32.whl", hash = "sha256:810549cb2a4aedaa84ad9a1c92fbfdfc14090e2749cedf2c1589ad8359aa169b"}, + {file = "opencv_python-4.11.0.86-cp37-abi3-win_amd64.whl", hash = "sha256:085ad9b77c18853ea66283e98affefe2de8cc4c1f43eda4c100cf9b2721142ec"}, ] [package.dependencies] numpy = [ + {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, + {version = ">=1.23.5", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, {version = ">=1.21.4", markers = "python_version >= \"3.10\" and platform_system == \"Darwin\" and python_version < \"3.11\""}, {version = ">=1.21.2", markers = "platform_system != \"Darwin\" and python_version >= \"3.10\" and python_version < \"3.11\""}, - {version = ">=1.23.5", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, - {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, ] [[package]] name = "orjson" -version = "3.9.12" +version = "3.11.9" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" optional = false -python-versions = ">=3.8" -files = [ - {file = "orjson-3.9.12-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:6b4e2bed7d00753c438e83b613923afdd067564ff7ed696bfe3a7b073a236e07"}, - {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd1b8ec63f0bf54a50b498eedeccdca23bd7b658f81c524d18e410c203189365"}, - {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ab8add018a53665042a5ae68200f1ad14c7953fa12110d12d41166f111724656"}, - {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12756a108875526b76e505afe6d6ba34960ac6b8c5ec2f35faf73ef161e97e07"}, - {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:890e7519c0c70296253660455f77e3a194554a3c45e42aa193cdebc76a02d82b"}, - {file = "orjson-3.9.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d664880d7f016efbae97c725b243b33c2cbb4851ddc77f683fd1eec4a7894146"}, - {file = "orjson-3.9.12-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cfdaede0fa5b500314ec7b1249c7e30e871504a57004acd116be6acdda3b8ab3"}, - {file = "orjson-3.9.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6492ff5953011e1ba9ed1bf086835fd574bd0a3cbe252db8e15ed72a30479081"}, - {file = "orjson-3.9.12-cp310-none-win32.whl", hash = "sha256:29bf08e2eadb2c480fdc2e2daae58f2f013dff5d3b506edd1e02963b9ce9f8a9"}, - {file = "orjson-3.9.12-cp310-none-win_amd64.whl", hash = "sha256:0fc156fba60d6b50743337ba09f052d8afc8b64595112996d22f5fce01ab57da"}, - {file = "orjson-3.9.12-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:2849f88a0a12b8d94579b67486cbd8f3a49e36a4cb3d3f0ab352c596078c730c"}, - {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3186b18754befa660b31c649a108a915493ea69b4fc33f624ed854ad3563ac65"}, - {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cbbf313c9fb9d4f6cf9c22ced4b6682230457741daeb3d7060c5d06c2e73884a"}, - {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99e8cd005b3926c3db9b63d264bd05e1bf4451787cc79a048f27f5190a9a0311"}, - {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:59feb148392d9155f3bfed0a2a3209268e000c2c3c834fb8fe1a6af9392efcbf"}, - {file = "orjson-3.9.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4ae815a172a1f073b05b9e04273e3b23e608a0858c4e76f606d2d75fcabde0c"}, - {file = "orjson-3.9.12-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ed398f9a9d5a1bf55b6e362ffc80ac846af2122d14a8243a1e6510a4eabcb71e"}, - {file = "orjson-3.9.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d3cfb76600c5a1e6be91326b8f3b83035a370e727854a96d801c1ea08b708073"}, - {file = "orjson-3.9.12-cp311-none-win32.whl", hash = "sha256:a2b6f5252c92bcab3b742ddb3ac195c0fa74bed4319acd74f5d54d79ef4715dc"}, - {file = "orjson-3.9.12-cp311-none-win_amd64.whl", hash = "sha256:c95488e4aa1d078ff5776b58f66bd29d628fa59adcb2047f4efd3ecb2bd41a71"}, - {file = "orjson-3.9.12-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d6ce2062c4af43b92b0221ed4f445632c6bf4213f8a7da5396a122931377acd9"}, - {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:950951799967558c214cd6cceb7ceceed6f81d2c3c4135ee4a2c9c69f58aa225"}, - {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2dfaf71499d6fd4153f5c86eebb68e3ec1bf95851b030a4b55c7637a37bbdee4"}, - {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:659a8d7279e46c97661839035a1a218b61957316bf0202674e944ac5cfe7ed83"}, - {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af17fa87bccad0b7f6fd8ac8f9cbc9ee656b4552783b10b97a071337616db3e4"}, - {file = "orjson-3.9.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd52dec9eddf4c8c74392f3fd52fa137b5f2e2bed1d9ae958d879de5f7d7cded"}, - {file = "orjson-3.9.12-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:640e2b5d8e36b970202cfd0799d11a9a4ab46cf9212332cd642101ec952df7c8"}, - {file = "orjson-3.9.12-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:daa438bd8024e03bcea2c5a92cd719a663a58e223fba967296b6ab9992259dbf"}, - {file = "orjson-3.9.12-cp312-none-win_amd64.whl", hash = "sha256:1bb8f657c39ecdb924d02e809f992c9aafeb1ad70127d53fb573a6a6ab59d549"}, - {file = "orjson-3.9.12-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:f4098c7674901402c86ba6045a551a2ee345f9f7ed54eeffc7d86d155c8427e5"}, - {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5586a533998267458fad3a457d6f3cdbddbcce696c916599fa8e2a10a89b24d3"}, - {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:54071b7398cd3f90e4bb61df46705ee96cb5e33e53fc0b2f47dbd9b000e238e1"}, - {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:67426651faa671b40443ea6f03065f9c8e22272b62fa23238b3efdacd301df31"}, - {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4a0cd56e8ee56b203abae7d482ac0d233dbfb436bb2e2d5cbcb539fe1200a312"}, - {file = "orjson-3.9.12-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a84a0c3d4841a42e2571b1c1ead20a83e2792644c5827a606c50fc8af7ca4bee"}, - {file = "orjson-3.9.12-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:09d60450cda3fa6c8ed17770c3a88473a16460cd0ff2ba74ef0df663b6fd3bb8"}, - {file = "orjson-3.9.12-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bc82a4db9934a78ade211cf2e07161e4f068a461c1796465d10069cb50b32a80"}, - {file = "orjson-3.9.12-cp38-none-win32.whl", hash = "sha256:61563d5d3b0019804d782137a4f32c72dc44c84e7d078b89d2d2a1adbaa47b52"}, - {file = "orjson-3.9.12-cp38-none-win_amd64.whl", hash = "sha256:410f24309fbbaa2fab776e3212a81b96a1ec6037259359a32ea79fbccfcf76aa"}, - {file = "orjson-3.9.12-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e773f251258dd82795fd5daeac081d00b97bacf1548e44e71245543374874bcf"}, - {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b159baecfda51c840a619948c25817d37733a4d9877fea96590ef8606468b362"}, - {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:975e72e81a249174840d5a8df977d067b0183ef1560a32998be340f7e195c730"}, - {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:06e42e899dde61eb1851a9fad7f1a21b8e4be063438399b63c07839b57668f6c"}, - {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c157e999e5694475a5515942aebeed6e43f7a1ed52267c1c93dcfde7d78d421"}, - {file = "orjson-3.9.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dde1bc7c035f2d03aa49dc8642d9c6c9b1a81f2470e02055e76ed8853cfae0c3"}, - {file = "orjson-3.9.12-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b0e9d73cdbdad76a53a48f563447e0e1ce34bcecef4614eb4b146383e6e7d8c9"}, - {file = "orjson-3.9.12-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:96e44b21fe407b8ed48afbb3721f3c8c8ce17e345fbe232bd4651ace7317782d"}, - {file = "orjson-3.9.12-cp39-none-win32.whl", hash = "sha256:cbd0f3555205bf2a60f8812133f2452d498dbefa14423ba90fe89f32276f7abf"}, - {file = "orjson-3.9.12-cp39-none-win_amd64.whl", hash = "sha256:03ea7ee7e992532c2f4a06edd7ee1553f0644790553a118e003e3c405add41fa"}, - {file = "orjson-3.9.12.tar.gz", hash = "sha256:da908d23a3b3243632b523344403b128722a5f45e278a8343c2bb67538dff0e4"}, +python-versions = ">=3.10" +files = [ + {file = "orjson-3.11.9-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:135869ef917b8704ea0a94e01620e0c05021c15c52036e4663baffe75e72f8ce"}, + {file = "orjson-3.11.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:115ab5f5f4a0f203cc2a5f0fb09aee503a3f771aa08392949ab5ca230c4fbdbd"}, + {file = "orjson-3.11.9-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4da3c38a2083ca4aaf9c2a36776cce3e9328e6647b10d118948f3cfb4913ffe4"}, + {file = "orjson-3.11.9-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53b50b0e14084b8f7e29c5ce84c5af0f1160169b30d8a6914231d97d2fe297d4"}, + {file = "orjson-3.11.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:231742b4a11dad8d5380a435962c57e91b7c37b79be858f4ef1c0df1a259897e"}, + {file = "orjson-3.11.9-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:34fd2317602587321faab75ab76c623a0117e80841a6413654f04e47f339a8fb"}, + {file = "orjson-3.11.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:71f3db16e69b667b132e0f305a833d5497da302d801508cbb051ed9a9819da47"}, + {file = "orjson-3.11.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0b34789fa0da61cf7bef0546b09c738fb195331e017e477096d129e9105ab03d"}, + {file = "orjson-3.11.9-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:87e4d4ab280b0c87424d47695bec2182caf8cfc17879ea78dab76680194abc13"}, + {file = "orjson-3.11.9-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ace6c58523302d3b97b6ac5c38a5298a54b473762b6be82726b4265c41029f92"}, + {file = "orjson-3.11.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:97d0d932803c1b164fde11cb542a9efcb1e0f63b184537cca65887147906ff48"}, + {file = "orjson-3.11.9-cp310-cp310-win32.whl", hash = "sha256:b3afcf569c15577a9fe64627292daa3e6b3a70f4fb77a5df246a87ec21681b94"}, + {file = "orjson-3.11.9-cp310-cp310-win_amd64.whl", hash = "sha256:8697ab6a080a5c46edaad50e2bc5bd8c7ca5c66442d24104fa44ec74910a8244"}, + {file = "orjson-3.11.9-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:f01c4818b3fc9b0da8e096722a84318071eaa118df35f6ed2344da0e73a5444f"}, + {file = "orjson-3.11.9-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:3ebca4179031ee716ed076ffadc29428e900512f6fccee8614c9983157fcf19c"}, + {file = "orjson-3.11.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48ee05097750de0ff69ed5b7bbcf0732182fd57a24043dcc2a1da780a5ead3a5"}, + {file = "orjson-3.11.9-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a6082706765a95a6680d812e1daf1c0cfe8adec7831b3ff3b625693f3b461b1c"}, + {file = "orjson-3.11.9-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:277fefe9d76ee17eb14debf399e3533d4d63b5f677a4d3719eb763536af1f4bd"}, + {file = "orjson-3.11.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03db380e3780fa0015ed776a90f20e8e20bb11dde13b216ce19e5718e3dfba62"}, + {file = "orjson-3.11.9-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33d7d766701847dc6729846362dc27895d2f2d2251264f9d10e7cb9878194877"}, + {file = "orjson-3.11.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:147302878da387104b66bb4a8b0227d1d487e976ce41a8501916161072ed87b1"}, + {file = "orjson-3.11.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3513550321f8c8c811a7c3297b8a630e82dc08e4c10216d07703c997776236cd"}, + {file = "orjson-3.11.9-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:c5d001196b89fa9cf0a4ab79766cd835b991a166e4b621ba95089edc50c429ff"}, + {file = "orjson-3.11.9-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:16969c9d369c98eb084889c6e4d2d39b77c7eb38ceccf8da2a9fff62ae908980"}, + {file = "orjson-3.11.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:63e0efbc991250c0b3143488fa57d95affcabbfc63c99c48d625dd37779aafe2"}, + {file = "orjson-3.11.9-cp311-cp311-win32.whl", hash = "sha256:14ed654580c1ed2bc217352ec82f91b047aef82951aa71c7f64e0dcb03c0e180"}, + {file = "orjson-3.11.9-cp311-cp311-win_amd64.whl", hash = "sha256:57ea77fb70a448ce87d18fca050193202a3da5e54598f6501ca5476fb66cfe02"}, + {file = "orjson-3.11.9-cp311-cp311-win_arm64.whl", hash = "sha256:19b72ed11572a2ee51a67a903afbe5af504f84ed6f529c0fe44b0ab3fb5cc697"}, + {file = "orjson-3.11.9-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9ef6fe90aadef185c7b128859f40beb24720b4ecea95379fc9000931179c3a49"}, + {file = "orjson-3.11.9-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:e5c9b8f28e726e97d97696c826bc7bea5d71cecd63576dba92924a32c1961291"}, + {file = "orjson-3.11.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26a473dbb4162108b27901492546f83c76fdcea3d0eadff00ae7a07e18dcce09"}, + {file = "orjson-3.11.9-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:011382e2a60fda9d46f1cdee31068cfc52ffe952b587d683ec0463002802a0f4"}, + {file = "orjson-3.11.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c2d3dc759490128c5c1711a53eeaa8ee1d437fd0038ffd2b6008abf46db3f882"}, + {file = "orjson-3.11.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d8ea516b3726d190e1b4297e6f4e7a8650347ae053868a18163b4dd3641d1fff"}, + {file = "orjson-3.11.9-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:380cdce7ba24989af81d0a7013d0aaec5d0e2a21734c0e2681b1bc4f141957fe"}, + {file = "orjson-3.11.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be4fa4f0af7fa18951f7ab3fc2148e223af211bf03f59e1c6034ec3f97f21d61"}, + {file = "orjson-3.11.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a8f5f8bc7ce7d59f08d9f99fa510c06496164a24cb5f3d34537dbd9ca30132e2"}, + {file = "orjson-3.11.9-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:4d7fde5501b944f83b3e665e1b31343ff6e154b15560a16b7130ea1e594a4206"}, + {file = "orjson-3.11.9-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cde1a448023ba7d5bb4c01c5afb48894380b5e4956e0627266526587ef4e535f"}, + {file = "orjson-3.11.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:71e63adb0e1f1ed5d9e168f50a91ceb93ae6420731d222dc7da5c69409aa47aa"}, + {file = "orjson-3.11.9-cp312-cp312-win32.whl", hash = "sha256:2d057a602cdd19a0ad680417527c45b6961a095081c0f46fe0e03e304aac6470"}, + {file = "orjson-3.11.9-cp312-cp312-win_amd64.whl", hash = "sha256:59e403b1cc5a676da8eaf31f6254801b7341b3e29efa85f92b48d272637e77be"}, + {file = "orjson-3.11.9-cp312-cp312-win_arm64.whl", hash = "sha256:9af678d6488357948f1f84c6cd1c1d397c014e1ae2f98ae082a44eb48f602624"}, + {file = "orjson-3.11.9-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:4bab1b2d6141fe7b32ae71dac905666ece4f94936efbfb13d55bb7739a3a6021"}, + {file = "orjson-3.11.9-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:844417969855fc7a41be124aafe83dc424592a7f77cd4501900c67307122b92c"}, + {file = "orjson-3.11.9-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffe02797b5e9f3a9d8292ddcd289b474ad13e81ad83cd1891a240811f1d2cb81"}, + {file = "orjson-3.11.9-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e4eed3b200023042814d2fc8a5d2e880f13b52e1ed2485e83da4f3962f7dc1a"}, + {file = "orjson-3.11.9-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8aff7da9952a5ad1cef8e68017724d96c7b9a66e99e91d6252e1b133d67a7b10"}, + {file = "orjson-3.11.9-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4d4e98d6f3b8afed8bc8cd9718ec0cdf46661826beefb53fe8eafb37f2bf0362"}, + {file = "orjson-3.11.9-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a81d52442a7c99b3662333235b3adf96a1715864658b35bb797212be7bddb97"}, + {file = "orjson-3.11.9-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e39364e726a8fff737309aff059ff67d8a8c8d5b677be7bb49a8b3e84b7e218"}, + {file = "orjson-3.11.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4fd66214623f1b17501df9f0543bef0b833979ab5b6ded1e1d123222866aa8c9"}, + {file = "orjson-3.11.9-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:8ecc30f10465fa1e0ce13fd01d9e22c316e5053a719a8d915d4545a09a5ff677"}, + {file = "orjson-3.11.9-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:97db4c94a7db398a5bd636273324f0b3fd58b350bbbac8bb380ceb825a9b40f4"}, + {file = "orjson-3.11.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9f78cf8fec5bd627f4082b8dfeac7871b43d7f3274904492a43dab39f18a19a0"}, + {file = "orjson-3.11.9-cp313-cp313-win32.whl", hash = "sha256:d4087e5c0209a0a8efe4de3303c234b9c44d1174161dcd851e8eea07c7560b32"}, + {file = "orjson-3.11.9-cp313-cp313-win_amd64.whl", hash = "sha256:051b102c93b4f634e89f3866b07b9a9a98915ada541f4ec30f177067b2694979"}, + {file = "orjson-3.11.9-cp313-cp313-win_arm64.whl", hash = "sha256:cce9127885941bd28f080cecf1f1d288336b7e0d812c345b08be88b572796254"}, + {file = "orjson-3.11.9-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:b6ef1979adc4bc243523f1a2ba91418030a8e29b0a99cbe7e0e2d6807d4dce6e"}, + {file = "orjson-3.11.9-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:f36b7f32c7c0db4a719f1fc5824db4a9c6f8bd1a354debb91faf26ebf3a4c71e"}, + {file = "orjson-3.11.9-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08f4d8ebb44925c794e535b2bebc507cebf32209df81de22ae285fb0d8d66de0"}, + {file = "orjson-3.11.9-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6cc7923789694fd58f001cbcac7e47abc13af4d560ebbfcf3b41a8b1a0748124"}, + {file = "orjson-3.11.9-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea5c46eb2d3af39e806b986f4b09d5c2706a1f5afde3cbf7544ce6616127173c"}, + {file = "orjson-3.11.9-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f5d89a2ed90731df3be64bab0aa44f78bff39fdc9d71c291f4a8023aa46425b7"}, + {file = "orjson-3.11.9-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:25e4aed0312d292c09f61af25bba34e0b2c88546041472b09088c39a4d828af1"}, + {file = "orjson-3.11.9-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaea64f3f467d22e70eeed68bdccb3bc4f83f650446c4a03c59f2cba28a108db"}, + {file = "orjson-3.11.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a028425d1b440c5d92a6be1e1a020739dfe67ea87d96c6dbe828c1b30041728b"}, + {file = "orjson-3.11.9-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:5b192c6cf397e4455b11523c5cf2b18ed084c1bbd61b6c0926344d2129481972"}, + {file = "orjson-3.11.9-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ea407d4ccf5891d667d045fecae97a7a1e5e87b3b97f97ae1803c2e741130be0"}, + {file = "orjson-3.11.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5f63aaf97afd9f6dec5b1a68e1b8da12bfccb4cb9a9a65c3e0b6c847849e7586"}, + {file = "orjson-3.11.9-cp314-cp314-win32.whl", hash = "sha256:e30ab17845bb9fa54ccf67fa4f9f5282652d54faa6d17452f47d0f369d038673"}, + {file = "orjson-3.11.9-cp314-cp314-win_amd64.whl", hash = "sha256:32ef5f4283a3be81913947d19608eacb7c6608026851123790cd9cc8982af34b"}, + {file = "orjson-3.11.9-cp314-cp314-win_arm64.whl", hash = "sha256:eebdbdeef0094e4f5aefa20dcd4eb2368ab5e7a3b4edea27f1e7b2892e009cf9"}, + {file = "orjson-3.11.9.tar.gz", hash = "sha256:4fef17e1f8722c11587a6ef18e35902450221da0028e65dbaaa543619e68e48f"}, ] [[package]] name = "packaging" -version = "23.2" +version = "26.2" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, + {file = "packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e"}, + {file = "packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661"}, ] [[package]] name = "pandas" -version = "2.2.0" +version = "2.3.3" description = "Powerful data structures for data analysis, time series, and statistics" optional = false python-versions = ">=3.9" files = [ - {file = "pandas-2.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8108ee1712bb4fa2c16981fba7e68b3f6ea330277f5ca34fa8d557e986a11670"}, - {file = "pandas-2.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:736da9ad4033aeab51d067fc3bd69a0ba36f5a60f66a527b3d72e2030e63280a"}, - {file = "pandas-2.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38e0b4fc3ddceb56ec8a287313bc22abe17ab0eb184069f08fc6a9352a769b18"}, - {file = "pandas-2.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20404d2adefe92aed3b38da41d0847a143a09be982a31b85bc7dd565bdba0f4e"}, - {file = "pandas-2.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7ea3ee3f125032bfcade3a4cf85131ed064b4f8dd23e5ce6fa16473e48ebcaf5"}, - {file = "pandas-2.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f9670b3ac00a387620489dfc1bca66db47a787f4e55911f1293063a78b108df1"}, - {file = "pandas-2.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:5a946f210383c7e6d16312d30b238fd508d80d927014f3b33fb5b15c2f895430"}, - {file = "pandas-2.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a1b438fa26b208005c997e78672f1aa8138f67002e833312e6230f3e57fa87d5"}, - {file = "pandas-2.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8ce2fbc8d9bf303ce54a476116165220a1fedf15985b09656b4b4275300e920b"}, - {file = "pandas-2.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2707514a7bec41a4ab81f2ccce8b382961a29fbe9492eab1305bb075b2b1ff4f"}, - {file = "pandas-2.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85793cbdc2d5bc32620dc8ffa715423f0c680dacacf55056ba13454a5be5de88"}, - {file = "pandas-2.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cfd6c2491dc821b10c716ad6776e7ab311f7df5d16038d0b7458bc0b67dc10f3"}, - {file = "pandas-2.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a146b9dcacc3123aa2b399df1a284de5f46287a4ab4fbfc237eac98a92ebcb71"}, - {file = "pandas-2.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:fbc1b53c0e1fdf16388c33c3cca160f798d38aea2978004dd3f4d3dec56454c9"}, - {file = "pandas-2.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a41d06f308a024981dcaa6c41f2f2be46a6b186b902c94c2674e8cb5c42985bc"}, - {file = "pandas-2.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:159205c99d7a5ce89ecfc37cb08ed179de7783737cea403b295b5eda8e9c56d1"}, - {file = "pandas-2.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb1e1f3861ea9132b32f2133788f3b14911b68102d562715d71bd0013bc45440"}, - {file = "pandas-2.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:761cb99b42a69005dec2b08854fb1d4888fdf7b05db23a8c5a099e4b886a2106"}, - {file = "pandas-2.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a20628faaf444da122b2a64b1e5360cde100ee6283ae8effa0d8745153809a2e"}, - {file = "pandas-2.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f5be5d03ea2073627e7111f61b9f1f0d9625dc3c4d8dda72cc827b0c58a1d042"}, - {file = "pandas-2.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:a626795722d893ed6aacb64d2401d017ddc8a2341b49e0384ab9bf7112bdec30"}, - {file = "pandas-2.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9f66419d4a41132eb7e9a73dcec9486cf5019f52d90dd35547af11bc58f8637d"}, - {file = "pandas-2.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:57abcaeda83fb80d447f28ab0cc7b32b13978f6f733875ebd1ed14f8fbc0f4ab"}, - {file = "pandas-2.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e60f1f7dba3c2d5ca159e18c46a34e7ca7247a73b5dd1a22b6d59707ed6b899a"}, - {file = "pandas-2.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb61dc8567b798b969bcc1fc964788f5a68214d333cade8319c7ab33e2b5d88a"}, - {file = "pandas-2.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:52826b5f4ed658fa2b729264d63f6732b8b29949c7fd234510d57c61dbeadfcd"}, - {file = "pandas-2.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bde2bc699dbd80d7bc7f9cab1e23a95c4375de615860ca089f34e7c64f4a8de7"}, - {file = "pandas-2.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:3de918a754bbf2da2381e8a3dcc45eede8cd7775b047b923f9006d5f876802ae"}, - {file = "pandas-2.2.0.tar.gz", hash = "sha256:30b83f7c3eb217fb4d1b494a57a2fda5444f17834f5df2de6b2ffff68dc3c8e2"}, + {file = "pandas-2.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:376c6446ae31770764215a6c937f72d917f214b43560603cd60da6408f183b6c"}, + {file = "pandas-2.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e19d192383eab2f4ceb30b412b22ea30690c9e618f78870357ae1d682912015a"}, + {file = "pandas-2.3.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5caf26f64126b6c7aec964f74266f435afef1c1b13da3b0636c7518a1fa3e2b1"}, + {file = "pandas-2.3.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd7478f1463441ae4ca7308a70e90b33470fa593429f9d4c578dd00d1fa78838"}, + {file = "pandas-2.3.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4793891684806ae50d1288c9bae9330293ab4e083ccd1c5e383c34549c6e4250"}, + {file = "pandas-2.3.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:28083c648d9a99a5dd035ec125d42439c6c1c525098c58af0fc38dd1a7a1b3d4"}, + {file = "pandas-2.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:503cf027cf9940d2ceaa1a93cfb5f8c8c7e6e90720a2850378f0b3f3b1e06826"}, + {file = "pandas-2.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:602b8615ebcc4a0c1751e71840428ddebeb142ec02c786e8ad6b1ce3c8dec523"}, + {file = "pandas-2.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8fe25fc7b623b0ef6b5009149627e34d2a4657e880948ec3c840e9402e5c1b45"}, + {file = "pandas-2.3.3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b468d3dad6ff947df92dcb32ede5b7bd41a9b3cceef0a30ed925f6d01fb8fa66"}, + {file = "pandas-2.3.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b98560e98cb334799c0b07ca7967ac361a47326e9b4e5a7dfb5ab2b1c9d35a1b"}, + {file = "pandas-2.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37b5848ba49824e5c30bedb9c830ab9b7751fd049bc7914533e01c65f79791"}, + {file = "pandas-2.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:db4301b2d1f926ae677a751eb2bd0e8c5f5319c9cb3f88b0becbbb0b07b34151"}, + {file = "pandas-2.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:f086f6fe114e19d92014a1966f43a3e62285109afe874f067f5abbdcbb10e59c"}, + {file = "pandas-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d21f6d74eb1725c2efaa71a2bfc661a0689579b58e9c0ca58a739ff0b002b53"}, + {file = "pandas-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3fd2f887589c7aa868e02632612ba39acb0b8948faf5cc58f0850e165bd46f35"}, + {file = "pandas-2.3.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecaf1e12bdc03c86ad4a7ea848d66c685cb6851d807a26aa245ca3d2017a1908"}, + {file = "pandas-2.3.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b3d11d2fda7eb164ef27ffc14b4fcab16a80e1ce67e9f57e19ec0afaf715ba89"}, + {file = "pandas-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a68e15f780eddf2b07d242e17a04aa187a7ee12b40b930bfdd78070556550e98"}, + {file = "pandas-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:371a4ab48e950033bcf52b6527eccb564f52dc826c02afd9a1bc0ab731bba084"}, + {file = "pandas-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:a16dcec078a01eeef8ee61bf64074b4e524a2a3f4b3be9326420cabe59c4778b"}, + {file = "pandas-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:56851a737e3470de7fa88e6131f41281ed440d29a9268dcbf0002da5ac366713"}, + {file = "pandas-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdcd9d1167f4885211e401b3036c0c8d9e274eee67ea8d0758a256d60704cfe8"}, + {file = "pandas-2.3.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e32e7cc9af0f1cc15548288a51a3b681cc2a219faa838e995f7dc53dbab1062d"}, + {file = "pandas-2.3.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318d77e0e42a628c04dc56bcef4b40de67918f7041c2b061af1da41dcff670ac"}, + {file = "pandas-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e0a175408804d566144e170d0476b15d78458795bb18f1304fb94160cabf40c"}, + {file = "pandas-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2d9ab0fc11822b5eece72ec9587e172f63cff87c00b062f6e37448ced4493"}, + {file = "pandas-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f8bfc0e12dc78f777f323f55c58649591b2cd0c43534e8355c51d3fede5f4dee"}, + {file = "pandas-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:75ea25f9529fdec2d2e93a42c523962261e567d250b0013b16210e1d40d7c2e5"}, + {file = "pandas-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74ecdf1d301e812db96a465a525952f4dde225fdb6d8e5a521d47e1f42041e21"}, + {file = "pandas-2.3.3-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6435cb949cb34ec11cc9860246ccb2fdc9ecd742c12d3304989017d53f039a78"}, + {file = "pandas-2.3.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:900f47d8f20860de523a1ac881c4c36d65efcb2eb850e6948140fa781736e110"}, + {file = "pandas-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a45c765238e2ed7d7c608fc5bc4a6f88b642f2f01e70c0c23d2224dd21829d86"}, + {file = "pandas-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4fc4c21971a1a9f4bdb4c73978c7f7256caa3e62b323f70d6cb80db583350bc"}, + {file = "pandas-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ee15f284898e7b246df8087fc82b87b01686f98ee67d85a17b7ab44143a3a9a0"}, + {file = "pandas-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1611aedd912e1ff81ff41c745822980c49ce4a7907537be8692c8dbc31924593"}, + {file = "pandas-2.3.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d2cefc361461662ac48810cb14365a365ce864afe85ef1f447ff5a1e99ea81c"}, + {file = "pandas-2.3.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ee67acbbf05014ea6c763beb097e03cd629961c8a632075eeb34247120abcb4b"}, + {file = "pandas-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c46467899aaa4da076d5abc11084634e2d197e9460643dd455ac3db5856b24d6"}, + {file = "pandas-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6253c72c6a1d990a410bc7de641d34053364ef8bcd3126f7e7450125887dffe3"}, + {file = "pandas-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:1b07204a219b3b7350abaae088f451860223a52cfb8a6c53358e7948735158e5"}, + {file = "pandas-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2462b1a365b6109d275250baaae7b760fd25c726aaca0054649286bcfbb3e8ec"}, + {file = "pandas-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0242fe9a49aa8b4d78a4fa03acb397a58833ef6199e9aa40a95f027bb3a1b6e7"}, + {file = "pandas-2.3.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a21d830e78df0a515db2b3d2f5570610f5e6bd2e27749770e8bb7b524b89b450"}, + {file = "pandas-2.3.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e3ebdb170b5ef78f19bfb71b0dc5dc58775032361fa188e814959b74d726dd5"}, + {file = "pandas-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d051c0e065b94b7a3cea50eb1ec32e912cd96dba41647eb24104b6c6c14c5788"}, + {file = "pandas-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3869faf4bd07b3b66a9f462417d0ca3a9df29a9f6abd5d0d0dbab15dac7abe87"}, + {file = "pandas-2.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c503ba5216814e295f40711470446bc3fd00f0faea8a086cbc688808e26f92a2"}, + {file = "pandas-2.3.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a637c5cdfa04b6d6e2ecedcb81fc52ffb0fd78ce2ebccc9ea964df9f658de8c8"}, + {file = "pandas-2.3.3-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:854d00d556406bffe66a4c0802f334c9ad5a96b4f1f868adf036a21b11ef13ff"}, + {file = "pandas-2.3.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bf1f8a81d04ca90e32a0aceb819d34dbd378a98bf923b6398b9a3ec0bf44de29"}, + {file = "pandas-2.3.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:23ebd657a4d38268c7dfbdf089fbc31ea709d82e4923c5ffd4fbd5747133ce73"}, + {file = "pandas-2.3.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5554c929ccc317d41a5e3d1234f3be588248e61f08a74dd17c9eabb535777dc9"}, + {file = "pandas-2.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:d3e28b3e83862ccf4d85ff19cf8c20b2ae7e503881711ff2d534dc8f761131aa"}, + {file = "pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b"}, ] [package.dependencies] numpy = [ - {version = ">=1.22.4,<2", markers = "python_version < \"3.11\""}, - {version = ">=1.23.2,<2", markers = "python_version == \"3.11\""}, - {version = ">=1.26.0,<2", markers = "python_version >= \"3.12\""}, + {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, + {version = ">=1.23.2", markers = "python_version == \"3.11\""}, + {version = ">=1.22.4", markers = "python_version < \"3.11\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" @@ -2806,6 +3464,7 @@ parquet = ["pyarrow (>=10.0.1)"] performance = ["bottleneck (>=1.3.6)", "numba (>=0.56.4)", "numexpr (>=2.8.4)"] plot = ["matplotlib (>=3.6.3)"] postgresql = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "psycopg2 (>=2.9.6)"] +pyarrow = ["pyarrow (>=10.0.1)"] spss = ["pyreadstat (>=1.2.0)"] sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)"] test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] @@ -2841,135 +3500,143 @@ pyasn1 = "*" [[package]] name = "pillow" -version = "11.0.0" -description = "Python Imaging Library (Fork)" -optional = false -python-versions = ">=3.9" -files = [ - {file = "pillow-11.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:6619654954dc4936fcff82db8eb6401d3159ec6be81e33c6000dfd76ae189947"}, - {file = "pillow-11.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b3c5ac4bed7519088103d9450a1107f76308ecf91d6dabc8a33a2fcfb18d0fba"}, - {file = "pillow-11.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a65149d8ada1055029fcb665452b2814fe7d7082fcb0c5bed6db851cb69b2086"}, - {file = "pillow-11.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88a58d8ac0cc0e7f3a014509f0455248a76629ca9b604eca7dc5927cc593c5e9"}, - {file = "pillow-11.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:c26845094b1af3c91852745ae78e3ea47abf3dbcd1cf962f16b9a5fbe3ee8488"}, - {file = "pillow-11.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:1a61b54f87ab5786b8479f81c4b11f4d61702830354520837f8cc791ebba0f5f"}, - {file = "pillow-11.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:674629ff60030d144b7bca2b8330225a9b11c482ed408813924619c6f302fdbb"}, - {file = "pillow-11.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:598b4e238f13276e0008299bd2482003f48158e2b11826862b1eb2ad7c768b97"}, - {file = "pillow-11.0.0-cp310-cp310-win32.whl", hash = "sha256:9a0f748eaa434a41fccf8e1ee7a3eed68af1b690e75328fd7a60af123c193b50"}, - {file = "pillow-11.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:a5629742881bcbc1f42e840af185fd4d83a5edeb96475a575f4da50d6ede337c"}, - {file = "pillow-11.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:ee217c198f2e41f184f3869f3e485557296d505b5195c513b2bfe0062dc537f1"}, - {file = "pillow-11.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1c1d72714f429a521d8d2d018badc42414c3077eb187a59579f28e4270b4b0fc"}, - {file = "pillow-11.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:499c3a1b0d6fc8213519e193796eb1a86a1be4b1877d678b30f83fd979811d1a"}, - {file = "pillow-11.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8b2351c85d855293a299038e1f89db92a2f35e8d2f783489c6f0b2b5f3fe8a3"}, - {file = "pillow-11.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f4dba50cfa56f910241eb7f883c20f1e7b1d8f7d91c750cd0b318bad443f4d5"}, - {file = "pillow-11.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5ddbfd761ee00c12ee1be86c9c0683ecf5bb14c9772ddbd782085779a63dd55b"}, - {file = "pillow-11.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:45c566eb10b8967d71bf1ab8e4a525e5a93519e29ea071459ce517f6b903d7fa"}, - {file = "pillow-11.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b4fd7bd29610a83a8c9b564d457cf5bd92b4e11e79a4ee4716a63c959699b306"}, - {file = "pillow-11.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cb929ca942d0ec4fac404cbf520ee6cac37bf35be479b970c4ffadf2b6a1cad9"}, - {file = "pillow-11.0.0-cp311-cp311-win32.whl", hash = "sha256:006bcdd307cc47ba43e924099a038cbf9591062e6c50e570819743f5607404f5"}, - {file = "pillow-11.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:52a2d8323a465f84faaba5236567d212c3668f2ab53e1c74c15583cf507a0291"}, - {file = "pillow-11.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:16095692a253047fe3ec028e951fa4221a1f3ed3d80c397e83541a3037ff67c9"}, - {file = "pillow-11.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2c0a187a92a1cb5ef2c8ed5412dd8d4334272617f532d4ad4de31e0495bd923"}, - {file = "pillow-11.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:084a07ef0821cfe4858fe86652fffac8e187b6ae677e9906e192aafcc1b69903"}, - {file = "pillow-11.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8069c5179902dcdce0be9bfc8235347fdbac249d23bd90514b7a47a72d9fecf4"}, - {file = "pillow-11.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f02541ef64077f22bf4924f225c0fd1248c168f86e4b7abdedd87d6ebaceab0f"}, - {file = "pillow-11.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:fcb4621042ac4b7865c179bb972ed0da0218a076dc1820ffc48b1d74c1e37fe9"}, - {file = "pillow-11.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:00177a63030d612148e659b55ba99527803288cea7c75fb05766ab7981a8c1b7"}, - {file = "pillow-11.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8853a3bf12afddfdf15f57c4b02d7ded92c7a75a5d7331d19f4f9572a89c17e6"}, - {file = "pillow-11.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3107c66e43bda25359d5ef446f59c497de2b5ed4c7fdba0894f8d6cf3822dafc"}, - {file = "pillow-11.0.0-cp312-cp312-win32.whl", hash = "sha256:86510e3f5eca0ab87429dd77fafc04693195eec7fd6a137c389c3eeb4cfb77c6"}, - {file = "pillow-11.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:8ec4a89295cd6cd4d1058a5e6aec6bf51e0eaaf9714774e1bfac7cfc9051db47"}, - {file = "pillow-11.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:27a7860107500d813fcd203b4ea19b04babe79448268403172782754870dac25"}, - {file = "pillow-11.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bcd1fb5bb7b07f64c15618c89efcc2cfa3e95f0e3bcdbaf4642509de1942a699"}, - {file = "pillow-11.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e038b0745997c7dcaae350d35859c9715c71e92ffb7e0f4a8e8a16732150f38"}, - {file = "pillow-11.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ae08bd8ffc41aebf578c2af2f9d8749d91f448b3bfd41d7d9ff573d74f2a6b2"}, - {file = "pillow-11.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d69bfd8ec3219ae71bcde1f942b728903cad25fafe3100ba2258b973bd2bc1b2"}, - {file = "pillow-11.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:61b887f9ddba63ddf62fd02a3ba7add935d053b6dd7d58998c630e6dbade8527"}, - {file = "pillow-11.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:c6a660307ca9d4867caa8d9ca2c2658ab685de83792d1876274991adec7b93fa"}, - {file = "pillow-11.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:73e3a0200cdda995c7e43dd47436c1548f87a30bb27fb871f352a22ab8dcf45f"}, - {file = "pillow-11.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fba162b8872d30fea8c52b258a542c5dfd7b235fb5cb352240c8d63b414013eb"}, - {file = "pillow-11.0.0-cp313-cp313-win32.whl", hash = "sha256:f1b82c27e89fffc6da125d5eb0ca6e68017faf5efc078128cfaa42cf5cb38798"}, - {file = "pillow-11.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ba470552b48e5835f1d23ecb936bb7f71d206f9dfeee64245f30c3270b994de"}, - {file = "pillow-11.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:846e193e103b41e984ac921b335df59195356ce3f71dcfd155aa79c603873b84"}, - {file = "pillow-11.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4ad70c4214f67d7466bea6a08061eba35c01b1b89eaa098040a35272a8efb22b"}, - {file = "pillow-11.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6ec0d5af64f2e3d64a165f490d96368bb5dea8b8f9ad04487f9ab60dc4bb6003"}, - {file = "pillow-11.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c809a70e43c7977c4a42aefd62f0131823ebf7dd73556fa5d5950f5b354087e2"}, - {file = "pillow-11.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:4b60c9520f7207aaf2e1d94de026682fc227806c6e1f55bba7606d1c94dd623a"}, - {file = "pillow-11.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1e2688958a840c822279fda0086fec1fdab2f95bf2b717b66871c4ad9859d7e8"}, - {file = "pillow-11.0.0-cp313-cp313t-win32.whl", hash = "sha256:607bbe123c74e272e381a8d1957083a9463401f7bd01287f50521ecb05a313f8"}, - {file = "pillow-11.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c39ed17edea3bc69c743a8dd3e9853b7509625c2462532e62baa0732163a904"}, - {file = "pillow-11.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:75acbbeb05b86bc53cbe7b7e6fe00fbcf82ad7c684b3ad82e3d711da9ba287d3"}, - {file = "pillow-11.0.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2e46773dc9f35a1dd28bd6981332fd7f27bec001a918a72a79b4133cf5291dba"}, - {file = "pillow-11.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2679d2258b7f1192b378e2893a8a0a0ca472234d4c2c0e6bdd3380e8dfa21b6a"}, - {file = "pillow-11.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eda2616eb2313cbb3eebbe51f19362eb434b18e3bb599466a1ffa76a033fb916"}, - {file = "pillow-11.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ec184af98a121fb2da42642dea8a29ec80fc3efbaefb86d8fdd2606619045d"}, - {file = "pillow-11.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:8594f42df584e5b4bb9281799698403f7af489fba84c34d53d1c4bfb71b7c4e7"}, - {file = "pillow-11.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:c12b5ae868897c7338519c03049a806af85b9b8c237b7d675b8c5e089e4a618e"}, - {file = "pillow-11.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:70fbbdacd1d271b77b7721fe3cdd2d537bbbd75d29e6300c672ec6bb38d9672f"}, - {file = "pillow-11.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5178952973e588b3f1360868847334e9e3bf49d19e169bbbdfaf8398002419ae"}, - {file = "pillow-11.0.0-cp39-cp39-win32.whl", hash = "sha256:8c676b587da5673d3c75bd67dd2a8cdfeb282ca38a30f37950511766b26858c4"}, - {file = "pillow-11.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:94f3e1780abb45062287b4614a5bc0874519c86a777d4a7ad34978e86428b8dd"}, - {file = "pillow-11.0.0-cp39-cp39-win_arm64.whl", hash = "sha256:290f2cc809f9da7d6d622550bbf4c1e57518212da51b6a30fe8e0a270a5b78bd"}, - {file = "pillow-11.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1187739620f2b365de756ce086fdb3604573337cc28a0d3ac4a01ab6b2d2a6d2"}, - {file = "pillow-11.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fbbcb7b57dc9c794843e3d1258c0fbf0f48656d46ffe9e09b63bbd6e8cd5d0a2"}, - {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d203af30149ae339ad1b4f710d9844ed8796e97fda23ffbc4cc472968a47d0b"}, - {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21a0d3b115009ebb8ac3d2ebec5c2982cc693da935f4ab7bb5c8ebe2f47d36f2"}, - {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:73853108f56df97baf2bb8b522f3578221e56f646ba345a372c78326710d3830"}, - {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e58876c91f97b0952eb766123bfef372792ab3f4e3e1f1a2267834c2ab131734"}, - {file = "pillow-11.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:224aaa38177597bb179f3ec87eeefcce8e4f85e608025e9cfac60de237ba6316"}, - {file = "pillow-11.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5bd2d3bdb846d757055910f0a59792d33b555800813c3b39ada1829c372ccb06"}, - {file = "pillow-11.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:375b8dd15a1f5d2feafff536d47e22f69625c1aa92f12b339ec0b2ca40263273"}, - {file = "pillow-11.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:daffdf51ee5db69a82dd127eabecce20729e21f7a3680cf7cbb23f0829189790"}, - {file = "pillow-11.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7326a1787e3c7b0429659e0a944725e1b03eeaa10edd945a86dead1913383944"}, - {file = "pillow-11.0.0.tar.gz", hash = "sha256:72bacbaf24ac003fea9bff9837d1eedb6088758d41e100c1552930151f677739"}, +version = "12.3.0" +description = "Python Imaging Library (fork)" +optional = false +python-versions = ">=3.10" +files = [ + {file = "pillow-12.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:6c0016e7b354317c4e9e525b937ac8596c38d2d232b419529b9cd7a1cd46e39a"}, + {file = "pillow-12.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bcc33feacfaefce60c12fd500a277533bdc02b10a19f7f6d348763d8140bbba7"}, + {file = "pillow-12.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5594fc43d548a7ed94949d139aa1341b270f1863f11cfd37f5a6c8b778a6b67f"}, + {file = "pillow-12.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f0606c8bf2cdefea14a43530f7657cbbb7ecf1c4222512492ef4a4434a9501ec"}, + {file = "pillow-12.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:85f998ea1848bc6757289e739cfbdda3a04adfd58b02fc018ce54d754a5ce468"}, + {file = "pillow-12.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:25b9b82bb22e6e2b3cd07b39c68b7b862001226cb3dff7130d1cb914121b39ed"}, + {file = "pillow-12.3.0-cp310-cp310-win32.whl", hash = "sha256:37dc8f7bbb66efe481bb60defacef820c950c24713fb44962ed6aa2a50966de1"}, + {file = "pillow-12.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:300557495eb45ebb8aec96c2da9c4be642fbf7cd937278b4013ba894ea8eb0eb"}, + {file = "pillow-12.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:514435a37670e3e5e08f3945b68718b6ed329bb84367777e16f9f4dfe1e61a0f"}, + {file = "pillow-12.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:00808c5e14ef63ac5161091d242999076604ff74b883423a11e5d7bbb38bf756"}, + {file = "pillow-12.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:37d6d0a00072fd2948eb22bce7e1475f34569d90c87c59f7a2ec59541b77f7a6"}, + {file = "pillow-12.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bcb46e2f9feff8d06323983bd83ed00c201fdcab3d74973e7072a889b3979fcd"}, + {file = "pillow-12.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23d27a3e0307ec2244cc51e7287b919aa68d097504ebe19df4e76a98a3eea5bd"}, + {file = "pillow-12.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4f883547d4b7f0495ebe7056b0cc2aea76094e7a4abc8e933540f3271df27d9c"}, + {file = "pillow-12.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:236ff70b9312fb68943c703aa842ca6a758abfa45ac187a5e7c1452e96ef72b5"}, + {file = "pillow-12.3.0-cp311-cp311-win32.whl", hash = "sha256:10e41f0fbf1eec8cfd234b8fe17a4caac7c9d0db4c204d3c173a8f9f6ef3232b"}, + {file = "pillow-12.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8e95e1385e4998ae9694eeaa4730ba5457ff61185b3a55e2e7bea0880aef452a"}, + {file = "pillow-12.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:ebaea975e03d3141d9d3a507df75c9b3ec90fa9d2ffd07567b3a978d9d790b26"}, + {file = "pillow-12.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ba09209fbe443b4acccebe845d8a138b89a8f4fbaeedd44953490b5315d5e965"}, + {file = "pillow-12.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffd0c5368496f41b0944be820fcb7a838aa6e623d250b01acf2643939c3f99d7"}, + {file = "pillow-12.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9c7f76c0673154f044e9d78c8655fb4213f6ca31a836df48b40fe5d187717b9"}, + {file = "pillow-12.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:78cb2c6865a35ab8ff8b75fd122f6033b92a62c82801110e48ddd6c936a45d91"}, + {file = "pillow-12.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e491916b378fba47242221bb9ead245211b70d504f495d105d17b14a24b4907c"}, + {file = "pillow-12.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0dd2064cbc55aaec028ef5fbb60fa47bb6c3e7918e07ff17935284b227a9d2df"}, + {file = "pillow-12.3.0-cp312-cp312-win32.whl", hash = "sha256:dbce0b29841537a2fa4a214c2bbf14de3587c9680caa9b4e217568472490b28f"}, + {file = "pillow-12.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a2b55dd6b2a4c4b7d87ffa56bdb33fdc5fdb9a462173861a7bc097f17d91cb09"}, + {file = "pillow-12.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:331b624368d4f1d069149002f25f44bc61c8919ce8ddb3c45bdad8f6e2d89510"}, + {file = "pillow-12.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:21900ce7ba264168cd50defae43cd75d25c833ad4ad6e73ffc5596d12e25ac89"}, + {file = "pillow-12.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:4e8c2a84d977f50b9daed6eeaf3baef67d00d5d74d932288f02cb94518ee3ace"}, + {file = "pillow-12.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:ae26d61dfa7a47befdc7572b521024e8745f3d809bd95ca9505a7bba9ef849ec"}, + {file = "pillow-12.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7a743ff716f746fc19a9557f60dab1600d4613255f8a7aeb3cdde4db7eb15a66"}, + {file = "pillow-12.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d69141514cc30b774ceea5e3ed3a6635c8d8a96edf664689b890f4089111fb35"}, + {file = "pillow-12.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f7401aebd7f581d7f83a439d87d474999317ee099218e5ad25d125290990ba65"}, + {file = "pillow-12.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0847a763afefb695bc912d7c131e7e0632d4edc1d8698f58ddabec8e46b8b6d3"}, + {file = "pillow-12.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:571b9fcb07b97ef3a492028fb3d2dc0993ca23a06138b0315286566d29ef718a"}, + {file = "pillow-12.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:756c768d0c9c2955feb7a56c37ea24aea2e369f8d36a88da270b6a9f19e62b5e"}, + {file = "pillow-12.3.0-cp313-cp313-win32.whl", hash = "sha256:a876864214e136f0eb367788dbd7df045f4806801518e2cfe9e13229cfe06d8f"}, + {file = "pillow-12.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:1cca606cd25738df4ed873d5ad46bbdb3d83b5cbca291f6b4ff13a4df6b0bbe8"}, + {file = "pillow-12.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:b629de27fda84b42cde7edef0d85f13b958b47f6e9bbcbba9b673c562a89bd8b"}, + {file = "pillow-12.3.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:9cf95fe4d0f84c82d282745d9bb08ad9f926efa00be4697e767b814ce40d4330"}, + {file = "pillow-12.3.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:8728f216dcdb6e6d555cf971cb34076139ad74b31fc2c14da4fafc741c5f6217"}, + {file = "pillow-12.3.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:a45650e8ce7fafffd731db8550230db6b0d306d181a90b67d3e6bca2f1990930"}, + {file = "pillow-12.3.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ba54cfebe86920a559a7c4d6b9050791c20513650a1952ebe3368c7dc70306f8"}, + {file = "pillow-12.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e158cb00350dc278f3b91551101aa7d12415a66ebf2c91d8d5ac14e56ddd3ad0"}, + {file = "pillow-12.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9aeb04d6aef139de265b29683e119b638208f88cf73cdd1658aa07221165321"}, + {file = "pillow-12.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:251bf95b67017e27b13d82f5b326234ca62d70f9cf4c2b9032de2358a3b12c7b"}, + {file = "pillow-12.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fe3cca2e4e8a592be0f269a1ca4835c25199d9f3ce815c8491048f785b0a0198"}, + {file = "pillow-12.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:23aceaa007d6172b02c277f0cd359c79492bbb14f7072b4ede9fbcaf20648130"}, + {file = "pillow-12.3.0-cp314-cp314-win32.whl", hash = "sha256:af8d94b0db561cf68b88a267c5c44b49e134f525d0dc2cb7ed413a66bc23559a"}, + {file = "pillow-12.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:fdafc9cce40277e0f7a0feabce0ee50dd2fa1800f3b38015e51296b5e814048d"}, + {file = "pillow-12.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:e91206ee562682b51b98ef4b26a6ef48fd84e15fd4c4bc5ec768eb641d206838"}, + {file = "pillow-12.3.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:164b31cd1a0490ab6efae01aa5df49da7061be0af1b30e035b6e9a1bfe34ee6e"}, + {file = "pillow-12.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5afb51d599ea772b8365ae807ae557f18bccfe46ab261fd1c2a9ed700fc6eb17"}, + {file = "pillow-12.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3edce1d53195db527e0191f84b71d02022de0540bf43a16ed734ed7537b07385"}, + {file = "pillow-12.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bf16ba1b4d0b6b7c8e534936632270cf70eb00dbe09005bc345b2677b726855c"}, + {file = "pillow-12.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:24870b09b224f7ae3c39ed07d10e819d06f8720bc551847b1d623832b5b0e28d"}, + {file = "pillow-12.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:30f2aa603c41533cc25c05acd0da21636e84a315768feb631c937177db558931"}, + {file = "pillow-12.3.0-cp314-cp314t-win32.whl", hash = "sha256:4b0a7fe987b14c31ebda6083f74f22b561fd3739bc0ac51e019622e3d72668c7"}, + {file = "pillow-12.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:962864dc93511324d51ddbb5b9f8731bf71675b93ca612a07441896f4688fb8c"}, + {file = "pillow-12.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0740a512dc522224c77d9aa5a8d70d8b7d73fb91f2c21125d8d025d3b8990e45"}, + {file = "pillow-12.3.0-cp315-cp315-ios_13_0_arm64_iphoneos.whl", hash = "sha256:0feb2e9d6ad6c9e3c06effe9d00f3f1e618a6643273576b016f591e9315a7139"}, + {file = "pillow-12.3.0-cp315-cp315-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:9e881fca225083806662a5c43d627d215f258ff43c890f831966c7d7ba9c7402"}, + {file = "pillow-12.3.0-cp315-cp315-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:4998562bf62a445225f22e07c896bb04b35b1b1f2eb6d760584c9c51d7a5f78c"}, + {file = "pillow-12.3.0-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:dc624f6bc473dacdf7ef7eb8678d0d08edf15cd94fad6ae5c7d6cc67a4e4902f"}, + {file = "pillow-12.3.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:71d6097b330eea8fd15097780c8e89cb1a8ce7838669f48c5bacd6f663dd4701"}, + {file = "pillow-12.3.0-cp315-cp315-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:28ce87c5ab450a9dd970b52e5aca5fe63ed432d18a2eaddd1979a00a1ba24ace"}, + {file = "pillow-12.3.0-cp315-cp315-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6b02afb9b97f65fbca5f31db6a2a3ba21aa93030225f150fa3f249717e938fb4"}, + {file = "pillow-12.3.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:1182d52bc2d5e5d7d0949503aa7e36d12f42205dc287e4883f407b1988820d39"}, + {file = "pillow-12.3.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:e795b7eb908249c4e43c7c99fac7c2c75dab0c43566e37db472a355f63693d71"}, + {file = "pillow-12.3.0-cp315-cp315-win32.whl", hash = "sha256:57b3d78c95ba9059768b10e28b813002261d3f3dfc55cc48b0c988f625175827"}, + {file = "pillow-12.3.0-cp315-cp315-win_amd64.whl", hash = "sha256:fa4ecea169a355be7a3ade2c783e2ed12f0e40d2c5621cda8b3297faf7fbb9f5"}, + {file = "pillow-12.3.0-cp315-cp315-win_arm64.whl", hash = "sha256:877c3f311ff35410f690861c4409e7ccbf0cd2f878e50628a28e5a0bb689e658"}, + {file = "pillow-12.3.0-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:e9871b1ffbfa9656b60aeee92ed5136a5742696006fa322b29ea3d8da0ecc9cf"}, + {file = "pillow-12.3.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:53aa02d20d10c3d814d536aa4e5ac9b84ca0ff5a88377963b085ad6822f93e64"}, + {file = "pillow-12.3.0-cp315-cp315t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:446c34dcc4324b084a53b705127dc15717b22c5e140ae0a3c38349d4efec071e"}, + {file = "pillow-12.3.0-cp315-cp315t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf1845d02ad822a369a49f2bb9345b1614744267682e7a03527dc3bf6eea1777"}, + {file = "pillow-12.3.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:186941b6aef820ad110fb01fb06eb925374dc3a21b17e37ec9a53b250c6fe2d1"}, + {file = "pillow-12.3.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:f13c32a3abd6079a66d9526e18dad9b6d280384d49d7c54040cd57b6424041d9"}, + {file = "pillow-12.3.0-cp315-cp315t-win32.whl", hash = "sha256:1657923d2d45afb66526e5b933e5b3052e6bdea196c90d3abb2424e18c77dae8"}, + {file = "pillow-12.3.0-cp315-cp315t-win_amd64.whl", hash = "sha256:8cd2f7bdda092d99c9fc2fb7391354f306d01443d22785d0cbfafa2e2c8bb418"}, + {file = "pillow-12.3.0-cp315-cp315t-win_arm64.whl", hash = "sha256:06ff022112bc9cbf83b60f8e028d94ad87b60621706487e65f673de61610ab59"}, + {file = "pillow-12.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b3c777e849237620b022f7f297dd67705f9f5cf1685f09f02e46f93e92725468"}, + {file = "pillow-12.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:b343699e8308bdc51978310e1c959c584e7869cc8c40780058c87da7781a1e94"}, + {file = "pillow-12.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbd139c8447d25dd750ab79ee274cc5e1fe80fc56340ab10b18a195e1b6eca3e"}, + {file = "pillow-12.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e7e480451b9fa137494bccd3a7d69adbe8ac65a87d97be61e11f1b1050a5bac3"}, + {file = "pillow-12.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:04f01d28a6aaff387bf842a13be313df23ba0597a44f1a976c9feb3c6ff4711a"}, + {file = "pillow-12.3.0.tar.gz", hash = "sha256:3b8182a766685eaa002637e28b4ec8d6b18819a0c71f579bf0dbaa5830297cce"}, ] [package.extras] -docs = ["furo", "olefile", "sphinx (>=8.1)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] +docs = ["furo", "olefile", "sphinx (>=8.2)", "sphinx-autobuild", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] fpx = ["olefile"] mic = ["olefile"] -tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] -typing = ["typing-extensions"] +test-arrow = ["arro3-compute", "arro3-core", "nanoarrow", "pyarrow"] +tests = ["coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "setuptools", "trove-classifiers (>=2024.10.12)"] xmp = ["defusedxml"] [[package]] name = "platformdirs" -version = "4.1.0" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +version = "4.10.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, - {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, + {file = "platformdirs-4.10.0-py3-none-any.whl", hash = "sha256:fb516cdb12eb0d857d0cd85a7c57cea4d060bee4578d6cf5a14dfdf8cbf8784a"}, + {file = "platformdirs-4.10.0.tar.gz", hash = "sha256:31e761a6a0ca04faf7353ea759bdba55652be214725111e5aac52dfa29d4bef7"}, ] -[package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] - [[package]] name = "pluggy" -version = "1.4.0" +version = "1.6.0" description = "plugin and hook calling mechanisms for python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, - {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, + {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, + {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, ] [package.extras] dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] +testing = ["coverage", "pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "3.6.0" +version = "4.6.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" files = [ - {file = "pre_commit-3.6.0-py2.py3-none-any.whl", hash = "sha256:c255039ef399049a5544b6ce13d135caba8f2c28c3b4033277a788f434308376"}, - {file = "pre_commit-3.6.0.tar.gz", hash = "sha256:d30bad9abf165f7785c15a21a1f46da7d0677cb00ee7ff4c579fd38922efe15d"}, + {file = "pre_commit-4.6.0-py2.py3-none-any.whl", hash = "sha256:e2cf246f7299edcabcf15f9b0571fdce06058527f0a06535068a86d38089f29b"}, + {file = "pre_commit-4.6.0.tar.gz", hash = "sha256:718d2208cef53fdc38206e40524a6d4d9576d103eb16f0fec11c875e7716e9d9"}, ] [package.dependencies] @@ -2981,382 +3648,539 @@ virtualenv = ">=20.10.0" [[package]] name = "propcache" -version = "0.3.0" +version = "0.5.2" description = "Accelerated property cache" optional = false -python-versions = ">=3.9" -files = [ - {file = "propcache-0.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:efa44f64c37cc30c9f05932c740a8b40ce359f51882c70883cc95feac842da4d"}, - {file = "propcache-0.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2383a17385d9800b6eb5855c2f05ee550f803878f344f58b6e194de08b96352c"}, - {file = "propcache-0.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d3e7420211f5a65a54675fd860ea04173cde60a7cc20ccfbafcccd155225f8bc"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3302c5287e504d23bb0e64d2a921d1eb4a03fb93a0a0aa3b53de059f5a5d737d"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7e2e068a83552ddf7a39a99488bcba05ac13454fb205c847674da0352602082f"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d913d36bdaf368637b4f88d554fb9cb9d53d6920b9c5563846555938d5450bf"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ee1983728964d6070ab443399c476de93d5d741f71e8f6e7880a065f878e0b9"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:36ca5e9a21822cc1746023e88f5c0af6fce3af3b85d4520efb1ce4221bed75cc"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9ecde3671e62eeb99e977f5221abcf40c208f69b5eb986b061ccec317c82ebd0"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d383bf5e045d7f9d239b38e6acadd7b7fdf6c0087259a84ae3475d18e9a2ae8b"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:8cb625bcb5add899cb8ba7bf716ec1d3e8f7cdea9b0713fa99eadf73b6d4986f"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5fa159dcee5dba00c1def3231c249cf261185189205073bde13797e57dd7540a"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:a7080b0159ce05f179cfac592cda1a82898ca9cd097dacf8ea20ae33474fbb25"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ed7161bccab7696a473fe7ddb619c1d75963732b37da4618ba12e60899fefe4f"}, - {file = "propcache-0.3.0-cp310-cp310-win32.whl", hash = "sha256:bf0d9a171908f32d54f651648c7290397b8792f4303821c42a74e7805bfb813c"}, - {file = "propcache-0.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:42924dc0c9d73e49908e35bbdec87adedd651ea24c53c29cac103ede0ea1d340"}, - {file = "propcache-0.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9ddd49258610499aab83b4f5b61b32e11fce873586282a0e972e5ab3bcadee51"}, - {file = "propcache-0.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2578541776769b500bada3f8a4eeaf944530516b6e90c089aa368266ed70c49e"}, - {file = "propcache-0.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8074c5dd61c8a3e915fa8fc04754fa55cfa5978200d2daa1e2d4294c1f136aa"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b58229a844931bca61b3a20efd2be2a2acb4ad1622fc026504309a6883686fbf"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e45377d5d6fefe1677da2a2c07b024a6dac782088e37c0b1efea4cfe2b1be19b"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ec5060592d83454e8063e487696ac3783cc48c9a329498bafae0d972bc7816c9"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15010f29fbed80e711db272909a074dc79858c6d28e2915704cfc487a8ac89c6"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a254537b9b696ede293bfdbc0a65200e8e4507bc9f37831e2a0318a9b333c85c"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2b975528998de037dfbc10144b8aed9b8dd5a99ec547f14d1cb7c5665a43f075"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:19d36bb351ad5554ff20f2ae75f88ce205b0748c38b146c75628577020351e3c"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6032231d4a5abd67c7f71168fd64a47b6b451fbcb91c8397c2f7610e67683810"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6985a593417cdbc94c7f9c3403747335e450c1599da1647a5af76539672464d3"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:6a1948df1bb1d56b5e7b0553c0fa04fd0e320997ae99689488201f19fa90d2e7"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8319293e85feadbbfe2150a5659dbc2ebc4afdeaf7d98936fb9a2f2ba0d4c35c"}, - {file = "propcache-0.3.0-cp311-cp311-win32.whl", hash = "sha256:63f26258a163c34542c24808f03d734b338da66ba91f410a703e505c8485791d"}, - {file = "propcache-0.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:cacea77ef7a2195f04f9279297684955e3d1ae4241092ff0cfcef532bb7a1c32"}, - {file = "propcache-0.3.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e53d19c2bf7d0d1e6998a7e693c7e87300dd971808e6618964621ccd0e01fe4e"}, - {file = "propcache-0.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a61a68d630e812b67b5bf097ab84e2cd79b48c792857dc10ba8a223f5b06a2af"}, - {file = "propcache-0.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fb91d20fa2d3b13deea98a690534697742029f4fb83673a3501ae6e3746508b5"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67054e47c01b7b349b94ed0840ccae075449503cf1fdd0a1fdd98ab5ddc2667b"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:997e7b8f173a391987df40f3b52c423e5850be6f6df0dcfb5376365440b56667"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d663fd71491dde7dfdfc899d13a067a94198e90695b4321084c6e450743b8c7"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8884ba1a0fe7210b775106b25850f5e5a9dc3c840d1ae9924ee6ea2eb3acbfe7"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa806bbc13eac1ab6291ed21ecd2dd426063ca5417dd507e6be58de20e58dfcf"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6f4d7a7c0aff92e8354cceca6fe223973ddf08401047920df0fcb24be2bd5138"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:9be90eebc9842a93ef8335291f57b3b7488ac24f70df96a6034a13cb58e6ff86"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:bf15fc0b45914d9d1b706f7c9c4f66f2b7b053e9517e40123e137e8ca8958b3d"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5a16167118677d94bb48bfcd91e420088854eb0737b76ec374b91498fb77a70e"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:41de3da5458edd5678b0f6ff66691507f9885f5fe6a0fb99a5d10d10c0fd2d64"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:728af36011bb5d344c4fe4af79cfe186729efb649d2f8b395d1572fb088a996c"}, - {file = "propcache-0.3.0-cp312-cp312-win32.whl", hash = "sha256:6b5b7fd6ee7b54e01759f2044f936dcf7dea6e7585f35490f7ca0420fe723c0d"}, - {file = "propcache-0.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:2d15bc27163cd4df433e75f546b9ac31c1ba7b0b128bfb1b90df19082466ff57"}, - {file = "propcache-0.3.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a2b9bf8c79b660d0ca1ad95e587818c30ccdb11f787657458d6f26a1ea18c568"}, - {file = "propcache-0.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b0c1a133d42c6fc1f5fbcf5c91331657a1ff822e87989bf4a6e2e39b818d0ee9"}, - {file = "propcache-0.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bb2f144c6d98bb5cbc94adeb0447cfd4c0f991341baa68eee3f3b0c9c0e83767"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1323cd04d6e92150bcc79d0174ce347ed4b349d748b9358fd2e497b121e03c8"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b812b3cb6caacd072276ac0492d249f210006c57726b6484a1e1805b3cfeea0"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:742840d1d0438eb7ea4280f3347598f507a199a35a08294afdcc560c3739989d"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c6e7e4f9167fddc438cd653d826f2222222564daed4116a02a184b464d3ef05"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a94ffc66738da99232ddffcf7910e0f69e2bbe3a0802e54426dbf0714e1c2ffe"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c6ec957025bf32b15cbc6b67afe233c65b30005e4c55fe5768e4bb518d712f1"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:549722908de62aa0b47a78b90531c022fa6e139f9166be634f667ff45632cc92"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5d62c4f6706bff5d8a52fd51fec6069bef69e7202ed481486c0bc3874912c787"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:24c04f8fbf60094c531667b8207acbae54146661657a1b1be6d3ca7773b7a545"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7c5f5290799a3f6539cc5e6f474c3e5c5fbeba74a5e1e5be75587746a940d51e"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4fa0e7c9c3cf7c276d4f6ab9af8adddc127d04e0fcabede315904d2ff76db626"}, - {file = "propcache-0.3.0-cp313-cp313-win32.whl", hash = "sha256:ee0bd3a7b2e184e88d25c9baa6a9dc609ba25b76daae942edfb14499ac7ec374"}, - {file = "propcache-0.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:1c8f7d896a16da9455f882870a507567d4f58c53504dc2d4b1e1d386dfe4588a"}, - {file = "propcache-0.3.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e560fd75aaf3e5693b91bcaddd8b314f4d57e99aef8a6c6dc692f935cc1e6bbf"}, - {file = "propcache-0.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:65a37714b8ad9aba5780325228598a5b16c47ba0f8aeb3dc0514701e4413d7c0"}, - {file = "propcache-0.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:07700939b2cbd67bfb3b76a12e1412405d71019df00ca5697ce75e5ef789d829"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c0fdbdf6983526e269e5a8d53b7ae3622dd6998468821d660d0daf72779aefa"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:794c3dd744fad478b6232289c866c25406ecdfc47e294618bdf1697e69bd64a6"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4544699674faf66fb6b4473a1518ae4999c1b614f0b8297b1cef96bac25381db"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fddb8870bdb83456a489ab67c6b3040a8d5a55069aa6f72f9d872235fbc52f54"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f857034dc68d5ceb30fb60afb6ff2103087aea10a01b613985610e007053a121"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:02df07041e0820cacc8f739510078f2aadcfd3fc57eaeeb16d5ded85c872c89e"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f47d52fd9b2ac418c4890aad2f6d21a6b96183c98021f0a48497a904199f006e"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9ff4e9ecb6e4b363430edf2c6e50173a63e0820e549918adef70515f87ced19a"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ecc2920630283e0783c22e2ac94427f8cca29a04cfdf331467d4f661f4072dac"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:c441c841e82c5ba7a85ad25986014be8d7849c3cfbdb6004541873505929a74e"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6c929916cbdb540d3407c66f19f73387f43e7c12fa318a66f64ac99da601bcdf"}, - {file = "propcache-0.3.0-cp313-cp313t-win32.whl", hash = "sha256:0c3e893c4464ebd751b44ae76c12c5f5c1e4f6cbd6fbf67e3783cd93ad221863"}, - {file = "propcache-0.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:75e872573220d1ee2305b35c9813626e620768248425f58798413e9c39741f46"}, - {file = "propcache-0.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:03c091bb752349402f23ee43bb2bff6bd80ccab7c9df6b88ad4322258d6960fc"}, - {file = "propcache-0.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:46ed02532cb66612d42ae5c3929b5e98ae330ea0f3900bc66ec5f4862069519b"}, - {file = "propcache-0.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11ae6a8a01b8a4dc79093b5d3ca2c8a4436f5ee251a9840d7790dccbd96cb649"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df03cd88f95b1b99052b52b1bb92173229d7a674df0ab06d2b25765ee8404bce"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03acd9ff19021bd0567582ac88f821b66883e158274183b9e5586f678984f8fe"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd54895e4ae7d32f1e3dd91261df46ee7483a735017dc6f987904f194aa5fd14"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26a67e5c04e3119594d8cfae517f4b9330c395df07ea65eab16f3d559b7068fe"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee25f1ac091def37c4b59d192bbe3a206298feeb89132a470325bf76ad122a1e"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:58e6d2a5a7cb3e5f166fd58e71e9a4ff504be9dc61b88167e75f835da5764d07"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:be90c94570840939fecedf99fa72839aed70b0ced449b415c85e01ae67422c90"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:49ea05212a529c2caffe411e25a59308b07d6e10bf2505d77da72891f9a05641"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:119e244ab40f70a98c91906d4c1f4c5f2e68bd0b14e7ab0a06922038fae8a20f"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:507c5357a8d8b4593b97fb669c50598f4e6cccbbf77e22fa9598aba78292b4d7"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8526b0941ec5a40220fc4dfde76aed58808e2b309c03e9fa8e2260083ef7157f"}, - {file = "propcache-0.3.0-cp39-cp39-win32.whl", hash = "sha256:7cedd25e5f678f7738da38037435b340694ab34d424938041aa630d8bac42663"}, - {file = "propcache-0.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:bf4298f366ca7e1ad1d21bbb58300a6985015909964077afd37559084590c929"}, - {file = "propcache-0.3.0-py3-none-any.whl", hash = "sha256:67dda3c7325691c2081510e92c561f465ba61b975f481735aefdfc845d2cd043"}, - {file = "propcache-0.3.0.tar.gz", hash = "sha256:a8fd93de4e1d278046345f49e2238cdb298589325849b2645d4a94c53faeffc5"}, +python-versions = ">=3.10" +files = [ + {file = "propcache-0.5.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5a81be28596d6559f6131ef33e10200de6e17643b3c74ce03f9eb103be6ae8b"}, + {file = "propcache-0.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29cbaac5ea0212663e6845e04b5e188d5a6ae6dd919810ac835bf1d3b42c3f4c"}, + {file = "propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6bf3be92233808fcd338eba0fb4d0b59ec5772af4f4ecfcec450d1bfc0f8b5eb"}, + {file = "propcache-0.5.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2f8ea531c794b9d6274acd4e8d2c2ebcac590a4361d27482edd3010b79f1325e"}, + {file = "propcache-0.5.2-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:decfca4c79dd53ebab484b00cc4b6717d8c369f86e74aa4ca395a64ac651495e"}, + {file = "propcache-0.5.2-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4621064bbf28fa77ff64dd5d94367c04684c67d3a5bf1dff25f0cd0d98a38f3b"}, + {file = "propcache-0.5.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b96db7141a592cbc968daf1feea83a118e6ab378af4abbc72b248c895414c22d"}, + {file = "propcache-0.5.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1ca071adabaab6e9219924bbe00af821f1ee7de113a9eca1cdc292de3d120f4d"}, + {file = "propcache-0.5.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e4294d04a94dcab1b3bccd8b66d962dcad411a1d19414b2a41d1445f1de32ad0"}, + {file = "propcache-0.5.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a0e399a2eccb91ed18721f86aa85757727400b6865c89e88934781deb9c8498b"}, + {file = "propcache-0.5.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:823581fd5cb08b12a48bfa11fe962a7916766b6170c17b028fbdf762b85eb9bf"}, + {file = "propcache-0.5.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:949c91d1a990cf3b2e8188dfcfb25005e0b834a06c63fa4ef9f360878ce21ecf"}, + {file = "propcache-0.5.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:cc1177027eda740fdb152706bd215a3f124e3eea15afc39f2cb9fe351b50619e"}, + {file = "propcache-0.5.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b05d643f944a8c3c4bd86d65ffd87bf3264b617f87791940302bc474d2ff5274"}, + {file = "propcache-0.5.2-cp310-cp310-win32.whl", hash = "sha256:8114f28879e0904748e831c3a7774261bd9e75f49be089f389a76f959dcd13fe"}, + {file = "propcache-0.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:5fcb98e7598b1ee0addab320d90f65b530297a867dbfe9de52ea838077e16e3d"}, + {file = "propcache-0.5.2-cp310-cp310-win_arm64.whl", hash = "sha256:04dc2390d9edbbaef7461f33322555976ffddf0b650a038649d026358714e6c5"}, + {file = "propcache-0.5.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:74b70780220e2dd89175ca24b81b68b67c83db499ae611e7f2313cb329801c78"}, + {file = "propcache-0.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a4840ab0ae0216d952f4b53dc6d0b992bfc2bedbfe360bdd9b548bc184c08959"}, + {file = "propcache-0.5.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c6844ba6364fb12f403928a82cfd295ab103a2b315c77c747b2dbe4a41894ea7"}, + {file = "propcache-0.5.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2293949b855ce597f2826452d17c2d545fb5622379c4ea6fdf525e9b8e8a2511"}, + {file = "propcache-0.5.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0fd59b5af35f74da48d905dcbad55449ba13be91823cb05a9bd590bbf5b61660"}, + {file = "propcache-0.5.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29f9309a2e42b0d273be006fdb4be2d6c39a47f6f57d8fb1cf9f81481df81b66"}, + {file = "propcache-0.5.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5aaa2b923c1944ac8febd6609cb373540a5563e7cbcb0fd770f75dace2eb817b"}, + {file = "propcache-0.5.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:66ea454f095ddf5b6b14f56c064c0941c4788be11e18d2464cf643bf7203ff67"}, + {file = "propcache-0.5.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:95f1e3f4760d404b13c9976c0229b2b49a3c8e2c62a9ce92efdd2b11ada75e3f"}, + {file = "propcache-0.5.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:85341b12b9d55bad0bded24cac341bb34289469e03a11f3f583ea1cc1db0326c"}, + {file = "propcache-0.5.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:26a4dca084132874e639895c3135dfad5eb20bae209f62d1aeb31b03e601c3c0"}, + {file = "propcache-0.5.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3b199b9b2b3d6a7edf3183ba8a9a137a22b97f7df525feb5ae1eccf026d2a9c6"}, + {file = "propcache-0.5.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e59bc9e66329185b93dab73f210f1a37f81cb40f321501db8017c9aea15dba27"}, + {file = "propcache-0.5.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:552ffadf6ad409844bc5919c42a0a83d88314cedddaea0e41e80a8b8fffe881f"}, + {file = "propcache-0.5.2-cp311-cp311-win32.whl", hash = "sha256:cd416c1de191973c52ff1a12a57446bfc7642797b282d7caf2162d7d1b8aa9a0"}, + {file = "propcache-0.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:44e488ef40dbb452700b2b1f8188934121f6648f52c295055662d2191959ff82"}, + {file = "propcache-0.5.2-cp311-cp311-win_arm64.whl", hash = "sha256:54adaa85a22078d1e306304a40984dc5be99d599bf3dc0a24dc98f7daeab89ab"}, + {file = "propcache-0.5.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:806719138ecd720339a12410fb9614ac9b2b2d3a5fdf8235d56981c36f4039ba"}, + {file = "propcache-0.5.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:db2b80ea58eab4f86b2beec3cc8b39e8ff9276ac20e96b7cce43c8ae84cd6b5a"}, + {file = "propcache-0.5.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e5cbfac9f61484f7e9f3597775500cd3ebe8274e9b050c38f9525c77c97520bf"}, + {file = "propcache-0.5.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5dbc581d2814337da56222fab8dc5f161cd798a434e49bac27930aaef798e144"}, + {file = "propcache-0.5.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:857187f381f88c8e2fa2fe56ab94879d011b883d5a2ee5a1b60a8cd2a06846d9"}, + {file = "propcache-0.5.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:178b4a2cdaac1818e2bf1c5a99b94383fa73ea5382e032a48dec07dc5668dc42"}, + {file = "propcache-0.5.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f328175a2cde1f0ff2c4ed8ce968b9dcfb55f3a7153f39e2957ed994da13476"}, + {file = "propcache-0.5.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5671d09a36b06d0fd4a3da0fccbcae360e9b1570924171a15e9e0997f0249fba"}, + {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:80168e2ebe4d3ec6599d10ad8f520304ae1cad9b6c5a95372aef1b66b7bfb53a"}, + {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:45f11346f884bc47444f6e6647131055844134c3175b629f84952e2b5cd62b64"}, + {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8e778ebd44ef4f66ed60a0416b06b489687db264a9c0b3620362f26489492913"}, + {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:c0cb9ed24c8964e172768d455a38254c2dd8a552905729ce006cad3d3dda59b1"}, + {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1d1ad32d9d4355e2be65574fd0bfd3677e7066b009cd5b9b2dee8aa6a6393b33"}, + {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c80f4ba3e8f00189165999a742ee526ebeccedf6c3f7beb0c7df821e9772435a"}, + {file = "propcache-0.5.2-cp312-cp312-win32.whl", hash = "sha256:8c7972d8f193740d9175f0998ab38717e6cd322d5935c5b0fef8c0d323fd9031"}, + {file = "propcache-0.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:d9ee8826a7d47863a08ac44e1a5f611a462eefc3a194b492da242128bec75b42"}, + {file = "propcache-0.5.2-cp312-cp312-win_arm64.whl", hash = "sha256:2800a4a8ead6b28cccd1ec54b59346f0def7922ee1c7598e8499c733cfbb7c84"}, + {file = "propcache-0.5.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:099aaf4b4d1a02265b92a977edf00b5c4f63b3b17ac6de39b0d637c9cac0188a"}, + {file = "propcache-0.5.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:68ce1c44c7a813a7f71ea04315a8c7b330b63db99d059a797a4651bb6f69f117"}, + {file = "propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fc299c129490f55f254cd90be0deca4764e36e9a7c08b4aa588479a3bbed3098"}, + {file = "propcache-0.5.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a6ae2198be502c10f09b2516e7b5d019816924bc3183a43ce792a7bd6625e6f4"}, + {file = "propcache-0.5.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6041d31504dc1779d700e1edcfb08eea334b357620b06681a4eabb57a74e574e"}, + {file = "propcache-0.5.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7eabc04151c78a9f4d5bbb5f1faf571e4defeb4b585e0fe95b60ff2dbe4d3d7"}, + {file = "propcache-0.5.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4db0ba63d693afd40d249bd93f842b5f144f8fcbb83de05660373bcf30517b1d"}, + {file = "propcache-0.5.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1dbcf7675229b35d31abb6547d8ebc8c27a830ac3f9a794edff6254873ec7c0a"}, + {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d310c013aad2c72f1c3f2f8dd3279d460a858c551f97aeb8c63e4693cca7b4d2"}, + {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:06187263ddad280d05b4d8a8b3bb7d164cbebd469236544a42e6d9b28ac6a4fa"}, + {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3115559b8effafd63b142ea5ed53d63a16ea6469cbc63dce4ee194b42db5d853"}, + {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c60462af8e6dc30c35407c7237ea908d777b22862bbee27bc4699c0d8bcdc45a"}, + {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:40314bca9ac559716fe374094fc81c11dcc34b64fd6c585360f5775690505704"}, + {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cfa21e036ce1e1db2be04ba3b85d2df1bb1702fa01932d984c5464c665228ff4"}, + {file = "propcache-0.5.2-cp313-cp313-win32.whl", hash = "sha256:f156a3529f38063b6dbaf356e15602a7f95f8055b1295a438433a6386f10463d"}, + {file = "propcache-0.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:dfed59d0a5aeb01e242e66ff0300bc4a265a7c05f612d30016f0b60b1017d757"}, + {file = "propcache-0.5.2-cp313-cp313-win_arm64.whl", hash = "sha256:ba338430e87ceb9c8f0cf754de38a9860560261e56c00376debd628698a7364f"}, + {file = "propcache-0.5.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a592f5f3da71c8691c788c13cb6734b6d17663d2e1cb8caddf0673d01ef8847d"}, + {file = "propcache-0.5.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6a997d0489e9668a384fcfd5061b857aa5361de73191cac204d04b889cfbbafa"}, + {file = "propcache-0.5.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:10734b5484ea113152ee25a91dccedf81631791805d2c9ccb054958e51842c94"}, + {file = "propcache-0.5.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cafca7e56c12bb02ae16d283742bef25a61122e9dab2b5b3f2ccbe589ce32164"}, + {file = "propcache-0.5.2-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f064f8d2b59177878b7615df1735cd8fe3462ed6be8c7b217d17a276489c2b7f"}, + {file = "propcache-0.5.2-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f78abfa8dfc32376fd1aacf597b2f2fbbe0ea751419aee718af5d4f82537ef8c"}, + {file = "propcache-0.5.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7467da8a9822bf1a55336f877340c5bcbd3c482afc43a99771169f74a26dedc"}, + {file = "propcache-0.5.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a6ddc6ac9e25de626c1f129c1b467d7ecd33ce2237d3fd0c4e429feef0a7ee1f"}, + {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2f22cbbac9e26a8e864c0985ff1268d5d939d53d9d9411a9824279097e03a2cb"}, + {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:fc76378c62a0f04d0cd82fbb1a2cd2d7e28fcb40d5873f28a6c44e388aaa2751"}, + {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:acd2c8edba48e31e58a363b8cf4e5c7db3b04b3f9e371f601df30d9b0d244836"}, + {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:452b5065457eb9991ec5eb38ff41d6cd4c991c9ac7c531c4d5849ae473a9a13f"}, + {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:3430bb2bfe1331885c427745a751e774ee679fd4344f80b97bf879815fe8fa55"}, + {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cef6cea3922890dd6c9654971001fa797b526c16ab5e1e46c05fd6f877be7568"}, + {file = "propcache-0.5.2-cp313-cp313t-win32.whl", hash = "sha256:72d61e16dd78228b58c5d47be830ff3da7e5f139abdf0aef9d86cde1c5cf2191"}, + {file = "propcache-0.5.2-cp313-cp313t-win_amd64.whl", hash = "sha256:0958834041a0166d343b8d2cedcd8bcbaeb4fdbe0cf08320c5379f143c3be6e7"}, + {file = "propcache-0.5.2-cp313-cp313t-win_arm64.whl", hash = "sha256:6de8bd93ddde9b992cf2b2e0d796d501a19026b5b9fd87356d7d0779531a8d96"}, + {file = "propcache-0.5.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:46088abff4cba581dea21ae0467a480526cb25aa5f3c269e909f800328bc3999"}, + {file = "propcache-0.5.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fc88b26f08d634f7bc819a7852e5214f5802641ab8d9fd5326892292eee1993e"}, + {file = "propcache-0.5.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:97797ebb098e670a2f92dd66f32897e30d7615b14e7f59711de23e30a9072539"}, + {file = "propcache-0.5.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba57fffe4ac99c5d30076161b5866336d97600769bad35cc68f7774b15298a4e"}, + {file = "propcache-0.5.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:583c19759d9eec1e5b69e2fbef36a7d9c326041be9746cb822d335c8cedc2979"}, + {file = "propcache-0.5.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d0326e2e5e1f3163fa306c834e48e8d490e5fae607a097a40c0648109b47ba80"}, + {file = "propcache-0.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e00820e192c8dbebcafb383ebbf99030895f09905e7a0eb2e0340a0bcc2bc825"}, + {file = "propcache-0.5.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c66afea89b1e43725731d2004732a046fe6fe955d51f952c3e95a7314a284a39"}, + {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d4dc37dec6c6cdad0b57881a5658fd14fbf53e333b1a86cf86559f190e1d9ec4"}, + {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:5570dbcc97571c15f68068e529c92715a12f8d54030e272d264b377e22bd17a5"}, + {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f814362777a9f841adddb200ecdf8f5cb1e5a3c4b7a86378edbd6ccb26edd702"}, + {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:196913dea116aeb5a2ba95af4ddcb7ea85559ae07d8eee8751688310d09168c3"}, + {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:6e7b8719005dd1175be4ab1cd25e9b98659a5e0347331506ec6760d2773a7fb5"}, + {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:51f96d685ab16e88cab128cd37a52c5da540809c8b879fa047731bfcb4ad35a4"}, + {file = "propcache-0.5.2-cp314-cp314-win32.whl", hash = "sha256:cc6fc3cc62e8501d3ed62894425040d2728ecddb1ed072737a5c70bd537aa9f0"}, + {file = "propcache-0.5.2-cp314-cp314-win_amd64.whl", hash = "sha256:81e3a30b0bb60caa22033dd0f8a3618d1d67356212514f62c57db75cb0ef410c"}, + {file = "propcache-0.5.2-cp314-cp314-win_arm64.whl", hash = "sha256:0d2c9bf8528f135dbb805ce027567e09164f7efa51a2be07458a2c0420f292d0"}, + {file = "propcache-0.5.2-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:4bc8ff1feffc6a61c7002ffe84634c41b822e104990ae009f44a0834430070bb"}, + {file = "propcache-0.5.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:79aa3ff0a9b566633b642fa9caf7e21ed1c13d6feca718187873f199e1514078"}, + {file = "propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1b31822f4474c4036bae62de9402710051d431a606d6a0f907fec79935a071aa"}, + {file = "propcache-0.5.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13fef48778b5a2a756523fdb781326b028ca75e32858b04f2cdd19f394564917"}, + {file = "propcache-0.5.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8b73ab70f1a3351fbc71f663b3e645af6dd0329100c353081cf69c37433fc6fe"}, + {file = "propcache-0.5.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5538d2c13d93e4698af7e092b57bc7298fd35d1d58e656ae18f23ee0d0378e03"}, + {file = "propcache-0.5.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd645f03898405cabe694fb8bc35241e3a9c332ec85627584fe3de201452b335"}, + {file = "propcache-0.5.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a473b3440261e0c60706e732b2ed2f517857344fc21bf48fdfe211e2d98eb285"}, + {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7afa37062e6650640e932e4cc9297d81f9f42d9944029cc386b8247dea4da837"}, + {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:8a90efd5777e996e42d568db9ac740b944d691e565cbfd31b2f7832f9184b2b8"}, + {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:f19bb891234d72535764d703bfed1153cc34f4214d5bd7150aee1eec9e8f4366"}, + {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:32775082acd2d807ee3db715c7770d38767b817870acfa08c29e057f3c4d5b56"}, + {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9282fb1a3bccd038da9f768b927b24a0c753e466c086b7c4f3c6982851eefb2d"}, + {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cc49723e2f60d6b32a0f0b08a3fd6d13203c07f1cd9566cfce0f12a917c967a2"}, + {file = "propcache-0.5.2-cp314-cp314t-win32.whl", hash = "sha256:2d7aa89ebca5acc98cba9d1472d976e394782f587bad6661003602a619fd1821"}, + {file = "propcache-0.5.2-cp314-cp314t-win_amd64.whl", hash = "sha256:d447bb0b3054be5818458fbb171208b1d9ff11eba14e18ca18b90cbb45767370"}, + {file = "propcache-0.5.2-cp314-cp314t-win_arm64.whl", hash = "sha256:fe67a3d11cd9b4efabfa45c3d00ffba2b26811442a73a581a94b67c2b5faccf6"}, + {file = "propcache-0.5.2-py3-none-any.whl", hash = "sha256:be1ddfcbb376e3de5d2e2db1d58d6d67463e6b4f9f040c000de8e300295465fe"}, + {file = "propcache-0.5.2.tar.gz", hash = "sha256:01c4fc7480cd0598bb4b57022df55b9ca296da7fc5a8760bd8451a7e63a7d427"}, +] + +[[package]] +name = "proto-plus" +version = "1.28.1" +description = "Beautiful, Pythonic protocol buffers" +optional = false +python-versions = ">=3.10" +files = [ + {file = "proto_plus-1.28.1-py3-none-any.whl", hash = "sha256:6660f5f1970874bdcfc3088b435188a36a37bd3596668f7d726417c4ae8cfbed"}, + {file = "proto_plus-1.28.1.tar.gz", hash = "sha256:832e68e7fe064cf90ab153b6e5eb935b27891bb89aaeb68b115e9b702f6cb168"}, ] +[package.dependencies] +protobuf = ">=4.25.8,<8.0.0" + +[package.extras] +testing = ["google-api-core (>=1.31.5)"] + [[package]] name = "protobuf" -version = "4.25.2" +version = "7.35.1" description = "" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "protobuf-4.25.2-cp310-abi3-win32.whl", hash = "sha256:b50c949608682b12efb0b2717f53256f03636af5f60ac0c1d900df6213910fd6"}, - {file = "protobuf-4.25.2-cp310-abi3-win_amd64.whl", hash = "sha256:8f62574857ee1de9f770baf04dde4165e30b15ad97ba03ceac65f760ff018ac9"}, - {file = "protobuf-4.25.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:2db9f8fa64fbdcdc93767d3cf81e0f2aef176284071507e3ede160811502fd3d"}, - {file = "protobuf-4.25.2-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:10894a2885b7175d3984f2be8d9850712c57d5e7587a2410720af8be56cdaf62"}, - {file = "protobuf-4.25.2-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:fc381d1dd0516343f1440019cedf08a7405f791cd49eef4ae1ea06520bc1c020"}, - {file = "protobuf-4.25.2-cp38-cp38-win32.whl", hash = "sha256:33a1aeef4b1927431d1be780e87b641e322b88d654203a9e9d93f218ee359e61"}, - {file = "protobuf-4.25.2-cp38-cp38-win_amd64.whl", hash = "sha256:47f3de503fe7c1245f6f03bea7e8d3ec11c6c4a2ea9ef910e3221c8a15516d62"}, - {file = "protobuf-4.25.2-cp39-cp39-win32.whl", hash = "sha256:5e5c933b4c30a988b52e0b7c02641760a5ba046edc5e43d3b94a74c9fc57c1b3"}, - {file = "protobuf-4.25.2-cp39-cp39-win_amd64.whl", hash = "sha256:d66a769b8d687df9024f2985d5137a337f957a0916cf5464d1513eee96a63ff0"}, - {file = "protobuf-4.25.2-py3-none-any.whl", hash = "sha256:a8b7a98d4ce823303145bf3c1a8bdb0f2f4642a414b196f04ad9853ed0c8f830"}, - {file = "protobuf-4.25.2.tar.gz", hash = "sha256:fe599e175cb347efc8ee524bcd4b902d11f7262c0e569ececcb89995c15f0a5e"}, + {file = "protobuf-7.35.1-cp310-abi3-macosx_10_9_universal2.whl", hash = "sha256:24f857477359a85c0c235261b8ba905fd51b2562f4a64ca1df5473f29850cbf6"}, + {file = "protobuf-7.35.1-cp310-abi3-manylinux2014_aarch64.whl", hash = "sha256:11d6b0ec246892d85215b0a13ca6e0233cf5284b68f0ac02646427f4ff88a799"}, + {file = "protobuf-7.35.1-cp310-abi3-manylinux2014_s390x.whl", hash = "sha256:b73f9489a4b8b1c9cb1f8ed951c736392592edb24b9d6819f36d2e10b171d5b4"}, + {file = "protobuf-7.35.1-cp310-abi3-manylinux2014_x86_64.whl", hash = "sha256:74758715c53d7158fb76caf4f0cfdacc5329a4b1bb994f865d6cf302d413a1c4"}, + {file = "protobuf-7.35.1-cp310-abi3-win32.whl", hash = "sha256:353652e4efd0bca5b5fc2656abf8307ef351f0cf938c9eba09f0e09c20a25c30"}, + {file = "protobuf-7.35.1-cp310-abi3-win_amd64.whl", hash = "sha256:230a75ddfc2de4806e56696ce9640c1cdfdb6543b7cfce98d42a4c0a0e7bdb87"}, + {file = "protobuf-7.35.1-py3-none-any.whl", hash = "sha256:4bc97768d8fe4ad6743c8a19403e314511ed9f6d13205b687e52421c023ac1b9"}, + {file = "protobuf-7.35.1.tar.gz", hash = "sha256:ce115a26fe0c39a2c29973d914d327e516a6455464489fe3cd1e51a1b354f81a"}, ] [[package]] name = "psycopg2" -version = "2.9.9" +version = "2.9.12" description = "psycopg2 - Python-PostgreSQL Database Adapter" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "psycopg2-2.9.9-cp310-cp310-win32.whl", hash = "sha256:38a8dcc6856f569068b47de286b472b7c473ac7977243593a288ebce0dc89516"}, - {file = "psycopg2-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:426f9f29bde126913a20a96ff8ce7d73fd8a216cfb323b1f04da402d452853c3"}, - {file = "psycopg2-2.9.9-cp311-cp311-win32.whl", hash = "sha256:ade01303ccf7ae12c356a5e10911c9e1c51136003a9a1d92f7aa9d010fb98372"}, - {file = "psycopg2-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:121081ea2e76729acfb0673ff33755e8703d45e926e416cb59bae3a86c6a4981"}, - {file = "psycopg2-2.9.9-cp312-cp312-win32.whl", hash = "sha256:d735786acc7dd25815e89cc4ad529a43af779db2e25aa7c626de864127e5a024"}, - {file = "psycopg2-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:a7653d00b732afb6fc597e29c50ad28087dcb4fbfb28e86092277a559ae4e693"}, - {file = "psycopg2-2.9.9-cp37-cp37m-win32.whl", hash = "sha256:5e0d98cade4f0e0304d7d6f25bbfbc5bd186e07b38eac65379309c4ca3193efa"}, - {file = "psycopg2-2.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:7e2dacf8b009a1c1e843b5213a87f7c544b2b042476ed7755be813eaf4e8347a"}, - {file = "psycopg2-2.9.9-cp38-cp38-win32.whl", hash = "sha256:ff432630e510709564c01dafdbe996cb552e0b9f3f065eb89bdce5bd31fabf4c"}, - {file = "psycopg2-2.9.9-cp38-cp38-win_amd64.whl", hash = "sha256:bac58c024c9922c23550af2a581998624d6e02350f4ae9c5f0bc642c633a2d5e"}, - {file = "psycopg2-2.9.9-cp39-cp39-win32.whl", hash = "sha256:c92811b2d4c9b6ea0285942b2e7cac98a59e166d59c588fe5cfe1eda58e72d59"}, - {file = "psycopg2-2.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:de80739447af31525feddeb8effd640782cf5998e1a4e9192ebdf829717e3913"}, - {file = "psycopg2-2.9.9.tar.gz", hash = "sha256:d1454bde93fb1e224166811694d600e746430c006fbb031ea06ecc2ea41bf156"}, + {file = "psycopg2-2.9.12-cp310-cp310-win_amd64.whl", hash = "sha256:d5fbe092315fb007c03544704e6d1e678a6c0378139d01cea433dc59edf041b4"}, + {file = "psycopg2-2.9.12-cp311-cp311-win_amd64.whl", hash = "sha256:2532c0cdc6ad18c9c35cd935cc3159712e14f05276a6d29a6435c52d24b840c1"}, + {file = "psycopg2-2.9.12-cp312-cp312-win_amd64.whl", hash = "sha256:83d48e66e18c301d832e93c984a7bcbc0f4ac3bb79e2137e3bc335978c756dc0"}, + {file = "psycopg2-2.9.12-cp313-cp313-win_amd64.whl", hash = "sha256:3d23e684927d37b95cee9a943f6927b04ae2fdcd056fd0e2a30929ee89fee5a9"}, + {file = "psycopg2-2.9.12-cp314-cp314-win_amd64.whl", hash = "sha256:a73d5513bfe929c56555006c7a9cc7ae6e4276aa99dd2b1e2544eb8bb54f8b23"}, + {file = "psycopg2-2.9.12-cp39-cp39-win_amd64.whl", hash = "sha256:09826a6b89714626a662275d03f21639f1c68d183e2dcc9ba134d463a3da753e"}, + {file = "psycopg2-2.9.12.tar.gz", hash = "sha256:1dedb1c7a1d8552c4a6044c6b1c41a52e6a8e2d144af83eccac758076b1b7c15"}, ] [[package]] name = "pyasn1" -version = "0.5.1" +version = "0.6.4" description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +python-versions = ">=3.8" files = [ - {file = "pyasn1-0.5.1-py2.py3-none-any.whl", hash = "sha256:4439847c58d40b1d0a573d07e3856e95333f1976294494c325775aeca506eb58"}, - {file = "pyasn1-0.5.1.tar.gz", hash = "sha256:6d391a96e59b23130a5cfa74d6fd7f388dbbe26cc8f1edf39fdddf08d9d6676c"}, + {file = "pyasn1-0.6.4-py3-none-any.whl", hash = "sha256:deda9277cfd454080ec40b207fb6df82206a3a2688735233cdcd8d3d565f088b"}, + {file = "pyasn1-0.6.4.tar.gz", hash = "sha256:9c447d8431c947fe4c8febc4ed9e760bc29011a5b01e5c74b67025bd9fb8ce81"}, ] [[package]] name = "pyasn1-modules" -version = "0.3.0" +version = "0.4.2" description = "A collection of ASN.1-based protocols modules" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +python-versions = ">=3.8" files = [ - {file = "pyasn1_modules-0.3.0-py2.py3-none-any.whl", hash = "sha256:d3ccd6ed470d9ffbc716be08bd90efbd44d0734bc9303818f7336070984a162d"}, - {file = "pyasn1_modules-0.3.0.tar.gz", hash = "sha256:5bd01446b736eb9d31512a30d46c1ac3395d676c6f3cafa4c03eb54b9925631c"}, + {file = "pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a"}, + {file = "pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6"}, ] [package.dependencies] -pyasn1 = ">=0.4.6,<0.6.0" +pyasn1 = ">=0.6.1,<0.7.0" [[package]] name = "pycocotools" -version = "2.0.7" +version = "2.0.11" description = "Official APIs for the MS-COCO dataset" optional = false -python-versions = ">=3.5" -files = [ - {file = "pycocotools-2.0.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a6683a002fcb4500edbcec94bdf48be69f578a9aa5c638db38614df1f45cc935"}, - {file = "pycocotools-2.0.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d517ec315e53ef8df9f6b0899ebc4c79bd61fd715383861949bb1c3fca2c6d5"}, - {file = "pycocotools-2.0.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eb5d46900375adaba88eedb5cbc29d8cbcf43e82505d67378df1c3b720a8c5f"}, - {file = "pycocotools-2.0.7-cp310-cp310-win_amd64.whl", hash = "sha256:363a6be808125306ace1a163c0b9ba479ee08eceec1fbd3889a88bd8245f73dc"}, - {file = "pycocotools-2.0.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:623b941bbafecbfee574aedbf3cb257f7a879f4fdb79394e6d3fb9c76e7ad6cf"}, - {file = "pycocotools-2.0.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ac4f30bac1503c780072053e6922971392fa3628b2e6967192bfca1f14736e2"}, - {file = "pycocotools-2.0.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:121017ca87e2eec4e9081636d1a79519b50f473959defc5671c2d1ce0eec482e"}, - {file = "pycocotools-2.0.7-cp311-cp311-win_amd64.whl", hash = "sha256:4a8ec6f439638120e11f49120e1ddb6c66e0b1f293d7884207d02703a73d25a1"}, - {file = "pycocotools-2.0.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1a675728e459d72be6e3bb3546672bb37c7daffdc2e5335aa7b834aece2b560"}, - {file = "pycocotools-2.0.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6541340f26bae32e044eedc5d8ccdac5bd0cb64eb2b0a342dac859b696edd0aa"}, - {file = "pycocotools-2.0.7-cp37-cp37m-win_amd64.whl", hash = "sha256:8def3c46349e919999d6d5a1d6b7e587e6891524cc28f8b4a11e463bf0914621"}, - {file = "pycocotools-2.0.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6469089b9b36a1f645dc9ee830f29d261e99b4b3be73cb260688fd8b6d02760c"}, - {file = "pycocotools-2.0.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1dbc429018149dc34e206ea32ee6297ff30b55a8615a3f7f4c6e3842f9df73db"}, - {file = "pycocotools-2.0.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66864bec8b30d47faa946bb55c8e8d6b7acb9fba0c17ff6aaa37abd78cda962a"}, - {file = "pycocotools-2.0.7-cp38-cp38-win_amd64.whl", hash = "sha256:625388f52e543f6f798f75f1ec125fe519580f22e72ccbd75eee0355ce336e18"}, - {file = "pycocotools-2.0.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:73dc251ae4a06b7c10747ca7e2d29faabb4f13e5fc43760945966845581e79ae"}, - {file = "pycocotools-2.0.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e6f7bfa1c5fb206a614bf2382c923d56092219a12dfd0fec3b5f83c13e29e00"}, - {file = "pycocotools-2.0.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b29086b6ce7b73e4ddaf3045006f5c059f344a2720605cd4474814017ff2af53"}, - {file = "pycocotools-2.0.7-cp39-cp39-win_amd64.whl", hash = "sha256:254506c0eecabb3abbde17640f82103c0c04d53148ae920657664cab9cd649fc"}, - {file = "pycocotools-2.0.7.tar.gz", hash = "sha256:da8b7815196eebf0adabf67fcc459126cbc6498bbc6ab1fd144c371465d86879"}, +python-versions = ">=3.9" +files = [ + {file = "pycocotools-2.0.11-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:484d33515353186aadba9e2a290d81b107275cdb9565084e31a5568a52a0b120"}, + {file = "pycocotools-2.0.11-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ca9f120f719ec405ad0c74ccfdb8402b0c37bd5f88ab5b6482a0de2efd5a36f4"}, + {file = "pycocotools-2.0.11-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e40a3a898c6e5340b8d70cf7984868b9bff8c3d80187de9a3b661d504d665978"}, + {file = "pycocotools-2.0.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7cd4cdfd2c676f30838aa0b1047441892fb4f97d70bf3df480bcc7a18a64d7d4"}, + {file = "pycocotools-2.0.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08c79789fd79e801ae4ecfcfeec32b31e36254e7a2b4019af28c104975d5e730"}, + {file = "pycocotools-2.0.11-cp310-cp310-win_amd64.whl", hash = "sha256:f78cbb1a32d061fcad4bdba083de70a39a21c1c3d9235a3f77d8f007541ec5ef"}, + {file = "pycocotools-2.0.11-cp310-cp310-win_arm64.whl", hash = "sha256:e21311ea71f85591680d8992858e2d44a2a156dc3b2bf1c5c901c4a19348177b"}, + {file = "pycocotools-2.0.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:81bdceebb4c64e9265213e2d733808a12f9c18dfb14457323cc6b9af07fa0e61"}, + {file = "pycocotools-2.0.11-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a1c05f91ccc658dfe01325267209c4b435da1722c93eeb5749fabc1d087b6882"}, + {file = "pycocotools-2.0.11-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18ba75ff58cedb33a85ce2c18f1452f1fe20c9dd59925eec5300b2bf6205dbe1"}, + {file = "pycocotools-2.0.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:693417797f0377fd094eb815c0a1e7d1c3c0251b71e3b3779fce3b3cf24793c5"}, + {file = "pycocotools-2.0.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b6a07071c441d0f5e480a8f287106191582e40289d4e242dfe684e0c8a751088"}, + {file = "pycocotools-2.0.11-cp311-cp311-win_amd64.whl", hash = "sha256:8e159232adae3aef6b4e2d37b008bff107b26e9ed3b48e70ea6482302834bd34"}, + {file = "pycocotools-2.0.11-cp311-cp311-win_arm64.whl", hash = "sha256:4fc9889e819452b9c142036e1eabac8a13a8bd552d8beba299a57e0da6bfa1ec"}, + {file = "pycocotools-2.0.11-cp312-abi3-macosx_10_13_universal2.whl", hash = "sha256:a2e9634bc7cadfb01c88e0b98589aaf0bd12983c7927bde93f19c0103e5441f4"}, + {file = "pycocotools-2.0.11-cp312-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7fd4121766cc057133534679c0ec3f9023dbd96e9b31cf95c86a069ebdac2b65"}, + {file = "pycocotools-2.0.11-cp312-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a82d1c9ed83f75da0b3f244f2a3cf559351a283307bd9b79a4ee2b93ab3231dd"}, + {file = "pycocotools-2.0.11-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:89e853425018e2c2920ee0f2112cf7c140a1dcf5f4f49abd9c2da112c3e0f4b3"}, + {file = "pycocotools-2.0.11-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:87af87b8d06d5b852a885a319d9362dca3bed9f8bbcc3feb6513acb1f88ea242"}, + {file = "pycocotools-2.0.11-cp312-abi3-win_amd64.whl", hash = "sha256:ffe806ce535f5996445188f9a35643791dc54beabc61bd81e2b03367356d604f"}, + {file = "pycocotools-2.0.11-cp312-abi3-win_arm64.whl", hash = "sha256:c230f5e7b14bd19085217b4f40bba81bf14a182b150b8e9fab1c15d504ade343"}, + {file = "pycocotools-2.0.11-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:fd72b9734e6084b217c1fc3945bfd4ec05bdc75a44e4f0c461a91442bb804973"}, + {file = "pycocotools-2.0.11-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f7eb43b79448476b094240450420b7425d06e297880144b8ea6f01e9b4340e43"}, + {file = "pycocotools-2.0.11-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c3546b93b39943347c4f5b0694b5824105cbe2174098a416bcad4acd9c21e957"}, + {file = "pycocotools-2.0.11-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:efd1694b2075f2f10c5828f10f6e6c4e44368841fd07dae385c3aa015c8e25f9"}, + {file = "pycocotools-2.0.11-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:368244f30eb8d6cae7003aa2c0831fbdf0153664a32859ec7fbceea52bfb6878"}, + {file = "pycocotools-2.0.11-cp313-cp313t-win_amd64.whl", hash = "sha256:ac8aa17263e6489aa521f9fa91e959dfe0ea3a5519fde2cbf547312cdce7559e"}, + {file = "pycocotools-2.0.11-cp313-cp313t-win_arm64.whl", hash = "sha256:04480330df5013f6edd94891a0ee8294274185f1b5093d1b0f23d51778f0c0e9"}, + {file = "pycocotools-2.0.11-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:a6b13baf6bfcf881b6d6ac6e23c776f87a68304cd86e53d1d6b9afa31e363c4e"}, + {file = "pycocotools-2.0.11-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78bae4a9de9d34c4759754a848dfb3306f9ef1c2fcb12164ffbd3d013d008321"}, + {file = "pycocotools-2.0.11-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:83d896f4310379849dfcfa7893afb0ff21f4f3cdb04ab3f61b05dd98953dd0ad"}, + {file = "pycocotools-2.0.11-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:eebd723503a2eb2c8b285f56ea3be1d9f3875cd7c40d945358a428db94f14015"}, + {file = "pycocotools-2.0.11-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:bd7a1e19ef56a828a94bace673372071d334a9232cd32ae3cd48845a04d45c4f"}, + {file = "pycocotools-2.0.11-cp314-cp314t-win_amd64.whl", hash = "sha256:63026e11a56211058d0e84e8263f74cbccd5e786fac18d83fd221ecb9819fcc7"}, + {file = "pycocotools-2.0.11-cp314-cp314t-win_arm64.whl", hash = "sha256:8cedb8ccb97ffe9ed2c8c259234fa69f4f1e8665afe3a02caf93f6ef2952c07f"}, + {file = "pycocotools-2.0.11-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9dc8b388984c72aa84b1a68933f196ce71ab114c59232d0eab20c97cc1300875"}, + {file = "pycocotools-2.0.11-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2b018497ec198ffc737dd7e6306a2e69999779ca619a9e12950e4506e410c3e"}, + {file = "pycocotools-2.0.11-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e72527fdc00985d29dbe31d17b19cd2d16fbad7b01e974c567b593d5844de710"}, + {file = "pycocotools-2.0.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d6b88557166794a24acd03f50296f2b95adf3e4206b4b8995e6bdca925c9cb72"}, + {file = "pycocotools-2.0.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6a2f4f036f5bfdaf8c9625279051e921721fc9d27f92c97a3f3355a07ba38513"}, + {file = "pycocotools-2.0.11-cp39-cp39-win_amd64.whl", hash = "sha256:eba35d6e06caaea28ce65a4b92e4343ecbb9abf4915f7ef7fca989b80839111c"}, + {file = "pycocotools-2.0.11-cp39-cp39-win_arm64.whl", hash = "sha256:1192de413a23b4b94199197e8f8dbe1277cc24e6e9847bee6a71be3d8e543963"}, + {file = "pycocotools-2.0.11.tar.gz", hash = "sha256:34254d76da85576fcaf5c1f3aa9aae16b8cb15418334ba4283b800796bd1993d"}, ] [package.dependencies] -matplotlib = ">=2.1.0" numpy = "*" +[package.extras] +all = ["matplotlib (>=2.1.0)"] + [[package]] name = "pycparser" -version = "2.21" +version = "3.0" description = "C parser in Python" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.10" files = [ - {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, - {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, + {file = "pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992"}, + {file = "pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29"}, ] [[package]] name = "pycryptodome" -version = "3.21.0" +version = "3.23.0" description = "Cryptographic library for Python" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" -files = [ - {file = "pycryptodome-3.21.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:dad9bf36eda068e89059d1f07408e397856be9511d7113ea4b586642a429a4fd"}, - {file = "pycryptodome-3.21.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:a1752eca64c60852f38bb29e2c86fca30d7672c024128ef5d70cc15868fa10f4"}, - {file = "pycryptodome-3.21.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:3ba4cc304eac4d4d458f508d4955a88ba25026890e8abff9b60404f76a62c55e"}, - {file = "pycryptodome-3.21.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7cb087b8612c8a1a14cf37dd754685be9a8d9869bed2ffaaceb04850a8aeef7e"}, - {file = "pycryptodome-3.21.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:26412b21df30b2861424a6c6d5b1d8ca8107612a4cfa4d0183e71c5d200fb34a"}, - {file = "pycryptodome-3.21.0-cp27-cp27m-win32.whl", hash = "sha256:cc2269ab4bce40b027b49663d61d816903a4bd90ad88cb99ed561aadb3888dd3"}, - {file = "pycryptodome-3.21.0-cp27-cp27m-win_amd64.whl", hash = "sha256:0fa0a05a6a697ccbf2a12cec3d6d2650b50881899b845fac6e87416f8cb7e87d"}, - {file = "pycryptodome-3.21.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6cce52e196a5f1d6797ff7946cdff2038d3b5f0aba4a43cb6bf46b575fd1b5bb"}, - {file = "pycryptodome-3.21.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:a915597ffccabe902e7090e199a7bf7a381c5506a747d5e9d27ba55197a2c568"}, - {file = "pycryptodome-3.21.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4e74c522d630766b03a836c15bff77cb657c5fdf098abf8b1ada2aebc7d0819"}, - {file = "pycryptodome-3.21.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:a3804675283f4764a02db05f5191eb8fec2bb6ca34d466167fc78a5f05bbe6b3"}, - {file = "pycryptodome-3.21.0-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:2480ec2c72438430da9f601ebc12c518c093c13111a5c1644c82cdfc2e50b1e4"}, - {file = "pycryptodome-3.21.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:de18954104667f565e2fbb4783b56667f30fb49c4d79b346f52a29cb198d5b6b"}, - {file = "pycryptodome-3.21.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2de4b7263a33947ff440412339cb72b28a5a4c769b5c1ca19e33dd6cd1dcec6e"}, - {file = "pycryptodome-3.21.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0714206d467fc911042d01ea3a1847c847bc10884cf674c82e12915cfe1649f8"}, - {file = "pycryptodome-3.21.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d85c1b613121ed3dbaa5a97369b3b757909531a959d229406a75b912dd51dd1"}, - {file = "pycryptodome-3.21.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:8898a66425a57bcf15e25fc19c12490b87bd939800f39a03ea2de2aea5e3611a"}, - {file = "pycryptodome-3.21.0-cp36-abi3-musllinux_1_2_i686.whl", hash = "sha256:932c905b71a56474bff8a9c014030bc3c882cee696b448af920399f730a650c2"}, - {file = "pycryptodome-3.21.0-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:18caa8cfbc676eaaf28613637a89980ad2fd96e00c564135bf90bc3f0b34dd93"}, - {file = "pycryptodome-3.21.0-cp36-abi3-win32.whl", hash = "sha256:280b67d20e33bb63171d55b1067f61fbd932e0b1ad976b3a184303a3dad22764"}, - {file = "pycryptodome-3.21.0-cp36-abi3-win_amd64.whl", hash = "sha256:b7aa25fc0baa5b1d95b7633af4f5f1838467f1815442b22487426f94e0d66c53"}, - {file = "pycryptodome-3.21.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:2cb635b67011bc147c257e61ce864879ffe6d03342dc74b6045059dfbdedafca"}, - {file = "pycryptodome-3.21.0-pp27-pypy_73-win32.whl", hash = "sha256:4c26a2f0dc15f81ea3afa3b0c87b87e501f235d332b7f27e2225ecb80c0b1cdd"}, - {file = "pycryptodome-3.21.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d5ebe0763c982f069d3877832254f64974139f4f9655058452603ff559c482e8"}, - {file = "pycryptodome-3.21.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ee86cbde706be13f2dec5a42b52b1c1d1cbb90c8e405c68d0755134735c8dc6"}, - {file = "pycryptodome-3.21.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fd54003ec3ce4e0f16c484a10bc5d8b9bd77fa662a12b85779a2d2d85d67ee0"}, - {file = "pycryptodome-3.21.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5dfafca172933506773482b0e18f0cd766fd3920bd03ec85a283df90d8a17bc6"}, - {file = "pycryptodome-3.21.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:590ef0898a4b0a15485b05210b4a1c9de8806d3ad3d47f74ab1dc07c67a6827f"}, - {file = "pycryptodome-3.21.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f35e442630bc4bc2e1878482d6f59ea22e280d7121d7adeaedba58c23ab6386b"}, - {file = "pycryptodome-3.21.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff99f952db3db2fbe98a0b355175f93ec334ba3d01bbde25ad3a5a33abc02b58"}, - {file = "pycryptodome-3.21.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8acd7d34af70ee63f9a849f957558e49a98f8f1634f86a59d2be62bb8e93f71c"}, - {file = "pycryptodome-3.21.0.tar.gz", hash = "sha256:f7787e0d469bdae763b876174cf2e6c0f7be79808af26b1da96f1a64bcf47297"}, +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "pycryptodome-3.23.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a176b79c49af27d7f6c12e4b178b0824626f40a7b9fed08f712291b6d54bf566"}, + {file = "pycryptodome-3.23.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:573a0b3017e06f2cffd27d92ef22e46aa3be87a2d317a5abf7cc0e84e321bd75"}, + {file = "pycryptodome-3.23.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:63dad881b99ca653302b2c7191998dd677226222a3f2ea79999aa51ce695f720"}, + {file = "pycryptodome-3.23.0-cp27-cp27m-win32.whl", hash = "sha256:b34e8e11d97889df57166eda1e1ddd7676da5fcd4d71a0062a760e75060514b4"}, + {file = "pycryptodome-3.23.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:7ac1080a8da569bde76c0a104589c4f414b8ba296c0b3738cf39a466a9fb1818"}, + {file = "pycryptodome-3.23.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6fe8258e2039eceb74dfec66b3672552b6b7d2c235b2dfecc05d16b8921649a8"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:0011f7f00cdb74879142011f95133274741778abba114ceca229adbf8e62c3e4"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:90460fc9e088ce095f9ee8356722d4f10f86e5be06e2354230a9880b9c549aae"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4764e64b269fc83b00f682c47443c2e6e85b18273712b98aa43bcb77f8570477"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d97618c9c6684a97ef7637ba43bdf6663a2e2e77efe0f863cce97a76af396446"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a53a4fe5cb075075d515797d6ce2f56772ea7e6a1e5e4b96cf78a14bac3d265"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:763d1d74f56f031788e5d307029caef067febf890cd1f8bf61183ae142f1a77b"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:954af0e2bd7cea83ce72243b14e4fb518b18f0c1649b576d114973e2073b273d"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:257bb3572c63ad8ba40b89f6fc9d63a2a628e9f9708d31ee26560925ebe0210a"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6501790c5b62a29fcb227bd6b62012181d886a767ce9ed03b303d1f22eb5c625"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9a77627a330ab23ca43b48b130e202582e91cc69619947840ea4d2d1be21eb39"}, + {file = "pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27"}, + {file = "pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843"}, + {file = "pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490"}, + {file = "pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575"}, + {file = "pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b"}, + {file = "pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a"}, + {file = "pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f"}, + {file = "pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa"}, + {file = "pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886"}, + {file = "pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2"}, + {file = "pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c"}, + {file = "pycryptodome-3.23.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:350ebc1eba1da729b35ab7627a833a1a355ee4e852d8ba0447fafe7b14504d56"}, + {file = "pycryptodome-3.23.0-pp27-pypy_73-win32.whl", hash = "sha256:93837e379a3e5fd2bb00302a47aee9fdf7940d83595be3915752c74033d17ca7"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddb95b49df036ddd264a0ad246d1be5b672000f12d6961ea2c267083a5e19379"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e95564beb8782abfd9e431c974e14563a794a4944c29d6d3b7b5ea042110b4"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e15c081e912c4b0d75632acd8382dfce45b258667aa3c67caf7a4d4c13f630"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7fc76bf273353dc7e5207d172b83f569540fc9a28d63171061c42e361d22353"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:865d83c906b0fc6a59b510deceee656b6bc1c4fa0d82176e2b77e97a420a996a"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89d4d56153efc4d81defe8b65fd0821ef8b2d5ddf8ed19df31ba2f00872b8002"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3f2d0aaf8080bda0587d58fc9fe4766e012441e2eed4269a77de6aea981c8be"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64093fc334c1eccfd3933c134c4457c34eaca235eeae49d69449dc4728079339"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ce64e84a962b63a47a592690bdc16a7eaf709d2c2697ababf24a0def566899a6"}, + {file = "pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef"}, ] [[package]] name = "pydantic" -version = "2.6.4" +version = "2.13.4" description = "Data validation using Python type hints" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pydantic-2.6.4-py3-none-any.whl", hash = "sha256:cc46fce86607580867bdc3361ad462bab9c222ef042d3da86f2fb333e1d916c5"}, - {file = "pydantic-2.6.4.tar.gz", hash = "sha256:b1704e0847db01817624a6b86766967f552dd9dbf3afba4004409f908dcc84e6"}, + {file = "pydantic-2.13.4-py3-none-any.whl", hash = "sha256:45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba"}, + {file = "pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6"}, ] [package.dependencies] -annotated-types = ">=0.4.0" -pydantic-core = "2.16.3" -typing-extensions = ">=4.6.1" +annotated-types = ">=0.6.0" +email-validator = {version = ">=2.0.0", optional = true, markers = "extra == \"email\""} +pydantic-core = "2.46.4" +typing-extensions = ">=4.14.1" +typing-inspection = ">=0.4.2" [package.extras] email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata"] [[package]] name = "pydantic-core" -version = "2.16.3" -description = "" +version = "2.46.4" +description = "Core functionality for Pydantic validation and serialization" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" +files = [ + {file = "pydantic_core-2.46.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a396dcc17e5a0b164dbe026896245a4fa9ff402edca1dff0be3d53a517f74de4"}, + {file = "pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:da4b951fe36dc7c3a1ccb4e3cd1747c3542b8c9ceede8fc86cae054e764485f5"}, + {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb63e0198ca18aad131c089b9204c23079c3afa95487e561f4c522d519e55aba"}, + {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f47286a97f0bc9b8859519809077b91b2cefe4ae47fcbf5e466a009c1c5d742b"}, + {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:905a0ed8ea6f2d61c1738835f99b699348d7857379083e5fc497fa0c967a407c"}, + {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea793e075b70290d89d8142074262885d3f7da19634845135751bd6344f73b50"}, + {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:395aebd9183f9d112f569aeb5b2214d1a10a33bec8456447f7fbdfa51d38d4cd"}, + {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:b078afbc25f3a1436c7a1d2cd3e322497ee99615ba97c563566fdf46aff1ee01"}, + {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f747929cf940cddb5b3668a390056ddd5ba2e5010615ea2dcf4f9c4f3ab8791d"}, + {file = "pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:daa27d92c36f24388fe3ad306b174781c747627f134452e4f128ea00ce1fe8c4"}, + {file = "pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:19e51f073cd3df251856a8a4189fbdf1de4012c3ebacfb1884f94f1eb406079f"}, + {file = "pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1747f85cee84c26985853c6f3d9bd3e75da5212912443fa111c113b9c246f39"}, + {file = "pydantic_core-2.46.4-cp310-cp310-win32.whl", hash = "sha256:2f84c03c8607173d16b5a854ec68a2f9079ae03237a54fb506d13af47e1d018d"}, + {file = "pydantic_core-2.46.4-cp310-cp310-win_amd64.whl", hash = "sha256:8358a950c8909158e3df31538a7e4edc2d7265a7c54b47f0864d9e5bae9dcebf"}, + {file = "pydantic_core-2.46.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0e96592440881c74a213e5ad528e2b24d3d4f940de2766bed9010ab1d9e51594"}, + {file = "pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0d65b8c354be7fb5f720c3caa8bc940bc2d20ce749c8e06135f07f8ed95dd7c"}, + {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bfb192b3f4b9e8a89b6277b6ce787564f62cfd272055f6e685726b111dc7826"}, + {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9037063db01f09b09e237c282b6792bd4da634b5402c4e7f0c61effed7701a04"}, + {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc010ab034c8c7452522748bf937df58020d256ccae0874463d1f4d01758af8e"}, + {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c5dac79fa1614d1e06ca695109c6105923bd9c7d1d6c918d4e637b7e6b32fd3"}, + {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9fa868638bf362d3d138ea55829cefb3d5f4b0d7f142234382a15e2485dbec4"}, + {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:17299feefe090f2caa5b8e37222bb5f663e4935a8bfa6931d4102e5df1a9f398"}, + {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4c63ebc82684aa89d9a3bcbd13d515b3be44250dc68dd3bd81526c1cb31286c3"}, + {file = "pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:aaa2a54443eff1950ba5ddc6b6ccda0d9c84a364276a62f969bdf2a390650848"}, + {file = "pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:18e5ceec2ab67e6d5f1a9085e5a24c9c4e2ac4545730bfe668680bca05e555f3"}, + {file = "pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a0f62d0a58f4e7da165457e995725421e0064f2255d8eccebc49f41bbc23b109"}, + {file = "pydantic_core-2.46.4-cp311-cp311-win32.whl", hash = "sha256:041bde0a48fd37cf71cab1c9d56d3e8625a3793fef1f7dd232b3ff37e978ecda"}, + {file = "pydantic_core-2.46.4-cp311-cp311-win_amd64.whl", hash = "sha256:6f2eeda33a839975441c86a4119e1383c50b47faf0cbb5176985565c6bb02c33"}, + {file = "pydantic_core-2.46.4-cp311-cp311-win_arm64.whl", hash = "sha256:14f4c5d6db102bd796a627bbb3a17b4cf4574b9ae861d8b7c9a9661c6dd3362d"}, + {file = "pydantic_core-2.46.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3245406455a5d98187ec35530fd772b1d799b26667980872c8d4614991e2c4a2"}, + {file = "pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:962ccbab7b642487b1d8b7df90ef677e03134cf1fd8880bf698649b22a69371f"}, + {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8233f2947cf85404441fd7e0085f53b10c93e0ee78611099b5c7237e36aacbf7"}, + {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a233125ac121aa3ffba9a2b59edfc4a985a76092dc8279586ab4b71390875e7"}, + {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b712b53160b79a5850310b912a5ef8e57e56947c8ad690c227f5c9d7e561712"}, + {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9401557acd873c3a7f3eb9383edef8ac4968f9510e340f4808d427e75667e7b4"}, + {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:926c9541b14b12b1681dca8a0b75feb510b06c6341b70a8e500c2fdcff837cce"}, + {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:56cb4851bcaf3d117eddcef4fe66afd750a50274b0da8e22be256d10e5611987"}, + {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c68fcd102d71ea85c5b2dfac3f4f8476eff42a9e078fd5faefff6d145063536b"}, + {file = "pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b2f69dec1725e79a012d920df1707de5caf7ed5e08f3be4435e25803efc47458"}, + {file = "pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:8d0820e8192167f80d88d64038e609c31452eeca865b4e1d9950a27a4609b00b"}, + {file = "pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fbdb89b3e1c94a30cc5edfce477c6e6a5dc4d8f84665b455c27582f211a1c72c"}, + {file = "pydantic_core-2.46.4-cp312-cp312-win32.whl", hash = "sha256:9aa768456404a8bf48a4406685ac2bec8e72b62c69313734fa3b73cf33b3a894"}, + {file = "pydantic_core-2.46.4-cp312-cp312-win_amd64.whl", hash = "sha256:e9c26f834c65f5752f3f06cb08cb86a913ceb7274d0db6e267808a708b46bc89"}, + {file = "pydantic_core-2.46.4-cp312-cp312-win_arm64.whl", hash = "sha256:4fc73cb559bdb54b1134a706a2802a4cddd27a0633f5abb7e53056268751ac6a"}, + {file = "pydantic_core-2.46.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5d5902252db0d3cedf8d4a1bc68f70eeb430f7e4c7104c8c476753519b423008"}, + {file = "pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c94f0688e7b8d0a67abf40e57a7eaaecd17cc9586706a31b76c031f63df052b4"}, + {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f027324c56cd5406ca49c124b0db10e56c69064fec039acc571c29020cc87c76"}, + {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e739fee756ba1010f8bcccb534252e85a35fe45ae92c295a06059ce58b74ccd3"}, + {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d56801be94b86a9da183e5f3766e6310752b99ff647e38b09a9500d88e46e76"}, + {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2412e734dcb48da14d4e4006b82b46b74f2518b8a26ee7e58c6844a6cd6d03c4"}, + {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9551187363ffc0de2a00b2e47c25aeaeb1020b69b668762966df15fc5659dd5a"}, + {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0186750b482eefa11d7f435892b09c5c606193ef3375bcf94aa00ae6bfb66262"}, + {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5855698a4856556d86e8e6cd8434bc3ac0314ee8e12089ae0e143f64c6256e4e"}, + {file = "pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cbaf13819775b7f769bf4a1f066cb6df7a28d4480081a589828ef190226881cd"}, + {file = "pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:633147d34cf4550417f12e2b1a0383973bdf5cdfde212cb09e9a581cf10820be"}, + {file = "pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:82cf5301172168103724d49a1444d3378cb20cdee30b116a1bd6031236298a5d"}, + {file = "pydantic_core-2.46.4-cp313-cp313-win32.whl", hash = "sha256:9fa8ae11da9e2b3126c6426f147e0fba88d96d65921799bb30c6abd1cb2c97fb"}, + {file = "pydantic_core-2.46.4-cp313-cp313-win_amd64.whl", hash = "sha256:6b3ace8194b0e5204818c92802dcdca7fc6d88aabbb799d7c795540d9cd6d292"}, + {file = "pydantic_core-2.46.4-cp313-cp313-win_arm64.whl", hash = "sha256:184c081504d17f1c1066e430e117142b2c77d9448a97f7b65c6ac9fd9aee238d"}, + {file = "pydantic_core-2.46.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:428e04521a40150c85216fc8b85e8d39fece235a9cf5e383761238c7fa9b96fb"}, + {file = "pydantic_core-2.46.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23ace664830ee0bfe014a0c7bc248b1f7f25ed7ad103852c317624a1083af462"}, + {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce5c1d2a8b27468f433ca974829c44060b8097eedc39933e3c206a90ee49c4a9"}, + {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7283d57845ecf5a163403eb0702dfc220cc4fbdd18919cb5ccea4f95ee1cdab4"}, + {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8daafc69c93ee8a0204506a3b6b30f586ef54028f52aeeeb5c4cfc5184fd5914"}, + {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd2213145bcc2ba85884d0ac63d222fece9209678f77b9b4d76f054c561adb28"}, + {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a5f930472650a82629163023e630d160863fce524c616f4e5186e5de9d9a49b"}, + {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:c1b3f518abeca3aa13c712fd202306e145abf59a18b094a6bafb2d2bbf59192c"}, + {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a7dd0b3ee80d90150e3495a3a13ac34dbcbfd4f012996a6a1d8900e91b5c0fb"}, + {file = "pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:3fb702cd90b0446a3a1c5e470bfa0dd23c0233b676a9099ddcc964fa6ca13898"}, + {file = "pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b8458003118a712e66286df6a707db01c52c0f52f7db8e4a38f0da1d3b94fc4e"}, + {file = "pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:372429a130e469c9cd698925ce5fc50940b7a1336b0d82038e63d5bbc4edc519"}, + {file = "pydantic_core-2.46.4-cp314-cp314-win32.whl", hash = "sha256:85bb3611ff1802f3ee7fdd7dbff26b56f343fb432d57a4728fdd49b6ef35e2f4"}, + {file = "pydantic_core-2.46.4-cp314-cp314-win_amd64.whl", hash = "sha256:811ff8e9c313ab425368bcbb36e5c4ebd7108c2bbf4e4089cfbb0b01eff63fac"}, + {file = "pydantic_core-2.46.4-cp314-cp314-win_arm64.whl", hash = "sha256:bfec22eab3c8cc2ceec0248aec886624116dc079afa027ecc8ad4a7e62010f8a"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:af8244b2bef6aaad6d92cda81372de7f8c8d36c9f0c3ea36e827c60e7d9467a0"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a4330cdbc57162e4b3aa303f588ba752257694c9c9be3e7ebb11b4aca659b5d"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c61fc04a3d840155ff08e475a04809278972fe6aef51e2720554e96367e34b"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c50f2528cf200c5eed56faf3f4e22fcd5f38c157a8b78576e6ba3168ec35f000"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0cbe8b01f948de4286c74cdd6c667aceb38f5c1e26f0693b3983d9d74887c65e"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:617d7e2ca7dcb8c5cf6bcb8c59b8832c94b36196bbf1cbd1bfb56ed341905edd"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7027560ee92211647d0d34e3f7cd6f50da56399d26a9c8ad0da286d3869a53f3"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:f99626688942fb746e545232e7726926f3be91b5975f8b55327665fafda991c7"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc3e9034a63de20e15e8ade85358bc6efc614008cab72898b4b4952bea0509ff"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:97e7cf2be5c77b7d1a9713a05605d49460d02c6078d38d8bef3cbe323c548424"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:3bf92c5d0e00fefaab325a4d27828fe6b6e2a21848686b5b60d2d9eeb09d76c6"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:3ecbc122d18468d06ca279dc26a8c2e2d5acb10943bb35e36ae92096dc3b5565"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-win32.whl", hash = "sha256:e846ae7835bf0703ae43f534ab79a867146dadd59dc9ca5c8b53d5c8f7c9ef02"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-win_amd64.whl", hash = "sha256:2108ba5c1c1eca18030634489dc544844144ee36357f2f9f780b93e7ddbb44b5"}, + {file = "pydantic_core-2.46.4-cp314-cp314t-win_arm64.whl", hash = "sha256:4fcbe087dbc2068af7eda3aa87634eba216dbda64d1ae73c8684b621d33f6596"}, + {file = "pydantic_core-2.46.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:fd8b3d9fd264be37976686c7f65cd52a83f5e84f4bfd2adf9c1d469676bbb6ae"}, + {file = "pydantic_core-2.46.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9f444c499b3eefd3a92e348059471ea0c3a6e303d9c1cec09fa748fd9f895201"}, + {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3447661d99f75a3683a4cf5c87da72f2161964611864dbbeac7fbb118bb4bfc0"}, + {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b9bab013d1c7a79d3501ff86d0bc9c31bf587db4551677b96bec07df78c6b15"}, + {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d995260fdf4e1db774581b4900e0f832abe3c7c84996726bbc161b19c8f29e76"}, + {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f13a646d65d09fbf1bc6b3a9635d30095c8e7e5cc419ff35ecc563c5fd04cd49"}, + {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432c179df7874eeb73307aad2df0755e1ae0efa61ff0ea89b93e194411ae3928"}, + {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_31_riscv64.whl", hash = "sha256:e68b7a074f65a2fd746c52a7ce6142ab7006074ac269ace0c25cd8ba171f8066"}, + {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4a05d69cba51d852c5c3e92758653245a50c0b646ced0cf05bd793ed592839d6"}, + {file = "pydantic_core-2.46.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:228ee9bae8bef5b1e97ec58302f80357c37199e0d0a99174e138d28e6957b9d9"}, + {file = "pydantic_core-2.46.4-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:10e17cbb10a330363733efc4d7c4d0dd827ac0909b8f6a6542298fed1ea62f29"}, + {file = "pydantic_core-2.46.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:91a06d2e259ecfbd8c901d70c3c507900458498142b3026a296b7de4d1322cc9"}, + {file = "pydantic_core-2.46.4-cp39-cp39-win32.whl", hash = "sha256:d80ee3d731373b24cebbc10d689ca4ee1875caf0d5703a245db18efd4dd37fc1"}, + {file = "pydantic_core-2.46.4-cp39-cp39-win_amd64.whl", hash = "sha256:3be77f45df024d789a672ae34f8b06fb346c4f9f46ea714956660ea4862e89ac"}, + {file = "pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:14d4edf427bdcf950a8a02d7cb44a08614388dd6e1bdcbf4f67504fa7887da9c"}, + {file = "pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:0ce40cd7b21210e99342afafbd4d0f76d784eb5b1d60f3bdc566be4983c6c73b"}, + {file = "pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90884113d8b48f760e9587002789ddd741e76ab9f89518cd1e43b1f1a52ec44b"}, + {file = "pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66ce7632c22d837c95301830e111ad0128a32b8207533b60896a96c4915192ea"}, + {file = "pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:1d8ba486450b14f3b1d63bc521d410ec7565e52f887b9fb671791886436a42f7"}, + {file = "pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:3009f12e4e90b7f88b4f9adb1b0c4a3d58fe7820f3238c190047209d148026df"}, + {file = "pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad785e92e6dc634c21555edc8bd6b64957ab844541bcb96a1366c202951ae526"}, + {file = "pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00c603d540afdd6b80eb39f078f33ebd46211f02f33e34a32d9f053bba711de0"}, + {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0c563b08bca408dc7f65f700633d8442fffb2421fc47b8101377e9fd65051ff0"}, + {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:db06ffe51636ffe9ca531fe9023dd64bdd794be8754cb5df57c5498ae5b518a7"}, + {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:133878133d271ade3d41d1bfb2a45ec38dbdbda40bc065921c6b04e4630127e2"}, + {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9bc519fbf2b7578398853d815009ae5e4d4603d12f4e3f91da8c06852d3da3e9"}, + {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c7a7bd4e39e8e4c12c39cd480356842b6a8a06e41b23a55a5e3e191718838ddf"}, + {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:d396ec2b979760aaf3218e76c24e65bd0aca24983298653b3a9d7a45f9e47b30"}, + {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:86e1a4418c6cd97d60c95c71164158eaf7324fae7b0923264016baa993eba6fc"}, + {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:d51026d73fcfd93610abc7b27789c26b313920fcfb20e27462d74a7f8b06e983"}, + {file = "pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1"}, +] + +[package.dependencies] +typing-extensions = ">=4.14.1" + +[[package]] +name = "pydantic-extra-types" +version = "2.11.1" +description = "Extra Pydantic types." +optional = false +python-versions = ">=3.9" +files = [ + {file = "pydantic_extra_types-2.11.1-py3-none-any.whl", hash = "sha256:1722ea2bddae5628ace25f2aa685b69978ef533123e5638cfbddb999e0100ec1"}, + {file = "pydantic_extra_types-2.11.1.tar.gz", hash = "sha256:46792d2307383859e923d8fcefa82108b1a141f8a9c0198982b3832ab5ef1049"}, +] + +[package.dependencies] +pydantic = ">=2.5.2" +typing-extensions = "*" + +[package.extras] +all = ["cron-converter (>=1.2.2)", "pendulum (>=3.0.0,<4.0.0)", "phonenumbers (>=8,<10)", "pycountry (>=23)", "pymongo (>=4.0.0,<5.0.0)", "python-ulid (>=1,<2)", "python-ulid (>=1,<4)", "pytz (>=2024.1)", "semver (>=3.0.2)", "semver (>=3.0.2,<3.1.0)", "tzdata (>=2024.1)", "uuid-utils (>=0.6.0)"] +cron = ["cron-converter (>=1.2.2)"] +pendulum = ["pendulum (>=3.0.0,<4.0.0)"] +phonenumbers = ["phonenumbers (>=8,<10)"] +pycountry = ["pycountry (>=23)"] +python-ulid = ["python-ulid (>=1,<2)", "python-ulid (>=1,<4)"] +semver = ["semver (>=3.0.2)"] +uuid-utils = ["uuid-utils (>=0.6.0)"] + +[[package]] +name = "pydantic-settings" +version = "2.14.2" +description = "Settings management using Pydantic" +optional = false +python-versions = ">=3.10" files = [ - {file = "pydantic_core-2.16.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4"}, - {file = "pydantic_core-2.16.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99"}, - {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979"}, - {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db"}, - {file = "pydantic_core-2.16.3-cp310-none-win32.whl", hash = "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132"}, - {file = "pydantic_core-2.16.3-cp310-none-win_amd64.whl", hash = "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb"}, - {file = "pydantic_core-2.16.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4"}, - {file = "pydantic_core-2.16.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f"}, - {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e"}, - {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba"}, - {file = "pydantic_core-2.16.3-cp311-none-win32.whl", hash = "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721"}, - {file = "pydantic_core-2.16.3-cp311-none-win_amd64.whl", hash = "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df"}, - {file = "pydantic_core-2.16.3-cp311-none-win_arm64.whl", hash = "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9"}, - {file = "pydantic_core-2.16.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff"}, - {file = "pydantic_core-2.16.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e"}, - {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca"}, - {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf"}, - {file = "pydantic_core-2.16.3-cp312-none-win32.whl", hash = "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe"}, - {file = "pydantic_core-2.16.3-cp312-none-win_amd64.whl", hash = "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed"}, - {file = "pydantic_core-2.16.3-cp312-none-win_arm64.whl", hash = "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6"}, - {file = "pydantic_core-2.16.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01"}, - {file = "pydantic_core-2.16.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c"}, - {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8"}, - {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5"}, - {file = "pydantic_core-2.16.3-cp38-none-win32.whl", hash = "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a"}, - {file = "pydantic_core-2.16.3-cp38-none-win_amd64.whl", hash = "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed"}, - {file = "pydantic_core-2.16.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820"}, - {file = "pydantic_core-2.16.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8"}, - {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b"}, - {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972"}, - {file = "pydantic_core-2.16.3-cp39-none-win32.whl", hash = "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2"}, - {file = "pydantic_core-2.16.3-cp39-none-win_amd64.whl", hash = "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da"}, - {file = "pydantic_core-2.16.3.tar.gz", hash = "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad"}, + {file = "pydantic_settings-2.14.2-py3-none-any.whl", hash = "sha256:a20c97b37910b6550d5ea50fbcc2d4187defe58cd57070b73863d069419c9440"}, + {file = "pydantic_settings-2.14.2.tar.gz", hash = "sha256:c19dd64b19097f1de80184f0cc7b0272a13ae6e170cbf240a3e27e381ed14a5f"}, ] [package.dependencies] -typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" +pydantic = ">=2.7.0" +python-dotenv = ">=0.21.0" +typing-inspection = ">=0.4.0" + +[package.extras] +aws-secrets-manager = ["boto3 (>=1.35.0)", "types-boto3[secretsmanager]"] +azure-key-vault = ["azure-identity (>=1.16.0)", "azure-keyvault-secrets (>=4.8.0)"] +gcp-secret-manager = ["google-cloud-secret-manager (>=2.23.1)"] +toml = ["tomli (>=2.0.1)"] +yaml = ["pyyaml (>=6.0.1)"] [[package]] name = "pygments" -version = "2.18.0" +version = "2.20.0" description = "Pygments is a syntax highlighting package written in Python." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, - {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, + {file = "pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176"}, + {file = "pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f"}, ] [package.extras] @@ -3364,13 +4188,13 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyparsing" -version = "3.1.1" -description = "pyparsing module - Classes and methods to define and execute parsing grammars" +version = "3.3.2" +description = "pyparsing - Classes and methods to define and execute parsing grammars" optional = false -python-versions = ">=3.6.8" +python-versions = ">=3.9" files = [ - {file = "pyparsing-3.1.1-py3-none-any.whl", hash = "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb"}, - {file = "pyparsing-3.1.1.tar.gz", hash = "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db"}, + {file = "pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d"}, + {file = "pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc"}, ] [package.extras] @@ -3378,35 +4202,36 @@ diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "pytest" -version = "7.4.4" +version = "9.1.1" description = "pytest: simple powerful testing with Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" files = [ - {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, - {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, + {file = "pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c"}, + {file = "pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313"}, ] [package.dependencies] -colorama = {version = "*", markers = "sys_platform == \"win32\""} -exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} -iniconfig = "*" -packaging = "*" -pluggy = ">=0.12,<2.0" -tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} +colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1", markers = "python_version < \"3.11\""} +iniconfig = ">=1.0.1" +packaging = ">=22" +pluggy = ">=1.5,<2" +pygments = ">=2.7.2" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] [[package]] name = "python-dateutil" -version = "2.8.2" +version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, ] [package.dependencies] @@ -3414,13 +4239,13 @@ six = ">=1.5" [[package]] name = "python-dotenv" -version = "1.0.1" +version = "1.2.2" description = "Read key-value pairs from a .env file and set them as environment variables" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, - {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, + {file = "python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a"}, + {file = "python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3"}, ] [package.extras] @@ -3428,122 +4253,147 @@ cli = ["click (>=5.0)"] [[package]] name = "python-multipart" -version = "0.0.16" +version = "0.0.32" description = "A streaming multipart parser for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "python_multipart-0.0.16-py3-none-any.whl", hash = "sha256:c2759b7b976ef3937214dfb592446b59dfaa5f04682a076f78b117c94776d87a"}, - {file = "python_multipart-0.0.16.tar.gz", hash = "sha256:8dee37b88dab9b59922ca173c35acb627cc12ec74019f5cd4578369c6df36554"}, + {file = "python_multipart-0.0.32-py3-none-any.whl", hash = "sha256:ff6d3f776f16878c894e52e107296ffc890e913c611b1a4ec6c44e2821fe2e23"}, + {file = "python_multipart-0.0.32.tar.gz", hash = "sha256:be54b7f3fa167bb83e4fcd936b887b708f4e57fe75911c02aebf53efaf8d938e"}, ] [[package]] name = "pytz" -version = "2023.4" +version = "2026.2" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" files = [ - {file = "pytz-2023.4-py2.py3-none-any.whl", hash = "sha256:f90ef520d95e7c46951105338d918664ebfd6f1d995bd7d153127ce90efafa6a"}, - {file = "pytz-2023.4.tar.gz", hash = "sha256:31d4583c4ed539cd037956140d695e42c033a19e984bfce9964a3f7d59bc2b40"}, + {file = "pytz-2026.2-py2.py3-none-any.whl", hash = "sha256:04156e608bee23d3792fd45c94ae47fae1036688e75032eea2e3bf0323d1f126"}, + {file = "pytz-2026.2.tar.gz", hash = "sha256:0e60b47b29f21574376f218fe21abc009894a2321ea16c6754f3cad6eb7cdd6a"}, ] [[package]] name = "pyunormalize" -version = "16.0.0" -description = "Unicode normalization forms (NFC, NFKC, NFD, NFKD). A library independent of the Python core Unicode database." +version = "17.0.0" +description = "A library for Unicode normalization (NFC, NFD, NFKC, NFKD) independent of Python's core Unicode database." optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "pyunormalize-16.0.0-py3-none-any.whl", hash = "sha256:c647d95e5d1e2ea9a2f448d1d95d8518348df24eab5c3fd32d2b5c3300a49152"}, - {file = "pyunormalize-16.0.0.tar.gz", hash = "sha256:2e1dfbb4a118154ae26f70710426a52a364b926c9191f764601f5a8cb12761f7"}, + {file = "pyunormalize-17.0.0-py3-none-any.whl", hash = "sha256:f0d93b076f938db2b26d319d04f2b58505d1cd7a80b5b72badbe7d1aa4d2a31c"}, + {file = "pyunormalize-17.0.0.tar.gz", hash = "sha256:0949a3e56817e287febcaf1b0cc4b5adf0bb107628d379335938040947eec792"}, ] [[package]] name = "pywin32" -version = "308" -description = "Python for Window Extensions" +version = "312" +description = "Python for Windows Extensions" optional = false -python-versions = "*" +python-versions = ">=3.9" files = [ - {file = "pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e"}, - {file = "pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e"}, - {file = "pywin32-308-cp310-cp310-win_arm64.whl", hash = "sha256:a5ab5381813b40f264fa3495b98af850098f814a25a63589a8e9eb12560f450c"}, - {file = "pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a"}, - {file = "pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b"}, - {file = "pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6"}, - {file = "pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897"}, - {file = "pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47"}, - {file = "pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091"}, - {file = "pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed"}, - {file = "pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4"}, - {file = "pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd"}, - {file = "pywin32-308-cp37-cp37m-win32.whl", hash = "sha256:1f696ab352a2ddd63bd07430080dd598e6369152ea13a25ebcdd2f503a38f1ff"}, - {file = "pywin32-308-cp37-cp37m-win_amd64.whl", hash = "sha256:13dcb914ed4347019fbec6697a01a0aec61019c1046c2b905410d197856326a6"}, - {file = "pywin32-308-cp38-cp38-win32.whl", hash = "sha256:5794e764ebcabf4ff08c555b31bd348c9025929371763b2183172ff4708152f0"}, - {file = "pywin32-308-cp38-cp38-win_amd64.whl", hash = "sha256:3b92622e29d651c6b783e368ba7d6722b1634b8e70bd376fd7610fe1992e19de"}, - {file = "pywin32-308-cp39-cp39-win32.whl", hash = "sha256:7873ca4dc60ab3287919881a7d4f88baee4a6e639aa6962de25a98ba6b193341"}, - {file = "pywin32-308-cp39-cp39-win_amd64.whl", hash = "sha256:71b3322d949b4cc20776436a9c9ba0eeedcbc9c650daa536df63f0ff111bb920"}, + {file = "pywin32-312-cp310-cp310-win32.whl", hash = "sha256:772235332b5d1024c696f11cea1ae4be7930f0a8b894bb43db14e3f435f1ff7e"}, + {file = "pywin32-312-cp310-cp310-win_amd64.whl", hash = "sha256:5dbc35d2b5320dc07f25fa31269cfb767471002b17de5eb067d03da68c7cb2db"}, + {file = "pywin32-312-cp310-cp310-win_arm64.whl", hash = "sha256:3020656e34f1cf7faeb7bccd2b84653a607c6ff0c55ada85e6487d61716deabd"}, + {file = "pywin32-312-cp311-cp311-win32.whl", hash = "sha256:17948aeadbdb091f0ced6ef0841620794e68327b94ee415571c1203594b7215c"}, + {file = "pywin32-312-cp311-cp311-win_amd64.whl", hash = "sha256:d11417d84412f859b722fad0841b3614459ed0047f7542d8362e77884f6b6e8a"}, + {file = "pywin32-312-cp311-cp311-win_arm64.whl", hash = "sha256:b2200a054ca6d6625c4842fc56a4976a4b47f96b73dbe5538c3f813a80359f47"}, + {file = "pywin32-312-cp312-cp312-win32.whl", hash = "sha256:dab4f65ac9c4e48400a2a0530c46c3c579cd5905ecd11b80692373915269208b"}, + {file = "pywin32-312-cp312-cp312-win_amd64.whl", hash = "sha256:b457f6d628a47e8a7346ce22acb7e1a46a4a78b52e1d17e1af56871bd19a93bc"}, + {file = "pywin32-312-cp312-cp312-win_arm64.whl", hash = "sha256:6017c58e12f6809fbb0555b75df144c2922a9ffd18e4b9b5afa863b6c1a9d950"}, + {file = "pywin32-312-cp313-cp313-win32.whl", hash = "sha256:7a27df850933d16a8eabfbaeb73d52b273e2da667f80d70b01a89d1f6828d02c"}, + {file = "pywin32-312-cp313-cp313-win_amd64.whl", hash = "sha256:c53e878d15a1c44788082bfe712a905433473aa38f86375b7cf8b45e3acbaaf9"}, + {file = "pywin32-312-cp313-cp313-win_arm64.whl", hash = "sha256:59aba5d5940842075343a5ddc6b11f1cdf0d1567fe745290359dfbcc7c2eb831"}, + {file = "pywin32-312-cp314-cp314-win32.whl", hash = "sha256:a77a90fbb6881238d2ca9c6fd797b25817f3768fe78d214a90137ff055a75f5b"}, + {file = "pywin32-312-cp314-cp314-win_amd64.whl", hash = "sha256:a4dd3a848290ef724347b19f301045831d8e802fa4464f491b98b1e0a081432e"}, + {file = "pywin32-312-cp314-cp314-win_arm64.whl", hash = "sha256:9fce94568364e0155e6dfb781ac5d95903be8baf28670632beab1b523f300daa"}, + {file = "pywin32-312-cp315-cp315-win32.whl", hash = "sha256:5c1fbe4a937a73ae9297384a3da38518cbc694c68ad8a809b2e19acd350f03ed"}, + {file = "pywin32-312-cp315-cp315-win_amd64.whl", hash = "sha256:c2f03a0f73f804a13c2735b99392b0cd426bb4f2c4d0178e5ac966a0f21618d5"}, + {file = "pywin32-312-cp315-cp315-win_arm64.whl", hash = "sha256:a8597d28f267b39074aef51fa593530082b39cbe5a074226096857b1fed2dfb9"}, + {file = "pywin32-312-cp39-cp39-win32.whl", hash = "sha256:d620900033cc7531e50727c3c8333091df5dd3ffe6d68cdca38c03f5821408d5"}, + {file = "pywin32-312-cp39-cp39-win_amd64.whl", hash = "sha256:dc90147579a905b8635e1b0ec6514967dcb07e6e0d9c42f1477feef14cac23bb"}, + {file = "pywin32-312-cp39-cp39-win_arm64.whl", hash = "sha256:02ebca0f0242b75292e218065004310d6a477407c09fa449bfe4f6022bc0c0fc"}, ] [[package]] name = "pyyaml" -version = "6.0.1" +version = "6.0.3" description = "YAML parser and emitter for Python" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, - {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, - {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, - {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, - {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, - {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, - {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, - {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, - {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, - {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, - {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, - {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, - {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, - {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, + {file = "PyYAML-6.0.3-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6"}, + {file = "PyYAML-6.0.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369"}, + {file = "PyYAML-6.0.3-cp38-cp38-win32.whl", hash = "sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295"}, + {file = "PyYAML-6.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b"}, + {file = "pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b"}, + {file = "pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b"}, + {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0"}, + {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69"}, + {file = "pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e"}, + {file = "pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c"}, + {file = "pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e"}, + {file = "pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d"}, + {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a"}, + {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4"}, + {file = "pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b"}, + {file = "pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf"}, + {file = "pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196"}, + {file = "pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc"}, + {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e"}, + {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea"}, + {file = "pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5"}, + {file = "pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b"}, + {file = "pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd"}, + {file = "pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8"}, + {file = "pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6"}, + {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6"}, + {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be"}, + {file = "pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26"}, + {file = "pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c"}, + {file = "pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb"}, + {file = "pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac"}, + {file = "pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5"}, + {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764"}, + {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35"}, + {file = "pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac"}, + {file = "pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3"}, + {file = "pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3"}, + {file = "pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c"}, + {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065"}, + {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65"}, + {file = "pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9"}, + {file = "pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b"}, + {file = "pyyaml-6.0.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da"}, + {file = "pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a"}, + {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926"}, + {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7"}, + {file = "pyyaml-6.0.3-cp39-cp39-win32.whl", hash = "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0"}, + {file = "pyyaml-6.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007"}, + {file = "pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f"}, ] [[package]] @@ -3651,44 +4501,222 @@ files = [ [[package]] name = "requests" -version = "2.31.0" +version = "2.34.2" description = "Python HTTP for Humans." optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" files = [ - {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, - {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, + {file = "requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0"}, + {file = "requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed"}, ] [package.dependencies] -certifi = ">=2017.4.17" -charset-normalizer = ">=2,<4" +certifi = ">=2023.5.7" +charset_normalizer = ">=2,<4" idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<3" +urllib3 = ">=1.26,<3" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<8)"] [[package]] name = "rich" -version = "13.9.3" +version = "15.0.0" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false -python-versions = ">=3.8.0" +python-versions = ">=3.9.0" files = [ - {file = "rich-13.9.3-py3-none-any.whl", hash = "sha256:9836f5096eb2172c9e77df411c1b009bace4193d6a481d534fea75ebba758283"}, - {file = "rich-13.9.3.tar.gz", hash = "sha256:bc1e01b899537598cf02579d2b9f4a415104d3fc439313a7a2c165d76557a08e"}, + {file = "rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb"}, + {file = "rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36"}, ] [package.dependencies] markdown-it-py = ">=2.2.0" pygments = ">=2.13.0,<3.0.0" -typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.11\""} [package.extras] jupyter = ["ipywidgets (>=7.5.1,<9)"] +[[package]] +name = "rich-toolkit" +version = "0.20.3" +description = "Rich toolkit for building command-line applications" +optional = false +python-versions = ">=3.8" +files = [ + {file = "rich_toolkit-0.20.3-py3-none-any.whl", hash = "sha256:419aa87516d5f3849cca553c6dcf707c02a36d508fcf996946606725d34a3002"}, + {file = "rich_toolkit-0.20.3.tar.gz", hash = "sha256:223dd2cfba325ed55e94933b9e53f3aca13e9fdf76622bd564c18109a2273c1b"}, +] + +[package.dependencies] +click = ">=8.1.7" +rich = ">=13.7.1" +typing-extensions = ">=4.12.2" + +[[package]] +name = "rignore" +version = "0.7.6" +description = "Python Bindings for the ignore crate" +optional = false +python-versions = ">=3.8" +files = [ + {file = "rignore-0.7.6-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f3c74a7e5ee77aea669c95fdb3933f2a6c7549893700082e759128a29cf67e45"}, + {file = "rignore-0.7.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b7202404958f5fe3474bac91f65350f0b1dde1a5e05089f2946549b7e91e79ec"}, + {file = "rignore-0.7.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bde7c5835fa3905bfb7e329a4f1d7eccb676de63da7a3f934ddd5c06df20597"}, + {file = "rignore-0.7.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:626c3d4ba03af266694d25101bc1d8d16eda49c5feb86cedfec31c614fceca7d"}, + {file = "rignore-0.7.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a43841e651e7a05a4274b9026cc408d1912e64016ede8cd4c145dae5d0635be"}, + {file = "rignore-0.7.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7978c498dbf7f74d30cdb8859fe612167d8247f0acd377ae85180e34490725da"}, + {file = "rignore-0.7.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d22f72ab695c07d2d96d2a645208daff17084441b5d58c07378c9dd6f9c4c87"}, + {file = "rignore-0.7.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5bd8e1a91ed1a789b2cbe39eeea9204a6719d4f2cf443a9544b521a285a295f"}, + {file = "rignore-0.7.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bc1fc03efad5789365018e94ac4079f851a999bc154d1551c45179f7fcf45322"}, + {file = "rignore-0.7.6-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:ce2617fe28c51367fd8abfd4eeea9e61664af63c17d4ea00353d8ef56dfb95fa"}, + {file = "rignore-0.7.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7c4ad2cee85068408e7819a38243043214e2c3047e9bd4c506f8de01c302709e"}, + {file = "rignore-0.7.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:02cd240bfd59ecc3907766f4839cbba20530a2e470abca09eaa82225e4d946fb"}, + {file = "rignore-0.7.6-cp310-cp310-win32.whl", hash = "sha256:fe2bd8fa1ff555259df54c376abc73855cb02628a474a40d51b358c3a1ddc55b"}, + {file = "rignore-0.7.6-cp310-cp310-win_amd64.whl", hash = "sha256:d80afd6071c78baf3765ec698841071b19e41c326f994cfa69b5a1df676f5d39"}, + {file = "rignore-0.7.6-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:40be8226e12d6653abbebaffaea2885f80374c1c8f76fe5ca9e0cadd120a272c"}, + {file = "rignore-0.7.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:182f4e5e4064d947c756819446a7d4cdede8e756b8c81cf9e509683fe38778d7"}, + {file = "rignore-0.7.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16b63047648a916a87be1e51bb5c009063f1b8b6f5afe4f04f875525507e63dc"}, + {file = "rignore-0.7.6-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ba5524f5178deca4d7695e936604ebc742acb8958f9395776e1fcb8133f8257a"}, + {file = "rignore-0.7.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:62020dbb89a1dd4b84ab3d60547b3b2eb2723641d5fb198463643f71eaaed57d"}, + {file = "rignore-0.7.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b34acd532769d5a6f153a52a98dcb81615c949ab11697ce26b2eb776af2e174d"}, + {file = "rignore-0.7.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c5e53b752f9de44dff7b3be3c98455ce3bf88e69d6dc0cf4f213346c5e3416c"}, + {file = "rignore-0.7.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:25b3536d13a5d6409ce85f23936f044576eeebf7b6db1d078051b288410fc049"}, + {file = "rignore-0.7.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6e01cad2b0b92f6b1993f29fc01f23f2d78caf4bf93b11096d28e9d578eb08ce"}, + {file = "rignore-0.7.6-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:5991e46ab9b4868334c9e372ab0892b0150f3f586ff2b1e314272caeb38aaedb"}, + {file = "rignore-0.7.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6c8ae562e5d1246cba5eaeb92a47b2a279e7637102828dde41dcbe291f529a3e"}, + {file = "rignore-0.7.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:aaf938530dcc0b47c4cfa52807aa2e5bfd5ca6d57a621125fe293098692f6345"}, + {file = "rignore-0.7.6-cp311-cp311-win32.whl", hash = "sha256:166ebce373105dd485ec213a6a2695986346e60c94ff3d84eb532a237b24a4d5"}, + {file = "rignore-0.7.6-cp311-cp311-win_amd64.whl", hash = "sha256:44f35ee844b1a8cea50d056e6a595190ce9d42d3cccf9f19d280ae5f3058973a"}, + {file = "rignore-0.7.6-cp311-cp311-win_arm64.whl", hash = "sha256:14b58f3da4fa3d5c3fa865cab49821675371f5e979281c683e131ae29159a581"}, + {file = "rignore-0.7.6-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:03e82348cb7234f8d9b2834f854400ddbbd04c0f8f35495119e66adbd37827a8"}, + {file = "rignore-0.7.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b9e624f6be6116ea682e76c5feb71ea91255c67c86cb75befe774365b2931961"}, + {file = "rignore-0.7.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bda49950d405aa8d0ebe26af807c4e662dd281d926530f03f29690a2e07d649a"}, + {file = "rignore-0.7.6-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5fd5ab3840b8c16851d327ed06e9b8be6459702a53e5ab1fc4073b684b3789e"}, + {file = "rignore-0.7.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ced2a248352636a5c77504cb755dc02c2eef9a820a44d3f33061ce1bb8a7f2d2"}, + {file = "rignore-0.7.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a04a3b73b75ddc12c9c9b21efcdaab33ca3832941d6f1d67bffd860941cd448a"}, + {file = "rignore-0.7.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d24321efac92140b7ec910ac7c53ab0f0c86a41133d2bb4b0e6a7c94967f44dd"}, + {file = "rignore-0.7.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:73c7aa109d41e593785c55fdaa89ad80b10330affa9f9d3e3a51fa695f739b20"}, + {file = "rignore-0.7.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1734dc49d1e9501b07852ef44421f84d9f378da9fbeda729e77db71f49cac28b"}, + {file = "rignore-0.7.6-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5719ea14ea2b652c0c0894be5dfde954e1853a80dea27dd2fbaa749618d837f5"}, + {file = "rignore-0.7.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8e23424fc7ce35726854f639cb7968151a792c0c3d9d082f7f67e0c362cfecca"}, + {file = "rignore-0.7.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3efdcf1dd84d45f3e2bd2f93303d9be103888f56dfa7c3349b5bf4f0657ec696"}, + {file = "rignore-0.7.6-cp312-cp312-win32.whl", hash = "sha256:ccca9d1a8b5234c76b71546fc3c134533b013f40495f394a65614a81f7387046"}, + {file = "rignore-0.7.6-cp312-cp312-win_amd64.whl", hash = "sha256:c96a285e4a8bfec0652e0bfcf42b1aabcdda1e7625f5006d188e3b1c87fdb543"}, + {file = "rignore-0.7.6-cp312-cp312-win_arm64.whl", hash = "sha256:a64a750e7a8277a323f01ca50b7784a764845f6cce2fe38831cb93f0508d0051"}, + {file = "rignore-0.7.6-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:2bdab1d31ec9b4fb1331980ee49ea051c0d7f7bb6baa28b3125ef03cdc48fdaf"}, + {file = "rignore-0.7.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:90f0a00ce0c866c275bf888271f1dc0d2140f29b82fcf33cdbda1e1a6af01010"}, + {file = "rignore-0.7.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1ad295537041dc2ed4b540fb1a3906bd9ede6ccdad3fe79770cd89e04e3c73c"}, + {file = "rignore-0.7.6-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f782dbd3a65a5ac85adfff69e5c6b101285ef3f845c3a3cae56a54bebf9fe116"}, + {file = "rignore-0.7.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65cece3b36e5b0826d946494734c0e6aaf5a0337e18ff55b071438efe13d559e"}, + {file = "rignore-0.7.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7e4bb66c13cd7602dc8931822c02dfbbd5252015c750ac5d6152b186f0a8be0"}, + {file = "rignore-0.7.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:297e500c15766e196f68aaaa70e8b6db85fa23fdc075b880d8231fdfba738cd7"}, + {file = "rignore-0.7.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a07084211a8d35e1a5b1d32b9661a5ed20669970b369df0cf77da3adea3405de"}, + {file = "rignore-0.7.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:181eb2a975a22256a1441a9d2f15eb1292839ea3f05606620bd9e1938302cf79"}, + {file = "rignore-0.7.6-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:7bbcdc52b5bf9f054b34ce4af5269df5d863d9c2456243338bc193c28022bd7b"}, + {file = "rignore-0.7.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f2e027a6da21a7c8c0d87553c24ca5cc4364def18d146057862c23a96546238e"}, + {file = "rignore-0.7.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ee4a18b82cbbc648e4aac1510066682fe62beb5dc88e2c67c53a83954e541360"}, + {file = "rignore-0.7.6-cp313-cp313-win32.whl", hash = "sha256:a7d7148b6e5e95035d4390396895adc384d37ff4e06781a36fe573bba7c283e5"}, + {file = "rignore-0.7.6-cp313-cp313-win_amd64.whl", hash = "sha256:b037c4b15a64dced08fc12310ee844ec2284c4c5c1ca77bc37d0a04f7bff386e"}, + {file = "rignore-0.7.6-cp313-cp313-win_arm64.whl", hash = "sha256:e47443de9b12fe569889bdbe020abe0e0b667516ee2ab435443f6d0869bd2804"}, + {file = "rignore-0.7.6-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:8e41be9fa8f2f47239ded8920cc283699a052ac4c371f77f5ac017ebeed75732"}, + {file = "rignore-0.7.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6dc1e171e52cefa6c20e60c05394a71165663b48bca6c7666dee4f778f2a7d90"}, + {file = "rignore-0.7.6-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ce2268837c3600f82ab8db58f5834009dc638ee17103582960da668963bebc5"}, + {file = "rignore-0.7.6-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:690a3e1b54bfe77e89c4bacb13f046e642f8baadafc61d68f5a726f324a76ab6"}, + {file = "rignore-0.7.6-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09d12ac7a0b6210c07bcd145007117ebd8abe99c8eeb383e9e4673910c2754b2"}, + {file = "rignore-0.7.6-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a2b2b74a8c60203b08452479b90e5ce3dbe96a916214bc9eb2e5af0b6a9beb0"}, + {file = "rignore-0.7.6-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fc5a531ef02131e44359419a366bfac57f773ea58f5278c2cdd915f7d10ea94"}, + {file = "rignore-0.7.6-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b7a1f77d9c4cd7e76229e252614d963442686bfe12c787a49f4fe481df49e7a9"}, + {file = "rignore-0.7.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ead81f728682ba72b5b1c3d5846b011d3e0174da978de87c61645f2ed36659a7"}, + {file = "rignore-0.7.6-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:12ffd50f520c22ffdabed8cd8bfb567d9ac165b2b854d3e679f4bcaef11a9441"}, + {file = "rignore-0.7.6-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:e5a16890fbe3c894f8ca34b0fcacc2c200398d4d46ae654e03bc9b3dbf2a0a72"}, + {file = "rignore-0.7.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3abab3bf99e8a77488ef6c7c9a799fac22224c28fe9f25cc21aa7cc2b72bfc0b"}, + {file = "rignore-0.7.6-cp314-cp314-win32.whl", hash = "sha256:eeef421c1782953c4375aa32f06ecae470c1285c6381eee2a30d2e02a5633001"}, + {file = "rignore-0.7.6-cp314-cp314-win_amd64.whl", hash = "sha256:6aeed503b3b3d5af939b21d72a82521701a4bd3b89cd761da1e7dc78621af304"}, + {file = "rignore-0.7.6-cp314-cp314-win_arm64.whl", hash = "sha256:104f215b60b3c984c386c3e747d6ab4376d5656478694e22c7bd2f788ddd8304"}, + {file = "rignore-0.7.6-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:bb24a5b947656dd94cb9e41c4bc8b23cec0c435b58be0d74a874f63c259549e8"}, + {file = "rignore-0.7.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5b1e33c9501cefe24b70a1eafd9821acfd0ebf0b35c3a379430a14df089993e3"}, + {file = "rignore-0.7.6-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bec3994665a44454df86deb762061e05cd4b61e3772f5b07d1882a8a0d2748d5"}, + {file = "rignore-0.7.6-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26cba2edfe3cff1dfa72bddf65d316ddebf182f011f2f61538705d6dbaf54986"}, + {file = "rignore-0.7.6-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ffa86694fec604c613696cb91e43892aa22e1fec5f9870e48f111c603e5ec4e9"}, + {file = "rignore-0.7.6-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48efe2ed95aa8104145004afb15cdfa02bea5cdde8b0344afeb0434f0d989aa2"}, + {file = "rignore-0.7.6-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dcae43eb44b7f2457fef7cc87f103f9a0013017a6f4e62182c565e924948f21"}, + {file = "rignore-0.7.6-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2cd649a7091c0dad2f11ef65630d30c698d505cbe8660dd395268e7c099cc99f"}, + {file = "rignore-0.7.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42de84b0289d478d30ceb7ae59023f7b0527786a9a5b490830e080f0e4ea5aeb"}, + {file = "rignore-0.7.6-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:875a617e57b53b4acbc5a91de418233849711c02e29cc1f4f9febb2f928af013"}, + {file = "rignore-0.7.6-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:8703998902771e96e49968105207719f22926e4431b108450f3f430b4e268b7c"}, + {file = "rignore-0.7.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:602ef33f3e1b04c1e9a10a3c03f8bc3cef2d2383dcc250d309be42b49923cabc"}, + {file = "rignore-0.7.6-cp314-cp314t-win32.whl", hash = "sha256:c1d8f117f7da0a4a96a8daef3da75bc090e3792d30b8b12cfadc240c631353f9"}, + {file = "rignore-0.7.6-cp314-cp314t-win_amd64.whl", hash = "sha256:ca36e59408bec81de75d307c568c2d0d410fb880b1769be43611472c61e85c96"}, + {file = "rignore-0.7.6-cp314-cp314t-win_arm64.whl", hash = "sha256:b83adabeb3e8cf662cabe1931b83e165b88c526fa6af6b3aa90429686e474896"}, + {file = "rignore-0.7.6-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:1bd0bf3f4e57f3d50a91dd4eff6a22ddc9b999dbab2b20fb0473332a5551a0be"}, + {file = "rignore-0.7.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:afb5157cd217af4f47a13ad7cbfc35de0aa1740331ba662fa02fea94269d5894"}, + {file = "rignore-0.7.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca877c5a7b78fe74d97b34b735ea8f320f97c49083f7bf8fe9b61a02cf677e67"}, + {file = "rignore-0.7.6-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5fde2bdfd6b3afee19db5efe01e4165437329f9300441c1b25d5b2aa6752c0cc"}, + {file = "rignore-0.7.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ef2183285a49653517a100f28d8c1a3e037a5e8cefe79cffe205ecc4b98f5095"}, + {file = "rignore-0.7.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87554ae12f813d3a287a0f2aad957c11e5c4ace17bfed15d471e5be13e95d9fb"}, + {file = "rignore-0.7.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3111040f77ec6b543a501a194c48d5260898e618712472deb91bf48026f1606c"}, + {file = "rignore-0.7.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8dfa178ead3abeeaf6b8c4fe9c6c9b333d2d66c88735566f919169d18e728fa5"}, + {file = "rignore-0.7.6-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:112527b824eaa93c99c2c7eb11e7df83eab46a63d527bcd71a92151bba5d0435"}, + {file = "rignore-0.7.6-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:435c0c0f38f15d9bef2a97b039b5157bbc32791510670b89504e644de1d27a5e"}, + {file = "rignore-0.7.6-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:96e899cd34b422c2d3ad7bef279e16387f217d53ec5f9a25dbc3fcad19470381"}, + {file = "rignore-0.7.6-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:2ba1b9c80df4ea126ef303c7646021f44486342d43b7153f3454e15cd55eaa87"}, + {file = "rignore-0.7.6-cp38-cp38-win32.whl", hash = "sha256:1a1dffbfd930b27aef1962098710344297d52368b362f918eaf1464b0d8d052c"}, + {file = "rignore-0.7.6-cp38-cp38-win_amd64.whl", hash = "sha256:7f41cecc799005a029407893071b15082d504f9115a57db9ea893b35f3f70604"}, + {file = "rignore-0.7.6-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b3746bda73f2fe6a9c3ab2f20b792e7d810b30acbdba044313fbd2d0174802e7"}, + {file = "rignore-0.7.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:67a99cf19a5137cc12f14b78dc1bb3f48500f1d5580702c623297d5297bf2752"}, + {file = "rignore-0.7.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9e851cfa87033c0c3fd9d35dd8b102aff2981db8bc6e0cab27b460bfe38bf3f"}, + {file = "rignore-0.7.6-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e9b0def154665036516114437a5d603274e5451c0dc9694f622cc3b7e94603e7"}, + {file = "rignore-0.7.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b81274a47e8121224f7f637392b5dfcd9558e32a53e67ba7d04007d8b5281da9"}, + {file = "rignore-0.7.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d75d0b0696fb476664bea1169c8e67b13197750b91eceb4f10b3c7f379c7a204"}, + {file = "rignore-0.7.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ad3aa4dca77cef9168d0c142f72376f5bd27d1d4b8a81561bd01276d3ad9fe1"}, + {file = "rignore-0.7.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00f8a59e19d219f44a93af7173de197e0d0e61c386364da20ebe98a303cbe38c"}, + {file = "rignore-0.7.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dd6c682f3cdd741e7a30af2581f6a382ac910080977cd1f97c651467b6268352"}, + {file = "rignore-0.7.6-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:ae4e93193f75ebf6b820241594a78f347785cfd5a5fbbac94634052589418352"}, + {file = "rignore-0.7.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1163d8b5d3a320d4d7cc8635213328850dc41f60e438c7869d540061adf66c98"}, + {file = "rignore-0.7.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3e685f47b4c58b2df7dee81ebc1ec9dbb7f798b9455c3f22be6d75ac6bddee30"}, + {file = "rignore-0.7.6-cp39-cp39-win32.whl", hash = "sha256:2af6a0a76575220863cd838693c808a94e750640e0c8a3e9f707e93c2f131fdf"}, + {file = "rignore-0.7.6-cp39-cp39-win_amd64.whl", hash = "sha256:a326eab6db9ab85b4afb5e6eb28736a9f2b885a9246d9e8c1989bc693dd059a0"}, + {file = "rignore-0.7.6-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c3d3a523af1cd4ed2c0cba8d277a32d329b0c96ef9901fb7ca45c8cfaccf31a5"}, + {file = "rignore-0.7.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:990853566e65184a506e1e2af2d15045afad3ebaebb8859cb85b882081915110"}, + {file = "rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cab9ff2e436ce7240d7ee301c8ef806ed77c1fd6b8a8239ff65f9bbbcb5b8a3"}, + {file = "rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d1a6671b2082c13bfd9a5cf4ce64670f832a6d41470556112c4ab0b6519b2fc4"}, + {file = "rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2468729b4c5295c199d084ab88a40afcb7c8b974276805105239c07855bbacee"}, + {file = "rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:775710777fd71e5fdf54df69cdc249996a1d6f447a2b5bfb86dbf033fddd9cf9"}, + {file = "rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4565407f4a77f72cf9d91469e75d15d375f755f0a01236bb8aaa176278cc7085"}, + {file = "rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc44c33f8fb2d5c9da748de7a6e6653a78aa740655e7409895e94a247ffa97c8"}, + {file = "rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:8f32478f05540513c11923e8838afab9efef0131d66dca7f67f0e1bbd118af6a"}, + {file = "rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:1b63a3dd76225ea35b01dd6596aa90b275b5d0f71d6dc28fce6dd295d98614aa"}, + {file = "rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fe6c41175c36554a4ef0994cd1b4dbd6d73156fca779066456b781707402048e"}, + {file = "rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9a0c6792406ae36f4e7664dc772da909451d46432ff8485774526232d4885063"}, + {file = "rignore-0.7.6-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a20b6fb61bcced9a83dfcca6599ad45182b06ba720cff7c8d891e5b78db5b65f"}, + {file = "rignore-0.7.6-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:392dcabfecbe176c9ebbcb40d85a5e86a5989559c4f988c2741da7daf1b5be25"}, + {file = "rignore-0.7.6-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22baa462abdc36fdd5a5e2dae423107723351b85ff093762f9261148b9d0a04a"}, + {file = "rignore-0.7.6-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53fb28882d2538cb2d231972146c4927a9d9455e62b209f85d634408c4103538"}, + {file = "rignore-0.7.6-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:87409f7eeb1103d6b77f3472a3a0d9a5953e3ae804a55080bdcb0120ee43995b"}, + {file = "rignore-0.7.6-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:684014e42e4341ab3ea23a203551857fcc03a7f8ae96ca3aefb824663f55db32"}, + {file = "rignore-0.7.6-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77356ebb01ba13f8a425c3d30fcad40e57719c0e37670d022d560884a30e4767"}, + {file = "rignore-0.7.6-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6cbd8a48abbd3747a6c830393cd578782fab5d43f4deea48c5f5e344b8fed2b0"}, + {file = "rignore-0.7.6-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2673225dcec7f90497e79438c35e34638d0d0391ccea3cbb79bfb9adc0dc5bd7"}, + {file = "rignore-0.7.6-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:c081f17290d8a2b96052b79207622aa635686ea39d502b976836384ede3d303c"}, + {file = "rignore-0.7.6-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:57e8327aacc27f921968cb2a174f9e47b084ce9a7dd0122c8132d22358f6bd79"}, + {file = "rignore-0.7.6-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:d8955b57e42f2a5434670d5aa7b75eaf6e74602ccd8955dddf7045379cd762fb"}, + {file = "rignore-0.7.6-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e6ba1511c0ab8cd1ed8d6055bb0a6e629f48bfe04854293e0cd2dd88bd7153f8"}, + {file = "rignore-0.7.6-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:50586d90be15f9aa8a2e2ee5a042ee6c51e28848812a35f0c95d4bfc0533d469"}, + {file = "rignore-0.7.6-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b129873dd0ade248e67f25a09b5b72288cbef76ba1a9aae6bac193ee1d8be72"}, + {file = "rignore-0.7.6-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d9d6dd947556ddebfd62753005104986ee14a4e0663818aed19cdf2c33a6b5d5"}, + {file = "rignore-0.7.6-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91b95faa532efba888b196331e9af69e693635d469185ac52c796e435e2484e5"}, + {file = "rignore-0.7.6-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a1016f430fb56f7e400838bbc56fdf43adddb6fcb7bf2a14731dfd725c2fae6c"}, + {file = "rignore-0.7.6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f00c519861926dc703ecbb7bbeb884be67099f96f98b175671fa0a54718f55d1"}, + {file = "rignore-0.7.6-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e34d172bf50e881b7c02e530ae8b1ea96093f0b16634c344f637227b39707b41"}, + {file = "rignore-0.7.6-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:101d3143619898db1e7bede2e3e647daf19bb867c4fb25978016d67978d14868"}, + {file = "rignore-0.7.6-pp39-pypy39_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:c9f3b420f54199a2b2b3b532d8c7e0860be3fa51f67501113cca6c7bfc392840"}, + {file = "rignore-0.7.6-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:1c6795e3694d750ae5ef172eab7d68a52aefbd9168d2e06647df691db2b03a50"}, + {file = "rignore-0.7.6-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:750a83a254b020e1193bfa7219dc7edca26bd8888a94cdc59720cbe386ab0c72"}, + {file = "rignore-0.7.6.tar.gz", hash = "sha256:00d3546cd793c30cb17921ce674d2c8f3a4b00501cb0e3dd0e82217dbeba2671"}, +] + [[package]] name = "rlp" version = "4.1.0" @@ -3709,198 +4737,192 @@ docs = ["sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme rust-backend = ["rusty-rlp (>=0.2.1)"] test = ["hypothesis (>=6.22.0,<6.108.7)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] -[[package]] -name = "rsa" -version = "4.9" -description = "Pure-Python RSA implementation" -optional = false -python-versions = ">=3.6,<4" -files = [ - {file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"}, - {file = "rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"}, -] - -[package.dependencies] -pyasn1 = ">=0.1.3" - [[package]] name = "ruamel-yaml" -version = "0.18.5" +version = "0.19.1" description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "ruamel.yaml-0.18.5-py3-none-any.whl", hash = "sha256:a013ac02f99a69cdd6277d9664689eb1acba07069f912823177c5eced21a6ada"}, - {file = "ruamel.yaml-0.18.5.tar.gz", hash = "sha256:61917e3a35a569c1133a8f772e1226961bf5a1198bea7e23f06a0841dea1ab0e"}, + {file = "ruamel_yaml-0.19.1-py3-none-any.whl", hash = "sha256:27592957fedf6e0b62f281e96effd28043345e0e66001f97683aa9a40c667c93"}, + {file = "ruamel_yaml-0.19.1.tar.gz", hash = "sha256:53eb66cd27849eff968ebf8f0bf61f46cdac2da1d1f3576dd4ccee9b25c31993"}, ] -[package.dependencies] -"ruamel.yaml.clib" = {version = ">=0.2.7", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.13\""} - [package.extras] docs = ["mercurial (>5.7)", "ryd"] jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] - -[[package]] -name = "ruamel-yaml-clib" -version = "0.2.8" -description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" -optional = false -python-versions = ">=3.6" -files = [ - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win_amd64.whl", hash = "sha256:1758ce7d8e1a29d23de54a16ae867abd370f01b5a69e1a3ba75223eaa3ca1a1b"}, - {file = "ruamel.yaml.clib-0.2.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:77159f5d5b5c14f7c34073862a6b7d34944075d9f93e681638f6d753606c6ce6"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win32.whl", hash = "sha256:75e1ed13e1f9de23c5607fe6bd1aeaae21e523b32d83bb33918245361e9cc51b"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win_amd64.whl", hash = "sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win32.whl", hash = "sha256:955eae71ac26c1ab35924203fda6220f84dce57d6d7884f189743e2abe3a9fbe"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win_amd64.whl", hash = "sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win32.whl", hash = "sha256:84b554931e932c46f94ab306913ad7e11bba988104c5cff26d90d03f68258cd5"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win_amd64.whl", hash = "sha256:25ac8c08322002b06fa1d49d1646181f0b2c72f5cbc15a85e80b4c30a544bb15"}, - {file = "ruamel.yaml.clib-0.2.8.tar.gz", hash = "sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512"}, -] +libyaml = ["ruamel.yaml.clibz (>=0.3.7)"] +oldlibyaml = ["ruamel.yaml.clib"] [[package]] name = "ruff" -version = "0.6.1" +version = "0.15.22" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.6.1-py3-none-linux_armv6l.whl", hash = "sha256:b4bb7de6a24169dc023f992718a9417380301b0c2da0fe85919f47264fb8add9"}, - {file = "ruff-0.6.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:45efaae53b360c81043e311cdec8a7696420b3d3e8935202c2846e7a97d4edae"}, - {file = "ruff-0.6.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:bc60c7d71b732c8fa73cf995efc0c836a2fd8b9810e115be8babb24ae87e0850"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c7477c3b9da822e2db0b4e0b59e61b8a23e87886e727b327e7dcaf06213c5cf"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a0af7ab3f86e3dc9f157a928e08e26c4b40707d0612b01cd577cc84b8905cc9"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:392688dbb50fecf1bf7126731c90c11a9df1c3a4cdc3f481b53e851da5634fa5"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5278d3e095ccc8c30430bcc9bc550f778790acc211865520f3041910a28d0024"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fe6d5f65d6f276ee7a0fc50a0cecaccb362d30ef98a110f99cac1c7872df2f18"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2e0dd11e2ae553ee5c92a81731d88a9883af8db7408db47fc81887c1f8b672e"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d812615525a34ecfc07fd93f906ef5b93656be01dfae9a819e31caa6cfe758a1"}, - {file = "ruff-0.6.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:faaa4060f4064c3b7aaaa27328080c932fa142786f8142aff095b42b6a2eb631"}, - {file = "ruff-0.6.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:99d7ae0df47c62729d58765c593ea54c2546d5de213f2af2a19442d50a10cec9"}, - {file = "ruff-0.6.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9eb18dfd7b613eec000e3738b3f0e4398bf0153cb80bfa3e351b3c1c2f6d7b15"}, - {file = "ruff-0.6.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:c62bc04c6723a81e25e71715aa59489f15034d69bf641df88cb38bdc32fd1dbb"}, - {file = "ruff-0.6.1-py3-none-win32.whl", hash = "sha256:9fb4c4e8b83f19c9477a8745e56d2eeef07a7ff50b68a6998f7d9e2e3887bdc4"}, - {file = "ruff-0.6.1-py3-none-win_amd64.whl", hash = "sha256:c2ebfc8f51ef4aca05dad4552bbcf6fe8d1f75b2f6af546cc47cc1c1ca916b5b"}, - {file = "ruff-0.6.1-py3-none-win_arm64.whl", hash = "sha256:3bc81074971b0ffad1bd0c52284b22411f02a11a012082a76ac6da153536e014"}, - {file = "ruff-0.6.1.tar.gz", hash = "sha256:af3ffd8c6563acb8848d33cd19a69b9bfe943667f0419ca083f8ebe4224a3436"}, + {file = "ruff-0.15.22-py3-none-linux_armv6l.whl", hash = "sha256:44423e73493737f5e7c5b41d475483898ff37afcdae38bc3da5085e29af1c2d8"}, + {file = "ruff-0.15.22-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b82c6482946e9eda7ff2e091d25b8bad3f718684e1916d41bd56873cee05b697"}, + {file = "ruff-0.15.22-py3-none-macosx_11_0_arm64.whl", hash = "sha256:11c1c715af53a09f714e011106bffc419751ec8232fcb5da42173284ea3fec6f"}, + {file = "ruff-0.15.22-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:742a29cf29bddb7c8327895d6a10e0e6c5b38a96dd407af9b5d0857f809c0576"}, + {file = "ruff-0.15.22-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72af58b951b0ae395935ae79763dc349bc0eb706319d28f7a33ad2cfb3cfc178"}, + {file = "ruff-0.15.22-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62d425005c1835eb24e2ee4161cb90e8db263415f4a71c8c72c33abaa6c0c224"}, + {file = "ruff-0.15.22-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8b9b3f8779a4f08c969defc3c8c35abffaa757e601ed5ae66d6d1db6519969a"}, + {file = "ruff-0.15.22-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e0dd1b2e4d3d585f897a0d137cbf4eaf6223bef4e8ce34d6bb12556c5f9249e"}, + {file = "ruff-0.15.22-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:365523eb91d9224e1bcb03b022fbf0facb8f9e23792a2c53d9d4b3924bdbdebb"}, + {file = "ruff-0.15.22-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:fabfd168afdf29fee5be98b831efa9683c94d7c5a3b58b9ce5a2e38444589a74"}, + {file = "ruff-0.15.22-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:225dbf095a87f1d9f90f5fd7924d2613ee452a75a4308c63a8f50f761787aa7c"}, + {file = "ruff-0.15.22-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1877d63b9d24ed278744f1523fd11b85540566d54641f97c566d7d9dc5ca5296"}, + {file = "ruff-0.15.22-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a1606c510bd7215680d32efab38965f7cdec3ef69f5170a3f4791404ffdd5262"}, + {file = "ruff-0.15.22-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:630479b18625f5ffc373f77603a22a9f8ac0acd7ff0501178b5db28ec71e9c64"}, + {file = "ruff-0.15.22-py3-none-win32.whl", hash = "sha256:e5ba0e4a13fd14abbed2a77b517a3911290c6c6c59ef67784328d1668fab76cf"}, + {file = "ruff-0.15.22-py3-none-win_amd64.whl", hash = "sha256:9be63ba1eb936acd2d1342fb8337c356353706fce233b2a15a09a97037e6acde"}, + {file = "ruff-0.15.22-py3-none-win_arm64.whl", hash = "sha256:e1168075b72158510839f250027659cdd78476f40507dd517892304c41318661"}, + {file = "ruff-0.15.22.tar.gz", hash = "sha256:3f15175b1fb580126f58285a5dae6b2ea89000136d980c64499211f116b54809"}, ] [[package]] name = "s3transfer" -version = "0.10.0" +version = "0.19.1" description = "An Amazon S3 Transfer Manager" optional = false -python-versions = ">= 3.8" +python-versions = ">=3.10" files = [ - {file = "s3transfer-0.10.0-py3-none-any.whl", hash = "sha256:3cdb40f5cfa6966e812209d0994f2a4709b561c88e90cf00c2696d2df4e56b2e"}, - {file = "s3transfer-0.10.0.tar.gz", hash = "sha256:d0c8bbf672d5eebbe4e57945e23b972d963f07d82f661cabf678a5c88831595b"}, + {file = "s3transfer-0.19.1-py3-none-any.whl", hash = "sha256:d5fd7005ee39307455ad5f310b5ea67f4b1960d7fed5b3671ee50c249de675de"}, + {file = "s3transfer-0.19.1.tar.gz", hash = "sha256:d3d6371dc3f1e5c5427b2b457bcf13bcf87bec334c95aed18642eae61f6926f3"}, ] [package.dependencies] -botocore = ">=1.33.2,<2.0a.0" +botocore = ">=1.37.4,<2.0a.0" [package.extras] -crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"] +crt = ["botocore[crt] (>=1.37.4,<2.0a.0)"] [[package]] name = "scipy" -version = "1.12.0" +version = "1.15.3" description = "Fundamental algorithms for scientific computing in Python" optional = false -python-versions = ">=3.9" -files = [ - {file = "scipy-1.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:78e4402e140879387187f7f25d91cc592b3501a2e51dfb320f48dfb73565f10b"}, - {file = "scipy-1.12.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:f5f00ebaf8de24d14b8449981a2842d404152774c1a1d880c901bf454cb8e2a1"}, - {file = "scipy-1.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e53958531a7c695ff66c2e7bb7b79560ffdc562e2051644c5576c39ff8efb563"}, - {file = "scipy-1.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e32847e08da8d895ce09d108a494d9eb78974cf6de23063f93306a3e419960c"}, - {file = "scipy-1.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4c1020cad92772bf44b8e4cdabc1df5d87376cb219742549ef69fc9fd86282dd"}, - {file = "scipy-1.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:75ea2a144096b5e39402e2ff53a36fecfd3b960d786b7efd3c180e29c39e53f2"}, - {file = "scipy-1.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:408c68423f9de16cb9e602528be4ce0d6312b05001f3de61fe9ec8b1263cad08"}, - {file = "scipy-1.12.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:5adfad5dbf0163397beb4aca679187d24aec085343755fcdbdeb32b3679f254c"}, - {file = "scipy-1.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3003652496f6e7c387b1cf63f4bb720951cfa18907e998ea551e6de51a04467"}, - {file = "scipy-1.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b8066bce124ee5531d12a74b617d9ac0ea59245246410e19bca549656d9a40a"}, - {file = "scipy-1.12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8bee4993817e204d761dba10dbab0774ba5a8612e57e81319ea04d84945375ba"}, - {file = "scipy-1.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:a24024d45ce9a675c1fb8494e8e5244efea1c7a09c60beb1eeb80373d0fecc70"}, - {file = "scipy-1.12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e7e76cc48638228212c747ada851ef355c2bb5e7f939e10952bc504c11f4e372"}, - {file = "scipy-1.12.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:f7ce148dffcd64ade37b2df9315541f9adad6efcaa86866ee7dd5db0c8f041c3"}, - {file = "scipy-1.12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c39f92041f490422924dfdb782527a4abddf4707616e07b021de33467f917bc"}, - {file = "scipy-1.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7ebda398f86e56178c2fa94cad15bf457a218a54a35c2a7b4490b9f9cb2676c"}, - {file = "scipy-1.12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:95e5c750d55cf518c398a8240571b0e0782c2d5a703250872f36eaf737751338"}, - {file = "scipy-1.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:e646d8571804a304e1da01040d21577685ce8e2db08ac58e543eaca063453e1c"}, - {file = "scipy-1.12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:913d6e7956c3a671de3b05ccb66b11bc293f56bfdef040583a7221d9e22a2e35"}, - {file = "scipy-1.12.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba1b0c7256ad75401c73e4b3cf09d1f176e9bd4248f0d3112170fb2ec4db067"}, - {file = "scipy-1.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:730badef9b827b368f351eacae2e82da414e13cf8bd5051b4bdfd720271a5371"}, - {file = "scipy-1.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6546dc2c11a9df6926afcbdd8a3edec28566e4e785b915e849348c6dd9f3f490"}, - {file = "scipy-1.12.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:196ebad3a4882081f62a5bf4aeb7326aa34b110e533aab23e4374fcccb0890dc"}, - {file = "scipy-1.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:b360f1b6b2f742781299514e99ff560d1fe9bd1bff2712894b52abe528d1fd1e"}, - {file = "scipy-1.12.0.tar.gz", hash = "sha256:4bf5abab8a36d20193c698b0f1fc282c1d083c94723902c447e5d2f1780936a3"}, +python-versions = ">=3.10" +files = [ + {file = "scipy-1.15.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a345928c86d535060c9c2b25e71e87c39ab2f22fc96e9636bd74d1dbf9de448c"}, + {file = "scipy-1.15.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ad3432cb0f9ed87477a8d97f03b763fd1d57709f1bbde3c9369b1dff5503b253"}, + {file = "scipy-1.15.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:aef683a9ae6eb00728a542b796f52a5477b78252edede72b8327a886ab63293f"}, + {file = "scipy-1.15.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:1c832e1bd78dea67d5c16f786681b28dd695a8cb1fb90af2e27580d3d0967e92"}, + {file = "scipy-1.15.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:263961f658ce2165bbd7b99fa5135195c3a12d9bef045345016b8b50c315cb82"}, + {file = "scipy-1.15.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2abc762b0811e09a0d3258abee2d98e0c703eee49464ce0069590846f31d40"}, + {file = "scipy-1.15.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ed7284b21a7a0c8f1b6e5977ac05396c0d008b89e05498c8b7e8f4a1423bba0e"}, + {file = "scipy-1.15.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5380741e53df2c566f4d234b100a484b420af85deb39ea35a1cc1be84ff53a5c"}, + {file = "scipy-1.15.3-cp310-cp310-win_amd64.whl", hash = "sha256:9d61e97b186a57350f6d6fd72640f9e99d5a4a2b8fbf4b9ee9a841eab327dc13"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:993439ce220d25e3696d1b23b233dd010169b62f6456488567e830654ee37a6b"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:34716e281f181a02341ddeaad584205bd2fd3c242063bd3423d61ac259ca7eba"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3b0334816afb8b91dab859281b1b9786934392aa3d527cd847e41bb6f45bee65"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:6db907c7368e3092e24919b5e31c76998b0ce1684d51a90943cb0ed1b4ffd6c1"}, + {file = "scipy-1.15.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:721d6b4ef5dc82ca8968c25b111e307083d7ca9091bc38163fb89243e85e3889"}, + {file = "scipy-1.15.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39cb9c62e471b1bb3750066ecc3a3f3052b37751c7c3dfd0fd7e48900ed52982"}, + {file = "scipy-1.15.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:795c46999bae845966368a3c013e0e00947932d68e235702b5c3f6ea799aa8c9"}, + {file = "scipy-1.15.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:18aaacb735ab38b38db42cb01f6b92a2d0d4b6aabefeb07f02849e47f8fb3594"}, + {file = "scipy-1.15.3-cp311-cp311-win_amd64.whl", hash = "sha256:ae48a786a28412d744c62fd7816a4118ef97e5be0bee968ce8f0a2fba7acf3bb"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6ac6310fdbfb7aa6612408bd2f07295bcbd3fda00d2d702178434751fe48e019"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:185cd3d6d05ca4b44a8f1595af87f9c372bb6acf9c808e99aa3e9aa03bd98cf6"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:05dc6abcd105e1a29f95eada46d4a3f251743cfd7d3ae8ddb4088047f24ea477"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:06efcba926324df1696931a57a176c80848ccd67ce6ad020c810736bfd58eb1c"}, + {file = "scipy-1.15.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05045d8b9bfd807ee1b9f38761993297b10b245f012b11b13b91ba8945f7e45"}, + {file = "scipy-1.15.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271e3713e645149ea5ea3e97b57fdab61ce61333f97cfae392c28ba786f9bb49"}, + {file = "scipy-1.15.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6cfd56fc1a8e53f6e89ba3a7a7251f7396412d655bca2aa5611c8ec9a6784a1e"}, + {file = "scipy-1.15.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ff17c0bb1cb32952c09217d8d1eed9b53d1463e5f1dd6052c7857f83127d539"}, + {file = "scipy-1.15.3-cp312-cp312-win_amd64.whl", hash = "sha256:52092bc0472cfd17df49ff17e70624345efece4e1a12b23783a1ac59a1b728ed"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c620736bcc334782e24d173c0fdbb7590a0a436d2fdf39310a8902505008759"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:7e11270a000969409d37ed399585ee530b9ef6aa99d50c019de4cb01e8e54e62"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8c9ed3ba2c8a2ce098163a9bdb26f891746d02136995df25227a20e71c396ebb"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0bdd905264c0c9cfa74a4772cdb2070171790381a5c4d312c973382fc6eaf730"}, + {file = "scipy-1.15.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79167bba085c31f38603e11a267d862957cbb3ce018d8b38f79ac043bc92d825"}, + {file = "scipy-1.15.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9deabd6d547aee2c9a81dee6cc96c6d7e9a9b1953f74850c179f91fdc729cb7"}, + {file = "scipy-1.15.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dde4fc32993071ac0c7dd2d82569e544f0bdaff66269cb475e0f369adad13f11"}, + {file = "scipy-1.15.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f77f853d584e72e874d87357ad70f44b437331507d1c311457bed8ed2b956126"}, + {file = "scipy-1.15.3-cp313-cp313-win_amd64.whl", hash = "sha256:b90ab29d0c37ec9bf55424c064312930ca5f4bde15ee8619ee44e69319aab163"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3ac07623267feb3ae308487c260ac684b32ea35fd81e12845039952f558047b8"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6487aa99c2a3d509a5227d9a5e889ff05830a06b2ce08ec30df6d79db5fcd5c5"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:50f9e62461c95d933d5c5ef4a1f2ebf9a2b4e83b0db374cb3f1de104d935922e"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:14ed70039d182f411ffc74789a16df3835e05dc469b898233a245cdfd7f162cb"}, + {file = "scipy-1.15.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a769105537aa07a69468a0eefcd121be52006db61cdd8cac8a0e68980bbb723"}, + {file = "scipy-1.15.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db984639887e3dffb3928d118145ffe40eff2fa40cb241a306ec57c219ebbbb"}, + {file = "scipy-1.15.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:40e54d5c7e7ebf1aa596c374c49fa3135f04648a0caabcb66c52884b943f02b4"}, + {file = "scipy-1.15.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5e721fed53187e71d0ccf382b6bf977644c533e506c4d33c3fb24de89f5c3ed5"}, + {file = "scipy-1.15.3-cp313-cp313t-win_amd64.whl", hash = "sha256:76ad1fb5f8752eabf0fa02e4cc0336b4e8f021e2d5f061ed37d6d264db35e3ca"}, + {file = "scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf"}, ] [package.dependencies] -numpy = ">=1.22.4,<1.29.0" +numpy = ">=1.23.5,<2.5" [package.extras] -dev = ["click", "cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy", "pycodestyle", "pydevtool", "rich-click", "ruff", "types-psutil", "typing_extensions"] -doc = ["jupytext", "matplotlib (>2)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (==0.9.0)", "sphinx (!=4.1.0)", "sphinx-design (>=0.2.0)"] -test = ["asv", "gmpy2", "hypothesis", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] +dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy (==1.10.0)", "pycodestyle", "pydevtool", "rich-click", "ruff (>=0.0.292)", "types-psutil", "typing_extensions"] +doc = ["intersphinx_registry", "jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.19.1)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0,<8.0.0)", "sphinx-copybutton", "sphinx-design (>=0.4.0)"] +test = ["Cython", "array-api-strict (>=2.0,<2.1.1)", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] [[package]] -name = "setuptools" -version = "69.0.3" -description = "Easily download, build, install, upgrade, and uninstall Python packages" +name = "sentry-sdk" +version = "2.66.0" +description = "Python client for Sentry (https://sentry.io)" optional = false -python-versions = ">=3.8" +python-versions = ">=3.6" files = [ - {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"}, - {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"}, + {file = "sentry_sdk-2.66.0-py3-none-any.whl", hash = "sha256:096136c214c602be2b323524d30755dc5b30ec5a218a206207f33b12c05c6f11"}, + {file = "sentry_sdk-2.66.0.tar.gz", hash = "sha256:9727d35aa83c56cd53294676fe65b96296a334c9ce107fa2142bd70f47acb265"}, ] +[package.dependencies] +certifi = "*" +urllib3 = ">=1.26.11" + [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +aiohttp = ["aiohttp (>=3.5)"] +anthropic = ["anthropic (>=0.16)"] +arq = ["arq (>=0.23)"] +asyncio = ["httpcore[asyncio] (==1.*)"] +asyncpg = ["asyncpg (>=0.23)"] +beam = ["apache-beam (>=2.12)"] +bottle = ["bottle (>=0.12.13)"] +celery = ["celery (>=3)"] +celery-redbeat = ["celery-redbeat (>=2)"] +chalice = ["chalice (>=1.16.0)"] +clickhouse-driver = ["clickhouse-driver (>=0.2.0)"] +django = ["django (>=1.8)"] +falcon = ["falcon (>=1.4)"] +fastapi = ["fastapi (>=0.79.0)"] +flask = ["blinker (>=1.1)", "flask (>=0.11)", "markupsafe"] +google-genai = ["google-genai (>=1.29.0)"] +grpcio = ["grpcio (>=1.21.1)", "protobuf (>=3.8.0)"] +http2 = ["httpcore[http2] (==1.*)"] +httpx = ["httpx (>=0.16.0)"] +huey = ["huey (>=2)"] +huggingface-hub = ["huggingface_hub (>=0.22)"] +langchain = ["langchain (>=0.0.210)"] +langgraph = ["langgraph (>=0.6.6)"] +launchdarkly = ["launchdarkly-server-sdk (>=9.8.0)"] +litellm = ["litellm (>=1.77.5,!=1.82.7,!=1.82.8)"] +litestar = ["litestar (>=2.0.0)"] +loguru = ["loguru (>=0.5)"] +mcp = ["mcp (>=1.15.0)"] +openai = ["openai (>=1.0.0)", "tiktoken (>=0.3.0)"] +openfeature = ["openfeature-sdk (>=0.7.1)"] +opentelemetry = ["opentelemetry-distro (>=0.35b0)"] +opentelemetry-experimental = ["opentelemetry-distro"] +opentelemetry-otlp = ["opentelemetry-distro[otlp] (>=0.35b0)"] +pure-eval = ["asttokens", "executing", "pure_eval"] +pydantic-ai = ["pydantic-ai (>=1.0.0)"] +pymongo = ["pymongo (>=3.1)"] +pyspark = ["pyspark (>=2.4.4)"] +quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] +rq = ["rq (>=0.6)"] +sanic = ["sanic (>=0.8)"] +sqlalchemy = ["sqlalchemy (>=1.2)"] +starlette = ["starlette (>=0.19.1)"] +starlite = ["starlite (>=1.48)"] +statsig = ["statsig (>=0.55.3)"] +tornado = ["tornado (>=6)"] +unleash = ["UnleashClient (>=6.0.1)"] [[package]] name = "shellingham" @@ -3915,95 +4937,93 @@ files = [ [[package]] name = "six" -version = "1.16.0" +version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] - -[[package]] -name = "sniffio" -version = "1.3.0" -description = "Sniff out which async library your code is running under" -optional = false -python-versions = ">=3.7" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, - {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] [[package]] name = "sqlalchemy" -version = "2.0.25" +version = "2.0.51" description = "Database Abstraction Library" optional = false python-versions = ">=3.7" files = [ - {file = "SQLAlchemy-2.0.25-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4344d059265cc8b1b1be351bfb88749294b87a8b2bbe21dfbe066c4199541ebd"}, - {file = "SQLAlchemy-2.0.25-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6f9e2e59cbcc6ba1488404aad43de005d05ca56e069477b33ff74e91b6319735"}, - {file = "SQLAlchemy-2.0.25-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84daa0a2055df9ca0f148a64fdde12ac635e30edbca80e87df9b3aaf419e144a"}, - {file = "SQLAlchemy-2.0.25-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc8b7dabe8e67c4832891a5d322cec6d44ef02f432b4588390017f5cec186a84"}, - {file = "SQLAlchemy-2.0.25-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f5693145220517b5f42393e07a6898acdfe820e136c98663b971906120549da5"}, - {file = "SQLAlchemy-2.0.25-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:db854730a25db7c956423bb9fb4bdd1216c839a689bf9cc15fada0a7fb2f4570"}, - {file = "SQLAlchemy-2.0.25-cp310-cp310-win32.whl", hash = "sha256:14a6f68e8fc96e5e8f5647ef6cda6250c780612a573d99e4d881581432ef1669"}, - {file = "SQLAlchemy-2.0.25-cp310-cp310-win_amd64.whl", hash = "sha256:87f6e732bccd7dcf1741c00f1ecf33797383128bd1c90144ac8adc02cbb98643"}, - {file = "SQLAlchemy-2.0.25-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:342d365988ba88ada8af320d43df4e0b13a694dbd75951f537b2d5e4cb5cd002"}, - {file = "SQLAlchemy-2.0.25-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f37c0caf14b9e9b9e8f6dbc81bc56db06acb4363eba5a633167781a48ef036ed"}, - {file = "SQLAlchemy-2.0.25-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa9373708763ef46782d10e950b49d0235bfe58facebd76917d3f5cbf5971aed"}, - {file = "SQLAlchemy-2.0.25-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d24f571990c05f6b36a396218f251f3e0dda916e0c687ef6fdca5072743208f5"}, - {file = "SQLAlchemy-2.0.25-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75432b5b14dc2fff43c50435e248b45c7cdadef73388e5610852b95280ffd0e9"}, - {file = "SQLAlchemy-2.0.25-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:884272dcd3ad97f47702965a0e902b540541890f468d24bd1d98bcfe41c3f018"}, - {file = "SQLAlchemy-2.0.25-cp311-cp311-win32.whl", hash = "sha256:e607cdd99cbf9bb80391f54446b86e16eea6ad309361942bf88318bcd452363c"}, - {file = "SQLAlchemy-2.0.25-cp311-cp311-win_amd64.whl", hash = "sha256:7d505815ac340568fd03f719446a589162d55c52f08abd77ba8964fbb7eb5b5f"}, - {file = "SQLAlchemy-2.0.25-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0dacf67aee53b16f365c589ce72e766efaabd2b145f9de7c917777b575e3659d"}, - {file = "SQLAlchemy-2.0.25-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b801154027107461ee992ff4b5c09aa7cc6ec91ddfe50d02bca344918c3265c6"}, - {file = "SQLAlchemy-2.0.25-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59a21853f5daeb50412d459cfb13cb82c089ad4c04ec208cd14dddd99fc23b39"}, - {file = "SQLAlchemy-2.0.25-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29049e2c299b5ace92cbed0c1610a7a236f3baf4c6b66eb9547c01179f638ec5"}, - {file = "SQLAlchemy-2.0.25-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b64b183d610b424a160b0d4d880995e935208fc043d0302dd29fee32d1ee3f95"}, - {file = "SQLAlchemy-2.0.25-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4f7a7d7fcc675d3d85fbf3b3828ecd5990b8d61bd6de3f1b260080b3beccf215"}, - {file = "SQLAlchemy-2.0.25-cp312-cp312-win32.whl", hash = "sha256:cf18ff7fc9941b8fc23437cc3e68ed4ebeff3599eec6ef5eebf305f3d2e9a7c2"}, - {file = "SQLAlchemy-2.0.25-cp312-cp312-win_amd64.whl", hash = "sha256:91f7d9d1c4dd1f4f6e092874c128c11165eafcf7c963128f79e28f8445de82d5"}, - {file = "SQLAlchemy-2.0.25-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bb209a73b8307f8fe4fe46f6ad5979649be01607f11af1eb94aa9e8a3aaf77f0"}, - {file = "SQLAlchemy-2.0.25-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:798f717ae7c806d67145f6ae94dc7c342d3222d3b9a311a784f371a4333212c7"}, - {file = "SQLAlchemy-2.0.25-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fdd402169aa00df3142149940b3bf9ce7dde075928c1886d9a1df63d4b8de62"}, - {file = "SQLAlchemy-2.0.25-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0d3cab3076af2e4aa5693f89622bef7fa770c6fec967143e4da7508b3dceb9b9"}, - {file = "SQLAlchemy-2.0.25-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:74b080c897563f81062b74e44f5a72fa44c2b373741a9ade701d5f789a10ba23"}, - {file = "SQLAlchemy-2.0.25-cp37-cp37m-win32.whl", hash = "sha256:87d91043ea0dc65ee583026cb18e1b458d8ec5fc0a93637126b5fc0bc3ea68c4"}, - {file = "SQLAlchemy-2.0.25-cp37-cp37m-win_amd64.whl", hash = "sha256:75f99202324383d613ddd1f7455ac908dca9c2dd729ec8584c9541dd41822a2c"}, - {file = "SQLAlchemy-2.0.25-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:420362338681eec03f53467804541a854617faed7272fe71a1bfdb07336a381e"}, - {file = "SQLAlchemy-2.0.25-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c88f0c7dcc5f99bdb34b4fd9b69b93c89f893f454f40219fe923a3a2fd11625"}, - {file = "SQLAlchemy-2.0.25-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3be4987e3ee9d9a380b66393b77a4cd6d742480c951a1c56a23c335caca4ce3"}, - {file = "SQLAlchemy-2.0.25-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a159111a0f58fb034c93eeba211b4141137ec4b0a6e75789ab7a3ef3c7e7e3"}, - {file = "SQLAlchemy-2.0.25-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8b8cb63d3ea63b29074dcd29da4dc6a97ad1349151f2d2949495418fd6e48db9"}, - {file = "SQLAlchemy-2.0.25-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:736ea78cd06de6c21ecba7416499e7236a22374561493b456a1f7ffbe3f6cdb4"}, - {file = "SQLAlchemy-2.0.25-cp38-cp38-win32.whl", hash = "sha256:10331f129982a19df4284ceac6fe87353ca3ca6b4ca77ff7d697209ae0a5915e"}, - {file = "SQLAlchemy-2.0.25-cp38-cp38-win_amd64.whl", hash = "sha256:c55731c116806836a5d678a70c84cb13f2cedba920212ba7dcad53260997666d"}, - {file = "SQLAlchemy-2.0.25-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:605b6b059f4b57b277f75ace81cc5bc6335efcbcc4ccb9066695e515dbdb3900"}, - {file = "SQLAlchemy-2.0.25-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:665f0a3954635b5b777a55111ababf44b4fc12b1f3ba0a435b602b6387ffd7cf"}, - {file = "SQLAlchemy-2.0.25-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecf6d4cda1f9f6cb0b45803a01ea7f034e2f1aed9475e883410812d9f9e3cfcf"}, - {file = "SQLAlchemy-2.0.25-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c51db269513917394faec5e5c00d6f83829742ba62e2ac4fa5c98d58be91662f"}, - {file = "SQLAlchemy-2.0.25-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:790f533fa5c8901a62b6fef5811d48980adeb2f51f1290ade8b5e7ba990ba3de"}, - {file = "SQLAlchemy-2.0.25-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1b1180cda6df7af84fe72e4530f192231b1f29a7496951db4ff38dac1687202d"}, - {file = "SQLAlchemy-2.0.25-cp39-cp39-win32.whl", hash = "sha256:555651adbb503ac7f4cb35834c5e4ae0819aab2cd24857a123370764dc7d7e24"}, - {file = "SQLAlchemy-2.0.25-cp39-cp39-win_amd64.whl", hash = "sha256:dc55990143cbd853a5d038c05e79284baedf3e299661389654551bd02a6a68d7"}, - {file = "SQLAlchemy-2.0.25-py3-none-any.whl", hash = "sha256:a86b4240e67d4753dc3092d9511886795b3c2852abe599cffe108952f7af7ac3"}, - {file = "SQLAlchemy-2.0.25.tar.gz", hash = "sha256:a2c69a7664fb2d54b8682dd774c3b54f67f84fa123cf84dda2a5f40dcaa04e08"}, + {file = "sqlalchemy-2.0.51-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e8203d2fbd5c6254692ef0a72c740d75b2f3c7ca345404f4c1a4604813c77c0"}, + {file = "sqlalchemy-2.0.51-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1af05726b3d0cdba1c55284bf408fd3b792e690fe2399bfb8304565551cda652"}, + {file = "sqlalchemy-2.0.51-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e54ff2dd657f2e3e0fbf2b097db1182f7bfea263eca4353f00065bae2a67c3d"}, + {file = "sqlalchemy-2.0.51-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:1e47b1199c2e832e325eacabc8d32d2487f58c9358f97e9a00f5eb93c5680d84"}, + {file = "sqlalchemy-2.0.51-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c68568f3facf8f66fa76c60e0ced69b67666ffa9941d1d0a3756fda196049080"}, + {file = "sqlalchemy-2.0.51-cp310-cp310-win32.whl", hash = "sha256:0592bdadf86ddcabfd72d9ab66ea8a5d8d2cc6be1cc51fa7e66c03868ac5eac1"}, + {file = "sqlalchemy-2.0.51-cp310-cp310-win_amd64.whl", hash = "sha256:740cf6f35351b1ac3d82369152acf1d51d37e3dcf85d4dc0a22ca01410eabe2a"}, + {file = "sqlalchemy-2.0.51-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1aa10c0daee6705294d181daadaa793221e1a59ed55000a3fab1d42b088ce4ba"}, + {file = "sqlalchemy-2.0.51-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a5b2ed6d828f1f09bd812861f4f59ca3bc3803f9df871f4555187f0faf018604"}, + {file = "sqlalchemy-2.0.51-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:436728ce18a80f6951a1e11cc6112c2ede9faf20766f1a26195a7c441ca12dbd"}, + {file = "sqlalchemy-2.0.51-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dc261707bf5739aea8a541593f3cc1d463c2701fb05fbcbba0ce031b69a21260"}, + {file = "sqlalchemy-2.0.51-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a6d26094615306d116dd5e4a51b0304c99dd2356fc569eed6922a80a6bd3b265"}, + {file = "sqlalchemy-2.0.51-cp311-cp311-win32.whl", hash = "sha256:ca8435d13829b92f4a97362d91975154a4015db3a2634154e1754e9a915e6b86"}, + {file = "sqlalchemy-2.0.51-cp311-cp311-win_amd64.whl", hash = "sha256:4a011ea4510683319ce4ed274b56ee05194b39b6da9d09ca7a39388f0fa84dcc"}, + {file = "sqlalchemy-2.0.51-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d78702b26ba1c18b2d0fb2ea940ba7f17a9581b42e8361ff93920ebbee1235a"}, + {file = "sqlalchemy-2.0.51-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581921d849d6e6f994d560389192955e80e2950e18fcdfe2ccea863e01158e6e"}, + {file = "sqlalchemy-2.0.51-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1d21ce524ab86c23046e992a5b81cb54c21079c6df6e78b8fc77d77cac70a6b9"}, + {file = "sqlalchemy-2.0.51-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c5d98a2709840027f5a347c3af0a7c3d5f6c1ff93af2ca1c54494e23cba8f389"}, + {file = "sqlalchemy-2.0.51-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1181256e0f16479691b5616d36375dc2620ad8332b25978763c3d206ad3f3f1d"}, + {file = "sqlalchemy-2.0.51-cp312-cp312-win32.whl", hash = "sha256:9f380393be5abeb6815f68fd39271b95127173511b6706b0a630a9995d53f8f5"}, + {file = "sqlalchemy-2.0.51-cp312-cp312-win_amd64.whl", hash = "sha256:2cf39aabdf48e87c1c2c2ed6d20d33ffa0733b3071ce9c5f66357947dd009080"}, + {file = "sqlalchemy-2.0.51-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7c2056838b6685b72fdb36c99996cf862753461a62f2e84f4196371d3b2d6a07"}, + {file = "sqlalchemy-2.0.51-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:483b11bd46bf35fc14c52faf338b04300c9e6ce554bce9b11be85bfec3bc3195"}, + {file = "sqlalchemy-2.0.51-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1bed1ee8b01da6088210aa9412023326fb98a599ba502e6118308601dcbef77f"}, + {file = "sqlalchemy-2.0.51-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:72ca54c952107ba5cd58854b67a5a6268631289d21651a1235396f3b98b47400"}, + {file = "sqlalchemy-2.0.51-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b3e693d15533a45cd5906f0589f9c35090bef6ef45bf1e8195c424aa0ae06a8d"}, + {file = "sqlalchemy-2.0.51-cp313-cp313-win32.whl", hash = "sha256:b93ab07b5292dbe7e6b8da89475275e7042744283921344b56105f3eeb0f828b"}, + {file = "sqlalchemy-2.0.51-cp313-cp313-win_amd64.whl", hash = "sha256:0f053118c30e53161857a953e4de667d90e274980dccbe5dd3829bbbeece72a5"}, + {file = "sqlalchemy-2.0.51-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6ea306caaae6bd5afd0a46050003c88f6bf33227377a49298c498c3cb88ff491"}, + {file = "sqlalchemy-2.0.51-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c45a496d6bc05dec41dcd4c3a2b183723f47473255c159cd80b503c8f246424d"}, + {file = "sqlalchemy-2.0.51-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4004ada0aafe8ae1991b2cd1d99c6d9146126e123bd6f883c260d974aa012e54"}, + {file = "sqlalchemy-2.0.51-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0f6bcad487aee1c638d707235682fc96f741de00663619881ab235400d03289e"}, + {file = "sqlalchemy-2.0.51-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:39a76529db6305693d8d4affa58ad5b5e2e18edd62daea628b29b97930b3513d"}, + {file = "sqlalchemy-2.0.51-cp314-cp314-win32.whl", hash = "sha256:08a204d8b5638717c26a24df18fcf40af45a6b22e35b70b1d62f0113c2e278e8"}, + {file = "sqlalchemy-2.0.51-cp314-cp314-win_amd64.whl", hash = "sha256:96747bfbadb055466e5b46d572618170046b45ce5a4879167f50d70a5319a499"}, + {file = "sqlalchemy-2.0.51-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e5ea1a213be1fcd5e49d9904c3b9939211ded90bc2a64e93f4c01963474285de"}, + {file = "sqlalchemy-2.0.51-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7c6b36ed71f41942bdcd2ad2522be46bfce09d5705be5640ecf19bbc7660e4b7"}, + {file = "sqlalchemy-2.0.51-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0c2c62877097e1a0db401fba5cb4debee33265e5b2a55c4ccb489c02c53b4f72"}, + {file = "sqlalchemy-2.0.51-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0378d055e9e8cd6ce4d8dff683bdd3d7d413533c4ee51d67a2b1e0f9eacc0f23"}, + {file = "sqlalchemy-2.0.51-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6e46fc36029eff666391e0531e5387b62ce6c4f1d8e50b3fb3099eaca1b42522"}, + {file = "sqlalchemy-2.0.51-cp314-cp314t-win32.whl", hash = "sha256:9161cfc9efce70d1715f47d6ff40f79c6778c00d53be4fbc09d70301e4b83ba7"}, + {file = "sqlalchemy-2.0.51-cp314-cp314t-win_amd64.whl", hash = "sha256:159bb6ba32059f57ad7375a8f50d844dd2f19d14954ecf820cd33e20debd46b2"}, + {file = "sqlalchemy-2.0.51-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bb1f5062f98b0b3290e72b707747fdd7e0f22d6956b236ba7ca7f5c9971d2da2"}, + {file = "sqlalchemy-2.0.51-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:247acaa29ccef6250dfd6a3eedf8f94ddf23564180a39fe362e32ae9dbdbde46"}, + {file = "sqlalchemy-2.0.51-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c95ef01f53233a305a874a44a63fbfb1d81cd79b49de0f8529b3548cde437e37"}, + {file = "sqlalchemy-2.0.51-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:fa268106c8987639a17a18514cfe0cd9bf17420ab887e1e1bf486da8836135b1"}, + {file = "sqlalchemy-2.0.51-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:b7f08588854bbb724041d9ae9d980d40040c922382e1d9a2ecb390edc4fd5032"}, + {file = "sqlalchemy-2.0.51-cp38-cp38-win32.whl", hash = "sha256:6b588fd681ddf0c196b8df1ea49a8913514894b2b8f945a9511b4b48871f99c8"}, + {file = "sqlalchemy-2.0.51-cp38-cp38-win_amd64.whl", hash = "sha256:ca216e8af5c05e326efc7e28716ac2381a7cf9791749f5ee1849dccdc99c9b00"}, + {file = "sqlalchemy-2.0.51-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:aa18ae738b5170e253ad0bb6c4b0f07585081e8a6e50893e4d911d47b39a0904"}, + {file = "sqlalchemy-2.0.51-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:59cab3686b1bc039dd9cded2f8d0c08a246e84e76bd4ab5b4f18c7cdae293825"}, + {file = "sqlalchemy-2.0.51-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:111604e637da87031255ddc26c7d7bc22bc6af6f5d459ccff3af1b4660233a85"}, + {file = "sqlalchemy-2.0.51-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ad30ae663711786303fbcd46a47516302d201ee49a877cb3fac61f672895110a"}, + {file = "sqlalchemy-2.0.51-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b21f0e7efc7a5c509e953784e9d1575ebb8b4318960e7e7d7a93bb803626cf64"}, + {file = "sqlalchemy-2.0.51-cp39-cp39-win32.whl", hash = "sha256:a42ad6afcbaaa777241e347aa2e29155993045a0d6b7db74da61053ffe875fe0"}, + {file = "sqlalchemy-2.0.51-cp39-cp39-win_amd64.whl", hash = "sha256:2a97eaad21c84b4ef8010b11eeba9fe6153eb0b3df3ff8b6abc309df1b978ef7"}, + {file = "sqlalchemy-2.0.51-py3-none-any.whl", hash = "sha256:bb024d8b621d0be75f4f44ecc7c950450026e76d66dc8f791bb5331d7fed59d5"}, + {file = "sqlalchemy-2.0.51.tar.gz", hash = "sha256:804dccd8a4a6242c4e30ad961e540e18a588f6527202f2d6791b01845d59fdc9"}, ] [package.dependencies] -greenlet = {version = "!=0.4.17", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""} +greenlet = {version = ">=1", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""} typing-extensions = ">=4.6.0" [package.extras] -aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"] -aioodbc = ["aioodbc", "greenlet (!=0.4.17)"] -aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] -asyncio = ["greenlet (!=0.4.17)"] -asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (!=0.4.17)"] -mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5)"] +aiomysql = ["aiomysql (>=0.2.0)", "greenlet (>=1)"] +aioodbc = ["aioodbc", "greenlet (>=1)"] +aiosqlite = ["aiosqlite", "greenlet (>=1)", "typing_extensions (!=3.10.0.1)"] +asyncio = ["greenlet (>=1)"] +asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (>=1)"] +mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5,!=1.1.10)"] mssql = ["pyodbc"] mssql-pymssql = ["pymssql"] mssql-pyodbc = ["pyodbc"] @@ -4013,7 +5033,7 @@ mysql-connector = ["mysql-connector-python"] oracle = ["cx_oracle (>=8)"] oracle-oracledb = ["oracledb (>=1.0.1)"] postgresql = ["psycopg2 (>=2.7)"] -postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] +postgresql-asyncpg = ["asyncpg", "greenlet (>=1)"] postgresql-pg8000 = ["pg8000 (>=1.29.1)"] postgresql-psycopg = ["psycopg (>=3.0.7)"] postgresql-psycopg2binary = ["psycopg2-binary"] @@ -4024,138 +5044,178 @@ sqlcipher = ["sqlcipher3_binary"] [[package]] name = "starlette" -version = "0.41.2" +version = "1.3.1" description = "The little ASGI library that shines." optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "starlette-0.41.2-py3-none-any.whl", hash = "sha256:fbc189474b4731cf30fcef52f18a8d070e3f3b46c6a04c97579e85e6ffca942d"}, - {file = "starlette-0.41.2.tar.gz", hash = "sha256:9834fd799d1a87fd346deb76158668cfa0b0d56f85caefe8268e2d97c3468b62"}, + {file = "starlette-1.3.1-py3-none-any.whl", hash = "sha256:c7372aae11c3c3f26a42df7bd626cec2f47d03483d261d369516a615a53714c6"}, + {file = "starlette-1.3.1.tar.gz", hash = "sha256:05d0213193f2fbaae60e2ecb593b4add4262ad4e46536b54abe36f11a71724e0"}, ] [package.dependencies] -anyio = ">=3.4.0,<5" +anyio = ">=3.6.2,<5" +typing-extensions = {version = ">=4.10.0", markers = "python_version < \"3.13\""} [package.extras] -full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"] +full = ["httpx (>=0.27.0,<0.29.0)", "httpx2 (>=2.0.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.18)", "pyyaml"] [[package]] -name = "tensorboardx" -version = "2.6.2.2" -description = "TensorBoardX lets you watch Tensors Flow without Tensorflow" +name = "strenum" +version = "0.4.15" +description = "An Enum that inherits from str." optional = false python-versions = "*" files = [ - {file = "tensorboardX-2.6.2.2-py2.py3-none-any.whl", hash = "sha256:160025acbf759ede23fd3526ae9d9bfbfd8b68eb16c38a010ebe326dc6395db8"}, - {file = "tensorboardX-2.6.2.2.tar.gz", hash = "sha256:c6476d7cd0d529b0b72f4acadb1269f9ed8b22f441e87a84f2a3b940bb87b666"}, + {file = "StrEnum-0.4.15-py3-none-any.whl", hash = "sha256:a30cda4af7cc6b5bf52c8055bc4bf4b2b6b14a93b574626da33df53cf7740659"}, + {file = "StrEnum-0.4.15.tar.gz", hash = "sha256:878fb5ab705442070e4dd1929bb5e2249511c0bcf2b0eeacf3bcd80875c82eff"}, ] -[package.dependencies] -numpy = "*" -packaging = "*" -protobuf = ">=3.20" +[package.extras] +docs = ["myst-parser[linkify]", "sphinx", "sphinx-rtd-theme"] +release = ["twine"] +test = ["pylint", "pytest", "pytest-black", "pytest-cov", "pytest-pylint"] [[package]] -name = "tinydb" -version = "4.8.2" -description = "TinyDB is a tiny, document oriented database optimized for your happiness :)" +name = "tensorboardx" +version = "2.6.5" +description = "TensorBoardX lets you watch Tensors Flow without Tensorflow" optional = false -python-versions = "<4.0,>=3.8" +python-versions = ">=3.9" files = [ - {file = "tinydb-4.8.2-py3-none-any.whl", hash = "sha256:f97030ee5cbc91eeadd1d7af07ab0e48ceb04aa63d4a983adbaca4cba16e86c3"}, - {file = "tinydb-4.8.2.tar.gz", hash = "sha256:f7dfc39b8d7fda7a1ca62a8dbb449ffd340a117c1206b68c50b1a481fb95181d"}, + {file = "tensorboardx-2.6.5-py3-none-any.whl", hash = "sha256:c10b891d00af306537cb8b58a039b2ba41571f0da06f433a41c4ca8d6abe1373"}, + {file = "tensorboardx-2.6.5.tar.gz", hash = "sha256:ca176db3997ee8c07d2eb77381225956a3fd1c10c91beafab1f17069adc47017"}, ] +[package.dependencies] +numpy = "*" +packaging = "*" +protobuf = ">=3.20" + [[package]] name = "tomli" -version = "2.0.1" +version = "2.4.1" description = "A lil' TOML parser" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, + {file = "tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30"}, + {file = "tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a"}, + {file = "tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076"}, + {file = "tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9"}, + {file = "tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c"}, + {file = "tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc"}, + {file = "tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049"}, + {file = "tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e"}, + {file = "tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece"}, + {file = "tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a"}, + {file = "tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085"}, + {file = "tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9"}, + {file = "tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5"}, + {file = "tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585"}, + {file = "tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1"}, + {file = "tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917"}, + {file = "tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9"}, + {file = "tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257"}, + {file = "tomli-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54"}, + {file = "tomli-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a"}, + {file = "tomli-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897"}, + {file = "tomli-2.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f"}, + {file = "tomli-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d"}, + {file = "tomli-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5"}, + {file = "tomli-2.4.1-cp313-cp313-win32.whl", hash = "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd"}, + {file = "tomli-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36"}, + {file = "tomli-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd"}, + {file = "tomli-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf"}, + {file = "tomli-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac"}, + {file = "tomli-2.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662"}, + {file = "tomli-2.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853"}, + {file = "tomli-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15"}, + {file = "tomli-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba"}, + {file = "tomli-2.4.1-cp314-cp314-win32.whl", hash = "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6"}, + {file = "tomli-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7"}, + {file = "tomli-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232"}, + {file = "tomli-2.4.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4"}, + {file = "tomli-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c"}, + {file = "tomli-2.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d"}, + {file = "tomli-2.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41"}, + {file = "tomli-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c"}, + {file = "tomli-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f"}, + {file = "tomli-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8"}, + {file = "tomli-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26"}, + {file = "tomli-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396"}, + {file = "tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe"}, + {file = "tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f"}, ] [[package]] name = "toolz" -version = "1.0.0" +version = "1.1.0" description = "List processing tools and functional utilities" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "toolz-1.0.0-py3-none-any.whl", hash = "sha256:292c8f1c4e7516bf9086f8850935c799a874039c8bcf959d47b600e4c44a6236"}, - {file = "toolz-1.0.0.tar.gz", hash = "sha256:2c86e3d9a04798ac556793bced838816296a2f085017664e4995cb40a1047a02"}, + {file = "toolz-1.1.0-py3-none-any.whl", hash = "sha256:15ccc861ac51c53696de0a5d6d4607f99c210739caf987b5d2054f3efed429d8"}, + {file = "toolz-1.1.0.tar.gz", hash = "sha256:27a5c770d068c110d9ed9323f24f1543e83b2f300a687b7891c1a6d56b697b5b"}, ] [[package]] name = "tqdm" -version = "4.66.6" +version = "4.68.4" description = "Fast, Extensible Progress Meter" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tqdm-4.66.6-py3-none-any.whl", hash = "sha256:223e8b5359c2efc4b30555531f09e9f2f3589bcd7fdd389271191031b49b7a63"}, - {file = "tqdm-4.66.6.tar.gz", hash = "sha256:4bdd694238bef1485ce839d67967ab50af8f9272aab687c0d7702a01da0be090"}, + {file = "tqdm-4.68.4-py3-none-any.whl", hash = "sha256:5168118b2368f48c561afda8020fd79195b1bdb0bdf8086b88442c267a315dc2"}, + {file = "tqdm-4.68.4.tar.gz", hash = "sha256:19829c9673638f2a0b8617da4cdcb927e831cd88bcfcb6e78d42a4d1af131520"}, ] [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} [package.extras] -dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"] +discord = ["envwrap", "requests"] notebook = ["ipywidgets (>=6)"] -slack = ["slack-sdk"] -telegram = ["requests"] +slack = ["envwrap", "slack-sdk"] +telegram = ["envwrap", "requests"] [[package]] -name = "tuspy" -version = "0.2.5" -description = "A Python client for the tus resumable upload protocol -> http://tus.io" +name = "truststore" +version = "0.10.4" +description = "Verify certificates using native system trust stores" optional = false -python-versions = "*" +python-versions = ">=3.10" files = [ - {file = "tuspy-0.2.5-py3-none-any.whl", hash = "sha256:8ce106dd139ac77a097e8728f15f90d99df7408d9e67ac780ce44aefb9b5dd8d"}, - {file = "tuspy-0.2.5.tar.gz", hash = "sha256:1f238f65d444c0688f57e1dd704d9aa11cf5747eec33669e917627150170b9b8"}, + {file = "truststore-0.10.4-py3-none-any.whl", hash = "sha256:adaeaecf1cbb5f4de3b1959b42d41f6fab57b2b1666adb59e89cb0b53361d981"}, + {file = "truststore-0.10.4.tar.gz", hash = "sha256:9d91bd436463ad5e4ee4aba766628dd6cd7010cf3e2461756b3303710eebc301"}, ] -[package.dependencies] -certifi = ">=2018.1.18" -future = ">=0.16.0" -requests = ">=2.18.4" -six = ">=1.11.0" -tinydb = ">=3.5.0" - -[package.extras] -dev = ["Sphinx (==1.7.1)", "sphinx-autobuild (==0.7.1)", "tox (>=2.3.1)"] -test = ["coverage (>=4.2)", "mock (>=2.0.0)", "pytest (>=3.0.3)", "pytest-cov (>=2.3.1,<2.6)", "responses (>=0.5.1)"] - [[package]] name = "typer" -version = "0.12.5" +version = "0.27.0" description = "Typer, build great CLIs. Easy to code. Based on Python type hints." optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" files = [ - {file = "typer-0.12.5-py3-none-any.whl", hash = "sha256:62fe4e471711b147e3365034133904df3e235698399bc4de2b36c8579298d52b"}, - {file = "typer-0.12.5.tar.gz", hash = "sha256:f592f089bedcc8ec1b974125d64851029c3b1af145f04aca64d69410f0c9b722"}, + {file = "typer-0.27.0-py3-none-any.whl", hash = "sha256:6f4b27631e47f077871b7dc30e933ec0131c1390fbe0e387ea5574b5bac9ccf1"}, + {file = "typer-0.27.0.tar.gz", hash = "sha256:629bd12ea5d13a17148125d9a264f949eb171fb3f120f9b04d85873cab054fa5"}, ] [package.dependencies] -click = ">=8.0.0" -rich = ">=10.11.0" +annotated-doc = ">=0.0.2" +colorama = {version = "*", markers = "platform_system == \"Windows\""} +rich = ">=13.8.0" shellingham = ">=1.3.0" -typing-extensions = ">=3.7.4.3" [[package]] name = "types-requests" -version = "2.32.0.20241016" +version = "2.33.0.20260712" description = "Typing stubs for requests" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "types-requests-2.32.0.20241016.tar.gz", hash = "sha256:0d9cad2f27515d0e3e3da7134a1b6f28fb97129d86b867f24d9c726452634d95"}, - {file = "types_requests-2.32.0.20241016-py3-none-any.whl", hash = "sha256:4195d62d6d3e043a4eaaf08ff8a62184584d2e8684e9d2aa178c7915a7da3747"}, + {file = "types_requests-2.33.0.20260712-py3-none-any.whl", hash = "sha256:de027e28c171d3da529689cbfa023b0b4eab188c8dfa22fd834eebd2cee6e7bb"}, + {file = "types_requests-2.33.0.20260712.tar.gz", hash = "sha256:2141b67ab534a5c5cd2dac5034f2a35f42e699c5bf185eee608c5246a069d7fb"}, ] [package.dependencies] @@ -4163,146 +5223,172 @@ urllib3 = ">=2" [[package]] name = "typing-extensions" -version = "4.9.0" -description = "Backported and Experimental Type Hints for Python 3.8+" +version = "4.16.0" +description = "Backported and Experimental Type Hints for Python 3.9+" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, - {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, + {file = "typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8"}, + {file = "typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5"}, ] +[[package]] +name = "typing-inspection" +version = "0.4.2" +description = "Runtime typing introspection tools" +optional = false +python-versions = ">=3.9" +files = [ + {file = "typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7"}, + {file = "typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464"}, +] + +[package.dependencies] +typing-extensions = ">=4.12.0" + [[package]] name = "tzdata" -version = "2023.4" +version = "2026.3" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2023.4-py2.py3-none-any.whl", hash = "sha256:aa3ace4329eeacda5b7beb7ea08ece826c28d761cda36e747cfbf97996d39bf3"}, - {file = "tzdata-2023.4.tar.gz", hash = "sha256:dd54c94f294765522c77399649b4fefd95522479a664a0cec87f41bebc6148c9"}, + {file = "tzdata-2026.3-py2.py3-none-any.whl", hash = "sha256:dc096730c87af6cab1b171c9d532be840741ff5d459015e7f6947bd7d7e54931"}, + {file = "tzdata-2026.3.tar.gz", hash = "sha256:4a1518b8993086a7982523e071643f3c0e5f213e75b21318e78bcabfff9d1415"}, ] [[package]] name = "tzlocal" -version = "5.2" +version = "5.4.4" description = "tzinfo object for the local timezone" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "tzlocal-5.2-py3-none-any.whl", hash = "sha256:49816ef2fe65ea8ac19d19aa7a1ae0551c834303d5014c6d5a62e4cbda8047b8"}, - {file = "tzlocal-5.2.tar.gz", hash = "sha256:8d399205578f1a9342816409cc1e46a93ebd5755e39ea2d85334bea911bf0e6e"}, + {file = "tzlocal-5.4.4-py3-none-any.whl", hash = "sha256:aae09f0126a8a86fa736be266eb4a471380d26a0de3bc14844e7821fee3e2a15"}, + {file = "tzlocal-5.4.4.tar.gz", hash = "sha256:8dbb8660838688a7b6ba4fed31d18dedf842afb4d47ca050d6d891c2c15f3be4"}, ] [package.dependencies] tzdata = {version = "*", markers = "platform_system == \"Windows\""} [package.extras] -devenv = ["check-manifest", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3)", "zest.releaser"] +devenv = ["zest.releaser"] +testing = ["check_manifest", "pyroma", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3)", "ruff"] [[package]] name = "urllib3" -version = "2.0.7" +version = "2.7.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" files = [ - {file = "urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"}, - {file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"}, + {file = "urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897"}, + {file = "urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c"}, ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] +brotli = ["brotli (>=1.2.0)", "brotlicffi (>=1.2.0.0)"] +h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["zstandard (>=0.18.0)"] +zstd = ["backports-zstd (>=1.0.0)"] [[package]] name = "uvicorn" -version = "0.32.1" +version = "0.51.0" description = "The lightning-fast ASGI server." optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" files = [ - {file = "uvicorn-0.32.1-py3-none-any.whl", hash = "sha256:82ad92fd58da0d12af7482ecdb5f2470a04c9c9a53ced65b9bbb4a205377602e"}, - {file = "uvicorn-0.32.1.tar.gz", hash = "sha256:ee9519c246a72b1c084cea8d3b44ed6026e78a4a309cbedae9c37e4cb9fbb175"}, + {file = "uvicorn-0.51.0-py3-none-any.whl", hash = "sha256:5d38af6cd620f2ae3849fb44fd4879e0890aa1febe8d47eb355fb45d93fe6a5b"}, + {file = "uvicorn-0.51.0.tar.gz", hash = "sha256:f6f4b69b657c312f516dd2d268ab9ae6f254b11e4bac504f37b2ab58b24dd0b0"}, ] [package.dependencies] click = ">=7.0" -colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""} h11 = ">=0.8" -httptools = {version = ">=0.6.3", optional = true, markers = "extra == \"standard\""} +httptools = {version = ">=0.8.0", optional = true, markers = "extra == \"standard\""} python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} pyyaml = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} -uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "(sys_platform != \"win32\" and sys_platform != \"cygwin\") and platform_python_implementation != \"PyPy\" and extra == \"standard\""} -watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} -websockets = {version = ">=10.4", optional = true, markers = "extra == \"standard\""} +uvloop = {version = ">=0.15.1", optional = true, markers = "(sys_platform != \"win32\" and sys_platform != \"cygwin\") and platform_python_implementation != \"PyPy\" and extra == \"standard\""} +watchfiles = {version = ">=0.20", optional = true, markers = "extra == \"standard\""} +websockets = {version = ">=13.0", optional = true, markers = "extra == \"standard\""} [package.extras] -standard = ["colorama (>=0.4)", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] +standard = ["httptools (>=0.8.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.15.1)", "watchfiles (>=0.20)", "websockets (>=13.0)"] [[package]] name = "uvloop" -version = "0.21.0" +version = "0.22.1" description = "Fast implementation of asyncio event loop on top of libuv" optional = false -python-versions = ">=3.8.0" -files = [ - {file = "uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f"}, - {file = "uvloop-0.21.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:196274f2adb9689a289ad7d65700d37df0c0930fd8e4e743fa4834e850d7719d"}, - {file = "uvloop-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f38b2e090258d051d68a5b14d1da7203a3c3677321cf32a95a6f4db4dd8b6f26"}, - {file = "uvloop-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c43e0f13022b998eb9b973b5e97200c8b90823454d4bc06ab33829e09fb9bb"}, - {file = "uvloop-0.21.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10d66943def5fcb6e7b37310eb6b5639fd2ccbc38df1177262b0640c3ca68c1f"}, - {file = "uvloop-0.21.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:67dd654b8ca23aed0a8e99010b4c34aca62f4b7fce88f39d452ed7622c94845c"}, - {file = "uvloop-0.21.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c0f3fa6200b3108919f8bdabb9a7f87f20e7097ea3c543754cabc7d717d95cf8"}, - {file = "uvloop-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0"}, - {file = "uvloop-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9fb766bb57b7388745d8bcc53a359b116b8a04c83a2288069809d2b3466c37e"}, - {file = "uvloop-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a375441696e2eda1c43c44ccb66e04d61ceeffcd76e4929e527b7fa401b90fb"}, - {file = "uvloop-0.21.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:baa0e6291d91649c6ba4ed4b2f982f9fa165b5bbd50a9e203c416a2797bab3c6"}, - {file = "uvloop-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d"}, - {file = "uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c"}, - {file = "uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2"}, - {file = "uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d"}, - {file = "uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc"}, - {file = "uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb"}, - {file = "uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f"}, - {file = "uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281"}, - {file = "uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af"}, - {file = "uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6"}, - {file = "uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816"}, - {file = "uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc"}, - {file = "uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553"}, - {file = "uvloop-0.21.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:17df489689befc72c39a08359efac29bbee8eee5209650d4b9f34df73d22e414"}, - {file = "uvloop-0.21.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bc09f0ff191e61c2d592a752423c767b4ebb2986daa9ed62908e2b1b9a9ae206"}, - {file = "uvloop-0.21.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0ce1b49560b1d2d8a2977e3ba4afb2414fb46b86a1b64056bc4ab929efdafbe"}, - {file = "uvloop-0.21.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e678ad6fe52af2c58d2ae3c73dc85524ba8abe637f134bf3564ed07f555c5e79"}, - {file = "uvloop-0.21.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:460def4412e473896ef179a1671b40c039c7012184b627898eea5072ef6f017a"}, - {file = "uvloop-0.21.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:10da8046cc4a8f12c91a1c39d1dd1585c41162a15caaef165c2174db9ef18bdc"}, - {file = "uvloop-0.21.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c097078b8031190c934ed0ebfee8cc5f9ba9642e6eb88322b9958b649750f72b"}, - {file = "uvloop-0.21.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:46923b0b5ee7fc0020bef24afe7836cb068f5050ca04caf6b487c513dc1a20b2"}, - {file = "uvloop-0.21.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53e420a3afe22cdcf2a0f4846e377d16e718bc70103d7088a4f7623567ba5fb0"}, - {file = "uvloop-0.21.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88cb67cdbc0e483da00af0b2c3cdad4b7c61ceb1ee0f33fe00e09c81e3a6cb75"}, - {file = "uvloop-0.21.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:221f4f2a1f46032b403bf3be628011caf75428ee3cc204a22addf96f586b19fd"}, - {file = "uvloop-0.21.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2d1f581393673ce119355d56da84fe1dd9d2bb8b3d13ce792524e1607139feff"}, - {file = "uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3"}, +python-versions = ">=3.8.1" +files = [ + {file = "uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ef6f0d4cc8a9fa1f6a910230cd53545d9a14479311e87e3cb225495952eb672c"}, + {file = "uvloop-0.22.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7cd375a12b71d33d46af85a3343b35d98e8116134ba404bd657b3b1d15988792"}, + {file = "uvloop-0.22.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac33ed96229b7790eb729702751c0e93ac5bc3bcf52ae9eccbff30da09194b86"}, + {file = "uvloop-0.22.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:481c990a7abe2c6f4fc3d98781cc9426ebd7f03a9aaa7eb03d3bfc68ac2a46bd"}, + {file = "uvloop-0.22.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a592b043a47ad17911add5fbd087c76716d7c9ccc1d64ec9249ceafd735f03c2"}, + {file = "uvloop-0.22.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1489cf791aa7b6e8c8be1c5a080bae3a672791fcb4e9e12249b05862a2ca9cec"}, + {file = "uvloop-0.22.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c60ebcd36f7b240b30788554b6f0782454826a0ed765d8430652621b5de674b9"}, + {file = "uvloop-0.22.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b7f102bf3cb1995cfeaee9321105e8f5da76fdb104cdad8986f85461a1b7b77"}, + {file = "uvloop-0.22.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53c85520781d84a4b8b230e24a5af5b0778efdb39142b424990ff1ef7c48ba21"}, + {file = "uvloop-0.22.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:56a2d1fae65fd82197cb8c53c367310b3eabe1bbb9fb5a04d28e3e3520e4f702"}, + {file = "uvloop-0.22.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40631b049d5972c6755b06d0bfe8233b1bd9a8a6392d9d1c45c10b6f9e9b2733"}, + {file = "uvloop-0.22.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:535cc37b3a04f6cd2c1ef65fa1d370c9a35b6695df735fcff5427323f2cd5473"}, + {file = "uvloop-0.22.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:fe94b4564e865d968414598eea1a6de60adba0c040ba4ed05ac1300de402cd42"}, + {file = "uvloop-0.22.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:51eb9bd88391483410daad430813d982010f9c9c89512321f5b60e2cddbdddd6"}, + {file = "uvloop-0.22.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:700e674a166ca5778255e0e1dc4e9d79ab2acc57b9171b79e65feba7184b3370"}, + {file = "uvloop-0.22.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b5b1ac819a3f946d3b2ee07f09149578ae76066d70b44df3fa990add49a82e4"}, + {file = "uvloop-0.22.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e047cc068570bac9866237739607d1313b9253c3051ad84738cbb095be0537b2"}, + {file = "uvloop-0.22.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:512fec6815e2dd45161054592441ef76c830eddaad55c8aa30952e6fe1ed07c0"}, + {file = "uvloop-0.22.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:561577354eb94200d75aca23fbde86ee11be36b00e52a4eaf8f50fb0c86b7705"}, + {file = "uvloop-0.22.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cdf5192ab3e674ca26da2eada35b288d2fa49fdd0f357a19f0e7c4e7d5077c8"}, + {file = "uvloop-0.22.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e2ea3d6190a2968f4a14a23019d3b16870dd2190cd69c8180f7c632d21de68d"}, + {file = "uvloop-0.22.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0530a5fbad9c9e4ee3f2b33b148c6a64d47bbad8000ea63704fa8260f4cf728e"}, + {file = "uvloop-0.22.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bc5ef13bbc10b5335792360623cc378d52d7e62c2de64660616478c32cd0598e"}, + {file = "uvloop-0.22.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1f38ec5e3f18c8a10ded09742f7fb8de0108796eb673f30ce7762ce1b8550cad"}, + {file = "uvloop-0.22.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3879b88423ec7e97cd4eba2a443aa26ed4e59b45e6b76aabf13fe2f27023a142"}, + {file = "uvloop-0.22.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4baa86acedf1d62115c1dc6ad1e17134476688f08c6efd8a2ab076e815665c74"}, + {file = "uvloop-0.22.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:297c27d8003520596236bdb2335e6b3f649480bd09e00d1e3a99144b691d2a35"}, + {file = "uvloop-0.22.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c1955d5a1dd43198244d47664a5858082a3239766a839b2102a269aaff7a4e25"}, + {file = "uvloop-0.22.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b31dc2fccbd42adc73bc4e7cdbae4fc5086cf378979e53ca5d0301838c5682c6"}, + {file = "uvloop-0.22.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:93f617675b2d03af4e72a5333ef89450dfaa5321303ede6e67ba9c9d26878079"}, + {file = "uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:37554f70528f60cad66945b885eb01f1bb514f132d92b6eeed1c90fd54ed6289"}, + {file = "uvloop-0.22.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:b76324e2dc033a0b2f435f33eb88ff9913c156ef78e153fb210e03c13da746b3"}, + {file = "uvloop-0.22.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:badb4d8e58ee08dad957002027830d5c3b06aea446a6a3744483c2b3b745345c"}, + {file = "uvloop-0.22.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b91328c72635f6f9e0282e4a57da7470c7350ab1c9f48546c0f2866205349d21"}, + {file = "uvloop-0.22.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:daf620c2995d193449393d6c62131b3fbd40a63bf7b307a1527856ace637fe88"}, + {file = "uvloop-0.22.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6cde23eeda1a25c75b2e07d39970f3374105d5eafbaab2a4482be82f272d5a5e"}, + {file = "uvloop-0.22.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:80eee091fe128e425177fbd82f8635769e2f32ec9daf6468286ec57ec0313efa"}, + {file = "uvloop-0.22.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:017bd46f9e7b78e81606329d07141d3da446f8798c6baeec124260e22c262772"}, + {file = "uvloop-0.22.1-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3e5c6727a57cb6558592a95019e504f605d1c54eb86463ee9f7a2dbd411c820"}, + {file = "uvloop-0.22.1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:57df59d8b48feb0e613d9b1f5e57b7532e97cbaf0d61f7aa9aa32221e84bc4b6"}, + {file = "uvloop-0.22.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:55502bc2c653ed2e9692e8c55cb95b397d33f9f2911e929dc97c4d6b26d04242"}, + {file = "uvloop-0.22.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:4a968a72422a097b09042d5fa2c5c590251ad484acf910a651b4b620acd7f193"}, + {file = "uvloop-0.22.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b45649628d816c030dba3c80f8e2689bab1c89518ed10d426036cdc47874dfc4"}, + {file = "uvloop-0.22.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ea721dd3203b809039fcc2983f14608dae82b212288b346e0bfe46ec2fab0b7c"}, + {file = "uvloop-0.22.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ae676de143db2b2f60a9696d7eca5bb9d0dd6cc3ac3dad59a8ae7e95f9e1b54"}, + {file = "uvloop-0.22.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:17d4e97258b0172dfa107b89aa1eeba3016f4b1974ce85ca3ef6a66b35cbf659"}, + {file = "uvloop-0.22.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:05e4b5f86e621cf3927631789999e697e58f0d2d32675b67d9ca9eb0bca55743"}, + {file = "uvloop-0.22.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:286322a90bea1f9422a470d5d2ad82d38080be0a29c4dd9b3e6384320a4d11e7"}, + {file = "uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f"}, ] [package.extras] dev = ["Cython (>=3.0,<4.0)", "setuptools (>=60)"] -docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] -test = ["aiohttp (>=3.10.5)", "flake8 (>=5.0,<6.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=23.0.0,<23.1.0)", "pycodestyle (>=2.9.0,<2.10.0)"] +docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx_rtd_theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] +test = ["aiohttp (>=3.10.5)", "flake8 (>=6.1,<7.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=25.3.0,<25.4.0)", "pycodestyle (>=2.11.0,<2.12.0)"] [[package]] name = "validators" -version = "0.34.0" +version = "0.35.0" description = "Python Data Validation for Humans™" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "validators-0.34.0-py3-none-any.whl", hash = "sha256:c804b476e3e6d3786fa07a30073a4ef694e617805eb1946ceee3fe5a9b8b1321"}, - {file = "validators-0.34.0.tar.gz", hash = "sha256:647fe407b45af9a74d245b943b18e6a816acf4926974278f6dd617778e1e781f"}, + {file = "validators-0.35.0-py3-none-any.whl", hash = "sha256:e8c947097eae7892cb3d26868d637f79f47b4a0554bc6b80065dfe5aac3705dd"}, + {file = "validators-0.35.0.tar.gz", hash = "sha256:992d6c48a4e77c81f1b4daba10d16c3a9bb0dbb79b3a19ea847ff0928e70497a"}, ] [package.extras] @@ -4310,114 +5396,135 @@ crypto-eth-addresses = ["eth-hash[pycryptodome] (>=0.7.0)"] [[package]] name = "virtualenv" -version = "20.25.0" +version = "20.39.1" description = "Virtual Python Environment builder" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3"}, - {file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b"}, + {file = "virtualenv-20.39.1-py3-none-any.whl", hash = "sha256:a00332e0b089ba64edefbf94ef34e6db33f45fe5184df0652cf0b754dcd36190"}, + {file = "virtualenv-20.39.1.tar.gz", hash = "sha256:c551ea1072d7717a273dd9a4a0adad8f45571af134b0f63a12430e85f6ac1c08"}, ] [package.dependencies] distlib = ">=0.3.7,<1" -filelock = ">=3.12.2,<4" +filelock = {version = ">=3.24.2,<4", markers = "python_version >= \"3.10\""} platformdirs = ">=3.9.1,<5" - -[package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] +typing-extensions = {version = ">=4.13.2", markers = "python_version < \"3.11\""} [[package]] name = "watchfiles" -version = "0.24.0" +version = "1.2.0" description = "Simple, modern and high performance file watching and code reload in python." optional = false -python-versions = ">=3.8" -files = [ - {file = "watchfiles-0.24.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:083dc77dbdeef09fa44bb0f4d1df571d2e12d8a8f985dccde71ac3ac9ac067a0"}, - {file = "watchfiles-0.24.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e94e98c7cb94cfa6e071d401ea3342767f28eb5a06a58fafdc0d2a4974f4f35c"}, - {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82ae557a8c037c42a6ef26c494d0631cacca040934b101d001100ed93d43f361"}, - {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:acbfa31e315a8f14fe33e3542cbcafc55703b8f5dcbb7c1eecd30f141df50db3"}, - {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b74fdffce9dfcf2dc296dec8743e5b0332d15df19ae464f0e249aa871fc1c571"}, - {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:449f43f49c8ddca87c6b3980c9284cab6bd1f5c9d9a2b00012adaaccd5e7decd"}, - {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4abf4ad269856618f82dee296ac66b0cd1d71450fc3c98532d93798e73399b7a"}, - {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f895d785eb6164678ff4bb5cc60c5996b3ee6df3edb28dcdeba86a13ea0465e"}, - {file = "watchfiles-0.24.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7ae3e208b31be8ce7f4c2c0034f33406dd24fbce3467f77223d10cd86778471c"}, - {file = "watchfiles-0.24.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2efec17819b0046dde35d13fb8ac7a3ad877af41ae4640f4109d9154ed30a188"}, - {file = "watchfiles-0.24.0-cp310-none-win32.whl", hash = "sha256:6bdcfa3cd6fdbdd1a068a52820f46a815401cbc2cb187dd006cb076675e7b735"}, - {file = "watchfiles-0.24.0-cp310-none-win_amd64.whl", hash = "sha256:54ca90a9ae6597ae6dc00e7ed0a040ef723f84ec517d3e7ce13e63e4bc82fa04"}, - {file = "watchfiles-0.24.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:bdcd5538e27f188dd3c804b4a8d5f52a7fc7f87e7fd6b374b8e36a4ca03db428"}, - {file = "watchfiles-0.24.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2dadf8a8014fde6addfd3c379e6ed1a981c8f0a48292d662e27cabfe4239c83c"}, - {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6509ed3f467b79d95fc62a98229f79b1a60d1b93f101e1c61d10c95a46a84f43"}, - {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8360f7314a070c30e4c976b183d1d8d1585a4a50c5cb603f431cebcbb4f66327"}, - {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:316449aefacf40147a9efaf3bd7c9bdd35aaba9ac5d708bd1eb5763c9a02bef5"}, - {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73bde715f940bea845a95247ea3e5eb17769ba1010efdc938ffcb967c634fa61"}, - {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3770e260b18e7f4e576edca4c0a639f704088602e0bc921c5c2e721e3acb8d15"}, - {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa0fd7248cf533c259e59dc593a60973a73e881162b1a2f73360547132742823"}, - {file = "watchfiles-0.24.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d7a2e3b7f5703ffbd500dabdefcbc9eafeff4b9444bbdd5d83d79eedf8428fab"}, - {file = "watchfiles-0.24.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d831ee0a50946d24a53821819b2327d5751b0c938b12c0653ea5be7dea9c82ec"}, - {file = "watchfiles-0.24.0-cp311-none-win32.whl", hash = "sha256:49d617df841a63b4445790a254013aea2120357ccacbed00253f9c2b5dc24e2d"}, - {file = "watchfiles-0.24.0-cp311-none-win_amd64.whl", hash = "sha256:d3dcb774e3568477275cc76554b5a565024b8ba3a0322f77c246bc7111c5bb9c"}, - {file = "watchfiles-0.24.0-cp311-none-win_arm64.whl", hash = "sha256:9301c689051a4857d5b10777da23fafb8e8e921bcf3abe6448a058d27fb67633"}, - {file = "watchfiles-0.24.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7211b463695d1e995ca3feb38b69227e46dbd03947172585ecb0588f19b0d87a"}, - {file = "watchfiles-0.24.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4b8693502d1967b00f2fb82fc1e744df128ba22f530e15b763c8d82baee15370"}, - {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdab9555053399318b953a1fe1f586e945bc8d635ce9d05e617fd9fe3a4687d6"}, - {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:34e19e56d68b0dad5cff62273107cf5d9fbaf9d75c46277aa5d803b3ef8a9e9b"}, - {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:41face41f036fee09eba33a5b53a73e9a43d5cb2c53dad8e61fa6c9f91b5a51e"}, - {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5148c2f1ea043db13ce9b0c28456e18ecc8f14f41325aa624314095b6aa2e9ea"}, - {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e4bd963a935aaf40b625c2499f3f4f6bbd0c3776f6d3bc7c853d04824ff1c9f"}, - {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c79d7719d027b7a42817c5d96461a99b6a49979c143839fc37aa5748c322f234"}, - {file = "watchfiles-0.24.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:32aa53a9a63b7f01ed32e316e354e81e9da0e6267435c7243bf8ae0f10b428ef"}, - {file = "watchfiles-0.24.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ce72dba6a20e39a0c628258b5c308779b8697f7676c254a845715e2a1039b968"}, - {file = "watchfiles-0.24.0-cp312-none-win32.whl", hash = "sha256:d9018153cf57fc302a2a34cb7564870b859ed9a732d16b41a9b5cb2ebed2d444"}, - {file = "watchfiles-0.24.0-cp312-none-win_amd64.whl", hash = "sha256:551ec3ee2a3ac9cbcf48a4ec76e42c2ef938a7e905a35b42a1267fa4b1645896"}, - {file = "watchfiles-0.24.0-cp312-none-win_arm64.whl", hash = "sha256:b52a65e4ea43c6d149c5f8ddb0bef8d4a1e779b77591a458a893eb416624a418"}, - {file = "watchfiles-0.24.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3d2e3ab79a1771c530233cadfd277fcc762656d50836c77abb2e5e72b88e3a48"}, - {file = "watchfiles-0.24.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327763da824817b38ad125dcd97595f942d720d32d879f6c4ddf843e3da3fe90"}, - {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd82010f8ab451dabe36054a1622870166a67cf3fce894f68895db6f74bbdc94"}, - {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d64ba08db72e5dfd5c33be1e1e687d5e4fcce09219e8aee893a4862034081d4e"}, - {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1cf1f6dd7825053f3d98f6d33f6464ebdd9ee95acd74ba2c34e183086900a827"}, - {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43e3e37c15a8b6fe00c1bce2473cfa8eb3484bbeecf3aefbf259227e487a03df"}, - {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88bcd4d0fe1d8ff43675360a72def210ebad3f3f72cabfeac08d825d2639b4ab"}, - {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:999928c6434372fde16c8f27143d3e97201160b48a614071261701615a2a156f"}, - {file = "watchfiles-0.24.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:30bbd525c3262fd9f4b1865cb8d88e21161366561cd7c9e1194819e0a33ea86b"}, - {file = "watchfiles-0.24.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:edf71b01dec9f766fb285b73930f95f730bb0943500ba0566ae234b5c1618c18"}, - {file = "watchfiles-0.24.0-cp313-none-win32.whl", hash = "sha256:f4c96283fca3ee09fb044f02156d9570d156698bc3734252175a38f0e8975f07"}, - {file = "watchfiles-0.24.0-cp313-none-win_amd64.whl", hash = "sha256:a974231b4fdd1bb7f62064a0565a6b107d27d21d9acb50c484d2cdba515b9366"}, - {file = "watchfiles-0.24.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:ee82c98bed9d97cd2f53bdb035e619309a098ea53ce525833e26b93f673bc318"}, - {file = "watchfiles-0.24.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fd92bbaa2ecdb7864b7600dcdb6f2f1db6e0346ed425fbd01085be04c63f0b05"}, - {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f83df90191d67af5a831da3a33dd7628b02a95450e168785586ed51e6d28943c"}, - {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fca9433a45f18b7c779d2bae7beeec4f740d28b788b117a48368d95a3233ed83"}, - {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b995bfa6bf01a9e09b884077a6d37070464b529d8682d7691c2d3b540d357a0c"}, - {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed9aba6e01ff6f2e8285e5aa4154e2970068fe0fc0998c4380d0e6278222269b"}, - {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5171ef898299c657685306d8e1478a45e9303ddcd8ac5fed5bd52ad4ae0b69b"}, - {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4933a508d2f78099162da473841c652ad0de892719043d3f07cc83b33dfd9d91"}, - {file = "watchfiles-0.24.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:95cf3b95ea665ab03f5a54765fa41abf0529dbaf372c3b83d91ad2cfa695779b"}, - {file = "watchfiles-0.24.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:01def80eb62bd5db99a798d5e1f5f940ca0a05986dcfae21d833af7a46f7ee22"}, - {file = "watchfiles-0.24.0-cp38-none-win32.whl", hash = "sha256:4d28cea3c976499475f5b7a2fec6b3a36208656963c1a856d328aeae056fc5c1"}, - {file = "watchfiles-0.24.0-cp38-none-win_amd64.whl", hash = "sha256:21ab23fdc1208086d99ad3f69c231ba265628014d4aed31d4e8746bd59e88cd1"}, - {file = "watchfiles-0.24.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b665caeeda58625c3946ad7308fbd88a086ee51ccb706307e5b1fa91556ac886"}, - {file = "watchfiles-0.24.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5c51749f3e4e269231510da426ce4a44beb98db2dce9097225c338f815b05d4f"}, - {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82b2509f08761f29a0fdad35f7e1638b8ab1adfa2666d41b794090361fb8b855"}, - {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a60e2bf9dc6afe7f743e7c9b149d1fdd6dbf35153c78fe3a14ae1a9aee3d98b"}, - {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f7d9b87c4c55e3ea8881dfcbf6d61ea6775fffed1fedffaa60bd047d3c08c430"}, - {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:78470906a6be5199524641f538bd2c56bb809cd4bf29a566a75051610bc982c3"}, - {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:07cdef0c84c03375f4e24642ef8d8178e533596b229d32d2bbd69e5128ede02a"}, - {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d337193bbf3e45171c8025e291530fb7548a93c45253897cd764a6a71c937ed9"}, - {file = "watchfiles-0.24.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ec39698c45b11d9694a1b635a70946a5bad066b593af863460a8e600f0dff1ca"}, - {file = "watchfiles-0.24.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2e28d91ef48eab0afb939fa446d8ebe77e2f7593f5f463fd2bb2b14132f95b6e"}, - {file = "watchfiles-0.24.0-cp39-none-win32.whl", hash = "sha256:7138eff8baa883aeaa074359daabb8b6c1e73ffe69d5accdc907d62e50b1c0da"}, - {file = "watchfiles-0.24.0-cp39-none-win_amd64.whl", hash = "sha256:b3ef2c69c655db63deb96b3c3e587084612f9b1fa983df5e0c3379d41307467f"}, - {file = "watchfiles-0.24.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:632676574429bee8c26be8af52af20e0c718cc7f5f67f3fb658c71928ccd4f7f"}, - {file = "watchfiles-0.24.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a2a9891723a735d3e2540651184be6fd5b96880c08ffe1a98bae5017e65b544b"}, - {file = "watchfiles-0.24.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a7fa2bc0efef3e209a8199fd111b8969fe9db9c711acc46636686331eda7dd4"}, - {file = "watchfiles-0.24.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01550ccf1d0aed6ea375ef259706af76ad009ef5b0203a3a4cce0f6024f9b68a"}, - {file = "watchfiles-0.24.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:96619302d4374de5e2345b2b622dc481257a99431277662c30f606f3e22f42be"}, - {file = "watchfiles-0.24.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:85d5f0c7771dcc7a26c7a27145059b6bb0ce06e4e751ed76cdf123d7039b60b5"}, - {file = "watchfiles-0.24.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:951088d12d339690a92cef2ec5d3cfd957692834c72ffd570ea76a6790222777"}, - {file = "watchfiles-0.24.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49fb58bcaa343fedc6a9e91f90195b20ccb3135447dc9e4e2570c3a39565853e"}, - {file = "watchfiles-0.24.0.tar.gz", hash = "sha256:afb72325b74fa7a428c009c1b8be4b4d7c2afedafb2982827ef2156646df2fe1"}, +python-versions = ">=3.10" +files = [ + {file = "watchfiles-1.2.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:bb68bf4df85abebe5efddc53cf2075520f243a59868d9b3973278b23e76962a9"}, + {file = "watchfiles-1.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c16cb06dd17d43b9d185094268459eac92c9538356f050e55b54e82cf700e1d4"}, + {file = "watchfiles-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77a0feab9af4c021c581f695258c642b3d10c5fd4c676e33a0d8606425d82631"}, + {file = "watchfiles-1.2.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a16ffe19bf5cf9f5edaa1ad1dd830c5a816e8feec430c522302ab55483a4b994"}, + {file = "watchfiles-1.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:204f299afcbd65918ab78dbc52626b0ae45e9d8cef403fdbf33ecf9e40eac66e"}, + {file = "watchfiles-1.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11743adfa510bfffebe97659fb280182b5c9b238708f667e866f308c3430dc19"}, + {file = "watchfiles-1.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb72919d93e3a16fc451d3aa3d4b1698423daca1b382d3d959c9ac51297c12a8"}, + {file = "watchfiles-1.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62f042afde2dde21ec1d2c1a74361e804673df86f51e418a999c9acfe671b07"}, + {file = "watchfiles-1.2.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:027ae72bfdfd254862065d8b3e2a815c6ab9b1853ce41e6648ece84afd34a551"}, + {file = "watchfiles-1.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e1cfd51e97e13ff3bd047c140764d277fc9b95b7cb5da59e46a47d167adab310"}, + {file = "watchfiles-1.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:24b2405c0a46738dd9e1cf7135aa5dbdb9d42d024628651b3b13d5117e99f8df"}, + {file = "watchfiles-1.2.0-cp310-cp310-win32.whl", hash = "sha256:8c520725602756229f045b032a1ff33d7ef0f7404189d62f6c2438cb6d8ef6a1"}, + {file = "watchfiles-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:03b14855c6f35539e2d95c442ae9530a75762f1e26567152b9ed05f96534a74d"}, + {file = "watchfiles-1.2.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:704fd259e332e01f9b9c178f4bce9e49027e5587cc2600eeeaf8e76e1c846201"}, + {file = "watchfiles-1.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6543cf55d170003296d185c0af981f3e1311564907e1f4e08671fc7693a890a5"}, + {file = "watchfiles-1.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89d8c2394a065ca86f5d2910ff263ae67c127e1376ccc4f9fc35c71db879f80a"}, + {file = "watchfiles-1.2.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:772b80df316480d894a0e3165fdd19cf77f5d17f9a787f94029465ad0e3529d1"}, + {file = "watchfiles-1.2.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d158cd89df6053823533e06fb1d73c549133bff5f0396170c0e53d9559340717"}, + {file = "watchfiles-1.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d516b3283a758e087841aedb8031549fb41ced08f3db10aa6d2bf32dc042525b"}, + {file = "watchfiles-1.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:53b2290c92e0506d102cd448fbc610d87079553f86caa39d67440856a8b8bba5"}, + {file = "watchfiles-1.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a711b51aec4370d0dcda5b6c09463206f133a5759341d7744b953a7b62e1100e"}, + {file = "watchfiles-1.2.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:e2ca07fa7d89195ec0865d3d285666286740bfa83d83e5cee204043a31ecc165"}, + {file = "watchfiles-1.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e0618518f282c4ebff60f5e5b1247b6d91bb8b9f4476947563a1e74acc66f3c6"}, + {file = "watchfiles-1.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0d191c054d0715c3c95c99df9b8dbf6fd096d8c1e021e8f212e1bd8bc444ccb5"}, + {file = "watchfiles-1.2.0-cp311-cp311-win32.whl", hash = "sha256:9342472aff9b093c5acd4f6d8f70ae0937964ab56542502bcf5579782da69ae8"}, + {file = "watchfiles-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:dbd6c97045dad81227c8d040173da044c1de08de64a5ea8b555da4aee1d5fa22"}, + {file = "watchfiles-1.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:57a2d9fa4fb4c2ecae57b13dfff2c7ab53e21a2ba674fe9f05506680fcdcc0d7"}, + {file = "watchfiles-1.2.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:bc13eb17538be00c874699dc0abe4ee2bc8d50bb1166a6b9e175ef3fd7eb8f26"}, + {file = "watchfiles-1.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2d95ddc1eb6914154253d239089900813f6a767e174b8e6a50e7fdacb7e4236c"}, + {file = "watchfiles-1.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f70d8b291ef6e88d19b1f297a6905ddb978888d9272b0d05e6f53309856bcfc"}, + {file = "watchfiles-1.2.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:56d8641cf834c2836922899105bd3ce3d0dfc69291d52edf0b4d0436829b34c0"}, + {file = "watchfiles-1.2.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2581a94056e55d7d0a31a823ea92bf73749c489ca2285bfdc0fbe6b2bb49d50c"}, + {file = "watchfiles-1.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:41bc1199f7523b3f82843c88cbb979180c949caef0342cf90968f178e5d49b01"}, + {file = "watchfiles-1.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7571e4464cb6e434958f867f7f730b8ab0b75e3f8e5eac0499168486ab3c33a8"}, + {file = "watchfiles-1.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e53a384f76b631c3ae5334ce6a52f0baa3a911eb94a4eac7f160079868b716d5"}, + {file = "watchfiles-1.2.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:d20029a60a71a052a24c4db7673bc4de39ab89adbaccbfb5d67987c5d73f424d"}, + {file = "watchfiles-1.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:2cb93af48550faf1cea04c303107c8b75833de7013e57ce27d3b8d21d8d0f58c"}, + {file = "watchfiles-1.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2995c176de7692b86a2e4c58d9ec718f753150a979cb4a754e2b4ffa38e70906"}, + {file = "watchfiles-1.2.0-cp312-cp312-win32.whl", hash = "sha256:7a2cffd17d27d2ecbb310c2b1d8174f222a5495b1a721894afa88ec11e25b898"}, + {file = "watchfiles-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:f155b3a1b2a5fc89cdc70d47ee5d54e3b75e88efa34982028a35daef9ba00379"}, + {file = "watchfiles-1.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:8fa585ede612ee9f9e91b18bebf9ba11b9ae29a4e3a0d0cf6fca3e382133f0d5"}, + {file = "watchfiles-1.2.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:01ea8d66f0693b9b60a6541c8d10263091ca9a9060d242f3c1f3143f9aad2c98"}, + {file = "watchfiles-1.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7ba0480b9a74af058f43b337e937a451e109295c420916d68ad24e3dc02f5e44"}, + {file = "watchfiles-1.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f34e26a19f91f710c08e0183429f0d1d15df734e6bc78c31e77b9ea9c433658"}, + {file = "watchfiles-1.2.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b4e77f6a55f858504069abd35d336a637555c09bca453dde1ee1e5ada8a6a1fb"}, + {file = "watchfiles-1.2.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0cb4d80e212f116474a545c21c912b445f16bb0cef9e6a73a498164223e14e2f"}, + {file = "watchfiles-1.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b974946a10af379d425e2eef5b62f5c6ebeaccf91d45eaad6f5b27ecd4f91aa0"}, + {file = "watchfiles-1.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86bc13c25a8d1fcd70b51d0ce7c9b65e90de5666fcbfd3e34957cc73ee19aeb5"}, + {file = "watchfiles-1.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca148d73dea36c9763aaa351e4d7a51780ec1584217c45276f4fe8239c768b71"}, + {file = "watchfiles-1.2.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:c525543d91961c6955b2636b308569e84a1d1c5f5f2932041ab9ef46422f43e3"}, + {file = "watchfiles-1.2.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:a204794696ffb8f9b10fba6f7cb5216d42f3b2b71860ccac6b6e42f5f10973b0"}, + {file = "watchfiles-1.2.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:10d86db20695afe7997ac9e1717637d6714a8d0220458c33f3d2061f54cec427"}, + {file = "watchfiles-1.2.0-cp313-cp313-win32.whl", hash = "sha256:eb283ee99e21ad6443c8cdb06ac5b34b1308c329cbdf03fa02b445363714c799"}, + {file = "watchfiles-1.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:a0f27f01bee51861392bb6b7c4fdb290b27d1eb194e9e28788d68102a0e898d9"}, + {file = "watchfiles-1.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:3651aa7058595e9cfb75d35dd5ada2bf9f48a5b8a0f3562821d3e210c507e077"}, + {file = "watchfiles-1.2.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:faea288b6f0ab1902ef08f4ca6de005dccf856c4e0c4f21b8c5fce02d90a1b08"}, + {file = "watchfiles-1.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:01859b11fd9fbca670f4d5da00fbac282cfea9bd67a2125d8b2833a3b5617ea9"}, + {file = "watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fff610d7bb2256a317bb1e96f0d7862c7aa8076733ee5df0fd41bbe76a24a4f4"}, + {file = "watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b141a4891c995a039cd89e9a49e62df1dc8a559a5d1a6e4c7106d16c12777a55"}, + {file = "watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f22943b7770483f6ea0721c6b11d022947a98eb0acae14694de034f4d0d38925"}, + {file = "watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1bc6195825b7dcd217968bb1f801a60fd4c16e8eeab5bedc7fe917d7d5995ab4"}, + {file = "watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4a4b147f5dca2a5d325a06a832fb43f345751adfbc63204aec30e0d9ca965a2"}, + {file = "watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4543579a9bdb0c9560039b4ffddbdb39545707659fbc430ce4c10f3f68d557f9"}, + {file = "watchfiles-1.2.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:20aa0e708b920bde876a4aa82dc7dd6ebea228a63a67cda6632c2fc87b787efa"}, + {file = "watchfiles-1.2.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:d413349d565dab74297f2a63e84a097936be69bf8f3b3801f27f380e32040f44"}, + {file = "watchfiles-1.2.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:f28b2725eb8cce327b9b3ab02415c853011dc55c95832fe90de6bc56f5315f72"}, + {file = "watchfiles-1.2.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:b8c8358484d5fa12ef34f05b7f4168eaf1932f408725ff6d023c33ec17bd79d4"}, + {file = "watchfiles-1.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f04b092229ad2c50126dd3c922c8822e51e605993764a33058d4a791ab42281"}, + {file = "watchfiles-1.2.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a7ce236284f002a156f70add88efe5c70879cccbb658be0822c54b1306fc09d"}, + {file = "watchfiles-1.2.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b9909cc2b48468b575eefa944919e1fe8a36c5849d5c7c168f80a8c1db69398e"}, + {file = "watchfiles-1.2.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a37faaed405c67e28e6be45a1fa4f206ef5a2860f27c237db9fa30704c38242"}, + {file = "watchfiles-1.2.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9649193aa27bd9ff2e80ff29bfaa93085496c7a3a377592823cc58b77ee88add"}, + {file = "watchfiles-1.2.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e4ff8e37f99cf1da89e255e07c9c4b37c214038c4283707bdec308cb1b0ea1f"}, + {file = "watchfiles-1.2.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:054dc20fd2e3132b4c3883b4a00d72fd6e1f56fdaf89fccd12e8057d74cd74d7"}, + {file = "watchfiles-1.2.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:e140ed30ebde76796b686e67c182cff10ea2fbab186fafd1560f74bb5a473a6e"}, + {file = "watchfiles-1.2.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:bb7e52ecf68ba46d22df23467b87cffeb2146908aa523ebfe803019618cfda06"}, + {file = "watchfiles-1.2.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:23282a321c8baf9b3a3c4afff673f9fe65eb7fdc2338d765ccad9d3d1916a5ba"}, + {file = "watchfiles-1.2.0-cp314-cp314-win32.whl", hash = "sha256:c0db965c5f79aa49fe672d297cf1febc5ad149b658594944f49a54a2b96270a7"}, + {file = "watchfiles-1.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:71283b39fd17e5408eb123bd37aeecfd9d54c81fc184421943208aadb879d103"}, + {file = "watchfiles-1.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:c5c19526f4e54a00f2666a6c0e9e40d582c09e865055ea7378bf0009aab857b3"}, + {file = "watchfiles-1.2.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:d73a585accffa5ae39c17264c36ec3166d2fad7000c780f5ef83b2722afb9dd2"}, + {file = "watchfiles-1.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ae99b14c5f21e026e0e9d96f40e07d8570ebee6cafd9d8fc318354606daa7a28"}, + {file = "watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4429f3b105524a10b72c3a819b091c495d2811d419c1e1e8df773a5a5974f831"}, + {file = "watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:43d818978d06062d9b22c4fab2ebe44cf5213d42dc8e62bda8c2760cfa2eeb33"}, + {file = "watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9f732dc58b2dbe69e464ccf8fff7a03b0dd0be439da4c0720d3558527d3d6b4"}, + {file = "watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f200104103feb097de4cab8fe4f5dd18a2026934c7dea98c55a2f5fd6d5a33b"}, + {file = "watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:63ac26eefbf4af1741247d6fb68b11c49a25b2f7413fbd318a83a12aaa9cf666"}, + {file = "watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c4997d4e4a55f0d02b6cde327322daf3a0400e5df6c6b15948994bf72497925"}, + {file = "watchfiles-1.2.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:4c887eba18b7945ac73067a8b4a66f21cd46c2539b2bc68588f7be6c7eb6d26b"}, + {file = "watchfiles-1.2.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:3416ff151bb6b5a8d8d11664974fbef4d9305b9b2957839ab5a270468fd8df30"}, + {file = "watchfiles-1.2.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:0e831a271c035d89789cffc386b6aa1375f39f1cd25eb7ca0997e4970d152fc5"}, + {file = "watchfiles-1.2.0-cp315-cp315-macosx_10_12_x86_64.whl", hash = "sha256:37a6721cdf3f65dbb13aa9503510ccb4451603ac837e44d265d7992a597e1374"}, + {file = "watchfiles-1.2.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:2b37d10b5a63bd4d87e18472d80fa525bd670586fae62e5dd580452764879b65"}, + {file = "watchfiles-1.2.0-cp315-cp315-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a105bc2283f67e8fbec74253ec2d94925de92ed72c0393f1206bf326b7b7b69"}, + {file = "watchfiles-1.2.0-cp315-cp315-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5327989a465505f05cfe06f04fa9d0c2fd5432bb243e10e6f012b1bdca3c8579"}, + {file = "watchfiles-1.2.0-cp315-cp315-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ecb47f183a8025b2aa18b546725c3657e542112ae9c0613a2af79b4fa8d04ad7"}, + {file = "watchfiles-1.2.0-cp315-cp315-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8520a4ab0e37f770afc34459c4f8f7019e153f9124dc101c15538365875d1ab2"}, + {file = "watchfiles-1.2.0-cp315-cp315-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:71cd71740ed2c15211ebb237ced4e39a1cdf6f80566e5fe95428da1626f4fde6"}, + {file = "watchfiles-1.2.0-cp315-cp315-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f88af53d6ddaf72179ef613ddc905e6f4785f712b49b80b3bef9f3525e6194b4"}, + {file = "watchfiles-1.2.0-cp315-cp315-manylinux_2_31_riscv64.whl", hash = "sha256:cee9d5efd929efdac5f7e58f72b3376f676b64050a91c5b99a7094c5b2317488"}, + {file = "watchfiles-1.2.0-cp315-cp315-musllinux_1_1_aarch64.whl", hash = "sha256:b718bf356bbc15e559bd8ef41782b573b8ae0e3f177ab244b440568d7ea02cfb"}, + {file = "watchfiles-1.2.0-cp315-cp315-musllinux_1_1_x86_64.whl", hash = "sha256:922c0e019fe68b3ae392965a766b02a71ba1168c932cebc3733cd52c5fe5b377"}, + {file = "watchfiles-1.2.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:4674d49eb94706dfe666c069fc0a1b646ffcf920473492e209f6d5f60d3f0cc2"}, + {file = "watchfiles-1.2.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:094b9b70103d4e963499bdea001ee3c2697b144cd9ae6218a62c0f89ec9e31db"}, + {file = "watchfiles-1.2.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0ef001f8c25ad0fa9529f914c1600647ecd0f542d11c19b7894768c67b6acb7"}, + {file = "watchfiles-1.2.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a88fc94e647bc4eec523f1caa540258eb71d14278b9daf72fa1e2658a98df0f0"}, + {file = "watchfiles-1.2.0.tar.gz", hash = "sha256:c995fba777f1ea992f090f9236e9284cf7a5d1a0130dd5a3d82c598cacd76838"}, ] [package.dependencies] @@ -4425,19 +5532,19 @@ anyio = ">=3.0.0" [[package]] name = "web3" -version = "7.8.0" +version = "7.16.0" description = "web3: A Python library for interacting with Ethereum" optional = false python-versions = "<4,>=3.8" files = [ - {file = "web3-7.8.0-py3-none-any.whl", hash = "sha256:c8771b3d8772f7104a0462804449beb57d36cef7bd8b411140f95a92fc46b559"}, - {file = "web3-7.8.0.tar.gz", hash = "sha256:712bc9fd6b1ef6e467ee24c25b581e1951cab2cba17f9f548f12587734f2c857"}, + {file = "web3-7.16.0-py3-none-any.whl", hash = "sha256:760b2718c473980d70708c3593d9d28395db4b482f45e38a63a36fa028178f51"}, + {file = "web3-7.16.0.tar.gz", hash = "sha256:b4a75a3fa94fef4d23d502eb3c2244146ef9a1ee0082cf1cb0a91586ba0510c3"}, ] [package.dependencies] aiohttp = ">=3.7.4.post0" eth-abi = ">=5.0.1" -eth-account = ">=0.13.1" +eth-account = ">=0.13.6" eth-hash = {version = ">=0.5.1", extras = ["pycryptodome"]} eth-typing = ">=5.0.0" eth-utils = ">=5.0.0" @@ -4448,192 +5555,211 @@ pywin32 = {version = ">=223", markers = "platform_system == \"Windows\""} requests = ">=2.23.0" types-requests = ">=2.0.0" typing-extensions = ">=4.0.1" -websockets = ">=10.0.0,<14.0.0" +websockets = ">=10.0.0,<16.0.0" [package.extras] -dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "eth-tester[py-evm] (>=0.12.0b1,<0.13.0b1)", "flaky (>=3.7.0)", "hypothesis (>=3.31.2)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "py-geth (>=5.1.0)", "pytest (>=7.0.0)", "pytest-asyncio (>=0.18.1,<0.23)", "pytest-mock (>=1.10)", "pytest-xdist (>=2.4.0)", "setuptools (>=38.6.0)", "sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "tqdm (>4.32)", "twine (>=1.13)", "wheel"] -docs = ["sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=21,<22)"] -test = ["eth-tester[py-evm] (>=0.12.0b1,<0.13.0b1)", "flaky (>=3.7.0)", "hypothesis (>=3.31.2)", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "py-geth (>=5.1.0)", "pytest (>=7.0.0)", "pytest-asyncio (>=0.18.1,<0.23)", "pytest-mock (>=1.10)", "pytest-xdist (>=2.4.0)", "tox (>=4.0.0)"] -tester = ["eth-tester[py-evm] (>=0.12.0b1,<0.13.0b1)", "py-geth (>=5.1.0)"] +dev = ["build (>=0.9.0)", "bump_my_version (>=0.19.0)", "eth-tester[py-evm] (>=0.13.0b1,<0.14.0b1)", "flaky (>=3.7.0)", "hypothesis (>=3.31.2)", "ipython", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "py-geth (>=6.4.0)", "pytest (>=7.0.0)", "pytest-asyncio (>=0.18.1,<0.23)", "pytest-mock (>=1.10)", "pytest-xdist (>=2.4.0)", "setuptools (>=38.6.0)", "sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)", "tox (>=4.0.0)", "tqdm (>4.32)", "twine (>=1.13)", "wheel"] +docs = ["sphinx (>=6.0.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx_rtd_theme (>=1.0.0)", "towncrier (>=24,<25)"] +test = ["eth-tester[py-evm] (>=0.13.0b1,<0.14.0b1)", "flaky (>=3.7.0)", "hypothesis (>=3.31.2)", "mypy (==1.10.0)", "pre-commit (>=3.4.0)", "py-geth (>=6.4.0)", "pytest (>=7.0.0)", "pytest-asyncio (>=0.18.1,<0.23)", "pytest-mock (>=1.10)", "pytest-xdist (>=2.4.0)", "tox (>=4.0.0)"] +tester = ["eth-tester[py-evm] (>=0.13.0b1,<0.14.0b1)", "py-geth (>=6.4.0)"] [[package]] name = "websockets" -version = "12.0" +version = "15.0.1" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" 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-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b"}, + {file = "websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205"}, + {file = "websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a"}, + {file = "websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e"}, + {file = "websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf"}, + {file = "websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb"}, + {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d"}, + {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9"}, + {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c"}, + {file = "websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256"}, + {file = "websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41"}, + {file = "websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431"}, + {file = "websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57"}, + {file = "websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905"}, + {file = "websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562"}, + {file = "websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792"}, + {file = "websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413"}, + {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8"}, + {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3"}, + {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf"}, + {file = "websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85"}, + {file = "websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065"}, + {file = "websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3"}, + {file = "websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665"}, + {file = "websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2"}, + {file = "websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215"}, + {file = "websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5"}, + {file = "websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65"}, + {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe"}, + {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4"}, + {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597"}, + {file = "websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9"}, + {file = "websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7"}, + {file = "websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931"}, + {file = "websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675"}, + {file = "websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151"}, + {file = "websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22"}, + {file = "websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f"}, + {file = "websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8"}, + {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375"}, + {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d"}, + {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4"}, + {file = "websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa"}, + {file = "websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561"}, + {file = "websockets-15.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5f4c04ead5aed67c8a1a20491d54cdfba5884507a48dd798ecaf13c74c4489f5"}, + {file = "websockets-15.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abdc0c6c8c648b4805c5eacd131910d2a7f6455dfd3becab248ef108e89ab16a"}, + {file = "websockets-15.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a625e06551975f4b7ea7102bc43895b90742746797e2e14b70ed61c43a90f09b"}, + {file = "websockets-15.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d591f8de75824cbb7acad4e05d2d710484f15f29d4a915092675ad3456f11770"}, + {file = "websockets-15.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47819cea040f31d670cc8d324bb6435c6f133b8c7a19ec3d61634e62f8d8f9eb"}, + {file = "websockets-15.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac017dd64572e5c3bd01939121e4d16cf30e5d7e110a119399cf3133b63ad054"}, + {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4a9fac8e469d04ce6c25bb2610dc535235bd4aa14996b4e6dbebf5e007eba5ee"}, + {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363c6f671b761efcb30608d24925a382497c12c506b51661883c3e22337265ed"}, + {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2034693ad3097d5355bfdacfffcbd3ef5694f9718ab7f29c29689a9eae841880"}, + {file = "websockets-15.0.1-cp39-cp39-win32.whl", hash = "sha256:3b1ac0d3e594bf121308112697cf4b32be538fb1444468fb0a6ae4feebc83411"}, + {file = "websockets-15.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7643a03db5c95c799b89b31c036d5f27eeb4d259c798e878d6937d71832b1e4"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04"}, + {file = "websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7f493881579c90fc262d9cdbaa05a6b54b3811c2f300766748db79f098db9940"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:47b099e1f4fbc95b701b6e85768e1fcdaf1630f3cbe4765fa216596f12310e2e"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67f2b6de947f8c757db2db9c71527933ad0019737ec374a8a6be9a956786aaf9"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d08eb4c2b7d6c41da6ca0600c077e93f5adcfd979cd777d747e9ee624556da4b"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b826973a4a2ae47ba357e4e82fa44a463b8f168e1ca775ac64521442b19e87f"}, + {file = "websockets-15.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:21c1fa28a6a7e3cbdc171c694398b6df4744613ce9b36b1a498e816787e28123"}, + {file = "websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f"}, + {file = "websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee"}, ] [[package]] name = "yarl" -version = "1.18.3" +version = "1.24.2" description = "Yet another URL library" optional = false -python-versions = ">=3.9" -files = [ - {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34"}, - {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7"}, - {file = "yarl-1.18.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:602d98f2c2d929f8e697ed274fbadc09902c4025c5a9963bf4e9edfc3ab6f7ed"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c654d5207c78e0bd6d749f6dae1dcbbfde3403ad3a4b11f3c5544d9906969dde"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5094d9206c64181d0f6e76ebd8fb2f8fe274950a63890ee9e0ebfd58bf9d787b"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35098b24e0327fc4ebdc8ffe336cee0a87a700c24ffed13161af80124b7dc8e5"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3236da9272872443f81fedc389bace88408f64f89f75d1bdb2256069a8730ccc"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2c08cc9b16f4f4bc522771d96734c7901e7ebef70c6c5c35dd0f10845270bcd"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80316a8bd5109320d38eef8833ccf5f89608c9107d02d2a7f985f98ed6876990"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c1e1cc06da1491e6734f0ea1e6294ce00792193c463350626571c287c9a704db"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fea09ca13323376a2fdfb353a5fa2e59f90cd18d7ca4eaa1fd31f0a8b4f91e62"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e3b9fd71836999aad54084906f8663dffcd2a7fb5cdafd6c37713b2e72be1760"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:757e81cae69244257d125ff31663249b3013b5dc0a8520d73694aed497fb195b"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b1771de9944d875f1b98a745bc547e684b863abf8f8287da8466cf470ef52690"}, - {file = "yarl-1.18.3-cp310-cp310-win32.whl", hash = "sha256:8874027a53e3aea659a6d62751800cf6e63314c160fd607489ba5c2edd753cf6"}, - {file = "yarl-1.18.3-cp310-cp310-win_amd64.whl", hash = "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8"}, - {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069"}, - {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193"}, - {file = "yarl-1.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a"}, - {file = "yarl-1.18.3-cp311-cp311-win32.whl", hash = "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1"}, - {file = "yarl-1.18.3-cp311-cp311-win_amd64.whl", hash = "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5"}, - {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50"}, - {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576"}, - {file = "yarl-1.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285"}, - {file = "yarl-1.18.3-cp312-cp312-win32.whl", hash = "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2"}, - {file = "yarl-1.18.3-cp312-cp312-win_amd64.whl", hash = "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477"}, - {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb"}, - {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa"}, - {file = "yarl-1.18.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8"}, - {file = "yarl-1.18.3-cp313-cp313-win32.whl", hash = "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d"}, - {file = "yarl-1.18.3-cp313-cp313-win_amd64.whl", hash = "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c"}, - {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:61e5e68cb65ac8f547f6b5ef933f510134a6bf31bb178be428994b0cb46c2a04"}, - {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe57328fbc1bfd0bd0514470ac692630f3901c0ee39052ae47acd1d90a436719"}, - {file = "yarl-1.18.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a440a2a624683108a1b454705ecd7afc1c3438a08e890a1513d468671d90a04e"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09c7907c8548bcd6ab860e5f513e727c53b4a714f459b084f6580b49fa1b9cee"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4f6450109834af88cb4cc5ecddfc5380ebb9c228695afc11915a0bf82116789"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9ca04806f3be0ac6d558fffc2fdf8fcef767e0489d2684a21912cc4ed0cd1b8"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77a6e85b90a7641d2e07184df5557132a337f136250caafc9ccaa4a2a998ca2c"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6333c5a377c8e2f5fae35e7b8f145c617b02c939d04110c76f29ee3676b5f9a5"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0b3c92fa08759dbf12b3a59579a4096ba9af8dd344d9a813fc7f5070d86bbab1"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:4ac515b860c36becb81bb84b667466885096b5fc85596948548b667da3bf9f24"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:045b8482ce9483ada4f3f23b3774f4e1bf4f23a2d5c912ed5170f68efb053318"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:a4bb030cf46a434ec0225bddbebd4b89e6471814ca851abb8696170adb163985"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:54d6921f07555713b9300bee9c50fb46e57e2e639027089b1d795ecd9f7fa910"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1d407181cfa6e70077df3377938c08012d18893f9f20e92f7d2f314a437c30b1"}, - {file = "yarl-1.18.3-cp39-cp39-win32.whl", hash = "sha256:ac36703a585e0929b032fbaab0707b75dc12703766d0b53486eabd5139ebadd5"}, - {file = "yarl-1.18.3-cp39-cp39-win_amd64.whl", hash = "sha256:ba87babd629f8af77f557b61e49e7c7cac36f22f871156b91e10a6e9d4f829e9"}, - {file = "yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b"}, - {file = "yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1"}, +python-versions = ">=3.10" +files = [ + {file = "yarl-1.24.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5249a113065c2b7a958bc699759e359cd61cfc81e3069662208f48f191b7ed12"}, + {file = "yarl-1.24.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7f4425fa244fbf530b006d0c5f79ce920114cfff5b4f5f6056e669f8e160fdc0"}, + {file = "yarl-1.24.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:15c0b5e49d3c44e2a0b93e6a49476c5edad0a7686b92c395765a7ea775572a75"}, + {file = "yarl-1.24.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:246d32a53a947c8f0189f5d699cbd4c7036de45d9359e13ba238d1239678c727"}, + {file = "yarl-1.24.2-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:64480fb3e4d4ed9ed71c48a91a477384fc342a50ca30071d2f8a88d51d9c9413"}, + {file = "yarl-1.24.2-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:349de4701dc3760b6e876628423a8f147ef4f5599d10aba1e10702075d424ed9"}, + {file = "yarl-1.24.2-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d162677af8d5d3d6ebab8394b021f4d041ac107a4b705873148a77a49dc9e1b2"}, + {file = "yarl-1.24.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f5f5c6ec23a9043f2d139cc072f53dd23168d202a334b9b2fda8de4c3e890d90"}, + {file = "yarl-1.24.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:60de6742447fbbf697f16f070b8a443f1b5fe6ca3826fbef9fe70ecd5328e643"}, + {file = "yarl-1.24.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:acf93187c3710e422368eb768aee98db551ec7c85adc250207a95c16548ab7ac"}, + {file = "yarl-1.24.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:f4b0352fd41fd34b6651934606268816afd6914d09626f9bcbbf018edb0afb3f"}, + {file = "yarl-1.24.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:6b208bb939099b4b297438da4e9b25357f0b1c791888669b963e45b203ea9f36"}, + {file = "yarl-1.24.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:4b85b8825e631295ff4bc8943f7471d54c533a9360bbe15ebb38e018b555bb8a"}, + {file = "yarl-1.24.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e26acf20c26cb4fefc631fdb75aca2a6b8fa8b7b5d7f204fb6a8f1e63c706f53"}, + {file = "yarl-1.24.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:819ca24f8eafcfb683c1bd5f44f2f488cea1274eb8944731ffd2e1f10f619342"}, + {file = "yarl-1.24.2-cp310-cp310-win_amd64.whl", hash = "sha256:5cb0f995a901c36be096ccbf4c673591c2faabbe96279598ffaec8c030f85bf4"}, + {file = "yarl-1.24.2-cp310-cp310-win_arm64.whl", hash = "sha256:f408eace7e22a68b467a0562e0d27d322f91fe3eaaa6f466b962c6cfaea9fa39"}, + {file = "yarl-1.24.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:36348bebb147b83818b9d7e673ea4debc75970afc6ffdc7e3975ad05ce5a58c1"}, + {file = "yarl-1.24.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a97e42c8a2233f2f279ecadd9e4a037bcb5d813b78435e8eedd4db5a9e9708c"}, + {file = "yarl-1.24.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8d027d56f1035e339d1001ac33eceab5b2ec8e42e449787bb75e289fb9a5cd1d"}, + {file = "yarl-1.24.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a6377060e7927187a42b7eb202090cbe2b34933a4eeaf90e3bd9e33432e5cae"}, + {file = "yarl-1.24.2-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:17076578bce0049a5ce57d14ad1bded391b68a3b213e9b81b0097b090244999a"}, + {file = "yarl-1.24.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:50713f1d4d6be6375bb178bb43d140ee1acb8abe589cd723320b7925a275be1e"}, + {file = "yarl-1.24.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:34263e2fa8fb5bb63a0d97706cda38edbad62fddb58c7f12d6acbc092812aa50"}, + {file = "yarl-1.24.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:49016d82f032b1bd1e10b01078a7d29ae71bf468eeae0ea22df8bab691e60003"}, + {file = "yarl-1.24.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3f6d2c216318f8f32038ca3f72501ba08536f0fd18a36e858836b121b2deed9f"}, + {file = "yarl-1.24.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:08d3a33218e0c64393e7610284e770409a9c31c429b078bcb24096ed0a783b8f"}, + {file = "yarl-1.24.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:5d699376c4ca3cba49bbfae3a05b5b70ded572937171ce1e0b8d87118e2ba294"}, + {file = "yarl-1.24.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a1cab588b4fa14bea2e55ebea27478adfb05372f47573738e1acc4a36c0b05d2"}, + {file = "yarl-1.24.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:ec87ccc31bd21db7ad009d8572c127c1000f268517618a4cc09adba3c2a7f21c"}, + {file = "yarl-1.24.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d1dd47a22843b212baa8d74f37796815d43bd046b42a0f41e9da433386c3136b"}, + {file = "yarl-1.24.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7b54b9c67c2b06bd7b9a77253d242124b9c95d2c02def5a1144001ee547dd9d5"}, + {file = "yarl-1.24.2-cp311-cp311-win_amd64.whl", hash = "sha256:f8fdbcff8b2c7c9284e60c196f693588598ddcee31e11c18e14949ce44519d45"}, + {file = "yarl-1.24.2-cp311-cp311-win_arm64.whl", hash = "sha256:b32c37a7a337e90822c45797bf3d79d60875cfcccd3ecc80e9f453d87026c122"}, + {file = "yarl-1.24.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b975866c184564c827e0877380f0dae57dcca7e52782128381b72feff6dfceb8"}, + {file = "yarl-1.24.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3b075301a2836a0e297b1b658cb6d6135df535d62efefdd60366bd589c2c82f2"}, + {file = "yarl-1.24.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8ae44649b00947634ab0dab2a374a638f52923a6e67083f2c156cd5cbd1a881d"}, + {file = "yarl-1.24.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:507cc19f0b45454e2d6dcd62ff7d062b9f77a2812404e62dbdaec05b50faa035"}, + {file = "yarl-1.24.2-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c4c17bad5a530912d2111825d3f05e89bab2dd376aaa8cbc77e449e6db63e576"}, + {file = "yarl-1.24.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f5f0cbb112838a4a293985b6ed73948a547dadcc1ba6d2089938e7abdedceef8"}, + {file = "yarl-1.24.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ec8356b8a6afcf81fc7aeeef13b1ff7a49dec00f313394bbb9e83830d32ccd7"}, + {file = "yarl-1.24.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7e7ebcdef69dec6c6451e616f32b622a6d4a2e92b445c992f7c8e5274a6bbc4c"}, + {file = "yarl-1.24.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:47a55d6cf6db2f401017a9e96e5288844e5051911fb4e0c8311a3980f5e59a7d"}, + {file = "yarl-1.24.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3065657c80a2321225e804048597ad55658a7e76b32d6f5ee4074d04c50401db"}, + {file = "yarl-1.24.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:cb84b80d88e19ede158619b80813968713d8d008b0e2497a576e6a0557d50712"}, + {file = "yarl-1.24.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:990de4f680b1c217e77ff0d6aa0029f9eb79889c11fb3e9a3942c7eba29c1996"}, + {file = "yarl-1.24.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:abb8ec0323b80161e3802da3150ef660b41d0e9be2048b76a363d93eee992c2b"}, + {file = "yarl-1.24.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e7977781f83638a4c73e0f88425563d70173e0dfd90ac006a45c65036293ee3c"}, + {file = "yarl-1.24.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e30dd55825dc554ec5b66a94953b8eda8745926514c5089dfcacecb9c99b5bd1"}, + {file = "yarl-1.24.2-cp312-cp312-win_amd64.whl", hash = "sha256:7dafe10c12ddd4d120d528c4b5599c953bd7b12845347d507b95451195bb6cad"}, + {file = "yarl-1.24.2-cp312-cp312-win_arm64.whl", hash = "sha256:044a09d8401fcf8681977faef6d286b8ade1e2d2e9dceda175d1cfa5ca496f30"}, + {file = "yarl-1.24.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:491ac9141decf49ee8030199e1ee251cdff0e131f25678817ff6aa5f837a3536"}, + {file = "yarl-1.24.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e89418f65eda18f99030386305bd44d7d504e328a7945db1ead514fbe03a0607"}, + {file = "yarl-1.24.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cdfcce633b4a4bb8281913c57fcafd4b5933fbc19111a5e3930bbd299d6102f1"}, + {file = "yarl-1.24.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:863297ddede92ee49024e9a9b11ecb59f310ca85b60d8537f56bed9bbb5b1986"}, + {file = "yarl-1.24.2-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:374423f70754a2c96942ede36a29d37dc6b0cb8f92f8d009ddf3ed78d3da5488"}, + {file = "yarl-1.24.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:33a29b5d00ccbf3219bb3e351d7875739c19481e030779f48cc46a7a71681a9b"}, + {file = "yarl-1.24.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a9532c57211730c515341af11fef6e9b61d157487272a096d0c04da445642592"}, + {file = "yarl-1.24.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:91e72cf093fd833483a97ee648e0c053c7c629f51ff4a0e7edd84f806b0c5617"}, + {file = "yarl-1.24.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b3177bc0a768ef3bacceb4f272632990b7bea352f1b2f1eee9d6d6ff16516f92"}, + {file = "yarl-1.24.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e196952aacaf3b232e265ff02980b64d483dc0972bd49bcb061171ff22ac203a"}, + {file = "yarl-1.24.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:204e7a61ce99919c0de1bf904ab5d7aa188a129ea8f690a8f76cfb6e2844dc44"}, + {file = "yarl-1.24.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b156914620f0b9d78dc1adb3751141daee561cfec796088abb89ed49d220f1a"}, + {file = "yarl-1.24.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:8372a2b976cf70654b2be6619ab6068acabb35f724c0fda7b277fbf53d66a5cf"}, + {file = "yarl-1.24.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f9a1e9b622ca284143aab5d885848686dcd85453bb1ca9abcdb7503e64dc0056"}, + {file = "yarl-1.24.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:810e19b685c8c3c5862f6a38160a1f4e4c0916c9390024ec347b6157a45a0992"}, + {file = "yarl-1.24.2-cp313-cp313-win_amd64.whl", hash = "sha256:7d37fb7c38f2b6edab0f845c4f85148d4c44204f52bc127021bd2bc9fdbf1656"}, + {file = "yarl-1.24.2-cp313-cp313-win_arm64.whl", hash = "sha256:1e831894be7c2954240e49791fa4b50c05a0dc881de2552cfe3ffd8631c7f461"}, + {file = "yarl-1.24.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:f9312b3c02d9b3d23840f67952913c9c8721d7f1b7db305289faefa878f364c2"}, + {file = "yarl-1.24.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a4f4d6cd615823bfc7fb7e9b5987c3f41666371d870d51058f77e2680fbe9630"}, + {file = "yarl-1.24.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0c3063e5c0a8e8e62fae6c2596fa01da1561e4cd1da6fec5789f5cf99a8aefd8"}, + {file = "yarl-1.24.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fecd17873a096036c1c87ab3486f1aef7f269ada7f23f7f856f93b1cc7744f14"}, + {file = "yarl-1.24.2-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a46d1ab4ba4d32e6dc80daf8a28ce0bd83d08df52fbc32f3e288663427734535"}, + {file = "yarl-1.24.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:73e68edf6dfd5f73f9ca127d84e2a6f9213c65bdffb736bda19524c0564fcd14"}, + {file = "yarl-1.24.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a296ca617f2d25fbceafb962b88750d627e5984e75732c712154d058ae8d79a3"}, + {file = "yarl-1.24.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51b2cf5ec89a8b8470177641ed62a3ba22d74e1e898e06ad53aa77972487208"}, + {file = "yarl-1.24.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:310fc687f7b2044ec54e372c8cbe923bb88f5c37bded0d3079e5791c2fc3cf50"}, + {file = "yarl-1.24.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:297a2fe352ecf858b30a98f87948746ec16f001d279f84aebdbd3bd965e2f1bd"}, + {file = "yarl-1.24.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2a263e76b97bc42bdcd7c5f4953dec1f7cd62a1112fa7f869e57255229390d67"}, + {file = "yarl-1.24.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:822519b64cf0b474f1a0aaef1dc621438ea46bb77c94df97a5b4d213a7d8a8b1"}, + {file = "yarl-1.24.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:b6067060d9dc594899ba83e6db6c48c68d1e494a6dab158156ed86977ca7bcb1"}, + {file = "yarl-1.24.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:0063adad533e57171b79db3943b229d40dfafeeee579767f96541f106bac5f1b"}, + {file = "yarl-1.24.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ee8e3fb34513e8dc082b586ef4910c98335d43a6fab688cd44d4851bacfce3e8"}, + {file = "yarl-1.24.2-cp314-cp314-win_amd64.whl", hash = "sha256:afb00d7fd8e0f285ca29a44cc50df2d622ff2f7a6d933fa641577b5f9d5f3db0"}, + {file = "yarl-1.24.2-cp314-cp314-win_arm64.whl", hash = "sha256:68cf6eacd6028ef1142bc4b48376b81566385ca6f9e7dde3b0fa91be08ffcb57"}, + {file = "yarl-1.24.2-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:221ce1dd921ac4f603957f17d7c18c5cc0797fbb52f156941f92e04605d1d67b"}, + {file = "yarl-1.24.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5f3224db28173a00d7afacdee07045cc4673dfab2b15492c7ae10deddbece761"}, + {file = "yarl-1.24.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c557165320d6244ebe3a02431b2a201a20080e02f41f0cfa0ccc47a183765da8"}, + {file = "yarl-1.24.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:904065e6e85b1fa54d0d87438bd58c14c0bad97aad654ad1077fd9d87e8478ed"}, + {file = "yarl-1.24.2-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8cec2a38d70edc10e0e856ceda886af5327a017ccbde8e1de1bd44d300357543"}, + {file = "yarl-1.24.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e7484b9361ed222ee1ca5b4337aa4cbdcc4618ce5aff57d9ef1582fd95893fc0"}, + {file = "yarl-1.24.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:84f9670b89f34db07f81e53aee83e0b938a3412329d51c8f922488be7fcc4024"}, + {file = "yarl-1.24.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:abb2759733d63a28b4956500a5dd57140f26486c92b2caedfb964ab7d9b79dbf"}, + {file = "yarl-1.24.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:081c2bf54efe03774d0311172bc04fedf9ca01e644d4cd8c805688e527209bdc"}, + {file = "yarl-1.24.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:86746bef442aa479107fe28132e1277237f9c24c2f00b0b0cf22b3ee0904f2bb"}, + {file = "yarl-1.24.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:2d07d21d0bc4b17558e8de0b02fbfdf1e347d3bb3699edd00bb92e7c57925420"}, + {file = "yarl-1.24.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:4fb1ac3fc5fecd8ae7453ea237e4d22b49befa70266dfe1629924245c21a0c7f"}, + {file = "yarl-1.24.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:4da31a5512ed1729ca8d8aacde3f7faeb8843cde3165d6bcf7f88f74f17bb8aa"}, + {file = "yarl-1.24.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:533ded4dceb5f1f3da7906244f4e82cf46cfd40d84c69a1faf5ac506aa65ecbe"}, + {file = "yarl-1.24.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7b3a85525f6e7eeabcfdd372862b21ee1915db1b498a04e8bf0e389b607ff0bd"}, + {file = "yarl-1.24.2-cp314-cp314t-win_amd64.whl", hash = "sha256:a7624b1ca46ca5d7b864ef0d2f8efe3091454085ee1855b4e992314529972215"}, + {file = "yarl-1.24.2-cp314-cp314t-win_arm64.whl", hash = "sha256:e434a45ce2e7a947f951fc5a8944c8cc080b7e59f9c50ae80fd39107cf88126d"}, + {file = "yarl-1.24.2-py3-none-any.whl", hash = "sha256:2783d9226db8797636cd6896e4de81feed252d1db72265686c9558d97a4d94b9"}, + {file = "yarl-1.24.2.tar.gz", hash = "sha256:9ac374123c6fd7abf64d1fec93962b0bd4ee2c19751755a762a72dd96c0378f8"}, ] [package.dependencies] idna = ">=2.0" multidict = ">=4.0" -propcache = ">=0.2.0" +propcache = ">=0.2.1" [metadata] lock-version = "2.0" python-versions = "^3.10, <3.13" -content-hash = "7b255d62870b43bd42bf9b686e94e5dbbda9929f4a503d6b5e6e91c8ca2627f4" +content-hash = "115608e5d541b2c820a1d6ae0ea554831bb7f1f654476614869a21b0efc6795a" diff --git a/packages/examples/cvat/recording-oracle/pyproject.toml b/packages/examples/cvat/recording-oracle/pyproject.toml index b51dab8f05..7082c9dc08 100644 --- a/packages/examples/cvat/recording-oracle/pyproject.toml +++ b/packages/examples/cvat/recording-oracle/pyproject.toml @@ -3,44 +3,48 @@ name = "recording-oracle" version = "0.1.0" description = "An example of recording with with CVAT as an annotation instrument" authors = ["Sergey Dzeranov ", "Marius Hamacher "] -readme = "README.md" -packages = [{include = "recording_oracle"}] +package-mode = false [tool.poetry.dependencies] python = "^3.10, <3.13" -fastapi = {version = "^0.115.4", extras = ["standard"]} +fastapi = {version = "~0.136.0", extras = ["standard"]} # <0.137: avoids the alpha router refactor (breaks fastapi-pagination) uvicorn = ">=0.32.1" # post https://github.com/encode/uvicorn/pull/2397, where using several workers was fixed. Read more https://github.com/encode/uvicorn/discussions/2450 python-dotenv = "^1.0.0" SQLAlchemy = "^2.0.17" psycopg2 = "^2.9.6" APScheduler = "^3.10.1" alembic = "^1.11.1" -pydantic = ">=2.6.1,<2.7.0" -httpx = "^0.24.1" +pydantic = "^2.9.0" +httpx = "0.28.1" # transitive for fastapi, pinned to the last known secure release +httpx2 = "^2.7.0" # httpx gone, the successor numpy = "^1.25.2" boto3 = "^1.28.40" google-cloud-storage = "^2.14.0" datumaro = {git = "https://github.com/cvat-ai/datumaro.git", rev = "ff83c00c2c1bc4b8fdfcc55067fcab0a9b5b6b11"} hexbytes = ">=1.2.0" # required for to_0x_hex() function -starlette = ">=0.40.0" # avoid the vulnerability with multipart/form-data -cvat-sdk = "2.37.0" +starlette = ">=1.3.1" # avoid the vulnerability with multipart/form-data +cvat-sdk = "2.70.0" cryptography = "<44.0.0" # human-protocol-sdk -> pgpy dep requires cryptography < 45 human-protocol-sdk = "^7.3.1" +strenum = "^0.4.15" +audio-qe = {path = "libs/audio_qe", develop = true} [tool.poetry.group.dev.dependencies] -pytest = "^7.4.0" -pre-commit = "^3.3.3" -ruff = "^0.6.0" +pytest = "^9.0.0" +pre-commit = "^4.6.0" +ruff = "^0.15.21" +virtualenv = "<21" # 21.x drops APIs that poetry's build isolation (local audio-qe pkg) relies on [tool.ruff] line-length = 100 target-version = "py310" +extend-exclude = ["libs/"] [tool.ruff.lint] select = ["ALL"] unfixable = [ - "RUF005", # messes up concantenation with numpy structures + "RUF005", # messes up concatenation with numpy structures ] ignore = [ "W191", # Rules conflicting with ruff format (https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules) @@ -57,12 +61,10 @@ ignore = [ "COM819", # | "ISC001", # | "ISC002", # | - "ANN101", # Method args annotations (mypy will take care of that) - "ANN001", # | + "ANN001", # Method args annotations (mypy will take care of that) "ANN202", # | "ANN201", # | "ANN401", # | - "ANN102", # | "RUF001", # Allow cyrillic letters in comments "B904", # Raise from: modern pythons preserve previous exceptions @@ -109,6 +111,11 @@ ignore = [ "PTH119", # `os.path.basename()` should be replaced by `Path.name` "PTH122", # `os.path.splitext()` should be replaced by `Path.suffix`, `Path.stem`, and `Path.parent` "PTH207", # Replace `glob` with `Path.glob` or `Path.rglob` + "RET505", # Unnecessary elif/else statements after/before raise/return. + "PLC0415", # import-outside-top-level + "INP001", # implicit-namespace-package (app is not packaged; package-mode = false) + "FBT001", # boolean-typed positional argument + "DTZ901", # datetime.min/max without tzinfo ] @@ -120,6 +127,8 @@ ignore = [ "ANN001", # | "ANN003", # | "ARG001", # | + "ARG002", # Allow unused args in test doubles mirroring real signatures + "RET504", # Allow assign-before-return for readability in tests "FBT001", # Allow bool-annotated positional args in functions "SLF001", # Allow private attrs access "PLR2004", # Allow magic values @@ -144,6 +153,11 @@ forced-separate = ["tests"] [tool.ruff.lint.flake8-tidy-imports] ban-relative-imports = "all" +[tool.ruff.lint.flake8-type-checking] +# pydantic models evaluate annotations at runtime, so imports used only in their field types must +# stay at runtime +runtime-evaluated-base-classes = ["pydantic.BaseModel"] + [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" diff --git a/packages/examples/cvat/recording-oracle/src/chain/escrow.py b/packages/examples/cvat/recording-oracle/src/chain/escrow.py index e0955548a7..5885288fa9 100644 --- a/packages/examples/cvat/recording-oracle/src/chain/escrow.py +++ b/packages/examples/cvat/recording-oracle/src/chain/escrow.py @@ -1,6 +1,6 @@ import json -import httpx +import httpx2 from human_protocol_sdk.constants import ChainId, Status from human_protocol_sdk.encryption import Encryption, EncryptionUtils from human_protocol_sdk.escrow import EscrowClient, EscrowData, EscrowUtils @@ -18,7 +18,7 @@ class ManifestNotAvailableError(Exception): def _get_manifest_content(manifest: str) -> str: if validate_url(manifest): try: - response = httpx.get(manifest, follow_redirects=True) + response = httpx2.get(manifest, follow_redirects=True) response.raise_for_status() except Exception as e: raise ManifestNotAvailableError( diff --git a/packages/examples/cvat/recording-oracle/src/core/manifest/__init__.py b/packages/examples/cvat/recording-oracle/src/core/manifest/__init__.py new file mode 100644 index 0000000000..5d91f29f36 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/src/core/manifest/__init__.py @@ -0,0 +1,38 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + +from src.core.manifest import v1, v2 +from src.core.manifest.base import ManifestBase + +if TYPE_CHECKING: + from src.core.tasks import TaskTypes + +__all__ = [ + "ManifestBase", + "get_manifest_task_type", + "parse_manifest", + "v1", + "v2", +] + + +def parse_manifest(manifest: Any) -> ManifestBase: + if isinstance(manifest, dict): + version = manifest.get("version") + else: + version = getattr(manifest, "version", None) + + if version == 2: + return v2.JobManifest.model_validate(manifest) + else: + return v1.JobManifest.model_validate(manifest) + + +def get_manifest_task_type(manifest: ManifestBase) -> TaskTypes: + if isinstance(manifest, v1.JobManifest): + return manifest.annotation.type + if isinstance(manifest, v2.JobManifest): + return manifest.job_type + + raise NotImplementedError(f"Unknown manifest version '{manifest.version}'") diff --git a/packages/examples/cvat/recording-oracle/src/core/manifest/base.py b/packages/examples/cvat/recording-oracle/src/core/manifest/base.py new file mode 100644 index 0000000000..5c14e1bc11 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/src/core/manifest/base.py @@ -0,0 +1,6 @@ +from typing import Protocol, runtime_checkable + + +@runtime_checkable +class ManifestBase(Protocol): + version: int diff --git a/packages/examples/cvat/exchange-oracle/src/core/manifest.py b/packages/examples/cvat/recording-oracle/src/core/manifest/shared.py similarity index 50% rename from packages/examples/cvat/exchange-oracle/src/core/manifest.py rename to packages/examples/cvat/recording-oracle/src/core/manifest/shared.py index 4a0f7a81c8..1a61fc3774 100644 --- a/packages/examples/cvat/exchange-oracle/src/core/manifest.py +++ b/packages/examples/cvat/recording-oracle/src/core/manifest/shared.py @@ -1,14 +1,11 @@ -from decimal import Decimal -from enum import Enum from typing import Annotated, Any, Literal -from pydantic import AnyUrl, BaseModel, Field, model_validator +from pydantic import BaseModel, Field, model_validator -from src.core.types import TaskTypes -from src.utils.enums import BetterEnumMeta +from src.utils.enums import BetterEnumMeta, StrEnum -class BucketProviders(str, Enum): +class BucketProviders(StrEnum): aws = "AWS" gcs = "GCS" @@ -34,28 +31,14 @@ class GcsBucketUrl(BucketUrlBase, BaseModel): BucketUrl = Annotated[AwsBucketUrl | GcsBucketUrl, Field(discriminator="provider")] -class DataInfo(BaseModel): - data_url: AnyUrl | BucketUrl - "Bucket URL, AWS S3 | GCS, virtual-hosted-style access" - # https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-bucket-intro.html - - points_url: AnyUrl | BucketUrl | None = None - "A path to an archive with a set of points in COCO Keypoints format, " - "which provides information about all objects on images" - - boxes_url: AnyUrl | BucketUrl | None = None - "A path to an archive with a set of boxes in COCO Instances format, " - "which provides information about all objects on images" - - -class LabelTypes(str, Enum, metaclass=BetterEnumMeta): +class LabelTypes(StrEnum, metaclass=BetterEnumMeta): plain = "plain" skeleton = "skeleton" class LabelInfoBase(BaseModel): name: str = Field(min_length=1) - # https://opencv.github.io/cvat/docs/api_sdk/sdk/reference/models/label/ + # https://docs.cvat.ai/docs/api_sdk/sdk/reference/models/label/ type: LabelTypes = LabelTypes.plain @@ -119,67 +102,3 @@ def validate_type(cls, values: dict[str, Any]) -> dict[str, Any]: LabelInfo = Annotated[PlainLabelInfo | SkeletonLabelInfo, Field(discriminator="type")] - - -class AnnotationInfo(BaseModel): - type: TaskTypes - - labels: list[LabelInfo] = Field(min_length=1) - "Label declarations with accepted annotation types" - - description: str = "" - "Brief task description" - - user_guide: str = "" - "User guide in markdown format" - - job_size: int = 10 - "Frames per job, validation frames are not included" - - qualifications: list[str] = Field(default_factory=list) - "A list of annotator qualifications required for participation" - - @model_validator(mode="before") - @classmethod - def validate_label_type(cls, values: dict[str, Any]) -> dict[str, Any]: - if not isinstance(values, dict): - raise NotImplementedError - - default_label_type = LabelTypes.plain - if values["type"] == TaskTypes.image_skeletons_from_boxes: - default_label_type = LabelTypes.skeleton - - # Add default value for labels, if none provided. - # pydantic can't do this for tagged unions - try: - labels = values["labels"] - for label_info in labels: - label_info["type"] = label_info.get("type", default_label_type) - except KeyError: - pass - - return values - - -class ValidationInfo(BaseModel): - min_quality: float = Field(ge=0) - "Minimal accepted annotation accuracy" - - val_size: int = Field(default=2, gt=0) - "Validation frames per job" - - gt_url: AnyUrl | BucketUrl - "URL to the archive with Ground Truth annotations, the format is COCO keypoints" - - -class TaskManifest(BaseModel): - data: DataInfo - annotation: AnnotationInfo - validation: ValidationInfo - - job_bounty: Decimal = Field(ge=0) - "Assignment bounty, a decimal value in HMT" - - -def parse_manifest(manifest: Any) -> TaskManifest: - return TaskManifest.model_validate(manifest) diff --git a/packages/examples/cvat/recording-oracle/src/core/manifest/v1.py b/packages/examples/cvat/recording-oracle/src/core/manifest/v1.py new file mode 100644 index 0000000000..1b774ebd5f --- /dev/null +++ b/packages/examples/cvat/recording-oracle/src/core/manifest/v1.py @@ -0,0 +1,83 @@ +from decimal import Decimal +from typing import Any, Literal + +from pydantic import AnyUrl, BaseModel, Field, model_validator + +from src.core.manifest.shared import BucketUrl, LabelInfo, LabelTypes +from src.core.tasks import TaskTypes + + +class DataInfo(BaseModel): + data_url: AnyUrl | BucketUrl + "Bucket URL, AWS S3 | GCS, virtual-hosted-style access" + # https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-bucket-intro.html + + points_url: AnyUrl | BucketUrl | None = None + "A path to an archive with a set of points in COCO Keypoints format, " + "which provides information about all objects on images" + + boxes_url: AnyUrl | BucketUrl | None = None + "A path to an archive with a set of boxes in COCO Instances format, " + "which provides information about all objects on images" + + +class AnnotationInfo(BaseModel): + type: TaskTypes + + labels: list[LabelInfo] = Field(min_length=1) + "Label declarations with accepted annotation types" + + description: str = "" + "Brief task description" + + user_guide: str = "" + "User guide in markdown format" + + job_size: int = 10 + "Frames per job, validation frames are not included" + + qualifications: list[str] = Field(default_factory=list) + "A list of annotator qualifications required for participation" + + @model_validator(mode="before") + @classmethod + def validate_label_type(cls, values: dict[str, Any]) -> dict[str, Any]: + if not isinstance(values, dict): + raise NotImplementedError + + default_label_type = LabelTypes.plain + if values["type"] == TaskTypes.image_skeletons_from_boxes: + default_label_type = LabelTypes.skeleton + + # Add default value for labels, if none provided. + # pydantic can't do this for tagged unions + try: + labels = values["labels"] + for label_info in labels: + label_info["type"] = label_info.get("type", default_label_type) + except KeyError: + pass + + return values + + +class ValidationInfo(BaseModel): + min_quality: float = Field(ge=0) + "Minimal accepted annotation accuracy" + + val_size: int = Field(default=2, gt=0) + "Validation frames per job" + + gt_url: AnyUrl | BucketUrl + "URL to the archive with Ground Truth annotations, the format is COCO keypoints" + + +class JobManifest(BaseModel): + version: Literal[1] = 1 + + data: DataInfo + annotation: AnnotationInfo + validation: ValidationInfo + + job_bounty: Decimal = Field(ge=0) + "Assignment bounty, a decimal value in HMT" diff --git a/packages/examples/cvat/recording-oracle/src/core/manifest/v2.py b/packages/examples/cvat/recording-oracle/src/core/manifest/v2.py new file mode 100644 index 0000000000..228986d72f --- /dev/null +++ b/packages/examples/cvat/recording-oracle/src/core/manifest/v2.py @@ -0,0 +1,170 @@ +from copy import deepcopy +from typing import Any, Literal + +from pydantic import AnyUrl, BaseModel, ConfigDict, Field, model_validator + +from src.core.manifest.shared import BucketUrl, LabelInfo, LabelTypes +from src.core.tasks import TaskTypes +from src.utils.enums import BetterEnumMeta, StrEnum + + +class DataInfo(BaseModel): + media_url: AnyUrl | BucketUrl + "Bucket URL, AWS S3 | GCS, virtual-hosted-style access" + + gt_url: AnyUrl | BucketUrl + "URL to the archive with Ground Truth annotations" + + points_url: AnyUrl | BucketUrl | None = None + """ + A path to a file or an archive with a set of points in COCO Keypoints format. + Applicable for: image_boxes_from_points + """ + + boxes_url: AnyUrl | BucketUrl | None = None + """ + A path to a file or an archive with a set of boxes in COCO Instances format. + Applicable for: image_skeletons_from_boxes + """ + + regions_url: AnyUrl | BucketUrl | None = None + """ + A path to a file or an archive with audio regions in the CVAT Generic TSV format. + Applicable for: audio_transcription + """ + + +class TargetMetrics(StrEnum, metaclass=BetterEnumMeta): + accuracy = "accuracy" + wer = "wer" + cer = "cer" + + +class ValidationInfo(BaseModel): + target_score: float = Field(ge=0) + "Required annotation score. Can be minimal or maximal depending on the metric used" + + target_metric: TargetMetrics = TargetMetrics.accuracy + "Metric used to score annotations against the target" + + +class MinComposition(BaseModel): + gt: int + "Minimal number of Ground Truth samples per composition" + + ds: int + "Minimal number of dataset samples per composition" + + +class DetailsInfoBase(BaseModel): + model_config = ConfigDict(extra="forbid") + + max_time: int | None = None + "Maximum assignment time, seconds" + + +class ImageJobDetails(DetailsInfoBase): + job_size: int | None = None + "Frames per job, validation frames are not included" + + val_size: int | None = None + "Validation frames per job" + + +class AudioJobDetails(DetailsInfoBase): + normalizer: str | None = "basic" + "Text normalizer for audio transcription" + + max_segment_duration: int | None = None + "Maximum audio segment duration, seconds" + + min_gt_span_duration: int | None = None + """ + Minimum duration of densely-annotated GT regions, in seconds. + Each is expected to contain 1 or more annotated intervals inside. + A span is identified by the span_id field. + """ + + min_composition: MinComposition | None = None + "Minimal composition of a job" + + validation_overhead: int | None = None + "Extra validation samples added on top of the required amount" + + boundary_tolerance: int | None = None + "Allowed annotation/GT interval boundary misalignment at honeypots, milliseconds" + + +DetailsInfo = ImageJobDetails | AudioJobDetails + + +class SharedAttribute(BaseModel): + name: str = Field(min_length=1) + type: str + values: list[str] = Field(default_factory=list) + default_value: str = "" + + +class AnnotationInfo(BaseModel): + description: str = "" + "Brief task description" + + user_guide_url: str = "" + "URL to the user guide in markdown format" + + labels: list[LabelInfo] = Field(min_length=1) + "Label declarations with accepted annotation types" + + shared_attributes: list[SharedAttribute] = Field(default_factory=list) + "Shared annotation attributes" + + validation: ValidationInfo + + qualifications: list[str] = Field(default_factory=list) + "A list of annotator qualifications required for participation" + + details: ImageJobDetails | AudioJobDetails | None = None + "Task-specific details" + + +class JobManifest(BaseModel): + version: Literal[2] + + job_type: TaskTypes + data: DataInfo + annotation: AnnotationInfo + + @model_validator(mode="before") + @classmethod + def parse_task_specific_params(cls, values: dict[str, Any]) -> dict[str, Any]: + if not isinstance(values, dict): + raise NotImplementedError + + values = deepcopy(values) # copy before mutating + + job_type = values.get("job_type") + + annotation = values.get("annotation") + if not isinstance(annotation, dict): + raise NotImplementedError + + # Default label types (pydantic can't do this for tagged unions). + default_label_type = ( + LabelTypes.skeleton + if job_type == TaskTypes.image_skeletons_from_boxes + else LabelTypes.plain + ) + for label_info in annotation.get("labels", []): + if isinstance(label_info, dict): + label_info.setdefault("type", default_label_type) + + if details := annotation.get("details"): + if not isinstance(details, dict): + raise NotImplementedError + + details_cls = ( + AudioJobDetails if job_type == TaskTypes.audio_transcription else ImageJobDetails + ) + annotation["details"] = details_cls.model_validate(details) + + return values diff --git a/packages/examples/cvat/recording-oracle/src/core/tasks/__init__.py b/packages/examples/cvat/recording-oracle/src/core/tasks/__init__.py index e69de29bb2..3f24f51e5c 100644 --- a/packages/examples/cvat/recording-oracle/src/core/tasks/__init__.py +++ b/packages/examples/cvat/recording-oracle/src/core/tasks/__init__.py @@ -0,0 +1,7 @@ +from src.core.tasks import errors +from src.core.tasks.types import TaskTypes + +__all__ = [ + "TaskTypes", + "errors", +] diff --git a/packages/examples/cvat/recording-oracle/src/core/tasks/audio_transcription/__init__.py b/packages/examples/cvat/recording-oracle/src/core/tasks/audio_transcription/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/examples/cvat/recording-oracle/src/core/tasks/audio_transcription/meta.py b/packages/examples/cvat/recording-oracle/src/core/tasks/audio_transcription/meta.py new file mode 100644 index 0000000000..1f7c45f2c3 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/src/core/tasks/audio_transcription/meta.py @@ -0,0 +1,252 @@ +"""Domain types and meta persistence for audio transcription tasks. + +Regions are mixed across input files into assignments, so every region carries its own source +provenance. The persisted mappings (regions + assignments) let each region be located back in its +source media after mixing. +""" + +from __future__ import annotations + +import csv +import io +import time +from datetime import timedelta + +from attrs import Factory, frozen +from datumaro.util import dump_json, parse_json + +from src.utils.enums import BetterEnumMeta, StrEnum + +CVAT_EXPORT_FORMAT = "Generic TSV 1.0" + + +def parse_time(value: str) -> timedelta: + """Parse an ``H:MM:SS(.ffffff)`` timestamp (as used in the region/GT TSVs).""" + for fmt_string in ("%H:%M:%S.%f", "%H:%M:%S"): + try: + parsed_time = time.strptime(value, fmt_string) + if fmt_string.endswith(".%f"): + # time.strptime drops sub-second precision, so recover it from the raw string. + frac = value.split(".", maxsplit=1)[-1] + microseconds = int(frac.ljust(6, "0")[:6]) + else: + microseconds = 0 + except ValueError: + continue + else: + return timedelta( + hours=parsed_time.tm_hour, + minutes=parsed_time.tm_min, + seconds=parsed_time.tm_sec, + microseconds=microseconds, + ) + + raise ValueError(f"Failed to parse timestamp '{value}'") + + +def format_time(value: timedelta) -> str: + """Render a timedelta as an ``H:MM:SS.ffffff`` timestamp.""" + total = value.total_seconds() + h = int(total // 3600) + m = int((total % 3600) // 60) + s = total - h * 3600 - m * 60 + return f"{h}:{m:02d}:{s:09.6f}" + + +@frozen(kw_only=True) +class InputRegion: + """A region to annotate, parsed from the input regions TSV.""" + + filename: str + start: timedelta + stop: timedelta + label: str | None = None + row_idx: int + + @property + def id(self) -> str: + return f"{self.filename}:{self.row_idx}" + + +@frozen(kw_only=True) +class InputGtRegion: + """A ground-truth region, parsed from the input GT TSV.""" + + filename: str + start: timedelta + stop: timedelta + label: str + text: str + row_idx: int + span_id: str + + @property + def id(self) -> str: + return f"{self.filename}:{self.row_idx}" + + +def parse_gt_tsv(data: bytes) -> list[InputGtRegion]: + reader = csv.DictReader(io.StringIO(data.decode("utf-8")), delimiter="\t") + return [ + InputGtRegion( + filename=row["filename"].strip(), + row_idx=row_idx, + start=parse_time(row["start"]), + stop=parse_time(row["stop"]), + label=row["label"].strip(), + text=row["text"].strip(), + span_id=row["span_id"].strip(), + ) + for row_idx, row in enumerate(reader) + ] + + +class RegionKind(StrEnum, metaclass=BetterEnumMeta): + gt = "gt" # ground-truth honeypot region + ds = "ds" # regular dataset region to annotate + + +@frozen(kw_only=True) +class PresentedRegion: + "A bundle of consecutive input ROIs from one source file, presented as a single region." + + source_filename: str + start: float # bundle span (file-time seconds): first ROI start .. last ROI stop + stop: float + kind: RegionKind + input_ids: list[str] = Factory(list) + + @property + def duration(self) -> float: + return self.stop - self.start + + +@frozen(kw_only=True) +class PlacedRegion: + "A presented region placed in an assignment" + + index: int # 0-based position within the assignment clip + source_filename: str + source_start: float + source_stop: float + clip_start: float + clip_stop: float + kind: RegionKind + input_ids: list[str] = Factory(list) # ids of the input ROIs this bundle was built from + + +@frozen(kw_only=True) +class Clip: + """A single concatenated audio clip built from ``placed`` regions (one per CVAT task).""" + + id: str + clip_filename: str + clip_duration: float + placed: list[PlacedRegion] = Factory(list) + + +def _region_to_dict(r: PresentedRegion) -> dict: + return { + "source_filename": r.source_filename, + "start": r.start, + "stop": r.stop, + "kind": r.kind.value, + "input_ids": list(r.input_ids), + } + + +def _region_from_dict(d: dict) -> PresentedRegion: + return PresentedRegion( + source_filename=d["source_filename"], + start=d["start"], + stop=d["stop"], + kind=RegionKind(d["kind"]), + input_ids=list(d.get("input_ids", [])), + ) + + +def _placed_to_dict(r: PlacedRegion) -> dict: + return { + "index": r.index, + "source_filename": r.source_filename, + "source_start": r.source_start, + "source_stop": r.source_stop, + "clip_start": r.clip_start, + "clip_stop": r.clip_stop, + "kind": r.kind.value, + "input_ids": list(r.input_ids), + } + + +def _placed_from_dict(d: dict) -> PlacedRegion: + return PlacedRegion( + index=d["index"], + source_filename=d["source_filename"], + source_start=d["source_start"], + source_stop=d["source_stop"], + clip_start=d["clip_start"], + clip_stop=d["clip_stop"], + kind=RegionKind(d["kind"]), + input_ids=list(d.get("input_ids", [])), + ) + + +class TaskMetaLayout: + CLIPS_DIR = "clips" # assignment clips subdir on the oracle bucket + GT_FILENAME = "gt.tsv" + REGIONS_TSV_FILENAME = "regions.tsv" + REGIONS_FILENAME = "regions.json" + CLIPS_FILENAME = "assignments.json" + TASK_CLIPS_FILENAME = "task_clips.json" + DS_CUTS_DIR = "ds_cuts" + GT_CUTS_DIR = "gt_cuts" + + +class TaskResultsLayout: + "Layout of the escrow results dir on the oracle bucket." + + ASSIGNMENTS_DIR = "assignments" # per-assignment annotation TSVs (one per CVAT job) + ANNOTATIONS_FILENAME = "annotations.tsv" # merged annotations (without honeypots or GT) + + @classmethod + def assignment_annotation_filename(cls, job_id: int, assignment_id: str) -> str: + "Path (relative to the results dir) of a job's per-assignment annotation TSV." + return f"{cls.ASSIGNMENTS_DIR}/{job_id}-{assignment_id}.tsv" + + +class TaskMetaSerializer: + def serialize_regions(self, regions: list[PresentedRegion]) -> bytes: + return dump_json([_region_to_dict(r) for r in regions]) + + def parse_regions(self, data: bytes) -> list[PresentedRegion]: + return [_region_from_dict(d) for d in parse_json(data)] + + def serialize_clips(self, clips: list[Clip]) -> bytes: + return dump_json( + [ + { + "id": clip.id, + "clip_filename": clip.clip_filename, + "clip_dur": clip.clip_duration, + "placed": [_placed_to_dict(p) for p in clip.placed], + } + for clip in clips + ] + ) + + def parse_clips(self, data: bytes) -> list[Clip]: + return [ + Clip( + id=d["id"], + clip_filename=d["clip_filename"], + clip_duration=d["clip_dur"], + placed=[_placed_from_dict(p) for p in d.get("placed", [])], + ) + for d in parse_json(data) + ] + + def serialize_task_clips(self, task_clips: dict[int, str]) -> bytes: + return dump_json({str(task_id): clip_id for task_id, clip_id in task_clips.items()}) + + def parse_task_clips(self, data: bytes) -> dict[int, str]: + return {int(task_id): clip_id for task_id, clip_id in parse_json(data).items()} diff --git a/packages/examples/cvat/recording-oracle/src/core/tasks/audio_transcription/spec.py b/packages/examples/cvat/recording-oracle/src/core/tasks/audio_transcription/spec.py new file mode 100644 index 0000000000..7f688c983e --- /dev/null +++ b/packages/examples/cvat/recording-oracle/src/core/tasks/audio_transcription/spec.py @@ -0,0 +1,170 @@ +from __future__ import annotations + +from datetime import timedelta +from typing import TYPE_CHECKING + +from pydantic import AnyUrl, BaseModel, Field + +from src.core.manifest.shared import BucketUrl +from src.core.manifest.v2 import TargetMetrics +from src.core.tasks.errors import UnsupportedManifestError +from src.utils.enums import BetterEnumMeta, StrEnum + +if TYPE_CHECKING: + from src.core.manifest.v2 import JobManifest + + +class NormalizerPreset(StrEnum, metaclass=BetterEnumMeta): + basic = "basic" # universal Unicode + case + whitespace fold + # Tier-1 language presets (BASIC plus per-language rules) + en = "en" + es = "es" + fr = "fr" + de = "de" + it = "it" + pt = "pt" + nl = "nl" + pl = "pl" + ru = "ru" + tr = "tr" + zh = "zh" + ja = "ja" + ko = "ko" + hi = "hi" + ar = "ar" + + +class TranscriptionTaskData(BaseModel): + media_url: AnyUrl | BucketUrl + regions_url: AnyUrl | BucketUrl + gt_url: AnyUrl | BucketUrl + + +class TranscriptionTaskValidation(BaseModel): + target_metric: TargetMetrics + target_score: float + + +class TranscriptionDetails(BaseModel): + assignment_time_limit: timedelta | None = None + "Maximum time to complete an assignment" + + validation_overhead: float = 0.2 + "Honeypot share of the assignment duration" + + normalizer: NormalizerPreset | None = NormalizerPreset.basic + "Text normalization for transcriptions" + + min_composition: tuple[int, int] = (2, 2) + "(gt, ds): minimum number of honeypot and DS regions per assignment" + + min_gt_span_duration: timedelta = timedelta(seconds=30) + """ + Minimum duration of densely-annotated GT regions, in seconds. + Each is expected to contain 1 or more annotated intervals inside. + A span is identified by the span_id field. + """ + + roi_min_duration: timedelta = timedelta(seconds=5) + "Minimum presented region duration. Smaller segments are bundled together" + + roi_max_duration: timedelta = timedelta(seconds=120) + "Maximum presented region duration. Used for input validation" + + roi_join_pause: timedelta = timedelta(milliseconds=700) + "Silence inserted between concatenated regions in an assignment clip" + + boundary_tolerance: timedelta = timedelta(milliseconds=200) + "Allowed joined annotation/GT interval boundary misalignment when matching transcriptions" + + standard_assignment_duration: timedelta = timedelta(seconds=60) + "Target audio duration per assignment" + + # TODO: add honeypot rotation later + # max_validation_gt: float = 0.05 + # "Maximum share of GT regions used as honeypots. The rest is used for honeypot rotation" + + max_discarded_gt: float = 0.5 + "Maximum share of GT regions that may be discarded before job creation fails" + + sample_rate: int = 48000 + "Sample rate of the generated assignment clips, Hz" + + transcription_attr_name: str = "transcription" + "The name of the output attribute for transcriptions in CVAT tasks and annotations" + + random_seed: int = 0 + "Seed for deterministic honeypot selection and assignment mixing" + + +class TranscriptionTaskSpecification(BaseModel): + data: TranscriptionTaskData + + labels: list[str] + shared_attributes: list = Field(default_factory=list) + user_guide: str = "" + + validation: TranscriptionTaskValidation + + details: TranscriptionDetails = Field(default_factory=TranscriptionDetails) + + +def parse_audio_manifest(manifest: JobManifest) -> TranscriptionTaskSpecification: + """ + Produce the task specification from a manifest, encapsulating manifest-version differences. + + Only v2 manifests are supported. + """ + + version = getattr(manifest, "version", 1) + if version != 2: + raise UnsupportedManifestError( + f"Audio transcription requires a v2 manifest, got version {version}" + ) + + annotation = manifest.annotation + validation = annotation.validation + manifest_details = annotation.details + + # Only pass the details fields the manifest provides; pydantic fills the rest with defaults + # and coerces raw values (e.g. normalizer str -> NormalizerPreset). + details_fields: dict = {} + if manifest_details is not None: + if manifest_details.max_segment_duration is not None: + details_fields["roi_max_duration"] = timedelta( + seconds=manifest_details.max_segment_duration + ) + if manifest_details.min_gt_span_duration is not None: + details_fields["min_gt_span_duration"] = timedelta( + seconds=manifest_details.min_gt_span_duration + ) + if manifest_details.boundary_tolerance is not None: + details_fields["boundary_tolerance"] = timedelta( + milliseconds=manifest_details.boundary_tolerance + ) + if manifest_details.validation_overhead is not None: + details_fields["validation_overhead"] = manifest_details.validation_overhead / 100.0 + if manifest_details.min_composition is not None: + details_fields["min_composition"] = ( + manifest_details.min_composition.gt, + manifest_details.min_composition.ds, + ) + details_fields["normalizer"] = manifest_details.normalizer + if manifest_details.max_time is not None: + details_fields["assignment_time_limit"] = timedelta(seconds=manifest_details.max_time) + + return TranscriptionTaskSpecification( + data=TranscriptionTaskData( + media_url=manifest.data.media_url, + regions_url=manifest.data.regions_url, + gt_url=manifest.data.gt_url, + ), + labels=[label.name for label in annotation.labels], + shared_attributes=list(annotation.shared_attributes), + user_guide=annotation.user_guide_url, + validation=TranscriptionTaskValidation( + target_metric=validation.target_metric, + target_score=validation.target_score, + ), + details=TranscriptionDetails(**details_fields), + ) diff --git a/packages/examples/cvat/recording-oracle/src/core/tasks/cvat_formats.py b/packages/examples/cvat/recording-oracle/src/core/tasks/cvat_formats.py new file mode 100644 index 0000000000..a2a465c891 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/src/core/tasks/cvat_formats.py @@ -0,0 +1,22 @@ +from __future__ import annotations + +from src.core.tasks.types import TaskTypes + +DM_DATASET_FORMAT_MAPPING = { + TaskTypes.image_label_binary: "cvat_images", + TaskTypes.image_points: "coco_person_keypoints", + TaskTypes.image_boxes: "coco_instances", + TaskTypes.image_polygons: "coco_instances", + TaskTypes.image_boxes_from_points: "coco_instances", + TaskTypes.image_skeletons_from_boxes: "coco_person_keypoints", +} + +DM_GT_DATASET_FORMAT_MAPPING = { + # GT uses the same format both for boxes and points + TaskTypes.image_label_binary: "cvat_images", + TaskTypes.image_points: "coco_instances", + TaskTypes.image_boxes: "coco_instances", + TaskTypes.image_polygons: "coco_instances", + TaskTypes.image_boxes_from_points: "coco_instances", + TaskTypes.image_skeletons_from_boxes: "coco_person_keypoints", +} diff --git a/packages/examples/cvat/recording-oracle/src/core/tasks/errors.py b/packages/examples/cvat/recording-oracle/src/core/tasks/errors.py new file mode 100644 index 0000000000..6f002952f7 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/src/core/tasks/errors.py @@ -0,0 +1,2 @@ +class UnsupportedManifestError(Exception): + pass diff --git a/packages/examples/cvat/recording-oracle/src/core/tasks/types.py b/packages/examples/cvat/recording-oracle/src/core/tasks/types.py new file mode 100644 index 0000000000..0c65e58bcb --- /dev/null +++ b/packages/examples/cvat/recording-oracle/src/core/tasks/types.py @@ -0,0 +1,11 @@ +from src.utils.enums import BetterEnumMeta, StrEnum + + +class TaskTypes(StrEnum, metaclass=BetterEnumMeta): + image_label_binary = "image_label_binary" + image_points = "image_points" + image_boxes = "image_boxes" + image_boxes_from_points = "image_boxes_from_points" + image_skeletons_from_boxes = "image_skeletons_from_boxes" + image_polygons = "image_polygons" + audio_transcription = "audio_transcription" diff --git a/packages/examples/cvat/recording-oracle/src/core/types.py b/packages/examples/cvat/recording-oracle/src/core/types.py index 682b9f2703..8716aa32b7 100644 --- a/packages/examples/cvat/recording-oracle/src/core/types.py +++ b/packages/examples/cvat/recording-oracle/src/core/types.py @@ -1,43 +1,34 @@ -from enum import Enum +from enum import IntEnum from src.core.config import Config -from src.utils.enums import BetterEnumMeta +from src.utils.enums import BetterEnumMeta, StrEnum -class Networks(int, Enum): +class Networks(IntEnum): polygon_mainnet = Config.polygon_mainnet.chain_id polygon_amoy = Config.polygon_amoy.chain_id localhost = Config.localhost.chain_id -class TaskTypes(str, Enum, metaclass=BetterEnumMeta): - image_label_binary = "image_label_binary" - image_points = "image_points" - image_polygons = "image_polygons" - image_boxes = "image_boxes" - image_boxes_from_points = "image_boxes_from_points" - image_skeletons_from_boxes = "image_skeletons_from_boxes" - - -class OracleWebhookTypes(str, Enum, metaclass=BetterEnumMeta): +class OracleWebhookTypes(StrEnum, metaclass=BetterEnumMeta): exchange_oracle = "exchange_oracle" recording_oracle = "recording_oracle" reputation_oracle = "reputation_oracle" -class OracleWebhookStatuses(str, Enum, metaclass=BetterEnumMeta): +class OracleWebhookStatuses(StrEnum, metaclass=BetterEnumMeta): pending = "pending" completed = "completed" failed = "failed" -class ExchangeOracleEventTypes(str, Enum, metaclass=BetterEnumMeta): +class ExchangeOracleEventTypes(StrEnum, metaclass=BetterEnumMeta): escrow_failed = "escrow_failed" job_finished = "job_finished" escrow_cleaned = "escrow_cleaned" escrow_recorded = "escrow_recorded" -class RecordingOracleEventTypes(str, Enum, metaclass=BetterEnumMeta): +class RecordingOracleEventTypes(StrEnum, metaclass=BetterEnumMeta): job_completed = "job_completed" submission_rejected = "submission_rejected" diff --git a/packages/examples/cvat/recording-oracle/src/core/validation_errors.py b/packages/examples/cvat/recording-oracle/src/core/validation_errors.py index 40ad8c1d39..0d05ba7a0f 100644 --- a/packages/examples/cvat/recording-oracle/src/core/validation_errors.py +++ b/packages/examples/cvat/recording-oracle/src/core/validation_errors.py @@ -11,7 +11,7 @@ def __str__(self) -> str: ) -class LowAccuracyError(DatasetValidationError): +class LowQualityError(DatasetValidationError): pass diff --git a/packages/examples/cvat/recording-oracle/src/crons/_utils.py b/packages/examples/cvat/recording-oracle/src/crons/_utils.py index c9002dc7a5..f4ad07d648 100644 --- a/packages/examples/cvat/recording-oracle/src/crons/_utils.py +++ b/packages/examples/cvat/recording-oracle/src/crons/_utils.py @@ -4,7 +4,7 @@ from contextlib import contextmanager, nullcontext from functools import wraps -import httpx +import httpx2 from sqlalchemy.orm import Session import src.services.webhook as oracle_db_service @@ -39,14 +39,14 @@ def decorator(fn: Callable[..., None]): parameters = dict(inspect.signature(fn).parameters) session_param = parameters.pop("session", None) if session_param is not None: - assert ( - session_param.annotation == Session - ), f"{cron_repr} session argument type muse be of type {Session.__qualname__}" + assert session_param.annotation == Session, ( + f"{cron_repr} session argument type muse be of type {Session.__qualname__}" + ) logger_param = parameters.pop("logger", None) assert logger_param is not None, f"{cron_repr} must have logger argument" - assert ( - logger_param.annotation == logging.Logger - ), f"{cron_repr} logger argument type muse be of type {logging.Logger}" + assert logger_param.annotation == logging.Logger, ( + f"{cron_repr} logger argument type muse be of type {logging.Logger}" + ) assert not parameters, ( f"{cron_repr} expected to have only have logger and session arguments," f" not {set(parameters.keys())}" @@ -109,7 +109,7 @@ def send_webhook(url: str, webhook: Webhook, *, with_timestamp: bool = True) -> body=body, ) headers = {"human-signature": signature} - with httpx.Client() as client: + with httpx2.Client() as client: response = client.post(url, headers=headers, json=body) response.raise_for_status() diff --git a/packages/examples/cvat/recording-oracle/src/cvat/api_calls.py b/packages/examples/cvat/recording-oracle/src/cvat/api_calls.py index 574e44c918..7566791f8f 100644 --- a/packages/examples/cvat/recording-oracle/src/cvat/api_calls.py +++ b/packages/examples/cvat/recording-oracle/src/cvat/api_calls.py @@ -209,7 +209,7 @@ def get_task_labels(task_id: int) -> list[str]: project_id = task.project_id return [ - cast(models.ILabel, label).name + cast("models.ILabel", label).name for label in get_paginated_collection( api_client.labels_api.list_endpoint, **({"project_id": project_id} if project_id else {"task_id": task_id}), diff --git a/packages/examples/cvat/recording-oracle/src/endpoints/__init__.py b/packages/examples/cvat/recording-oracle/src/endpoints/__init__.py index 4a21381846..d3afad4828 100644 --- a/packages/examples/cvat/recording-oracle/src/endpoints/__init__.py +++ b/packages/examples/cvat/recording-oracle/src/endpoints/__init__.py @@ -9,7 +9,7 @@ greet_router = APIRouter() -@greet_router.get("/", description="Endpoint describing the API", response_model=MetaResponse) +@greet_router.get("/", description="Endpoint describing the API") def meta_route() -> MetaResponse: networks = [Config.polygon_mainnet, Config.polygon_amoy] diff --git a/packages/examples/cvat/recording-oracle/src/endpoints/webhook.py b/packages/examples/cvat/recording-oracle/src/endpoints/webhook.py index c2e4d0d511..871bea0d67 100644 --- a/packages/examples/cvat/recording-oracle/src/endpoints/webhook.py +++ b/packages/examples/cvat/recording-oracle/src/endpoints/webhook.py @@ -1,3 +1,5 @@ +from typing import Annotated + from fastapi import APIRouter, Header, HTTPException, Request import src.services.webhook as oracle_db_service @@ -12,7 +14,7 @@ async def receive_oracle_webhook( webhook: OracleWebhook, request: Request, - human_signature: str | None = Header(default=None), + human_signature: Annotated[str | None, Header()] = None, ) -> OracleWebhookResponse: try: sender = await validate_oracle_webhook_signature(request, human_signature, webhook) diff --git a/packages/examples/cvat/recording-oracle/src/entrypoints/__init__.py b/packages/examples/cvat/recording-oracle/src/entrypoints/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/examples/cvat/recording-oracle/debug.py b/packages/examples/cvat/recording-oracle/src/entrypoints/debug.py similarity index 98% rename from packages/examples/cvat/recording-oracle/debug.py rename to packages/examples/cvat/recording-oracle/src/entrypoints/debug.py index 37c00dbd9a..4549807de9 100644 --- a/packages/examples/cvat/recording-oracle/debug.py +++ b/packages/examples/cvat/recording-oracle/src/entrypoints/debug.py @@ -35,8 +35,7 @@ def patched_get_escrow(chain_id: int, escrow_address: str) -> EscrowData: fn for fn in minio_manifests if ( - "/" in escrow_address - and fn == f"{escrow_address}.json" + ("/" in escrow_address and fn == f"{escrow_address}.json") or PurePosixPath(fn).name == f"{escrow_address}.json" ) ] diff --git a/packages/examples/cvat/recording-oracle/run.py b/packages/examples/cvat/recording-oracle/src/entrypoints/run.py similarity index 100% rename from packages/examples/cvat/recording-oracle/run.py rename to packages/examples/cvat/recording-oracle/src/entrypoints/run.py diff --git a/packages/examples/cvat/recording-oracle/src/handlers/completion/__init__.py b/packages/examples/cvat/recording-oracle/src/handlers/completion/__init__.py new file mode 100644 index 0000000000..6f744a8a50 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/src/handlers/completion/__init__.py @@ -0,0 +1,3 @@ +from src.handlers.completion.handlers import export_results + +__all__ = ["export_results"] diff --git a/packages/examples/cvat/recording-oracle/src/handlers/completion/final_results.py b/packages/examples/cvat/recording-oracle/src/handlers/completion/final_results.py new file mode 100644 index 0000000000..e6ad08a557 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/src/handlers/completion/final_results.py @@ -0,0 +1,109 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +import numpy as np + +import src.services.validation as db_service +from src.core.validation_meta import JobMeta, ResultMeta, ValidationMeta +from src.core.validation_results import FinalResult +from src.db.utils import ForUpdateParams +from src.handlers.completion.task_exporters.factory import create_exporter +from src.handlers.validation.common import UNKNOWN_QUALITY, _JobResults + +if TYPE_CHECKING: + import logging + + from sqlalchemy.orm import Session + + from src.core.annotation_meta import AnnotationMeta + from src.core.manifest import ManifestBase + + +def process_final_results( + session: Session, + *, + escrow_address: str, + chain_id: int, + meta: AnnotationMeta, + manifest: ManifestBase, + logger: logging.Logger, +) -> FinalResult: + assert logger # unused + + task = db_service.get_task_by_escrow_address( + session, + escrow_address, + for_update=ForUpdateParams( + nowait=True + ), # should not happen, but waiting should not block processing + ) + if not task: + raise AssertionError(f"Validation results for escrow {escrow_address} not found") + + exporter = create_exporter(manifest, escrow_address, chain_id, session) + resulting_annotations = exporter.export() + + job_final_result_ids: dict[str, str] = {} + + for job_meta in meta.jobs: + job = db_service.get_job_by_cvat_id(session, job_meta.job_id) + if not job: + raise AssertionError( + f"Can't find validation results for job {job_meta.job_id} ({escrow_address=})" + ) + + assignment_validation_result = db_service.get_validation_result_by_assignment_id( + session, job_meta.assignment_id + ) + if not assignment_validation_result: + raise AssertionError( + f"Can't find validation results for assignments " + f"{job_meta.assignment_id} ({escrow_address=})" + ) + + job_final_result_ids[job.id] = assignment_validation_result.id + + task_jobs = task.jobs + + task_validation_results = db_service.get_task_validation_results(session, task.id) + + job_id_to_meta_id = {job.id: i for i, job in enumerate(task_jobs)} + + validation_result_id_to_meta_id = {r.id: i for i, r in enumerate(task_validation_results)} + + validation_meta = ValidationMeta( + jobs=[ + JobMeta( + job_id=job_id_to_meta_id[job.id], + final_result_id=validation_result_id_to_meta_id[job_final_result_ids[job.id]], + ) + for job in task_jobs + ], + results=[ + ResultMeta( + id=validation_result_id_to_meta_id[r.id], + job_id=job_id_to_meta_id[r.job.id], + annotator_wallet_address=r.annotator_wallet_address, + annotation_quality=r.annotation_quality, + ) + for r in task_validation_results + ], + ) + + # Include final results for all jobs + job_results: _JobResults = { + job.cvat_id: task_validation_results[ + validation_result_id_to_meta_id[job_final_result_ids[job.id]] + ].annotation_quality + for job in task_jobs + } + + return FinalResult( + job_results=job_results, + validation_meta=validation_meta, + resulting_annotations=resulting_annotations, + average_quality=np.mean( + [v for v in job_results.values() if v != UNKNOWN_QUALITY and v >= 0] or [0] + ), + ) diff --git a/packages/examples/cvat/recording-oracle/src/handlers/completion.py b/packages/examples/cvat/recording-oracle/src/handlers/completion/handlers.py similarity index 72% rename from packages/examples/cvat/recording-oracle/src/handlers/completion.py rename to packages/examples/cvat/recording-oracle/src/handlers/completion/handlers.py index 22db6e9f29..d48355ba10 100644 --- a/packages/examples/cvat/recording-oracle/src/handlers/completion.py +++ b/packages/examples/cvat/recording-oracle/src/handlers/completion/handlers.py @@ -9,20 +9,15 @@ import src.services.webhook as oracle_db_service from src.chain import escrow from src.core.config import Config -from src.core.manifest import TaskManifest, parse_manifest -from src.core.oracle_events import ( - RecordingOracleEvent_JobCompleted, -) +from src.core.manifest import ManifestBase, parse_manifest +from src.core.oracle_events import RecordingOracleEvent_JobCompleted from src.core.storage import ( compose_results_bucket_filename as compose_annotation_results_bucket_filename, ) from src.core.types import OracleWebhookTypes from src.core.validation_results import FinalResult -from src.handlers.process_intermediate_results import ( - parse_annotation_metafile, - process_final_results, - serialize_validation_meta, -) +from src.handlers.completion.final_results import process_final_results +from src.handlers.validation import parse_annotation_metafile, serialize_validation_meta from src.log import ROOT_LOGGER_NAME from src.services.cloud import make_client as make_cloud_client from src.services.cloud.utils import BucketAccessInfo @@ -32,9 +27,9 @@ module_logger_name = f"{ROOT_LOGGER_NAME}.cron.webhook" -class _TaskUploader: +class _EscrowExporter: def __init__( - self, escrow_address: str, chain_id: int, manifest: TaskManifest, db_session: Session + self, escrow_address: str, chain_id: int, manifest: ManifestBase, db_session: Session ) -> None: self.escrow_address = escrow_address self.chain_id = chain_id @@ -45,7 +40,6 @@ def __init__( self.data_bucket = BucketAccessInfo.parse_obj(Config.exchange_oracle_storage_config) self.annotation_meta: annotation.AnnotationMeta | None = None - self.merged_annotations: bytes | None = None def set_logger(self, logger: Logger): self.logger = logger @@ -61,55 +55,32 @@ def _download_results_meta(self): annotation_metafile_data = data_bucket_client.download_file(annotation_meta_path) self.annotation_meta = parse_annotation_metafile(io.BytesIO(annotation_metafile_data)) - def _download_annotations(self): - assert self.annotation_meta is not None - - data_bucket_client = make_cloud_client(self.data_bucket) - - exchange_oracle_merged_annotation_path = compose_annotation_results_bucket_filename( - self.escrow_address, - self.chain_id, - annotation.RESULTING_ANNOTATIONS_FILE, - ) - merged_annotations = data_bucket_client.download_file( - exchange_oracle_merged_annotation_path - ) - - self.merged_annotations = merged_annotations - def _download_results(self): self._download_results_meta() - self._download_annotations() def _process_annotation_results(self) -> FinalResult: assert self.annotation_meta is not None - assert self.merged_annotations is not None return process_final_results( session=self.db_session, escrow_address=self.escrow_address, chain_id=self.chain_id, meta=self.annotation_meta, - merged_annotations=io.BytesIO(self.merged_annotations), manifest=self.manifest, logger=self.logger, ) - def upload(self): + def export(self): self._download_results() - validation_result = self._process_annotation_results() + export_result = self._process_annotation_results() - self._handle_validation_result(validation_result) + self._handle_result(export_result) def _compose_validation_results_bucket_filename(self, filename: str) -> str: return f"{self.escrow_address}@{self.chain_id}/{filename}" - _LOW_QUALITY_REASON_MESSAGE_TEMPLATE = ( - "Annotation quality ({}) is below the required threshold ({})" - ) - - def _handle_validation_result(self, export_result: FinalResult): + def _handle_result(self, export_result: FinalResult): logger = self.logger escrow_address = self.escrow_address chain_id = self.chain_id @@ -117,7 +88,7 @@ def _handle_validation_result(self, export_result: FinalResult): logger.info( f"Result uploading for escrow_address={escrow_address}: successful, " - f"average annotation quality is {export_result.average_quality * 100:.2f}%" + f"average quality score is {export_result.average_quality * 100:.2f}%" ) recor_merged_annotations_path = self._compose_validation_results_bucket_filename( @@ -166,8 +137,8 @@ def export_results( manifest = parse_manifest(escrow.get_escrow_manifest(chain_id, escrow_address)) - uploader = _TaskUploader( + exporter = _EscrowExporter( escrow_address=escrow_address, chain_id=chain_id, manifest=manifest, db_session=db_session ) - uploader.set_logger(logger) - uploader.upload() + exporter.set_logger(logger) + exporter.export() diff --git a/packages/examples/cvat/recording-oracle/src/handlers/completion/task_exporters/__init__.py b/packages/examples/cvat/recording-oracle/src/handlers/completion/task_exporters/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/examples/cvat/recording-oracle/src/handlers/completion/task_exporters/audio.py b/packages/examples/cvat/recording-oracle/src/handlers/completion/task_exporters/audio.py new file mode 100644 index 0000000000..f72dbcc765 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/src/handlers/completion/task_exporters/audio.py @@ -0,0 +1,73 @@ +from __future__ import annotations + +import csv +import io +import zipfile + +from src.core.tasks.audio_transcription.meta import ( + TaskMetaLayout, + TaskResultsLayout, + format_time, + parse_gt_tsv, + parse_time, +) +from src.core.tasks.audio_transcription.spec import parse_audio_manifest +from src.handlers.completion.task_exporters.base import TaskExporter + +# Column marking each merged row's origin: annotator annotation vs ground truth. +_SOURCE_COLUMN = "source" +_ANNOTATION_SOURCE = "annotation" +_GT_SOURCE = "gt" + + +class AudioTaskExporter(TaskExporter): + def export(self) -> bytes: + tsv = self._build_merged_tsv() + + archive = io.BytesIO() + with zipfile.ZipFile(archive, "w", zipfile.ZIP_DEFLATED) as zf: + zf.writestr(TaskResultsLayout.ANNOTATIONS_FILENAME, tsv) + + return archive.getvalue() + + def _build_merged_tsv(self) -> bytes: + spec = parse_audio_manifest(self.manifest) + attr = spec.details.transcription_attr_name + + annotations = self._download_annotation_result_file( + TaskResultsLayout.ANNOTATIONS_FILENAME + ).decode("utf-8") + reader = csv.DictReader(io.StringIO(annotations), delimiter="\t") + columns = list(reader.fieldnames or []) + if _SOURCE_COLUMN not in columns: + # place it right after "label" when possible, otherwise append + insert_at = columns.index("label") + 1 if "label" in columns else len(columns) + columns.insert(insert_at, _SOURCE_COLUMN) + + ds_rows = list(reader) + for row in ds_rows: + row[_SOURCE_COLUMN] = _ANNOTATION_SOURCE + + gt_regions = parse_gt_tsv(self._download_task_data_file(TaskMetaLayout.GT_FILENAME)) + gt_rows = [ + { + "filename": r.filename, + "start": format_time(r.start), + "stop": format_time(r.stop), + "label": r.label or "", + "input_region_ids": str(r.row_idx), + _SOURCE_COLUMN: _GT_SOURCE, + attr: r.text, + } + for r in gt_regions + ] + + rows = ds_rows + gt_rows + rows.sort(key=lambda r: (r["filename"], parse_time(r["start"]).total_seconds())) + + buffer = io.StringIO() + writer = csv.DictWriter(buffer, fieldnames=columns, delimiter="\t", extrasaction="ignore") + writer.writeheader() + for global_id, row in enumerate(rows): + writer.writerow({**dict.fromkeys(columns, ""), **row, "id": global_id}) + return buffer.getvalue().encode("utf-8") diff --git a/packages/examples/cvat/recording-oracle/src/handlers/completion/task_exporters/base.py b/packages/examples/cvat/recording-oracle/src/handlers/completion/task_exporters/base.py new file mode 100644 index 0000000000..2643a54e97 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/src/handlers/completion/task_exporters/base.py @@ -0,0 +1,49 @@ +from __future__ import annotations + +from abc import ABCMeta, abstractmethod +from typing import TYPE_CHECKING + +from src.core.config import Config +from src.core.storage import compose_data_bucket_filename, compose_results_bucket_filename +from src.handlers.validation.common import _TaskHandler +from src.services.cloud import make_client as make_cloud_client +from src.services.cloud.utils import BucketAccessInfo + +if TYPE_CHECKING: + from sqlalchemy.orm import Session + + from src.core.manifest import ManifestBase + + +class TaskExporter(_TaskHandler, metaclass=ABCMeta): + """ + Produces the task final annotations file. The Ground Truth annotations should be copied + into the output. + """ + + def __init__( + self, + escrow_address: str, + chain_id: int, + manifest: ManifestBase, + session: Session, + ) -> None: + super().__init__(escrow_address=escrow_address, chain_id=chain_id, manifest=manifest) + self.session = session + + self._eo_bucket = BucketAccessInfo.parse_obj(Config.exchange_oracle_storage_config) + + def _download_annotation_result_file(self, filename: str) -> bytes: + "Download a file from the exchange oracle's escrow results dir." + return make_cloud_client(self._eo_bucket).download_file( + compose_results_bucket_filename(self.escrow_address, self.chain_id, filename) + ) + + def _download_task_data_file(self, filename: str) -> bytes: + "Download a file from the exchange oracle's escrow data dir." + return make_cloud_client(self._eo_bucket).download_file( + compose_data_bucket_filename(self.escrow_address, self.chain_id, filename) + ) + + @abstractmethod + def export(self) -> bytes: ... diff --git a/packages/examples/cvat/recording-oracle/src/handlers/completion/task_exporters/factory.py b/packages/examples/cvat/recording-oracle/src/handlers/completion/task_exporters/factory.py new file mode 100644 index 0000000000..748b1ee3ce --- /dev/null +++ b/packages/examples/cvat/recording-oracle/src/handlers/completion/task_exporters/factory.py @@ -0,0 +1,40 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +from src.core.manifest import get_manifest_task_type +from src.core.tasks import TaskTypes +from src.handlers.completion.task_exporters.audio import AudioTaskExporter +from src.handlers.completion.task_exporters.image import ImageTaskExporter + +if TYPE_CHECKING: + from sqlalchemy.orm import Session + + from src.core.manifest import ManifestBase + from src.handlers.completion.task_exporters.base import TaskExporter + + +def create_exporter( + manifest: ManifestBase, + escrow_address: str, + chain_id: int, + session: Session, +) -> TaskExporter: + task_type = get_manifest_task_type(manifest) + + match task_type: + case TaskTypes.audio_transcription: + exporter_type = AudioTaskExporter + case ( + TaskTypes.image_label_binary + | TaskTypes.image_boxes + | TaskTypes.image_polygons + | TaskTypes.image_points + | TaskTypes.image_boxes_from_points + | TaskTypes.image_skeletons_from_boxes + ): + exporter_type = ImageTaskExporter + case _: + raise NotImplementedError(f"Unsupported task type '{task_type}'") + + return exporter_type(escrow_address, chain_id, manifest, session) diff --git a/packages/examples/cvat/recording-oracle/src/handlers/completion/task_exporters/image.py b/packages/examples/cvat/recording-oracle/src/handlers/completion/task_exporters/image.py new file mode 100644 index 0000000000..43e5a06463 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/src/handlers/completion/task_exporters/image.py @@ -0,0 +1,190 @@ +from __future__ import annotations + +import io +import os +from pathlib import Path +from tempfile import TemporaryDirectory +from typing import TYPE_CHECKING + +import datumaro as dm + +from src.core.annotation_meta import RESULTING_ANNOTATIONS_FILE +from src.core.manifest import get_manifest_task_type +from src.core.tasks import TaskTypes +from src.core.tasks.cvat_formats import DM_DATASET_FORMAT_MAPPING, DM_GT_DATASET_FORMAT_MAPPING +from src.handlers.completion.task_exporters.base import TaskExporter +from src.handlers.validation.common import _TaskHandler +from src.services.cloud import make_client as make_cloud_client +from src.services.cloud.utils import BucketAccessInfo +from src.utils.annotations import ProjectLabels +from src.utils.zip_archive import extract_zip_archive, write_dir_to_zip_archive + +if TYPE_CHECKING: + from src.core.manifest import ManifestBase + + +class ImageTaskExporter(TaskExporter): + def export(self) -> bytes: + merged = self._download_annotation_result_file(RESULTING_ANNOTATIONS_FILE) + merger = _TaskAnnotationMerger( + escrow_address=self.escrow_address, + chain_id=self.chain_id, + manifest=self.manifest, + merged_annotations=io.BytesIO(merged), + ) + return merger.merge_results().read() + + +class _TaskAnnotationMerger(_TaskHandler): + def __init__( + self, + escrow_address: str, + chain_id: int, + manifest: ManifestBase, + *, + merged_annotations: io.IOBase, + ) -> None: + super().__init__(escrow_address=escrow_address, chain_id=chain_id, manifest=manifest) + + self._merged_annotations: io.IOBase = merged_annotations + + self._updated_merged_dataset_archive: io.IOBase | None = None + + self._temp_dir: Path | None = None + self._input_gt_dataset: dm.Dataset | None = None + + def _parse_gt_dataset(self, gt_file_data: bytes) -> dm.Dataset: + with TemporaryDirectory() as gt_temp_dir: + gt_filename = os.path.join(gt_temp_dir, "gt_annotations.json") + with open(gt_filename, "wb") as f: + f.write(gt_file_data) + + gt_dataset = dm.Dataset.import_from( + gt_filename, + format=DM_GT_DATASET_FORMAT_MAPPING[get_manifest_task_type(self.manifest)], + ) + + gt_dataset.init_cache() + + return gt_dataset + + def _load_gt_dataset(self): + input_gt_bucket = BucketAccessInfo.parse_obj(self.manifest.validation.gt_url) + gt_bucket_client = make_cloud_client(input_gt_bucket) + gt_data = gt_bucket_client.download_file(input_gt_bucket.path) + self._input_gt_dataset = self._parse_gt_dataset(gt_data) + + def _restore_original_image_paths(self, merged_dataset: dm.Dataset) -> dm.Dataset: + class RemoveCommonPrefix(dm.ItemTransform): + def __init__(self, extractor: dm.IExtractor, *, prefix: str) -> None: + super().__init__(extractor) + self._prefix = prefix + + def transform_item(self, item: dm.DatasetItem) -> dm.DatasetItem: + if item.id.startswith(self._prefix): + item = item.wrap(id=item.id[len(self._prefix) :]) + return item + + prefix = BucketAccessInfo.parse_obj(self.manifest.data.data_url).path.strip("/\\") + "/" + + # Remove prefixes if it can be done safely + sample_ids = {sample.id for sample in merged_dataset} + if all( + sample_id.startswith(prefix) and (sample_id[len(prefix) :] not in sample_ids) + for sample_id in sample_ids + ): + merged_dataset.transform(RemoveCommonPrefix, prefix=prefix) + + return merged_dataset + + def _prepare_merged_dataset(self): + tempdir = self._require_field(self._temp_dir) + manifest = self._require_field(self.manifest) + merged_annotations = self._require_field(self._merged_annotations) + input_gt_dataset = self._require_field(self._input_gt_dataset) + + merged_dataset_path = tempdir / "merged" + merged_dataset_format = DM_DATASET_FORMAT_MAPPING[get_manifest_task_type(manifest)] + extract_zip_archive(merged_annotations, merged_dataset_path) + + merged_dataset = dm.Dataset.import_from( + os.fspath(merged_dataset_path), format=merged_dataset_format + ) + self._restore_original_image_paths(merged_dataset) + self._put_gt_into_merged_dataset(input_gt_dataset, merged_dataset, manifest=manifest) + + updated_merged_dataset_path = tempdir / "merged_updated" + merged_dataset.export( + updated_merged_dataset_path, merged_dataset_format, save_media=False, reindex=True + ) + + updated_merged_dataset_archive = io.BytesIO() + write_dir_to_zip_archive(updated_merged_dataset_path, updated_merged_dataset_archive) + updated_merged_dataset_archive.seek(0) + + self._updated_merged_dataset_archive = updated_merged_dataset_archive + + @classmethod + def _put_gt_into_merged_dataset( + cls, input_gt_dataset: dm.Dataset, merged_dataset: dm.Dataset, *, manifest: ManifestBase + ) -> None: + """ + Updates the merged dataset inplace, writing GT annotations corresponding to the task type. + """ + + match get_manifest_task_type(manifest): + case TaskTypes.image_boxes.value | TaskTypes.image_polygons.value: + merged_dataset.update(input_gt_dataset) + case TaskTypes.image_points.value: + merged_label_cat: dm.LabelCategories = merged_dataset.categories()[ + dm.AnnotationType.label + ] + + # we support no more than 1 label so far + assert len(manifest.annotation.labels) == 1 + + skeleton_label_id = next( + i for i, label in enumerate(merged_label_cat) if not label.parent + ) + point_label_id = next(i for i, label in enumerate(merged_label_cat) if label.parent) + + for sample in input_gt_dataset: + annotations = [ + dm.Skeleton( + elements=[ + # Put a point in the center of each GT bbox + # Not ideal, but it's the target for now + dm.Points( + [bbox.x + bbox.w / 2, bbox.y + bbox.h / 2], + label=point_label_id, + attributes=bbox.attributes, + ) + ], + label=skeleton_label_id, + ) + for bbox in sample.annotations + if isinstance(bbox, dm.Bbox) + ] + merged_dataset.put(sample.wrap(annotations=annotations)) + case TaskTypes.image_label_binary.value: + merged_dataset.update(input_gt_dataset) + case TaskTypes.image_boxes_from_points: + merged_dataset.update(input_gt_dataset) + case TaskTypes.image_skeletons_from_boxes: + # The original behavior of project_labels is broken for skeletons + input_gt_dataset = dm.Dataset(input_gt_dataset) + input_gt_dataset = input_gt_dataset.transform( + ProjectLabels, dst_labels=merged_dataset.categories()[dm.AnnotationType.label] + ) + merged_dataset.update(input_gt_dataset) + case _: + raise AssertionError(f"Unknown task type {get_manifest_task_type(manifest)}") + + def merge_results(self) -> io.IOBase: + with TemporaryDirectory() as tempdir: + self._temp_dir = Path(tempdir) + + self._load_gt_dataset() + self._prepare_merged_dataset() + + return self._require_field(self._updated_merged_dataset_archive) diff --git a/packages/examples/cvat/recording-oracle/src/handlers/validation/__init__.py b/packages/examples/cvat/recording-oracle/src/handlers/validation/__init__.py new file mode 100644 index 0000000000..54ba1eb45e --- /dev/null +++ b/packages/examples/cvat/recording-oracle/src/handlers/validation/__init__.py @@ -0,0 +1,10 @@ +from src.handlers.validation.handlers import validate_results +from src.handlers.validation.intermediate_results import process_intermediate_results +from src.handlers.validation.meta import parse_annotation_metafile, serialize_validation_meta + +__all__ = [ + "parse_annotation_metafile", + "process_intermediate_results", + "serialize_validation_meta", + "validate_results", +] diff --git a/packages/examples/cvat/recording-oracle/src/handlers/validation/common.py b/packages/examples/cvat/recording-oracle/src/handlers/validation/common.py new file mode 100644 index 0000000000..2cc9784a11 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/src/handlers/validation/common.py @@ -0,0 +1,66 @@ +from __future__ import annotations + +from dataclasses import dataclass +from typing import TYPE_CHECKING, TypeVar + +import src.cvat.api_calls as cvat_api +from src.core.validation_errors import DatasetValidationError + +if TYPE_CHECKING: + from pathlib import Path + + from src.core.gt_stats import GtStats + from src.core.manifest import ManifestBase + +UNKNOWN_QUALITY = -1 +"The value to be used when job quality cannot be computed (e.g. no GT images available)" + +_JobResults = dict[int, float] + +_RejectedJobs = dict[int, DatasetValidationError] + +_HoneypotFrameId = int +_ValidationFrameId = int +_HoneypotFrameToValFrame = dict[_HoneypotFrameId, _ValidationFrameId] +_TaskIdToValidationLayout = dict[int, cvat_api.models.ITaskValidationLayoutRead] +_TaskIdToHoneypotsMapping = dict[int, _HoneypotFrameToValFrame] +_TaskIdToFrameNames = dict[int, list[str]] +_TaskIdToLabels = dict[int, list[str]] + + +@dataclass +class _ValidationResult: + job_results: _JobResults + rejected_jobs: _RejectedJobs + gt_stats: GtStats + task_id_to_val_layout: _TaskIdToValidationLayout + task_id_to_honeypots_mapping: _TaskIdToHoneypotsMapping + task_id_to_frame_names: _TaskIdToFrameNames + task_id_to_labels: _TaskIdToLabels + + +@dataclass +class _HoneypotUpdateResult: + updated_gt_stats: GtStats + can_continue_annotation: bool + + +T = TypeVar("T") + + +class _TaskHandler: + def __init__( + self, + escrow_address: str, + chain_id: int, + manifest: ManifestBase, + ) -> None: + self.escrow_address = escrow_address + self.chain_id = chain_id + self.manifest = manifest + + self._temp_dir: Path | None = None + + def _require_field(self, field: T | None) -> T: + assert field is not None + return field diff --git a/packages/examples/cvat/recording-oracle/src/handlers/validation.py b/packages/examples/cvat/recording-oracle/src/handlers/validation/handlers.py similarity index 83% rename from packages/examples/cvat/recording-oracle/src/handlers/validation.py rename to packages/examples/cvat/recording-oracle/src/handlers/validation/handlers.py index 8c13346efa..4dce2b5baa 100644 --- a/packages/examples/cvat/recording-oracle/src/handlers/validation.py +++ b/packages/examples/cvat/recording-oracle/src/handlers/validation/handlers.py @@ -1,15 +1,17 @@ import io from collections import Counter from logging import Logger +from typing import cast from sqlalchemy.orm import Session import src.core.annotation_meta as annotation +import src.core.manifest as manifest_utils import src.core.validation_meta as validation import src.services.webhook as oracle_db_service from src.chain import escrow from src.core.config import Config -from src.core.manifest import TaskManifest, parse_manifest +from src.core.manifest import ManifestBase from src.core.oracle_events import ( RecordingOracleEvent_JobCompleted, RecordingOracleEvent_SubmissionRejected, @@ -20,11 +22,8 @@ from src.core.types import OracleWebhookTypes from src.core.validation_errors import TooFewGtError from src.core.validation_results import ValidationFailure, ValidationSuccess -from src.handlers.process_intermediate_results import ( - parse_annotation_metafile, - process_intermediate_results, - serialize_validation_meta, -) +from src.handlers.validation.intermediate_results import process_intermediate_results +from src.handlers.validation.meta import parse_annotation_metafile, serialize_validation_meta from src.log import ROOT_LOGGER_NAME from src.services.cloud import make_client as make_cloud_client from src.services.cloud.utils import BucketAccessInfo @@ -33,9 +32,9 @@ module_logger_name = f"{ROOT_LOGGER_NAME}.cron.webhook" -class _TaskValidator: +class _EscrowValidator: def __init__( - self, escrow_address: str, chain_id: int, manifest: TaskManifest, db_session: Session + self, escrow_address: str, chain_id: int, manifest: ManifestBase, db_session: Session ) -> None: self.escrow_address = escrow_address self.chain_id = chain_id @@ -101,7 +100,7 @@ def _handle_validation_result(self, validation_result: ValidationResult): if isinstance(validation_result, ValidationSuccess): logger.info( f"Validation for escrow_address={escrow_address}: successful, " - f"average annotation quality is {validation_result.average_quality * 100:.2f}%" + f"average quality score is {validation_result.average_quality * 100:.2f}%" ) recor_validation_meta_path = self._compose_validation_results_bucket_filename( @@ -137,6 +136,15 @@ def _handle_validation_result(self, validation_result: ValidationResult): job_meta.job_id: job_meta.assignment_id for job_meta in self.annotation_meta.jobs } + if self.manifest.version == 1: + manifest = cast("manifest_utils.v1.JobManifest", self.manifest) + quality_threshold = manifest.validation.min_quality + elif self.manifest.version == 2: + manifest = cast("manifest_utils.v2.JobManifest", self.manifest) + quality_threshold = manifest.annotation.validation.target_score + else: + raise NotImplementedError(f"Unknown manifest version '{manifest.version}'") + oracle_db_service.outbox.create_webhook( db_session, escrow_address, @@ -149,7 +157,7 @@ def _handle_validation_result(self, validation_result: ValidationResult): assignment_id=job_id_to_assignment_id[rejected_job_id], reason=self._LOW_QUALITY_REASON_MESSAGE_TEMPLATE.format( validation_result.job_results[rejected_job_id], - self.manifest.validation.min_quality, + quality_threshold, ), ) for rejected_job_id, reason in validation_result.rejected_jobs.items() @@ -168,9 +176,9 @@ def validate_results( ): logger = get_function_logger(module_logger_name) - manifest = parse_manifest(escrow.get_escrow_manifest(chain_id, escrow_address)) + manifest = manifest_utils.parse_manifest(escrow.get_escrow_manifest(chain_id, escrow_address)) - validator = _TaskValidator( + validator = _EscrowValidator( escrow_address=escrow_address, chain_id=chain_id, manifest=manifest, db_session=db_session ) validator.set_logger(logger) diff --git a/packages/examples/cvat/recording-oracle/src/handlers/process_intermediate_results.py b/packages/examples/cvat/recording-oracle/src/handlers/validation/intermediate_results.py similarity index 53% rename from packages/examples/cvat/recording-oracle/src/handlers/process_intermediate_results.py rename to packages/examples/cvat/recording-oracle/src/handlers/validation/intermediate_results.py index 74a1bde5ca..ee7dc13724 100644 --- a/packages/examples/cvat/recording-oracle/src/handlers/process_intermediate_results.py +++ b/packages/examples/cvat/recording-oracle/src/handlers/validation/intermediate_results.py @@ -1,420 +1,39 @@ from __future__ import annotations -import io import logging -import os from collections import Counter -from dataclasses import dataclass from functools import cached_property -from pathlib import Path -from tempfile import TemporaryDirectory from typing import TYPE_CHECKING, TypeVar -import datumaro as dm import numpy as np import src.cvat.api_calls as cvat_api import src.models.validation as db_models import src.services.validation as db_service -from src.core.annotation_meta import AnnotationMeta from src.core.config import Config -from src.core.gt_stats import GtKey, GtStats, ValidationFrameStats -from src.core.types import TaskTypes -from src.core.validation_errors import ( - DatasetValidationError, - LowAccuracyError, - TooFewGtError, - TooSlowAnnotationError, -) +from src.core.gt_stats import GtKey, ValidationFrameStats +from src.core.validation_errors import TooFewGtError, TooSlowAnnotationError from src.core.validation_meta import JobMeta, ResultMeta, ValidationMeta -from src.core.validation_results import FinalResult, ValidationFailure, ValidationSuccess +from src.core.validation_results import ValidationFailure, ValidationSuccess from src.db.utils import ForUpdateParams -from src.services.cloud import make_client as make_cloud_client -from src.services.cloud.utils import BucketAccessInfo +from src.handlers.validation.common import ( + UNKNOWN_QUALITY, + _HoneypotUpdateResult, + _JobResults, + _ValidationResult, +) +from src.handlers.validation.quality_checkers.factory import create_quality_checker from src.utils import grouped -from src.utils.annotations import ProjectLabels from src.utils.formatting import value_and_percent -from src.utils.zip_archive import extract_zip_archive, write_dir_to_zip_archive if TYPE_CHECKING: from collections.abc import Callable, Sequence from sqlalchemy.orm import Session - from src.core.manifest import TaskManifest - from src.cvat.interface import QualityReportData - -DM_DATASET_FORMAT_MAPPING = { - TaskTypes.image_label_binary: "cvat_images", - TaskTypes.image_polygons: "coco_instances", - TaskTypes.image_points: "coco_person_keypoints", - TaskTypes.image_boxes: "coco_instances", - TaskTypes.image_boxes_from_points: "coco_instances", - TaskTypes.image_skeletons_from_boxes: "coco_person_keypoints", -} - -DM_GT_DATASET_FORMAT_MAPPING = { - TaskTypes.image_label_binary: "cvat_images", - TaskTypes.image_points: "coco_instances", # we compare points against boxes - TaskTypes.image_polygons: "coco_instances", - TaskTypes.image_boxes: "coco_instances", - TaskTypes.image_boxes_from_points: "coco_instances", - TaskTypes.image_skeletons_from_boxes: "coco_person_keypoints", -} - -_JobResults = dict[int, float] - -_RejectedJobs = dict[int, DatasetValidationError] - -_HoneypotFrameId = int -_ValidationFrameId = int -_HoneypotFrameToValFrame = dict[_HoneypotFrameId, _ValidationFrameId] -_TaskIdToValidationLayout = dict[int, cvat_api.models.ITaskValidationLayoutRead] -_TaskIdToHoneypotsMapping = dict[int, _HoneypotFrameToValFrame] -_TaskIdToFrameNames = dict[int, list[str]] -_TaskIdToLabels = dict[int, list[str]] - - -@dataclass -class _ValidationResult: - job_results: _JobResults - rejected_jobs: _RejectedJobs - gt_stats: GtStats - task_id_to_val_layout: _TaskIdToValidationLayout - task_id_to_honeypots_mapping: _TaskIdToHoneypotsMapping - task_id_to_frame_names: _TaskIdToFrameNames - task_id_to_labels: _TaskIdToLabels - - -T = TypeVar("T") - - -class _TaskHandler: - def __init__( - self, - escrow_address: str, - chain_id: int, - manifest: TaskManifest, - ) -> None: - self.escrow_address = escrow_address - self.chain_id = chain_id - self.manifest = manifest - - self._temp_dir: Path | None = None - - def _require_field(self, field: T | None) -> T: - assert field is not None - return field - - -class _TaskValidator(_TaskHandler): - UNKNOWN_QUALITY = -1 - "The value to be used when job quality cannot be computed (e.g. no GT images available)" - - def __init__( - self, - escrow_address: str, - chain_id: int, - manifest: TaskManifest, - *, - meta: AnnotationMeta, - gt_stats: GtStats | None = None, - ) -> None: - super().__init__(escrow_address=escrow_address, chain_id=chain_id, manifest=manifest) - - self._gt_stats: GtStats = gt_stats or {} - - self._job_results: _JobResults | None = None - self._rejected_jobs: _RejectedJobs | None = None - - self._temp_dir: Path | None = None - self._meta: AnnotationMeta = meta - - def _validate_jobs(self): - manifest = self._require_field(self.manifest) - meta = self._require_field(self._meta) - - job_results: _JobResults = {} - rejected_jobs: _RejectedJobs = {} - - cvat_task_ids = {job_meta.task_id for job_meta in meta.jobs} - - task_id_to_quality_report_data: dict[int, QualityReportData] = {} - task_id_to_val_layout: dict[int, cvat_api.models.TaskValidationLayoutRead] = {} - task_id_to_honeypots_mapping: dict[int, _HoneypotFrameToValFrame] = {} - - # store sequence of frame names for each task - # task honeypot with frame index matches the sequence[index] - task_id_to_sequence_of_frame_names: dict[int, list[str]] = {} - - task_id_to_labels: dict[int, list[str]] = {} - - min_quality = manifest.validation.min_quality - - job_id_to_quality_report: dict[int, cvat_api.models.QualityReport] = {} - - for cvat_task_id in cvat_task_ids: - # obtain quality report details - task_labels = cvat_api.get_task_labels(cvat_task_id) - task_quality_report = cvat_api.get_task_quality_report(cvat_task_id) - task_quality_report_data = cvat_api.get_quality_report_data(task_quality_report.id) - task_id_to_quality_report_data[cvat_task_id] = task_quality_report_data - - # obtain task validation layout and define honeypots mapping - task_val_layout = cvat_api.get_task_validation_layout(cvat_task_id) - task_honeypot_frame_to_real = { - f: task_val_layout.honeypot_real_frames[idx] - for idx, f in enumerate(task_val_layout.honeypot_frames) - } - task_id_to_val_layout[cvat_task_id] = task_val_layout - task_id_to_honeypots_mapping[cvat_task_id] = task_honeypot_frame_to_real - task_id_to_sequence_of_frame_names[cvat_task_id] = [ - frame.name for frame in cvat_api.get_task_data_meta(cvat_task_id).frames - ] - task_id_to_labels[cvat_task_id] = task_labels - - # obtain quality reports for each job from the task - job_id_to_quality_report.update( - { - quality_report.job_id: quality_report - for quality_report in cvat_api.get_jobs_quality_reports(task_quality_report.id) - } - ) - - # accepted jobs from the previous epochs are not included - for job_meta in meta.jobs: - cvat_job_id = job_meta.job_id - cvat_task_id = job_meta.task_id - - # assess quality of the job's honeypots - task_quality_report_data = task_id_to_quality_report_data[cvat_task_id] - task_frame_names = task_id_to_sequence_of_frame_names[cvat_task_id] - task_honeypots = set(task_id_to_val_layout[cvat_task_id].honeypot_frames) - task_honeypots_mapping = task_id_to_honeypots_mapping[cvat_task_id] - task_labels = task_id_to_labels[cvat_task_id] - - job_honeypots = task_honeypots & set(job_meta.job_frame_range) - if not job_honeypots: - job_results[cvat_job_id] = self.UNKNOWN_QUALITY - rejected_jobs[cvat_job_id] = TooFewGtError - continue - - for honeypot in job_honeypots: - val_frame = task_honeypots_mapping[honeypot] - val_frame_name = task_frame_names[val_frame] - val_frame_key = GtKey(filename=val_frame_name, labels=task_labels) - - result = task_quality_report_data.frame_results[str(honeypot)] - self._gt_stats.setdefault(val_frame_key, ValidationFrameStats()) - self._gt_stats[val_frame_key].accumulated_quality += result.annotations.accuracy - - if result.annotations.accuracy < min_quality: - self._gt_stats[val_frame_key].failed_attempts += 1 - else: - self._gt_stats[val_frame_key].accepted_attempts += 1 - - # assess job quality - job_quality_report = job_id_to_quality_report[cvat_job_id] - - accuracy = job_quality_report.summary.accuracy - - job_results[cvat_job_id] = accuracy - - if accuracy < min_quality: - rejected_jobs[cvat_job_id] = LowAccuracyError() - - for gt_stat in self._gt_stats.values(): - gt_stat.total_uses = max( - gt_stat.total_uses, - gt_stat.failed_attempts + gt_stat.accepted_attempts, - # at the first iteration we have no information on total uses - # from previous iterations, so we derive it from the validation results - ) - - self._job_results = job_results - self._rejected_jobs = rejected_jobs - self._task_id_to_val_layout = task_id_to_val_layout - self._task_id_to_honeypots_mapping = task_id_to_honeypots_mapping - self._task_id_to_sequence_of_frame_names = task_id_to_sequence_of_frame_names - self._task_id_to_labels = task_id_to_labels - - def validate(self) -> _ValidationResult: - with TemporaryDirectory() as tempdir: - self._temp_dir = Path(tempdir) - - self._validate_jobs() - - return _ValidationResult( - job_results=self._require_field(self._job_results), - rejected_jobs=self._require_field(self._rejected_jobs), - gt_stats=self._require_field(self._gt_stats), - task_id_to_val_layout=self._require_field(self._task_id_to_val_layout), - task_id_to_honeypots_mapping=self._require_field(self._task_id_to_honeypots_mapping), - task_id_to_frame_names=self._require_field(self._task_id_to_sequence_of_frame_names), - task_id_to_labels=self._require_field(self._task_id_to_labels), - ) - - -class _TaskAnnotationMerger(_TaskHandler): - def __init__( - self, - escrow_address: str, - chain_id: int, - manifest: TaskManifest, - *, - merged_annotations: io.IOBase, - ) -> None: - super().__init__(escrow_address=escrow_address, chain_id=chain_id, manifest=manifest) - - self._merged_annotations: io.IOBase = merged_annotations - - self._updated_merged_dataset_archive: io.IOBase | None = None - - self._temp_dir: Path | None = None - self._input_gt_dataset: dm.Dataset | None = None - - def _parse_gt_dataset(self, gt_file_data: bytes) -> dm.Dataset: - with TemporaryDirectory() as gt_temp_dir: - gt_filename = os.path.join(gt_temp_dir, "gt_annotations.json") - with open(gt_filename, "wb") as f: - f.write(gt_file_data) - - gt_dataset = dm.Dataset.import_from( - gt_filename, - format=DM_GT_DATASET_FORMAT_MAPPING[self.manifest.annotation.type], - ) - - gt_dataset.init_cache() - - return gt_dataset - - def _load_gt_dataset(self): - input_gt_bucket = BucketAccessInfo.parse_obj(self.manifest.validation.gt_url) - gt_bucket_client = make_cloud_client(input_gt_bucket) - gt_data = gt_bucket_client.download_file(input_gt_bucket.path) - self._input_gt_dataset = self._parse_gt_dataset(gt_data) - - def _restore_original_image_paths(self, merged_dataset: dm.Dataset) -> dm.Dataset: - class RemoveCommonPrefix(dm.ItemTransform): - def __init__(self, extractor: dm.IExtractor, *, prefix: str) -> None: - super().__init__(extractor) - self._prefix = prefix - - def transform_item(self, item: dm.DatasetItem) -> dm.DatasetItem: - if item.id.startswith(self._prefix): - item = item.wrap(id=item.id[len(self._prefix) :]) - return item - - prefix = BucketAccessInfo.parse_obj(self.manifest.data.data_url).path.strip("/\\") + "/" - - # Remove prefixes if it can be done safely - sample_ids = {sample.id for sample in merged_dataset} - if all( - sample_id.startswith(prefix) and (sample_id[len(prefix) :] not in sample_ids) - for sample_id in sample_ids - ): - merged_dataset.transform(RemoveCommonPrefix, prefix=prefix) - - return merged_dataset - - def _prepare_merged_dataset(self): - tempdir = self._require_field(self._temp_dir) - manifest = self._require_field(self.manifest) - merged_annotations = self._require_field(self._merged_annotations) - input_gt_dataset = self._require_field(self._input_gt_dataset) - - merged_dataset_path = tempdir / "merged" - merged_dataset_format = DM_DATASET_FORMAT_MAPPING[manifest.annotation.type] - extract_zip_archive(merged_annotations, merged_dataset_path) - - merged_dataset = dm.Dataset.import_from( - os.fspath(merged_dataset_path), format=merged_dataset_format - ) - self._restore_original_image_paths(merged_dataset) - self._put_gt_into_merged_dataset(input_gt_dataset, merged_dataset, manifest=manifest) - - updated_merged_dataset_path = tempdir / "merged_updated" - merged_dataset.export( - updated_merged_dataset_path, merged_dataset_format, save_media=False, reindex=True - ) - - updated_merged_dataset_archive = io.BytesIO() - write_dir_to_zip_archive(updated_merged_dataset_path, updated_merged_dataset_archive) - updated_merged_dataset_archive.seek(0) - - self._updated_merged_dataset_archive = updated_merged_dataset_archive - - @classmethod - def _put_gt_into_merged_dataset( - cls, input_gt_dataset: dm.Dataset, merged_dataset: dm.Dataset, *, manifest: TaskManifest - ) -> None: - """ - Updates the merged dataset inplace, writing GT annotations corresponding to the task type. - """ - - match manifest.annotation.type: - case TaskTypes.image_boxes.value | TaskTypes.image_polygons.value: - merged_dataset.update(input_gt_dataset) - case TaskTypes.image_points.value: - merged_label_cat: dm.LabelCategories = merged_dataset.categories()[ - dm.AnnotationType.label - ] - - # we support no more than 1 label so far - assert len(manifest.annotation.labels) == 1 - - skeleton_label_id = next( - i for i, label in enumerate(merged_label_cat) if not label.parent - ) - point_label_id = next(i for i, label in enumerate(merged_label_cat) if label.parent) - - for sample in input_gt_dataset: - annotations = [ - dm.Skeleton( - elements=[ - # Put a point in the center of each GT bbox - # Not ideal, but it's the target for now - dm.Points( - [bbox.x + bbox.w / 2, bbox.y + bbox.h / 2], - label=point_label_id, - attributes=bbox.attributes, - ) - ], - label=skeleton_label_id, - ) - for bbox in sample.annotations - if isinstance(bbox, dm.Bbox) - ] - merged_dataset.put(sample.wrap(annotations=annotations)) - case TaskTypes.image_label_binary.value: - merged_dataset.update(input_gt_dataset) - case TaskTypes.image_boxes_from_points: - merged_dataset.update(input_gt_dataset) - case TaskTypes.image_skeletons_from_boxes: - # The original behavior of project_labels is broken for skeletons - input_gt_dataset = dm.Dataset(input_gt_dataset) - input_gt_dataset = input_gt_dataset.transform( - ProjectLabels, dst_labels=merged_dataset.categories()[dm.AnnotationType.label] - ) - merged_dataset.update(input_gt_dataset) - case _: - raise AssertionError(f"Unknown task type {manifest.annotation.type}") - - def merge_results(self) -> io.IOBase: - with TemporaryDirectory() as tempdir: - self._temp_dir = Path(tempdir) - - self._load_gt_dataset() - self._prepare_merged_dataset() - - return self._require_field(self._updated_merged_dataset_archive) - - -@dataclass -class _HoneypotUpdateResult: - updated_gt_stats: GtStats - can_continue_annotation: bool - + from src.core.annotation_meta import AnnotationMeta + from src.core.gt_stats import GtStats + from src.core.manifest import ManifestBase _K = TypeVar("_K") @@ -423,7 +42,7 @@ class _TaskHoneypotManager: def __init__( self, task: db_models.Task, - manifest: TaskManifest, + manifest: ManifestBase, *, annotation_meta: AnnotationMeta, gt_stats: GtStats, @@ -744,7 +363,7 @@ def process_intermediate_results( # noqa: PLR0912 escrow_address: str, chain_id: int, meta: AnnotationMeta, - manifest: TaskManifest, + manifest: ManifestBase, logger: logging.Logger, ) -> ValidationSuccess | ValidationFailure: should_complete = False @@ -784,15 +403,15 @@ def process_intermediate_results( # noqa: PLR0912 for gt_stat in db_service.get_task_gt_stats(session, task.id) } - validator = _TaskValidator( - escrow_address=escrow_address, - chain_id=chain_id, - manifest=manifest, + checker = create_quality_checker( + manifest, + escrow_address, + chain_id, meta=unchecked_jobs_meta, gt_stats=gt_stats, ) - validation_result = validator.validate() + validation_result = checker.validate() job_results = validation_result.job_results rejected_jobs = validation_result.rejected_jobs @@ -940,112 +559,6 @@ def process_intermediate_results( # noqa: PLR0912 job_results=job_results, validation_meta=validation_meta, average_quality=np.mean( - [v for v in job_results.values() if v != _TaskValidator.UNKNOWN_QUALITY and v >= 0] - or [0] - ), - ) - - -def process_final_results( - session: Session, - *, - escrow_address: str, - chain_id: int, - meta: AnnotationMeta, - merged_annotations: io.RawIOBase, - manifest: TaskManifest, - logger: logging.Logger, -) -> FinalResult: - assert logger # unused - - task = db_service.get_task_by_escrow_address( - session, - escrow_address, - for_update=ForUpdateParams( - nowait=True - ), # should not happen, but waiting should not block processing - ) - if not task: - raise AssertionError(f"Validation results for escrow {escrow_address} not found") - - merger = _TaskAnnotationMerger( - escrow_address=escrow_address, - chain_id=chain_id, - manifest=manifest, - merged_annotations=merged_annotations, - ) - - merged_annotations = merger.merge_results() - - job_final_result_ids: dict[str, str] = {} - - for job_meta in meta.jobs: - job = db_service.get_job_by_cvat_id(session, job_meta.job_id) - if not job: - raise AssertionError( - f"Can't find validation results for job " f"{job_meta.job_id} ({escrow_address=})" - ) - - assignment_validation_result = db_service.get_validation_result_by_assignment_id( - session, job_meta.assignment_id - ) - if not assignment_validation_result: - raise AssertionError( - f"Can't find validation results for assignments " - f"{job_meta.assignment_id} ({escrow_address=})" - ) - - job_final_result_ids[job.id] = assignment_validation_result.id - - task_jobs = task.jobs - - task_validation_results = db_service.get_task_validation_results(session, task.id) - - job_id_to_meta_id = {job.id: i for i, job in enumerate(task_jobs)} - - validation_result_id_to_meta_id = {r.id: i for i, r in enumerate(task_validation_results)} - - validation_meta = ValidationMeta( - jobs=[ - JobMeta( - job_id=job_id_to_meta_id[job.id], - final_result_id=validation_result_id_to_meta_id[job_final_result_ids[job.id]], - ) - for job in task_jobs - ], - results=[ - ResultMeta( - id=validation_result_id_to_meta_id[r.id], - job_id=job_id_to_meta_id[r.job.id], - annotator_wallet_address=r.annotator_wallet_address, - annotation_quality=r.annotation_quality, - ) - for r in task_validation_results - ], - ) - - # Include final results for all jobs - job_results: _JobResults = { - job.cvat_id: task_validation_results[ - validation_result_id_to_meta_id[job_final_result_ids[job.id]] - ].annotation_quality - for job in task_jobs - } - - return FinalResult( - job_results=job_results, - validation_meta=validation_meta, - resulting_annotations=merged_annotations.read(), - average_quality=np.mean( - [v for v in job_results.values() if v != _TaskValidator.UNKNOWN_QUALITY and v >= 0] - or [0] + [v for v in job_results.values() if v != UNKNOWN_QUALITY and v >= 0] or [0] ), ) - - -def parse_annotation_metafile(metafile: io.RawIOBase) -> AnnotationMeta: - return AnnotationMeta.model_validate_json(metafile.read()) - - -def serialize_validation_meta(validation_meta: ValidationMeta) -> bytes: - return validation_meta.model_dump_json().encode() diff --git a/packages/examples/cvat/recording-oracle/src/handlers/validation/meta.py b/packages/examples/cvat/recording-oracle/src/handlers/validation/meta.py new file mode 100644 index 0000000000..fd2d87b834 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/src/handlers/validation/meta.py @@ -0,0 +1,18 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +from src.core.annotation_meta import AnnotationMeta + +if TYPE_CHECKING: + import io + + from src.core.validation_meta import ValidationMeta + + +def parse_annotation_metafile(metafile: io.RawIOBase) -> AnnotationMeta: + return AnnotationMeta.model_validate_json(metafile.read()) + + +def serialize_validation_meta(validation_meta: ValidationMeta) -> bytes: + return validation_meta.model_dump_json().encode() diff --git a/packages/examples/cvat/recording-oracle/src/handlers/validation/quality_checkers/__init__.py b/packages/examples/cvat/recording-oracle/src/handlers/validation/quality_checkers/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/examples/cvat/recording-oracle/src/handlers/validation/quality_checkers/audio.py b/packages/examples/cvat/recording-oracle/src/handlers/validation/quality_checkers/audio.py new file mode 100644 index 0000000000..fdfb29e093 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/src/handlers/validation/quality_checkers/audio.py @@ -0,0 +1,338 @@ +from __future__ import annotations + +import csv +import io +from typing import TYPE_CHECKING + +from audio_qe import ( + Granularity, + GroupingConfig, + GroupingStrategy, + Interval, + Metric, + Normalizer, + NormalizerConfig, + NormalizerMode, + TranscriptionRequirement, + lang_preset, + match_transcriptions, +) +from audio_qe.data import AlignMode +from audio_qe.transcription_matching import aggregate_metric, tokenize + +from src.core.config import Config +from src.core.manifest.v2 import TargetMetrics +from src.core.storage import compose_data_bucket_filename, compose_results_bucket_filename +from src.core.tasks.audio_transcription.meta import ( + InputGtRegion, + RegionKind, + TaskMetaLayout, + TaskMetaSerializer, + TaskResultsLayout, + parse_gt_tsv, + parse_time, +) +from src.core.tasks.audio_transcription.spec import NormalizerPreset, parse_audio_manifest +from src.core.validation_errors import LowQualityError, TooFewGtError +from src.handlers.validation.common import UNKNOWN_QUALITY +from src.handlers.validation.quality_checkers.base import TaskQualityChecker +from src.services.cloud import make_client as make_cloud_client +from src.services.cloud.utils import BucketAccessInfo + +if TYPE_CHECKING: + from src.core.annotation_meta import JobMeta + from src.core.tasks.audio_transcription.meta import Clip, PlacedRegion + from src.services.cloud.client import StorageClient + +# Groups are keyed by the presented honeypot so each honeypot's transcription is aligned in +# isolation (no cross-honeypot / cross-file overlap). +_GROUP_ATTR = "honeypot_id" + + +class AudioTaskQualityChecker(TaskQualityChecker): + """ + Scores audio-transcription assignments. CVAT doesn't support quality computation for such tasks + yet, so the computations are performed in the oracle. + + Each assignment annotations are scored per their honeypots, computing the WER/CER metrics. + + Honeypot rotation is not used. + """ + + ALLOWED_METRICS = (TargetMetrics.wer, TargetMetrics.cer) + + _METRIC_PARAMS = { + TargetMetrics.wer: { + "granularity": Granularity.WORD, + "align": AlignMode.WORD, + "metric": Metric.EQUALITY, + }, + TargetMetrics.cer: { + "granularity": Granularity.CHARACTER, + "align": AlignMode.CHAR, + "metric": Metric.EQUALITY, + }, + } + + def _validate_jobs(self) -> None: + spec = parse_audio_manifest(self.manifest) + + metric = spec.validation.target_metric + if metric not in self.ALLOWED_METRICS: + raise NotImplementedError( + "Audio transcription validation only supports {} metrics, got '{}'".format( + ", ".join(v.value for v in self.ALLOWED_METRICS), metric.value + ) + ) + + target = spec.validation.target_score + transcription_attr = spec.details.transcription_attr_name + + req = TranscriptionRequirement( + **self._METRIC_PARAMS[metric], + text_attribute=transcription_attr, + normalizer=self._normalizer_config(spec.details.normalizer), + grouping=GroupingConfig(attribute=_GROUP_ATTR, strategy=GroupingStrategy.JOIN), + overlap_tolerance_ms=round(spec.details.boundary_tolerance.total_seconds() * 1000), + ) + normalizer = Normalizer(req.normalizer) + + client = make_cloud_client( + BucketAccessInfo.parse_obj(Config.exchange_oracle_storage_config) + ) + gt_annotations = self._load_gt(client) + clips_by_id = self._load_clips_meta(client) + task_clips = self._load_task_clips(client) + annotation_bytes = self._download_assignment_annotations(client) + + job_results: dict[int, float] = {} + rejected_jobs: dict[int, object] = {} + + for job_meta in self._meta.jobs: + ds_annotations = self._parse_annotations(annotation_bytes[job_meta.job_id]) + # Each CVAT task holds exactly one clip; join the job to its clip via the EO-recorded + # task -> clip mapping. An empty submission still resolves here, so its honeypots score + # as full deletions (rate 1.0) instead of being treated as unverifiable. + clip_meta = clips_by_id[task_clips[job_meta.task_id]] + + gt_intervals, hyp_intervals = self._build_intervals( + ds_annotations, + gt_annotations, + clip_meta=clip_meta, + transcription_attr=transcription_attr, + ) + if not gt_intervals: + # No honeypots available - not expected by construction. + job_results[job_meta.job_id] = UNKNOWN_QUALITY + rejected_jobs[job_meta.job_id] = TooFewGtError() + continue + + report = match_transcriptions(gt_intervals, hyp_intervals, req=req) + rate = self._job_error_rate(report, req, normalizer) + job_results[job_meta.job_id] = rate + + # WER/CER are lower-is-better; reject when the error rate exceeds the target. + if rate > target: + rejected_jobs[job_meta.job_id] = LowQualityError() + + self._job_results = job_results + self._rejected_jobs = rejected_jobs + + # No honeypot rotation for audio: empty gt_stats skips the rotation branch in + # process_intermediate_results; the layout maps are unused but must be set for validate(). + self._gt_stats = {} + self._task_id_to_val_layout = {} + self._task_id_to_honeypots_mapping = {} + self._task_id_to_sequence_of_frame_names = {} + self._task_id_to_labels = {} + + @staticmethod + def _normalizer_config(preset: NormalizerPreset | None) -> NormalizerConfig: + # Absent normalizer = passthrough; basic = built-in mode; a language code resolves to its + # preset (BASIC plus per-language rules). + if preset is None: + return NormalizerConfig(mode=NormalizerMode.NONE) + if preset == NormalizerPreset.basic: + return NormalizerConfig(mode=NormalizerMode.BASIC) + return lang_preset(preset.value) + + def _load_gt(self, client: StorageClient) -> dict[str, InputGtRegion]: + data = client.download_file( + compose_data_bucket_filename( + self.escrow_address, self.chain_id, TaskMetaLayout.GT_FILENAME + ) + ) + return {region.id: region for region in parse_gt_tsv(data)} + + def _load_clips_meta(self, client: StorageClient) -> dict[str, Clip]: + "Returns clip id -> clip meta mapping." + + data = client.download_file( + compose_data_bucket_filename( + self.escrow_address, self.chain_id, TaskMetaLayout.CLIPS_FILENAME + ) + ) + return {a.id: a for a in TaskMetaSerializer().parse_clips(data)} + + def _load_task_clips(self, client: StorageClient) -> dict[int, str]: + "Returns CVAT task id -> clip id mapping." + + data = client.download_file( + compose_data_bucket_filename( + self.escrow_address, self.chain_id, TaskMetaLayout.TASK_CLIPS_FILENAME + ) + ) + return TaskMetaSerializer().parse_task_clips(data) + + @staticmethod + def _parse_annotations(annotation: bytes) -> list[dict]: + return list(csv.DictReader(io.StringIO(annotation.decode("utf-8")), delimiter="\t")) + + def _build_intervals( + self, + ds_annotations: list[dict], + gt_annotations: dict[str, InputGtRegion], + *, + clip_meta: Clip, + transcription_attr: str, + ) -> tuple[list[Interval], list[Interval]]: + gt_placements = [p for p in clip_meta.placed if p.kind == RegionKind.gt] + + # Ground-truth reference intervals for every presented honeypot (built regardless of what + # the annotator produced, so an omitted honeypot becomes a missing group = full errors). + gt_intervals: list[Interval] = [] + counter = 0 + for placed in gt_placements: + honeypot_id = self._honeypot_id(placed) + for region_id in placed.input_ids: + try: + gt = gt_annotations[region_id] + except KeyError as e: + raise AssertionError( + f"Honeypot region '{region_id}' is missing from gt.tsv" + ) from e + + gt_intervals.append( + Interval( + id=counter, + start=gt.start.total_seconds() * 1000.0, + stop=gt.stop.total_seconds() * 1000.0, + label=gt.label, + extra={transcription_attr: gt.text, _GROUP_ATTR: honeypot_id}, + ) + ) + counter += 1 + + # Annotator (hypothesis) intervals: only rows falling inside a honeypot window, mapped from + # clip-time back to source-file time. + hyp_intervals: list[Interval] = [] + for row in ds_annotations: + start_s = parse_time(row["start"]).total_seconds() + stop_s = parse_time(row["stop"]).total_seconds() + placed = self._honeypot_at(clip_meta, start_s, stop_s) + if placed is None: + continue + offset = placed.source_start - placed.clip_start + hyp_intervals.append( + Interval( + id=counter, + start=(start_s + offset) * 1000.0, + stop=(stop_s + offset) * 1000.0, + label=row["label"], + extra={ + transcription_attr: row[transcription_attr], + _GROUP_ATTR: self._honeypot_id(placed), + }, + ) + ) + counter += 1 + + return gt_intervals, hyp_intervals + + def _download_assignment_annotations(self, client: StorageClient) -> dict[int, bytes]: + "Download every job's per-assignment annotation TSV up front, keyed by cvat job id." + return { + job_meta.job_id: self._download_assignment_tsv(client, job_meta) + for job_meta in self._meta.jobs + } + + def _download_assignment_tsv(self, client: StorageClient, job_meta: JobMeta) -> bytes: + return client.download_file( + compose_results_bucket_filename( + self.escrow_address, + self.chain_id, + TaskResultsLayout.assignment_annotation_filename( + job_meta.job_id, job_meta.assignment_id + ), + ) + ) + + @staticmethod + def _honeypot_id(placed: PlacedRegion) -> str: + # A gt placement is always built from >=1 GT input ROI, so input_ids is non-empty. + assert placed.input_ids, f"honeypot placement has no input regions: {placed}" + return ",".join(placed.input_ids) + + @staticmethod + def _honeypot_at(clip: Clip, start_s: float, stop_s: float) -> PlacedRegion | None: + """ + Return the honeypot placement that fully contains the annotator interval ``[start_s, + stop_s]`` within its inclusion window. + + Each honeypot window is extended by half of the join pause to the adjacent region on each + side (``[hp_start - pause/2, hp_stop + pause/2]``); an interval counts for the honeypot only + if both its endpoints fall inside. Annotator segment boundaries don't align with the + synthetic cut/pause boundaries: the half-pause margin keeps a segment that drifts into the + surrounding pause, while requiring both endpoints inside excludes one that spills into an + adjacent region. + """ + regions = sorted(clip.placed, key=lambda p: p.clip_start) + for idx, p in enumerate(regions): + if p.kind != RegionKind.gt: + continue + lo = p.clip_start + hi = p.clip_stop + if idx > 0: + lo -= (p.clip_start - regions[idx - 1].clip_stop) / 2 + if idx < len(regions) - 1: + hi += (regions[idx + 1].clip_start - p.clip_stop) / 2 + if lo <= start_s and stop_s <= hi: + return p + return None + + def _job_error_rate(self, report, req: TranscriptionRequirement, normalizer) -> float: + """ + Micro-averaged error rate over the assignment's honeypots. The library's ``corpus_rate`` + only aggregates matched groups, so missing groups (honeypot the annotator left empty) are + added as full deletions and extra groups as insertions (mirrors the CVAT accumulation). + """ + total_err = 0.0 + total_ref = 0 + + matched_ref = sum(len(a.ref_units) for a in report.alignments) + if matched_ref: + _, matched_rate = aggregate_metric( + report.alignments, + metric=req.metric, + threshold=req.threshold, + granularity=req.granularity, + ) + total_err += matched_rate * matched_ref + total_ref += matched_ref + + for _key, gt_group in report.missing_groups: + units = self._group_units(gt_group, req, normalizer) + total_err += len(units) + total_ref += len(units) + + for _key, ds_group in report.extra_groups: + total_err += len(self._group_units(ds_group, req, normalizer)) + + return total_err / total_ref if total_ref else 0.0 + + @staticmethod + def _group_units(group: list[Interval], req: TranscriptionRequirement, normalizer) -> list[str]: + joined = req.grouping.join_separator.join( + iv.extra[req.text_attribute] for iv in sorted(group, key=lambda i: i.start) + ) + return tokenize(normalizer(joined), granularity=req.granularity) diff --git a/packages/examples/cvat/recording-oracle/src/handlers/validation/quality_checkers/base.py b/packages/examples/cvat/recording-oracle/src/handlers/validation/quality_checkers/base.py new file mode 100644 index 0000000000..f029628eb2 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/src/handlers/validation/quality_checkers/base.py @@ -0,0 +1,60 @@ +from __future__ import annotations + +from abc import ABCMeta, abstractmethod +from pathlib import Path +from tempfile import TemporaryDirectory +from typing import TYPE_CHECKING + +from src.handlers.validation.common import _TaskHandler, _ValidationResult + +if TYPE_CHECKING: + from src.core.annotation_meta import AnnotationMeta + from src.core.gt_stats import GtStats + from src.core.manifest import ManifestBase + from src.handlers.validation.common import _JobResults, _RejectedJobs + + +class TaskQualityChecker(_TaskHandler, metaclass=ABCMeta): + def __init__( + self, + escrow_address: str, + chain_id: int, + manifest: ManifestBase, + *, + meta: AnnotationMeta, + gt_stats: GtStats | None = None, + ) -> None: + super().__init__(escrow_address=escrow_address, chain_id=chain_id, manifest=manifest) + + self._gt_stats: GtStats = gt_stats or {} + + self._job_results: _JobResults | None = None + self._rejected_jobs: _RejectedJobs | None = None + + self._temp_dir: Path | None = None + self._meta: AnnotationMeta = meta + + @abstractmethod + def _validate_jobs(self) -> None: + """ + Compute per-job quality and populate: + ``_job_results``, ``_rejected_jobs``, ``_gt_stats``, ``_task_id_to_val_layout``, + ``_task_id_to_honeypots_mapping``, ``_task_id_to_sequence_of_frame_names``, + ``_task_id_to_labels``. + """ + + def validate(self) -> _ValidationResult: + with TemporaryDirectory() as tempdir: + self._temp_dir = Path(tempdir) + + self._validate_jobs() + + return _ValidationResult( + job_results=self._require_field(self._job_results), + rejected_jobs=self._require_field(self._rejected_jobs), + gt_stats=self._require_field(self._gt_stats), + task_id_to_val_layout=self._require_field(self._task_id_to_val_layout), + task_id_to_honeypots_mapping=self._require_field(self._task_id_to_honeypots_mapping), + task_id_to_frame_names=self._require_field(self._task_id_to_sequence_of_frame_names), + task_id_to_labels=self._require_field(self._task_id_to_labels), + ) diff --git a/packages/examples/cvat/recording-oracle/src/handlers/validation/quality_checkers/factory.py b/packages/examples/cvat/recording-oracle/src/handlers/validation/quality_checkers/factory.py new file mode 100644 index 0000000000..a6d012304e --- /dev/null +++ b/packages/examples/cvat/recording-oracle/src/handlers/validation/quality_checkers/factory.py @@ -0,0 +1,42 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +from src.core.manifest import get_manifest_task_type +from src.core.tasks import TaskTypes +from src.handlers.validation.quality_checkers.audio import AudioTaskQualityChecker +from src.handlers.validation.quality_checkers.image import ImageTaskQualityChecker + +if TYPE_CHECKING: + from src.core.annotation_meta import AnnotationMeta + from src.core.gt_stats import GtStats + from src.core.manifest import ManifestBase + from src.handlers.validation.quality_checkers.base import TaskQualityChecker + + +def create_quality_checker( + manifest: ManifestBase, + escrow_address: str, + chain_id: int, + *, + meta: AnnotationMeta, + gt_stats: GtStats | None = None, +) -> TaskQualityChecker: + task_type = get_manifest_task_type(manifest) + + match task_type: + case TaskTypes.audio_transcription: + checker_type = AudioTaskQualityChecker + case ( + TaskTypes.image_label_binary + | TaskTypes.image_boxes + | TaskTypes.image_polygons + | TaskTypes.image_points + | TaskTypes.image_boxes_from_points + | TaskTypes.image_skeletons_from_boxes + ): + checker_type = ImageTaskQualityChecker + case _: + raise NotImplementedError(f"Unsupported task type '{task_type}'") + + return checker_type(escrow_address, chain_id, manifest, meta=meta, gt_stats=gt_stats) diff --git a/packages/examples/cvat/recording-oracle/src/handlers/validation/quality_checkers/image.py b/packages/examples/cvat/recording-oracle/src/handlers/validation/quality_checkers/image.py new file mode 100644 index 0000000000..4851724c97 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/src/handlers/validation/quality_checkers/image.py @@ -0,0 +1,125 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +import src.cvat.api_calls as cvat_api +from src.core.gt_stats import GtKey, ValidationFrameStats +from src.core.validation_errors import LowQualityError, TooFewGtError +from src.handlers.validation.common import UNKNOWN_QUALITY +from src.handlers.validation.quality_checkers.base import TaskQualityChecker + +if TYPE_CHECKING: + from src.cvat.interface import QualityReportData + from src.handlers.validation.common import _HoneypotFrameToValFrame, _JobResults, _RejectedJobs + + +class ImageTaskQualityChecker(TaskQualityChecker): + def _validate_jobs(self) -> None: + manifest = self._require_field(self.manifest) + meta = self._require_field(self._meta) + if manifest.version != 1: + raise NotImplementedError + + job_results: _JobResults = {} + rejected_jobs: _RejectedJobs = {} + + cvat_task_ids = {job_meta.task_id for job_meta in meta.jobs} + + task_id_to_quality_report_data: dict[int, QualityReportData] = {} + task_id_to_val_layout: dict[int, cvat_api.models.TaskValidationLayoutRead] = {} + task_id_to_honeypots_mapping: dict[int, _HoneypotFrameToValFrame] = {} + + # store sequence of frame names for each task + # task honeypot with frame index matches the sequence[index] + task_id_to_sequence_of_frame_names: dict[int, list[str]] = {} + + task_id_to_labels: dict[int, list[str]] = {} + + min_quality = manifest.validation.min_quality + + job_id_to_quality_report: dict[int, cvat_api.models.QualityReport] = {} + + for cvat_task_id in cvat_task_ids: + # obtain quality report details + task_labels = cvat_api.get_task_labels(cvat_task_id) + task_quality_report = cvat_api.get_task_quality_report(cvat_task_id) + task_quality_report_data = cvat_api.get_quality_report_data(task_quality_report.id) + task_id_to_quality_report_data[cvat_task_id] = task_quality_report_data + + # obtain task validation layout and define honeypots mapping + task_val_layout = cvat_api.get_task_validation_layout(cvat_task_id) + task_honeypot_frame_to_real = { + f: task_val_layout.honeypot_real_frames[idx] + for idx, f in enumerate(task_val_layout.honeypot_frames) + } + task_id_to_val_layout[cvat_task_id] = task_val_layout + task_id_to_honeypots_mapping[cvat_task_id] = task_honeypot_frame_to_real + task_id_to_sequence_of_frame_names[cvat_task_id] = [ + frame.name for frame in cvat_api.get_task_data_meta(cvat_task_id).frames + ] + task_id_to_labels[cvat_task_id] = task_labels + + # obtain quality reports for each job from the task + job_id_to_quality_report.update( + { + quality_report.job_id: quality_report + for quality_report in cvat_api.get_jobs_quality_reports(task_quality_report.id) + } + ) + + # accepted jobs from the previous epochs are not included + for job_meta in meta.jobs: + cvat_job_id = job_meta.job_id + cvat_task_id = job_meta.task_id + + # assess quality of the job's honeypots + task_quality_report_data = task_id_to_quality_report_data[cvat_task_id] + task_frame_names = task_id_to_sequence_of_frame_names[cvat_task_id] + task_honeypots = set(task_id_to_val_layout[cvat_task_id].honeypot_frames) + task_honeypots_mapping = task_id_to_honeypots_mapping[cvat_task_id] + task_labels = task_id_to_labels[cvat_task_id] + + job_honeypots = task_honeypots & set(job_meta.job_frame_range) + if not job_honeypots: + job_results[cvat_job_id] = UNKNOWN_QUALITY + rejected_jobs[cvat_job_id] = TooFewGtError + continue + + for honeypot in job_honeypots: + val_frame = task_honeypots_mapping[honeypot] + val_frame_name = task_frame_names[val_frame] + val_frame_key = GtKey(filename=val_frame_name, labels=task_labels) + + result = task_quality_report_data.frame_results[str(honeypot)] + self._gt_stats.setdefault(val_frame_key, ValidationFrameStats()) + self._gt_stats[val_frame_key].accumulated_quality += result.annotations.accuracy + + if result.annotations.accuracy < min_quality: + self._gt_stats[val_frame_key].failed_attempts += 1 + else: + self._gt_stats[val_frame_key].accepted_attempts += 1 + + # assess job quality + job_quality_report = job_id_to_quality_report[cvat_job_id] + + accuracy = job_quality_report.summary.accuracy + + job_results[cvat_job_id] = accuracy + + if accuracy < min_quality: + rejected_jobs[cvat_job_id] = LowQualityError() + + for gt_stat in self._gt_stats.values(): + gt_stat.total_uses = max( + gt_stat.total_uses, + gt_stat.failed_attempts + gt_stat.accepted_attempts, + # at the first iteration we have no information on total uses + # from previous iterations, so we derive it from the validation results + ) + + self._job_results = job_results + self._rejected_jobs = rejected_jobs + self._task_id_to_val_layout = task_id_to_val_layout + self._task_id_to_honeypots_mapping = task_id_to_honeypots_mapping + self._task_id_to_sequence_of_frame_names = task_id_to_sequence_of_frame_names + self._task_id_to_labels = task_id_to_labels diff --git a/packages/examples/cvat/recording-oracle/src/models/__init__.py b/packages/examples/cvat/recording-oracle/src/models/__init__.py index e69de29bb2..4edf9ab64c 100644 --- a/packages/examples/cvat/recording-oracle/src/models/__init__.py +++ b/packages/examples/cvat/recording-oracle/src/models/__init__.py @@ -0,0 +1,10 @@ +from src.models.validation import GtStats, Job, Task, ValidationResult +from src.models.webhook import Webhook + +__all__ = [ + "GtStats", + "Job", + "Task", + "ValidationResult", + "Webhook", +] diff --git a/packages/examples/cvat/recording-oracle/src/services/cloud/types.py b/packages/examples/cvat/recording-oracle/src/services/cloud/types.py index 935dc7f4b1..830714f119 100644 --- a/packages/examples/cvat/recording-oracle/src/services/cloud/types.py +++ b/packages/examples/cvat/recording-oracle/src/services/cloud/types.py @@ -9,8 +9,8 @@ import pydantic -from src.core import manifest from src.core.config import Config, IStorageConfig +from src.core.manifest.shared import BucketUrl, BucketUrlBase from src.services.cloud.gcs import DEFAULT_GCS_HOST from src.services.cloud.s3 import DEFAULT_S3_HOST from src.utils.enums import BetterEnumMeta @@ -171,14 +171,14 @@ def from_storage_config(cls, config: type[IStorageConfig]) -> BucketAccessInfo: ) @classmethod - def from_bucket_url(cls, bucket_url: manifest.BucketUrl) -> BucketAccessInfo: + def from_bucket_url(cls, bucket_url: BucketUrl) -> BucketAccessInfo: return cls._from_dict(bucket_url.model_dump()) @classmethod def parse_obj( - cls, data: str | type[IStorageConfig] | manifest.BucketUrl | pydantic.AnyUrl + cls, data: str | type[IStorageConfig] | BucketUrl | pydantic.AnyUrl ) -> BucketAccessInfo: - if isinstance(data, manifest.BucketUrlBase): + if isinstance(data, BucketUrlBase): return cls.from_bucket_url(data) if isinstance(data, str): return cls.from_url(data) diff --git a/packages/examples/cvat/recording-oracle/src/services/webhook.py b/packages/examples/cvat/recording-oracle/src/services/webhook.py index 014c4651cd..773ef8c424 100644 --- a/packages/examples/cvat/recording-oracle/src/services/webhook.py +++ b/packages/examples/cvat/recording-oracle/src/services/webhook.py @@ -1,7 +1,6 @@ import datetime import uuid from collections.abc import Sequence -from enum import Enum from attrs import define from sqlalchemy import case, update @@ -14,11 +13,11 @@ from src.db.utils import ForUpdateParams from src.db.utils import maybe_for_update as _maybe_for_update from src.models.webhook import Webhook -from src.utils.enums import BetterEnumMeta +from src.utils.enums import BetterEnumMeta, StrEnum from src.utils.time import utcnow -class OracleWebhookDirectionTags(str, Enum, metaclass=BetterEnumMeta): +class OracleWebhookDirectionTags(StrEnum, metaclass=BetterEnumMeta): incoming = "incoming" outgoing = "outgoing" @@ -43,9 +42,9 @@ def create_webhook( Creates a webhook in a database """ assert not event_data or event_type, "'event_data' requires 'event_type'" - assert bool(event) ^ bool( - event_type - ), "'event' and 'event_type' cannot be used together. Please use only one of the fields" + assert bool(event) ^ bool(event_type), ( + "'event' and 'event_type' cannot be used together. Please use only one of the fields" + ) if event_type: if self.direction == OracleWebhookDirectionTags.incoming: @@ -97,9 +96,9 @@ def get_pending_webhooks( limit: int = 10, for_update: bool | ForUpdateParams = False, ) -> list[Webhook]: - assert not ( - event_type_in and event_type_not_in - ), f"{event_type_in} and {event_type_not_in} cannot be used together" + assert not (event_type_in and event_type_not_in), ( + f"{event_type_in} and {event_type_not_in} cannot be used together" + ) return ( _maybe_for_update(session.query(Webhook), enable=for_update) diff --git a/packages/examples/cvat/recording-oracle/src/utils/annotations.py b/packages/examples/cvat/recording-oracle/src/utils/annotations.py index 9553ecf5f5..352216b2f2 100644 --- a/packages/examples/cvat/recording-oracle/src/utils/annotations.py +++ b/packages/examples/cvat/recording-oracle/src/utils/annotations.py @@ -208,7 +208,7 @@ def _make_label_id_map(self, src_label_cat, dst_label_cat): src_id: dst_label_cat.find(src_label_cat[src_id].name, src_label_cat[src_id].parent)[0] for src_id in range(len(src_label_cat or ())) } - self._map_id = lambda src_id: id_mapping.get(src_id) + self._map_id = id_mapping.get def categories(self): return self._categories diff --git a/packages/examples/cvat/recording-oracle/src/utils/enums.py b/packages/examples/cvat/recording-oracle/src/utils/enums.py index d4c133b0e5..b069d48158 100644 --- a/packages/examples/cvat/recording-oracle/src/utils/enums.py +++ b/packages/examples/cvat/recording-oracle/src/utils/enums.py @@ -1,5 +1,12 @@ from enum import EnumMeta +from strenum import StrEnum # added in python 3.11 + +__all__ = [ + "BetterEnumMeta", + "StrEnum", +] + class BetterEnumMeta(EnumMeta): """ diff --git a/packages/examples/cvat/recording-oracle/tests/assets/cloud/audio_validation/assignments.json b/packages/examples/cvat/recording-oracle/tests/assets/cloud/audio_validation/assignments.json new file mode 100644 index 0000000000..0e7598abfb --- /dev/null +++ b/packages/examples/cvat/recording-oracle/tests/assets/cloud/audio_validation/assignments.json @@ -0,0 +1 @@ +[{"id":"21b0aeed1730488989aeeaf704cbcc35","clip_filename":"21b0aeed1730488989aeeaf704cbcc35.wav","clip_dur":55.5,"placed":[{"index":0,"source_filename":"audio2.wav","source_start":106.0,"source_stop":112.0,"clip_start":0.0,"clip_stop":6.0,"kind":"gt","input_ids":["audio2.wav:2"]},{"index":1,"source_filename":"audio3.wav","source_start":92.0,"source_stop":98.0,"clip_start":6.7,"clip_stop":12.7,"kind":"gt","input_ids":["audio3.wav:4"]},{"index":2,"source_filename":"audio4.wav","source_start":25.0,"source_stop":35.0,"clip_start":13.399999999999999,"clip_stop":23.4,"kind":"ds","input_ids":["audio4.wav:12"]},{"index":3,"source_filename":"audio1.wav","source_start":45.0,"source_stop":55.0,"clip_start":24.099999999999998,"clip_stop":34.099999999999994,"kind":"ds","input_ids":["audio1.wav:1"]},{"index":4,"source_filename":"audio4.wav","source_start":10.0,"source_stop":20.0,"clip_start":34.8,"clip_stop":44.8,"kind":"ds","input_ids":["audio4.wav:11"]},{"index":5,"source_filename":"audio5.wav","source_start":10.0,"source_stop":20.0,"clip_start":45.5,"clip_stop":55.5,"kind":"ds","input_ids":["audio5.wav:14"]}]},{"id":"384334a3a0c74a8d8b973a6cee6d7c40","clip_filename":"384334a3a0c74a8d8b973a6cee6d7c40.wav","clip_dur":55.50000000000001,"placed":[{"index":0,"source_filename":"audio3.wav","source_start":25.0,"source_stop":35.0,"clip_start":0.0,"clip_stop":10.0,"kind":"ds","input_ids":["audio3.wav:8"]},{"index":1,"source_filename":"audio1.wav","source_start":75.0,"source_stop":85.0,"clip_start":10.7,"clip_stop":20.7,"kind":"ds","input_ids":["audio1.wav:3"]},{"index":2,"source_filename":"audio1.wav","source_start":30.0,"source_stop":40.0,"clip_start":21.4,"clip_stop":31.4,"kind":"ds","input_ids":["audio1.wav:0"]},{"index":3,"source_filename":"audio4.wav","source_start":40.0,"source_stop":50.0,"clip_start":32.1,"clip_stop":42.1,"kind":"ds","input_ids":["audio4.wav:13"]},{"index":4,"source_filename":"audio3.wav","source_start":80.0,"source_stop":86.0,"clip_start":42.800000000000004,"clip_stop":48.800000000000004,"kind":"gt","input_ids":["audio3.wav:3"]},{"index":5,"source_filename":"audio3.wav","source_start":104.0,"source_stop":110.0,"clip_start":49.50000000000001,"clip_stop":55.50000000000001,"kind":"gt","input_ids":["audio3.wav:5"]}]},{"id":"eff82f2c73e3498b9368003af01373ba","clip_filename":"eff82f2c73e3498b9368003af01373ba.wav","clip_dur":73.50000000000001,"placed":[{"index":0,"source_filename":"audio3.wav","source_start":10.0,"source_stop":20.0,"clip_start":0.0,"clip_stop":10.0,"kind":"ds","input_ids":["audio3.wav:7"]},{"index":1,"source_filename":"audio1.wav","source_start":90.0,"source_stop":112.0,"clip_start":10.7,"clip_stop":32.7,"kind":"gt","input_ids":["audio1.wav:0"]},{"index":2,"source_filename":"audio2.wav","source_start":90.0,"source_stop":98.0,"clip_start":33.400000000000006,"clip_stop":41.400000000000006,"kind":"gt","input_ids":["audio2.wav:1"]},{"index":3,"source_filename":"audio2.wav","source_start":60.0,"source_stop":70.0,"clip_start":42.10000000000001,"clip_stop":52.10000000000001,"kind":"ds","input_ids":["audio2.wav:6"]},{"index":4,"source_filename":"audio3.wav","source_start":55.0,"source_stop":65.0,"clip_start":52.80000000000001,"clip_stop":62.80000000000001,"kind":"ds","input_ids":["audio3.wav:10"]},{"index":5,"source_filename":"audio2.wav","source_start":45.0,"source_stop":55.0,"clip_start":63.500000000000014,"clip_stop":73.50000000000001,"kind":"ds","input_ids":["audio2.wav:5"]}]},{"id":"c4d6975a85a846e4ba75ea9a7b2643c2","clip_filename":"c4d6975a85a846e4ba75ea9a7b2643c2.wav","clip_dur":57.5,"placed":[{"index":0,"source_filename":"audio2.wav","source_start":90.0,"source_stop":98.0,"clip_start":0.0,"clip_stop":8.0,"kind":"gt","input_ids":["audio2.wav:1"]},{"index":1,"source_filename":"audio5.wav","source_start":25.0,"source_stop":35.0,"clip_start":8.7,"clip_stop":18.7,"kind":"ds","input_ids":["audio5.wav:15"]},{"index":2,"source_filename":"audio3.wav","source_start":40.0,"source_stop":50.0,"clip_start":19.4,"clip_stop":29.4,"kind":"ds","input_ids":["audio3.wav:9"]},{"index":3,"source_filename":"audio1.wav","source_start":60.0,"source_stop":70.0,"clip_start":30.099999999999998,"clip_stop":40.099999999999994,"kind":"ds","input_ids":["audio1.wav:2"]},{"index":4,"source_filename":"audio2.wav","source_start":30.0,"source_stop":40.0,"clip_start":40.8,"clip_stop":50.8,"kind":"ds","input_ids":["audio2.wav:4"]},{"index":5,"source_filename":"audio3.wav","source_start":92.0,"source_stop":98.0,"clip_start":51.5,"clip_stop":57.5,"kind":"gt","input_ids":["audio3.wav:4"]}]}] \ No newline at end of file diff --git a/packages/examples/cvat/recording-oracle/tests/assets/cloud/audio_validation/gt.tsv b/packages/examples/cvat/recording-oracle/tests/assets/cloud/audio_validation/gt.tsv new file mode 100644 index 0000000000..1e76d815fc --- /dev/null +++ b/packages/examples/cvat/recording-oracle/tests/assets/cloud/audio_validation/gt.tsv @@ -0,0 +1,7 @@ +filename start stop label text span_id +audio1.wav 0:01:30.000000 0:01:52.000000 speech gt s1 0 text s1 +audio2.wav 0:01:30.000000 0:01:38.000000 speech gt s2 1 text s2 +audio2.wav 0:01:46.000000 0:01:52.000000 speech gt s2 1 text s2 +audio3.wav 0:01:20.000000 0:01:26.000000 speech gt s3 2 text s3 +audio3.wav 0:01:32.000000 0:01:38.000000 speech gt s3 2 text s3 +audio3.wav 0:01:44.000000 0:01:50.000000 speech gt s3 2 text s3 diff --git a/packages/examples/cvat/recording-oracle/tests/assets/cloud/audio_validation/manifest.json b/packages/examples/cvat/recording-oracle/tests/assets/cloud/audio_validation/manifest.json new file mode 100644 index 0000000000..1b72a7f8cb --- /dev/null +++ b/packages/examples/cvat/recording-oracle/tests/assets/cloud/audio_validation/manifest.json @@ -0,0 +1,28 @@ +{ + "version": 2, + "job_type": "audio_transcription", + "data": { + "media_url": "https://invalid/", + "regions_url": "https://invalid/", + "gt_url": "https://invalid/" + }, + "annotation": { + "description": "Audio transcription task", + "user_guide_url": "https://invalid/audio-transcription-guide.md", + "labels": [{ "name": "speech" }], + "shared_attributes": [], + "validation": { + "target_score": 0.5, + "target_metric": "wer" + }, + "qualifications": [], + "details": { + "max_time": 1800, + "normalizer": "basic", + "max_segment_duration": 120, + "min_gt_span_duration": 20, + "min_composition": { "gt": 2, "ds": 2 }, + "validation_overhead": 20 + } + } +} diff --git a/packages/examples/cvat/recording-oracle/tests/assets/cloud/audio_validation/task_clips.json b/packages/examples/cvat/recording-oracle/tests/assets/cloud/audio_validation/task_clips.json new file mode 100644 index 0000000000..f4d211ab50 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/tests/assets/cloud/audio_validation/task_clips.json @@ -0,0 +1 @@ +{"1000":"21b0aeed1730488989aeeaf704cbcc35","1001":"384334a3a0c74a8d8b973a6cee6d7c40","1002":"eff82f2c73e3498b9368003af01373ba","1003":"c4d6975a85a846e4ba75ea9a7b2643c2"} \ No newline at end of file diff --git a/packages/examples/cvat/recording-oracle/tests/utils/manifest.json b/packages/examples/cvat/recording-oracle/tests/assets/cloud/manifests/manifest-v1.json similarity index 100% rename from packages/examples/cvat/recording-oracle/tests/utils/manifest.json rename to packages/examples/cvat/recording-oracle/tests/assets/cloud/manifests/manifest-v1.json diff --git a/packages/examples/cvat/recording-oracle/tests/integration/chain/test_web3.py b/packages/examples/cvat/recording-oracle/tests/integration/chain/test_web3.py index 1638bcdafb..123bd122e6 100644 --- a/packages/examples/cvat/recording-oracle/tests/integration/chain/test_web3.py +++ b/packages/examples/cvat/recording-oracle/tests/integration/chain/test_web3.py @@ -1,3 +1,4 @@ +import re import unittest from unittest.mock import patch @@ -56,7 +57,9 @@ def test_get_web3_localhost(self): assert w3.manager._provider.endpoint_uri == LocalhostConfig.rpc_api def test_get_web3_invalid_chain_id(self): - with pytest.raises(ValueError, match="1234 is not in available list of networks."): + with pytest.raises( + ValueError, match=re.escape("1234 is not in available list of networks.") + ): get_web3(1234) def test_sign_message_polygon(self): @@ -84,7 +87,9 @@ def test_sign_message_amoy(self): assert signed_message == SIGNATURE def test_sign_message_invalid_chain_id(self): - with pytest.raises(ValueError, match="1234 is not in available list of networks."): + with pytest.raises( + ValueError, match=re.escape("1234 is not in available list of networks.") + ): sign_message(1234, "message") def test_recover_signer(self): diff --git a/packages/examples/cvat/recording-oracle/tests/integration/cron/test_process_reputation_oracle_webhooks.py b/packages/examples/cvat/recording-oracle/tests/integration/cron/test_process_reputation_oracle_webhooks.py index 11bdf6cd7e..49e8381445 100644 --- a/packages/examples/cvat/recording-oracle/tests/integration/cron/test_process_reputation_oracle_webhooks.py +++ b/packages/examples/cvat/recording-oracle/tests/integration/cron/test_process_reputation_oracle_webhooks.py @@ -41,7 +41,7 @@ def get_webhook(self, escrow_address, chain_id, event_data): def test_process_reputation_oracle_webhooks(self): expected_url = "expected_url" with ( - patch("src.crons._utils.httpx.Client.post") as mock_httpx, + patch("src.crons._utils.httpx2.Client.post") as mock_httpx, patch("src.crons._utils.prepare_signed_message") as mock_signature, patch( "src.crons.process_reputation_oracle_webhooks.get_reputation_oracle_url" diff --git a/packages/examples/cvat/recording-oracle/tests/integration/endpoints/test_webhook.py b/packages/examples/cvat/recording-oracle/tests/integration/endpoints/test_webhook.py index 97a9f14b96..48fcc8e663 100644 --- a/packages/examples/cvat/recording-oracle/tests/integration/endpoints/test_webhook.py +++ b/packages/examples/cvat/recording-oracle/tests/integration/endpoints/test_webhook.py @@ -2,6 +2,7 @@ import unittest from unittest.mock import MagicMock, patch +from fastapi import FastAPI from fastapi.testclient import TestClient from src.chain.web3 import sign_message @@ -17,7 +18,11 @@ class ServiceIntegrationTest(unittest.TestCase): def setUp(self): random.seed(42) self.session = SessionLocal() - self.client = TestClient(router) + # Wrap the router in an app so request.body() has the middleware stack (required by + # newer Starlette; a bare router lacks it). + app = FastAPI() + app.include_router(router) + self.client = TestClient(app) self.mock_escrow = MagicMock() self.mock_escrow.exchange_oracle = DEFAULT_GAS_PAYER self.mock_escrow.status = "Pending" diff --git a/packages/examples/cvat/recording-oracle/tests/integration/services/test_validation_service.py b/packages/examples/cvat/recording-oracle/tests/integration/services/test_validation_service.py index e901f89c14..84331e298d 100644 --- a/packages/examples/cvat/recording-oracle/tests/integration/services/test_validation_service.py +++ b/packages/examples/cvat/recording-oracle/tests/integration/services/test_validation_service.py @@ -24,8 +24,8 @@ from src.core.validation_results import ValidationFailure, ValidationSuccess from src.cvat import api_calls as cvat_api from src.db import SessionLocal -from src.handlers.process_intermediate_results import ( - process_final_results, +from src.handlers.completion.final_results import process_final_results +from src.handlers.validation import ( process_intermediate_results, ) from src.services.validation import ( @@ -129,7 +129,9 @@ def test_can_handle_lowered_quality_requirements_in_manifest(self, session: Sess logger = mock.Mock(Logger) common_lock_es.enter_context( - mock.patch("src.handlers.process_intermediate_results.BucketAccessInfo.parse_obj") + mock.patch( + "src.handlers.completion.task_exporters.image.BucketAccessInfo.parse_obj" + ) ) common_lock_es.enter_context( @@ -137,13 +139,13 @@ def test_can_handle_lowered_quality_requirements_in_manifest(self, session: Sess ) mock_make_cloud_client = common_lock_es.enter_context( - mock.patch("src.handlers.process_intermediate_results.make_cloud_client") + mock.patch("src.handlers.completion.task_exporters.image.make_cloud_client") ) mock_make_cloud_client.return_value.download_file = mock.Mock(return_value=b"") mock_get_task_validation_layout = common_lock_es.enter_context( mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_task_validation_layout" + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_validation_layout" ) ) mock_get_task_validation_layout.return_value = mock.Mock( @@ -156,7 +158,9 @@ def test_can_handle_lowered_quality_requirements_in_manifest(self, session: Sess ) mock_get_task_data_meta = common_lock_es.enter_context( - mock.patch("src.handlers.process_intermediate_results.cvat_api.get_task_data_meta") + mock.patch( + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_data_meta" + ) ) mock_get_task_data_meta.return_value = mock.Mock( cvat_api.models.IDataMetaRead, @@ -164,7 +168,9 @@ def test_can_handle_lowered_quality_requirements_in_manifest(self, session: Sess ) mock_get_task_labels = common_lock_es.enter_context( - mock.patch("src.handlers.process_intermediate_results.cvat_api.get_task_labels") + mock.patch( + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_labels" + ) ) mock_get_task_labels.return_value = [label.name for label in manifest.annotation.labels] @@ -183,16 +189,16 @@ def test_can_handle_lowered_quality_requirements_in_manifest(self, session: Sess with ( mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_task_quality_report" + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_quality_report" ) as mock_get_task_quality_report, mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_quality_report_data" + "src.handlers.validation.quality_checkers.image.cvat_api.get_quality_report_data" ) as mock_get_quality_report_data, mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_jobs_quality_reports" + "src.handlers.validation.quality_checkers.image.cvat_api.get_jobs_quality_reports" ) as mock_get_jobs_quality_reports, mock.patch( - "src.handlers.process_intermediate_results.cvat_api.update_task_validation_layout" + "src.handlers.validation.quality_checkers.image.cvat_api.update_task_validation_layout" ), mock.patch("src.core.config.ValidationConfig.min_available_gt_threshold", 0), mock.patch("src.core.config.ValidationConfig.max_gt_share", 1), @@ -233,13 +239,13 @@ def test_can_handle_lowered_quality_requirements_in_manifest(self, session: Sess with ( mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_task_quality_report" + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_quality_report" ) as mock_get_task_quality_report, mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_quality_report_data" + "src.handlers.validation.quality_checkers.image.cvat_api.get_quality_report_data" ) as mock_get_quality_report_data, mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_jobs_quality_reports" + "src.handlers.validation.quality_checkers.image.cvat_api.get_jobs_quality_reports" ) as mock_get_jobs_quality_reports, ): mock_get_task_quality_report.return_value = mock.Mock( @@ -333,17 +339,19 @@ def test_can_change_bad_honeypots_in_jobs(self, session: Session, seed: int): logger = mock.Mock(Logger) common_lock_es.enter_context( - mock.patch("src.handlers.process_intermediate_results.BucketAccessInfo.parse_obj") + mock.patch( + "src.handlers.completion.task_exporters.image.BucketAccessInfo.parse_obj" + ) ) mock_make_cloud_client = common_lock_es.enter_context( - mock.patch("src.handlers.process_intermediate_results.make_cloud_client") + mock.patch("src.handlers.completion.task_exporters.image.make_cloud_client") ) mock_make_cloud_client.return_value.download_file = mock.Mock(return_value=b"") mock_get_task_validation_layout = common_lock_es.enter_context( mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_task_validation_layout" + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_validation_layout" ) ) mock_get_task_validation_layout.return_value = mock.Mock( @@ -357,7 +365,9 @@ def test_can_change_bad_honeypots_in_jobs(self, session: Session, seed: int): ) mock_get_task_data_meta = common_lock_es.enter_context( - mock.patch("src.handlers.process_intermediate_results.cvat_api.get_task_data_meta") + mock.patch( + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_data_meta" + ) ) mock_get_task_data_meta.return_value = mock.Mock( cvat_api.models.IDataMetaRead, @@ -365,7 +375,9 @@ def test_can_change_bad_honeypots_in_jobs(self, session: Session, seed: int): ) mock_get_task_labels = common_lock_es.enter_context( - mock.patch("src.handlers.process_intermediate_results.cvat_api.get_task_labels") + mock.patch( + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_labels" + ) ) mock_get_task_labels.return_value = [label.name for label in manifest.annotation.labels] @@ -388,16 +400,16 @@ def test_can_change_bad_honeypots_in_jobs(self, session: Session, seed: int): with ( mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_task_quality_report" + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_quality_report" ) as mock_get_task_quality_report, mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_quality_report_data" + "src.handlers.validation.quality_checkers.image.cvat_api.get_quality_report_data" ) as mock_get_quality_report_data, mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_jobs_quality_reports" + "src.handlers.validation.quality_checkers.image.cvat_api.get_jobs_quality_reports" ) as mock_get_jobs_quality_reports, mock.patch( - "src.handlers.process_intermediate_results.cvat_api.update_task_validation_layout" + "src.handlers.validation.quality_checkers.image.cvat_api.update_task_validation_layout" ) as mock_update_task_validation_layout, mock.patch("src.core.config.ValidationConfig.min_available_gt_threshold", 0), mock.patch("src.core.config.ValidationConfig.max_gt_share", 1), @@ -496,7 +508,7 @@ def _generate_task_frames( output_task_honeypots = [] output_task_honeypot_real_frames = [] - validation_frame_uses = {fn: 0 for fn in task_validation_frame_names} + validation_frame_uses = dict.fromkeys(task_validation_frame_names, 0) jobs = [] for job_frame_names in take_by( task_frame_names[: frame_count - validation_frames_count], job_size @@ -568,17 +580,19 @@ def test_can_stop_on_slow_annotation_after_warmup_iterations(self, session: Sess logger = mock.Mock(Logger) common_lock_es.enter_context( - mock.patch("src.handlers.process_intermediate_results.BucketAccessInfo.parse_obj") + mock.patch( + "src.handlers.completion.task_exporters.image.BucketAccessInfo.parse_obj" + ) ) mock_make_cloud_client = common_lock_es.enter_context( - mock.patch("src.handlers.process_intermediate_results.make_cloud_client") + mock.patch("src.handlers.completion.task_exporters.image.make_cloud_client") ) mock_make_cloud_client.return_value.download_file = mock.Mock(return_value=b"") mock_get_task_validation_layout = common_lock_es.enter_context( mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_task_validation_layout" + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_validation_layout" ) ) mock_get_task_validation_layout.return_value = mock.Mock( @@ -591,7 +605,9 @@ def test_can_stop_on_slow_annotation_after_warmup_iterations(self, session: Sess ) mock_get_task_data_meta = common_lock_es.enter_context( - mock.patch("src.handlers.process_intermediate_results.cvat_api.get_task_data_meta") + mock.patch( + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_data_meta" + ) ) mock_get_task_data_meta.return_value = mock.Mock( cvat_api.models.IDataMetaRead, @@ -599,7 +615,9 @@ def test_can_stop_on_slow_annotation_after_warmup_iterations(self, session: Sess ) mock_get_task_labels = common_lock_es.enter_context( - mock.patch("src.handlers.process_intermediate_results.cvat_api.get_task_labels") + mock.patch( + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_labels" + ) ) mock_get_task_labels.return_value = [label.name for label in manifest.annotation.labels] @@ -618,16 +636,16 @@ def test_can_stop_on_slow_annotation_after_warmup_iterations(self, session: Sess with ( mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_task_quality_report" + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_quality_report" ) as mock_get_task_quality_report, mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_quality_report_data" + "src.handlers.validation.quality_checkers.image.cvat_api.get_quality_report_data" ) as mock_get_quality_report_data, mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_jobs_quality_reports" + "src.handlers.validation.quality_checkers.image.cvat_api.get_jobs_quality_reports" ) as mock_get_jobs_quality_reports, mock.patch( - "src.handlers.process_intermediate_results.cvat_api.update_task_validation_layout" + "src.handlers.validation.quality_checkers.image.cvat_api.update_task_validation_layout" ), mock.patch("src.core.config.ValidationConfig.min_available_gt_threshold", 0), mock.patch("src.core.config.ValidationConfig.max_gt_share", 1), @@ -685,18 +703,20 @@ def test_can_exclude_bad_gt_for_each_label_separately(self, session: Session): logger = mock.Mock(Logger) common_lock_es.enter_context( - mock.patch("src.handlers.process_intermediate_results.BucketAccessInfo.parse_obj") + mock.patch( + "src.handlers.completion.task_exporters.image.BucketAccessInfo.parse_obj" + ) ) mock_make_cloud_client = common_lock_es.enter_context( - mock.patch("src.handlers.process_intermediate_results.make_cloud_client") + mock.patch("src.handlers.completion.task_exporters.image.make_cloud_client") ) mock_make_cloud_client.return_value.download_file = mock.Mock(return_value=b"") # All tasks have the same validation layout mock_get_task_validation_layout = common_lock_es.enter_context( mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_task_validation_layout", + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_validation_layout", ) ) mock_get_task_validation_layout.return_value = mock.Mock( @@ -710,7 +730,9 @@ def test_can_exclude_bad_gt_for_each_label_separately(self, session: Session): # All tasks have the same frames mock_get_task_data_meta = common_lock_es.enter_context( - mock.patch("src.handlers.process_intermediate_results.cvat_api.get_task_data_meta") + mock.patch( + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_data_meta" + ) ) mock_get_task_data_meta.return_value = mock.Mock( cvat_api.models.IDataMetaRead, @@ -722,7 +744,7 @@ def patched_get_task_labels(task_id: int): common_lock_es.enter_context( mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_task_labels", + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_labels", patched_get_task_labels, ) ) @@ -782,19 +804,19 @@ def patched_get_jobs_quality_reports(task_id: int): with ( mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_task_quality_report", + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_quality_report", side_effect=patched_get_task_quality_report, ) as mock_get_task_quality_report, mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_quality_report_data", + "src.handlers.validation.quality_checkers.image.cvat_api.get_quality_report_data", patched_get_quality_report_data, ), mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_jobs_quality_reports", + "src.handlers.validation.quality_checkers.image.cvat_api.get_jobs_quality_reports", patched_get_jobs_quality_reports, ), mock.patch( - "src.handlers.process_intermediate_results.cvat_api.update_task_validation_layout" + "src.handlers.validation.quality_checkers.image.cvat_api.update_task_validation_layout" ) as mock_update_task_validation_layout, mock.patch("src.core.config.ValidationConfig.min_available_gt_threshold", 0), mock.patch("src.core.config.ValidationConfig.max_gt_share", 1), @@ -866,18 +888,20 @@ def test_can_complete_if_not_enough_gt_left_in_task_with_several_jobs( logger = logging.getLogger() common_lock_es.enter_context( - mock.patch("src.handlers.process_intermediate_results.BucketAccessInfo.parse_obj") + mock.patch( + "src.handlers.completion.task_exporters.image.BucketAccessInfo.parse_obj" + ) ) mock_make_cloud_client = common_lock_es.enter_context( - mock.patch("src.handlers.process_intermediate_results.make_cloud_client") + mock.patch("src.handlers.completion.task_exporters.image.make_cloud_client") ) mock_make_cloud_client.return_value.download_file = mock.Mock(return_value=b"") # All tasks have the same validation layout mock_get_task_validation_layout = common_lock_es.enter_context( mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_task_validation_layout", + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_validation_layout", ) ) mock_get_task_validation_layout.return_value = mock.Mock( @@ -891,7 +915,9 @@ def test_can_complete_if_not_enough_gt_left_in_task_with_several_jobs( # All tasks have the same frames mock_get_task_data_meta = common_lock_es.enter_context( - mock.patch("src.handlers.process_intermediate_results.cvat_api.get_task_data_meta") + mock.patch( + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_data_meta" + ) ) mock_get_task_data_meta.return_value = mock.Mock( cvat_api.models.IDataMetaRead, @@ -903,7 +929,7 @@ def patched_get_task_labels(task_id: int): common_lock_es.enter_context( mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_task_labels", + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_labels", patched_get_task_labels, ) ) @@ -963,19 +989,19 @@ def patched_get_jobs_quality_reports(task_id: int): with ( mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_task_quality_report", + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_quality_report", side_effect=patched_get_task_quality_report, ), mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_quality_report_data", + "src.handlers.validation.quality_checkers.image.cvat_api.get_quality_report_data", patched_get_quality_report_data, ), mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_jobs_quality_reports", + "src.handlers.validation.quality_checkers.image.cvat_api.get_jobs_quality_reports", patched_get_jobs_quality_reports, ), mock.patch( - "src.handlers.process_intermediate_results.cvat_api.update_task_validation_layout" + "src.handlers.validation.quality_checkers.image.cvat_api.update_task_validation_layout" ) as mock_update_task_validation_layout, mock.patch("src.core.config.ValidationConfig.min_available_gt_threshold", 0.7), mock.patch("src.core.config.ValidationConfig.max_gt_share", 1), @@ -1020,18 +1046,20 @@ def test_can_complete_if_not_enough_gt_left_in_task_with_one_job( logger = logging.getLogger() common_lock_es.enter_context( - mock.patch("src.handlers.process_intermediate_results.BucketAccessInfo.parse_obj") + mock.patch( + "src.handlers.completion.task_exporters.image.BucketAccessInfo.parse_obj" + ) ) mock_make_cloud_client = common_lock_es.enter_context( - mock.patch("src.handlers.process_intermediate_results.make_cloud_client") + mock.patch("src.handlers.completion.task_exporters.image.make_cloud_client") ) mock_make_cloud_client.return_value.download_file = mock.Mock(return_value=b"") # All tasks have the same validation layout mock_get_task_validation_layout = common_lock_es.enter_context( mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_task_validation_layout", + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_validation_layout", ) ) mock_get_task_validation_layout.return_value = mock.Mock( @@ -1045,7 +1073,9 @@ def test_can_complete_if_not_enough_gt_left_in_task_with_one_job( # All tasks have the same frames mock_get_task_data_meta = common_lock_es.enter_context( - mock.patch("src.handlers.process_intermediate_results.cvat_api.get_task_data_meta") + mock.patch( + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_data_meta" + ) ) mock_get_task_data_meta.return_value = mock.Mock( cvat_api.models.IDataMetaRead, @@ -1057,7 +1087,7 @@ def patched_get_task_labels(task_id: int): common_lock_es.enter_context( mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_task_labels", + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_labels", patched_get_task_labels, ) ) @@ -1101,19 +1131,19 @@ def patched_get_jobs_quality_reports(task_id: int): with ( mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_task_quality_report", + "src.handlers.validation.quality_checkers.image.cvat_api.get_task_quality_report", side_effect=patched_get_task_quality_report, ), mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_quality_report_data", + "src.handlers.validation.quality_checkers.image.cvat_api.get_quality_report_data", patched_get_quality_report_data, ), mock.patch( - "src.handlers.process_intermediate_results.cvat_api.get_jobs_quality_reports", + "src.handlers.validation.quality_checkers.image.cvat_api.get_jobs_quality_reports", patched_get_jobs_quality_reports, ), mock.patch( - "src.handlers.process_intermediate_results.cvat_api.update_task_validation_layout" + "src.handlers.validation.quality_checkers.image.cvat_api.update_task_validation_layout" ) as mock_update_task_validation_layout, mock.patch("src.core.config.ValidationConfig.min_available_gt_threshold", 0), mock.patch("src.core.config.ValidationConfig.max_gt_share", 1), @@ -1174,19 +1204,25 @@ def patched_prepare_merged_dataset(self): self._updated_merged_dataset_archive = io.BytesIO(b"test") with ( - mock.patch("src.handlers.process_intermediate_results.BucketAccessInfo.parse_obj"), + # base downloads the exchange-oracle result file; the merger (image) downloads GT + mock.patch("src.handlers.completion.task_exporters.base.BucketAccessInfo.parse_obj"), + mock.patch( + "src.handlers.completion.task_exporters.base.make_cloud_client" + ) as mock_base_make_cloud_client, + mock.patch("src.handlers.completion.task_exporters.image.BucketAccessInfo.parse_obj"), mock.patch( - "src.handlers.process_intermediate_results.make_cloud_client" + "src.handlers.completion.task_exporters.image.make_cloud_client" ) as mock_make_cloud_client, - mock.patch("src.handlers.process_intermediate_results.dm.Dataset.import_from"), - mock.patch("src.handlers.process_intermediate_results.extract_zip_archive"), - mock.patch("src.handlers.process_intermediate_results.write_dir_to_zip_archive"), + mock.patch("src.handlers.completion.task_exporters.image.dm.Dataset.import_from"), + mock.patch("src.handlers.completion.task_exporters.image.extract_zip_archive"), + mock.patch("src.handlers.completion.task_exporters.image.write_dir_to_zip_archive"), mock.patch( - "src.handlers.process_intermediate_results._TaskAnnotationMerger._prepare_merged_dataset", + "src.handlers.completion.task_exporters.image._TaskAnnotationMerger._prepare_merged_dataset", patched_prepare_merged_dataset, ), ): mock_make_cloud_client.return_value.download_file = mock.Mock(return_value=b"") + mock_base_make_cloud_client.return_value.download_file = mock.Mock(return_value=b"") annotation_meta = AnnotationMeta( jobs=[ @@ -1215,7 +1251,6 @@ def patched_prepare_merged_dataset(self): chain_id=chain_id, meta=annotation_meta, manifest=manifest, - merged_annotations=io.BytesIO(), logger=mock.Mock(Logger), ) diff --git a/packages/examples/cvat/recording-oracle/tests/unit/__init__.py b/packages/examples/cvat/recording-oracle/tests/unit/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/examples/cvat/recording-oracle/tests/unit/test_audio_validation.py b/packages/examples/cvat/recording-oracle/tests/unit/test_audio_validation.py new file mode 100644 index 0000000000..a26303c221 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/tests/unit/test_audio_validation.py @@ -0,0 +1,162 @@ +import json +import logging +from collections.abc import Callable +from pathlib import Path +from types import SimpleNamespace + +import pytest +from sqlalchemy.orm import Session + +from src.core.annotation_meta import AnnotationMeta, JobMeta +from src.core.config import Config +from src.core.manifest import parse_manifest +from src.core.storage import ( + compose_data_bucket_filename, + compose_data_bucket_prefix, + compose_results_bucket_filename, + compose_results_bucket_prefix, +) +from src.core.tasks.audio_transcription.meta import ( + Clip, + TaskMetaLayout, + TaskMetaSerializer, + TaskResultsLayout, +) +from src.core.types import Networks +from src.core.validation_results import ValidationFailure, ValidationSuccess +from src.handlers.validation import process_intermediate_results +from src.services.cloud import make_client as make_cloud_client +from src.services.cloud.utils import BucketAccessInfo + +from tests.utils.audio_transcription import ( + TRANSCRIPTION_ATTR, + build_empty_annotation, + build_perfect_annotation, + gt_regions_by_id, +) +from tests.utils.constants import ESCROW_ADDRESS, WALLET_ADDRESS1 + +CHAIN_ID = Networks.localhost.value + +# Real exchange-oracle builder output. Regenerate by +# exchange-oracle/tests/assets/utils/gen_audio_validation_fixture.py +FIXTURE_DIR = Path(__file__).resolve().parents[1] / "assets" / "cloud" / "audio_validation" + +MANIFEST_FILENAME = "manifest.json" + + +def _load_manifest(): + return parse_manifest(json.loads((FIXTURE_DIR / MANIFEST_FILENAME).read_text())) + + +def _cleanup_eo_bucket(): + client = make_cloud_client(BucketAccessInfo.parse_obj(Config.exchange_oracle_storage_config)) + client.remove_files(prefix=compose_data_bucket_prefix(ESCROW_ADDRESS, CHAIN_ID)) + client.remove_files(prefix=compose_results_bucket_prefix(ESCROW_ADDRESS, CHAIN_ID)) + + +@pytest.fixture +def pre_cleanup_eo_bucket(): + _cleanup_eo_bucket() + + +@pytest.fixture +def post_cleanup_eo_bucket(): + yield + _cleanup_eo_bucket() + + +@pytest.fixture +def fxt_published_task(pre_cleanup_eo_bucket): + """Publish the golden builder metadata to the exchange-oracle bucket the validator reads.""" + + client = make_cloud_client(BucketAccessInfo.parse_obj(Config.exchange_oracle_storage_config)) + + gt_tsv = (FIXTURE_DIR / TaskMetaLayout.GT_FILENAME).read_text() + clips_data = (FIXTURE_DIR / TaskMetaLayout.CLIPS_FILENAME).read_bytes() + task_clips_data = (FIXTURE_DIR / TaskMetaLayout.TASK_CLIPS_FILENAME).read_bytes() + + for filename, data in ( + (TaskMetaLayout.GT_FILENAME, gt_tsv.encode()), + (TaskMetaLayout.CLIPS_FILENAME, clips_data), + (TaskMetaLayout.TASK_CLIPS_FILENAME, task_clips_data), + ): + client.create_file(compose_data_bucket_filename(ESCROW_ADDRESS, CHAIN_ID, filename), data) + + serializer = TaskMetaSerializer() + return SimpleNamespace( + client=client, + clips_by_id={clip.id: clip for clip in serializer.parse_clips(clips_data)}, + task_clips=serializer.parse_task_clips(task_clips_data), + gt=gt_regions_by_id(gt_tsv), + ) + + +@pytest.mark.usefixtures("post_cleanup_eo_bucket") +class AudioValidationTest: + def _validate(self, session: Session, published_task, build_annotation: Callable[[Clip], str]): + """Upload one annotator submission per CVAT task and run the intermediate-results flow. + + ``build_annotation`` maps a clip to its submission TSV. Returns the validation result and + the job metas (their ``job_id`` keys the result). + """ + + jobs = [] + for job_id, (task_id, clip_id) in enumerate( + sorted(published_task.task_clips.items()), start=1 + ): + assignment_id = f"assignment-{job_id}" + published_task.client.create_file( + compose_results_bucket_filename( + ESCROW_ADDRESS, + CHAIN_ID, + TaskResultsLayout.assignment_annotation_filename(job_id, assignment_id), + ), + build_annotation(published_task.clips_by_id[clip_id]).encode(), + ) + jobs.append( + JobMeta( + job_id=job_id, + task_id=task_id, + annotator_wallet_address=WALLET_ADDRESS1, + assignment_id=assignment_id, + start_frame=0, + stop_frame=0, + ) + ) + + result = process_intermediate_results( + session=session, + escrow_address=ESCROW_ADDRESS, + chain_id=CHAIN_ID, + meta=AnnotationMeta(jobs=jobs), + manifest=_load_manifest(), + logger=logging.getLogger(__name__), + ) + + return result, jobs + + def test_can_pass_validation(self, session: Session, fxt_published_task): + result, jobs = self._validate( + session, + fxt_published_task, + lambda clip: build_perfect_annotation( + clip, fxt_published_task.gt, transcription_attr=TRANSCRIPTION_ATTR + ), + ) + + # No rejections -> the escrow completes with a 0.0 (perfect) score per job. + assert isinstance(result, ValidationSuccess) + assert result.job_results == {job.job_id: 0.0 for job in jobs} + + def test_can_fail_validation(self, session: Session, fxt_published_task): + result, jobs = self._validate( + session, + fxt_published_task, + lambda _clip: build_empty_annotation(TRANSCRIPTION_ATTR), + ) + + # Every honeypot is a full deletion -> rate 1.0 > the 0.5 target, so every job is rejected. + assert isinstance(result, ValidationFailure) + assert set(result.rejected_jobs) == {job.job_id for job in jobs} + assert result.job_results == {job.job_id: 1.0 for job in jobs} diff --git a/packages/examples/cvat/recording-oracle/tests/utils/audio_transcription.py b/packages/examples/cvat/recording-oracle/tests/utils/audio_transcription.py new file mode 100644 index 0000000000..b799c9b01f --- /dev/null +++ b/packages/examples/cvat/recording-oracle/tests/utils/audio_transcription.py @@ -0,0 +1,108 @@ +from __future__ import annotations + +import math +from typing import TYPE_CHECKING + +from src.core.tasks.audio_transcription.meta import ( + RegionKind, + parse_gt_tsv, +) + +if TYPE_CHECKING: + from src.core.tasks.audio_transcription.meta import Clip, InputGtRegion + +# Canonical audio task input, shared by the task-creation and validation tests so both exercise +# the same layout. DS_ROIS: per-file region start times (each ROI is DS_LEN seconds long). +DS_LEN = 10.0 +DS_ROIS = { + "audio1.wav": [30.0, 45.0, 60.0, 75.0], + "audio2.wav": [30.0, 45.0, 60.0], + "audio3.wav": [10.0, 25.0, 40.0, 55.0], + "audio4.wav": [10.0, 25.0, 40.0], + "audio5.wav": [10.0, 25.0], +} +# (span_id, filename, [(start, stop), ...]) -- 3 GT spans with 1, 2 and 3 cues. Each span covers +# >= min_gt_span_duration and sits after its recording's DS regions, so GT and DS stay disjoint. +GT_ROIS = [ + ("s1", "audio1.wav", [(90.0, 112.0)]), + ("s2", "audio2.wav", [(90.0, 98.0), (106.0, 112.0)]), + ("s3", "audio3.wav", [(80.0, 86.0), (92.0, 98.0), (104.0, 110.0)]), +] +TRANSCRIPTION_ATTR = "transcription" + +# Media, regions and GT share one layout: the recordings must contain every DS/GT cue, so the +# file set and duration are derived from DS_ROIS/GT_ROIS rather than pinned independently. +MEDIA_MARGIN_S = 8.0 + + +def _region_stops() -> list[float]: + ds_stops = [start + DS_LEN for starts in DS_ROIS.values() for start in starts] + gt_stops = [stop for _span_id, _filename, regions in GT_ROIS for _start, stop in regions] + return ds_stops + gt_stops + + +MEDIA_FILES = sorted({*DS_ROIS, *(filename for _span_id, filename, _regions in GT_ROIS)}) +MEDIA_DURATION_S = math.ceil(max(_region_stops()) + MEDIA_MARGIN_S) + + +def ts(seconds: float) -> str: + """Render seconds as an ``H:MM:SS.ffffff`` timestamp (the region/GT/annotation TSV format).""" + h = int(seconds // 3600) + m = int((seconds % 3600) // 60) + s = seconds - h * 3600 - m * 60 + return f"{h}:{m:02d}:{s:09.6f}" + + +def build_regions_tsv(ds_rois: dict[str, list[float]] = DS_ROIS, ds_len: float = DS_LEN) -> str: + return "filename\tstart\tstop\tlabel\n" + "".join( + f"{filename}\t{ts(start)}\t{ts(start + ds_len)}\tspeech\n" + for filename, starts in ds_rois.items() + for start in starts + ) + + +def build_gt_tsv(gt_rois: list = GT_ROIS) -> str: + return "filename\tstart\tstop\tlabel\ttext\tspan_id\n" + "".join( + f"{filename}\t{ts(start)}\t{ts(stop)}\tspeech\tgt {span_id} {roi_idx} text\t{span_id}\n" + for roi_idx, (span_id, filename, regions) in enumerate(gt_rois) + for start, stop in regions + ) + + +def gt_regions_by_id(gt_tsv: str) -> dict[str, InputGtRegion]: + return {region.id: region for region in parse_gt_tsv(gt_tsv.encode())} + + +def build_perfect_annotation( + clip: Clip, + gt: dict[str, InputGtRegion], + *, + transcription_attr: str = TRANSCRIPTION_ATTR, +) -> str: + """Produce an annotator submission TSV that perfectly transcribes every honeypot in ``clip``. + + Each GT cue's source-time window is mapped back to clip time via its placement offset and + emitted with the GT text, so validation aligns it exactly (WER/CER == 0). + """ + rows: list[tuple[float, float, str]] = [] + for placed in clip.placed: + if placed.kind != RegionKind.gt: + continue + offset = placed.source_start - placed.clip_start # clip_time = source_time - offset + for region_id in placed.input_ids: + cue = gt[region_id] + rows.append( + (cue.start.total_seconds() - offset, cue.stop.total_seconds() - offset, cue.text) + ) + rows.sort() + body = "".join(f"{ts(start)}\t{ts(stop)}\tspeech\t{text}\n" for start, stop, text in rows) + return build_empty_annotation(transcription_attr) + body + + +def build_empty_annotation(transcription_attr: str = TRANSCRIPTION_ATTR) -> str: + """An annotator submission with no transcribed intervals. + + Every presented honeypot is then unmatched, so validation scores each as a full deletion + (error rate 1.0) -- i.e. a failing assignment. + """ + return f"start\tstop\tlabel\t{transcription_attr}\n" diff --git a/packages/examples/cvat/recording-oracle/tests/utils/constants.py b/packages/examples/cvat/recording-oracle/tests/utils/constants.py index 90af4374a6..fcf9263452 100644 --- a/packages/examples/cvat/recording-oracle/tests/utils/constants.py +++ b/packages/examples/cvat/recording-oracle/tests/utils/constants.py @@ -19,7 +19,7 @@ EXCHANGE_ORACLE_ADDRESS = "0x90F79bf6EB2c4f870365E785982E1f101E93b906" EXCHANGE_ORACLE_FEE = 10 -DEFAULT_MANIFEST_URL = "http://host.docker.internal:9000/manifests/manifest.json" +DEFAULT_MANIFEST_URL = "http://host.docker.internal:9000/manifests/manifest-v1.json" DEFAULT_HASH = "test" SIGNATURE = ( diff --git a/packages/examples/cvat/recording-oracle/tests/utils/helpers.py b/packages/examples/cvat/recording-oracle/tests/utils/helpers.py index 22ff66fa0f..eff59da8cf 100644 --- a/packages/examples/cvat/recording-oracle/tests/utils/helpers.py +++ b/packages/examples/cvat/recording-oracle/tests/utils/helpers.py @@ -1,6 +1,6 @@ from collections.abc import Iterable -from src.core.manifest import TaskManifest, parse_manifest +from src.core.manifest import ManifestBase, parse_manifest def generate_manifest( @@ -9,7 +9,7 @@ def generate_manifest( job_size: int = 10, validation_frames_per_job: int = 2, labels: int | Iterable[int] = 1, -) -> TaskManifest: +) -> ManifestBase: label_definitions = [] if isinstance(labels, int): label_definitions.extend({"name": f"label_{i}"} for i in range(labels)) diff --git a/packages/examples/cvat/recording-oracle/tests/utils/intermediate-results.json b/packages/examples/cvat/recording-oracle/tests/utils/intermediate-results.json deleted file mode 100644 index c0bf2a08c2..0000000000 --- a/packages/examples/cvat/recording-oracle/tests/utils/intermediate-results.json +++ /dev/null @@ -1,29 +0,0 @@ -[ - { - "answers": [ - { - "assignee": "0x1234567890123456789012345678901234567890", - "tag": "dummy_label" - } - ], - "url": "https://test.storage.googleapis.com/1.jpg" - }, - { - "answers": [ - { - "assignee": "0x1234567890123456789012345678901234567890", - "tag": "dummy_label" - } - ], - "url": "https://test.storage.googleapis.com/2.jpg" - }, - { - "answers": [ - { - "assignee": "0x1234567890123456789012345678901234567890", - "tag": "dummy_label" - } - ], - "url": "https://test.storage.googleapis.com/3.jpg" - } -] diff --git a/packages/examples/cvat/recording-oracle/tests/utils/recording_oracle_dummy_input.json b/packages/examples/cvat/recording-oracle/tests/utils/recording_oracle_dummy_input.json deleted file mode 100644 index 872bc46ac6..0000000000 --- a/packages/examples/cvat/recording-oracle/tests/utils/recording_oracle_dummy_input.json +++ /dev/null @@ -1,321 +0,0 @@ -[ - { - "answers": [ - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b36", - "tag": "" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b37", - "tag": "" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b38", - "tag": "" - } - ], - "url": "https://test.storage.googleapis.com/1.png" - }, - { - "answers": [ - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b36", - "tag": "dummy_label" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b37", - "tag": "" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b38", - "tag": "" - } - ], - "url": "https://test.storage.googleapis.com/2.png" - }, - { - "answers": [ - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b36", - "tag": "dummy_label" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b37", - "tag": "" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b38", - "tag": "dummy_label" - } - ], - "url": "https://test.storage.googleapis.com/3.png" - }, - { - "answers": [ - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b36", - "tag": "" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b37", - "tag": "" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b38", - "tag": "" - } - ], - "url": "https://test.storage.googleapis.com/4.png" - }, - { - "answers": [ - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b36", - "tag": "dummy_label" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b37", - "tag": "dummy_label" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b38", - "tag": "dummy_label" - } - ], - "url": "https://test.storage.googleapis.com/5.png" - }, - { - "answers": [ - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b36", - "tag": "dummy_label" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b37", - "tag": "dummy_label" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b38", - "tag": "dummy_label" - } - ], - "url": "https://test.storage.googleapis.com/6.png" - }, - { - "answers": [ - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b36", - "tag": "dummy_label" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b37", - "tag": "dummy_label" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b38", - "tag": "dummy_label" - } - ], - "url": "https://test.storage.googleapis.com/7.png" - }, - { - "answers": [ - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b36", - "tag": "" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b37", - "tag": "" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b38", - "tag": "" - } - ], - "url": "https://test.storage.googleapis.com/8.png" - }, - { - "answers": [ - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b36", - "tag": "" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b37", - "tag": "" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b38", - "tag": "" - } - ], - "url": "https://test.storage.googleapis.com/9.png" - }, - { - "answers": [ - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b36", - "tag": "" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b37", - "tag": "" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b38", - "tag": "" - } - ], - "url": "https://test.storage.googleapis.com/10.png" - }, - { - "answers": [ - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b36", - "tag": "" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b37", - "tag": "dummy_label" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b38", - "tag": "" - } - ], - "url": "https://test.storage.googleapis.com/11.png" - }, - { - "answers": [ - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b36", - "tag": "dummy_label" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b37", - "tag": "dummy_label" - } - ], - "url": "https://test.storage.googleapis.com/12.png" - }, - { - "answers": [ - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b36", - "tag": "dummy_label" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b37", - "tag": "dummy_label" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b38", - "tag": "dummy_label" - } - ], - "url": "https://test.storage.googleapis.com/13.png" - }, - { - "answers": [ - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b36", - "tag": "dummy_label" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b37", - "tag": "dummy_label" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b38", - "tag": "dummy_label" - } - ], - "url": "https://test.storage.googleapis.com/14.png" - }, - { - "answers": [ - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b36", - "tag": "" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b37", - "tag": "" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b38", - "tag": "" - } - ], - "url": "https://test.storage.googleapis.com/15.png" - }, - { - "answers": [ - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b36", - "tag": "" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b37", - "tag": "" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b38", - "tag": "" - } - ], - "url": "https://test.storage.googleapis.com/16.png" - }, - { - "answers": [ - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b36", - "tag": "" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b37", - "tag": "" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b38", - "tag": "" - } - ], - "url": "https://test.storage.googleapis.com/17.png" - }, - { - "answers": [ - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b36", - "tag": "" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b37", - "tag": "dummy_label" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b38", - "tag": "" - } - ], - "url": "https://test.storage.googleapis.com/18.png" - }, - { - "answers": [ - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b36", - "tag": "" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b37", - "tag": "" - }, - { - "assignee": "0x0755D4d722a4a201c1C5A4B5E614D913e7747b38", - "tag": "dummy_label" - } - ], - "url": "https://test.storage.googleapis.com/19.png" - } -] \ No newline at end of file From 368ee908852045dea459821f3222d68593d46ddc Mon Sep 17 00:00:00 2001 From: portuu3 <61605646+portuu3@users.noreply.github.com> Date: Mon, 20 Jul 2026 11:06:55 +0200 Subject: [PATCH 13/33] Add an endpoint that accepts an arbitrary JSON manifest (#3971) Co-authored-by: portuu3 <> --- .../job-launcher/client/src/types/index.ts | 1 + .../server/src/common/constants/index.ts | 1 + .../server/src/common/enums/job.ts | 18 +-- .../server/src/common/utils/storage.ts | 1 + .../migrations/1784028614177-addCvatTypes.ts | 59 +++++++++ .../src/modules/job/job.controller.spec.ts | 48 ++++++- .../server/src/modules/job/job.controller.ts | 37 ++++++ .../server/src/modules/job/job.dto.ts | 7 ++ .../src/modules/job/job.service.spec.ts | 117 ++++++++++++++++++ .../server/src/modules/job/job.service.ts | 37 ++++++ .../modules/manifest/manifest.service.spec.ts | 4 +- 11 files changed, 319 insertions(+), 11 deletions(-) create mode 100644 packages/apps/job-launcher/server/src/database/migrations/1784028614177-addCvatTypes.ts diff --git a/packages/apps/job-launcher/client/src/types/index.ts b/packages/apps/job-launcher/client/src/types/index.ts index 9e240856be..0f59474dab 100644 --- a/packages/apps/job-launcher/client/src/types/index.ts +++ b/packages/apps/job-launcher/client/src/types/index.ts @@ -112,6 +112,7 @@ export enum CvatJobType { IMAGE_BOXES = 'image_boxes', IMAGE_BOXES_FROM_POINTS = 'image_boxes_from_points', IMAGE_SKELETONS_FROM_BOXES = 'image_skeletons_from_boxes', + AUDIO_TRANSCRIPTION = 'audio_transcription', } export type FortuneRequest = { diff --git a/packages/apps/job-launcher/server/src/common/constants/index.ts b/packages/apps/job-launcher/server/src/common/constants/index.ts index 7bbb8b9a5e..aa4b361175 100644 --- a/packages/apps/job-launcher/server/src/common/constants/index.ts +++ b/packages/apps/job-launcher/server/src/common/constants/index.ts @@ -31,6 +31,7 @@ export const CVAT_JOB_TYPES = [ CvatJobType.IMAGE_POINTS, CvatJobType.IMAGE_BOXES_FROM_POINTS, CvatJobType.IMAGE_SKELETONS_FROM_BOXES, + CvatJobType.AUDIO_TRANSCRIPTION, ]; export const CANCEL_JOB_STATUSES = [ diff --git a/packages/apps/job-launcher/server/src/common/enums/job.ts b/packages/apps/job-launcher/server/src/common/enums/job.ts index db16799d11..bc8119a981 100644 --- a/packages/apps/job-launcher/server/src/common/enums/job.ts +++ b/packages/apps/job-launcher/server/src/common/enums/job.ts @@ -37,6 +37,7 @@ export enum CvatJobType { IMAGE_BOXES = 'image_boxes', IMAGE_BOXES_FROM_POINTS = 'image_boxes_from_points', IMAGE_SKELETONS_FROM_BOXES = 'image_skeletons_from_boxes', + AUDIO_TRANSCRIPTION = 'audio_transcription', } /** @deprecated Audino jobs are no longer supported. */ @@ -45,12 +46,14 @@ export enum AudinoJobType { AUDIO_ATTRIBUTE_ANNOTATION = 'audio_attribute_annotation', } -export const JobType = [ - ...Object.values(CvatJobType), - ...Object.values(FortuneJobType), - ...Object.values(HCaptchaJobType), - ...Object.values(AudinoJobType), -]; +export const JobType = Array.from( + new Set([ + ...Object.values(CvatJobType), + ...Object.values(FortuneJobType), + ...Object.values(HCaptchaJobType), + ...Object.values(AudinoJobType), + ]), +); export type JobRequestType = CvatJobType | FortuneJobType | HCaptchaJobType; @@ -59,10 +62,9 @@ export enum JobCaptchaMode { } export enum JobCaptchaRequestType { - IMAGE_LABEL_BINARY = 'image_label_binary', IMAGE_LABEL_MULTIPLE_CHOICE = 'image_label_multiple_choice', IMAGE_LABEL_AREA_SELECT = 'image_label_area_select', - TEXT_FREEE_NTRY = 'text_free_entry', + TEXT_FREE_ENTRY = 'text_free_entry', } export enum JobCaptchaShapeType { diff --git a/packages/apps/job-launcher/server/src/common/utils/storage.ts b/packages/apps/job-launcher/server/src/common/utils/storage.ts index fbe86382ec..b5e829b30b 100644 --- a/packages/apps/job-launcher/server/src/common/utils/storage.ts +++ b/packages/apps/job-launcher/server/src/common/utils/storage.ts @@ -36,6 +36,7 @@ export function generateBucketUrl( CvatJobType.IMAGE_POINTS, CvatJobType.IMAGE_BOXES_FROM_POINTS, CvatJobType.IMAGE_SKELETONS_FROM_BOXES, + CvatJobType.AUDIO_TRANSCRIPTION, ] as JobRequestType[] ).includes(jobType) && storageData.provider != StorageProviders.AWS && diff --git a/packages/apps/job-launcher/server/src/database/migrations/1784028614177-addCvatTypes.ts b/packages/apps/job-launcher/server/src/database/migrations/1784028614177-addCvatTypes.ts new file mode 100644 index 0000000000..5558b6bf54 --- /dev/null +++ b/packages/apps/job-launcher/server/src/database/migrations/1784028614177-addCvatTypes.ts @@ -0,0 +1,59 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class AddCvatTypes1784028614177 implements MigrationInterface { + name = 'AddCvatTypes1784028614177'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(` + ALTER TYPE "hmt"."jobs_request_type_enum" + RENAME TO "jobs_request_type_enum_old" + `); + await queryRunner.query(` + CREATE TYPE "hmt"."jobs_request_type_enum" AS ENUM( + 'image_points', + 'image_polygons', + 'image_boxes', + 'image_boxes_from_points', + 'image_skeletons_from_boxes', + 'audio_transcription', + 'fortune', + 'hcaptcha', + 'audio_attribute_annotation' + ) + `); + await queryRunner.query(` + ALTER TABLE "hmt"."jobs" + ALTER COLUMN "request_type" TYPE "hmt"."jobs_request_type_enum" USING "request_type"::"text"::"hmt"."jobs_request_type_enum" + `); + await queryRunner.query(` + DROP TYPE "hmt"."jobs_request_type_enum_old" + `); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(` + CREATE TYPE "hmt"."jobs_request_type_enum_old" AS ENUM( + 'image_points', + 'image_polygons', + 'image_boxes', + 'image_boxes_from_points', + 'image_skeletons_from_boxes', + 'fortune', + 'hcaptcha', + 'audio_transcription', + 'audio_attribute_annotation' + ) + `); + await queryRunner.query(` + ALTER TABLE "hmt"."jobs" + ALTER COLUMN "request_type" TYPE "hmt"."jobs_request_type_enum_old" USING "request_type"::"text"::"hmt"."jobs_request_type_enum_old" + `); + await queryRunner.query(` + DROP TYPE "hmt"."jobs_request_type_enum" + `); + await queryRunner.query(` + ALTER TYPE "hmt"."jobs_request_type_enum_old" + RENAME TO "jobs_request_type_enum" + `); + } +} diff --git a/packages/apps/job-launcher/server/src/modules/job/job.controller.spec.ts b/packages/apps/job-launcher/server/src/modules/job/job.controller.spec.ts index 5778fa133d..d294f939e7 100644 --- a/packages/apps/job-launcher/server/src/modules/job/job.controller.spec.ts +++ b/packages/apps/job-launcher/server/src/modules/job/job.controller.spec.ts @@ -23,7 +23,11 @@ import { } from '../manifest/fixtures'; import { MutexManagerService } from '../mutex/mutex-manager.service'; import { JobController } from './job.controller'; -import { JobManifestDto, JobQuickLaunchDto } from './job.dto'; +import { + JobManifestDto, + JobQuickLaunchDto, + JobUnknownManifestDto, +} from './job.dto'; import { JobService } from './job.service'; describe('JobController', () => { @@ -31,6 +35,7 @@ describe('JobController', () => { const mockJobService = { createJob: jest.fn(), + createJobWithUnknownManifest: jest.fn(), }; const mockMutexManagerService = { @@ -316,4 +321,45 @@ describe('JobController', () => { expect(mockJobService.createJob).not.toHaveBeenCalled(); }); }); + + describe('createJobWithUnknownManifest', () => { + it('should create a job with an unknown manifest and return job ID', async () => { + const jobUnknownManifestDto: JobUnknownManifestDto = { + chainId: ChainId.POLYGON_AMOY, + requestType: FortuneJobType.FORTUNE, + manifest: { + custom: faker.string.sample(), + nested: { + value: faker.number.int(), + }, + }, + paymentCurrency: PaymentCurrency.USD, + paymentAmount: faker.number.int({ min: 100, max: 1000 }), + escrowFundToken: EscrowFundToken.HMT, + }; + + mockMutexManagerService.runExclusive.mockImplementationOnce( + async (_id, _timeout, fn) => { + return await fn(); + }, + ); + mockJobService.createJobWithUnknownManifest.mockResolvedValueOnce(1); + + const result = await jobController.createJobWithUnknownManifest( + jobUnknownManifestDto, + mockRequest, + ); + + expect(result).toBe(1); + expect(mockJobService.createJobWithUnknownManifest).toHaveBeenCalledWith( + mockRequest.user, + jobUnknownManifestDto, + ); + expect(mockMutexManagerService.runExclusive).toHaveBeenCalledWith( + `user${mockRequest.user.id}`, + MUTEX_TIMEOUT, + expect.any(Function), + ); + }); + }); }); diff --git a/packages/apps/job-launcher/server/src/modules/job/job.controller.ts b/packages/apps/job-launcher/server/src/modules/job/job.controller.ts index abb5dbdf0f..1fda2dbe6b 100644 --- a/packages/apps/job-launcher/server/src/modules/job/job.controller.ts +++ b/packages/apps/job-launcher/server/src/modules/job/job.controller.ts @@ -33,6 +33,7 @@ import { JobListDto, JobManifestDto, JobQuickLaunchDto, + JobUnknownManifestDto, } from './job.dto'; import { JobService } from './job.service'; @@ -128,6 +129,42 @@ export class JobController { ); } + @ApiOperation({ + summary: 'Create a job with an unknown manifest', + description: + 'Endpoint to create a job using a manifest JSON body without validating its format.', + }) + @ApiBody({ type: JobUnknownManifestDto }) + @ApiResponse({ + status: 201, + description: 'ID of the created job.', + type: Number, + }) + @ApiResponse({ + status: 400, + description: 'Bad Request. Invalid input parameters.', + }) + @ApiResponse({ + status: 401, + description: 'Unauthorized. Missing or invalid credentials.', + }) + @Post('/manifest-quick-launch') + public async createJobWithUnknownManifest( + @Body() data: JobUnknownManifestDto, + @Request() req: RequestWithUser, + ): Promise { + return await this.mutexManagerService.runExclusive( + `user${req.user.id}`, + MUTEX_TIMEOUT, + async () => { + return await this.jobService.createJobWithUnknownManifest( + req.user, + data, + ); + }, + ); + } + @ApiOperation({ summary: 'Get a list of jobs', description: diff --git a/packages/apps/job-launcher/server/src/modules/job/job.dto.ts b/packages/apps/job-launcher/server/src/modules/job/job.dto.ts index 2fd27bb044..3e193930fd 100644 --- a/packages/apps/job-launcher/server/src/modules/job/job.dto.ts +++ b/packages/apps/job-launcher/server/src/modules/job/job.dto.ts @@ -111,6 +111,13 @@ export class JobManifestDto extends JobDto { public manifest: ManifestDto; } +export class JobUnknownManifestDto extends JobDto { + @ApiProperty({ type: Object }) + @IsObject() + @IsNotEmpty() + public manifest: Record; +} + export class StorageDataDto { @ApiProperty({ enum: StorageProviders }) @IsEnumCaseInsensitive(StorageProviders) diff --git a/packages/apps/job-launcher/server/src/modules/job/job.service.spec.ts b/packages/apps/job-launcher/server/src/modules/job/job.service.spec.ts index b9bb5312a8..b347647a80 100644 --- a/packages/apps/job-launcher/server/src/modules/job/job.service.spec.ts +++ b/packages/apps/job-launcher/server/src/modules/job/job.service.spec.ts @@ -61,6 +61,7 @@ import { GetJobsDto, JobManifestDto, JobQuickLaunchDto, + JobUnknownManifestDto, } from './job.dto'; import { JobRepository } from './job.repository'; import { JobService } from './job.service'; @@ -137,6 +138,122 @@ describe('JobService', () => { afterEach(() => { jest.clearAllMocks(); + jest.restoreAllMocks(); + }); + + describe('createJobWithUnknownManifest', () => { + it('should upload an unknown manifest and create a job without format validation', async () => { + const userMock = createUser({ whitelist: new WhitelistEntity() }); + const dto: JobUnknownManifestDto = { + chainId: ChainId.POLYGON_AMOY, + requestType: FortuneJobType.FORTUNE, + manifest: { + arbitrary: faker.string.sample(), + schema: { + value: faker.number.int(), + }, + }, + reputationOracle: faker.finance.ethereumAddress(), + exchangeOracle: faker.finance.ethereumAddress(), + recordingOracle: faker.finance.ethereumAddress(), + paymentCurrency: PaymentCurrency.USD, + paymentAmount: faker.number.int({ min: 100, max: 1000 }), + escrowFundToken: EscrowFundToken.HMT, + }; + const uploadedFile = { + url: faker.internet.url(), + hash: faker.string.uuid(), + }; + const jobId = faker.number.int({ min: 1 }); + const createJobSpy = jest + .spyOn(jobService, 'createJob') + .mockResolvedValueOnce(jobId); + + mockManifestService.uploadManifest.mockResolvedValueOnce(uploadedFile); + + const result = await jobService.createJobWithUnknownManifest( + userMock, + dto, + ); + + expect(result).toBe(jobId); + expect(mockWeb3Service.validateChainId).toHaveBeenCalledWith(dto.chainId); + expect(mockManifestService.validateManifest).not.toHaveBeenCalled(); + expect(mockManifestService.uploadManifest).toHaveBeenCalledWith( + dto.chainId, + dto.manifest, + [dto.exchangeOracle, dto.reputationOracle, dto.recordingOracle], + ); + expect(createJobSpy).toHaveBeenCalledWith( + userMock, + dto.requestType, + expect.objectContaining({ + chainId: dto.chainId, + requestType: dto.requestType, + reputationOracle: dto.reputationOracle, + exchangeOracle: dto.exchangeOracle, + recordingOracle: dto.recordingOracle, + paymentCurrency: dto.paymentCurrency, + paymentAmount: dto.paymentAmount, + escrowFundToken: dto.escrowFundToken, + manifestUrl: uploadedFile.url, + manifestHash: uploadedFile.hash, + }), + ); + expect(createJobSpy.mock.calls[0][2]).not.toHaveProperty('manifest'); + }); + + it('should use default oracles when creating a job with an unknown manifest', async () => { + const userMock = createUser({ whitelist: new WhitelistEntity() }); + const dto: JobUnknownManifestDto = { + chainId: ChainId.POLYGON_AMOY, + requestType: HCaptchaJobType.HCAPTCHA, + manifest: { + custom: faker.string.sample(), + }, + paymentCurrency: PaymentCurrency.USD, + paymentAmount: faker.number.int({ min: 100, max: 1000 }), + escrowFundToken: EscrowFundToken.HMT, + }; + const uploadedFile = { + url: faker.internet.url(), + hash: faker.string.uuid(), + }; + const createJobSpy = jest + .spyOn(jobService, 'createJob') + .mockResolvedValueOnce(faker.number.int({ min: 1 })); + + mockManifestService.uploadManifest.mockResolvedValueOnce(uploadedFile); + + await jobService.createJobWithUnknownManifest(userMock, dto); + + expect(mockManifestService.uploadManifest).toHaveBeenCalledWith( + dto.chainId, + dto.manifest, + [ + mockWeb3ConfigService.hCaptchaOracleAddress, + mockWeb3ConfigService.hCaptchaOracleAddress, + mockWeb3ConfigService.hCaptchaOracleAddress, + ], + ); + expect(createJobSpy).toHaveBeenCalledWith( + userMock, + dto.requestType, + expect.objectContaining({ + chainId: dto.chainId, + requestType: dto.requestType, + reputationOracle: mockWeb3ConfigService.hCaptchaOracleAddress, + exchangeOracle: mockWeb3ConfigService.hCaptchaOracleAddress, + recordingOracle: mockWeb3ConfigService.hCaptchaOracleAddress, + paymentCurrency: dto.paymentCurrency, + paymentAmount: dto.paymentAmount, + escrowFundToken: dto.escrowFundToken, + manifestUrl: uploadedFile.url, + manifestHash: uploadedFile.hash, + }), + ); + expect(createJobSpy.mock.calls[0][2]).not.toHaveProperty('manifest'); + }); }); describe('createJob', () => { diff --git a/packages/apps/job-launcher/server/src/modules/job/job.service.ts b/packages/apps/job-launcher/server/src/modules/job/job.service.ts index 2c967136b3..5e05787098 100644 --- a/packages/apps/job-launcher/server/src/modules/job/job.service.ts +++ b/packages/apps/job-launcher/server/src/modules/job/job.service.ts @@ -75,6 +75,8 @@ import { GetJobsDto, JobDetailsDto, JobListDto, + JobQuickLaunchDto, + JobUnknownManifestDto, } from './job.dto'; import { JobEntity } from './job.entity'; import { JobRepository } from './job.repository'; @@ -271,6 +273,41 @@ export class JobService { return jobEntity.id; } + public async createJobWithUnknownManifest( + user: UserEntity, + dto: JobUnknownManifestDto, + ): Promise { + const { chainId, requestType, manifest } = dto; + let { reputationOracle, exchangeOracle, recordingOracle } = dto; + + this.web3Service.validateChainId(chainId); + + if (!reputationOracle || !exchangeOracle || !recordingOracle) { + const defaultOracles = await this.getDefaultOracles(chainId, requestType); + reputationOracle = reputationOracle ?? defaultOracles.reputationOracle; + exchangeOracle = exchangeOracle ?? defaultOracles.exchangeOracle; + recordingOracle = recordingOracle ?? defaultOracles.recordingOracle; + } + + const { url, hash } = await this.manifestService.uploadManifest( + chainId, + manifest, + [exchangeOracle, reputationOracle, recordingOracle], + ); + + const { manifest: _manifest, ...jobDto } = dto; + const quickLaunchDto: JobQuickLaunchDto = { + ...jobDto, + reputationOracle, + exchangeOracle, + recordingOracle, + manifestUrl: url, + manifestHash: hash, + }; + + return this.createJob(user, dto.requestType, quickLaunchDto); + } + private async getDefaultOracles( chainId: ChainId, requestType: JobRequestType, diff --git a/packages/apps/job-launcher/server/src/modules/manifest/manifest.service.spec.ts b/packages/apps/job-launcher/server/src/modules/manifest/manifest.service.spec.ts index 413e893a0a..5fa407a6d2 100644 --- a/packages/apps/job-launcher/server/src/modules/manifest/manifest.service.spec.ts +++ b/packages/apps/job-launcher/server/src/modules/manifest/manifest.service.spec.ts @@ -64,7 +64,7 @@ describe('ManifestService', () => { it('should validate an hcaptcha manifest successfully', async () => { const manifest = { job_mode: faker.lorem.word(), - request_type: JobCaptchaRequestType.IMAGE_LABEL_BINARY, + request_type: JobCaptchaRequestType.IMAGE_LABEL_AREA_SELECT, request_config: {}, requester_accuracy_target: faker.number.float({ min: 0.5, @@ -112,7 +112,7 @@ describe('ManifestService', () => { it('should throw when a required hcaptcha property is missing', async () => { const manifest = { job_mode: faker.lorem.word(), - request_type: JobCaptchaRequestType.IMAGE_LABEL_BINARY, + request_type: JobCaptchaRequestType.IMAGE_LABEL_AREA_SELECT, request_config: {}, requester_accuracy_target: faker.number.float({ min: 0.5, From 5374362f2be2929af99c62b7f8c8d7d03385da09 Mon Sep 17 00:00:00 2001 From: Maxim Zhiltsov Date: Fri, 24 Jul 2026 12:31:38 +0300 Subject: [PATCH 14/33] [CVAT] Use remaining funds to compute assignment bounty (#3979) --- .../cvat/exchange-oracle/src/chain/escrow.py | 27 +++++++++++++++++-- .../cvat/exchange-oracle/src/chain/web3.py | 16 +++++++++++ .../exchange-oracle/src/entrypoints/debug.py | 4 +++ .../src/handlers/job_creation/utils.py | 13 ++++----- .../tests/unit/test_audio_task_creation.py | 11 +++++--- 5 files changed, 59 insertions(+), 12 deletions(-) diff --git a/packages/examples/cvat/exchange-oracle/src/chain/escrow.py b/packages/examples/cvat/exchange-oracle/src/chain/escrow.py index 43b72a28f1..0afcecc2a6 100644 --- a/packages/examples/cvat/exchange-oracle/src/chain/escrow.py +++ b/packages/examples/cvat/exchange-oracle/src/chain/escrow.py @@ -1,13 +1,14 @@ import json +from decimal import Decimal from functools import partial import httpx2 from human_protocol_sdk.constants import ChainId, Status from human_protocol_sdk.encryption import Encryption, EncryptionUtils -from human_protocol_sdk.escrow import EscrowData, EscrowUtils +from human_protocol_sdk.escrow import EscrowClient, EscrowData, EscrowUtils from human_protocol_sdk.utils import validate_url -from src.chain.web3 import get_token_symbol +from src.chain.web3 import get_token_decimals, get_token_symbol, get_web3 from src.core.config import Config from src.core.types import OracleWebhookTypes from src.services.cache import Cache @@ -108,3 +109,25 @@ def get_escrow_fund_token_symbol(chain_id: int, escrow_address: str) -> str: token_address=escrow.token, set_callback=partial(get_token_symbol, chain_id, escrow.token), ) + + +def get_escrow_fund_token_decimals(chain_id: int, escrow_address: str) -> int: + """ + ERC-20 decimals: divide the raw token amount by 10**decimals for the user representation + (https://eips.ethereum.org/EIPS/eip-20). + """ + + escrow = get_escrow(chain_id, escrow_address) + return get_token_decimals(chain_id, escrow.token) + + +def get_remaining_escrow_funds(chain_id: int, escrow_address: str) -> Decimal | None: + web3 = get_web3(chain_id) + client = EscrowClient(web3) + + remaining_funds = client.get_remaining_funds(escrow_address) + if remaining_funds is None: + return None + + token_decimals = get_escrow_fund_token_decimals(chain_id, escrow_address) + return Decimal(remaining_funds) / Decimal(10**token_decimals) diff --git a/packages/examples/cvat/exchange-oracle/src/chain/web3.py b/packages/examples/cvat/exchange-oracle/src/chain/web3.py index 9bf9f033bd..a28add23ed 100644 --- a/packages/examples/cvat/exchange-oracle/src/chain/web3.py +++ b/packages/examples/cvat/exchange-oracle/src/chain/web3.py @@ -19,6 +19,16 @@ } ] # ABI for fetching token symbol +decimals_abi = [ + { + "constant": True, + "inputs": [], + "name": "decimals", + "outputs": [{"name": "", "type": "uint8"}], + "type": "function", + } +] # ABI for fetching token decimals (ERC-20 optional method; https://eips.ethereum.org/EIPS/eip-20) + def get_web3(chain_id: int | Networks): match chain_id: @@ -83,3 +93,9 @@ def get_token_symbol(chain_id: int, token_address: str) -> str: w3 = get_web3(chain_id) contract = w3.eth.contract(address=w3.to_checksum_address(token_address), abi=symbol_abi) return contract.functions.symbol().call() + + +def get_token_decimals(chain_id: int, token_address: str) -> int: + w3 = get_web3(chain_id) + contract = w3.eth.contract(address=w3.to_checksum_address(token_address), abi=decimals_abi) + return contract.functions.decimals().call() diff --git a/packages/examples/cvat/exchange-oracle/src/entrypoints/debug.py b/packages/examples/cvat/exchange-oracle/src/entrypoints/debug.py index 0c996dfbc2..a656ba6457 100644 --- a/packages/examples/cvat/exchange-oracle/src/entrypoints/debug.py +++ b/packages/examples/cvat/exchange-oracle/src/entrypoints/debug.py @@ -6,6 +6,7 @@ from argparse import ArgumentParser from collections.abc import Generator from contextlib import ExitStack, contextmanager +from decimal import Decimal from logging import Logger from pathlib import Path, PurePosixPath from typing import Any @@ -118,6 +119,9 @@ def patched_get_escrow(chain_id: int, escrow_address: str) -> EscrowData: mock.patch.object(EscrowUtils, "get_escrow", patched_get_escrow), mock.patch("src.chain.escrow.get_token_symbol", return_value="HMT"), mock.patch("src.chain.web3.get_token_symbol", return_value="HMT"), + mock.patch( + "src.handlers.job_creation.utils.get_remaining_escrow_funds", return_value=Decimal(100) + ), ): yield diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/utils.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/utils.py index 5746ba5295..d86959e39e 100644 --- a/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/utils.py +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/utils.py @@ -1,13 +1,12 @@ from __future__ import annotations import os -from decimal import Decimal from typing import TYPE_CHECKING, TypeVar from datumaro.util.image import IMAGE_EXTENSIONS import src.cvat.api_calls as cvat_api -from src.chain.escrow import get_escrow +from src.chain.escrow import get_remaining_escrow_funds from src.core.tasks import TaskTypes from src.services.cloud import CloudProviders @@ -54,12 +53,14 @@ def get_assignment_bounty( def _get_assignment_bounty_from_escrow( escrow_address: str, chain_id: int, job_count: int ) -> str | None: - # TODO: refine (fees, already-paid amount, token decimals). Rough split of the escrow's total - # funds across the jobs. if not job_count: return None - escrow = get_escrow(chain_id, escrow_address) - return str(Decimal(escrow.total_funded_amount) / job_count) + + funds = get_remaining_escrow_funds(chain_id, escrow_address) + if funds is None: + return None + + return str(funds / job_count) def is_image(path: str) -> bool: diff --git a/packages/examples/cvat/exchange-oracle/tests/unit/test_audio_task_creation.py b/packages/examples/cvat/exchange-oracle/tests/unit/test_audio_task_creation.py index 2c853789f5..d2c4615b6f 100644 --- a/packages/examples/cvat/exchange-oracle/tests/unit/test_audio_task_creation.py +++ b/packages/examples/cvat/exchange-oracle/tests/unit/test_audio_task_creation.py @@ -1,5 +1,6 @@ import json import subprocess +from decimal import Decimal from pathlib import Path from unittest.mock import Mock, patch @@ -143,16 +144,18 @@ def test_create_audio_transcription_task(fxt_audio_transcription_input): manifest, ds_rois_tsv, gt_tsv = fxt_audio_transcription_input cvat_api = _make_cvat_api_mock() - escrow = Mock(total_funded_amount="40") with ( patch.object(handlers, "get_escrow_manifest", return_value=manifest), patch("src.handlers.job_creation.builders.audio.transcription.cvat_api", cvat_api), - patch("src.handlers.job_creation.utils.get_escrow", return_value=escrow) as mock_get_escrow, + patch( + "src.handlers.job_creation.utils.get_remaining_escrow_funds", + return_value=Decimal(40), + ) as mock_remaining_funds, ): handlers.create_task(ESCROW_ADDRESS, CHAIN_ID) # v2 manifest → per-assignment bounty derived from escrow funds / job count - mock_get_escrow.assert_called_once_with(CHAIN_ID, ESCROW_ADDRESS) + mock_remaining_funds.assert_called_once_with(CHAIN_ID, ESCROW_ADDRESS) # Check CVAT API calls cvat_api.create_project.assert_called_once() @@ -172,7 +175,7 @@ def test_create_audio_transcription_task(fxt_audio_transcription_input): assert project.cvat_cloudstorage_id == 100 assert project.job_type == TaskTypes.audio_transcription.value assert project.chain_id == CHAIN_ID - assert project.assignment_bounty == "10" # 40 escrow funds / 4 assignments + assert project.assignment_bounty == "10" # 40 tokens remaining / 4 assignments tasks = db_service.get_tasks_by_cvat_project_id(session, project.cvat_id) assert len(tasks) == assignment_count From cfeb8bb1c035e7219ee78cabd4151d240c8774c1 Mon Sep 17 00:00:00 2001 From: Maxim Zhiltsov Date: Fri, 24 Jul 2026 15:56:04 +0300 Subject: [PATCH 15/33] [CVAT] Fix default `.env` discovery (#3982) --- .../cvat/exchange-oracle/src/core/config.py | 16 +++++++- .../cvat/recording-oracle/src/__init__.py | 37 ------------------- .../recording-oracle/src/apps/__init__.py | 0 .../src/apps/recording_oracle.py | 37 +++++++++++++++++++ .../cvat/recording-oracle/src/core/config.py | 15 ++++++++ .../recording-oracle/src/entrypoints/debug.py | 2 +- .../recording-oracle/src/entrypoints/run.py | 2 +- .../cvat/recording-oracle/tests/conftest.py | 2 +- 8 files changed, 70 insertions(+), 41 deletions(-) create mode 100644 packages/examples/cvat/recording-oracle/src/apps/__init__.py create mode 100644 packages/examples/cvat/recording-oracle/src/apps/recording_oracle.py diff --git a/packages/examples/cvat/exchange-oracle/src/core/config.py b/packages/examples/cvat/exchange-oracle/src/core/config.py index 87a024ca00..453019939d 100644 --- a/packages/examples/cvat/exchange-oracle/src/core/config.py +++ b/packages/examples/cvat/exchange-oracle/src/core/config.py @@ -5,6 +5,7 @@ import os from collections.abc import Iterable from os import getenv +from pathlib import Path from typing import ClassVar, Optional from attrs.converters import to_bool @@ -17,13 +18,26 @@ from src.utils.logging import parse_log_level from src.utils.net import is_ipv4 + +def find_default_dotenv() -> Path | None: + # Check the default location in the project + dotenv_path = Path(__file__).parents[1] / ".env" + if dotenv_path.is_file(): + return str(dotenv_path) + else: + return None + + dotenv_path = getenv("DOTENV_PATH", None) + +if dotenv_path is None: + dotenv_path = find_default_dotenv() + if dotenv_path and not os.path.exists(dotenv_path): # noqa: PTH110 raise FileNotFoundError(dotenv_path) load_dotenv(dotenv_path) - # TODO: add some logic to report unused/deprecated env vars on startup diff --git a/packages/examples/cvat/recording-oracle/src/__init__.py b/packages/examples/cvat/recording-oracle/src/__init__.py index 1ecfdddd86..e69de29bb2 100644 --- a/packages/examples/cvat/recording-oracle/src/__init__.py +++ b/packages/examples/cvat/recording-oracle/src/__init__.py @@ -1,37 +0,0 @@ -import logging - -from fastapi import FastAPI - -from src.core.config import Config -from src.crons import setup_cron_jobs -from src.endpoints import init_api -from src.endpoints.error_handlers import setup_error_handlers -from src.log import setup_logging - -setup_logging() - -app = FastAPI( - title="Human Recording Oracle", - description=""" - Recording Oracle is a HUMAN oracle which main goal is to: - 1. Receive webhooks from an Exchange Oracle - 2. Process them and evaluate answers collected from CVAT - 3. Store evaluated answers in a s3 bucket - 4. Notify reputation oracle that final annotations are ready - """, - version="0.1.0", -) - -init_api(app) -setup_error_handlers(app) - - -@app.on_event("startup") -async def startup_event(): - logger = logging.getLogger("app") - logger.info("Recording Oracle is up and running!") - - -is_test = Config.environment == "test" -if not is_test: - setup_cron_jobs(app) diff --git a/packages/examples/cvat/recording-oracle/src/apps/__init__.py b/packages/examples/cvat/recording-oracle/src/apps/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/examples/cvat/recording-oracle/src/apps/recording_oracle.py b/packages/examples/cvat/recording-oracle/src/apps/recording_oracle.py new file mode 100644 index 0000000000..1ecfdddd86 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/src/apps/recording_oracle.py @@ -0,0 +1,37 @@ +import logging + +from fastapi import FastAPI + +from src.core.config import Config +from src.crons import setup_cron_jobs +from src.endpoints import init_api +from src.endpoints.error_handlers import setup_error_handlers +from src.log import setup_logging + +setup_logging() + +app = FastAPI( + title="Human Recording Oracle", + description=""" + Recording Oracle is a HUMAN oracle which main goal is to: + 1. Receive webhooks from an Exchange Oracle + 2. Process them and evaluate answers collected from CVAT + 3. Store evaluated answers in a s3 bucket + 4. Notify reputation oracle that final annotations are ready + """, + version="0.1.0", +) + +init_api(app) +setup_error_handlers(app) + + +@app.on_event("startup") +async def startup_event(): + logger = logging.getLogger("app") + logger.info("Recording Oracle is up and running!") + + +is_test = Config.environment == "test" +if not is_test: + setup_cron_jobs(app) diff --git a/packages/examples/cvat/recording-oracle/src/core/config.py b/packages/examples/cvat/recording-oracle/src/core/config.py index 477046d0bf..9cf334f9c6 100644 --- a/packages/examples/cvat/recording-oracle/src/core/config.py +++ b/packages/examples/cvat/recording-oracle/src/core/config.py @@ -5,6 +5,7 @@ import os from collections.abc import Iterable from os import getenv +from pathlib import Path from typing import ClassVar from attrs.converters import to_bool @@ -16,7 +17,21 @@ from src.utils.logging import parse_log_level from src.utils.net import is_ipv4 + +def find_default_dotenv() -> Path | None: + # Check the default location in the project + dotenv_path = Path(__file__).parents[1] / ".env" + if dotenv_path.is_file(): + return str(dotenv_path) + else: + return None + + dotenv_path = getenv("DOTENV_PATH", None) + +if dotenv_path is None: + dotenv_path = find_default_dotenv() + if dotenv_path and not os.path.exists(dotenv_path): # noqa: PTH110 raise FileNotFoundError(dotenv_path) diff --git a/packages/examples/cvat/recording-oracle/src/entrypoints/debug.py b/packages/examples/cvat/recording-oracle/src/entrypoints/debug.py index 4549807de9..5afe74580c 100644 --- a/packages/examples/cvat/recording-oracle/src/entrypoints/debug.py +++ b/packages/examples/cvat/recording-oracle/src/entrypoints/debug.py @@ -196,7 +196,7 @@ def apply_local_development_patches() -> Generator[None, None, None]: register_in_kvstore() uvicorn.run( - app="src:app", + app="src.apps.recording_oracle:app", host="0.0.0.0", # noqa: S104 port=int(Config.port), workers=Config.workers_amount, diff --git a/packages/examples/cvat/recording-oracle/src/entrypoints/run.py b/packages/examples/cvat/recording-oracle/src/entrypoints/run.py index 2f09b1a09f..54adeba6ae 100644 --- a/packages/examples/cvat/recording-oracle/src/entrypoints/run.py +++ b/packages/examples/cvat/recording-oracle/src/entrypoints/run.py @@ -10,7 +10,7 @@ register_in_kvstore() uvicorn.run( - app="src:app", + app="src.apps.recording_oracle:app", host="0.0.0.0", # noqa: S104 port=int(Config.port), workers=Config.workers_amount, diff --git a/packages/examples/cvat/recording-oracle/tests/conftest.py b/packages/examples/cvat/recording-oracle/tests/conftest.py index 32972c10f8..2f8e634cda 100644 --- a/packages/examples/cvat/recording-oracle/tests/conftest.py +++ b/packages/examples/cvat/recording-oracle/tests/conftest.py @@ -5,7 +5,7 @@ from sqlalchemy import inspect, text from sqlalchemy.orm import Session -from src import app +from src.apps.recording_oracle import app from src.db import Base, SessionLocal, engine From 98441cb59223958a1b0f76446a0a5ecfffc0c19c Mon Sep 17 00:00:00 2001 From: portuu3 <61605646+portuu3@users.noreply.github.com> Date: Mon, 27 Jul 2026 12:02:45 +0200 Subject: [PATCH 16/33] Update cvat payout calculator for the new manifest (#3981) Co-authored-by: portuu3 <> --- .../cvat-payouts-calculator.spec.ts | 88 ++++++++++++------- .../cvat-payouts-calculator.ts | 63 ++++--------- .../default-payouts-calculator.spec.ts | 7 +- 3 files changed, 80 insertions(+), 78 deletions(-) diff --git a/packages/apps/reputation-oracle/server/src/modules/escrow-completion/payouts-calculation/cvat-payouts-calculator.spec.ts b/packages/apps/reputation-oracle/server/src/modules/escrow-completion/payouts-calculation/cvat-payouts-calculator.spec.ts index 00cf233469..13c1da8dac 100644 --- a/packages/apps/reputation-oracle/server/src/modules/escrow-completion/payouts-calculation/cvat-payouts-calculator.spec.ts +++ b/packages/apps/reputation-oracle/server/src/modules/escrow-completion/payouts-calculation/cvat-payouts-calculator.spec.ts @@ -4,7 +4,6 @@ import { faker } from '@faker-js/faker'; import { createMock } from '@golevelup/ts-jest'; import { EscrowClient } from '@human-protocol/sdk'; import { Test } from '@nestjs/testing'; -import { ethers } from 'ethers'; import _ from 'lodash'; import { CvatAnnotationMeta } from '@/common/types'; @@ -48,14 +47,16 @@ describe('CvatPayoutsCalculator', () => { const mockedGetIntermediateResultsUrl = jest .fn() .mockImplementation(async () => faker.internet.url()); - const mockedGetTokenAddress = jest.fn().mockImplementation(async () => { - return faker.finance.ethereumAddress(); - }); + const mockedGetReservedFunds = jest + .fn() + .mockImplementation(async () => + BigInt(faker.number.int({ min: 1000, max: 100000 })), + ); beforeAll(() => { mockedEscrowClient.build.mockResolvedValue({ getIntermediateResultsUrl: mockedGetIntermediateResultsUrl, - getTokenAddress: mockedGetTokenAddress, + getReservedFunds: mockedGetReservedFunds, } as unknown as EscrowClient); }); @@ -84,23 +85,21 @@ describe('CvatPayoutsCalculator', () => { ); }); - it('should properly calculate workers bounties trimming the decimals', async () => { + it('should properly calculate workers bounties', async () => { const annotators = [ faker.finance.ethereumAddress(), faker.finance.ethereumAddress(), ]; const jobsPerAnnotator = faker.number.int({ min: 1, max: 3 }); - const tokenDecimals = BigInt(6); + const jobCount = jobsPerAnnotator * annotators.length; + const payoutPerJob = BigInt(faker.number.int({ min: 1000, max: 100000 })); const annotationsMeta: CvatAnnotationMeta = { - jobs: Array.from( - { length: jobsPerAnnotator * annotators.length }, - (_v, index: number) => ({ - job_id: index, - final_result_id: faker.number.int(), - }), - ), + jobs: Array.from({ length: jobCount }, (_v, index: number) => ({ + job_id: index, + final_result_id: faker.number.int(), + })), results: [], }; for (const job of annotationsMeta.jobs) { @@ -130,26 +129,20 @@ describe('CvatPayoutsCalculator', () => { mockedStorageService.downloadJsonLikeData.mockResolvedValueOnce( annotationsMeta, ); - mockedWeb3Service.getTokenDecimals.mockResolvedValueOnce(tokenDecimals); - - const mockedJobBounty = '0.123456789'; // more decimals than token has - const manifest = { - ...generateCvatManifest(), - job_bounty: mockedJobBounty, - }; + mockedGetReservedFunds.mockResolvedValueOnce( + payoutPerJob * BigInt(jobCount), + ); const payouts = await calculator.calculate({ chainId, escrowAddress, - manifest, + manifest: generateCvatManifest(), finalResultsUrl: faker.internet.url(), }); - const trimmedBounty = '0.123456'; - + const expectedJobBounty = payoutPerJob; const expectedAmountPerAnnotator = - BigInt(jobsPerAnnotator) * - ethers.parseUnits(trimmedBounty, tokenDecimals); + BigInt(jobsPerAnnotator) * expectedJobBounty; const expectedPayouts = annotators.map((address) => ({ address, @@ -168,7 +161,9 @@ describe('CvatPayoutsCalculator', () => { ]; const jobsPerAnnotator = faker.number.int({ min: 1, max: 3 }); - const tokenDecimals = BigInt(faker.number.int({ min: 6, max: 18 })); + const reservedFunds = BigInt( + faker.number.int({ min: 1000, max: 100000 }).toString(), + ); const annotationsMeta: CvatAnnotationMeta = { jobs: Array.from( @@ -207,7 +202,7 @@ describe('CvatPayoutsCalculator', () => { mockedStorageService.downloadJsonLikeData.mockResolvedValueOnce( annotationsMeta, ); - mockedWeb3Service.getTokenDecimals.mockResolvedValueOnce(tokenDecimals); + mockedGetReservedFunds.mockResolvedValueOnce(reservedFunds); const manifest = generateCvatManifest(); @@ -218,9 +213,14 @@ describe('CvatPayoutsCalculator', () => { finalResultsUrl: faker.internet.url(), }); + const matchedJobCount = annotationsMeta.jobs.filter((job) => + annotationsMeta.results.some( + (result) => result.id === job.final_result_id, + ), + ).length; + const expectedJobBounty = reservedFunds / BigInt(matchedJobCount); const expectedAmountPerAnnotator = - BigInt(jobsPerAnnotator) * - ethers.parseUnits(manifest.job_bounty, tokenDecimals); + BigInt(jobsPerAnnotator) * expectedJobBounty; const expectedPayouts = annotators.map((address) => ({ address, @@ -231,5 +231,33 @@ describe('CvatPayoutsCalculator', () => { _.sortBy(expectedPayouts, 'address'), ); }); + + it('throws when there are no jobs with matching final results', async () => { + mockedStorageService.downloadJsonLikeData.mockResolvedValueOnce({ + jobs: [ + { + job_id: faker.number.int(), + final_result_id: 1, + }, + ], + results: [ + { + id: 2, + job_id: faker.number.int(), + annotator_wallet_address: faker.finance.ethereumAddress(), + annotation_quality: faker.number.float(), + }, + ], + } as CvatAnnotationMeta); + + await expect( + calculator.calculate({ + chainId, + escrowAddress, + manifest: generateCvatManifest(), + finalResultsUrl: faker.internet.url(), + }), + ).rejects.toThrow('Invalid annotation meta'); + }); }); }); diff --git a/packages/apps/reputation-oracle/server/src/modules/escrow-completion/payouts-calculation/cvat-payouts-calculator.ts b/packages/apps/reputation-oracle/server/src/modules/escrow-completion/payouts-calculation/cvat-payouts-calculator.ts index bde421dbca..ad4e1660a8 100644 --- a/packages/apps/reputation-oracle/server/src/modules/escrow-completion/payouts-calculation/cvat-payouts-calculator.ts +++ b/packages/apps/reputation-oracle/server/src/modules/escrow-completion/payouts-calculation/cvat-payouts-calculator.ts @@ -1,6 +1,5 @@ import { EscrowClient } from '@human-protocol/sdk'; import { Injectable } from '@nestjs/common'; -import { ethers } from 'ethers'; import type { OverrideProperties } from 'type-fest'; import { CVAT_VALIDATION_META_FILENAME } from '@/common/constants'; @@ -27,7 +26,6 @@ export class CvatPayoutsCalculator implements EscrowPayoutsCalculator { ) {} async calculate({ - manifest, chainId, escrowAddress, }: CalculateCvatPayoutsInput): Promise { @@ -41,40 +39,34 @@ export class CvatPayoutsCalculator implements EscrowPayoutsCalculator { await this.storageService.downloadJsonLikeData( `${intermediateResultsUrl}/${CVAT_VALIDATION_META_FILENAME}`, ); - if (!annotations.jobs.length || !annotations.results.length) { throw new Error('Invalid annotation meta'); } - const tokenAddress = await escrowClient.getTokenAddress(escrowAddress); - const tokenDecimals = await this.web3Service.getTokenDecimals( - chainId, - tokenAddress, - ); - const jobBountyValue = this.parseJobBounty( - manifest.job_bounty, - Number(tokenDecimals), - ); - const workersBounties = new Map(); + const reservedFunds = await escrowClient.getReservedFunds(escrowAddress); - for (const job of annotations.jobs) { - const jobFinalResult = annotations.results.find( - (result) => result.id === job.final_result_id, + const matchedJobResults = annotations.jobs + .map((job) => + annotations.results.find((result) => result.id === job.final_result_id), + ) + .filter((result): result is CvatAnnotationMeta['results'][number] => + Boolean(result), ); + + if (!matchedJobResults.length) { + throw new Error('Invalid annotation meta'); + } + + const jobBountyValue = reservedFunds / BigInt(matchedJobResults.length); + const workersBounties = new Map(); + + for (const jobFinalResult of matchedJobResults) { // TODO: enable annotation quality validation when ready - if ( - jobFinalResult - // && jobFinalResult.annotation_quality >= manifest.validation.min_quality - ) { - const workerAddress = jobFinalResult.annotator_wallet_address; + const workerAddress = jobFinalResult.annotator_wallet_address; - const currentWorkerBounty = workersBounties.get(workerAddress) || 0n; + const currentWorkerBounty = workersBounties.get(workerAddress) || 0n; - workersBounties.set( - workerAddress, - currentWorkerBounty + jobBountyValue, - ); - } + workersBounties.set(workerAddress, currentWorkerBounty + jobBountyValue); } return Array.from(workersBounties.entries()).map( @@ -84,21 +76,4 @@ export class CvatPayoutsCalculator implements EscrowPayoutsCalculator { }), ); } - - private parseJobBounty(jobBounty: string, tokenDecimals: number): bigint { - const parts = jobBounty.split('.'); - if (parts.length > 1) { - const decimalsInBounty = parts[1].length; - if (decimalsInBounty > tokenDecimals) { - if (tokenDecimals === 0) { - return ethers.parseUnits(parts[0], tokenDecimals); - } - return ethers.parseUnits( - `${parts[0]}.${parts[1].slice(0, tokenDecimals)}`, - tokenDecimals, - ); - } - } - return ethers.parseUnits(jobBounty, tokenDecimals); - } } diff --git a/packages/apps/reputation-oracle/server/src/modules/escrow-completion/payouts-calculation/default-payouts-calculator.spec.ts b/packages/apps/reputation-oracle/server/src/modules/escrow-completion/payouts-calculation/default-payouts-calculator.spec.ts index 7f7e79cb4e..6f5c574f4a 100644 --- a/packages/apps/reputation-oracle/server/src/modules/escrow-completion/payouts-calculation/default-payouts-calculator.spec.ts +++ b/packages/apps/reputation-oracle/server/src/modules/escrow-completion/payouts-calculation/default-payouts-calculator.spec.ts @@ -49,10 +49,7 @@ describe('DefaultPayoutsCalculator', () => { }); describe('calculate', () => { - const reservedFunds = BigInt(faker.number.int({ min: 1000 }).toString()); - const mockedGetReservedFunds = jest - .fn() - .mockImplementation(async () => reservedFunds); + const mockedGetReservedFunds = jest.fn().mockResolvedValue(0n); beforeEach(() => { mockedEscrowClient.build.mockResolvedValue({ @@ -74,7 +71,9 @@ describe('DefaultPayoutsCalculator', () => { requestType: MarketingJobType.SOCIAL_MEDIA_PROMOTION, submissionsRequired: faker.number.int({ min: 2, max: 5 }), }; + const reservedFunds = BigInt(faker.number.int({ min: 1000 }).toString()); + mockedGetReservedFunds.mockResolvedValueOnce(reservedFunds); mockedStorageService.downloadJsonLikeData.mockResolvedValueOnce(results); const payouts = await calculator.calculate({ From 92bc526f5b58083bbb7f1b106d2886bf00f6d205 Mon Sep 17 00:00:00 2001 From: Dmitry Nechay Date: Mon, 27 Jul 2026 15:55:21 +0300 Subject: [PATCH 17/33] [Job Launcher] fix: accept unknown manifest as is (#3984) --- .../src/common/interceptors/snake-case.ts | 44 +++++++++++++++++-- .../server/src/modules/job/job.controller.ts | 2 + 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/packages/apps/job-launcher/server/src/common/interceptors/snake-case.ts b/packages/apps/job-launcher/server/src/common/interceptors/snake-case.ts index 5d87024276..9bcab61124 100644 --- a/packages/apps/job-launcher/server/src/common/interceptors/snake-case.ts +++ b/packages/apps/job-launcher/server/src/common/interceptors/snake-case.ts @@ -5,6 +5,7 @@ import { NestInterceptor, StreamableFile, } from '@nestjs/common'; +import { Reflector } from '@nestjs/core'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { @@ -12,16 +13,49 @@ import { transformKeysFromSnakeToCamel, } from '../utils/case-converter'; +export const SkipSnakeCaseTransform = Reflector.createDecorator< + | { + // Either skip specified top-level body props or skip it entirely + body?: string[] | boolean; + query?: boolean; + response?: boolean; + } + | undefined +>({ + key: 'skipSnakeCaseTransform', +}); + @Injectable() export class SnakeCaseInterceptor implements NestInterceptor { + constructor(private reflector: Reflector) {} + intercept(context: ExecutionContext, next: CallHandler): Observable { const request = context.switchToHttp().getRequest(); - if (request.body) { - request.body = transformKeysFromSnakeToCamel(request.body); + const skipTransformOptions = this.reflector.getAllAndOverride( + SkipSnakeCaseTransform, + [context.getHandler(), context.getClass()], + ) || { body: false, query: false, response: false }; + + const shouldSkipBody = skipTransformOptions.body === true; + if (request.body && !shouldSkipBody) { + const transformed = transformKeysFromSnakeToCamel(request.body); + + const skipBodyProps = Array.isArray(skipTransformOptions.body) + ? skipTransformOptions.body + : []; + for (const prop of skipBodyProps) { + if (prop in request.body) { + // @ts-expect-error - 'transformed' is same type as 'request.body' + transformed[prop] = request.body[prop]; + } + } + + request.body = transformed; } - if (request.query) { + const shouldSkipQuery = skipTransformOptions.query === true; + if (request.query && !shouldSkipQuery) { const transformedQuery = transformKeysFromSnakeToCamel(request.query); Object.defineProperty(request, 'query', { value: transformedQuery, @@ -33,9 +67,11 @@ export class SnakeCaseInterceptor implements NestInterceptor { return next.handle().pipe( map((data) => { - if (data instanceof StreamableFile) { + const shouldSkipResponse = skipTransformOptions.query === true; + if (data instanceof StreamableFile || shouldSkipResponse) { return data; } + return transformKeysFromCamelToSnake(data); }), ); diff --git a/packages/apps/job-launcher/server/src/modules/job/job.controller.ts b/packages/apps/job-launcher/server/src/modules/job/job.controller.ts index 1fda2dbe6b..cb9ee1b5c9 100644 --- a/packages/apps/job-launcher/server/src/modules/job/job.controller.ts +++ b/packages/apps/job-launcher/server/src/modules/job/job.controller.ts @@ -36,6 +36,7 @@ import { JobUnknownManifestDto, } from './job.dto'; import { JobService } from './job.service'; +import { SkipSnakeCaseTransform } from '../../common/interceptors/snake-case'; @ApiBearerAuth() @UseGuards(JwtAuthGuard) @@ -135,6 +136,7 @@ export class JobController { 'Endpoint to create a job using a manifest JSON body without validating its format.', }) @ApiBody({ type: JobUnknownManifestDto }) + @SkipSnakeCaseTransform({ body: ['manifest'] }) @ApiResponse({ status: 201, description: 'ID of the created job.', From 64732baf0edf0f69b91b0920eecbe72d7445abe8 Mon Sep 17 00:00:00 2001 From: Dmitry Nechay Date: Mon, 27 Jul 2026 17:49:08 +0300 Subject: [PATCH 18/33] [HUMAN App] chore: remove unused prop (#3986) --- .../human-app/server/src/modules/cron-job/cron-job.service.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/apps/human-app/server/src/modules/cron-job/cron-job.service.ts b/packages/apps/human-app/server/src/modules/cron-job/cron-job.service.ts index eec931c76f..154173b4ae 100644 --- a/packages/apps/human-app/server/src/modules/cron-job/cron-job.service.ts +++ b/packages/apps/human-app/server/src/modules/cron-job/cron-job.service.ts @@ -35,7 +35,6 @@ function assertJobsDiscoveryResponseItemsFormat( item.reward_amount, item.reward_token, item.created_at, - item.updated_at, ].includes(undefined) ) { throw new Error('Job discovery response items missing expected fields'); @@ -129,7 +128,6 @@ export class CronJobService { JobDiscoveryFieldName.RewardAmount, JobDiscoveryFieldName.RewardToken, JobDiscoveryFieldName.CreatedAt, - JobDiscoveryFieldName.UpdatedAt, ]; command.data.status = JobStatus.ACTIVE; const initialResponse = From cb85eb362539c50e9836d1e7f2a5ac1ea0490853 Mon Sep 17 00:00:00 2001 From: Maxim Zhiltsov Date: Tue, 28 Jul 2026 15:24:34 +0300 Subject: [PATCH 19/33] [CVAT] Support repeated query param style for selectable fields (#3987) --- .../exchange-oracle/src/endpoints/exchange.py | 12 ++- .../src/endpoints/filtering.py | 98 ++++++++++++++++++- .../tests/api/test_exchange_api.py | 47 +++++++++ 3 files changed, 151 insertions(+), 6 deletions(-) diff --git a/packages/examples/cvat/exchange-oracle/src/endpoints/exchange.py b/packages/examples/cvat/exchange-oracle/src/endpoints/exchange.py index af4ef571c7..bc996cdcd9 100644 --- a/packages/examples/cvat/exchange-oracle/src/endpoints/exchange.py +++ b/packages/examples/cvat/exchange-oracle/src/endpoints/exchange.py @@ -80,12 +80,20 @@ class SelectableFields(StrEnum, metaclass=BetterEnumMeta): # NOTE: default_factory=list should not be used since # FilterDepends changes valid types from list to str default=None, - description="Comma separated fields to be returned for every available job", + description=( + "Fields to be returned for every available job. " + "Accepts both a comma-separated list (?fields=a,b) " + "and repeated params (?fields=a&fields=b). Available fields: " + f"{', '.join(SelectableFields.__members__.values())}" + ), openapi_examples={ "one_field": Example(value=SelectableFields.job_description), - "several_fields": Example( + "several_fields_csv": Example( value=f"{SelectableFields.job_description},{SelectableFields.created_at}" ), + "several_fields_repeated": Example( + value=[SelectableFields.job_description, SelectableFields.created_at] + ), }, ), ), diff --git a/packages/examples/cvat/exchange-oracle/src/endpoints/filtering.py b/packages/examples/cvat/exchange-oracle/src/endpoints/filtering.py index e3f35b630b..ee0dea9f56 100644 --- a/packages/examples/cvat/exchange-oracle/src/endpoints/filtering.py +++ b/packages/examples/cvat/exchange-oracle/src/endpoints/filtering.py @@ -1,17 +1,31 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any, ClassVar, TypeVar +from collections.abc import Iterable +from copy import deepcopy +from types import UnionType +from typing import TYPE_CHECKING, Any, ClassVar, Optional, TypeVar, Union, get_args, get_origin import fastapi import fastapi.params import sqlalchemy import sqlalchemy.orm -from fastapi_filter import FilterDepends, with_prefix +from fastapi import Depends +from fastapi.exceptions import RequestValidationError +from fastapi_filter import with_prefix from fastapi_filter.contrib.sqlalchemy import Filter as _Filter -from pydantic import BaseModel, Field, ValidationInfo, field_validator +from pydantic import ( + BaseModel, + Field, + ValidationError, + ValidationInfo, + create_model, + field_validator, +) from src.utils.enums import BetterEnumMeta, StrEnum +_UNION_TYPES = (Union, UnionType) + if TYPE_CHECKING: from enum import Enum @@ -150,7 +164,16 @@ def split_selectable_fields(cls, value, field: ValidationInfo): if field.field_name == cls.Constants.selector_field_name: if not value: return cls.get_default_field_value(field.field_name) - return [v.strip() for v in value.split(",")] + + # Accept both popular formats: + # - a single comma-separated value ("?fields=a,b") + # - repeated params ("?fields=a&fields=b") + # and any mix of them. + if isinstance(value, str): + value = [value] + + return [item.strip() for entry in value for item in str(entry).split(",")] + return value @@ -158,4 +181,71 @@ def _get_field_info(klass: type[BaseModel], field_name: str): return klass.model_fields[field_name] +def _list_to_str_fields(filter_cls: type[_Filter]) -> dict[str, tuple[Any, Any]]: + # Reimplements fastapi_filter's _list_to_str_fields, but keeps the selector field + # as a real list type so that FastAPI parses repeated params ("?fields=a&fields=b") + # into a list. The list element type is relaxed to str so that a single + # comma-separated value ("?fields=a,b") also passes through untouched to the + # filter's own `split_selectable_fields` validator. + selector_field_name = getattr(filter_cls.Constants, "selector_field_name", None) + + ret: dict[str, tuple[Any, Any]] = {} + for name, f in filter_cls.model_fields.items(): + field_info = deepcopy(f) + annotation = f.annotation + + if get_origin(annotation) in _UNION_TYPES: + annotation_args: list = list(get_args(f.annotation)) + if type(None) in annotation_args: + annotation_args.remove(type(None)) + if len(annotation_args) == 1: + annotation = annotation_args[0] + + is_list = annotation is list or get_origin(annotation) is list + if not is_list: + ret[name] = (f.annotation, field_info) + elif name == selector_field_name: + ret[name] = (list[str] | None, field_info) + else: + if isinstance(field_info.default, Iterable): + field_info.default = ",".join(field_info.default) + ret[name] = (str if f.is_required() else Optional[str], field_info) # noqa: UP045 + + return ret + + +def FilterDepends( # noqa: N802 (public API name kept for drop-in compatibility) + filter_cls: type[_Filter], *, by_alias: bool = False, use_cache: bool = True +) -> Any: + # Check https://github.com/fastapi/fastapi/issues/50 for more info + # Local variant of fastapi_filter.FilterDepends that preserves the selector field + # as a list, enabling both the comma-separated and the repeated-param formats. + Filter = filter_cls # match the original function naming + fields = _list_to_str_fields(Filter) + GeneratedFilter: type[BaseModel] = create_model(Filter.__class__.__name__, **fields) + + class FilterWrapper(GeneratedFilter): # type: ignore[misc, valid-type] + def __new__(cls, *args, **kwargs): + try: + instance = GeneratedFilter(*args, **kwargs) + data = instance.model_dump( + exclude_unset=True, exclude_defaults=True, by_alias=by_alias + ) + if original_filter := getattr(Filter.Constants, "original_filter", None): + prefix = f"{Filter.Constants.prefix}__" + stripped = {} + # TODO: replace with `removeprefix` when python 3.8 is no longer supported + # stripped = {k.removeprefix(NestedFilter.Constants.prefix): v for k, v in value.items()} # noqa: E501 + for k, v in data.items(): + if k.startswith(prefix): + k = k.replace(prefix, "", 1) + stripped[k] = v + return original_filter(**stripped) + return Filter(**data) + except ValidationError as e: + raise RequestValidationError(e.errors()) from e + + return Depends(FilterWrapper, use_cache=use_cache) + + __all__ = ["Filter", "FilterDepends", "OrderingDirection", "with_prefix"] diff --git a/packages/examples/cvat/exchange-oracle/tests/api/test_exchange_api.py b/packages/examples/cvat/exchange-oracle/tests/api/test_exchange_api.py index 511a971907..2dd4d972f8 100644 --- a/packages/examples/cvat/exchange-oracle/tests/api/test_exchange_api.py +++ b/packages/examples/cvat/exchange-oracle/tests/api/test_exchange_api.py @@ -377,6 +377,53 @@ def test_can_list_jobs_200_with_fields(client: TestClient, session: Session) -> ) +def test_can_list_jobs_200_with_fields_comma_separated_and_repeated_are_equivalent( + client: TestClient, session: Session +) -> None: + session.begin() + user = User( + wallet_address=WALLET_ADDRESS1, + cvat_email=cvat_email, + cvat_id=1, + ) + session.add(user) + + _, _, cvat_job = create_project_task_and_job( + session, "0x86e83d346041E8806e352681f3F14549C0d2BC66", 1 + ) + assignment = Assignment( + id=str(uuid.uuid4()), + user_wallet_address=WALLET_ADDRESS1, + cvat_job_id=cvat_job.cvat_id, + expires_at=utcnow() + timedelta(days=1), + ) + session.add(assignment) + session.commit() + + with ( + open("tests/assets/cloud/manifests/manifest-v1.json") as data, + patch("src.endpoints.serializers.get_escrow_manifest") as mock_get_manifest, + patch( + "src.endpoints.serializers.get_escrow_fund_token_symbol" + ) as mock_get_escrow_fund_token_symbol, + ): + manifest = json.load(data) + mock_get_manifest.return_value = manifest + mock_get_escrow_fund_token_symbol.return_value = "HMT" + + fields = ["job_description", "created_at", "reward_amount"] + + # same field set requested two ways: "?fields=a,b,c" vs "?fields=a&fields=b&fields=c" + comma_response = client.get( + "/job", headers=get_auth_header(), params={"fields": ",".join(fields)} + ) + repeated_response = client.get("/job", headers=get_auth_header(), params={"fields": fields}) + + assert comma_response.status_code == 200 + assert repeated_response.status_code == 200 + assert comma_response.json() == repeated_response.json() + + def test_can_list_jobs_200_with_sorting(client: TestClient, session: Session) -> None: # sort: ASC, DESC; sort_field: chain_id|job_type|created_at|updated_at session.begin() From 126ba04223ebf1a51b212a63dbe2c8fbbd2a33f8 Mon Sep 17 00:00:00 2001 From: portuu3 <61605646+portuu3@users.noreply.github.com> Date: Wed, 29 Jul 2026 14:49:50 +0200 Subject: [PATCH 20/33] [Job Launcher] fix: error loading fee with an invalid rpc (#3988) Co-authored-by: portuu3 <> --- .../components/Jobs/Create/CryptoPayForm.tsx | 126 ++++++++++++++---- .../components/Jobs/Create/FiatPayForm.tsx | 19 ++- .../client/src/providers/WagmiProvider.tsx | 31 ++--- 3 files changed, 135 insertions(+), 41 deletions(-) diff --git a/packages/apps/job-launcher/client/src/components/Jobs/Create/CryptoPayForm.tsx b/packages/apps/job-launcher/client/src/components/Jobs/Create/CryptoPayForm.tsx index f9fce014bb..73dc6542df 100644 --- a/packages/apps/job-launcher/client/src/components/Jobs/Create/CryptoPayForm.tsx +++ b/packages/apps/job-launcher/client/src/components/Jobs/Create/CryptoPayForm.tsx @@ -7,6 +7,7 @@ import { Box, Button, Checkbox, + CircularProgress, FormControl, FormControlLabel, Grid, @@ -19,12 +20,8 @@ import { Decimal } from 'decimal.js'; import { ethers } from 'ethers'; import { useEffect, useMemo, useState } from 'react'; import { Address } from 'viem'; -import { - useAccount, - useReadContract, - useWalletClient, - usePublicClient, -} from 'wagmi'; +import { readContract } from 'viem/actions'; +import { useAccount, useWalletClient, usePublicClient } from 'wagmi'; import { TokenSelect } from '../../../components/TokenSelect'; import { useCreateJobPageUI } from '../../../providers/CreateJobPageUIProvider'; import * as jobService from '../../../services/job'; @@ -51,6 +48,11 @@ export const CryptoPayForm = ({ const [amount, setAmount] = useState(); const [isLoading, setIsLoading] = useState(false); const [jobLauncherAddress, setJobLauncherAddress] = useState(); + const [jobLauncherFee, setJobLauncherFee] = useState(); + const [configurationError, setConfigurationError] = useState(); + const [configurationRetry, setConfigurationRetry] = useState(0); + const [feeError, setFeeError] = useState(); + const [feeRetry, setFeeRetry] = useState(0); const [minFee, setMinFee] = useState(0.01); const { data: signer } = useWalletClient(); const publicClient = usePublicClient(); @@ -62,14 +64,21 @@ export const CryptoPayForm = ({ useEffect(() => { const fetchJobLauncherData = async () => { - const address = await paymentService.getOperatorAddress(); - const fee = await paymentService.getFee(); - setJobLauncherAddress(address); - setMinFee(fee); + setConfigurationError(undefined); + try { + const address = await paymentService.getOperatorAddress(); + const fee = await paymentService.getFee(); + setJobLauncherAddress(address); + setMinFee(fee); + } catch { + setConfigurationError( + 'Unable to load the payment configuration. Please try again.', + ); + } }; fetchJobLauncherData(); - }, []); + }, [configurationRetry]); useEffect(() => { const fetchRates = async () => { @@ -106,17 +115,46 @@ export const CryptoPayForm = ({ setDecimals(Math.min(tokenDecimals, 6)); }, [tokenDecimals]); - const { data: jobLauncherFee } = useReadContract({ - address: NETWORKS[jobRequest.chainId!]?.kvstoreAddress as Address, - abi: KVStoreABI, - functionName: 'get', - args: jobLauncherAddress - ? [jobLauncherAddress, KVStoreKeys.fee] - : undefined, - query: { - enabled: !!jobLauncherAddress, - }, - }); + useEffect(() => { + if (!signer || !publicClient || !jobLauncherAddress || !jobRequest.chainId) + return; + + let ignore = false; + + const fetchJobLauncherFee = async () => { + setFeeError(undefined); + setJobLauncherFee(undefined); + try { + const parameters = { + address: NETWORKS[jobRequest.chainId!]?.kvstoreAddress as Address, + abi: KVStoreABI, + functionName: 'get', + args: [jobLauncherAddress, KVStoreKeys.fee], + } as const; + + let fee: string; + try { + fee = (await readContract(signer, parameters)) as string; + } catch { + fee = (await readContract(publicClient, parameters)) as string; + } + + if (!ignore) { + setJobLauncherFee(fee); + } + } catch { + if (!ignore) { + setFeeError('Unable to load the job launcher fee. Please try again.'); + } + } + }; + + fetchJobLauncherFee(); + + return () => { + ignore = true; + }; + }, [feeRetry, jobLauncherAddress, jobRequest.chainId, publicClient, signer]); const minFeeToken = useMemo(() => { if (minFee && paymentTokenRate) @@ -125,7 +163,7 @@ export const CryptoPayForm = ({ }, [minFee, paymentTokenRate]); const feeAmount = useMemo(() => { - if (!amount) return 0; + if (!amount || jobLauncherFee == null) return 0; const amountDecimal = new Decimal(amount); const feeDecimal = new Decimal(jobLauncherFee as string).div(100); return Number( @@ -244,7 +282,7 @@ export const CryptoPayForm = ({ } }; - if (!chain || chain.id !== jobRequest.chainId) + if (isConnected && (!chain || chain.id !== jobRequest.chainId)) return ( @@ -257,6 +295,43 @@ export const CryptoPayForm = ({ ); + if (configurationError || feeError) + return ( + + + {configurationError || feeError} + + + + ); + + if ( + !jobLauncherAddress || + (isConnected && (!signer || jobLauncherFee == null)) + ) + return ( + + + + ); + return ( @@ -389,7 +464,7 @@ export const CryptoPayForm = ({ > Fee - ({Number(jobLauncherFee)}%){' '} + ({jobLauncherFee == null ? '—' : Number(jobLauncherFee)}%){' '} {paymentTokenSymbol ? `${Number(feeAmount.toFixed(6))} ${paymentTokenSymbol?.toUpperCase()}` : ''} @@ -476,6 +551,7 @@ export const CryptoPayForm = ({ !paymentTokenAddress || !fundTokenSymbol || !amount || + jobLauncherFee == null || jobRequest.chainId !== chain?.id } loading={isLoading} diff --git a/packages/apps/job-launcher/client/src/components/Jobs/Create/FiatPayForm.tsx b/packages/apps/job-launcher/client/src/components/Jobs/Create/FiatPayForm.tsx index 82502c9b9b..b6164da092 100644 --- a/packages/apps/job-launcher/client/src/components/Jobs/Create/FiatPayForm.tsx +++ b/packages/apps/job-launcher/client/src/components/Jobs/Create/FiatPayForm.tsx @@ -2,6 +2,7 @@ import KVStoreABI from '@human-protocol/core/abis/KVStore.json'; import { KVStoreKeys, NETWORKS } from '@human-protocol/sdk'; import { LoadingButton } from '@mui/lab'; import { + Alert, Box, Button, Checkbox, @@ -142,6 +143,8 @@ export const FiatPayForm = ({ data: jobLauncherFee, error, isError, + isFetching: isFeeFetching, + refetch: refetchJobLauncherFee, } = useReadContract({ address: NETWORKS[jobRequest.chainId!]?.kvstoreAddress as Address, abi: KVStoreABI, @@ -276,7 +279,9 @@ export const FiatPayForm = ({ return ( - {loadingInitialData ? ( + {loadingInitialData || + !jobLauncherAddress || + (!isError && (isFeeFetching || jobLauncherFee == null)) ? ( + ) : isError ? ( + + + Unable to load the job launcher fee from MetaMask or the public + network provider. + + + ) : ( @@ -522,6 +537,8 @@ export const FiatPayForm = ({ !amount || (!payWithAccountBalance && !selectedCard) || hasError || + isFeeFetching || + jobLauncherFee == null || !tokenSymbol } > diff --git a/packages/apps/job-launcher/client/src/providers/WagmiProvider.tsx b/packages/apps/job-launcher/client/src/providers/WagmiProvider.tsx index ad9308ed9e..f63c653823 100644 --- a/packages/apps/job-launcher/client/src/providers/WagmiProvider.tsx +++ b/packages/apps/job-launcher/client/src/providers/WagmiProvider.tsx @@ -4,10 +4,11 @@ import { WagmiProvider as WWagmiProvider, fallback, http, + injected, unstable_connector, } from 'wagmi'; import * as wagmiChains from 'wagmi/chains'; -import { coinbaseWallet, walletConnect, metaMask } from 'wagmi/connectors'; +import { coinbaseWallet, walletConnect } from 'wagmi/connectors'; import { LOCALHOST } from '../constants/chains'; @@ -37,41 +38,41 @@ export const wagmiConfig = createConfig({ coinbaseWallet({ appName: 'human-job-launcher', }), - metaMask(), + injected({ target: 'metaMask' }), ], transports: { - [wagmiChains.mainnet.id]: fallback([unstable_connector(metaMask), http()]), - [wagmiChains.sepolia.id]: fallback([unstable_connector(metaMask), http()]), - [wagmiChains.bsc.id]: fallback([unstable_connector(metaMask), http()]), + [wagmiChains.mainnet.id]: fallback([unstable_connector(injected), http()]), + [wagmiChains.sepolia.id]: fallback([unstable_connector(injected), http()]), + [wagmiChains.bsc.id]: fallback([unstable_connector(injected), http()]), [wagmiChains.bscTestnet.id]: fallback([ - unstable_connector(metaMask), + unstable_connector(injected), http(), ]), - [wagmiChains.polygon.id]: fallback([unstable_connector(metaMask), http()]), + [wagmiChains.polygon.id]: fallback([unstable_connector(injected), http()]), [wagmiChains.polygonAmoy.id]: fallback([ - unstable_connector(metaMask), + unstable_connector(injected), http(), ]), - [wagmiChains.moonbeam.id]: fallback([unstable_connector(metaMask), http()]), + [wagmiChains.moonbeam.id]: fallback([unstable_connector(injected), http()]), [wagmiChains.moonbaseAlpha.id]: fallback([ - unstable_connector(metaMask), + unstable_connector(injected), http(), ]), [wagmiChains.avalanche.id]: fallback([ - unstable_connector(metaMask), + unstable_connector(injected), http(), ]), [wagmiChains.avalancheFuji.id]: fallback([ - unstable_connector(metaMask), + unstable_connector(injected), http(), ]), - [wagmiChains.xLayer.id]: fallback([unstable_connector(metaMask), http()]), + [wagmiChains.xLayer.id]: fallback([unstable_connector(injected), http()]), [wagmiChains.xLayerTestnet.id]: fallback([ - unstable_connector(metaMask), + unstable_connector(injected), http(), ]), [LOCALHOST.id]: fallback([ - unstable_connector(metaMask), + unstable_connector(injected), http(LOCALHOST.rpcUrls.default.http[0]), ]), }, From daaf906f3cd1a887a22b3670a20c18f8e6e6c47f Mon Sep 17 00:00:00 2001 From: Dmitry Nechay Date: Thu, 30 Jul 2026 12:23:08 +0300 Subject: [PATCH 21/33] [HUMAN App] feat: enhance API for new UI (#3989) --- packages/apps/human-app/server/.env.example | 2 +- .../server/src/common/enums/global-common.ts | 15 --- .../server/src/common/utils/pageable.model.ts | 3 + .../exchange-oracle.gateway.ts | 28 ++-- .../exchange-oracle.mapper.profile.ts | 16 +-- .../model/exchange-oracle.model.ts | 95 ++++++++++++++ .../spec/exchange-oracle.fixtures.ts | 100 ++++++++++++++ .../spec/exchange-oracle.gateway.spec.ts | 48 +++---- .../integrations/kv-store/kv-store.gateway.ts | 2 +- .../src/modules/cron-job/cron-job.service.ts | 72 +++++----- .../cron-job/spec/cron-job.service.spec.ts | 30 ++--- .../jobs-discovery.controller.ts | 28 ++-- .../jobs-discovery.mapper.profile.ts | 27 ++-- .../jobs-discovery/jobs-discovery.module.ts | 4 +- .../jobs-discovery/jobs-discovery.service.ts | 101 ++++++-------- .../model/jobs-discovery.model.ts | 123 +++++++++--------- .../spec/jobs-discovery.controller.spec.ts | 19 ++- .../spec/jobs-discovery.fixtures.ts | 86 +++++------- .../spec/jobs-discovery.service.mock.ts | 2 +- .../spec/jobs-discovery.service.spec.ts | 48 +++---- .../model/oracle-discovery.model.ts | 112 +++++++--------- .../oracle-discovery.controller.ts | 50 ++++++- .../oracle-discovery.module.ts | 3 +- .../spec/oracle-discovery.controller.spec.ts | 88 ------------- .../spec/oracle-discovery.fixture.ts | 8 +- 25 files changed, 599 insertions(+), 511 deletions(-) create mode 100644 packages/apps/human-app/server/src/integrations/exchange-oracle/model/exchange-oracle.model.ts create mode 100644 packages/apps/human-app/server/src/integrations/exchange-oracle/spec/exchange-oracle.fixtures.ts delete mode 100644 packages/apps/human-app/server/src/modules/oracle-discovery/spec/oracle-discovery.controller.spec.ts diff --git a/packages/apps/human-app/server/.env.example b/packages/apps/human-app/server/.env.example index d009192d3c..8ec8f2c40b 100644 --- a/packages/apps/human-app/server/.env.example +++ b/packages/apps/human-app/server/.env.example @@ -18,7 +18,7 @@ HUMAN_APP_SECRET_KEY=sk_example_1VwUpBMO8H0v4Pmu4TPiWFEwuMguW4PkozSban4Rfbc # Redis REDIS_HOST=0.0.0.0 REDIS_PORT=6380 -REIDS_DB=1 +REDIS_DB=1 # Flush DB on startup IS_CACHE_TO_RESTART=false diff --git a/packages/apps/human-app/server/src/common/enums/global-common.ts b/packages/apps/human-app/server/src/common/enums/global-common.ts index 386300c11c..bf16bddec1 100644 --- a/packages/apps/human-app/server/src/common/enums/global-common.ts +++ b/packages/apps/human-app/server/src/common/enums/global-common.ts @@ -1,11 +1,3 @@ -export enum JobDiscoveryFieldName { - JobDescription = 'job_description', - RewardAmount = 'reward_amount', - RewardToken = 'reward_token', - CreatedAt = 'created_at', - UpdatedAt = 'updated_at', -} - export enum JobStatus { ACTIVE = 'active', COMPLETED = 'completed', @@ -21,13 +13,6 @@ export enum AssignmentStatus { REJECTED = 'rejected', } -export enum JobDiscoverySortField { - CHAIN_ID = 'chain_id', - JOB_TYPE = 'job_type', - REWARD_AMOUNT = 'reward_amount', - CREATED_AT = 'created_at', -} - export enum SortOrder { ASC = 'asc', DESC = 'desc', diff --git a/packages/apps/human-app/server/src/common/utils/pageable.model.ts b/packages/apps/human-app/server/src/common/utils/pageable.model.ts index 586b60804d..c6c1330238 100644 --- a/packages/apps/human-app/server/src/common/utils/pageable.model.ts +++ b/packages/apps/human-app/server/src/common/utils/pageable.model.ts @@ -40,6 +40,7 @@ export abstract class PageableDto { @IsOptional() abstract sort_field?: any; } + export abstract class PageableParams { @AutoMap() page?: number; @@ -52,6 +53,7 @@ export abstract class PageableParams { abstract sortField?: any; } + export abstract class PageableData { @AutoMap() page?: number; @@ -64,6 +66,7 @@ export abstract class PageableData { abstract sort_field?: any; } + export abstract class PageableResponse { page: number; page_size: number; diff --git a/packages/apps/human-app/server/src/integrations/exchange-oracle/exchange-oracle.gateway.ts b/packages/apps/human-app/server/src/integrations/exchange-oracle/exchange-oracle.gateway.ts index ef1d4f2316..c38742e779 100644 --- a/packages/apps/human-app/server/src/integrations/exchange-oracle/exchange-oracle.gateway.ts +++ b/packages/apps/human-app/server/src/integrations/exchange-oracle/exchange-oracle.gateway.ts @@ -5,8 +5,8 @@ import { Injectable } from '@nestjs/common'; import { AxiosError, AxiosRequestConfig } from 'axios'; import { lastValueFrom } from 'rxjs'; import { HttpMethod } from '../../common/enums/http-method'; -import { toCleanObjParams } from '../../common/utils/gateway-common.utils'; import * as errorUtils from '../../common/utils/error'; +import { toCleanObjParams } from '../../common/utils/gateway-common.utils'; import logger from '../../logger'; import { JobAssignmentCommand, @@ -20,12 +20,6 @@ import { ResignJobCommand, ResignJobData, } from '../../modules/job-assignment/model/job-assignment.model'; -import { - JobsDiscoveryParams, - JobsDiscoveryParamsCommand, - JobsDiscoveryParamsData, - JobsDiscoveryResponse, -} from '../../modules/jobs-discovery/model/jobs-discovery.model'; import { OracleStatisticsCommand, OracleStatisticsResponse, @@ -40,6 +34,12 @@ import { } from '../../modules/user-worker/model/worker-registration.model'; import { EscrowUtilsGateway } from '../escrow/escrow-utils-gateway.service'; import { KvStoreGateway } from '../kv-store/kv-store.gateway'; +import { + FetchJobsCommand, + FetchJobsParams, + FetchJobsParamsData, + FetchJobsResponse, +} from './model/exchange-oracle.model'; @Injectable() export class ExchangeOracleGateway { @@ -169,15 +169,13 @@ export class ExchangeOracleGateway { return this.callExternalHttpUtilRequest(options); } - async fetchJobs( - command: JobsDiscoveryParamsCommand, - ): Promise { - const jobsDiscoveryParamsData = this.mapper.map( + async fetchJobs(command: FetchJobsCommand): Promise { + const fetchJobsParamsData = this.mapper.map( command.data, - JobsDiscoveryParams, - JobsDiscoveryParamsData, + FetchJobsParams, + FetchJobsParamsData, ); - const reducedParams = toCleanObjParams(jobsDiscoveryParamsData); + const reducedParams = toCleanObjParams(fetchJobsParamsData); const options: AxiosRequestConfig = { method: HttpMethod.GET, url: `${await this.kvStoreGateway.getExchangeOracleUrlByAddress( @@ -189,7 +187,7 @@ export class ExchangeOracleGateway { Accept: 'application/json', }, }; - return this.callExternalHttpUtilRequest(options); + return this.callExternalHttpUtilRequest(options); } async sendRegistrationInExchangeOracle( diff --git a/packages/apps/human-app/server/src/integrations/exchange-oracle/exchange-oracle.mapper.profile.ts b/packages/apps/human-app/server/src/integrations/exchange-oracle/exchange-oracle.mapper.profile.ts index 9709289dd4..7132456fc3 100644 --- a/packages/apps/human-app/server/src/integrations/exchange-oracle/exchange-oracle.mapper.profile.ts +++ b/packages/apps/human-app/server/src/integrations/exchange-oracle/exchange-oracle.mapper.profile.ts @@ -1,5 +1,3 @@ -import { AutomapperProfile, InjectMapper } from '@automapper/nestjs'; -import { Injectable } from '@nestjs/common'; import { CamelCaseNamingConvention, createMap, @@ -9,6 +7,8 @@ import { namingConventions, SnakeCaseNamingConvention, } from '@automapper/core'; +import { AutomapperProfile, InjectMapper } from '@automapper/nestjs'; +import { Injectable } from '@nestjs/common'; import { JobAssignmentData, JobAssignmentParams, @@ -17,14 +17,14 @@ import { ResignJobCommand, ResignJobData, } from '../../modules/job-assignment/model/job-assignment.model'; -import { - JobsDiscoveryParams, - JobsDiscoveryParamsData, -} from '../../modules/jobs-discovery/model/jobs-discovery.model'; import { RegistrationInExchangeOracleCommand, RegistrationInExchangeOracleData, } from '../../modules/user-worker/model/worker-registration.model'; +import { + FetchJobsParams, + FetchJobsParamsData, +} from './model/exchange-oracle.model'; @Injectable() export class ExchangeOracleProfile extends AutomapperProfile { @@ -63,8 +63,8 @@ export class ExchangeOracleProfile extends AutomapperProfile { ); createMap( mapper, - JobsDiscoveryParams, - JobsDiscoveryParamsData, + FetchJobsParams, + FetchJobsParamsData, // Automapper has problem with mapping arrays, thus explicit conversion forMember( (destination) => destination.fields, diff --git a/packages/apps/human-app/server/src/integrations/exchange-oracle/model/exchange-oracle.model.ts b/packages/apps/human-app/server/src/integrations/exchange-oracle/model/exchange-oracle.model.ts new file mode 100644 index 0000000000..f5d5d151a8 --- /dev/null +++ b/packages/apps/human-app/server/src/integrations/exchange-oracle/model/exchange-oracle.model.ts @@ -0,0 +1,95 @@ +import { AutoMap } from '@automapper/classes'; +import { JobStatus } from '../../../common/enums/global-common'; +import { + PageableData, + PageableParams, + PageableResponse, +} from '../../../common/utils/pageable.model'; + +export enum FetchJobsFieldName { + JobDescription = 'job_description', + RewardAmount = 'reward_amount', + RewardToken = 'reward_token', + CreatedAt = 'created_at', +} + +export enum FetchJobsSortField { + CHAIN_ID = 'chain_id', + JOB_TYPE = 'job_type', + REWARD_AMOUNT = 'reward_amount', + CREATED_AT = 'created_at', +} + +export class FetchJobsParams extends PageableParams { + @AutoMap() + escrowAddress?: string; + + @AutoMap() + chainId?: number; + + @AutoMap() + sortField?: FetchJobsSortField; + + @AutoMap() + jobType?: string; + + @AutoMap() + fields: FetchJobsFieldName[]; + + @AutoMap() + status: JobStatus; + + @AutoMap() + updatedAfter?: string; + + qualifications?: string[]; +} + +export class FetchJobsCommand { + @AutoMap() + oracleAddress: string; + @AutoMap() + token: string; + @AutoMap() + data: FetchJobsParams; +} + +export class FetchJobsParamsData extends PageableData { + @AutoMap() + escrow_address?: string; + + @AutoMap() + chain_id?: number; + + @AutoMap() + sort_field?: FetchJobsSortField; + + @AutoMap() + job_type?: string; + + @AutoMap() + fields: FetchJobsFieldName[]; + + @AutoMap() + status: JobStatus; + + @AutoMap() + updated_after?: string; +} + +export type FetchJobsResponseItem = { + escrow_address: string; + chain_id: number; + job_type: string; + status: JobStatus; + job_description?: string; + reward_amount?: string; + reward_token?: string; + created_at?: string; + updated_at?: string; + qualifications: string[]; +}; + +export class FetchJobsResponse extends PageableResponse { + results: FetchJobsResponseItem[]; +} diff --git a/packages/apps/human-app/server/src/integrations/exchange-oracle/spec/exchange-oracle.fixtures.ts b/packages/apps/human-app/server/src/integrations/exchange-oracle/spec/exchange-oracle.fixtures.ts new file mode 100644 index 0000000000..82e4fd37dc --- /dev/null +++ b/packages/apps/human-app/server/src/integrations/exchange-oracle/spec/exchange-oracle.fixtures.ts @@ -0,0 +1,100 @@ +import { JobStatus, SortOrder } from '../../../common/enums/global-common'; +import { + FetchJobsCommand, + FetchJobsFieldName, + FetchJobsParamsData, + FetchJobsResponse, + FetchJobsResponseItem, + FetchJobsSortField, +} from '../model/exchange-oracle.model'; + +const ESCROW_ADDRESS = 'test_address'; +const CHAIN_ID = 1; +const PAGE_SIZE = 10; +const PAGE = 0; +const SORT = SortOrder.ASC; +const SORT_FIELD = FetchJobsSortField.CREATED_AT; +const JOB_TYPE = 'FORTUNE'; +const EXCHANGE_ORACLE_ADDRESS = '0x3dfa342'; +const STATUS = JobStatus.ACTIVE; +const FIELDS = [ + FetchJobsFieldName.CreatedAt, + FetchJobsFieldName.JobDescription, +]; + +export const fetchJobsCommandFixture: FetchJobsCommand = { + data: { + chainId: CHAIN_ID, + pageSize: PAGE_SIZE, + page: PAGE, + sort: SORT, + sortField: SORT_FIELD, + jobType: JOB_TYPE, + status: STATUS, + fields: FIELDS, + }, + token: 'jwt-token', + oracleAddress: EXCHANGE_ORACLE_ADDRESS, +}; + +export const paramsDataFixture: FetchJobsParamsData = { + chain_id: CHAIN_ID, + page_size: PAGE_SIZE, + page: PAGE, + sort: SORT, + sort_field: SORT_FIELD, + job_type: JOB_TYPE, + fields: FIELDS, + status: STATUS, +}; +export const paramsDataFixtureAsString = `?escrow_address=${paramsDataFixture.escrow_address}&chain_id=${paramsDataFixture.chain_id}&page_size=${paramsDataFixture.page_size}&page=${paramsDataFixture.page}&sort=${paramsDataFixture.sort}&sort_field=${paramsDataFixture.sort_field}&job_type=${paramsDataFixture.job_type}&fields=${paramsDataFixture.fields.join(',')}`; + +export const responseItemFixture1: FetchJobsResponseItem = { + escrow_address: ESCROW_ADDRESS, + chain_id: CHAIN_ID, + job_type: JOB_TYPE, + status: JobStatus.ACTIVE, + created_at: '2025-03-18T03:00:00.000Z', + qualifications: [], + job_description: 'Response item fixture 1 description', + reward_amount: '42.1', + reward_token: 'hmt', + updated_at: '2025-03-18T03:00:00.000Z', +}; +export const responseItemFixture2: FetchJobsResponseItem = { + escrow_address: ESCROW_ADDRESS, + chain_id: CHAIN_ID, + job_type: JOB_TYPE, + status: JobStatus.COMPLETED, + created_at: '2025-03-18T02:00:00.000Z', + qualifications: [], + job_description: 'Response item fixture 2 description', + reward_amount: '42.2', + reward_token: 'hmt', + updated_at: '2025-03-18T02:00:00.000Z', +}; +export const responseItemFixture3: FetchJobsResponseItem = { + escrow_address: ESCROW_ADDRESS, + chain_id: CHAIN_ID, + job_type: JOB_TYPE, + status: JobStatus.ACTIVE, + created_at: '2025-03-18T01:00:00.000Z', + qualifications: [], + job_description: 'Response item fixture 3 description', + reward_amount: '42.3', + reward_token: 'hmt', + updated_at: '2025-03-18T01:00:00.000Z', +}; +export const responseItemsFixture: FetchJobsResponseItem[] = [ + responseItemFixture1, + responseItemFixture2, + responseItemFixture3, +]; + +export const responseFixture: FetchJobsResponse = { + results: responseItemsFixture, + page: PAGE, + page_size: PAGE_SIZE, + total_pages: 34, + total_results: 4, +}; diff --git a/packages/apps/human-app/server/src/integrations/exchange-oracle/spec/exchange-oracle.gateway.spec.ts b/packages/apps/human-app/server/src/integrations/exchange-oracle/spec/exchange-oracle.gateway.spec.ts index f52aea4d11..d6558f25b7 100644 --- a/packages/apps/human-app/server/src/integrations/exchange-oracle/spec/exchange-oracle.gateway.spec.ts +++ b/packages/apps/human-app/server/src/integrations/exchange-oracle/spec/exchange-oracle.gateway.spec.ts @@ -1,15 +1,13 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { HttpService } from '@nestjs/axios'; -import { ExchangeOracleGateway } from '../exchange-oracle.gateway'; -import { - statisticsExchangeOracleUrl, - generalUserStatsCommandFixture, - oracleStatsCommandFixture, -} from '../../../modules/statistics/spec/statistics.fixtures'; -import { AutomapperModule } from '@automapper/nestjs'; import { classes } from '@automapper/classes'; +import { AutomapperModule } from '@automapper/nestjs'; +import { HttpService } from '@nestjs/axios'; +import { GoneException, HttpException } from '@nestjs/common'; +import { Test, TestingModule } from '@nestjs/testing'; +import { AxiosResponse } from 'axios'; import nock, { RequestBodyMatcher } from 'nock'; import { of, throwError } from 'rxjs'; +import { HttpMethod } from '../../../common/enums/http-method'; +import { ResignJobData } from '../../../modules/job-assignment/model/job-assignment.model'; import { jobAssignmentCommandFixture, jobAssignmentDataFixture, @@ -19,26 +17,28 @@ import { jobsFetchParamsDataFixtureAsString, workerRegisterUrl, } from '../../../modules/job-assignment/spec/job-assignment.fixtures'; -import { ExchangeOracleProfile } from '../exchange-oracle.mapper.profile'; import { - jobsDiscoveryParamsCommandFixture, - paramsDataFixture, - paramsDataFixtureAsString, - responseFixture, -} from '../../../modules/jobs-discovery/spec/jobs-discovery.fixtures'; -import { GoneException, HttpException } from '@nestjs/common'; -import { HttpMethod } from '../../../common/enums/http-method'; -import { KvStoreGateway } from '../../kv-store/kv-store.gateway'; -import { EscrowUtilsGateway } from '../../escrow/escrow-utils-gateway.service'; -import { ResignJobData } from '../../../modules/job-assignment/model/job-assignment.model'; -import { JobsDiscoveryParamsData } from '../../../modules/jobs-discovery/model/jobs-discovery.model'; -import { AxiosResponse } from 'axios'; + generalUserStatsCommandFixture, + oracleStatsCommandFixture, + statisticsExchangeOracleUrl, +} from '../../../modules/statistics/spec/statistics.fixtures'; import { RegistrationInExchangeOracleData } from '../../../modules/user-worker/model/worker-registration.model'; import { registerWorkerCommandFixture, registerWorkerDataFixture, responseWorkerFixture, } from '../../../modules/user-worker/spec/worker.fixtures'; +import { EscrowUtilsGateway } from '../../escrow/escrow-utils-gateway.service'; +import { KvStoreGateway } from '../../kv-store/kv-store.gateway'; +import { ExchangeOracleGateway } from '../exchange-oracle.gateway'; +import { ExchangeOracleProfile } from '../exchange-oracle.mapper.profile'; +import { FetchJobsParamsData } from '../model/exchange-oracle.model'; +import { + fetchJobsCommandFixture, + paramsDataFixture, + paramsDataFixtureAsString, + responseFixture, +} from './exchange-oracle.fixtures'; describe('ExchangeOracleApiGateway', () => { let gateway: ExchangeOracleGateway; @@ -232,8 +232,8 @@ describe('ExchangeOracleApiGateway', () => { config: {}, } as AxiosResponse), ); - const command = jobsDiscoveryParamsCommandFixture; - const expectedMappedData: JobsDiscoveryParamsData = paramsDataFixture; + const command = fetchJobsCommandFixture; + const expectedMappedData: FetchJobsParamsData = paramsDataFixture; nock(jobAssignmentOracleUrl) .get(`/assignment${paramsDataFixtureAsString}`) .reply(200, responseFixture); diff --git a/packages/apps/human-app/server/src/integrations/kv-store/kv-store.gateway.ts b/packages/apps/human-app/server/src/integrations/kv-store/kv-store.gateway.ts index 492dc6ebdd..64176e72e3 100644 --- a/packages/apps/human-app/server/src/integrations/kv-store/kv-store.gateway.ts +++ b/packages/apps/human-app/server/src/integrations/kv-store/kv-store.gateway.ts @@ -65,7 +65,7 @@ export class KvStoreGateway { chainId: ChainId, address: string, ): Promise { - const key = `jobTypes:${address}`; + const key = `jobTypes:${chainId}:${address}`; const cachedData: string | undefined = await this.cacheManager.get(key); if (cachedData) { return cachedData; diff --git a/packages/apps/human-app/server/src/modules/cron-job/cron-job.service.ts b/packages/apps/human-app/server/src/modules/cron-job/cron-job.service.ts index 154173b4ae..549b1f1744 100644 --- a/packages/apps/human-app/server/src/modules/cron-job/cron-job.service.ts +++ b/packages/apps/human-app/server/src/modules/cron-job/cron-job.service.ts @@ -3,41 +3,51 @@ import { SchedulerRegistry } from '@nestjs/schedule'; import { AxiosError } from 'axios'; import { CronJob } from 'cron'; import { EnvironmentConfigService } from '../../common/config/environment-config.service'; -import { - JobDiscoveryFieldName, - JobStatus, -} from '../../common/enums/global-common'; +import { JobStatus } from '../../common/enums/global-common'; import * as errorUtils from '../../common/utils/error'; import { ExchangeOracleGateway } from '../../integrations/exchange-oracle/exchange-oracle.gateway'; +import { + FetchJobsCommand, + FetchJobsFieldName, + FetchJobsParams, + FetchJobsResponse, +} from '../../integrations/exchange-oracle/model/exchange-oracle.model'; import { ReputationOracleGateway } from '../../integrations/reputation-oracle/reputation-oracle.gateway'; import logger from '../../logger'; import { JobsDiscoveryService } from '../jobs-discovery/jobs-discovery.service'; -import { - DiscoveredJob, - JobsDiscoveryParams, - JobsDiscoveryParamsCommand, - JobsDiscoveryResponse, -} from '../jobs-discovery/model/jobs-discovery.model'; +import { DiscoveredJob } from '../jobs-discovery/model/jobs-discovery.model'; import { DiscoveredOracle } from '../oracle-discovery/model/oracle-discovery.model'; import { OracleDiscoveryService } from '../oracle-discovery/oracle-discovery.service'; -function assertJobsDiscoveryResponseItemsFormat( - items: JobsDiscoveryResponse['results'], +const DISCOVERED_JOB_REQUIRED_KEYS = [ + 'escrow_address', + 'chain_id', + 'job_type', + 'status', + 'job_description', + 'reward_amount', + 'reward_token', + 'created_at', +] as const; + +function assertDiscoveredJobsFormat( + items: FetchJobsResponse['results'], ): asserts items is DiscoveredJob[] { if (items.length === 0) { return; } - const item = items[0]; - if ( - [ - item.job_description, - item.reward_amount, - item.reward_token, - item.created_at, - ].includes(undefined) - ) { - throw new Error('Job discovery response items missing expected fields'); + const missingKeys: string[] = []; + for (const requiredKey of DISCOVERED_JOB_REQUIRED_KEYS) { + if (items[0][requiredKey] === undefined) { + missingKeys.push(requiredKey); + } + } + + if (missingKeys.length) { + throw new Error( + `Jobs response items missing expected fields: ${missingKeys.join()}`, + ); } } @@ -117,23 +127,23 @@ export class CronJobService { let allResults: DiscoveredJob[] = []; // Initial fetch to determine the total number of pages - const command = new JobsDiscoveryParamsCommand(); + const command = new FetchJobsCommand(); command.oracleAddress = oracle.address; command.token = token; - command.data = new JobsDiscoveryParams(); + command.data = new FetchJobsParams(); command.data.page = 0; - command.data.pageSize = command.data.pageSize || 10; // Max value for Exchange Oracle + command.data.pageSize = 10; // Max value for Exchange Oracle command.data.fields = [ - JobDiscoveryFieldName.JobDescription, - JobDiscoveryFieldName.RewardAmount, - JobDiscoveryFieldName.RewardToken, - JobDiscoveryFieldName.CreatedAt, + FetchJobsFieldName.JobDescription, + FetchJobsFieldName.RewardAmount, + FetchJobsFieldName.RewardToken, + FetchJobsFieldName.CreatedAt, ]; command.data.status = JobStatus.ACTIVE; const initialResponse = await this.exchangeOracleGateway.fetchJobs(command); - assertJobsDiscoveryResponseItemsFormat(initialResponse.results); + assertDiscoveredJobsFormat(initialResponse.results); allResults = this.mergeJobs(allResults, initialResponse.results); @@ -148,7 +158,7 @@ export class CronJobService { const remainingResponses = await Promise.all(pageFetches); for (const response of remainingResponses) { - assertJobsDiscoveryResponseItemsFormat(response.results); + assertDiscoveredJobsFormat(response.results); allResults = this.mergeJobs(allResults, response.results); } diff --git a/packages/apps/human-app/server/src/modules/cron-job/spec/cron-job.service.spec.ts b/packages/apps/human-app/server/src/modules/cron-job/spec/cron-job.service.spec.ts index d05258f95b..5b44372733 100644 --- a/packages/apps/human-app/server/src/modules/cron-job/spec/cron-job.service.spec.ts +++ b/packages/apps/human-app/server/src/modules/cron-job/spec/cron-job.service.spec.ts @@ -1,22 +1,22 @@ import { ChainId } from '@human-protocol/sdk'; import { SchedulerRegistry } from '@nestjs/schedule'; import { Test, TestingModule } from '@nestjs/testing'; -import { CronJobService } from '../cron-job.service'; -import { ExchangeOracleGateway } from '../../../integrations/exchange-oracle/exchange-oracle.gateway'; -import { ReputationOracleGateway } from '../../../integrations/reputation-oracle/reputation-oracle.gateway'; -import { OracleDiscoveryService } from '../../../modules/oracle-discovery/oracle-discovery.service'; import { EnvironmentConfigService } from '../../../common/config/environment-config.service'; -import { - DiscoveredJob, - JobsDiscoveryParamsCommand, - JobsDiscoveryResponse, - JobsDiscoveryResponseItem, -} from '../../../modules/jobs-discovery/model/jobs-discovery.model'; import { JobStatus } from '../../../common/enums/global-common'; +import { ExchangeOracleGateway } from '../../../integrations/exchange-oracle/exchange-oracle.gateway'; +import { ReputationOracleGateway } from '../../../integrations/reputation-oracle/reputation-oracle.gateway'; import { JobsDiscoveryService } from '../../../modules/jobs-discovery/jobs-discovery.service'; +import { DiscoveredJob } from '../../../modules/jobs-discovery/model/jobs-discovery.model'; +import { OracleDiscoveryService } from '../../../modules/oracle-discovery/oracle-discovery.service'; import { generateOracleDiscoveryResponseBody } from '../../../modules/oracle-discovery/spec/oracle-discovery.fixture'; +import { CronJobService } from '../cron-job.service'; import { HMT_TOKEN_SYMBOL } from '../../../common/constants/hmt'; +import { + FetchJobsCommand, + FetchJobsResponse, + FetchJobsResponseItem, +} from '../../../integrations/exchange-oracle/model/exchange-oracle.model'; jest.mock('cron', () => { return { @@ -174,7 +174,7 @@ describe('CronJobService', () => { it('should fetch all jobs and update the cache', async () => { const now = new Date(); - const initialResponse: JobsDiscoveryResponse = { + const initialResponse: FetchJobsResponse = { results: [ { escrow_address: '0xabc', @@ -201,7 +201,7 @@ describe('CronJobService', () => { await service.updateJobsListCache(oracle, token); expect(exchangeOracleGatewayMock.fetchJobs).toHaveBeenCalledWith( - expect.any(JobsDiscoveryParamsCommand), + expect.any(FetchJobsCommand), ); expect(jobDiscoveryServiceMock.setCachedJobs).toHaveBeenCalledWith( oracle.address, @@ -236,7 +236,7 @@ describe('CronJobService', () => { it('should reset retries count after successful job fetch', async () => { const now = new Date(); - const initialResponse: JobsDiscoveryResponse = { + const initialResponse: FetchJobsResponse = { results: [ { escrow_address: '0xabc', @@ -290,7 +290,7 @@ describe('CronJobService', () => { }, ]; - const newJobs: JobsDiscoveryResponseItem[] = [ + const newJobs: FetchJobsResponseItem[] = [ { escrow_address: '0xdef', chain_id: 1, @@ -329,7 +329,7 @@ describe('CronJobService', () => { qualifications: [], }, ]; - const newJobs: JobsDiscoveryResponseItem[] = [ + const newJobs: FetchJobsResponseItem[] = [ { escrow_address: '0xabc', chain_id: 1, diff --git a/packages/apps/human-app/server/src/modules/jobs-discovery/jobs-discovery.controller.ts b/packages/apps/human-app/server/src/modules/jobs-discovery/jobs-discovery.controller.ts index 50650861b6..993cf5e55b 100644 --- a/packages/apps/human-app/server/src/modules/jobs-discovery/jobs-discovery.controller.ts +++ b/packages/apps/human-app/server/src/modules/jobs-discovery/jobs-discovery.controller.ts @@ -18,9 +18,9 @@ import { EnvironmentConfigService } from '../../common/config/environment-config import { RequestWithUser } from '../../common/interfaces/jwt'; import { JobsDiscoveryService } from './jobs-discovery.service'; import { - JobsDiscoveryParamsCommand, - JobsDiscoveryParamsDto, - JobsDiscoveryResponse, + GetJobsCommand, + GetJobsQueryDto, + GetJobsResponseDto, } from './model/jobs-discovery.model'; @Controller() @@ -37,11 +37,11 @@ export class JobsDiscoveryController { @ApiOperation({ summary: 'Retrieve a list of jobs for given Exchange Oracle', }) - @ApiOkResponse({ type: JobsDiscoveryResponse, description: 'List of jobs' }) + @ApiOkResponse({ type: GetJobsResponseDto, description: 'List of jobs' }) public async getJobs( - @Query() jobsDiscoveryParamsDto: JobsDiscoveryParamsDto, + @Query() query: GetJobsQueryDto, @Request() req: RequestWithUser, - ): Promise { + ): Promise { if (!this.environmentConfigService.jobsDiscoveryFlag) { throw new HttpException( 'Jobs discovery is disabled', @@ -49,14 +49,12 @@ export class JobsDiscoveryController { ); } - const jobsDiscoveryParamsCommand: JobsDiscoveryParamsCommand = - this.mapper.map( - jobsDiscoveryParamsDto, - JobsDiscoveryParamsDto, - JobsDiscoveryParamsCommand, - ); - jobsDiscoveryParamsCommand.token = req.token; - jobsDiscoveryParamsCommand.data.qualifications = req.user.qualifications; - return await this.service.processJobsDiscovery(jobsDiscoveryParamsCommand); + const getJobsCommand: GetJobsCommand = this.mapper.map( + query, + GetJobsQueryDto, + GetJobsCommand, + ); + getJobsCommand.data.qualifications = req.user.qualifications; + return await this.service.getJobs(getJobsCommand); } } diff --git a/packages/apps/human-app/server/src/modules/jobs-discovery/jobs-discovery.mapper.profile.ts b/packages/apps/human-app/server/src/modules/jobs-discovery/jobs-discovery.mapper.profile.ts index cab001c971..ca417f7782 100644 --- a/packages/apps/human-app/server/src/modules/jobs-discovery/jobs-discovery.mapper.profile.ts +++ b/packages/apps/human-app/server/src/modules/jobs-discovery/jobs-discovery.mapper.profile.ts @@ -1,5 +1,3 @@ -import { AutomapperProfile, InjectMapper } from '@automapper/nestjs'; -import { Injectable } from '@nestjs/common'; import { CamelCaseNamingConvention, createMap, @@ -9,10 +7,12 @@ import { namingConventions, SnakeCaseNamingConvention, } from '@automapper/core'; +import { AutomapperProfile, InjectMapper } from '@automapper/nestjs'; +import { Injectable } from '@nestjs/common'; import { - JobsDiscoveryParams, - JobsDiscoveryParamsCommand, - JobsDiscoveryParamsDto, + GetJobsCommand, + GetJobsParams, + GetJobsQueryDto, } from './model/jobs-discovery.model'; @Injectable() @@ -25,8 +25,8 @@ export class JobsDiscoveryProfile extends AutomapperProfile { return (mapper: Mapper) => { createMap( mapper, - JobsDiscoveryParamsDto, - JobsDiscoveryParams, + GetJobsQueryDto, + GetJobsParams, // forMember usage cause: https://github.com/nartc/mapper/issues/583 forMember( (destination) => destination.pageSize, @@ -36,11 +36,6 @@ export class JobsDiscoveryProfile extends AutomapperProfile { (destination) => destination.sortField, mapFrom((source) => source.sort_field), ), - // Automapper has problem with mapping arrays, thus explicit conversion - forMember( - (destination) => destination.fields, - mapFrom((source) => source.fields), - ), namingConventions({ source: new SnakeCaseNamingConvention(), destination: new CamelCaseNamingConvention(), @@ -48,12 +43,12 @@ export class JobsDiscoveryProfile extends AutomapperProfile { ); createMap( mapper, - JobsDiscoveryParamsDto, - JobsDiscoveryParamsCommand, + GetJobsQueryDto, + GetJobsCommand, forMember( (destination) => destination.data, - mapFrom((source: JobsDiscoveryParamsDto) => - mapper.map(source, JobsDiscoveryParamsDto, JobsDiscoveryParams), + mapFrom((source: GetJobsQueryDto) => + mapper.map(source, GetJobsQueryDto, GetJobsParams), ), ), namingConventions({ diff --git a/packages/apps/human-app/server/src/modules/jobs-discovery/jobs-discovery.module.ts b/packages/apps/human-app/server/src/modules/jobs-discovery/jobs-discovery.module.ts index 1117c638e3..1888fec479 100644 --- a/packages/apps/human-app/server/src/modules/jobs-discovery/jobs-discovery.module.ts +++ b/packages/apps/human-app/server/src/modules/jobs-discovery/jobs-discovery.module.ts @@ -1,7 +1,7 @@ -import { JobsDiscoveryService } from './jobs-discovery.service'; -import { JobsDiscoveryProfile } from './jobs-discovery.mapper.profile'; import { Module } from '@nestjs/common'; import { ExchangeOracleModule } from '../../integrations/exchange-oracle/exchange-oracle.module'; +import { JobsDiscoveryProfile } from './jobs-discovery.mapper.profile'; +import { JobsDiscoveryService } from './jobs-discovery.service'; @Module({ imports: [ExchangeOracleModule], diff --git a/packages/apps/human-app/server/src/modules/jobs-discovery/jobs-discovery.service.ts b/packages/apps/human-app/server/src/modules/jobs-discovery/jobs-discovery.service.ts index ee87a582cb..83e5b194f8 100644 --- a/packages/apps/human-app/server/src/modules/jobs-discovery/jobs-discovery.service.ts +++ b/packages/apps/human-app/server/src/modules/jobs-discovery/jobs-discovery.service.ts @@ -1,21 +1,18 @@ +import { CACHE_MANAGER } from '@nestjs/cache-manager'; import { Inject, Injectable } from '@nestjs/common'; +import { Cache } from 'cache-manager'; +import { EnvironmentConfigService } from '../../common/config/environment-config.service'; +import { JOB_DISCOVERY_CACHE_KEY } from '../../common/constants/cache'; import { Iteratee, paginateAndSortResults, } from '../../common/utils/pagination.utils'; import { DiscoveredJob, - JobsDiscoveryParamsCommand, - JobsDiscoveryResponse, -} from './model/jobs-discovery.model'; -import { CACHE_MANAGER } from '@nestjs/cache-manager'; -import { Cache } from 'cache-manager'; -import { EnvironmentConfigService } from '../../common/config/environment-config.service'; -import { JOB_DISCOVERY_CACHE_KEY } from '../../common/constants/cache'; -import { - JobDiscoveryFieldName, + GetJobsCommand, + GetJobsResponseDto, JobDiscoverySortField, -} from '../../common/enums/global-common'; +} from './model/jobs-discovery.model'; @Injectable() export class JobsDiscoveryService { @@ -24,9 +21,7 @@ export class JobsDiscoveryService { private configService: EnvironmentConfigService, ) {} - async processJobsDiscovery( - command: JobsDiscoveryParamsCommand, - ): Promise { + async getJobs(command: GetJobsCommand): Promise { const allJobs = await this.getCachedJobs(command.oracleAddress); let filteredJobs = this.applyFilters(allJobs, command.data); filteredJobs = filteredJobs.filter((job) => @@ -58,58 +53,46 @@ export class JobsDiscoveryService { private applyFilters( jobs: DiscoveredJob[], - filters: JobsDiscoveryParamsCommand['data'], + filters: GetJobsCommand['data'], ): DiscoveredJob[] { - const difference = Object.values(JobDiscoveryFieldName).filter( - (value) => !filters.fields?.includes(value), - ); - return jobs - .filter((job) => { - let matches = true; - - if (filters.escrowAddress) { - matches = matches && job.escrow_address === filters.escrowAddress; - } - - if (filters.chainId !== undefined && filters.chainId !== null) { - matches = matches && job.chain_id === filters.chainId; - } - - if (filters.jobType) { - matches = matches && job.job_type === filters.jobType; + return jobs.filter((job) => { + let matches = true; + + if (filters.escrowAddress) { + matches = matches && job.escrow_address === filters.escrowAddress; + } + + if (filters.chainId !== undefined && filters.chainId !== null) { + matches = matches && job.chain_id === filters.chainId; + } + + if (filters.jobType) { + matches = matches && job.job_type === filters.jobType; + } + + if (filters.status !== undefined && filters.status !== null) { + matches = matches && job.status === filters.status; + } + + if ( + filters.qualifications !== undefined && + filters.qualifications !== null + ) { + if (job.qualifications && job.qualifications.length > 0) { + matches = + matches && + job.qualifications.every((qualification) => + filters.qualifications?.includes(qualification), + ); } + } - if (filters.status !== undefined && filters.status !== null) { - matches = matches && job.status === filters.status; - } - - if ( - filters.qualifications !== undefined && - filters.qualifications !== null - ) { - if (job.qualifications && job.qualifications.length > 0) { - matches = - matches && - job.qualifications.every((qualification) => - filters.qualifications?.includes(qualification), - ); - } - } - - return matches; - }) - .map((job) => { - if (difference && difference.length > 0) { - difference.forEach((field) => { - delete job[field]; - }); - } - return job; - }); + return matches; + }); } static makeCacheKeyForOracle(oracleAddress: string): string { - return `${JOB_DISCOVERY_CACHE_KEY}:${oracleAddress}`; + return `${JOB_DISCOVERY_CACHE_KEY}:${oracleAddress.toLowerCase()}`; } async getCachedJobs(oracleAddress: string): Promise { diff --git a/packages/apps/human-app/server/src/modules/jobs-discovery/model/jobs-discovery.model.ts b/packages/apps/human-app/server/src/modules/jobs-discovery/model/jobs-discovery.model.ts index cc63a65da0..8d3a75ca66 100644 --- a/packages/apps/human-app/server/src/modules/jobs-discovery/model/jobs-discovery.model.ts +++ b/packages/apps/human-app/server/src/modules/jobs-discovery/model/jobs-discovery.model.ts @@ -1,115 +1,122 @@ -import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { AutoMap } from '@automapper/classes'; -import { IsNumber, IsOptional, IsString } from 'class-validator'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Type } from 'class-transformer'; +import { IsNumber, IsOptional, IsString } from 'class-validator'; +import { IsEnumCaseInsensitive } from '../../../common/decorators'; +import { JobStatus } from '../../../common/enums/global-common'; import { - JobDiscoveryFieldName, - JobDiscoverySortField, - JobStatus, -} from '../../../common/enums/global-common'; -import { - PageableData, PageableDto, PageableParams, PageableResponse, } from '../../../common/utils/pageable.model'; -import { IsEnumCaseInsensitive } from '../../../common/decorators'; +import { FetchJobsResponseItem } from '../../../integrations/exchange-oracle/model/exchange-oracle.model'; + +export enum JobDiscoverySortField { + REWARD_AMOUNT = 'reward_amount', + CREATED_AT = 'created_at', +} -export class JobsDiscoveryParamsDto extends PageableDto { +export class GetJobsQueryDto extends PageableDto { @AutoMap() @IsString() @ApiProperty() - oracle_address?: string; + oracle_address: string; + @AutoMap() @IsOptional() @IsString() @ApiPropertyOptional() escrow_address?: string; + @AutoMap() @Type(() => Number) @IsNumber() @IsOptional() @ApiPropertyOptional() chain_id?: number; - @AutoMap() - @IsOptional() - @IsEnumCaseInsensitive(JobDiscoverySortField) - @ApiPropertyOptional({ enum: JobDiscoverySortField }) - sort_field?: JobDiscoverySortField; + @AutoMap() @IsString() @IsOptional() @ApiPropertyOptional() job_type?: string; - @AutoMap() - @IsOptional() - @IsEnumCaseInsensitive(JobDiscoveryFieldName, { each: true }) - @ApiPropertyOptional({ enum: JobDiscoveryFieldName, isArray: true }) - fields: JobDiscoveryFieldName[]; + @AutoMap() @ApiPropertyOptional({ enum: JobStatus }) @IsEnumCaseInsensitive(JobStatus) @IsOptional() status: JobStatus; + + @AutoMap() + @IsOptional() + @IsEnumCaseInsensitive(JobDiscoverySortField) + @ApiPropertyOptional({ enum: JobDiscoverySortField }) + sort_field?: JobDiscoverySortField; } -export class JobsDiscoveryParams extends PageableParams { +export class GetJobsParams extends PageableParams { @AutoMap() escrowAddress?: string; + @AutoMap() chainId?: number; - @AutoMap() - sortField?: JobDiscoverySortField; + @AutoMap() jobType?: string; - @AutoMap() - fields: JobDiscoveryFieldName[]; + @AutoMap() status: JobStatus; + @AutoMap() - updatedAfter?: string; + sortField?: JobDiscoverySortField; + qualifications?: string[]; } -export class JobsDiscoveryParamsData extends PageableData { - @AutoMap() - escrow_address?: string; - @AutoMap() - chain_id?: number; - @AutoMap() - sort_field?: JobDiscoverySortField; - @AutoMap() - job_type?: string; - @AutoMap() - fields: JobDiscoveryFieldName[]; - @AutoMap() - status: JobStatus; - @AutoMap() - updated_after?: string; -} -export class JobsDiscoveryParamsCommand { + +export class GetJobsCommand { @AutoMap() oracleAddress: string; + @AutoMap() - token: string; - @AutoMap() - data: JobsDiscoveryParams; + data: GetJobsParams; } -export type JobsDiscoveryResponseItem = { +export class DiscoveredJob implements Required { + @ApiProperty() escrow_address: string; + + @ApiProperty() chain_id: number; + + @ApiProperty() job_type: string; + + @ApiProperty() status: JobStatus; - job_description?: string; - reward_amount?: string; - reward_token?: string; - created_at?: string; - updated_at?: string; - qualifications: string[]; -}; -export class JobsDiscoveryResponse extends PageableResponse { - results: JobsDiscoveryResponseItem[]; + @ApiProperty() + job_description: string; + + @ApiProperty() + reward_amount: string; + + @ApiProperty() + reward_token: string; + + @ApiProperty() + created_at: string; + + @ApiProperty() + updated_at: string; + + @ApiProperty() + qualifications: string[]; } -export type DiscoveredJob = Required; +export class GetJobsResponseDto extends PageableResponse { + @ApiProperty({ + type: DiscoveredJob, + isArray: true, + }) + results: DiscoveredJob[]; +} diff --git a/packages/apps/human-app/server/src/modules/jobs-discovery/spec/jobs-discovery.controller.spec.ts b/packages/apps/human-app/server/src/modules/jobs-discovery/spec/jobs-discovery.controller.spec.ts index c1780290c0..c6a6f66e17 100644 --- a/packages/apps/human-app/server/src/modules/jobs-discovery/spec/jobs-discovery.controller.spec.ts +++ b/packages/apps/human-app/server/src/modules/jobs-discovery/spec/jobs-discovery.controller.spec.ts @@ -11,8 +11,8 @@ import { JobsDiscoveryController } from '../jobs-discovery.controller'; import { JobsDiscoveryProfile } from '../jobs-discovery.mapper.profile'; import { JobsDiscoveryService } from '../jobs-discovery.service'; import { - dtoFixture, - jobsDiscoveryParamsCommandFixture, + queryDtoFixture, + getJobsCommandFixture, responseFixture, } from './jobs-discovery.fixtures'; import { jobsDiscoveryServiceMock } from './jobs-discovery.service.mock'; @@ -68,22 +68,19 @@ describe('JobsDiscoveryController', () => { expect(controller).toBeDefined(); }); - describe('processJobsDiscovery', () => { - it('should call service processJobsDiscovery method with proper fields set', async () => { - const dto = dtoFixture; - const command = jobsDiscoveryParamsCommandFixture; + describe('getJobs', () => { + it('should call service getJobs method with proper fields set', async () => { + const dto = queryDtoFixture; + const command = getJobsCommandFixture; await controller.getJobs(dto, { user: { qualifications: [] }, - token: command.token, } as any); command.data.qualifications = []; - expect(jobsDiscoveryService.processJobsDiscovery).toHaveBeenCalledWith( - command, - ); + expect(jobsDiscoveryService.getJobs).toHaveBeenCalledWith(command); }); it('should throw an error if jobsDiscoveryFlag is disabled', async () => { - const dto = dtoFixture; + const dto = queryDtoFixture; (configServiceMock as any).jobsDiscoveryFlag = false; await expect( controller.getJobs(dto, { user: { qualifications: [] } } as any), diff --git a/packages/apps/human-app/server/src/modules/jobs-discovery/spec/jobs-discovery.fixtures.ts b/packages/apps/human-app/server/src/modules/jobs-discovery/spec/jobs-discovery.fixtures.ts index bdd0b0fcb6..2ab227433a 100644 --- a/packages/apps/human-app/server/src/modules/jobs-discovery/spec/jobs-discovery.fixtures.ts +++ b/packages/apps/human-app/server/src/modules/jobs-discovery/spec/jobs-discovery.fixtures.ts @@ -1,20 +1,12 @@ import { - JobsDiscoveryParams, - JobsDiscoveryParamsCommand, - JobsDiscoveryParamsData, - JobsDiscoveryParamsDto, - JobsDiscoveryResponse, - JobsDiscoveryResponseItem, + GetJobsCommand, + GetJobsQueryDto, + GetJobsResponseDto, DiscoveredJob, -} from '../model/jobs-discovery.model'; -import { - JobDiscoveryFieldName, JobDiscoverySortField, - JobStatus, - SortOrder, -} from '../../../common/enums/global-common'; +} from '../model/jobs-discovery.model'; +import { JobStatus, SortOrder } from '../../../common/enums/global-common'; -const EXCHANGE_ORACLE_URL = 'https://www.test_url.org'; const ESCROW_ADDRESS1 = 'test_address1'; const ESCROW_ADDRESS2 = 'test_address2'; const ESCROW_ADDRESS3 = 'test_address3'; @@ -29,78 +21,68 @@ const TOTAL_PAGES = 4; const SORT = SortOrder.ASC; const SORT_FIELD = JobDiscoverySortField.CREATED_AT; const JOB_TYPE = 'FORTUNE'; -const FIELDS = [ - JobDiscoveryFieldName.CreatedAt, - JobDiscoveryFieldName.JobDescription, -]; -const TOKEN = 'test-token'; const EXCHANGE_ORACLE_ADDRESS = '0x3dfa342'; const STATUS = JobStatus.ACTIVE; -export const jobsDiscoveryOracleUrlFixture = EXCHANGE_ORACLE_URL; -export const jobDiscoveryToken = TOKEN; -export const dtoFixture: JobsDiscoveryParamsDto = { - oracle_address: EXCHANGE_ORACLE_ADDRESS, - chain_id: CHAIN_ID, - page_size: PAGE_SIZE, - page: PAGE, - sort: SORT, - sort_field: SORT_FIELD, - job_type: JOB_TYPE, - fields: FIELDS, - status: STATUS, -}; -const dataFixture: JobsDiscoveryParams = { - chainId: CHAIN_ID, - pageSize: PAGE_SIZE, - page: PAGE, - sort: SORT, - sortField: SORT_FIELD, - jobType: JOB_TYPE, - fields: FIELDS, - status: STATUS, -}; -export const paramsDataFixture: JobsDiscoveryParamsData = { +export const queryDtoFixture: GetJobsQueryDto = { + oracle_address: EXCHANGE_ORACLE_ADDRESS, chain_id: CHAIN_ID, page_size: PAGE_SIZE, page: PAGE, sort: SORT, sort_field: SORT_FIELD, job_type: JOB_TYPE, - fields: FIELDS, status: STATUS, }; -export const paramsDataFixtureAsString = `?escrow_address=${paramsDataFixture.escrow_address}&chain_id=${paramsDataFixture.chain_id}&page_size=${paramsDataFixture.page_size}&page=${paramsDataFixture.page}&sort=${paramsDataFixture.sort}&sort_field=${paramsDataFixture.sort_field}&job_type=${paramsDataFixture.job_type}&fields=${paramsDataFixture.fields.join(',')}`; -export const jobsDiscoveryParamsCommandFixture: JobsDiscoveryParamsCommand = { - data: dataFixture, +export const getJobsCommandFixture: GetJobsCommand = { + data: { + chainId: CHAIN_ID, + pageSize: PAGE_SIZE, + page: PAGE, + sort: SORT, + sortField: SORT_FIELD, + jobType: JOB_TYPE, + status: STATUS, + }, oracleAddress: EXCHANGE_ORACLE_ADDRESS, - token: TOKEN, }; -export const responseItemFixture1: JobsDiscoveryResponseItem = { +export const responseItemFixture1: DiscoveredJob = { escrow_address: ESCROW_ADDRESS1, chain_id: CHAIN_ID, job_type: JOB_TYPE, status: JobStatus.ACTIVE, created_at: '2025-03-18T03:00:00.000Z', qualifications: [], + job_description: 'Response item fixture 1 description', + reward_amount: '42.1', + reward_token: 'hmt', + updated_at: '2025-03-18T03:00:00.000Z', }; -export const responseItemFixture2: JobsDiscoveryResponseItem = { +export const responseItemFixture2: DiscoveredJob = { escrow_address: ESCROW_ADDRESS2, chain_id: CHAIN_ID, job_type: JOB_TYPE, status: JobStatus.COMPLETED, created_at: '2025-03-18T02:00:00.000Z', qualifications: [], + job_description: 'Response item fixture 2 description', + reward_amount: '42.2', + reward_token: 'hmt', + updated_at: '2025-03-18T02:00:00.000Z', }; -export const responseItemFixture3: JobsDiscoveryResponseItem = { +export const responseItemFixture3: DiscoveredJob = { escrow_address: ESCROW_ADDRESS3, chain_id: CHAIN_ID, job_type: JOB_TYPE, status: JobStatus.ACTIVE, created_at: '2025-03-18T01:00:00.000Z', qualifications: [], + job_description: 'Response item fixture 3 description', + reward_amount: '42.3', + reward_token: 'hmt', + updated_at: '2025-03-18T01:00:00.000Z', }; -export const responseItemsFixture: JobsDiscoveryResponseItem[] = [ +export const responseItemsFixture: DiscoveredJob[] = [ responseItemFixture1, responseItemFixture2, responseItemFixture3, @@ -141,7 +123,7 @@ export const validRewardAmountResponseItemFixture: DiscoveredJob = { reward_token: REWARD_TOKEN_HMT, updated_at: '2025-03-18T01:00:00.000Z', }; -export const responseFixture: JobsDiscoveryResponse = { +export const responseFixture: GetJobsResponseDto = { results: responseItemsFixture, page: PAGE, page_size: PAGE_SIZE, diff --git a/packages/apps/human-app/server/src/modules/jobs-discovery/spec/jobs-discovery.service.mock.ts b/packages/apps/human-app/server/src/modules/jobs-discovery/spec/jobs-discovery.service.mock.ts index b16d952239..d6ac491a58 100644 --- a/packages/apps/human-app/server/src/modules/jobs-discovery/spec/jobs-discovery.service.mock.ts +++ b/packages/apps/human-app/server/src/modules/jobs-discovery/spec/jobs-discovery.service.mock.ts @@ -1,5 +1,5 @@ import { responseFixture } from './jobs-discovery.fixtures'; export const jobsDiscoveryServiceMock = { - processJobsDiscovery: jest.fn().mockReturnValue(responseFixture), + getJobs: jest.fn().mockReturnValue(responseFixture), }; diff --git a/packages/apps/human-app/server/src/modules/jobs-discovery/spec/jobs-discovery.service.spec.ts b/packages/apps/human-app/server/src/modules/jobs-discovery/spec/jobs-discovery.service.spec.ts index d3d45b6cff..1bd81a9920 100644 --- a/packages/apps/human-app/server/src/modules/jobs-discovery/spec/jobs-discovery.service.spec.ts +++ b/packages/apps/human-app/server/src/modules/jobs-discovery/spec/jobs-discovery.service.spec.ts @@ -1,24 +1,21 @@ import { ChainId } from '@human-protocol/sdk'; import { CACHE_MANAGER } from '@nestjs/cache-manager'; -import { JobsDiscoveryService } from '../jobs-discovery.service'; -import { ExchangeOracleGateway } from '../../../integrations/exchange-oracle/exchange-oracle.gateway'; import { Test, TestingModule } from '@nestjs/testing'; +import { EnvironmentConfigService } from '../../../common/config/environment-config.service'; +import { SortOrder } from '../../../common/enums/global-common'; +import { ExchangeOracleGateway } from '../../../integrations/exchange-oracle/exchange-oracle.gateway'; +import { JobsDiscoveryService } from '../jobs-discovery.service'; import { hmtRewardAmountResponseItemFixture, invalidRewardAmountResponseItemFixture, - jobsDiscoveryParamsCommandFixture, - responseItemsFixture, + getJobsCommandFixture, responseItemFixture1, responseItemFixture3, + responseItemsFixture, usdcRewardAmountResponseItemFixture, validRewardAmountResponseItemFixture, } from './jobs-discovery.fixtures'; -import { EnvironmentConfigService } from '../../../common/config/environment-config.service'; -import { - JobDiscoveryFieldName, - JobDiscoverySortField, - SortOrder, -} from '../../../common/enums/global-common'; +import { JobDiscoverySortField } from '../model/jobs-discovery.model'; describe('JobsDiscoveryService', () => { let service: JobsDiscoveryService; @@ -51,20 +48,23 @@ describe('JobsDiscoveryService', () => { service = module.get(JobsDiscoveryService); }); + it('should be defined', () => { expect(service).toBeDefined(); }); - describe('processJobsDiscovery', () => { + + describe('getJobs', () => { it('should get oracle url and call api for jobs fetch', async () => { - const command = jobsDiscoveryParamsCommandFixture; + const command = getJobsCommandFixture; jest .spyOn(service as any, 'getCachedJobs') .mockReturnValue(responseItemsFixture); - const result = await service.processJobsDiscovery(command); + const result = await service.getJobs(command); + expect(service.getCachedJobs).toHaveBeenCalledWith( - jobsDiscoveryParamsCommandFixture.oracleAddress, + getJobsCommandFixture.oracleAddress, ); expect(result.results).toEqual([ responseItemFixture3, @@ -74,13 +74,9 @@ describe('JobsDiscoveryService', () => { it('should sort reward amounts using human-readable units', async () => { const command = { - ...jobsDiscoveryParamsCommandFixture, + ...getJobsCommandFixture, data: { - ...jobsDiscoveryParamsCommandFixture.data, - fields: [ - JobDiscoveryFieldName.RewardAmount, - JobDiscoveryFieldName.RewardToken, - ], + ...getJobsCommandFixture.data, sort: SortOrder.DESC, sortField: JobDiscoverySortField.REWARD_AMOUNT, }, @@ -93,7 +89,7 @@ describe('JobsDiscoveryService', () => { usdcRewardAmountResponseItemFixture, ]); - const result = await service.processJobsDiscovery(command); + const result = await service.getJobs(command); expect(result.results).toEqual([ usdcRewardAmountResponseItemFixture, @@ -103,13 +99,9 @@ describe('JobsDiscoveryService', () => { it('should use zero for invalid reward amounts', async () => { const command = { - ...jobsDiscoveryParamsCommandFixture, + ...getJobsCommandFixture, data: { - ...jobsDiscoveryParamsCommandFixture.data, - fields: [ - JobDiscoveryFieldName.RewardAmount, - JobDiscoveryFieldName.RewardToken, - ], + ...getJobsCommandFixture.data, sort: SortOrder.DESC, sortField: JobDiscoverySortField.REWARD_AMOUNT, }, @@ -122,7 +114,7 @@ describe('JobsDiscoveryService', () => { validRewardAmountResponseItemFixture, ]); - const result = await service.processJobsDiscovery(command); + const result = await service.getJobs(command); expect(result.results).toEqual([ validRewardAmountResponseItemFixture, diff --git a/packages/apps/human-app/server/src/modules/oracle-discovery/model/oracle-discovery.model.ts b/packages/apps/human-app/server/src/modules/oracle-discovery/model/oracle-discovery.model.ts index e8914a8d7e..683fe9974f 100644 --- a/packages/apps/human-app/server/src/modules/oracle-discovery/model/oracle-discovery.model.ts +++ b/packages/apps/human-app/server/src/modules/oracle-discovery/model/oracle-discovery.model.ts @@ -2,7 +2,7 @@ import { ChainId } from '@human-protocol/sdk'; import { AutoMap } from '@automapper/classes'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { IsArray, IsOptional } from 'class-validator'; -import { Exclude, Transform } from 'class-transformer'; +import { Transform } from 'class-transformer'; type DiscoveredOracleCreateProps = { id: string; @@ -29,89 +29,28 @@ type DiscoveredOracleCreateProps = { }; export class DiscoveredOracle { - @ApiProperty({ description: 'Unique identifier of the oracle operator' }) id: string; - - @ApiProperty({ description: 'Address of the oracle operator' }) address: string; - - @ApiProperty({ description: 'Chain ID where the oracle is registered' }) chainId: ChainId; - - @ApiPropertyOptional({ description: 'Amount staked by the operator' }) stakedAmount?: string; - - @ApiPropertyOptional({ - description: 'Amount currently locked by the operator', - }) lockedAmount?: string; - - @ApiPropertyOptional({ description: 'Timestamp until funds are locked' }) lockedUntilTimestamp?: string; - - @ApiPropertyOptional({ - description: 'Total amount withdrawn by the operator', - }) withdrawnAmount?: string; - - @ApiPropertyOptional({ - description: 'Total amount slashed from the operator', - }) slashedAmount?: string; - - @ApiPropertyOptional({ - description: 'Number of jobs processed by the operator', - }) amountJobsProcessed?: string; - - @ApiPropertyOptional({ description: 'Fee charged by the operator' }) fee?: string; - - @ApiPropertyOptional({ description: 'Public key of the operator' }) publicKey?: string; - - @ApiPropertyOptional({ description: 'Webhook URL of the operator' }) webhookUrl?: string; - - @ApiPropertyOptional({ description: 'Website of the operator' }) website?: string; - - @ApiProperty({ description: 'URL of the oracle operator' }) url: string; - - @ApiProperty({ description: 'Role of the oracle operator' }) role: string; - - @ApiPropertyOptional({ - type: [String], - description: 'Types of jobs the oracle supports', - }) jobTypes: string[]; - - @ApiPropertyOptional({ description: 'Indicates if registration is needed' }) registrationNeeded?: boolean; - - @ApiPropertyOptional({ - description: 'Instructions for registration, if needed', - }) registrationInstructions?: string; - - @ApiPropertyOptional({ - type: [String], - description: 'Reputation networks the operator belongs to', - }) reputationNetworks?: string[]; - - @ApiProperty({ description: 'Name of the operator' }) name: string; - - @ApiPropertyOptional({ description: 'Category of the operator' }) category?: string; - - @Exclude() retriesCount = 0; - - @Exclude() executionsToSkip = 0; constructor(props: DiscoveredOracleCreateProps) { @@ -152,3 +91,52 @@ export class GetOraclesCommand { @Transform(({ value }) => (Array.isArray(value) ? value : [value])) selectedJobTypes?: string[]; } + +export class GetOraclesResponseItem { + @ApiProperty({ description: 'Unique identifier of the oracle operator' }) + id: string; + + @ApiProperty({ description: 'Address of the oracle operator' }) + address: string; + + @ApiProperty({ description: 'Chain ID where the oracle is registered' }) + chainId: ChainId; + + @ApiProperty({ description: 'Role of the oracle operator' }) + role: string; + + @ApiProperty({ description: 'URL of the oracle operator' }) + url: string; + + @ApiPropertyOptional({ + type: [String], + description: 'Types of jobs the oracle supports', + }) + jobTypes: string[]; + + @ApiPropertyOptional({ description: 'Indicates if registration is needed' }) + registrationNeeded?: boolean; + + @ApiPropertyOptional({ + description: 'Instructions for registration, if needed', + }) + registrationInstructions?: string; + + @ApiProperty({ description: 'Name of the operator' }) + name: string; + + @ApiPropertyOptional({ description: 'Category of the operator' }) + category?: string; + + @ApiProperty() + nTasks: number; + + @ApiProperty() + minRewardAmount: string; + + @ApiProperty() + maxRewardAmount: string; + + @ApiProperty() + rewardToken: string; +} diff --git a/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.controller.ts b/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.controller.ts index 5adaa96875..02bfad380b 100644 --- a/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.controller.ts +++ b/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.controller.ts @@ -16,11 +16,12 @@ import { } from '@nestjs/swagger'; import { EnvironmentConfigService } from '../../common/config/environment-config.service'; import { - DiscoveredOracle, + GetOraclesResponseItem, GetOraclesCommand, GetOraclesQuery, } from './model/oracle-discovery.model'; import { OracleDiscoveryService } from './oracle-discovery.service'; +import { JobsDiscoveryService } from '../jobs-discovery/jobs-discovery.service'; @ApiTags('Oracle-Discovery') @ApiBearerAuth() @@ -29,19 +30,20 @@ export class OracleDiscoveryController { constructor( private readonly oracleDiscoveryService: OracleDiscoveryService, private readonly environmentConfigService: EnvironmentConfigService, + private readonly jobsDiscoveryService: JobsDiscoveryService, @InjectMapper() private readonly mapper: Mapper, ) {} @ApiOperation({ summary: 'Oracles discovery' }) @ApiOkResponse({ - type: Array, + type: Array, description: 'List of oracles', }) @Header('Cache-Control', 'private, max-age=60') @Get('/oracles') public async getOracles( @Query() query: GetOraclesQuery, - ): Promise { + ): Promise { if (!this.environmentConfigService.jobsDiscoveryFlag) { throw new HttpException( 'Oracles discovery is disabled', @@ -51,6 +53,46 @@ export class OracleDiscoveryController { const command = this.mapper.map(query, GetOraclesQuery, GetOraclesCommand); const oracles = await this.oracleDiscoveryService.getOracles(command); - return oracles; + const responseItems: GetOraclesResponseItem[] = []; + for (const oracle of oracles) { + const oracleJobs = await this.jobsDiscoveryService.getCachedJobs( + oracle.address, + ); + + let rewardToken: string; + let minRewardAmount: number; + let maxRewardAmount: number; + if (oracleJobs.length) { + rewardToken = oracleJobs[0].reward_token; + minRewardAmount = Number.MAX_VALUE; + maxRewardAmount = Number.MIN_VALUE; + + for (const oracleJob of oracleJobs) { + const jobRewardAmount = Number(oracleJob.reward_amount); + minRewardAmount = Math.min(minRewardAmount, jobRewardAmount); + maxRewardAmount = Math.max(maxRewardAmount, jobRewardAmount); + } + } else { + rewardToken = 'HMT'; + minRewardAmount = 0; + maxRewardAmount = 0; + } + + responseItems.push({ + id: oracle.id, + address: oracle.address, + chainId: oracle.chainId, + role: oracle.role, + url: oracle.url, + jobTypes: oracle.jobTypes, + name: oracle.name, + nTasks: oracleJobs.length, + minRewardAmount: minRewardAmount.toString(), + maxRewardAmount: maxRewardAmount.toString(), + rewardToken, + }); + } + + return responseItems; } } diff --git a/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.module.ts b/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.module.ts index 67b8eb8f6d..6c470714b4 100644 --- a/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.module.ts +++ b/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.module.ts @@ -2,9 +2,10 @@ import { Module } from '@nestjs/common'; import { OracleDiscoveryService } from './oracle-discovery.service'; import { OracleDiscoveryProfile } from './oracle-discovery.mapper.profile'; import { KvStoreModule } from '../../integrations/kv-store/kv-store.module'; +import { JobsDiscoveryModule } from '../jobs-discovery/jobs-discovery.module'; @Module({ - imports: [KvStoreModule], + imports: [JobsDiscoveryModule, KvStoreModule], providers: [OracleDiscoveryService, OracleDiscoveryProfile], exports: [OracleDiscoveryService], }) diff --git a/packages/apps/human-app/server/src/modules/oracle-discovery/spec/oracle-discovery.controller.spec.ts b/packages/apps/human-app/server/src/modules/oracle-discovery/spec/oracle-discovery.controller.spec.ts deleted file mode 100644 index 58df22e460..0000000000 --- a/packages/apps/human-app/server/src/modules/oracle-discovery/spec/oracle-discovery.controller.spec.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { AutomapperModule } from '@automapper/nestjs'; -import { classes } from '@automapper/classes'; -import { OracleDiscoveryController } from '../oracle-discovery.controller'; -import { OracleDiscoveryService } from '../oracle-discovery.service'; -import { oracleDiscoveryServiceMock } from './oracle-discovery.service.mock'; -import { - GetOraclesQuery, - DiscoveredOracle, -} from '../model/oracle-discovery.model'; -import { generateOracleDiscoveryResponseBody } from './oracle-discovery.fixture'; -import { OracleDiscoveryProfile } from '../oracle-discovery.mapper.profile'; -import { EnvironmentConfigService } from '../../../common/config/environment-config.service'; -import { CommonConfigModule } from '../../../common/config/common-config.module'; -import { ConfigModule } from '@nestjs/config'; -import { HttpException, HttpStatus } from '@nestjs/common'; -import { ChainId } from '@human-protocol/sdk'; - -describe('OracleDiscoveryController', () => { - let controller: OracleDiscoveryController; - let serviceMock: OracleDiscoveryService; - const configServiceMock: Partial = { - cacheTtlOracleDiscovery: 600, - chainIdsEnabled: [ChainId.POLYGON, ChainId.MAINNET], - jobsDiscoveryFlag: true, - }; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [OracleDiscoveryController], - imports: [ - AutomapperModule.forRoot({ - strategyInitializer: classes(), - }), - CommonConfigModule, - ConfigModule.forRoot({ - envFilePath: '.env', - isGlobal: true, - }), - ], - providers: [ - OracleDiscoveryService, - OracleDiscoveryProfile, - { provide: EnvironmentConfigService, useValue: configServiceMock }, - ], - }) - .overrideProvider(OracleDiscoveryService) - .useValue(oracleDiscoveryServiceMock) - .compile(); - - controller = module.get( - OracleDiscoveryController, - ); - serviceMock = module.get(OracleDiscoveryService); - }); - - it('should be defined', () => { - expect(controller).toBeDefined(); - }); - - describe('oracle discovery', () => { - it('should return discovered oracles', async () => { - const dtoFixture = { - selected_job_types: ['job-type-1', 'job-type-2'], - } as GetOraclesQuery; - const result: DiscoveredOracle[] = - await controller.getOracles(dtoFixture); - const expectedResponse = generateOracleDiscoveryResponseBody(); - expect(serviceMock.getOracles).toHaveBeenCalled(); - expect(result).toEqual(expectedResponse); - }); - - it('should throw an error if jobsDiscoveryFlag is disabled', async () => { - const dtoFixture = { - selected_job_types: ['job-type-1', 'job-type-2'], - } as GetOraclesQuery; - - (configServiceMock as any).jobsDiscoveryFlag = false; - - await expect(controller.getOracles(dtoFixture)).rejects.toThrow( - new HttpException( - 'Oracles discovery is disabled', - HttpStatus.FORBIDDEN, - ), - ); - }); - }); -}); diff --git a/packages/apps/human-app/server/src/modules/oracle-discovery/spec/oracle-discovery.fixture.ts b/packages/apps/human-app/server/src/modules/oracle-discovery/spec/oracle-discovery.fixture.ts index de9ca168c8..b343545384 100644 --- a/packages/apps/human-app/server/src/modules/oracle-discovery/spec/oracle-discovery.fixture.ts +++ b/packages/apps/human-app/server/src/modules/oracle-discovery/spec/oracle-discovery.fixture.ts @@ -4,7 +4,7 @@ import { DiscoveredOracle, } from '../model/oracle-discovery.model'; -export const response1: DiscoveredOracle = { +const response1: DiscoveredOracle = { id: '1', address: '0xd06eac24a0c47c776Ce6826A93162c4AfC029047', chainId: ChainId.POLYGON_AMOY, @@ -24,7 +24,7 @@ export const response1: DiscoveredOracle = { amountJobsProcessed: '0', }; -export const response2: DiscoveredOracle = { +const response2: DiscoveredOracle = { id: '2', address: '0xd10c3402155c058D78e4D5fB5f50E125F06eb39d', chainId: ChainId.POLYGON_AMOY, @@ -44,7 +44,7 @@ export const response2: DiscoveredOracle = { amountJobsProcessed: '0', }; -export const response3: DiscoveredOracle = { +const response3: DiscoveredOracle = { id: '3', address: '0xd83422155c058D78e4D5fB5f50E125F06eb39d', chainId: ChainId.POLYGON_AMOY, @@ -64,7 +64,7 @@ export const response3: DiscoveredOracle = { amountJobsProcessed: '0', }; -export const response4: DiscoveredOracle = { +const response4: DiscoveredOracle = { id: '4', address: '0xd83422155c058D78e4D5fB5f50E125F06eb39d', chainId: ChainId.BSC_TESTNET, From 18dd484f9351160ccd69db21d366cf999e47dc1f Mon Sep 17 00:00:00 2001 From: Maxim Zhiltsov Date: Thu, 30 Jul 2026 12:30:11 +0300 Subject: [PATCH 22/33] [CVAT] Reserve escrow funds in store_results (#3990) --- .../cvat/exchange-oracle/src/chain/escrow.py | 11 +- .../src/core/annotation_meta.py | 2 + .../src/handlers/job_creation/utils.py | 3 - .../src/handlers/job_export/results.py | 1 + .../utils/gen_audio_validation_fixture.py | 5 + .../b7c1f0a4d2e3_add_assignment_bounty.py | 26 ++++ .../cvat/recording-oracle/src/chain/escrow.py | 32 ++++- .../cvat/recording-oracle/src/chain/web3.py | 16 +++ .../src/core/annotation_meta.py | 2 + .../recording-oracle/src/entrypoints/debug.py | 3 +- .../src/handlers/completion/handlers.py | 65 ++++++++++ .../validation/intermediate_results.py | 1 + .../recording-oracle/src/models/validation.py | 2 + .../src/services/validation.py | 2 + .../tests/integration/chain/test_escrow.py | 21 +++- .../tests/unit/test_bounty_reservation.py | 111 ++++++++++++++++++ 16 files changed, 290 insertions(+), 13 deletions(-) create mode 100644 packages/examples/cvat/recording-oracle/alembic/versions/b7c1f0a4d2e3_add_assignment_bounty.py create mode 100644 packages/examples/cvat/recording-oracle/tests/unit/test_bounty_reservation.py diff --git a/packages/examples/cvat/exchange-oracle/src/chain/escrow.py b/packages/examples/cvat/exchange-oracle/src/chain/escrow.py index 0afcecc2a6..2e4faf04c3 100644 --- a/packages/examples/cvat/exchange-oracle/src/chain/escrow.py +++ b/packages/examples/cvat/exchange-oracle/src/chain/escrow.py @@ -121,13 +121,14 @@ def get_escrow_fund_token_decimals(chain_id: int, escrow_address: str) -> int: return get_token_decimals(chain_id, escrow.token) -def get_remaining_escrow_funds(chain_id: int, escrow_address: str) -> Decimal | None: +def get_raw_remaining_escrow_funds(chain_id: int, escrow_address: str) -> int: web3 = get_web3(chain_id) - client = EscrowClient(web3) + escrow_client = EscrowClient(web3) - remaining_funds = client.get_remaining_funds(escrow_address) - if remaining_funds is None: - return None + return escrow_client.get_remaining_funds(escrow_address) + +def get_remaining_escrow_funds(chain_id: int, escrow_address: str) -> Decimal: + remaining_funds = get_raw_remaining_escrow_funds(chain_id, escrow_address) token_decimals = get_escrow_fund_token_decimals(chain_id, escrow_address) return Decimal(remaining_funds) / Decimal(10**token_decimals) diff --git a/packages/examples/cvat/exchange-oracle/src/core/annotation_meta.py b/packages/examples/cvat/exchange-oracle/src/core/annotation_meta.py index 86f306921d..8ce7e9e667 100644 --- a/packages/examples/cvat/exchange-oracle/src/core/annotation_meta.py +++ b/packages/examples/cvat/exchange-oracle/src/core/annotation_meta.py @@ -11,6 +11,8 @@ class JobMeta(BaseModel): assignment_id: str start_frame: int stop_frame: int + assignment_bounty: str | None = None + "Assignment reward, a decimal value in the escrow fund token units" class AnnotationMeta(BaseModel): diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/utils.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/utils.py index d86959e39e..ae1dfd49e2 100644 --- a/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/utils.py +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_creation/utils.py @@ -57,9 +57,6 @@ def _get_assignment_bounty_from_escrow( return None funds = get_remaining_escrow_funds(chain_id, escrow_address) - if funds is None: - return None - return str(funds / job_count) diff --git a/packages/examples/cvat/exchange-oracle/src/handlers/job_export/results.py b/packages/examples/cvat/exchange-oracle/src/handlers/job_export/results.py index 05ef3492ea..7855daaa60 100644 --- a/packages/examples/cvat/exchange-oracle/src/handlers/job_export/results.py +++ b/packages/examples/cvat/exchange-oracle/src/handlers/job_export/results.py @@ -43,6 +43,7 @@ def prepare_annotation_metafile(jobs: list[Job]) -> FileDescriptor: task_id=job.cvat_task_id, start_frame=job.start_frame, stop_frame=job.stop_frame, + assignment_bounty=job.project.assignment_bounty, ) for job in jobs ] diff --git a/packages/examples/cvat/exchange-oracle/tests/assets/utils/gen_audio_validation_fixture.py b/packages/examples/cvat/exchange-oracle/tests/assets/utils/gen_audio_validation_fixture.py index 1602908a24..e6c9fc18a8 100644 --- a/packages/examples/cvat/exchange-oracle/tests/assets/utils/gen_audio_validation_fixture.py +++ b/packages/examples/cvat/exchange-oracle/tests/assets/utils/gen_audio_validation_fixture.py @@ -25,6 +25,7 @@ from __future__ import annotations import tempfile +from decimal import Decimal from pathlib import Path INPUT_BUCKET = "datasets" @@ -115,6 +116,10 @@ def upload_input(tmp_dir: Path): with ( patch.object(handlers, "get_escrow_manifest", return_value=manifest), patch("src.handlers.job_creation.builders.audio.transcription.cvat_api", cvat_api), + patch( + "src.handlers.job_creation.utils.get_remaining_escrow_funds", + return_value=Decimal(10), + ), ): handlers.create_task(ESCROW_ADDRESS, chain_id) diff --git a/packages/examples/cvat/recording-oracle/alembic/versions/b7c1f0a4d2e3_add_assignment_bounty.py b/packages/examples/cvat/recording-oracle/alembic/versions/b7c1f0a4d2e3_add_assignment_bounty.py new file mode 100644 index 0000000000..6a9bab4217 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/alembic/versions/b7c1f0a4d2e3_add_assignment_bounty.py @@ -0,0 +1,26 @@ +""" +Add assignment bounty + +Revision ID: b7c1f0a4d2e3 +Revises: a5907f01ac2d +Create Date: 2026-07-29 14:30:00.000000 + +""" + +import sqlalchemy as sa + +from alembic import op + +# revision identifiers, used by Alembic. +revision = "b7c1f0a4d2e3" +down_revision = "a5907f01ac2d" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + op.add_column("validation_results", sa.Column("assignment_bounty", sa.String(), nullable=True)) + + +def downgrade() -> None: + op.drop_column("validation_results", "assignment_bounty") diff --git a/packages/examples/cvat/recording-oracle/src/chain/escrow.py b/packages/examples/cvat/recording-oracle/src/chain/escrow.py index 5885288fa9..69811553eb 100644 --- a/packages/examples/cvat/recording-oracle/src/chain/escrow.py +++ b/packages/examples/cvat/recording-oracle/src/chain/escrow.py @@ -1,4 +1,5 @@ import json +from decimal import Decimal import httpx2 from human_protocol_sdk.constants import ChainId, Status @@ -6,7 +7,7 @@ from human_protocol_sdk.escrow import EscrowClient, EscrowData, EscrowUtils from human_protocol_sdk.utils import validate_url -from src.chain.web3 import get_web3 +from src.chain.web3 import get_token_decimals, get_web3 from src.core.config import Config from src.core.types import OracleWebhookTypes @@ -77,11 +78,36 @@ def get_escrow_manifest(chain_id: int, escrow_address: str) -> dict: return json.loads(manifest_content) -def store_results(chain_id: int, escrow_address: str, url: str, hash: str) -> None: +def get_escrow_fund_token_decimals(chain_id: int, escrow_address: str) -> int: + """ + ERC-20 decimals: divide the raw token amount by 10**decimals for the user representation + (https://eips.ethereum.org/EIPS/eip-20). + """ + + escrow = get_escrow(chain_id, escrow_address) + return get_token_decimals(chain_id, escrow.token) + + +def get_raw_remaining_escrow_funds(chain_id: int, escrow_address: str) -> int: + web3 = get_web3(chain_id) + escrow_client = EscrowClient(web3) + + return escrow_client.get_remaining_funds(escrow_address) + + +def get_remaining_escrow_funds(chain_id: int, escrow_address: str) -> Decimal: + remaining_funds = get_raw_remaining_escrow_funds(chain_id, escrow_address) + token_decimals = get_escrow_fund_token_decimals(chain_id, escrow_address) + return Decimal(remaining_funds) / Decimal(10**token_decimals) + + +def store_results( + chain_id: int, escrow_address: str, url: str, hash: str, funds_to_reserve: int | None = None +) -> None: web3 = get_web3(chain_id) escrow_client = EscrowClient(web3) - escrow_client.store_results(escrow_address, url, hash) + escrow_client.store_results(escrow_address, url, hash, funds_to_reserve=funds_to_reserve) def get_available_webhook_types( diff --git a/packages/examples/cvat/recording-oracle/src/chain/web3.py b/packages/examples/cvat/recording-oracle/src/chain/web3.py index c2ad58d5f1..dffdf5ab25 100644 --- a/packages/examples/cvat/recording-oracle/src/chain/web3.py +++ b/packages/examples/cvat/recording-oracle/src/chain/web3.py @@ -9,6 +9,16 @@ from src.core.config import Config from src.core.types import Networks +decimals_abi = [ + { + "constant": True, + "inputs": [], + "name": "decimals", + "outputs": [{"name": "", "type": "uint8"}], + "type": "function", + } +] # ABI for fetching token decimals (ERC-20 optional method; https://eips.ethereum.org/EIPS/eip-20) + def get_web3(chain_id: Networks): match chain_id: @@ -81,3 +91,9 @@ def validate_address(escrow_address: str) -> str: if not Web3.is_address(escrow_address): raise ValueError(f"{escrow_address} is not a correct Web3 address") return Web3.to_checksum_address(escrow_address) + + +def get_token_decimals(chain_id: int, token_address: str) -> int: + w3 = get_web3(chain_id) + contract = w3.eth.contract(address=w3.to_checksum_address(token_address), abi=decimals_abi) + return contract.functions.decimals().call() diff --git a/packages/examples/cvat/recording-oracle/src/core/annotation_meta.py b/packages/examples/cvat/recording-oracle/src/core/annotation_meta.py index 73daec8413..05f2073da0 100644 --- a/packages/examples/cvat/recording-oracle/src/core/annotation_meta.py +++ b/packages/examples/cvat/recording-oracle/src/core/annotation_meta.py @@ -18,6 +18,8 @@ class JobMeta(BaseModel): assignment_id: str start_frame: int stop_frame: int + assignment_bounty: str | None = None + "Assignment reward, a decimal value in the escrow fund token units" @property def job_frame_range(self) -> Iterator[int]: diff --git a/packages/examples/cvat/recording-oracle/src/entrypoints/debug.py b/packages/examples/cvat/recording-oracle/src/entrypoints/debug.py index 5afe74580c..90c82d58b3 100644 --- a/packages/examples/cvat/recording-oracle/src/entrypoints/debug.py +++ b/packages/examples/cvat/recording-oracle/src/entrypoints/debug.py @@ -79,10 +79,11 @@ def patched_store_results( escrow_address, url, hash, + funds_to_reserve=None, ) -> None: logger.info( f"DEV: Would store results for escrow '{escrow_address}@{chain_id}' " - f"on chain: {url}, {hash}" + f"on chain: {url}, {hash}, reserving {funds_to_reserve}" ) with mock.patch("src.chain.escrow.store_results", patched_store_results): diff --git a/packages/examples/cvat/recording-oracle/src/handlers/completion/handlers.py b/packages/examples/cvat/recording-oracle/src/handlers/completion/handlers.py index d48355ba10..6f4e311679 100644 --- a/packages/examples/cvat/recording-oracle/src/handlers/completion/handlers.py +++ b/packages/examples/cvat/recording-oracle/src/handlers/completion/handlers.py @@ -1,11 +1,13 @@ import io import os +from decimal import Decimal from logging import Logger from sqlalchemy.orm import Session import src.core.annotation_meta as annotation import src.core.validation_meta as validation +import src.services.validation as db_service import src.services.webhook as oracle_db_service from src.chain import escrow from src.core.config import Config @@ -80,6 +82,66 @@ def export(self): def _compose_validation_results_bucket_filename(self, filename: str) -> str: return f"{self.escrow_address}@{self.chain_id}/{filename}" + def _compute_total_bounty(self) -> Decimal | None: + """ + Computes the total reward for the final assignments. + Returns None, if the reward is unknown for the assignments. + """ + + assert self.annotation_meta is not None + + assignment_bounties = { + job_meta.assignment_id: db_service.get_validation_result_by_assignment_id( + self.db_session, job_meta.assignment_id + ).assignment_bounty + for job_meta in self.annotation_meta.jobs + } + + assignments_without_bounty = [ + assignment_id for assignment_id, bounty in assignment_bounties.items() if bounty is None + ] + if assignments_without_bounty: + # The assignment rewards are expected to be either known for all the assignments + # or unknown for all of them, otherwise the total reward can't be computed + if len(assignments_without_bounty) != len(assignment_bounties): + raise Exception( + f"Result uploading for escrow_address={self.escrow_address}: " + f"{len(assignments_without_bounty)} of {len(assignment_bounties)} assignments " + "have no reward specified. " + "Either all the assignments must have bounty specified or none of them." + ) + + return None + + return sum((Decimal(bounty) for bounty in assignment_bounties.values()), start=Decimal(0)) + + def _compute_funds_to_reserve(self, total_bounty: Decimal | None) -> int: + """ + Returns the escrow funds to be reserved for the payouts, in the raw token units. + All the remaining funds are reserved, the requested reward is only validated. + """ + + remaining_funds = escrow.get_raw_remaining_escrow_funds(self.chain_id, self.escrow_address) + + if total_bounty is not None: + token_decimals = escrow.get_escrow_fund_token_decimals( + self.chain_id, self.escrow_address + ) + requested_funds = total_bounty * 10**token_decimals + if requested_funds > remaining_funds: + raise Exception( + f"Result uploading for escrow_address={self.escrow_address}: " + f"the total assignment reward ({requested_funds}) exceeds " + f"the remaining escrow funds ({remaining_funds})" + ) + + self.logger.info( + f"Result uploading for escrow_address={self.escrow_address}: " + f"will reserve {remaining_funds} funds on the escrow." + ) + + return remaining_funds + def _handle_result(self, export_result: FinalResult): logger = self.logger escrow_address = self.escrow_address @@ -112,11 +174,14 @@ def _handle_result(self, export_result: FinalResult): validation_metafile, ) + funds_to_reserve = self._compute_funds_to_reserve(self._compute_total_bounty()) + escrow.store_results( chain_id, escrow_address, Config.storage_config.bucket_url() + os.path.dirname(recor_merged_annotations_path), # noqa: PTH120 compute_resulting_annotations_hash(export_result.resulting_annotations), + funds_to_reserve=funds_to_reserve, ) oracle_db_service.outbox.create_webhook( diff --git a/packages/examples/cvat/recording-oracle/src/handlers/validation/intermediate_results.py b/packages/examples/cvat/recording-oracle/src/handlers/validation/intermediate_results.py index ee7dc13724..fc4bc25234 100644 --- a/packages/examples/cvat/recording-oracle/src/handlers/validation/intermediate_results.py +++ b/packages/examples/cvat/recording-oracle/src/handlers/validation/intermediate_results.py @@ -473,6 +473,7 @@ def process_intermediate_results( # noqa: PLR0912 annotator_wallet_address=job_meta.annotator_wallet_address, annotation_quality=job_results[job_meta.job_id], assignment_id=job_meta.assignment_id, + assignment_bounty=job_meta.assignment_bounty, ) else: assignment_validation_result_id = assignment_validation_result.id diff --git a/packages/examples/cvat/recording-oracle/src/models/validation.py b/packages/examples/cvat/recording-oracle/src/models/validation.py index 120ace2c10..6b9f6e2996 100644 --- a/packages/examples/cvat/recording-oracle/src/models/validation.py +++ b/packages/examples/cvat/recording-oracle/src/models/validation.py @@ -53,6 +53,8 @@ class ValidationResult(Base): assignment_id = Column(String, unique=True, nullable=False) annotator_wallet_address = Column(String, nullable=False) annotation_quality = Column(Float, nullable=False) + assignment_bounty = Column(String, nullable=True) + "Assignment reward, a decimal value in the escrow fund token units" job: Mapped[Job] = relationship(back_populates="validation_results") diff --git a/packages/examples/cvat/recording-oracle/src/services/validation.py b/packages/examples/cvat/recording-oracle/src/services/validation.py index 1ccab5d30f..092055522b 100644 --- a/packages/examples/cvat/recording-oracle/src/services/validation.py +++ b/packages/examples/cvat/recording-oracle/src/services/validation.py @@ -98,6 +98,7 @@ def create_validation_result( annotator_wallet_address: str, annotation_quality: float, assignment_id: str, + assignment_bounty: str | None = None, ) -> str: obj_id = str(uuid.uuid4()) obj = ValidationResult( @@ -106,6 +107,7 @@ def create_validation_result( annotator_wallet_address=annotator_wallet_address, annotation_quality=annotation_quality, assignment_id=assignment_id, + assignment_bounty=assignment_bounty, ) session.add(obj) diff --git a/packages/examples/cvat/recording-oracle/tests/integration/chain/test_escrow.py b/packages/examples/cvat/recording-oracle/tests/integration/chain/test_escrow.py index 742c7addb6..83268e1205 100644 --- a/packages/examples/cvat/recording-oracle/tests/integration/chain/test_escrow.py +++ b/packages/examples/cvat/recording-oracle/tests/integration/chain/test_escrow.py @@ -130,7 +130,26 @@ def test_store_results(self): store_results(chain_id, escrow_address, DEFAULT_MANIFEST_URL, DEFAULT_HASH) is None ) mock_client_cls.return_value.store_results.assert_called_once_with( - escrow_address, DEFAULT_MANIFEST_URL, DEFAULT_HASH + escrow_address, DEFAULT_MANIFEST_URL, DEFAULT_HASH, funds_to_reserve=None + ) + + def test_store_results_with_funds_to_reserve(self): + with ( + patch("src.chain.escrow.get_web3"), + patch("src.chain.escrow.EscrowClient") as mock_client_cls, + ): + assert ( + store_results( + chain_id, + escrow_address, + DEFAULT_MANIFEST_URL, + DEFAULT_HASH, + funds_to_reserve=42, + ) + is None + ) + mock_client_cls.return_value.store_results.assert_called_once_with( + escrow_address, DEFAULT_MANIFEST_URL, DEFAULT_HASH, funds_to_reserve=42 ) def test_store_results_invalid_url(self): diff --git a/packages/examples/cvat/recording-oracle/tests/unit/test_bounty_reservation.py b/packages/examples/cvat/recording-oracle/tests/unit/test_bounty_reservation.py new file mode 100644 index 0000000000..b6362ba9f1 --- /dev/null +++ b/packages/examples/cvat/recording-oracle/tests/unit/test_bounty_reservation.py @@ -0,0 +1,111 @@ +from decimal import Decimal +from types import SimpleNamespace +from unittest.mock import MagicMock, patch + +import pytest + +from src.core.annotation_meta import AnnotationMeta, JobMeta +from src.handlers.completion.handlers import _EscrowExporter + +from tests.utils.constants import ESCROW_ADDRESS, WALLET_ADDRESS1 + +CHAIN_ID = 1338 + + +@pytest.fixture +def fxt_exporter(): + exporter = _EscrowExporter( + escrow_address=ESCROW_ADDRESS, chain_id=CHAIN_ID, manifest=None, db_session=None + ) + exporter.set_logger(MagicMock()) + return exporter + + +def _make_annotation_meta(assignment_ids: list[str]) -> AnnotationMeta: + return AnnotationMeta( + jobs=[ + JobMeta( + job_id=i, + task_id=1, + annotator_wallet_address=WALLET_ADDRESS1, + assignment_id=assignment_id, + start_frame=0, + stop_frame=1, + ) + for i, assignment_id in enumerate(assignment_ids) + ] + ) + + +def _patch_assignment_bounties(bounties: dict[str, str | None]): + return patch( + "src.services.validation.get_validation_result_by_assignment_id", + side_effect=lambda _session, assignment_id: SimpleNamespace( + assignment_bounty=bounties[assignment_id] + ), + ) + + +class EscrowBountyTest: + def test_can_sum_assignment_bounties(self, fxt_exporter): + fxt_exporter.annotation_meta = _make_annotation_meta(["a1", "a2", "a3"]) + + with _patch_assignment_bounties({"a1": "0.1", "a2": "0.2", "a3": "1"}): + total_bounty = fxt_exporter._compute_total_bounty() + + assert total_bounty == Decimal("1.3") + + def test_can_report_no_bounty_if_unknown_for_all_assignments(self, fxt_exporter): + fxt_exporter.annotation_meta = _make_annotation_meta(["a1", "a2"]) + + with _patch_assignment_bounties({"a1": None, "a2": None}): + total_bounty = fxt_exporter._compute_total_bounty() + + assert total_bounty is None + + def test_can_fail_if_bounty_is_unknown_for_some_assignments(self, fxt_exporter): + fxt_exporter.annotation_meta = _make_annotation_meta(["a1", "a2"]) + + with ( + _patch_assignment_bounties({"a1": "0.1", "a2": None}), + pytest.raises(Exception, match="1 of 2 assignments have no reward specified"), + ): + fxt_exporter._compute_total_bounty() + + def test_can_sum_empty_results(self, fxt_exporter): + fxt_exporter.annotation_meta = _make_annotation_meta([]) + + with _patch_assignment_bounties({}): + total_bounty = fxt_exporter._compute_total_bounty() + + assert total_bounty == Decimal(0) + + def test_can_reserve_remaining_funds(self, fxt_exporter): + with ( + patch( + "src.chain.escrow.get_raw_remaining_escrow_funds", return_value=10**19 + ) as mock_get_funds, + patch("src.chain.escrow.get_escrow_fund_token_decimals", return_value=18), + ): + funds_to_reserve = fxt_exporter._compute_funds_to_reserve(Decimal("1.5")) + + mock_get_funds.assert_called_once_with(CHAIN_ID, ESCROW_ADDRESS) + assert funds_to_reserve == 10**19 + + def test_can_fail_if_reward_exceeds_remaining_funds(self, fxt_exporter): + with ( + patch("src.chain.escrow.get_raw_remaining_escrow_funds", return_value=10**17), + patch("src.chain.escrow.get_escrow_fund_token_decimals", return_value=18), + pytest.raises(Exception, match="exceeds the remaining escrow funds"), + ): + fxt_exporter._compute_funds_to_reserve(Decimal(1)) + + def test_can_reserve_remaining_funds_if_bounty_is_unknown(self, fxt_exporter): + with ( + patch("src.chain.escrow.get_raw_remaining_escrow_funds", return_value=10**17), + patch("src.chain.escrow.get_escrow_fund_token_decimals") as mock_get_decimals, + ): + funds_to_reserve = fxt_exporter._compute_funds_to_reserve(None) + + assert funds_to_reserve == 10**17 + mock_get_decimals.assert_not_called() From cb24e4d94657cacfd7865fed2af65e1f6724db3f Mon Sep 17 00:00:00 2001 From: Dmitry Nechay Date: Thu, 30 Jul 2026 14:49:26 +0300 Subject: [PATCH 23/33] [Reputation Oracle] fix: cvat v2 manifest format (#3991) --- .../server/src/common/enums/manifest.ts | 3 ++- .../server/src/common/types/manifest.ts | 12 +++++------- .../src/modules/escrow-completion/fixtures/cvat.ts | 11 ++++------- .../cvat-payouts-calculator.spec.ts | 4 +--- .../reputation-oracle/server/src/utils/manifest.ts | 4 ++-- 5 files changed, 14 insertions(+), 20 deletions(-) diff --git a/packages/apps/reputation-oracle/server/src/common/enums/manifest.ts b/packages/apps/reputation-oracle/server/src/common/enums/manifest.ts index 738b18254a..6468dda156 100644 --- a/packages/apps/reputation-oracle/server/src/common/enums/manifest.ts +++ b/packages/apps/reputation-oracle/server/src/common/enums/manifest.ts @@ -8,11 +8,12 @@ export enum MarketingJobType { } export enum CvatJobType { - IMAGE_BOXES = 'image_boxes', IMAGE_POINTS = 'image_points', + IMAGE_BOXES = 'image_boxes', IMAGE_BOXES_FROM_POINTS = 'image_boxes_from_points', IMAGE_SKELETONS_FROM_BOXES = 'image_skeletons_from_boxes', IMAGE_POLYGONS = 'image_polygons', + AUDIO_TRANSCRIPTION = 'audio_transcription', } export const JobType = [ diff --git a/packages/apps/reputation-oracle/server/src/common/types/manifest.ts b/packages/apps/reputation-oracle/server/src/common/types/manifest.ts index 00b7d47c82..aba98c30c8 100644 --- a/packages/apps/reputation-oracle/server/src/common/types/manifest.ts +++ b/packages/apps/reputation-oracle/server/src/common/types/manifest.ts @@ -19,13 +19,11 @@ export interface MarketingManifest extends BaseManifest { } export type CvatManifest = { - annotation: { - type: CvatJobType; - }; - validation: { - min_quality: number; - }; - job_bounty: string; + version: 2; + job_type: CvatJobType; + // not necessary for RepO + data: unknown; + annotation: unknown; }; export type JobManifest = FortuneManifest | MarketingManifest | CvatManifest; diff --git a/packages/apps/reputation-oracle/server/src/modules/escrow-completion/fixtures/cvat.ts b/packages/apps/reputation-oracle/server/src/modules/escrow-completion/fixtures/cvat.ts index d1a6f89d26..1b083013f1 100644 --- a/packages/apps/reputation-oracle/server/src/modules/escrow-completion/fixtures/cvat.ts +++ b/packages/apps/reputation-oracle/server/src/modules/escrow-completion/fixtures/cvat.ts @@ -5,12 +5,9 @@ import { CvatManifest } from '@/common/types'; export function generateCvatManifest(): CvatManifest { return { - annotation: { - type: faker.helpers.arrayElement(Object.values(CvatJobType)), - }, - validation: { - min_quality: faker.number.float({ min: 0.1, max: 0.9 }), - }, - job_bounty: faker.finance.amount({ max: 42 }), + version: 2, + job_type: faker.helpers.arrayElement(Object.values(CvatJobType)), + data: undefined, + annotation: undefined, }; } diff --git a/packages/apps/reputation-oracle/server/src/modules/escrow-completion/payouts-calculation/cvat-payouts-calculator.spec.ts b/packages/apps/reputation-oracle/server/src/modules/escrow-completion/payouts-calculation/cvat-payouts-calculator.spec.ts index 13c1da8dac..d576409be9 100644 --- a/packages/apps/reputation-oracle/server/src/modules/escrow-completion/payouts-calculation/cvat-payouts-calculator.spec.ts +++ b/packages/apps/reputation-oracle/server/src/modules/escrow-completion/payouts-calculation/cvat-payouts-calculator.spec.ts @@ -204,12 +204,10 @@ describe('CvatPayoutsCalculator', () => { ); mockedGetReservedFunds.mockResolvedValueOnce(reservedFunds); - const manifest = generateCvatManifest(); - const payouts = await calculator.calculate({ chainId, escrowAddress, - manifest, + manifest: generateCvatManifest(), finalResultsUrl: faker.internet.url(), }); diff --git a/packages/apps/reputation-oracle/server/src/utils/manifest.ts b/packages/apps/reputation-oracle/server/src/utils/manifest.ts index 7b898e0f93..10ba60db7f 100644 --- a/packages/apps/reputation-oracle/server/src/utils/manifest.ts +++ b/packages/apps/reputation-oracle/server/src/utils/manifest.ts @@ -40,8 +40,8 @@ export function getJobRequestType(manifest: JobManifest): JobRequestType { if ('requestType' in manifest) { jobRequestType = manifest.requestType; - } else if ('annotation' in manifest) { - jobRequestType = manifest.annotation.type; + } else if ('job_type' in manifest) { + jobRequestType = manifest.job_type; } if (!jobRequestType) { From 9f35c06918fc8f8e78667a2f1484da0affb77aa9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Jul 2026 14:55:14 +0300 Subject: [PATCH 24/33] chore(deps): bump actions/setup-python from 6 to 7 (#3983) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/cd-python-sdk.yaml | 2 +- .github/workflows/ci-lint-cvat-exchange-oracle.yaml | 2 +- .github/workflows/ci-lint-cvat-recording-oracle.yaml | 2 +- .github/workflows/ci-test-python-sdk.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/cd-python-sdk.yaml b/.github/workflows/cd-python-sdk.yaml index aba50ea0f8..ac27dd7e2a 100644 --- a/.github/workflows/cd-python-sdk.yaml +++ b/.github/workflows/cd-python-sdk.yaml @@ -35,7 +35,7 @@ jobs: node-version-file: .nvmrc cache: yarn - name: Set up Python - uses: actions/setup-python@v6 + uses: actions/setup-python@v7 with: python-version: "3.x" - name: Read package version diff --git a/.github/workflows/ci-lint-cvat-exchange-oracle.yaml b/.github/workflows/ci-lint-cvat-exchange-oracle.yaml index 7b4d925fbb..40cb434fe0 100644 --- a/.github/workflows/ci-lint-cvat-exchange-oracle.yaml +++ b/.github/workflows/ci-lint-cvat-exchange-oracle.yaml @@ -24,7 +24,7 @@ jobs: uses: snok/install-poetry@v1 with: version: 1.8.4 - - uses: actions/setup-python@v6 + - uses: actions/setup-python@v7 with: python-version: '3.10' cache: 'poetry' diff --git a/.github/workflows/ci-lint-cvat-recording-oracle.yaml b/.github/workflows/ci-lint-cvat-recording-oracle.yaml index baa61a0dae..8bab8e5103 100644 --- a/.github/workflows/ci-lint-cvat-recording-oracle.yaml +++ b/.github/workflows/ci-lint-cvat-recording-oracle.yaml @@ -24,7 +24,7 @@ jobs: uses: snok/install-poetry@v1 with: version: 1.8.4 - - uses: actions/setup-python@v6 + - uses: actions/setup-python@v7 with: python-version: '3.10' cache: 'poetry' diff --git a/.github/workflows/ci-test-python-sdk.yaml b/.github/workflows/ci-test-python-sdk.yaml index a201efebcc..6c048c0b8f 100644 --- a/.github/workflows/ci-test-python-sdk.yaml +++ b/.github/workflows/ci-test-python-sdk.yaml @@ -22,7 +22,7 @@ jobs: - name: Build core package run: yarn workspace @human-protocol/core build - name: Set up Python 3.10 - uses: actions/setup-python@v6 + uses: actions/setup-python@v7 with: python-version: "3.10" - name: Install pipenv From 00aec0647413344c7eca48f8781b070e0ab68f48 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Jul 2026 15:17:00 +0300 Subject: [PATCH 25/33] chore(deps): bump @google-cloud/storage from 7.19.0 to 7.21.0 (#3975) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- packages/apps/job-launcher/server/package.json | 2 +- yarn.lock | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/apps/job-launcher/server/package.json b/packages/apps/job-launcher/server/package.json index 44b7e9b8c8..9c72fcee40 100644 --- a/packages/apps/job-launcher/server/package.json +++ b/packages/apps/job-launcher/server/package.json @@ -30,7 +30,7 @@ "typeorm": "typeorm-ts-node-commonjs" }, "dependencies": { - "@google-cloud/storage": "^7.19.0", + "@google-cloud/storage": "^7.21.0", "@google-cloud/vision": "^4.3.2", "@human-protocol/logger": "workspace:*", "@human-protocol/sdk": "workspace:*", diff --git a/yarn.lock b/yarn.lock index 79f52d1a19..82951c67a1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -613,7 +613,7 @@ __metadata: "@eslint/js": "npm:^10.0.1" "@faker-js/faker": "npm:^9.8.0" "@golevelup/ts-jest": "npm:^3.0.0" - "@google-cloud/storage": "npm:^7.19.0" + "@google-cloud/storage": "npm:^7.21.0" "@google-cloud/vision": "npm:^4.3.2" "@human-protocol/logger": "workspace:*" "@human-protocol/sdk": "workspace:*" @@ -4874,9 +4874,9 @@ __metadata: languageName: node linkType: hard -"@google-cloud/storage@npm:^7.19.0": - version: 7.19.0 - resolution: "@google-cloud/storage@npm:7.19.0" +"@google-cloud/storage@npm:^7.21.0": + version: 7.21.0 + resolution: "@google-cloud/storage@npm:7.21.0" dependencies: "@google-cloud/paginator": "npm:^5.0.0" "@google-cloud/projectify": "npm:^4.0.0" @@ -4892,8 +4892,7 @@ __metadata: p-limit: "npm:^3.0.1" retry-request: "npm:^7.0.0" teeny-request: "npm:^9.0.0" - uuid: "npm:^8.0.0" - checksum: 10c0/2951e4a0b3c2f90c28917a9b313a981722a9e5648ca2b6d04f384f816e9107e1637b00c32c5e71ed8d25c7e1840898b616f015b29c2cc1d8d8a22c8630778d8c + checksum: 10c0/07cffff2467575a56594ceb6534253d1dd653de2f093fb5c4e5efa52586351afdcecca3d95ea9617a243b3cbf2cae0cfc7f5448473fad8ba8f7425a291c76cb2 languageName: node linkType: hard @@ -31710,7 +31709,7 @@ __metadata: languageName: node linkType: hard -"uuid@npm:^8.0.0, uuid@npm:^8.3.2": +"uuid@npm:^8.3.2": version: 8.3.2 resolution: "uuid@npm:8.3.2" bin: From 9f4a632a7a60b64b0aad38b6c9f4572a5e15bf84 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Jul 2026 15:38:01 +0300 Subject: [PATCH 26/33] chore(deps): bump actions/setup-node from 6 to 7 (#3974) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/cd-packages.yaml | 2 +- .github/workflows/cd-python-sdk.yaml | 2 +- .github/workflows/cd-subgraph-hmt.yaml | 2 +- .github/workflows/cd-subgraph-human.yaml | 2 +- .github/workflows/ci-lint.yaml | 2 +- .github/workflows/ci-test-core.yaml | 2 +- .github/workflows/ci-test-dashboard.yaml | 2 +- .github/workflows/ci-test-faucet-server.yaml | 2 +- .github/workflows/ci-test-fortune.yaml | 4 ++-- .github/workflows/ci-test-human-app.yaml | 2 +- .github/workflows/ci-test-job-launcher.yaml | 2 +- .github/workflows/ci-test-node-sdk.yaml | 2 +- .github/workflows/ci-test-python-sdk.yaml | 2 +- .github/workflows/ci-test-reputation-oracle.yaml | 2 +- .github/workflows/ci-test-subgraph-hmt.yaml | 2 +- .github/workflows/ci-test-subgraph-human.yaml | 2 +- 16 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/cd-packages.yaml b/.github/workflows/cd-packages.yaml index 2b659d27cc..3a5b970caf 100644 --- a/.github/workflows/cd-packages.yaml +++ b/.github/workflows/cd-packages.yaml @@ -39,7 +39,7 @@ jobs: run: | git config --global user.name "github-actions[bot]" git config --global user.email "github-actions[bot]@users.noreply.github.com" - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v7 with: node-version-file: .nvmrc cache: yarn diff --git a/.github/workflows/cd-python-sdk.yaml b/.github/workflows/cd-python-sdk.yaml index ac27dd7e2a..cfd7aba1bf 100644 --- a/.github/workflows/cd-python-sdk.yaml +++ b/.github/workflows/cd-python-sdk.yaml @@ -30,7 +30,7 @@ jobs: run: | git config --global user.name "github-actions[bot]" git config --global user.email "github-actions[bot]@users.noreply.github.com" - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v7 with: node-version-file: .nvmrc cache: yarn diff --git a/.github/workflows/cd-subgraph-hmt.yaml b/.github/workflows/cd-subgraph-hmt.yaml index 5b53b69c26..62752bcaa5 100644 --- a/.github/workflows/cd-subgraph-hmt.yaml +++ b/.github/workflows/cd-subgraph-hmt.yaml @@ -30,7 +30,7 @@ jobs: max-parallel: 3 steps: - uses: actions/checkout@v7 - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v7 with: node-version-file: .nvmrc cache: yarn diff --git a/.github/workflows/cd-subgraph-human.yaml b/.github/workflows/cd-subgraph-human.yaml index 4a13ba84ed..17d87f4a74 100644 --- a/.github/workflows/cd-subgraph-human.yaml +++ b/.github/workflows/cd-subgraph-human.yaml @@ -30,7 +30,7 @@ jobs: max-parallel: 3 steps: - uses: actions/checkout@v7 - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v7 with: node-version-file: .nvmrc cache: yarn diff --git a/.github/workflows/ci-lint.yaml b/.github/workflows/ci-lint.yaml index efc5eba32b..07950c2785 100644 --- a/.github/workflows/ci-lint.yaml +++ b/.github/workflows/ci-lint.yaml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v7 with: node-version-file: .nvmrc cache: yarn diff --git a/.github/workflows/ci-test-core.yaml b/.github/workflows/ci-test-core.yaml index 6f5e30e46c..adab294c27 100644 --- a/.github/workflows/ci-test-core.yaml +++ b/.github/workflows/ci-test-core.yaml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v7 with: node-version-file: .nvmrc cache: yarn diff --git a/.github/workflows/ci-test-dashboard.yaml b/.github/workflows/ci-test-dashboard.yaml index 8465fa703e..52fb6163b6 100644 --- a/.github/workflows/ci-test-dashboard.yaml +++ b/.github/workflows/ci-test-dashboard.yaml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v7 with: node-version-file: .nvmrc cache: yarn diff --git a/.github/workflows/ci-test-faucet-server.yaml b/.github/workflows/ci-test-faucet-server.yaml index c9df4aa014..87fa2a0306 100644 --- a/.github/workflows/ci-test-faucet-server.yaml +++ b/.github/workflows/ci-test-faucet-server.yaml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v7 with: node-version-file: .nvmrc cache: yarn diff --git a/.github/workflows/ci-test-fortune.yaml b/.github/workflows/ci-test-fortune.yaml index 7e41bb531a..e51171b77b 100644 --- a/.github/workflows/ci-test-fortune.yaml +++ b/.github/workflows/ci-test-fortune.yaml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v7 with: node-version-file: .nvmrc cache: yarn @@ -30,7 +30,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v7 with: node-version-file: .nvmrc cache: yarn diff --git a/.github/workflows/ci-test-human-app.yaml b/.github/workflows/ci-test-human-app.yaml index 422db8ad55..2174d83bd4 100644 --- a/.github/workflows/ci-test-human-app.yaml +++ b/.github/workflows/ci-test-human-app.yaml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v7 with: node-version-file: .nvmrc cache: yarn diff --git a/.github/workflows/ci-test-job-launcher.yaml b/.github/workflows/ci-test-job-launcher.yaml index d28bb8d2c6..defaec586e 100644 --- a/.github/workflows/ci-test-job-launcher.yaml +++ b/.github/workflows/ci-test-job-launcher.yaml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v7 with: node-version-file: .nvmrc cache: yarn diff --git a/.github/workflows/ci-test-node-sdk.yaml b/.github/workflows/ci-test-node-sdk.yaml index 0420a09432..e065c841f0 100644 --- a/.github/workflows/ci-test-node-sdk.yaml +++ b/.github/workflows/ci-test-node-sdk.yaml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v7 with: node-version-file: .nvmrc cache: yarn diff --git a/.github/workflows/ci-test-python-sdk.yaml b/.github/workflows/ci-test-python-sdk.yaml index 6c048c0b8f..09f60e0872 100644 --- a/.github/workflows/ci-test-python-sdk.yaml +++ b/.github/workflows/ci-test-python-sdk.yaml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v7 with: node-version-file: .nvmrc cache: yarn diff --git a/.github/workflows/ci-test-reputation-oracle.yaml b/.github/workflows/ci-test-reputation-oracle.yaml index c5248a8e1e..e8497e7012 100644 --- a/.github/workflows/ci-test-reputation-oracle.yaml +++ b/.github/workflows/ci-test-reputation-oracle.yaml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v7 with: node-version-file: .nvmrc cache: yarn diff --git a/.github/workflows/ci-test-subgraph-hmt.yaml b/.github/workflows/ci-test-subgraph-hmt.yaml index e7913ed99c..28b9767236 100644 --- a/.github/workflows/ci-test-subgraph-hmt.yaml +++ b/.github/workflows/ci-test-subgraph-hmt.yaml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v7 - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v7 with: node-version-file: .nvmrc cache: yarn diff --git a/.github/workflows/ci-test-subgraph-human.yaml b/.github/workflows/ci-test-subgraph-human.yaml index f7cb543cb2..3a06bad898 100644 --- a/.github/workflows/ci-test-subgraph-human.yaml +++ b/.github/workflows/ci-test-subgraph-human.yaml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v7 - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v7 with: node-version-file: .nvmrc cache: yarn From c1ed2079b07da02d5d788e351e9f6a40e8048b0e Mon Sep 17 00:00:00 2001 From: Dmitry Nechay Date: Thu, 30 Jul 2026 17:44:32 +0300 Subject: [PATCH 27/33] chore: turn off dependabot (#3992) --- .github/{dependabot.yml => _dependabot.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{dependabot.yml => _dependabot.yml} (100%) diff --git a/.github/dependabot.yml b/.github/_dependabot.yml similarity index 100% rename from .github/dependabot.yml rename to .github/_dependabot.yml From 7e44b12ce7857fd784c9de8dd2f380e6e1191cdf Mon Sep 17 00:00:00 2001 From: Dmitry Nechay Date: Tue, 4 Aug 2026 13:38:26 +0300 Subject: [PATCH 28/33] [HUMAN App] fix: oracles response fields (#3994) --- .../modules/oracle-discovery/oracle-discovery.controller.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.controller.ts b/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.controller.ts index 02bfad380b..bb5cc540d0 100644 --- a/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.controller.ts +++ b/packages/apps/human-app/server/src/modules/oracle-discovery/oracle-discovery.controller.ts @@ -86,6 +86,9 @@ export class OracleDiscoveryController { url: oracle.url, jobTypes: oracle.jobTypes, name: oracle.name, + category: oracle.category, + registrationNeeded: oracle.registrationNeeded, + registrationInstructions: oracle.registrationInstructions, nTasks: oracleJobs.length, minRewardAmount: minRewardAmount.toString(), maxRewardAmount: maxRewardAmount.toString(), From 68a20e41fc24aff6ebb6155ba676325c1f3657fe Mon Sep 17 00:00:00 2001 From: Siarhei Date: Wed, 5 Aug 2026 13:25:35 +0300 Subject: [PATCH 29/33] chore: bump aiohttp to 3.14.3 to patch security vulnerabilities (#3995) --- .../examples/cvat/exchange-oracle/poetry.lock | 250 +++++++++--------- .../cvat/exchange-oracle/pyproject.toml | 1 + 2 files changed, 126 insertions(+), 125 deletions(-) diff --git a/packages/examples/cvat/exchange-oracle/poetry.lock b/packages/examples/cvat/exchange-oracle/poetry.lock index 13e2f3a12d..d097055fa0 100644 --- a/packages/examples/cvat/exchange-oracle/poetry.lock +++ b/packages/examples/cvat/exchange-oracle/poetry.lock @@ -33,130 +33,130 @@ files = [ [[package]] name = "aiohttp" -version = "3.14.1" +version = "3.14.3" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.10" files = [ - {file = "aiohttp-3.14.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8f6bb621e5863cfe8fe5ff5468002d200ec31f30f1280b259dc505b02595099e"}, - {file = "aiohttp-3.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4f7215cb3933784f79ed20e5f050e15984f390424339b22375d5a53c933a0491"}, - {file = "aiohttp-3.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d9d4e294455b23a68c9b8f042d0e8e377a265bcb15332753695f6e5b6819e0ce"}, - {file = "aiohttp-3.14.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b238af795833d5731d049d82bc84b768ae6f8f97f0495963b3ed9935c5901cc3"}, - {file = "aiohttp-3.14.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e4e5e0ae56914ecdbf446493addefc0159053dd53962cef37d7839f37f73d505"}, - {file = "aiohttp-3.14.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:092e4ce3619a7c6dee52a6bdabda973d9b34b66781f840ce93c7e0cec30cf521"}, - {file = "aiohttp-3.14.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bb33777ea21e8b7ecde0e6fc84f598be0a1192eab1a63bc746d75aa75d38e7bd"}, - {file = "aiohttp-3.14.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23119f8fd4f5d16902ed459b63b100bcd269628075162bddac56cc7b5273b3fb"}, - {file = "aiohttp-3.14.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:57fc6745a4b7d0f5a9eb4f40a69718be6c0bc1b8368cc9fe89e90118719f4f42"}, - {file = "aiohttp-3.14.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6fd35beba67c4183b09375c5fff9accb47524191a244a99f95fd4472f5402c2b"}, - {file = "aiohttp-3.14.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:672b9d65f42eb877f5c3f234a4547e4e1a226ca8c2eed879bb34670a0ce51192"}, - {file = "aiohttp-3.14.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:24ba13339fed9251d9b1a1bec8c7ab84c0d1675d79d33501e11f94f8b9a84e05"}, - {file = "aiohttp-3.14.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:94da27378da0610e341c4d30de29a191672683cc82b8f9556e8f7c7212a020fe"}, - {file = "aiohttp-3.14.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:52cdac9432d8b4a719f35094a818d95adcae0f0b4fe9b9b921909e0c87de9e7d"}, - {file = "aiohttp-3.14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:672ac254412a24d0d0cf00a9e6c238877e4be5e5fa2d188832c1244f45f31966"}, - {file = "aiohttp-3.14.1-cp310-cp310-win32.whl", hash = "sha256:2fe3607e71acc6ebb0ec8e492a247bf7a291226192dc0084236dfc12478916f6"}, - {file = "aiohttp-3.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:30099eda75a53c32efb0920e9c33c195314d2cc1c680fbfd30894932ac5f27df"}, - {file = "aiohttp-3.14.1-cp310-cp310-win_arm64.whl", hash = "sha256:5a837f49d901f9e368651b676912bff1104ed8c1a83b280bcd7b29adccef5c9c"}, - {file = "aiohttp-3.14.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:aa00140699487bd435fde4342d85c94cb256b7cd3a5b9c3396c67f19922afda2"}, - {file = "aiohttp-3.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1c1af67559445498b502030c35c59db59966f47041ca9de5b4e707f86bd10b5f"}, - {file = "aiohttp-3.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d44ec478e713ee7f29b439f7eb8dc2b9d4079e11ae114d2c2ac3d5daf30516c8"}, - {file = "aiohttp-3.14.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d3b1a184a9a8f548a6b73f1e26b96b052193e4b3175ed7342aaf1151a1f00a04"}, - {file = "aiohttp-3.14.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5f2504bc0322437c9a1ff6d3333ca56c7477b727c995f036b976ae17b98372c8"}, - {file = "aiohttp-3.14.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:73f05ea02013e02512c3bf42714f1208c57168c779cc6fe23516e4543089d0a6"}, - {file = "aiohttp-3.14.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:797457503c2d426bee06eef808d07b31ede30b65e054444e7de64cad0061b7af"}, - {file = "aiohttp-3.14.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b821a1f7dedf7e37450654e620038ac3b2e81e8fa6ea269337e97101978ec730"}, - {file = "aiohttp-3.14.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4cd96b5ba05d67ed0cf00b5b405c8cd99586d8e3481e8ee0a831057591af7621"}, - {file = "aiohttp-3.14.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d459b98a932296c6f0e94f87511a0b1b90a8a02c30a50e60a297619cd5a58ee"}, - {file = "aiohttp-3.14.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:764457a7be60825fb770a644852ff717bcbb5042f189f2bd16df61a81b3f6573"}, - {file = "aiohttp-3.14.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f7a16ef45b081454ef844502d87a848876c490c4cb5c650c230f6ec79ed2c1e7"}, - {file = "aiohttp-3.14.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2fbc3ed048b3475b9f0cbcb9978e9d2d3511acd91ead203af26ed9f0056004cf"}, - {file = "aiohttp-3.14.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bedb0cd073cc2dc035e30aeb99444389d3cd2113afe4ef9fcd23d439f5bade85"}, - {file = "aiohttp-3.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b6feea921016eb3d4e04d65fc4e9ca402d1a3801f562aef94989f54694917af3"}, - {file = "aiohttp-3.14.1-cp311-cp311-win32.whl", hash = "sha256:313701e488100074ce99850404ee36e741abf6330179fec908a1944ecf570126"}, - {file = "aiohttp-3.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:03ab4530fdcb3a543a122ba4b65ac9919da9fe9f78a03d328a6e38ff962f7aa5"}, - {file = "aiohttp-3.14.1-cp311-cp311-win_arm64.whl", hash = "sha256:486f7d16ed54c39c2cbd7ca71fd8ba2b8bb7860df65bd7b6ed640bab96a38a8b"}, - {file = "aiohttp-3.14.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d35143e27778b4bb0fb189562d7f275bff79c62ab8e98459717c0ea617ff2480"}, - {file = "aiohttp-3.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bcfb80a2cc36fba2534e5e5b5264dc7ae6fcd9bf15256da3e53d2f499e6fa29d"}, - {file = "aiohttp-3.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27fd7c91e51729b4f7e1577865fa6d34c9adccbc39aabe9000285b48af9f0ec2"}, - {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:64c567bf9eaf664280116a8688f63016e6b32db2505908e2bdaca1b6438142f2"}, - {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f5e6ff2bdbb8f4cd3fbe41f99e25bbcd58e3bf9f13d3dd31a11e7917251cc77a"}, - {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2f73e01dc37122325caf079982621262f96d74823c179038a82fddfc50359264"}, - {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bb2c0c80d431c0d03f2c7dbf125150fedd4f0de17366a7ca33f7ccb822391842"}, - {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3e6fc1a85fa7194a1a7d19f44e8609180f4a8eb5fa4c7ed8b4355f080fad235c"}, - {file = "aiohttp-3.14.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:686b6c0d3911ec387b444ddf5dc62fb7f7c0a7d5186a7861626496a5ab4aff95"}, - {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c6fa4dc7ad6f8109c70bb1499e589f76b0b792baf39f9b017eb92c8a81d0a199"}, - {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:87a5eea1b2a5e21e1ebdbb33ad4165359189327e63fc4e4894693e7f821ac817"}, - {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1c1421eb01d4fd608d88cc8290211d177a58532b55ad94076fb349c5bf467f0a"}, - {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:34b257ec41345c1e8f2df68fa908a7952f5de932723871eb633ecbbff396c9a4"}, - {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:de538791a80e5d862addbc183f70f0158ac9b9bb872bb147f1fd2a683691e087"}, - {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f71173be42d3241d428f760122febb748de0623f44308a6f120d0dd9ec572e3"}, - {file = "aiohttp-3.14.1-cp312-cp312-win32.whl", hash = "sha256:ec8dc383ee57ea3e883477dcca3f11b65d58199f1080acaf4cd6ad9a99698be4"}, - {file = "aiohttp-3.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:2aa92c87868cd13674989f9ee83e5f9f7ea4237589b728048e1f0c8f6caa3271"}, - {file = "aiohttp-3.14.1-cp312-cp312-win_arm64.whl", hash = "sha256:2c840c90759922cb5e6dda94596e079a30fb5a5ba548e7e0dc00574703940847"}, - {file = "aiohttp-3.14.1-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:b3a03285a7f9c7b016324574a6d92a1c895da6b978cb8f1deee3ac72bc6da178"}, - {file = "aiohttp-3.14.1-cp313-cp313-android_21_x86_64.whl", hash = "sha256:2a73f487ab8ef5abbb24b7aa9b73e98eaba9e9e031804ff2416f02eca315ccaf"}, - {file = "aiohttp-3.14.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:915fbb7b41b115192259f8c9ae58f3ddc444d2b5579917270211858e606a4afd"}, - {file = "aiohttp-3.14.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:7fb4bdf95b0561a79f259f9d28fbc109728c5ee7f27aff6391f0ca703a329abe"}, - {file = "aiohttp-3.14.1-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:1b9748363260121d2927704f5d4fc498150669ca3ae93625986ee89c8f80dcd4"}, - {file = "aiohttp-3.14.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:86a6dab78b0e43e2897a3bbe15745aa60dc5423ca437b7b0b164c069bf91b876"}, - {file = "aiohttp-3.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4dfd6e47d3c44c2279907607f73a4240b88c69eb8b90da7e2441a8045dfd21da"}, - {file = "aiohttp-3.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:317acd9f8602858dc7d59679812c376c7f0b97bcbbf16e0d6237f54141d8a8a6"}, - {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd869c427324e5cb15195793de951295710db28be7d818247f3097b4ab5d4b96"}, - {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:93b032b5ec3255473c143627d21a69ac74ae12f7f33974cb587c564d11b1066f"}, - {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f234b4deb12f3ad59127e037bc57c40c21e45b45282df7d3a55a0f409f595296"}, - {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9af6779bfb46abf124068327abcdf9ce95c9ef8287a3e8da76ccf2d0f16c28fa"}, - {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:faccab372e66bc76d5731525e7f1143c922271725b9d38c9f97edcc66266b451"}, - {file = "aiohttp-3.14.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f380468b09d2a81633ee863b0ec5648d364bd17bb8ecfb8c2f387f7ac1faf42c"}, - {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:97e704dcd26271f5bda3fa07c3ce0fb76d6d3f8659f4baa1a24442cc9ba177ca"}, - {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:269b76ac5394092b95bc4a098f4fc6c191c083c3bd12775d1e30e663132f6a09"}, - {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c0b3e614340c889d575451696374c9d17affd54cd607ca0babed8f8c37b9397"}, - {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:5663ee9257cfa1add7253a7da3035a02f31b6600ec48261585e1800a81533080"}, - {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:603a2c834142172ffddc054067f5ec0ca65d57a0aa98a71bc81952573208e345"}, - {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cb21957bb8aca671c1765e32f58164cf0c50e6bf41c0bbbd16da20732ecaf588"}, - {file = "aiohttp-3.14.1-cp313-cp313-win32.whl", hash = "sha256:e509a55f681e6158c20f70f102f9cf61fb20fbc382272bc6d94b7343f2582780"}, - {file = "aiohttp-3.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:1ac8531b638959718e18c2207fbfe297819875da46a740b29dfa29beba64355a"}, - {file = "aiohttp-3.14.1-cp313-cp313-win_arm64.whl", hash = "sha256:250d14af67f6b6a1a4a811049b1afa69d61d617fca6bf33149b3ab1a6dbcf7b8"}, - {file = "aiohttp-3.14.1-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:7c106c26852ca1c2047c6b80384f17100b4e439af276f21ef3d4e2f450ae7e15"}, - {file = "aiohttp-3.14.1-cp314-cp314-android_24_x86_64.whl", hash = "sha256:20205f7f5ade7aaec9f4b500549bbc071b046453aed72f9c06dcab87896a83e8"}, - {file = "aiohttp-3.14.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:62a759436b29e677181a9e76bab8b8f689a29cb9c535f45f7c48c9c830d3f8c3"}, - {file = "aiohttp-3.14.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:2964cbf553df4d7a57348da44d961d871895fc1ee4e8c322b2a95612c7b17fba"}, - {file = "aiohttp-3.14.1-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:237651caadc3a59badd39319c54642b5299e9cc98a3a194310e55d5bb9f5e397"}, - {file = "aiohttp-3.14.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:896e12dfdbbab9d8f7e16d2b28c6769a60126fa92095d1ebf9473d02593a2448"}, - {file = "aiohttp-3.14.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d03f281ed22579314ba00821ce20115a7c0ac430660b4cc05704a3f818b3e004"}, - {file = "aiohttp-3.14.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:07eabb979d236335fed927e137a928c9adfb7df3b9ec7aa31726f133a62be983"}, - {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4fe1f1087cbadb280b5e1bb054a4f00d1423c74d6626c5e48400d871d34ecefe"}, - {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:367a9314fdc79dab0fac96e216cb41dd73c85bdca85306ce8999118ba7e0f333"}, - {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a24f677ebe83749039e7bdf862ff0bbb16818ae4193d4ef96505e269375bcce0"}, - {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c83afe0ba876be7e943d2e0ba645809ad441575d2840c895c21ee5de93b9377a"}, - {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:634e385930fb6d2d479cf3aa66515955863b77a5e3c2b5894ca259a25b308602"}, - {file = "aiohttp-3.14.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eeea07c4397bbc57719c4eed8f9c284874d4f175f9b6d57f7a1546b976d455ca"}, - {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:335c0cc3e3545ce98dcb9cfcb836f40c3411f43fa03dab757597d80c89af8a35"}, - {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:ae6be797afdef264e8a84864a85b196ca06045586481b3df8a967322fd2fa844"}, - {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:8560b4d712474335d08907db7973f71912d3a9a8f1dee992ec06b5d2fe359496"}, - {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7edd08e0a5deb1e8564a2fcd8f4561014a3f05252334671bbf55ddd47db0e5"}, - {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:b6ff7fcee63287ae57b5df3e4f5957ce032122802509246dec1a5bcc55904c95"}, - {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6ffbb2f4ec1ceaff7e07d43922954da26b223d188bf30658e561b98e23089444"}, - {file = "aiohttp-3.14.1-cp314-cp314-win32.whl", hash = "sha256:a9875b46d910cff3ea2f5962f9d266b465459fe634e22556ab9bd6fc1192eea0"}, - {file = "aiohttp-3.14.1-cp314-cp314-win_amd64.whl", hash = "sha256:af8b4b81a960eeaf1234971ac3cd0ba5901f3cd42eae42a46b4d089a8b492719"}, - {file = "aiohttp-3.14.1-cp314-cp314-win_arm64.whl", hash = "sha256:cf4491381b1b57425c315a56a439251b1bdac07b2275f19a8c44bc57744532ec"}, - {file = "aiohttp-3.14.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:819c054312f1af92947e6a55883d1b66feefab11531a7fc45e0fb9b63880b5c2"}, - {file = "aiohttp-3.14.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:10ee9c1753a8f706345b22496c79fbddb5be0599e0823f3738b1534058e25340"}, - {file = "aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1601cc37baf5750ccacae618ec2daf020769581695550e3b654a911f859c563d"}, - {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4d6e0ac9da31c9c04c84e1c0182ad8d6df35965a85cae29cd71d089621b3ae94"}, - {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9e8f2d660c350b3d0e259c7a7e3d9b7fc8b41210cbcc3d4a7076ff0a5e5c2fdc"}, - {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4691802dda97be727f79d86818acaad7eb8e9252626a1d6b519fedbb92d5e251"}, - {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c389c482a7e9b9dc3ee2701ac46c4125297a3818875b9c305ddb603c04828fd1"}, - {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fc0cacab7ba4e56f0f81c82a98c09bed2f39c940107b03a34b168bdf7597edd3"}, - {file = "aiohttp-3.14.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:979ed4717f59b8bb12e3963378fa285d93d367e15bcd66c721311826d3c44a6c"}, - {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:38e1e7daaea81df51c952e18483f323d878499a1e2bfe564790e0f9701d6f203"}, - {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:4132e72c608fe9fecb8f409113567605915b83e9bdd3ea56538d2f9cd35002f1"}, - {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:eefd9cc9b6d4a2db5f00a26bc3e4f9acf71926a6ec557cd56c9c6f27c290b665"}, - {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:b165790117eea512d7f3fb22f1f6dad3d55a7189571993eb015591c1401276d1"}, - {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:ed09c7eb1c391271c2ed0314a51903e72a3acb653d5ccfc264cdf3ef11f8269d"}, - {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:99abd37084b82f5830c635fddd0b4993b9742a66eb746dacf433c8590e8f9e3c"}, - {file = "aiohttp-3.14.1-cp314-cp314t-win32.whl", hash = "sha256:47ddf841cdecc810749921d25606dee45857d12d2ad5ddb7b5bd7eab12e4b365"}, - {file = "aiohttp-3.14.1-cp314-cp314t-win_amd64.whl", hash = "sha256:5e78b522b7a6e27e0b25d19b247b75039ac4c94f99823e3c9e53ae1603a9f7e9"}, - {file = "aiohttp-3.14.1-cp314-cp314t-win_arm64.whl", hash = "sha256:90d53f1609c29ccc2193945ef732428382a28f78d0456ae4d3daf0d48b74f0f6"}, - {file = "aiohttp-3.14.1.tar.gz", hash = "sha256:307f2cff90a764d329e77040603fa032db89c5c24fdad50c4c15334cba744035"}, + {file = "aiohttp-3.14.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:eb0495d778817619273c108784292be161a924b9f5ae5cbbc70a2caa6838250b"}, + {file = "aiohttp-3.14.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c3c200cf9757edd785051dc699c7ecbec22110dbfcb3fefc7a9f9695eda8ea7a"}, + {file = "aiohttp-3.14.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd51ebf9d3a00c074df4ede271023f4d2dba289bcc740b88191872716014e3c5"}, + {file = "aiohttp-3.14.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:134ac5ddcf61c6fad984b9a5727d83492ada43d63471db20fb73042c13fca62f"}, + {file = "aiohttp-3.14.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:70c987b27534f9ae1a723f47ae921571d616da21d3208282bf4c52af5164ac43"}, + {file = "aiohttp-3.14.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1b59533861b70a2185c8f4f350f791f39d64358ef6944ce71c5240c9ec0982c9"}, + {file = "aiohttp-3.14.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1c5281acc88b92396f88c7e1e2748f8466689df22b80170e4f51efa712fb47a8"}, + {file = "aiohttp-3.14.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:48d67b87db6279c044760787eb01f6413032c2e6f3ba1cafaa492b1c8e578479"}, + {file = "aiohttp-3.14.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f53bcd52f585e1ac3e590d61434eb61f9a88c38df041b4ea126d97144344a77b"}, + {file = "aiohttp-3.14.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0fdea2281997af69da84c77ffa6f5938a0285f21fb3887c249d67419ca865b3d"}, + {file = "aiohttp-3.14.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:cda5fd5c95ad7a125a2e8464acc78b98b94c475a3780d6aa0aa157c93f470f4d"}, + {file = "aiohttp-3.14.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:6debfa7312ff9d4c124dc71d72e9a0a4b9e0879e48ba6fcb42bef5c3300289e2"}, + {file = "aiohttp-3.14.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:f4e05329faa0ea1a404b37de4f034fd2c2defcca06a68dc6745e4e56c88e8a48"}, + {file = "aiohttp-3.14.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:a3a8296e7ab5c295f53f1041487cb088e1480775aafbf7fe545d93b770a0f96f"}, + {file = "aiohttp-3.14.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5373dc80ad1aa2fb9ad95c83f24eef418bbda3a61375f128e5b0192e4f3f9b32"}, + {file = "aiohttp-3.14.3-cp310-cp310-win32.whl", hash = "sha256:a3e22975f905b89a55a488c2a08f2fdb2186175349e917d48985cc468a3d4c6e"}, + {file = "aiohttp-3.14.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdd0e2834dce1a26c1bbe26464861e16bbe217042cbff619247c11594472518c"}, + {file = "aiohttp-3.14.3-cp310-cp310-win_arm64.whl", hash = "sha256:eac645b09bcfdf73df7536331f0678c1086ea250981118ddb5199e17ccef72bb"}, + {file = "aiohttp-3.14.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e568e14940c09955aa51f4e645b6daa18a581c5dcfcd73744dcc86a856e3ced3"}, + {file = "aiohttp-3.14.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:54cfcdee2770dac994417cbb0ee1f3eb0e7cb6b30c79bf44f2c02ff79ec5124a"}, + {file = "aiohttp-3.14.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:21c016079415ed3fd676963e9793700a566d85dbbd6bfc564b9b2d209147dcc8"}, + {file = "aiohttp-3.14.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d6088ec9894113802bddb3c09e974929aed2c7b3a8c456219b8aab4481f1a239"}, + {file = "aiohttp-3.14.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:16ea7e24c309fb7c0bbd505d149abe4fe4dccfb8db911db7dbec0921bc889a6f"}, + {file = "aiohttp-3.14.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56f355e79f71aef2a85c80305cc915f894b170dba76de5fe84f6351939b83c06"}, + {file = "aiohttp-3.14.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:18c441d0a8fca6de8d1f546849b9f0ab20d435993e2c5b59562b2fae6be2f929"}, + {file = "aiohttp-3.14.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:53e7b4ce82b54a8bcc71b3b67a5cbd177ca1d7f592cbc92cd38b7349f73482db"}, + {file = "aiohttp-3.14.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f55119f7bf25f49ed210f6096090715da24f2943c62102448915fde3c62877ce"}, + {file = "aiohttp-3.14.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9aa6e61fdf20105c4144e755bd586008ff450791d67b1c8146fdc15959c4d51c"}, + {file = "aiohttp-3.14.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ccd4893707b3e2a13e39c90d43cf80edf2e4d0457935bcc103bf2346214c3f15"}, + {file = "aiohttp-3.14.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b2466434105a4e03113c36ec775cc2ebe6676b62eae326fa670bb607ef788c1c"}, + {file = "aiohttp-3.14.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:ba59d59aba08ac02fc03b0c8983ccd5ee39a199d0552ce9e6d2b4845b34d59ae"}, + {file = "aiohttp-3.14.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ed099d105449c4f9e84f24af203cd131349d4761d8813fa7e02c32e7128cd910"}, + {file = "aiohttp-3.14.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:152516815ef926786a0b6ae2b8f1fd2e0c71582dee0b435636865316fd4891b7"}, + {file = "aiohttp-3.14.3-cp311-cp311-win32.whl", hash = "sha256:a4af35c443e0b1a1bd6a8af3f3485d7fda15c142751a00f3ff8090f0b93346fa"}, + {file = "aiohttp-3.14.3-cp311-cp311-win_amd64.whl", hash = "sha256:e1e74298bab6ee0d6e749ed4fd1901c7e604bdda32c03d787a2cc71c46d0433d"}, + {file = "aiohttp-3.14.3-cp311-cp311-win_arm64.whl", hash = "sha256:03cd2bde3d7f085b64e549c985f4bb928cad7e8ecf5323bfca320db548d81b39"}, + {file = "aiohttp-3.14.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:39aded8c7f3b935b54aab1d8d73c70ec0ee2d3ec3b943e0e86611bc150ba47f5"}, + {file = "aiohttp-3.14.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5bcb6ff3fdab1258a192679ff1a05d44f59626430aa05cd1a9d2447423599228"}, + {file = "aiohttp-3.14.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:617105e2c3018ee38d0c8ce5ee3c84f621a6d8b9f723202aacaff28449ca91ee"}, + {file = "aiohttp-3.14.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f631fe87a6f30df5fbe6d79640b25e4cffb38c31c7fb6f10871517b84b0f8c1a"}, + {file = "aiohttp-3.14.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a94dbaae5ae27bd849c93570669bff91e0510f33a80805738e3de72a7be0447b"}, + {file = "aiohttp-3.14.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8f2f1c4c032c7cedd7d8da6f54c97b70266c6570c3108d3fdffee7188bb70529"}, + {file = "aiohttp-3.14.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ea05e1f97ceea523942d9b2a7d7c0359d781d683d6b043f5943a602b14da4787"}, + {file = "aiohttp-3.14.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:543906c127fb1d929b95076db19b83fa2d46751006ff1e23b093aa5ac4d8db42"}, + {file = "aiohttp-3.14.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0a5ff2dfbb9ce645fa5b8ef3e02c6c0b9cc3f6030ff863d0c51fffc50cb5541b"}, + {file = "aiohttp-3.14.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:041badb8f84396357c4d3ad26de6afd7a32b112f43d3c63045c0c8278cfd2043"}, + {file = "aiohttp-3.14.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:530125ee1163c4219af35dc3aa1206e541e7b31b6efc1a3f93b70a136f65d427"}, + {file = "aiohttp-3.14.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c8653fd547c93a61aadc612007790f5555cdd18946fa48cf45e26d8ea4ea473d"}, + {file = "aiohttp-3.14.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:89176250f686cb9853c0fb7ead90e639e915b84a6f43eedc2a4e7ec21f1037f0"}, + {file = "aiohttp-3.14.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3a26434dafe408229ff3403458ca58de24fb51936504decac49ce6755f77e59d"}, + {file = "aiohttp-3.14.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d1558173930a5a8d3069cee5c92fc91c87c4dbcb099debbb3622053717145a19"}, + {file = "aiohttp-3.14.3-cp312-cp312-win32.whl", hash = "sha256:16100ad3ab8d649fdfbee87602d9d2dcdca9df0b9eda8a1b5fdc0d41f96da559"}, + {file = "aiohttp-3.14.3-cp312-cp312-win_amd64.whl", hash = "sha256:33a2d7c28d33797a2e99923dffa63f83d908a19b6bf26cfe80fa790aa5e1a75a"}, + {file = "aiohttp-3.14.3-cp312-cp312-win_arm64.whl", hash = "sha256:362a3fd481769cac1a824514bcd86fda51c65e8fe6e051099e008fddde6db17c"}, + {file = "aiohttp-3.14.3-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:2e9878ae68e4a5f1c0abe4dd497dbc3d51946f5837b56759e2a02e78fa90ef86"}, + {file = "aiohttp-3.14.3-cp313-cp313-android_21_x86_64.whl", hash = "sha256:f3d2669fe7dec7fc359ecdb5984b29b50d85d5d00f8c1cb61de4f4a24ee42627"}, + {file = "aiohttp-3.14.3-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:cc7cb243a68167172f48c1fd43cee91ec4b1d40cefd190edd43369d1a6bc9c82"}, + {file = "aiohttp-3.14.3-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:78253b573e6ffab5028924fc98bc281aae05445969982a10864bc360dea2016c"}, + {file = "aiohttp-3.14.3-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7041d52c3a7fa20c9e8c182b534704abb19502c8bdcbde7ab23bfda6f642394f"}, + {file = "aiohttp-3.14.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ac74facc01463f138b0da5580329cfcc82818dea5656e83ddcd11268fc12ff80"}, + {file = "aiohttp-3.14.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d6218d92e450824e9b4881f44e8c09f1853b490f9a64130801024a4793b1b3b0"}, + {file = "aiohttp-3.14.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:11fb37ef075669eee52ab1928fbf6e1741fada40409fa309ebde9607a962aebf"}, + {file = "aiohttp-3.14.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:55bdcc472aafe2de4a253045cc128007a64f1e0264fb675791e132ea5edaa3bd"}, + {file = "aiohttp-3.14.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c39846c3aad97a8530c89d7a3869a8f8e9e3762c6ac0504481e5c80948f7e807"}, + {file = "aiohttp-3.14.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5895ef58c4620afe02fa16044f023dc4dafec08158f9d08874a46a7dbc0341b8"}, + {file = "aiohttp-3.14.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fa9467a8113aa69d3d7c55a70ef0b7c636010a40993f3df9d9d0d73b3eb7ef24"}, + {file = "aiohttp-3.14.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d7d2deec16eeedf55f2c7cf75b521ea3856a5177e123844f8fd0f114ce252cb5"}, + {file = "aiohttp-3.14.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dd54d0e8717de95939766febac482ac0474d8ac3b048115f9f2b1d23a16e7db4"}, + {file = "aiohttp-3.14.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:df82f3787c940c94986b34222d59c9e38843fba85139f36e85255a82ad5355a9"}, + {file = "aiohttp-3.14.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:42a67efc36300d052fb4508a53e8b6901b9284b599ae63945c377569c5fcc1e1"}, + {file = "aiohttp-3.14.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7a75aa63cbf9b21cfaf60dc2657e19df2c2867d91707d653fee171ffeedd1371"}, + {file = "aiohttp-3.14.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e92eb8acc45eb6a9f4935071a77edf5b85cc6f8dfad5cd99e97653c26593cdde"}, + {file = "aiohttp-3.14.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b014a6ed7cf912e787149fdc529166d3ceabac23f26efeea3158c9aba2354e7e"}, + {file = "aiohttp-3.14.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3d4f72af88ac2474bb5bca640030320e3d38a0163a1d7533500e87be458eef71"}, + {file = "aiohttp-3.14.3-cp313-cp313-win32.whl", hash = "sha256:5f08ec777f35ee70720233b8b9811d3bb5d728137f30ac91b7457709c3261ac0"}, + {file = "aiohttp-3.14.3-cp313-cp313-win_amd64.whl", hash = "sha256:dff9461ec275f22135650d5ba4b4931a11f3958df7dfbb8db630000d4dee0883"}, + {file = "aiohttp-3.14.3-cp313-cp313-win_arm64.whl", hash = "sha256:ddcac3c6b382e81f1dd0499199d4136b877beb4cb5ef770bbbfba56c4b8f55d2"}, + {file = "aiohttp-3.14.3-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:49f7325beb0f85ef4aef5f48f490269575f83e6e2acad00a1d80b807eb027062"}, + {file = "aiohttp-3.14.3-cp314-cp314-android_24_x86_64.whl", hash = "sha256:e3be98a7c30b8c25d573dafba7171d66dfb05ee6a9070fc46535464ff97700a6"}, + {file = "aiohttp-3.14.3-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:614c61d478b83953e261d02bb2df750f17227cd33ef8002945bf5aebbde21919"}, + {file = "aiohttp-3.14.3-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:1caa7b0d05f3e3a36f87788c59e970a7ee1cefcfcbb924a9f138c4a6551c9cb7"}, + {file = "aiohttp-3.14.3-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:dfa68deb2a443bdaa3ea5297b0699c1464f08aef3812b486d1348eee61b07dc0"}, + {file = "aiohttp-3.14.3-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:e72ee89e28d907a18f46959b4eb0bb06701cc7f8cf4366e00029e2ccfaaf5924"}, + {file = "aiohttp-3.14.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ad4c8b7488d745d2ca4838ebd8ae5ba9b56341d30b1da43640e4ce87f9f49646"}, + {file = "aiohttp-3.14.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:db332af25642007330fca8be5c4d194caf2bea7a7fc84415aff3497af5dfee6b"}, + {file = "aiohttp-3.14.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25bd2708db6bdf6a6630dd37bdcdfcb47c4434d22ac69c64665b802910140b30"}, + {file = "aiohttp-3.14.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:cef89a58e628c4efcac3275c2d68083f82426dcdc89c1492a6f654f9f7ea6ab9"}, + {file = "aiohttp-3.14.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c23ec8ee9d5ab2f5421f9c7fffce208435607af27fd46d4a44e031954352838f"}, + {file = "aiohttp-3.14.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e2667f0bbe7eb6c74eae5e9691441ad186e5845ca3cff63230fc09c4e7514f5d"}, + {file = "aiohttp-3.14.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18cb43369747b2ae007bd2655fb8e63a099c2ff1d207962943636dac989b3147"}, + {file = "aiohttp-3.14.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d77640cc618c1d99fc4f8589c0f24a730adfa54eb1e57ef7bf0c8dfb78da898c"}, + {file = "aiohttp-3.14.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:53e5179d8abb5710f8e83ba207c41c8d1261fcffd4616500e15ca2b7a33be10a"}, + {file = "aiohttp-3.14.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:cd817772b2fcf2b8c0905795318485f9ec16eae60b29feb7f4c77085311637f0"}, + {file = "aiohttp-3.14.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:4e3ac92d90e92773b2362d506068e9a948192bd553e743c5b2429e28527c8661"}, + {file = "aiohttp-3.14.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3f42e9b78301f11c8f861746175d8b9c1ccef713fcad9eab396e2f6db8ed4a22"}, + {file = "aiohttp-3.14.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:9d9edccfe496b476db5f398d97b865e9a6752bcf8aec4eef8390ce20fb64bb41"}, + {file = "aiohttp-3.14.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1c5ec8fb1bcc31a8466f74aaf26c345d5c386fa4bd08a3f0eb9c7a4a3fe8b5bf"}, + {file = "aiohttp-3.14.3-cp314-cp314-win32.whl", hash = "sha256:38901a84da3ce22249f6e860bf8f90d141bcab7da090cc398f8bb58c0e44b7da"}, + {file = "aiohttp-3.14.3-cp314-cp314-win_amd64.whl", hash = "sha256:8b3b60de05f3dcb6f6a00f818bb2ec781cee4de0645f59ccaf99b1d1823b6100"}, + {file = "aiohttp-3.14.3-cp314-cp314-win_arm64.whl", hash = "sha256:1576145bdceeb92382d899751e12743a3a5b8e460a841e3e50543859e54864dc"}, + {file = "aiohttp-3.14.3-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:8800c996b01c2772a783e3e46f3e1abd5823029adca0df54231960de9bfefa5b"}, + {file = "aiohttp-3.14.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:ebe8e504f058fe91223351cecd2d9d6946c9d241bb0250d898ffbdf584cc72b0"}, + {file = "aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:30402d03a7c0ff52bce290b57e564e9079fd9d0cb545c8aba73f86a103162d2e"}, + {file = "aiohttp-3.14.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9fc7b5bfec6573f3ae844f457fdde5adeb713f8b8e4a81ad64fc207b49383716"}, + {file = "aiohttp-3.14.3-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8a5fd34f7f7410d1730d5c2ba873cacb2eed3fede366feb268a70ba22581ed8f"}, + {file = "aiohttp-3.14.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:270d3dace9ca2f10f0da5d8ebe519b7a310fc6112ed916e32df5866df0888553"}, + {file = "aiohttp-3.14.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3ae5b3a59436d089b5395d910121a390feed4d00578eb95a0fd1a329fe963100"}, + {file = "aiohttp-3.14.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2498f0fe69ead802f9675beca44a7c21c62fdaa4ec5145ea1c3ad6edbee29f85"}, + {file = "aiohttp-3.14.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a0dc483c00da8b673abbb367eb6f8d8f4bcec30eb58529ea13cb42e7fd2dfa33"}, + {file = "aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c7d3a97c678d34fc5b59da671ee9cd630096ddc643e7b5a30d54a2a6f3574d3f"}, + {file = "aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:f8fb78a83c9e5f741ca3a68cfb455c1f5bb83b4e7249a3848b3cd78d0a8563b0"}, + {file = "aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:74ab5b6a9fb13e873e5a90946588baecaf488745e1db1a4a5c433f971f035098"}, + {file = "aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:bd52f811e65f6fb634b1047159657c98f52b407f8efec907bcfc09da9a4c0a25"}, + {file = "aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:f0f177d1b195b9e06376cfd7d308d8a1b920909a609d03ac82a8c73bbb16d3b9"}, + {file = "aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:498c6c623134f8e09a3c4e60bcd607a0b4590dd7dbf08dd40851b27cbb520ccb"}, + {file = "aiohttp-3.14.3-cp314-cp314t-win32.whl", hash = "sha256:b304db572b4368edd8dda8a2274f73156fe15558fca4a917cb8a09fc47af5963"}, + {file = "aiohttp-3.14.3-cp314-cp314t-win_amd64.whl", hash = "sha256:b20032766aedf6261c7a566585a40867d092ac03a0d81592d5370ef9b054f99b"}, + {file = "aiohttp-3.14.3-cp314-cp314t-win_arm64.whl", hash = "sha256:2e1161602f45a54de2ce0905243a95f58cb42dcd378402f3697f5e0b21e9d2e7"}, + {file = "aiohttp-3.14.3.tar.gz", hash = "sha256:9491196535a88924a60afd5b5f434b5b203b6cc616250878dbdb223a8f7844bc"}, ] [package.dependencies] @@ -3433,10 +3433,10 @@ files = [ [package.dependencies] numpy = [ - {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, - {version = ">=1.23.5", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, {version = ">=1.21.4", markers = "python_version >= \"3.10\" and platform_system == \"Darwin\" and python_version < \"3.11\""}, {version = ">=1.21.2", markers = "platform_system != \"Darwin\" and python_version >= \"3.10\" and python_version < \"3.11\""}, + {version = ">=1.23.5", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, + {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, ] [[package]] @@ -3599,9 +3599,9 @@ files = [ [package.dependencies] numpy = [ - {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, - {version = ">=1.23.2", markers = "python_version == \"3.11\""}, {version = ">=1.22.4", markers = "python_version < \"3.11\""}, + {version = ">=1.23.2", markers = "python_version == \"3.11\""}, + {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" @@ -6109,4 +6109,4 @@ propcache = ">=0.2.1" [metadata] lock-version = "2.0" python-versions = "^3.10,<3.13" -content-hash = "9a7cd1771fe2f604ab5a55485a5f9338797c503e9ec389cefd8ff8030e6bb288" +content-hash = "c3f6ab0cacf839df535b362cf3447a0048089323eb43ef7870aea10e8d3b68d5" diff --git a/packages/examples/cvat/exchange-oracle/pyproject.toml b/packages/examples/cvat/exchange-oracle/pyproject.toml index d26d171aff..a709b9975a 100644 --- a/packages/examples/cvat/exchange-oracle/pyproject.toml +++ b/packages/examples/cvat/exchange-oracle/pyproject.toml @@ -35,6 +35,7 @@ cryptography = "<44.0.0" # human-protocol-sdk -> pgpy dep requires cryptography aiocache = {extras = ["msgpack", "redis"], version = "^0.12.3"} # convenient api for redis (async) cachelib = "^0.14.0" # convenient api for redis (sync) human-protocol-sdk = "^7.3.1" +aiohttp = ">=3.14.3" # TODO: remove once aiohttp is bumped in human-protocol-sdk [tool.poetry.group.dev.dependencies] From 90fd6e8b9f29d42919aea952ec40d80daf3ce142 Mon Sep 17 00:00:00 2001 From: Siarhei Date: Fri, 7 Aug 2026 14:33:02 +0300 Subject: [PATCH 30/33] chore: bump 'aiohttp' to patch security issues (#3998) --- .../cvat/recording-oracle/poetry.lock | 250 +++++++++--------- .../cvat/recording-oracle/pyproject.toml | 1 + 2 files changed, 126 insertions(+), 125 deletions(-) diff --git a/packages/examples/cvat/recording-oracle/poetry.lock b/packages/examples/cvat/recording-oracle/poetry.lock index e8e1e77287..02a76a816f 100644 --- a/packages/examples/cvat/recording-oracle/poetry.lock +++ b/packages/examples/cvat/recording-oracle/poetry.lock @@ -13,130 +13,130 @@ files = [ [[package]] name = "aiohttp" -version = "3.14.1" +version = "3.14.3" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.10" files = [ - {file = "aiohttp-3.14.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8f6bb621e5863cfe8fe5ff5468002d200ec31f30f1280b259dc505b02595099e"}, - {file = "aiohttp-3.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4f7215cb3933784f79ed20e5f050e15984f390424339b22375d5a53c933a0491"}, - {file = "aiohttp-3.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d9d4e294455b23a68c9b8f042d0e8e377a265bcb15332753695f6e5b6819e0ce"}, - {file = "aiohttp-3.14.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b238af795833d5731d049d82bc84b768ae6f8f97f0495963b3ed9935c5901cc3"}, - {file = "aiohttp-3.14.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e4e5e0ae56914ecdbf446493addefc0159053dd53962cef37d7839f37f73d505"}, - {file = "aiohttp-3.14.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:092e4ce3619a7c6dee52a6bdabda973d9b34b66781f840ce93c7e0cec30cf521"}, - {file = "aiohttp-3.14.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bb33777ea21e8b7ecde0e6fc84f598be0a1192eab1a63bc746d75aa75d38e7bd"}, - {file = "aiohttp-3.14.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23119f8fd4f5d16902ed459b63b100bcd269628075162bddac56cc7b5273b3fb"}, - {file = "aiohttp-3.14.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:57fc6745a4b7d0f5a9eb4f40a69718be6c0bc1b8368cc9fe89e90118719f4f42"}, - {file = "aiohttp-3.14.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6fd35beba67c4183b09375c5fff9accb47524191a244a99f95fd4472f5402c2b"}, - {file = "aiohttp-3.14.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:672b9d65f42eb877f5c3f234a4547e4e1a226ca8c2eed879bb34670a0ce51192"}, - {file = "aiohttp-3.14.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:24ba13339fed9251d9b1a1bec8c7ab84c0d1675d79d33501e11f94f8b9a84e05"}, - {file = "aiohttp-3.14.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:94da27378da0610e341c4d30de29a191672683cc82b8f9556e8f7c7212a020fe"}, - {file = "aiohttp-3.14.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:52cdac9432d8b4a719f35094a818d95adcae0f0b4fe9b9b921909e0c87de9e7d"}, - {file = "aiohttp-3.14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:672ac254412a24d0d0cf00a9e6c238877e4be5e5fa2d188832c1244f45f31966"}, - {file = "aiohttp-3.14.1-cp310-cp310-win32.whl", hash = "sha256:2fe3607e71acc6ebb0ec8e492a247bf7a291226192dc0084236dfc12478916f6"}, - {file = "aiohttp-3.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:30099eda75a53c32efb0920e9c33c195314d2cc1c680fbfd30894932ac5f27df"}, - {file = "aiohttp-3.14.1-cp310-cp310-win_arm64.whl", hash = "sha256:5a837f49d901f9e368651b676912bff1104ed8c1a83b280bcd7b29adccef5c9c"}, - {file = "aiohttp-3.14.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:aa00140699487bd435fde4342d85c94cb256b7cd3a5b9c3396c67f19922afda2"}, - {file = "aiohttp-3.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1c1af67559445498b502030c35c59db59966f47041ca9de5b4e707f86bd10b5f"}, - {file = "aiohttp-3.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d44ec478e713ee7f29b439f7eb8dc2b9d4079e11ae114d2c2ac3d5daf30516c8"}, - {file = "aiohttp-3.14.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d3b1a184a9a8f548a6b73f1e26b96b052193e4b3175ed7342aaf1151a1f00a04"}, - {file = "aiohttp-3.14.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5f2504bc0322437c9a1ff6d3333ca56c7477b727c995f036b976ae17b98372c8"}, - {file = "aiohttp-3.14.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:73f05ea02013e02512c3bf42714f1208c57168c779cc6fe23516e4543089d0a6"}, - {file = "aiohttp-3.14.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:797457503c2d426bee06eef808d07b31ede30b65e054444e7de64cad0061b7af"}, - {file = "aiohttp-3.14.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b821a1f7dedf7e37450654e620038ac3b2e81e8fa6ea269337e97101978ec730"}, - {file = "aiohttp-3.14.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4cd96b5ba05d67ed0cf00b5b405c8cd99586d8e3481e8ee0a831057591af7621"}, - {file = "aiohttp-3.14.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d459b98a932296c6f0e94f87511a0b1b90a8a02c30a50e60a297619cd5a58ee"}, - {file = "aiohttp-3.14.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:764457a7be60825fb770a644852ff717bcbb5042f189f2bd16df61a81b3f6573"}, - {file = "aiohttp-3.14.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f7a16ef45b081454ef844502d87a848876c490c4cb5c650c230f6ec79ed2c1e7"}, - {file = "aiohttp-3.14.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2fbc3ed048b3475b9f0cbcb9978e9d2d3511acd91ead203af26ed9f0056004cf"}, - {file = "aiohttp-3.14.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bedb0cd073cc2dc035e30aeb99444389d3cd2113afe4ef9fcd23d439f5bade85"}, - {file = "aiohttp-3.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b6feea921016eb3d4e04d65fc4e9ca402d1a3801f562aef94989f54694917af3"}, - {file = "aiohttp-3.14.1-cp311-cp311-win32.whl", hash = "sha256:313701e488100074ce99850404ee36e741abf6330179fec908a1944ecf570126"}, - {file = "aiohttp-3.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:03ab4530fdcb3a543a122ba4b65ac9919da9fe9f78a03d328a6e38ff962f7aa5"}, - {file = "aiohttp-3.14.1-cp311-cp311-win_arm64.whl", hash = "sha256:486f7d16ed54c39c2cbd7ca71fd8ba2b8bb7860df65bd7b6ed640bab96a38a8b"}, - {file = "aiohttp-3.14.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d35143e27778b4bb0fb189562d7f275bff79c62ab8e98459717c0ea617ff2480"}, - {file = "aiohttp-3.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bcfb80a2cc36fba2534e5e5b5264dc7ae6fcd9bf15256da3e53d2f499e6fa29d"}, - {file = "aiohttp-3.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27fd7c91e51729b4f7e1577865fa6d34c9adccbc39aabe9000285b48af9f0ec2"}, - {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:64c567bf9eaf664280116a8688f63016e6b32db2505908e2bdaca1b6438142f2"}, - {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f5e6ff2bdbb8f4cd3fbe41f99e25bbcd58e3bf9f13d3dd31a11e7917251cc77a"}, - {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2f73e01dc37122325caf079982621262f96d74823c179038a82fddfc50359264"}, - {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bb2c0c80d431c0d03f2c7dbf125150fedd4f0de17366a7ca33f7ccb822391842"}, - {file = "aiohttp-3.14.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3e6fc1a85fa7194a1a7d19f44e8609180f4a8eb5fa4c7ed8b4355f080fad235c"}, - {file = "aiohttp-3.14.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:686b6c0d3911ec387b444ddf5dc62fb7f7c0a7d5186a7861626496a5ab4aff95"}, - {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c6fa4dc7ad6f8109c70bb1499e589f76b0b792baf39f9b017eb92c8a81d0a199"}, - {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:87a5eea1b2a5e21e1ebdbb33ad4165359189327e63fc4e4894693e7f821ac817"}, - {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1c1421eb01d4fd608d88cc8290211d177a58532b55ad94076fb349c5bf467f0a"}, - {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:34b257ec41345c1e8f2df68fa908a7952f5de932723871eb633ecbbff396c9a4"}, - {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:de538791a80e5d862addbc183f70f0158ac9b9bb872bb147f1fd2a683691e087"}, - {file = "aiohttp-3.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f71173be42d3241d428f760122febb748de0623f44308a6f120d0dd9ec572e3"}, - {file = "aiohttp-3.14.1-cp312-cp312-win32.whl", hash = "sha256:ec8dc383ee57ea3e883477dcca3f11b65d58199f1080acaf4cd6ad9a99698be4"}, - {file = "aiohttp-3.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:2aa92c87868cd13674989f9ee83e5f9f7ea4237589b728048e1f0c8f6caa3271"}, - {file = "aiohttp-3.14.1-cp312-cp312-win_arm64.whl", hash = "sha256:2c840c90759922cb5e6dda94596e079a30fb5a5ba548e7e0dc00574703940847"}, - {file = "aiohttp-3.14.1-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:b3a03285a7f9c7b016324574a6d92a1c895da6b978cb8f1deee3ac72bc6da178"}, - {file = "aiohttp-3.14.1-cp313-cp313-android_21_x86_64.whl", hash = "sha256:2a73f487ab8ef5abbb24b7aa9b73e98eaba9e9e031804ff2416f02eca315ccaf"}, - {file = "aiohttp-3.14.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:915fbb7b41b115192259f8c9ae58f3ddc444d2b5579917270211858e606a4afd"}, - {file = "aiohttp-3.14.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:7fb4bdf95b0561a79f259f9d28fbc109728c5ee7f27aff6391f0ca703a329abe"}, - {file = "aiohttp-3.14.1-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:1b9748363260121d2927704f5d4fc498150669ca3ae93625986ee89c8f80dcd4"}, - {file = "aiohttp-3.14.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:86a6dab78b0e43e2897a3bbe15745aa60dc5423ca437b7b0b164c069bf91b876"}, - {file = "aiohttp-3.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4dfd6e47d3c44c2279907607f73a4240b88c69eb8b90da7e2441a8045dfd21da"}, - {file = "aiohttp-3.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:317acd9f8602858dc7d59679812c376c7f0b97bcbbf16e0d6237f54141d8a8a6"}, - {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd869c427324e5cb15195793de951295710db28be7d818247f3097b4ab5d4b96"}, - {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:93b032b5ec3255473c143627d21a69ac74ae12f7f33974cb587c564d11b1066f"}, - {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f234b4deb12f3ad59127e037bc57c40c21e45b45282df7d3a55a0f409f595296"}, - {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9af6779bfb46abf124068327abcdf9ce95c9ef8287a3e8da76ccf2d0f16c28fa"}, - {file = "aiohttp-3.14.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:faccab372e66bc76d5731525e7f1143c922271725b9d38c9f97edcc66266b451"}, - {file = "aiohttp-3.14.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f380468b09d2a81633ee863b0ec5648d364bd17bb8ecfb8c2f387f7ac1faf42c"}, - {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:97e704dcd26271f5bda3fa07c3ce0fb76d6d3f8659f4baa1a24442cc9ba177ca"}, - {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:269b76ac5394092b95bc4a098f4fc6c191c083c3bd12775d1e30e663132f6a09"}, - {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c0b3e614340c889d575451696374c9d17affd54cd607ca0babed8f8c37b9397"}, - {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:5663ee9257cfa1add7253a7da3035a02f31b6600ec48261585e1800a81533080"}, - {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:603a2c834142172ffddc054067f5ec0ca65d57a0aa98a71bc81952573208e345"}, - {file = "aiohttp-3.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cb21957bb8aca671c1765e32f58164cf0c50e6bf41c0bbbd16da20732ecaf588"}, - {file = "aiohttp-3.14.1-cp313-cp313-win32.whl", hash = "sha256:e509a55f681e6158c20f70f102f9cf61fb20fbc382272bc6d94b7343f2582780"}, - {file = "aiohttp-3.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:1ac8531b638959718e18c2207fbfe297819875da46a740b29dfa29beba64355a"}, - {file = "aiohttp-3.14.1-cp313-cp313-win_arm64.whl", hash = "sha256:250d14af67f6b6a1a4a811049b1afa69d61d617fca6bf33149b3ab1a6dbcf7b8"}, - {file = "aiohttp-3.14.1-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:7c106c26852ca1c2047c6b80384f17100b4e439af276f21ef3d4e2f450ae7e15"}, - {file = "aiohttp-3.14.1-cp314-cp314-android_24_x86_64.whl", hash = "sha256:20205f7f5ade7aaec9f4b500549bbc071b046453aed72f9c06dcab87896a83e8"}, - {file = "aiohttp-3.14.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:62a759436b29e677181a9e76bab8b8f689a29cb9c535f45f7c48c9c830d3f8c3"}, - {file = "aiohttp-3.14.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:2964cbf553df4d7a57348da44d961d871895fc1ee4e8c322b2a95612c7b17fba"}, - {file = "aiohttp-3.14.1-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:237651caadc3a59badd39319c54642b5299e9cc98a3a194310e55d5bb9f5e397"}, - {file = "aiohttp-3.14.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:896e12dfdbbab9d8f7e16d2b28c6769a60126fa92095d1ebf9473d02593a2448"}, - {file = "aiohttp-3.14.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d03f281ed22579314ba00821ce20115a7c0ac430660b4cc05704a3f818b3e004"}, - {file = "aiohttp-3.14.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:07eabb979d236335fed927e137a928c9adfb7df3b9ec7aa31726f133a62be983"}, - {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4fe1f1087cbadb280b5e1bb054a4f00d1423c74d6626c5e48400d871d34ecefe"}, - {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:367a9314fdc79dab0fac96e216cb41dd73c85bdca85306ce8999118ba7e0f333"}, - {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a24f677ebe83749039e7bdf862ff0bbb16818ae4193d4ef96505e269375bcce0"}, - {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c83afe0ba876be7e943d2e0ba645809ad441575d2840c895c21ee5de93b9377a"}, - {file = "aiohttp-3.14.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:634e385930fb6d2d479cf3aa66515955863b77a5e3c2b5894ca259a25b308602"}, - {file = "aiohttp-3.14.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eeea07c4397bbc57719c4eed8f9c284874d4f175f9b6d57f7a1546b976d455ca"}, - {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:335c0cc3e3545ce98dcb9cfcb836f40c3411f43fa03dab757597d80c89af8a35"}, - {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:ae6be797afdef264e8a84864a85b196ca06045586481b3df8a967322fd2fa844"}, - {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:8560b4d712474335d08907db7973f71912d3a9a8f1dee992ec06b5d2fe359496"}, - {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7edd08e0a5deb1e8564a2fcd8f4561014a3f05252334671bbf55ddd47db0e5"}, - {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:b6ff7fcee63287ae57b5df3e4f5957ce032122802509246dec1a5bcc55904c95"}, - {file = "aiohttp-3.14.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6ffbb2f4ec1ceaff7e07d43922954da26b223d188bf30658e561b98e23089444"}, - {file = "aiohttp-3.14.1-cp314-cp314-win32.whl", hash = "sha256:a9875b46d910cff3ea2f5962f9d266b465459fe634e22556ab9bd6fc1192eea0"}, - {file = "aiohttp-3.14.1-cp314-cp314-win_amd64.whl", hash = "sha256:af8b4b81a960eeaf1234971ac3cd0ba5901f3cd42eae42a46b4d089a8b492719"}, - {file = "aiohttp-3.14.1-cp314-cp314-win_arm64.whl", hash = "sha256:cf4491381b1b57425c315a56a439251b1bdac07b2275f19a8c44bc57744532ec"}, - {file = "aiohttp-3.14.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:819c054312f1af92947e6a55883d1b66feefab11531a7fc45e0fb9b63880b5c2"}, - {file = "aiohttp-3.14.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:10ee9c1753a8f706345b22496c79fbddb5be0599e0823f3738b1534058e25340"}, - {file = "aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1601cc37baf5750ccacae618ec2daf020769581695550e3b654a911f859c563d"}, - {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4d6e0ac9da31c9c04c84e1c0182ad8d6df35965a85cae29cd71d089621b3ae94"}, - {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9e8f2d660c350b3d0e259c7a7e3d9b7fc8b41210cbcc3d4a7076ff0a5e5c2fdc"}, - {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4691802dda97be727f79d86818acaad7eb8e9252626a1d6b519fedbb92d5e251"}, - {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c389c482a7e9b9dc3ee2701ac46c4125297a3818875b9c305ddb603c04828fd1"}, - {file = "aiohttp-3.14.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fc0cacab7ba4e56f0f81c82a98c09bed2f39c940107b03a34b168bdf7597edd3"}, - {file = "aiohttp-3.14.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:979ed4717f59b8bb12e3963378fa285d93d367e15bcd66c721311826d3c44a6c"}, - {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:38e1e7daaea81df51c952e18483f323d878499a1e2bfe564790e0f9701d6f203"}, - {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:4132e72c608fe9fecb8f409113567605915b83e9bdd3ea56538d2f9cd35002f1"}, - {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:eefd9cc9b6d4a2db5f00a26bc3e4f9acf71926a6ec557cd56c9c6f27c290b665"}, - {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:b165790117eea512d7f3fb22f1f6dad3d55a7189571993eb015591c1401276d1"}, - {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:ed09c7eb1c391271c2ed0314a51903e72a3acb653d5ccfc264cdf3ef11f8269d"}, - {file = "aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:99abd37084b82f5830c635fddd0b4993b9742a66eb746dacf433c8590e8f9e3c"}, - {file = "aiohttp-3.14.1-cp314-cp314t-win32.whl", hash = "sha256:47ddf841cdecc810749921d25606dee45857d12d2ad5ddb7b5bd7eab12e4b365"}, - {file = "aiohttp-3.14.1-cp314-cp314t-win_amd64.whl", hash = "sha256:5e78b522b7a6e27e0b25d19b247b75039ac4c94f99823e3c9e53ae1603a9f7e9"}, - {file = "aiohttp-3.14.1-cp314-cp314t-win_arm64.whl", hash = "sha256:90d53f1609c29ccc2193945ef732428382a28f78d0456ae4d3daf0d48b74f0f6"}, - {file = "aiohttp-3.14.1.tar.gz", hash = "sha256:307f2cff90a764d329e77040603fa032db89c5c24fdad50c4c15334cba744035"}, + {file = "aiohttp-3.14.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:eb0495d778817619273c108784292be161a924b9f5ae5cbbc70a2caa6838250b"}, + {file = "aiohttp-3.14.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c3c200cf9757edd785051dc699c7ecbec22110dbfcb3fefc7a9f9695eda8ea7a"}, + {file = "aiohttp-3.14.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd51ebf9d3a00c074df4ede271023f4d2dba289bcc740b88191872716014e3c5"}, + {file = "aiohttp-3.14.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:134ac5ddcf61c6fad984b9a5727d83492ada43d63471db20fb73042c13fca62f"}, + {file = "aiohttp-3.14.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:70c987b27534f9ae1a723f47ae921571d616da21d3208282bf4c52af5164ac43"}, + {file = "aiohttp-3.14.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1b59533861b70a2185c8f4f350f791f39d64358ef6944ce71c5240c9ec0982c9"}, + {file = "aiohttp-3.14.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1c5281acc88b92396f88c7e1e2748f8466689df22b80170e4f51efa712fb47a8"}, + {file = "aiohttp-3.14.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:48d67b87db6279c044760787eb01f6413032c2e6f3ba1cafaa492b1c8e578479"}, + {file = "aiohttp-3.14.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f53bcd52f585e1ac3e590d61434eb61f9a88c38df041b4ea126d97144344a77b"}, + {file = "aiohttp-3.14.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0fdea2281997af69da84c77ffa6f5938a0285f21fb3887c249d67419ca865b3d"}, + {file = "aiohttp-3.14.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:cda5fd5c95ad7a125a2e8464acc78b98b94c475a3780d6aa0aa157c93f470f4d"}, + {file = "aiohttp-3.14.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:6debfa7312ff9d4c124dc71d72e9a0a4b9e0879e48ba6fcb42bef5c3300289e2"}, + {file = "aiohttp-3.14.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:f4e05329faa0ea1a404b37de4f034fd2c2defcca06a68dc6745e4e56c88e8a48"}, + {file = "aiohttp-3.14.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:a3a8296e7ab5c295f53f1041487cb088e1480775aafbf7fe545d93b770a0f96f"}, + {file = "aiohttp-3.14.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5373dc80ad1aa2fb9ad95c83f24eef418bbda3a61375f128e5b0192e4f3f9b32"}, + {file = "aiohttp-3.14.3-cp310-cp310-win32.whl", hash = "sha256:a3e22975f905b89a55a488c2a08f2fdb2186175349e917d48985cc468a3d4c6e"}, + {file = "aiohttp-3.14.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdd0e2834dce1a26c1bbe26464861e16bbe217042cbff619247c11594472518c"}, + {file = "aiohttp-3.14.3-cp310-cp310-win_arm64.whl", hash = "sha256:eac645b09bcfdf73df7536331f0678c1086ea250981118ddb5199e17ccef72bb"}, + {file = "aiohttp-3.14.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e568e14940c09955aa51f4e645b6daa18a581c5dcfcd73744dcc86a856e3ced3"}, + {file = "aiohttp-3.14.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:54cfcdee2770dac994417cbb0ee1f3eb0e7cb6b30c79bf44f2c02ff79ec5124a"}, + {file = "aiohttp-3.14.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:21c016079415ed3fd676963e9793700a566d85dbbd6bfc564b9b2d209147dcc8"}, + {file = "aiohttp-3.14.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d6088ec9894113802bddb3c09e974929aed2c7b3a8c456219b8aab4481f1a239"}, + {file = "aiohttp-3.14.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:16ea7e24c309fb7c0bbd505d149abe4fe4dccfb8db911db7dbec0921bc889a6f"}, + {file = "aiohttp-3.14.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56f355e79f71aef2a85c80305cc915f894b170dba76de5fe84f6351939b83c06"}, + {file = "aiohttp-3.14.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:18c441d0a8fca6de8d1f546849b9f0ab20d435993e2c5b59562b2fae6be2f929"}, + {file = "aiohttp-3.14.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:53e7b4ce82b54a8bcc71b3b67a5cbd177ca1d7f592cbc92cd38b7349f73482db"}, + {file = "aiohttp-3.14.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f55119f7bf25f49ed210f6096090715da24f2943c62102448915fde3c62877ce"}, + {file = "aiohttp-3.14.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9aa6e61fdf20105c4144e755bd586008ff450791d67b1c8146fdc15959c4d51c"}, + {file = "aiohttp-3.14.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ccd4893707b3e2a13e39c90d43cf80edf2e4d0457935bcc103bf2346214c3f15"}, + {file = "aiohttp-3.14.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b2466434105a4e03113c36ec775cc2ebe6676b62eae326fa670bb607ef788c1c"}, + {file = "aiohttp-3.14.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:ba59d59aba08ac02fc03b0c8983ccd5ee39a199d0552ce9e6d2b4845b34d59ae"}, + {file = "aiohttp-3.14.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ed099d105449c4f9e84f24af203cd131349d4761d8813fa7e02c32e7128cd910"}, + {file = "aiohttp-3.14.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:152516815ef926786a0b6ae2b8f1fd2e0c71582dee0b435636865316fd4891b7"}, + {file = "aiohttp-3.14.3-cp311-cp311-win32.whl", hash = "sha256:a4af35c443e0b1a1bd6a8af3f3485d7fda15c142751a00f3ff8090f0b93346fa"}, + {file = "aiohttp-3.14.3-cp311-cp311-win_amd64.whl", hash = "sha256:e1e74298bab6ee0d6e749ed4fd1901c7e604bdda32c03d787a2cc71c46d0433d"}, + {file = "aiohttp-3.14.3-cp311-cp311-win_arm64.whl", hash = "sha256:03cd2bde3d7f085b64e549c985f4bb928cad7e8ecf5323bfca320db548d81b39"}, + {file = "aiohttp-3.14.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:39aded8c7f3b935b54aab1d8d73c70ec0ee2d3ec3b943e0e86611bc150ba47f5"}, + {file = "aiohttp-3.14.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5bcb6ff3fdab1258a192679ff1a05d44f59626430aa05cd1a9d2447423599228"}, + {file = "aiohttp-3.14.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:617105e2c3018ee38d0c8ce5ee3c84f621a6d8b9f723202aacaff28449ca91ee"}, + {file = "aiohttp-3.14.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f631fe87a6f30df5fbe6d79640b25e4cffb38c31c7fb6f10871517b84b0f8c1a"}, + {file = "aiohttp-3.14.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a94dbaae5ae27bd849c93570669bff91e0510f33a80805738e3de72a7be0447b"}, + {file = "aiohttp-3.14.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8f2f1c4c032c7cedd7d8da6f54c97b70266c6570c3108d3fdffee7188bb70529"}, + {file = "aiohttp-3.14.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ea05e1f97ceea523942d9b2a7d7c0359d781d683d6b043f5943a602b14da4787"}, + {file = "aiohttp-3.14.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:543906c127fb1d929b95076db19b83fa2d46751006ff1e23b093aa5ac4d8db42"}, + {file = "aiohttp-3.14.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0a5ff2dfbb9ce645fa5b8ef3e02c6c0b9cc3f6030ff863d0c51fffc50cb5541b"}, + {file = "aiohttp-3.14.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:041badb8f84396357c4d3ad26de6afd7a32b112f43d3c63045c0c8278cfd2043"}, + {file = "aiohttp-3.14.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:530125ee1163c4219af35dc3aa1206e541e7b31b6efc1a3f93b70a136f65d427"}, + {file = "aiohttp-3.14.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c8653fd547c93a61aadc612007790f5555cdd18946fa48cf45e26d8ea4ea473d"}, + {file = "aiohttp-3.14.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:89176250f686cb9853c0fb7ead90e639e915b84a6f43eedc2a4e7ec21f1037f0"}, + {file = "aiohttp-3.14.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3a26434dafe408229ff3403458ca58de24fb51936504decac49ce6755f77e59d"}, + {file = "aiohttp-3.14.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d1558173930a5a8d3069cee5c92fc91c87c4dbcb099debbb3622053717145a19"}, + {file = "aiohttp-3.14.3-cp312-cp312-win32.whl", hash = "sha256:16100ad3ab8d649fdfbee87602d9d2dcdca9df0b9eda8a1b5fdc0d41f96da559"}, + {file = "aiohttp-3.14.3-cp312-cp312-win_amd64.whl", hash = "sha256:33a2d7c28d33797a2e99923dffa63f83d908a19b6bf26cfe80fa790aa5e1a75a"}, + {file = "aiohttp-3.14.3-cp312-cp312-win_arm64.whl", hash = "sha256:362a3fd481769cac1a824514bcd86fda51c65e8fe6e051099e008fddde6db17c"}, + {file = "aiohttp-3.14.3-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:2e9878ae68e4a5f1c0abe4dd497dbc3d51946f5837b56759e2a02e78fa90ef86"}, + {file = "aiohttp-3.14.3-cp313-cp313-android_21_x86_64.whl", hash = "sha256:f3d2669fe7dec7fc359ecdb5984b29b50d85d5d00f8c1cb61de4f4a24ee42627"}, + {file = "aiohttp-3.14.3-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:cc7cb243a68167172f48c1fd43cee91ec4b1d40cefd190edd43369d1a6bc9c82"}, + {file = "aiohttp-3.14.3-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:78253b573e6ffab5028924fc98bc281aae05445969982a10864bc360dea2016c"}, + {file = "aiohttp-3.14.3-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7041d52c3a7fa20c9e8c182b534704abb19502c8bdcbde7ab23bfda6f642394f"}, + {file = "aiohttp-3.14.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ac74facc01463f138b0da5580329cfcc82818dea5656e83ddcd11268fc12ff80"}, + {file = "aiohttp-3.14.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d6218d92e450824e9b4881f44e8c09f1853b490f9a64130801024a4793b1b3b0"}, + {file = "aiohttp-3.14.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:11fb37ef075669eee52ab1928fbf6e1741fada40409fa309ebde9607a962aebf"}, + {file = "aiohttp-3.14.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:55bdcc472aafe2de4a253045cc128007a64f1e0264fb675791e132ea5edaa3bd"}, + {file = "aiohttp-3.14.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c39846c3aad97a8530c89d7a3869a8f8e9e3762c6ac0504481e5c80948f7e807"}, + {file = "aiohttp-3.14.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5895ef58c4620afe02fa16044f023dc4dafec08158f9d08874a46a7dbc0341b8"}, + {file = "aiohttp-3.14.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fa9467a8113aa69d3d7c55a70ef0b7c636010a40993f3df9d9d0d73b3eb7ef24"}, + {file = "aiohttp-3.14.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d7d2deec16eeedf55f2c7cf75b521ea3856a5177e123844f8fd0f114ce252cb5"}, + {file = "aiohttp-3.14.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dd54d0e8717de95939766febac482ac0474d8ac3b048115f9f2b1d23a16e7db4"}, + {file = "aiohttp-3.14.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:df82f3787c940c94986b34222d59c9e38843fba85139f36e85255a82ad5355a9"}, + {file = "aiohttp-3.14.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:42a67efc36300d052fb4508a53e8b6901b9284b599ae63945c377569c5fcc1e1"}, + {file = "aiohttp-3.14.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7a75aa63cbf9b21cfaf60dc2657e19df2c2867d91707d653fee171ffeedd1371"}, + {file = "aiohttp-3.14.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e92eb8acc45eb6a9f4935071a77edf5b85cc6f8dfad5cd99e97653c26593cdde"}, + {file = "aiohttp-3.14.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b014a6ed7cf912e787149fdc529166d3ceabac23f26efeea3158c9aba2354e7e"}, + {file = "aiohttp-3.14.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3d4f72af88ac2474bb5bca640030320e3d38a0163a1d7533500e87be458eef71"}, + {file = "aiohttp-3.14.3-cp313-cp313-win32.whl", hash = "sha256:5f08ec777f35ee70720233b8b9811d3bb5d728137f30ac91b7457709c3261ac0"}, + {file = "aiohttp-3.14.3-cp313-cp313-win_amd64.whl", hash = "sha256:dff9461ec275f22135650d5ba4b4931a11f3958df7dfbb8db630000d4dee0883"}, + {file = "aiohttp-3.14.3-cp313-cp313-win_arm64.whl", hash = "sha256:ddcac3c6b382e81f1dd0499199d4136b877beb4cb5ef770bbbfba56c4b8f55d2"}, + {file = "aiohttp-3.14.3-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:49f7325beb0f85ef4aef5f48f490269575f83e6e2acad00a1d80b807eb027062"}, + {file = "aiohttp-3.14.3-cp314-cp314-android_24_x86_64.whl", hash = "sha256:e3be98a7c30b8c25d573dafba7171d66dfb05ee6a9070fc46535464ff97700a6"}, + {file = "aiohttp-3.14.3-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:614c61d478b83953e261d02bb2df750f17227cd33ef8002945bf5aebbde21919"}, + {file = "aiohttp-3.14.3-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:1caa7b0d05f3e3a36f87788c59e970a7ee1cefcfcbb924a9f138c4a6551c9cb7"}, + {file = "aiohttp-3.14.3-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:dfa68deb2a443bdaa3ea5297b0699c1464f08aef3812b486d1348eee61b07dc0"}, + {file = "aiohttp-3.14.3-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:e72ee89e28d907a18f46959b4eb0bb06701cc7f8cf4366e00029e2ccfaaf5924"}, + {file = "aiohttp-3.14.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ad4c8b7488d745d2ca4838ebd8ae5ba9b56341d30b1da43640e4ce87f9f49646"}, + {file = "aiohttp-3.14.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:db332af25642007330fca8be5c4d194caf2bea7a7fc84415aff3497af5dfee6b"}, + {file = "aiohttp-3.14.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25bd2708db6bdf6a6630dd37bdcdfcb47c4434d22ac69c64665b802910140b30"}, + {file = "aiohttp-3.14.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:cef89a58e628c4efcac3275c2d68083f82426dcdc89c1492a6f654f9f7ea6ab9"}, + {file = "aiohttp-3.14.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c23ec8ee9d5ab2f5421f9c7fffce208435607af27fd46d4a44e031954352838f"}, + {file = "aiohttp-3.14.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e2667f0bbe7eb6c74eae5e9691441ad186e5845ca3cff63230fc09c4e7514f5d"}, + {file = "aiohttp-3.14.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18cb43369747b2ae007bd2655fb8e63a099c2ff1d207962943636dac989b3147"}, + {file = "aiohttp-3.14.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d77640cc618c1d99fc4f8589c0f24a730adfa54eb1e57ef7bf0c8dfb78da898c"}, + {file = "aiohttp-3.14.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:53e5179d8abb5710f8e83ba207c41c8d1261fcffd4616500e15ca2b7a33be10a"}, + {file = "aiohttp-3.14.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:cd817772b2fcf2b8c0905795318485f9ec16eae60b29feb7f4c77085311637f0"}, + {file = "aiohttp-3.14.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:4e3ac92d90e92773b2362d506068e9a948192bd553e743c5b2429e28527c8661"}, + {file = "aiohttp-3.14.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3f42e9b78301f11c8f861746175d8b9c1ccef713fcad9eab396e2f6db8ed4a22"}, + {file = "aiohttp-3.14.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:9d9edccfe496b476db5f398d97b865e9a6752bcf8aec4eef8390ce20fb64bb41"}, + {file = "aiohttp-3.14.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1c5ec8fb1bcc31a8466f74aaf26c345d5c386fa4bd08a3f0eb9c7a4a3fe8b5bf"}, + {file = "aiohttp-3.14.3-cp314-cp314-win32.whl", hash = "sha256:38901a84da3ce22249f6e860bf8f90d141bcab7da090cc398f8bb58c0e44b7da"}, + {file = "aiohttp-3.14.3-cp314-cp314-win_amd64.whl", hash = "sha256:8b3b60de05f3dcb6f6a00f818bb2ec781cee4de0645f59ccaf99b1d1823b6100"}, + {file = "aiohttp-3.14.3-cp314-cp314-win_arm64.whl", hash = "sha256:1576145bdceeb92382d899751e12743a3a5b8e460a841e3e50543859e54864dc"}, + {file = "aiohttp-3.14.3-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:8800c996b01c2772a783e3e46f3e1abd5823029adca0df54231960de9bfefa5b"}, + {file = "aiohttp-3.14.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:ebe8e504f058fe91223351cecd2d9d6946c9d241bb0250d898ffbdf584cc72b0"}, + {file = "aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:30402d03a7c0ff52bce290b57e564e9079fd9d0cb545c8aba73f86a103162d2e"}, + {file = "aiohttp-3.14.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9fc7b5bfec6573f3ae844f457fdde5adeb713f8b8e4a81ad64fc207b49383716"}, + {file = "aiohttp-3.14.3-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8a5fd34f7f7410d1730d5c2ba873cacb2eed3fede366feb268a70ba22581ed8f"}, + {file = "aiohttp-3.14.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:270d3dace9ca2f10f0da5d8ebe519b7a310fc6112ed916e32df5866df0888553"}, + {file = "aiohttp-3.14.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3ae5b3a59436d089b5395d910121a390feed4d00578eb95a0fd1a329fe963100"}, + {file = "aiohttp-3.14.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2498f0fe69ead802f9675beca44a7c21c62fdaa4ec5145ea1c3ad6edbee29f85"}, + {file = "aiohttp-3.14.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a0dc483c00da8b673abbb367eb6f8d8f4bcec30eb58529ea13cb42e7fd2dfa33"}, + {file = "aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c7d3a97c678d34fc5b59da671ee9cd630096ddc643e7b5a30d54a2a6f3574d3f"}, + {file = "aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:f8fb78a83c9e5f741ca3a68cfb455c1f5bb83b4e7249a3848b3cd78d0a8563b0"}, + {file = "aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:74ab5b6a9fb13e873e5a90946588baecaf488745e1db1a4a5c433f971f035098"}, + {file = "aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:bd52f811e65f6fb634b1047159657c98f52b407f8efec907bcfc09da9a4c0a25"}, + {file = "aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:f0f177d1b195b9e06376cfd7d308d8a1b920909a609d03ac82a8c73bbb16d3b9"}, + {file = "aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:498c6c623134f8e09a3c4e60bcd607a0b4590dd7dbf08dd40851b27cbb520ccb"}, + {file = "aiohttp-3.14.3-cp314-cp314t-win32.whl", hash = "sha256:b304db572b4368edd8dda8a2274f73156fe15558fca4a917cb8a09fc47af5963"}, + {file = "aiohttp-3.14.3-cp314-cp314t-win_amd64.whl", hash = "sha256:b20032766aedf6261c7a566585a40867d092ac03a0d81592d5370ef9b054f99b"}, + {file = "aiohttp-3.14.3-cp314-cp314t-win_arm64.whl", hash = "sha256:2e1161602f45a54de2ce0905243a95f58cb42dcd378402f3697f5e0b21e9d2e7"}, + {file = "aiohttp-3.14.3.tar.gz", hash = "sha256:9491196535a88924a60afd5b5f434b5b203b6cc616250878dbdb223a8f7844bc"}, ] [package.dependencies] @@ -3271,10 +3271,10 @@ files = [ [package.dependencies] numpy = [ - {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, - {version = ">=1.23.5", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, {version = ">=1.21.4", markers = "python_version >= \"3.10\" and platform_system == \"Darwin\" and python_version < \"3.11\""}, {version = ">=1.21.2", markers = "platform_system != \"Darwin\" and python_version >= \"3.10\" and python_version < \"3.11\""}, + {version = ">=1.23.5", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, + {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, ] [[package]] @@ -3437,9 +3437,9 @@ files = [ [package.dependencies] numpy = [ - {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, - {version = ">=1.23.2", markers = "python_version == \"3.11\""}, {version = ">=1.22.4", markers = "python_version < \"3.11\""}, + {version = ">=1.23.2", markers = "python_version == \"3.11\""}, + {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" @@ -5762,4 +5762,4 @@ propcache = ">=0.2.1" [metadata] lock-version = "2.0" python-versions = "^3.10, <3.13" -content-hash = "115608e5d541b2c820a1d6ae0ea554831bb7f1f654476614869a21b0efc6795a" +content-hash = "e18cd34b1a4c6b393c9feb27fd517fc1b11eb3f8d104c3dc82798462153aeacd" diff --git a/packages/examples/cvat/recording-oracle/pyproject.toml b/packages/examples/cvat/recording-oracle/pyproject.toml index 7082c9dc08..5855c2c4d6 100644 --- a/packages/examples/cvat/recording-oracle/pyproject.toml +++ b/packages/examples/cvat/recording-oracle/pyproject.toml @@ -28,6 +28,7 @@ cryptography = "<44.0.0" # human-protocol-sdk -> pgpy dep requires cryptography human-protocol-sdk = "^7.3.1" strenum = "^0.4.15" audio-qe = {path = "libs/audio_qe", develop = true} +aiohttp = ">=3.14.3" [tool.poetry.group.dev.dependencies] pytest = "^9.0.0" From e07e362b49804768c9f0723862369c42c6a64765 Mon Sep 17 00:00:00 2001 From: KirillKirill Date: Fri, 7 Aug 2026 18:17:11 +0300 Subject: [PATCH 31/33] [Human App Frontend] App Redesign (#3980) --- packages/apps/human-app/frontend/.env.example | 4 - packages/apps/human-app/frontend/package.json | 9 - .../frontend/src/api/auth-service.ts | 26 +- .../frontend/src/api/common-api-paths.ts | 7 - .../src/api/hooks/use-access-token-refresh.ts | 41 +- .../signin-background-mobile.png | Bin 0 -> 318852 bytes .../background-images/signin-background.png | Bin 0 -> 1198902 bytes .../signup-background-mobile.png | Bin 0 -> 109526 bytes .../background-images/signup-background.png | Bin 0 -> 499370 bytes .../assets/icons-dark-mode/content-copy.svg | 3 - .../assets/icons-dark-mode/delete-icon.svg | 3 - .../src/assets/icons-dark-mode/edit-icon.svg | 3 - .../icons-dark-mode/filters-button-icon.svg | 3 - .../assets/icons-dark-mode/filters-icon.svg | 3 - .../src/assets/icons-dark-mode/hand.svg | 70 -- .../hcaptcha-disabled-icon.svg | 9 + .../src/assets/icons-dark-mode/hourglass.svg | 5 + .../icons-dark-mode/icons-homepage/logo.svg | 23 - .../icons-homepage/mobile-home-icons.svg | 114 --- .../icons-dark-mode/icons-homepage/user.svg | 26 - .../icons-dark-mode/icons-homepage/work.svg | 25 - .../icons-human-logo/human-logo.svg | 3 - .../icons-navbar/human-logo-navbar.svg | 31 +- .../assets/icons-dark-mode/locker-icon.svg | 3 - .../src/assets/icons-dark-mode/moon.svg | 4 +- .../assets/icons-dark-mode/profile-icon.svg | 26 - .../src/assets/icons-dark-mode/sort-arrow.svg | 3 - .../src/assets/icons-dark-mode/sun.svg | 5 +- .../assets/icons-dark-mode/user-outlined.svg | 3 - .../src/assets/icons-dark-mode/veriff.svg | 17 + .../assets/icons-dark-mode/work-header.svg | 30 - .../src/assets/icons-dark-mode/work.svg | 12 - .../frontend/src/assets/icons/chat.svg | 4 - .../src/assets/icons/checkmark-icon.svg | 5 +- .../src/assets/icons/content-copy.svg | 3 - .../frontend/src/assets/icons/delete-icon.svg | 3 - .../frontend/src/assets/icons/edit-icon.svg | 3 - .../src/assets/icons/ethereum-icon.svg | 15 + .../src/assets/icons/filters-button-icon.svg | 3 - .../src/assets/icons/filters-icon.svg | 3 - .../frontend/src/assets/icons/hand.svg | 79 -- .../assets/icons/hcaptcha-disabled-icon.svg | 9 + .../frontend/src/assets/icons/hcaptcha.svg | 46 + .../frontend/src/assets/icons/hourglass.svg | 5 + .../assets/icons/icons-homepage/discord.svg | 3 - .../src/assets/icons/icons-homepage/logo.svg | 34 - .../icons/icons-homepage/mobile-header.svg | 114 --- .../icons-homepage/mobile-home-icons.svg | 114 --- .../src/assets/icons/icons-homepage/user.svg | 37 - .../src/assets/icons/icons-homepage/work.svg | 36 - .../icons/icons-human-logo/human-logo.svg | 3 - .../icons/icons-navbar/human-logo-navbar.svg | 32 +- .../frontend/src/assets/icons/locker-icon.svg | 3 - .../frontend/src/assets/icons/logout.svg | 4 + .../frontend/src/assets/icons/moon.svg | 4 +- .../src/assets/icons/polygon-icon.svg | 14 + .../src/assets/icons/profile-icon.svg | 32 - .../frontend/src/assets/icons/sort-arrow.svg | 3 - .../frontend/src/assets/icons/sun.svg | 5 +- .../frontend/src/assets/icons/triangle.svg | 3 + .../frontend/src/assets/icons/user-filled.svg | 3 - .../src/assets/icons/user-outlined.svg | 3 - .../src/assets/icons/user-secondary.svg | 15 - .../frontend/src/assets/icons/veriff.svg | 10 + .../frontend/src/assets/icons/work-header.svg | 36 - .../src/assets/icons/work-secondary.svg | 14 - .../frontend/src/assets/icons/work.svg | 7 - packages/apps/human-app/frontend/src/main.tsx | 24 +- .../components/wallet-connect-modal.tsx | 72 -- .../auth-web3/context/web3-auth-context.tsx | 24 - .../hooks/use-wallet-connect-modal.tsx | 15 - .../modules/auth-web3/hooks/use-web3-auth.tsx | 12 - .../hooks/use-web3-authenticated-user.tsx | 14 - .../auth-web3/providers/require-web3-auth.tsx | 44 - .../src/modules/auth/context/auth-context.tsx | 1 - .../frontend/src/modules/auth/hooks/index.ts | 2 - .../modules/auth/providers/require-auth.tsx | 14 +- .../components/governance-banner.tsx | 4 +- .../src/modules/homepage/components/chat.tsx | 32 +- .../choose-sign-up-account-type.tsx | 38 - .../homepage/components/home-container.tsx | 26 - .../src/modules/homepage/components/index.ts | 1 - .../homepage/components/logo-section.tsx | 43 +- .../homepage/components/operator-sign-in.tsx | 89 -- .../homepage/components/operator-sign-up.tsx | 91 -- .../homepage/components/sign-in-section.tsx | 42 +- .../modules/homepage/components/welcome.tsx | 32 - .../homepage/components/worker-sign-in.tsx | 21 - .../homepage/components/worker-sign-up.tsx | 93 -- .../src/modules/homepage/hooks/index.ts | 1 - .../modules/homepage/hooks/use-web3-signin.ts | 50 - .../homepage/services/homepage.service.ts | 28 - .../src/modules/homepage/views/home.page.tsx | 61 +- .../src/modules/operator/hooks/index.ts | 1 - .../modules/operator/hooks/use-get-keys.ts | 51 - .../operator/profile/components/index.ts | 4 - .../profile/components/operator-info.tsx | 128 --- .../profile/components/operator-stats.tsx | 73 -- .../components/profile-disable-button.tsx | 55 -- .../components/profile-enable-button.tsx | 55 -- .../modules/operator/profile/hooks/index.ts | 3 - .../profile/hooks/use-disable-operator.ts | 21 - .../profile/hooks/use-enable-operator.ts | 21 - .../operator/profile/hooks/use-get-stats.ts | 29 - .../src/modules/operator/profile/index.ts | 1 - .../modules/operator/profile/profile.page.tsx | 56 -- .../src/modules/operator/profile/schemas.ts | 11 - .../profile/services/profile.service.ts | 60 -- .../src/modules/operator/profile/types.ts | 13 - .../src/modules/signin/worker/index.ts | 1 + .../modules/signin/worker/sign-in-form.tsx | 103 +- .../modules/signin/worker/sign-in.page.tsx | 165 +++- .../signin/worker/use-sign-in-mutation.ts | 10 +- .../src/modules/signin/worker/use-sign-in.tsx | 2 + .../signin/worker/verification-flow.tsx | 128 +++ .../signin/worker/verify-user.page.tsx | 89 ++ .../components/add-keys/add-keys-form.tsx | 51 - .../add-keys/edit-existing-keys-form.tsx | 131 --- .../add-keys/edit-pending-keys-form.tsx | 99 -- .../add-keys/existing-keys-form.tsx | 70 -- .../components/add-keys/existing-keys.tsx | 121 --- .../operator/components/add-keys/index.ts | 1 - .../components/add-keys/pending-keys-form.tsx | 58 -- .../operator/components/add-stake/buttons.tsx | 49 - .../operator/components/add-stake/index.ts | 2 - .../components/add-stake/stake-form.tsx | 101 -- .../modules/signup/operator/hooks/index.ts | 6 - .../hooks/use-add-stake-mutation-state.ts | 19 - .../signup/operator/hooks/use-add-stake.ts | 82 -- .../operator/hooks/use-edit-existing-keys.ts | 75 -- .../operator/hooks/use-get-stacked-amount.ts | 30 - .../hooks/use-human-token-decimals.ts | 25 - .../signup/operator/hooks/use-web3-signup.ts | 24 - .../src/modules/signup/operator/index.ts | 1 - .../add-stake-amount-call-arguments-schema.ts | 29 - .../eth-kv-store-values-mutation-schema.ts | 117 --- .../modules/signup/operator/schema/index.ts | 2 - .../__tests__/staked-amount-formatter.test.ts | 40 - .../modules/signup/operator/utils/index.ts | 2 - .../signup/operator/utils/sort-form.ts | 18 - .../operator/utils/staked-amount-formatter.ts | 12 - .../signup/operator/views/add-keys.page.tsx | 46 - .../signup/operator/views/add-stake.page.tsx | 111 --- .../operator/views/connect-wallet.page.tsx | 57 -- .../views/edit-existing-keys-success.page.tsx | 88 -- .../modules/signup/operator/views/index.ts | 5 - .../operator/views/set-up-operator.page.tsx | 36 - .../modules/signup/services/signup.service.ts | 48 +- .../worker/hooks/use-sign-up-mutation.ts | 5 +- .../worker/hooks/use-sign-up-worker.tsx | 1 + .../worker/views/sign-up-worker.page.tsx | 289 ++++-- .../smart-contracts/EthKVStore/config.ts | 46 - .../EthKVStore/eth-kv-store-get-keys.ts | 38 - .../EthKVStore/eth-kv-store-get-kyc-data.ts | 43 - .../EthKVStore/eth-kv-store-set-bulk.ts | 28 - .../HMToken/hm-token-allowance.ts | 23 - .../HMToken/hm-token-approve.ts | 22 - .../HMToken/hm-token-decimals.ts | 20 - .../Staking/staking-get-staked-tokens.ts | 21 - .../smart-contracts/Staking/staking-stake.ts | 21 - .../smart-contracts/get-contract-address.ts | 14 - .../src/modules/smart-contracts/types.ts | 8 - .../email-verification-form-container.tsx | 135 ++- .../components/email-verification-process.tsx | 8 +- .../email-verification-success-message.tsx | 57 +- .../resend-verification-email-form.tsx | 90 -- .../hooks/use-email-verification-mutation.ts | 8 +- .../hooks/use-email-verification-token.ts | 2 +- .../hooks/use-resend-email-router-params.ts | 2 +- .../worker/email-verification/pages/index.ts | 2 - ...worker-email-verification-process.page.tsx | 2 +- .../pages/worker-verify-email.page.tsx | 2 +- .../components/breadcrumbs.tsx | 42 + .../hcaptcha-labeling/components/index.ts | 4 - .../components/user-stats-accordion.tsx | 59 +- .../components/user-stats-details.tsx | 60 +- .../components/user-stats-drawer.tsx | 132 +-- .../hcaptcha-labeling/enable-labeler.page.tsx | 113 ++- .../hcaptcha-labeling.page.tsx | 289 ++++-- .../hooks/enable-hcaptcha-labeling.ts | 8 +- .../modules/worker/hooks/use-get-oracles.ts | 8 +- .../worker/hooks/use-register-address.ts | 8 +- .../components/explore-tasks-dialog.tsx | 96 ++ .../components/hcaptcha-widget.tsx | 267 +++++ .../worker/jobs-discovery/components/index.ts | 4 - .../components/oracle-job-card.tsx | 313 ++++++ .../components/oracles-list.tsx | 57 ++ .../components/oracles-table-desktop.tsx | 55 -- .../components/oracles-table-item-mobile.tsx | 60 -- .../oracles-table-job-types-select.tsx | 41 - .../components/oracles-table.tsx | 69 -- .../worker/jobs-discovery/helpers/index.ts | 1 - .../helpers/is-hcaptcha-oracle.spec.ts | 39 - .../helpers/is-hcaptcha-oracle.ts | 4 - .../should-navigate-to-registration.spec.ts | 4 + .../worker/jobs-discovery/hooks/index.ts | 1 - .../hooks/use-oracles-table-columns.tsx | 63 -- .../hooks/use-select-oracle-navigation.ts | 46 - .../jobs-discovery/jobs-discovery.page.tsx | 114 ++- .../available-jobs-filter-modal.tsx | 120 --- .../available-jobs/available-jobs-view.tsx | 17 - .../available-jobs-job-type-filter.tsx | 41 - .../available-jobs-network-filter.tsx | 36 - .../available-jobs-reward-amount-sort.tsx | 43 - .../desktop/available-jobs-table-desktop.tsx | 99 +- .../jobs/available-jobs/components/index.ts | 3 - ...vailable-jobs-assign-job-button-mobile.tsx | 39 - .../components/mobile/available-jobs-card.tsx | 186 ++++ .../mobile/available-jobs-list-mobile.tsx | 113 +-- ...ailable-jobs-reward-amount-sort-mobile.tsx | 47 - .../mobile/available-jobs-table-mobile.tsx | 38 - .../available-jobs/components/mobile/index.ts | 3 +- .../available-jobs/hooks/use-assign-job.ts | 4 +- .../hooks/use-available-jobs-filter-modal.tsx | 21 - .../hooks/use-get-available-jobs-columns.tsx | 140 +-- .../hooks/use-get-available-jobs-data.ts | 25 +- .../worker/jobs/available-jobs/index.ts | 2 - .../components/escrow-address-search-form.tsx | 103 -- .../worker/jobs/components/evm-address.tsx | 17 +- .../modules/worker/jobs/components/index.ts | 5 +- .../worker/jobs/components/jobs-tab-panel.tsx | 20 - .../worker/jobs/components/more-button.tsx | 47 +- .../jobs/components/my-jobs-table-actions.tsx | 11 +- ...buse-modal.tsx => report-abuse-dialog.tsx} | 180 ++-- .../worker/jobs/components/reward-amount.tsx | 30 +- .../worker/jobs/components/sorting.tsx | 102 -- .../src/modules/worker/jobs/hooks/index.ts | 2 - .../worker/jobs/hooks/use-get-all-networks.ts | 15 - .../worker/jobs/hooks/use-get-my-jobs-data.ts | 36 +- .../hooks/use-job-types-oracles-table.tsx | 17 - .../jobs/hooks/use-jobs-filter-store.tsx | 38 +- .../jobs/hooks/use-jobs-notifications.tsx | 4 +- .../jobs/hooks/use-my-jobs-filter-store.tsx | 67 +- .../frontend/src/modules/worker/jobs/index.ts | 1 - .../src/modules/worker/jobs/jobs.page.tsx | 142 --- .../my-jobs/components/desktop/columns.tsx | 175 ---- .../jobs/my-jobs/components/desktop/index.ts | 1 - .../desktop/my-jobs-expires-at-sort.tsx | 43 - .../components/desktop/my-jobs-filters.tsx | 209 ++++ .../desktop/my-jobs-job-type-filter.tsx | 36 - .../desktop/my-jobs-network-filter.tsx | 32 - .../desktop/my-jobs-reward-amount-sort.tsx | 43 - .../desktop/my-jobs-status-filter.tsx | 30 - .../components/desktop/my-jobs-table.tsx | 153 +-- .../components/desktop/status-chip.tsx | 27 - .../components/desktop/status-filter.tsx | 73 ++ .../jobs/my-jobs/components/mobile/index.ts | 2 - .../components/mobile/my-jobs-card-mobile.tsx | 163 +++ .../mobile/my-jobs-expires-at-sort-mobile.tsx | 47 - .../mobile/my-jobs-filter-modal.tsx | 136 --- .../mobile/my-jobs-job-type-filter-mobile.tsx | 31 - .../components/mobile/my-jobs-list-mobile.tsx | 230 +---- .../mobile/my-jobs-network-filter-mobile.tsx | 32 - .../my-jobs-reward-amount-sort-mobile.tsx | 47 - .../mobile/my-jobs-status-filter-mobile.tsx | 30 - .../jobs/my-jobs/components/time-until.tsx | 71 ++ .../my-jobs/hooks/use-get-my-jobs-columns.tsx | 142 +++ .../hooks/use-my-jobs-filter-modal.tsx | 21 - .../jobs/my-jobs/hooks/use-refresh-jobs.ts | 3 - .../jobs/my-jobs/hooks/use-resign-job.ts | 4 +- .../worker/jobs/my-jobs/my-jobs-view.tsx | 13 - .../worker/jobs/my-jobs/my-jobs.page.tsx | 88 ++ .../__tests__/get-chip-status-color.test.ts | 26 - .../my-jobs/utils/get-chip-status-color.ts | 18 - .../worker/jobs/my-jobs/utils/index.ts | 1 - .../frontend/src/modules/worker/jobs/types.ts | 2 + .../oracle-registration/registration-form.tsx | 53 +- .../oracle-registration/registration.page.tsx | 107 +- .../profile/components/buttons/index.ts | 2 - .../buttons/register-address-btn.tsx | 3 +- .../components/buttons/start-idv-btn.tsx | 26 - .../profile/components/custom-text-field.tsx | 42 - .../identity-verification-control.tsx | 238 ++++- .../worker/profile/components/index.ts | 1 - .../profile/components/modal-states.tsx | 64 -- .../components/profile-bottom-tray.tsx | 51 + .../profile/components/profile-data.tsx | 151 ++- .../components/wallet-connect-done.tsx | 101 -- .../components/wallet-connection-control.tsx | 34 +- .../src/modules/worker/profile/hooks/index.ts | 1 - .../profile/hooks/use-start-idv-mutation.ts | 6 +- .../worker/profile/hooks/use-start-idv.ts | 3 +- .../hooks/use-worker-profile-status.tsx | 11 - .../worker/profile/types/profile-types.ts | 5 - .../worker/profile/views/profile.page.tsx | 198 +++- .../reset-password/hooks/reset-password.ts | 6 +- .../reset-password-success.page.tsx | 102 +- .../reset-password/reset-password.page.tsx | 155 ++- .../send-reset-link/hooks/send-reset-link.ts | 5 +- .../send-reset-link-success.page.tsx | 182 ++-- .../send-reset-link/send-reset-link.page.tsx | 155 ++- .../worker/services/oracles.service.ts | 37 +- .../drawer-menu-items-operator.tsx | 25 - .../drawer-menu-items-worker.tsx | 42 - .../components/drawer-menu-items/index.ts | 2 - .../frontend/src/router/components/footer.tsx | 97 +- .../frontend/src/router/components/index.ts | 1 - .../router/components/layout/helpers/index.ts | 1 - .../layout/helpers/is-drawer-item.ts | 5 - .../protected/bottom-menu-items-list.tsx | 107 -- .../layout/protected/desktop-aside-bar.tsx | 177 ++++ .../layout/protected/drawer-navigation.tsx | 129 --- .../components/layout/protected/index.ts | 1 - .../layout/protected/jobs-switcher-mobile.tsx | 66 ++ .../components/layout/protected/layout.tsx | 158 ++- .../components/layout/protected/navbar.tsx | 114 +-- .../layout/protected/page-header.tsx | 70 -- .../layout/protected/top-menu-items-list.tsx | 103 -- .../components/layout/unprotected/layout.tsx | 30 +- .../components/layout/unprotected/navbar.tsx | 181 ++-- .../use-mobile-layout-background.ts | 32 + .../src/router/hooks/use-is-main-page.ts | 8 + .../frontend/src/router/router-paths.ts | 41 +- .../human-app/frontend/src/router/router.tsx | 89 +- .../human-app/frontend/src/router/routes.tsx | 158 +-- .../shared/components/data-entry/checkbox.tsx | 44 - .../shared/components/data-entry/input.tsx | 3 +- .../components/data-entry/multi-select.tsx | 158 --- .../data-entry/{password => }/password.tsx | 14 +- .../components/data-entry/radio-button.tsx | 52 - .../shared/components/data-entry/select.tsx | 65 -- .../shared/components/data-entry/slider.tsx | 40 - .../shared/components/expiration-modal.tsx | 64 +- .../shared/components/hcaptcha/h-captcha.tsx | 4 +- .../src/shared/components/ui/alert.tsx | 8 +- .../src/shared/components/ui/base-drawer.tsx | 74 ++ .../src/shared/components/ui/chain-icon.tsx | 33 + .../src/shared/components/ui/chip.tsx | 1 + .../src/shared/components/ui/chips.tsx | 16 - .../components/ui/connect-wallet-btn.tsx | 25 - .../ui/copy-to-clipboard-button.tsx | 60 ++ .../shared/components/ui/dark-mode-switch.tsx | 54 +- .../components/ui/empty-placeholder.tsx | 13 - .../src/shared/components/ui/icons.tsx | 391 +++++--- .../src/shared/components/ui/list-item.tsx | 34 - .../src/shared/components/ui/loader.tsx | 2 +- .../shared/components/ui/modal/base-modal.tsx | 92 ++ .../components/ui/modal/global-modal.tsx | 1 + .../src/shared/components/ui/no-records.tsx | 7 +- .../shared/components/ui/optional-text.tsx | 14 - .../components/ui/page-card/back-button.tsx | 31 + .../ui/page-card/page-card-error.tsx | 34 +- .../ui/page-card/page-card-loader.tsx | 24 +- .../components/ui/page-card/page-card.tsx | 135 +-- .../shared/components/ui/page-card/styles.ts | 26 +- .../src/shared/components/ui/profile/index.ts | 1 - .../ui/profile/profile-list-item.tsx | 95 -- .../components/ui/responsive-overlay.tsx | 54 + .../shared/components/ui/success-label.tsx | 17 - .../src/shared/components/ui/table-button.tsx | 2 +- .../components/ui/table/table-header-cell.tsx | 74 -- .../ui/table/table-header-menu/filtering.tsx | 92 -- .../ui/table/table-header-menu/sorting.tsx | 55 -- .../ui/table/table-query-context.tsx | 66 -- .../components/ui/text-header-with-icon.tsx | 35 - .../human-app/frontend/src/shared/consts.ts | 3 +- .../shared/contexts/background/background.tsx | 88 -- .../src/shared/contexts/background/index.ts | 2 - .../background/use-background-context.tsx | 12 - .../shared/contexts/browser-auth-provider.ts | 21 +- .../color-mode/color-mode-settings.ts | 5 +- .../shared/contexts/color-mode/color-mode.tsx | 9 +- .../shared/contexts/generic-auth-context.tsx | 12 +- .../homepage-state/homepage-state.tsx | 37 - .../shared/contexts/homepage-state/index.ts | 2 - .../homepage-state/use-homepage-state.tsx | 12 - .../shared/contexts/jwt-expiration-check.tsx | 35 +- .../shared/contexts/wallet-connect/index.ts | 2 - .../wallet-connect/require-wallet-connect.tsx | 37 - .../wallet-connect/use-connected-wallet.tsx | 14 - .../apps/human-app/frontend/src/shared/env.ts | 7 - .../frontend/src/shared/hooks/index.ts | 2 +- .../src/shared/hooks/use-combine-pages.ts | 23 +- .../hooks/use-handle-main-nav-icon-click.tsx | 18 +- .../hooks/use-is-hcaptcha-labeling-page.ts | 7 - .../src/shared/hooks/use-is-user-verified.tsx | 11 + .../src/shared/hooks/use-notification.tsx | 34 +- .../frontend/src/shared/i18n/en.json | 271 ++--- .../providers/notifications-provider.tsx | 6 +- .../frontend/src/shared/schemas/index.ts | 2 - .../src/shared/schemas/url-domain-schema.ts | 14 - .../shared/schemas/validate-address-schema.ts | 14 - .../src/shared/styles/color-palette.ts | 31 +- .../shared/styles/create-table-dark-mode.tsx | 1 + .../src/shared/styles/dark-color-palette.ts | 41 +- .../frontend/src/shared/styles/dark-theme.ts | 8 +- .../frontend/src/shared/styles/theme.ts | 39 +- .../frontend/src/shared/styles/typography.ts | 104 +- .../src/shared/types/browser-auth-provider.ts | 7 +- .../frontend/src/shared/types/entity.type.ts | 13 + .../frontend/src/shared/types/global.type.ts | 15 + yarn.lock | 928 +----------------- 392 files changed, 6524 insertions(+), 12064 deletions(-) delete mode 100644 packages/apps/human-app/frontend/src/api/common-api-paths.ts create mode 100644 packages/apps/human-app/frontend/src/assets/background-images/signin-background-mobile.png create mode 100644 packages/apps/human-app/frontend/src/assets/background-images/signin-background.png create mode 100644 packages/apps/human-app/frontend/src/assets/background-images/signup-background-mobile.png create mode 100644 packages/apps/human-app/frontend/src/assets/background-images/signup-background.png delete mode 100644 packages/apps/human-app/frontend/src/assets/icons-dark-mode/content-copy.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons-dark-mode/delete-icon.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons-dark-mode/edit-icon.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons-dark-mode/filters-button-icon.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons-dark-mode/filters-icon.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons-dark-mode/hand.svg create mode 100644 packages/apps/human-app/frontend/src/assets/icons-dark-mode/hcaptcha-disabled-icon.svg create mode 100644 packages/apps/human-app/frontend/src/assets/icons-dark-mode/hourglass.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons-dark-mode/icons-homepage/logo.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons-dark-mode/icons-homepage/mobile-home-icons.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons-dark-mode/icons-homepage/user.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons-dark-mode/icons-homepage/work.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons-dark-mode/icons-human-logo/human-logo.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons-dark-mode/locker-icon.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons-dark-mode/profile-icon.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons-dark-mode/sort-arrow.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons-dark-mode/user-outlined.svg create mode 100644 packages/apps/human-app/frontend/src/assets/icons-dark-mode/veriff.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons-dark-mode/work-header.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons-dark-mode/work.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons/chat.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons/content-copy.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons/delete-icon.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons/edit-icon.svg create mode 100644 packages/apps/human-app/frontend/src/assets/icons/ethereum-icon.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons/filters-button-icon.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons/filters-icon.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons/hand.svg create mode 100644 packages/apps/human-app/frontend/src/assets/icons/hcaptcha-disabled-icon.svg create mode 100644 packages/apps/human-app/frontend/src/assets/icons/hcaptcha.svg create mode 100644 packages/apps/human-app/frontend/src/assets/icons/hourglass.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons/icons-homepage/discord.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons/icons-homepage/logo.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons/icons-homepage/mobile-header.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons/icons-homepage/mobile-home-icons.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons/icons-homepage/user.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons/icons-homepage/work.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons/icons-human-logo/human-logo.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons/locker-icon.svg create mode 100644 packages/apps/human-app/frontend/src/assets/icons/logout.svg create mode 100644 packages/apps/human-app/frontend/src/assets/icons/polygon-icon.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons/profile-icon.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons/sort-arrow.svg create mode 100644 packages/apps/human-app/frontend/src/assets/icons/triangle.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons/user-filled.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons/user-outlined.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons/user-secondary.svg create mode 100644 packages/apps/human-app/frontend/src/assets/icons/veriff.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons/work-header.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons/work-secondary.svg delete mode 100644 packages/apps/human-app/frontend/src/assets/icons/work.svg delete mode 100644 packages/apps/human-app/frontend/src/modules/auth-web3/components/wallet-connect-modal.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/auth-web3/context/web3-auth-context.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/auth-web3/hooks/use-wallet-connect-modal.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/auth-web3/hooks/use-web3-auth.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/auth-web3/hooks/use-web3-authenticated-user.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/auth-web3/providers/require-web3-auth.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/auth/hooks/index.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/homepage/components/choose-sign-up-account-type.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/homepage/components/home-container.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/homepage/components/index.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/homepage/components/operator-sign-in.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/homepage/components/operator-sign-up.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/homepage/components/welcome.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/homepage/components/worker-sign-in.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/homepage/components/worker-sign-up.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/homepage/hooks/index.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/homepage/hooks/use-web3-signin.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/homepage/services/homepage.service.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/operator/hooks/index.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/operator/hooks/use-get-keys.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/operator/profile/components/index.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/operator/profile/components/operator-info.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/operator/profile/components/operator-stats.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/operator/profile/components/profile-disable-button.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/operator/profile/components/profile-enable-button.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/operator/profile/hooks/index.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/operator/profile/hooks/use-disable-operator.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/operator/profile/hooks/use-enable-operator.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/operator/profile/hooks/use-get-stats.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/operator/profile/index.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/operator/profile/profile.page.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/operator/profile/schemas.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/operator/profile/services/profile.service.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/operator/profile/types.ts create mode 100644 packages/apps/human-app/frontend/src/modules/signin/worker/verification-flow.tsx create mode 100644 packages/apps/human-app/frontend/src/modules/signin/worker/verify-user.page.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/components/add-keys/add-keys-form.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/components/add-keys/edit-existing-keys-form.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/components/add-keys/edit-pending-keys-form.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/components/add-keys/existing-keys-form.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/components/add-keys/existing-keys.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/components/add-keys/index.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/components/add-keys/pending-keys-form.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/components/add-stake/buttons.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/components/add-stake/index.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/components/add-stake/stake-form.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/hooks/index.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/hooks/use-add-stake-mutation-state.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/hooks/use-add-stake.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/hooks/use-edit-existing-keys.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/hooks/use-get-stacked-amount.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/hooks/use-human-token-decimals.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/hooks/use-web3-signup.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/index.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/schema/add-stake-amount-call-arguments-schema.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/schema/eth-kv-store-values-mutation-schema.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/schema/index.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/utils/__tests__/staked-amount-formatter.test.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/utils/index.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/utils/sort-form.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/utils/staked-amount-formatter.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/views/add-keys.page.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/views/add-stake.page.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/views/connect-wallet.page.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/views/edit-existing-keys-success.page.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/views/index.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/signup/operator/views/set-up-operator.page.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/smart-contracts/EthKVStore/config.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/smart-contracts/EthKVStore/eth-kv-store-get-keys.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/smart-contracts/EthKVStore/eth-kv-store-get-kyc-data.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/smart-contracts/EthKVStore/eth-kv-store-set-bulk.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/smart-contracts/HMToken/hm-token-allowance.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/smart-contracts/HMToken/hm-token-approve.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/smart-contracts/HMToken/hm-token-decimals.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/smart-contracts/Staking/staking-get-staked-tokens.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/smart-contracts/Staking/staking-stake.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/smart-contracts/get-contract-address.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/smart-contracts/types.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/email-verification/components/resend-verification-email-form.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/email-verification/pages/index.ts create mode 100644 packages/apps/human-app/frontend/src/modules/worker/hcaptcha-labeling/components/breadcrumbs.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/hcaptcha-labeling/components/index.ts create mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs-discovery/components/explore-tasks-dialog.tsx create mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs-discovery/components/hcaptcha-widget.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs-discovery/components/index.ts create mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs-discovery/components/oracle-job-card.tsx create mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs-discovery/components/oracles-list.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs-discovery/components/oracles-table-desktop.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs-discovery/components/oracles-table-item-mobile.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs-discovery/components/oracles-table-job-types-select.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs-discovery/components/oracles-table.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs-discovery/helpers/is-hcaptcha-oracle.spec.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs-discovery/helpers/is-hcaptcha-oracle.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs-discovery/hooks/index.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs-discovery/hooks/use-oracles-table-columns.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs-discovery/hooks/use-select-oracle-navigation.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/available-jobs-filter-modal.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/available-jobs-view.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/components/available-jobs-job-type-filter.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/components/available-jobs-network-filter.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/components/available-jobs-reward-amount-sort.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/components/index.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/components/mobile/available-jobs-assign-job-button-mobile.tsx create mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/components/mobile/available-jobs-card.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/components/mobile/available-jobs-reward-amount-sort-mobile.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/components/mobile/available-jobs-table-mobile.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/hooks/use-available-jobs-filter-modal.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/available-jobs/index.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/components/escrow-address-search-form.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/components/jobs-tab-panel.tsx rename packages/apps/human-app/frontend/src/modules/worker/jobs/components/{report-abuse-modal.tsx => report-abuse-dialog.tsx} (51%) delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/components/sorting.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/hooks/use-get-all-networks.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/hooks/use-job-types-oracles-table.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/index.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/jobs.page.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/components/desktop/columns.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/components/desktop/index.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/components/desktop/my-jobs-expires-at-sort.tsx create mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/components/desktop/my-jobs-filters.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/components/desktop/my-jobs-job-type-filter.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/components/desktop/my-jobs-network-filter.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/components/desktop/my-jobs-reward-amount-sort.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/components/desktop/my-jobs-status-filter.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/components/desktop/status-chip.tsx create mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/components/desktop/status-filter.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/components/mobile/index.ts create mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/components/mobile/my-jobs-card-mobile.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/components/mobile/my-jobs-expires-at-sort-mobile.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/components/mobile/my-jobs-filter-modal.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/components/mobile/my-jobs-job-type-filter-mobile.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/components/mobile/my-jobs-network-filter-mobile.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/components/mobile/my-jobs-reward-amount-sort-mobile.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/components/mobile/my-jobs-status-filter-mobile.tsx create mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/components/time-until.tsx create mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/hooks/use-get-my-jobs-columns.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/hooks/use-my-jobs-filter-modal.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/my-jobs-view.tsx create mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/my-jobs.page.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/utils/__tests__/get-chip-status-color.test.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/utils/get-chip-status-color.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/jobs/my-jobs/utils/index.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/profile/components/buttons/index.ts delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/profile/components/buttons/start-idv-btn.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/profile/components/custom-text-field.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/profile/components/modal-states.tsx create mode 100644 packages/apps/human-app/frontend/src/modules/worker/profile/components/profile-bottom-tray.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/profile/components/wallet-connect-done.tsx delete mode 100644 packages/apps/human-app/frontend/src/modules/worker/profile/hooks/use-worker-profile-status.tsx delete mode 100644 packages/apps/human-app/frontend/src/router/components/drawer-menu-items/drawer-menu-items-operator.tsx delete mode 100644 packages/apps/human-app/frontend/src/router/components/drawer-menu-items/drawer-menu-items-worker.tsx delete mode 100644 packages/apps/human-app/frontend/src/router/components/drawer-menu-items/index.ts delete mode 100644 packages/apps/human-app/frontend/src/router/components/layout/helpers/index.ts delete mode 100644 packages/apps/human-app/frontend/src/router/components/layout/helpers/is-drawer-item.ts delete mode 100644 packages/apps/human-app/frontend/src/router/components/layout/protected/bottom-menu-items-list.tsx create mode 100644 packages/apps/human-app/frontend/src/router/components/layout/protected/desktop-aside-bar.tsx delete mode 100644 packages/apps/human-app/frontend/src/router/components/layout/protected/drawer-navigation.tsx create mode 100644 packages/apps/human-app/frontend/src/router/components/layout/protected/jobs-switcher-mobile.tsx delete mode 100644 packages/apps/human-app/frontend/src/router/components/layout/protected/page-header.tsx delete mode 100644 packages/apps/human-app/frontend/src/router/components/layout/protected/top-menu-items-list.tsx create mode 100644 packages/apps/human-app/frontend/src/router/components/layout/unprotected/use-mobile-layout-background.ts create mode 100644 packages/apps/human-app/frontend/src/router/hooks/use-is-main-page.ts delete mode 100644 packages/apps/human-app/frontend/src/shared/components/data-entry/checkbox.tsx delete mode 100644 packages/apps/human-app/frontend/src/shared/components/data-entry/multi-select.tsx rename packages/apps/human-app/frontend/src/shared/components/data-entry/{password => }/password.tsx (81%) delete mode 100644 packages/apps/human-app/frontend/src/shared/components/data-entry/radio-button.tsx delete mode 100644 packages/apps/human-app/frontend/src/shared/components/data-entry/select.tsx delete mode 100644 packages/apps/human-app/frontend/src/shared/components/data-entry/slider.tsx create mode 100644 packages/apps/human-app/frontend/src/shared/components/ui/base-drawer.tsx create mode 100644 packages/apps/human-app/frontend/src/shared/components/ui/chain-icon.tsx delete mode 100644 packages/apps/human-app/frontend/src/shared/components/ui/chips.tsx delete mode 100644 packages/apps/human-app/frontend/src/shared/components/ui/connect-wallet-btn.tsx create mode 100644 packages/apps/human-app/frontend/src/shared/components/ui/copy-to-clipboard-button.tsx delete mode 100644 packages/apps/human-app/frontend/src/shared/components/ui/empty-placeholder.tsx delete mode 100644 packages/apps/human-app/frontend/src/shared/components/ui/list-item.tsx create mode 100644 packages/apps/human-app/frontend/src/shared/components/ui/modal/base-modal.tsx delete mode 100644 packages/apps/human-app/frontend/src/shared/components/ui/optional-text.tsx create mode 100644 packages/apps/human-app/frontend/src/shared/components/ui/page-card/back-button.tsx delete mode 100644 packages/apps/human-app/frontend/src/shared/components/ui/profile/index.ts delete mode 100644 packages/apps/human-app/frontend/src/shared/components/ui/profile/profile-list-item.tsx create mode 100644 packages/apps/human-app/frontend/src/shared/components/ui/responsive-overlay.tsx delete mode 100644 packages/apps/human-app/frontend/src/shared/components/ui/success-label.tsx delete mode 100644 packages/apps/human-app/frontend/src/shared/components/ui/table/table-header-cell.tsx delete mode 100644 packages/apps/human-app/frontend/src/shared/components/ui/table/table-header-menu/filtering.tsx delete mode 100644 packages/apps/human-app/frontend/src/shared/components/ui/table/table-header-menu/sorting.tsx delete mode 100644 packages/apps/human-app/frontend/src/shared/components/ui/table/table-query-context.tsx delete mode 100644 packages/apps/human-app/frontend/src/shared/components/ui/text-header-with-icon.tsx delete mode 100644 packages/apps/human-app/frontend/src/shared/contexts/background/background.tsx delete mode 100644 packages/apps/human-app/frontend/src/shared/contexts/background/index.ts delete mode 100644 packages/apps/human-app/frontend/src/shared/contexts/background/use-background-context.tsx delete mode 100644 packages/apps/human-app/frontend/src/shared/contexts/homepage-state/homepage-state.tsx delete mode 100644 packages/apps/human-app/frontend/src/shared/contexts/homepage-state/index.ts delete mode 100644 packages/apps/human-app/frontend/src/shared/contexts/homepage-state/use-homepage-state.tsx delete mode 100644 packages/apps/human-app/frontend/src/shared/contexts/wallet-connect/require-wallet-connect.tsx delete mode 100644 packages/apps/human-app/frontend/src/shared/contexts/wallet-connect/use-connected-wallet.tsx delete mode 100644 packages/apps/human-app/frontend/src/shared/hooks/use-is-hcaptcha-labeling-page.ts create mode 100644 packages/apps/human-app/frontend/src/shared/hooks/use-is-user-verified.tsx delete mode 100644 packages/apps/human-app/frontend/src/shared/schemas/url-domain-schema.ts delete mode 100644 packages/apps/human-app/frontend/src/shared/schemas/validate-address-schema.ts diff --git a/packages/apps/human-app/frontend/.env.example b/packages/apps/human-app/frontend/.env.example index 8a13a7385e..a605cc5028 100644 --- a/packages/apps/human-app/frontend/.env.example +++ b/packages/apps/human-app/frontend/.env.example @@ -17,10 +17,6 @@ VITE_HMT_DAILY_SPENT_LIMIT=0 # hCaptcha annotation tool VITE_H_CAPTCHA_EXCHANGE_URL=replace_me VITE_H_CAPTCHA_LABELING_BASE_URL=replace_me -VITE_H_CAPTCHA_ORACLE_ADDRESS=replace_me -VITE_H_CAPTCHA_ORACLE_ANNOTATION_TOOL=hcaptcha -VITE_H_CAPTCHA_ORACLE_ROLE=hcaptcha -VITE_H_CAPTCHA_ORACLE_TASK_TYPES=image_points,image_boxes # Other VITE_HUMAN_PROTOCOL_HELP_URL=https://docs.humanprotocol.org/ diff --git a/packages/apps/human-app/frontend/package.json b/packages/apps/human-app/frontend/package.json index 2c41645461..0d76ca8e37 100644 --- a/packages/apps/human-app/frontend/package.json +++ b/packages/apps/human-app/frontend/package.json @@ -30,7 +30,6 @@ "@mui/x-date-pickers": "^9.9.0", "@reown/appkit": "^1.8.20", "@reown/appkit-adapter-wagmi": "^1.8.20", - "@synaps-io/verify-sdk": "^4.0.45", "@tanstack/react-query": "^5.91.3", "@wagmi/core": "^3.4.0", "date-fns": "^4.1.0", @@ -40,13 +39,11 @@ "lodash": "^4.18.1", "material-react-table": "3.0.1", "notistack": "^3.0.1", - "prop-types": "^15.8.1", "query-string": "^9.0.0", "react": "^19.2.6", "react-dom": "^19.2.6", "react-hook-form": "^7.71.1", "react-i18next": "^15.1.0", - "react-imask": "^7.4.0", "react-number-format": "^5.4.5", "react-router-dom": "^7.18.1", "serve": "^14.2.6", @@ -58,23 +55,17 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", - "@tanstack/eslint-plugin-query": "^5.60.1", - "@tanstack/react-query-devtools": "^5.59.16", "@types/lodash": "^4.17.24", "@types/node": "^22.10.5", - "@types/prop-types": "^15", "@types/react": "^19.2.15", "@types/react-dom": "^19.2.3", - "@vercel/style-guide": "^6.0.0", "@vitejs/plugin-react": "^4.2.1", "eslint": "^10.1.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-react-hooks": "^5.2.0", - "eslint-plugin-react-refresh": "^0.5.2", "globals": "^17.7.0", - "husky": "^9.1.6", "jsdom": "^29.1.1", "prettier": "^3.8.1", "typescript": "^6.0.2", diff --git a/packages/apps/human-app/frontend/src/api/auth-service.ts b/packages/apps/human-app/frontend/src/api/auth-service.ts index 177a98c600..f54a1a49c5 100644 --- a/packages/apps/human-app/frontend/src/api/auth-service.ts +++ b/packages/apps/human-app/frontend/src/api/auth-service.ts @@ -7,7 +7,6 @@ import { } from '@/shared/schemas'; import { type BrowserAuthProvider } from '@/shared/types/browser-auth-provider'; import { type HttpApiClient } from './http-api-client'; -import { commonApiPaths } from './common-api-paths'; export interface AuthProvider { getAccessToken: () => Promise; @@ -15,12 +14,9 @@ export interface AuthProvider { } const apiPaths = { - worker: { - signIn: { - path: '/auth/signin', - }, - }, -} as const; + signIn: '/auth/signin', + refresh: '/auth/refresh', +}; export class AuthService implements AuthProvider { private readonly browserAuthProvider: BrowserAuthProvider = @@ -31,16 +27,16 @@ export class AuthService implements AuthProvider { constructor(private readonly httpClient: HttpApiClient) {} - async signIn(data: SignInDto): Promise { + async signIn(data: SignInDto): Promise { const res = await this.httpClient.post( - apiPaths.worker.signIn.path, + apiPaths.signIn, { successSchema: authTokensSuccessResponseSchema, body: data, } ); - this.browserAuthProvider.signIn(res, 'web2'); + return res; } async getAccessToken(): Promise { @@ -70,12 +66,6 @@ export class AuthService implements AuthProvider { } async refreshAccessToken(): Promise { - const authType = this.browserAuthProvider.getAuthType(); - - if (!authType) { - throw new Error('Auth type not found'); - } - if (!AuthService.refreshPromise) { AuthService.refreshPromise = this.fetchTokenRefresh(); } @@ -88,7 +78,7 @@ export class AuthService implements AuthProvider { throw new Error('Failed to refresh access token'); } - browserAuthProvider.signIn(tokens, authType); + browserAuthProvider.signIn(tokens); } private async fetchTokenRefresh(): Promise { @@ -100,7 +90,7 @@ export class AuthService implements AuthProvider { try { const response = await this.httpClient.post( - commonApiPaths.auth.refresh.path, + apiPaths.refresh, { body: { refresh_token: refreshToken, diff --git a/packages/apps/human-app/frontend/src/api/common-api-paths.ts b/packages/apps/human-app/frontend/src/api/common-api-paths.ts deleted file mode 100644 index ed28ab1e4b..0000000000 --- a/packages/apps/human-app/frontend/src/api/common-api-paths.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const commonApiPaths = { - auth: { - refresh: { - path: '/auth/refresh', - }, - }, -} as const; diff --git a/packages/apps/human-app/frontend/src/api/hooks/use-access-token-refresh.ts b/packages/apps/human-app/frontend/src/api/hooks/use-access-token-refresh.ts index 2f74d18fd5..3a7b272677 100644 --- a/packages/apps/human-app/frontend/src/api/hooks/use-access-token-refresh.ts +++ b/packages/apps/human-app/frontend/src/api/hooks/use-access-token-refresh.ts @@ -2,34 +2,28 @@ import { useMutation } from '@tanstack/react-query'; import { useNavigate } from 'react-router-dom'; import { useAuth } from '@/modules/auth/hooks/use-auth'; import { browserAuthProvider } from '@/shared/contexts/browser-auth-provider'; -import type { AuthType } from '@/shared/types/browser-auth-provider'; -import { useWeb3Auth } from '@/modules/auth-web3/hooks/use-web3-auth'; import { routerPaths } from '@/router/router-paths'; import { authService } from '../authorized-http-api-client'; +type RefreshAccessTokenParams = { + throwExpirationModalOnSignOut?: boolean; +}; + export function useAccessTokenRefresh() { const navigate = useNavigate(); - const { signOut: web2SignOut, user: web2User } = useAuth(); - - const { signOut: web3SignOut, user: web3User } = useWeb3Auth(); + const { user, signOut } = useAuth(); const mutation = useMutation({ - mutationFn: async ({ - authType, - throwExpirationModalOnSignOut = true, - }: { - authType: AuthType; - throwExpirationModalOnSignOut?: boolean; - }) => { + mutationFn: async (params?: RefreshAccessTokenParams) => { + const throwExpirationModalOnSignOut = + params?.throwExpirationModalOnSignOut ?? true; + try { await authService.refreshAccessToken(); } catch (error) { console.error(error); - if (authType === 'web2' && web2User) { - web2SignOut({ throwExpirationModal: false }); - } - if (authType === 'web3' && web3User) { - web3SignOut({ throwExpirationModal: false }); + if (user) { + signOut({ throwExpirationModal: false }); } browserAuthProvider.signOut({ triggerSignOutSubscriptions: throwExpirationModalOnSignOut, @@ -45,7 +39,16 @@ export function useAccessTokenRefresh() { }); return { - refreshAccessToken: mutation.mutate, - refreshAccessTokenAsync: mutation.mutateAsync, + refreshAccessToken: ( + params?: RefreshAccessTokenParams, + options?: Parameters[1] + ) => { + mutation.mutate(params, options); + }, + refreshAccessTokenAsync: ( + params?: RefreshAccessTokenParams, + options?: Parameters[1] + ) => mutation.mutateAsync(params, options), + isRefreshingAccessToken: mutation.isPending, }; } diff --git a/packages/apps/human-app/frontend/src/assets/background-images/signin-background-mobile.png b/packages/apps/human-app/frontend/src/assets/background-images/signin-background-mobile.png new file mode 100644 index 0000000000000000000000000000000000000000..6fff015e749963d1e5b7de15e17d61e7dd5f9fbf GIT binary patch literal 318852 zcmV(=K-s^EP)^NzQD*v#EM<9~CaWwp zSN`6oyW3^DoGxkT+q78DQ(o!XuWfpJJEqNcnNFv3sUXbcyP4>| zigeX$`?g4Z-=*m+OQ%Df+O|z)S*FRP^m_5V)nuBUzkb#CZPVp&O&7g>y2P{YtBvlpPg;+&K5w217B6*Lxk9U%r>q!K*Y+vT3w=+Mrdq?U8&Wl!rCMt; znN;cJ>n<&q>vXJnMx~z5RM*#}`qHN5%_3dSZQAdTsaj68hH>rl`6RV{pRR+xu5Qy@ z*PfTTewWg7xB{)^)F!%QR?D zT(4RyU2EMmerD{y)nbu`R?oBJruCmbyVdJ9>y_?bpK-qG8R*`--oNIaGkrJDKGXXL z{oh6Rq07>JY8{)}Yc-usbsweocE{d-(b}A@sa)!F^`5!bsMU4!+DEybXRGfi=QBNb zT^sAI&*2-j6;h#V<_rv4$6TM+51IFJ-(1sbGE1e_^;&Zl^lbDT3SA$2g8S|D-Hq;T zuJg-2m`@gR7wgEDdib{abrP_t5M5by{`a^e(-& z8`tBi|IK(d`g^fhL?Tz?wblcLc*>)witec$TulQh+y%Emp| zYflzhi$>R9YQGNJ3z^niw-#qm&rTaq%c;LlWb2aFTK7=M_NDrqhEjV`zvDaEl%3ws z=M7p%&QqtoT~vAc&F?l^^D;Gh&eQ2!XSGf1dEtAUO?9>}jc%(?Py5{Wh+Seo?{uHr z&0Nb;rSqlt`)^iL+YJ7$Ptdi?es%f|osV92`gm=;|BrgM(?WMR*=SFk(~a)sBD=u8 zzR1RHX8Mep{nGf^es{M?yTds>pK96WNm^>1FQ;R|pigwopT0b$?;h{;o~!miuXCsS z{{Q{I|2VX|05%XGT*B0H4jRg;V^#h^(yBmhdbyVIy-f3Qhi67!tQa%fIEM^jR3ioz{J!`^Fhyj5@8! zY=(hvwMH_&teF$pj6XU!7~hMov(Pi{~o?n>m!h1KlvQ#IdYb8xHiP>EdAV$H)TG9oF_YEodqm>cfsLZ zZQu#)rprZY&$XYfE za0;A`9F8S+8B`tc2Yw91xt(nS$3zdU@UZ zeB=&h7uw5{^maUW{U*82*Zx`OW8yP;)js1at{>MJw6vEko9j8e?ayhZXRjlb*b%2* zL6q+IOdwF<949(2N#7|uH!IR!cC6Iv-mY>E{UJSUR$dF9f2sB7ym8hivMZczf^mYu z9HY-c!|0zK4Q4(J98A0w1}D$QO{xPz@WA0A`XNeV5la@gz%y<1o`ntEwLUs>$%cs* zjSM9|cePsjGl+cHWMmz!BdQ{z8ojQRhpv^m=;PAycy>g{!Sd$RhWPGJAJa)5c%`2o zUK=g=F0J*s811DNyillz(IT>|7J2&k!>u-9FORLrP8;i@L)qvWA3l6Y+mCB!7(_ip zl2c_rY{r}0xtz-)afWI|i*rR*yWL4YUpdl$etxw9th7Ft^U2qKsWTgYHtG#lSsBAl z544d{Jj!_-j#mOF8~tb3&eGSX7kwhv zGOLAz{urD0NP15V`>`3saDCjK5nPp^* zSr{07U#&k!Wgf`~K-r8Uu#*g;K0wzer+*G(M)n|EqCGRW@h6(BWzZJNbR9Vo)$9HS zIYORGLAI=Qxtw@b7k!Qnuby?OXT*15=*TLF?oTqXQ|+0oBeTMo>FTs!GCiYu%)HyW zwezZoUv;nv5_pCs*_zJSL~G7DB%o%4NKk773U`){^4b}CI1j$#-xXD+pj zJ^|mvuV-&u>@e^fJfoA=kLOCD$63#0v?{%pEVk0~sLvN?2bnTdol@g==EK?Xa@zvCpfNL&g?8ZvRSQk z-s3*E>xCEG!C$%1{??gj&PFsQW!Q?%a>f%*`|C+RE7DTWpK$s1W+TLA?!blnnBU7u zXg?i}M?09)nZQnaQWx+d8}ZBT>OgJRkpxx_e8@a;#Mr!3-T5rHIazq0J}6V0WrfcR zsK$#N+o#vFZ5sOu^aUHj^DO?|zxeAP-_y9cyl!XDs>6gQ)kR@&_5Aejoi@`lA`%u( z(Ppk2ooFE^TDWO7^=3VtkKSxVMx_>>^p-T9=%pN^q?rz79EwQo4de8rTUQ$lj08sE zqJuas1>@-NKp7bOf}7CiwGC0qM6gw#mg}h@6T?r6{$HQ9U=5Iz(!LK zlTlbLNUH}!Q$+b3_>~+C(Ke9@aLq)2jtAXysc832UR!B=DJzdL-0v>w;qhM1uy&@f zTy6XyHaBwuBwy?E(?Oph1KHyEhIB8d!|#r#!H$v#2;8&XZqn=9Te`hnYpn_!AWTL{ zbgQW1<>f_df{{#Kw`yM6>9D?y9ZThB^749#NVOx%#&P#HuC2c8NED%Gg>lF;-hWA3 zUF%iRLeq4S+36wovc5AJ4x(fNK<62XxvvcGlL7de|u5bIEBZwgYF$WUcNWEFe?u+&nAy>ZYr zc#o3Rvlew7&KHNo{x;O4_ZKqm1S&-tK>?0}-x1t7iya7JCO(f7G9LYJR=18;c_vdC zK1c3)cI7mlF?JWYs35{7n26%{>40Lljj2TZs6lVCwQ9qfkUSANo zgEUmYk*$p)4gq7@>ss>7Lg!o0OzYZf-7wU>9j&fwI`l` zJ$-r6Au4rmg3yTRTSNJZJg>(4&$_Qp&TFw+*z4ciX#-r3>Erh|0sZu~qt{{z4&D2^ z%PJt6vf@2W0z%wuOT#&?dz3ie%nln&6F847g*5jFq@e5MnX_3-!G-(>1hCS&H9Ghk z;5lKcJhJW`>m?Y=0~?-dqv4bs_37DRG|!4c?{2pKEO2pWpL*}LVN(wN_d(CLa1>kl z5VBbdKZMrL7Q^3rhw1f2J_ZzQ*demGD&8|V5(js#buE=MrR7q4u8g`!A*1nG^%R1F zi8g$zz41}0J9RA#WesGP2o$b%V(dZoJ^`wsg2~i@KsiR4WJ^SbJ3+FgA=zZ(SQ-WF8Q}C+%i`tn!qhs$o^J%gQ2Vff@P`Ivr`nUdSJ{pschCf+wNhqc z2R4c9{-SewRTem81YN+;LVTnPN4W$}s~sDLsCL0`f7qw>c5Nt$Yr@0l zistt!+Wqju2VKj>&S;8ZA?4O#z|pV~mP;U{+L;;A1(Eyf%fYz%azmt77`x}Bx|rM~ zAEI0ap1Kav4h6Hr{^a)pKegJx*S58B=iu(%8V63)TPVE)8T6P ztZ`&NIFh}{XwQ}$Xc=d%)A7{Xz^oTjZ*nq>J|o># zLGA)zR`Ox0Egiyxjy6keQTqN({La( zojBuYa6J5;OanAR1_gY#%p)jq!Ix;={O*$!}Hi?17n3H*N zJ!i5RvUtv()?@kIgQDGo4HkI$OnaWfa6@66;;CNGK6l-KsCzt1{KvT_=P8L1wH_|q zPXYwXTu)PhVY~+Muyso{Iood_6_d;PFduRyh^(}4W zoPpiR=5Pvk+m&r+k3(S%C$lkVQXtj^d1E=R9Hiyd)CK9e&OVv-PC--K08>*pDScMf zsw1&47W3R^0Z96Ay1LwO)#n1U1I-qHp^V}R3qh+`IdaPE2#j@d7*pdn5&5_tQIaB8 z_Gp1)Cqq?44=idcuU?i@FK+M5V`2lu!WggSf4vcM|DBD@CdU91wb#1nYF7C@hkami zY{2and`@YUuzU=_-Gd&4yd4j4Qh?R(ZSbe_Ft{upsk|dbaC{eMDo0#6w}%h6dT@Ii z4j=_mJx4!T)Mx55Sa;{hbLxzSNcgD8Dh|-?-Hp@2wbIS2Y7{Q}7O_5;bL~U=>n~rl z$Q13m^zwE!ehVx?yv*8gj0$}=o0lk;g78!ae>y9TqjOMTY=PAqOD@@=`rW>lL!y8O zjCAtz;kq$i4Rsl99wGsZ-R+H_!D()0l9^W8xC=o=Z*PK9h?3;g>PzovcQNN$h$fV! z==r|9?6vv&^mwyKpOhVOz#czPq&vBIdeR!@SwN0BD58CeplutKkdrp{R$1Wfx-@hF z993(dQD0c-KptddX4FF_WfYKY{Ch`@Y*0QI19x>zr?e3RMwz)V*`}kO)BZ@ITK7a2 zdTi|Mm$SnAmzvXjmizl)Dj7oN0&6lP(^2Hsc}U7Gr>j+@p+x+X@$A)&Yf`Qu0re5RYL7b$()yjXHx2#i zdNDx!?&6;n-p6D+E;6&`V`jrO^WNsXw?SG89yN-<&-8tBL4L5;I49IHz}aoIY$Gyf z4FqU=g#G|^jiZJ7eFOoqD$ zULtb?5(G+z5!Ln%?#2hC7^-mwHnhW-DHSSc|B0aB!^nDS(m{4)HWgf?;PrYTa0c}n z97JP-ZtpkF4uJ2liJV28!(yYKpDx}Htf4lL9a(25nWxCJGu8TLwqF>0(1e4W_IkZC z!?FPqr$#3T4`>|6v{_Fbn9dft;{+!LMrf{vZ#m19WXX~!-g+oFEt{BV56b97hJPuT==tT@UX|}(YNNjGcXk-ypOqt&cwlEO%;IM5 z=oTYS8b(I3`mjoSN9#eCJt#W*sA6^)*dZV(8O@0niiZP;mm6oEnvKMF89vj7-pC7c z-#j{CBj6eW6z>14vJe~(4|XM^v|1@zSCNV6+B7;x0fMQt2H`L>Z;BcB-Ua++R%V_B z3{ge|P4wZc;MAJ=L;Z!?Nw2k{-hk60>hERrD4K7!V4j1bh^P+{!Q+ftZS*gnj(X3= zhmuW2^g5YkW>isVhLLeNg+UG&nP*X%uJ=WC9-`mNNMs<==DT4ikzwGtc@`5n?a3H1 zXG7`NwA6$2SvM4Ub;wr2yZO1Dw0CUOu*~1+!f;j&6l7F-;2Ws4%S2#96g$`b2;s9+ zdsSv<){Nf1my?8w$YF5ArzmZ$y`jriATqda;-WEh;JUX%Wqn{|!482EjG%k|ubD4*mUYwztJez#3m6@PnG&U1>e?5kO@_`rd2 zIu05rwrlUPM+>d%p!F}>FcgiV)b-}h20y6P!SrFB-V5mzula8!=&x%c5Fy|qtKqwV zXE=l4?EEih)5g9iztxH&v(WQ~#V7|jy}Q-_);1UzZ$9UYLDZg^D!4Oa3uq0eKeDHA z!u%aaP(Rht+ki9cd}K(#Mmm; zH8a7cMCk)8ySlNbAXCV>k2VMghKShA)C@3&Py|^EIg)~uOy`>a-YKy~8JS)Z6(fBb`tzs}SwAa%0KTkUt5I~9xNB=u&99$G~Qm8??` zMgq3)O<6yflmntM7hHALzo}0GTj6vjX8RRpJz?R1nAqzkr^tz|T(^jTc0P~wUCMD# zKc0?R+DU<^Gm7=bBp~V#oHsHG_60?E&Is=(K+gWZ|F1s`m$5KsmW7L90kvG~lPRV{ z%R{T}M0njWVxF**@c0~bA{_qiG!wjC50)&1bdL>q6&5y?fye6~PJ8!gaA(d;fI+@~ zi6XZ?w{8Q@+T7?GR7{nfQSoRJ2FpQzVQMAV9EPCQX2Cm>0dd&!su>G%nT^We;+?Lo z*Cqx1E{XbP0i9{n9u8*}r*G}V%wW>NAtRut#1DHQ4Nf-Jdo9}i{o1bu-@VX}q3?Qr zp&-3+8cS~j+~$>Fn+x|n!O&%_UyIX&Ylc}RGK=6v2r##QNMn^rqD_zW(I8OOn`zL#rmr@I<+9OC|L~~ z60#6;SM>Ug(rSv^XWiqQvedGSOaX_my;<9^I9)%s&gACvh-96ijr9{)GrWf&qcNRa z`%%vn13;iaU_w@~SykVN2GB)swMX9c_d8wx-~Mk;igfin%E+L2odX%pfzBRIo7w}B zDwzjagzE`%M*MuexgE3qA>b2?C&9*~3PS+|C1+vhI8u~N=^SA?;0!}%3Q~f=(0hH_ z@pb$I1BGKa*B1vq)8*QZg<|sc{hBdoMQ%i4(0f}sH)?05_F}B+CbEcFen;b+&;tc~_snEtFU=5r6vOy4NIXsNED$)U;<*#3LA`K~mi7bArmjawt&d&{ zf<=O40%?;kYS&i&+yB%5U}ln`{5)!T7?A0F;^#x5pSa3FQ6CT-HN!c zMGCI6|7ml#aZ`xXVb@5Ch(H7{knVy3KK`&VOl7REBYm4W5;(nr#VZniP;pg}a+6)s z!$%o;qBMPn3pPY_u)6d>j)Ju|w`&)R$evugYI-w~s4JXF-&PZ|24LX8)dyzU@1fcc=#CPi`ii8lDj)1=giEXsW(pUjD_r+f;asWU!R`6#>H5>z+P~4 zVa4E#w(EIhX>HI_bsAi}PcEod&IV*Tw6-Z%S5|V8Lq{8 zZL$Gm1rAficTf|cwkF4Sd!xYM(rHg?Efo|j^t|>I#`T(4V7q_(G4)z+hzz+4yhFf9 z)987?08GZdg4WO^y#rNR-`%G>Wxr&fSstuIe&4(oq_s|0oguPv98VfECX6y!1etp` zM6(=GW-xs+N3*6wyLqzozxTq$8*Tj6_QqKxpG*B_r{|K%_*B4ZMKV=-u(57^{jLYm z^W^L!pgZ?O$;n6kCwFZJn6~a(!;o!e>WvILY>mMzqW2)}@^Xv2=kP{MIhc9@QNu9FqX<%nf??>kP!RwD+2%OsQnrDb2R5po zuH;ZEL+P2H)y&sCOjh3ixGwjMKn5Vg)3d7NRNiFtdA?hvyOsV@1It23*3W@`*cVGV z4d70K=%WHv`Yw*zqxT>0^m^^#6_ovxpVLa814HjdD1ZYK*&_lC>aswNWW%ntW|f2K zy)xhBW@;G!c)YkM-70{55|RM4`or%Y{F;T9eaU{uc@C{1;HybBf~#bIYn(Rpf7LIQ zQT#0qC~$5f!scS*?TULhjGMN0hCqk4IndWI$Qh|R#X9)c#VopUiH5RBr6bL49FY`d z7&0OmU>D=hBP93U(l01O^dD^fC`F7~%QBTi>NaZLbc1*d%~! z?4TK%Dr#{1#VV|ZG!A?a zz`j|oBh5Awt%dgbs?Ag=y5G7m)m*zMpibhtqG(-2lh!1f$=LN~t#FXL%7tm*6K5&< z*_K`qdc1T^Q1VEX=h`)7Baje+Myt)IA~!t?h84A|fmg^l@u0@psTr~PH%qS*ST7_5 zt-3y^meIeYoAom2twr>1RHm5r0r|mR>7u`5tIwb&a{qYm-V$IR3?W(A#hClVdvi{~ z5W)pr;5rmUnq+zy_P(th<(e&IIC5~m&tzVi3QQIXp1zo2v=nhQL3t$urV$fE1Z&MT zwHdXCKFz^yuTe;+C>X?w zaPj$E2gY+YQp_>l&Lnis`mD2ofZ0=+I-DCSz!1|*gcCFE+@yeb=B*VAiuWYJ=ZUU! zB3bU2Y%+~(CZczOJe~{D>`DR8$w6WeOE}N23u%3R{hR;l$o<0)KiGj}ZqSWPA{s|q zvu+GWL2+(IN<2Xkuu&gH*ZKWp+9~iMv+5Mk6dTzCoE%w@)6pUVGd<6OOachG?(F

3j?!OrVdU9`|SyZ|lU^ZRb<-AM3|L^}{T0@M|^Zuee{r$%W@4fxG zaf9qynR}miMq=8&GUE$l?N0oGdrqcRv#!wR4S9Nfd#@*fH$e@LkaK!>F9`IKrB6S9 zO&@-vOyO{HMtA34uFQMF^+7T{=(ajrb<;V3GGk7*q48Om8sWi45<&20)Wo_OBhtZzY>c0=Wp~=Pu8Huv-P@}> z95H+taQMvN-)<&UgnmBOPO&fsupCV53?J!YF^dXJL30~wCBg1V?uod+7i6=OCthyc zi!jl>!x-WKlctkNtR{ss0*uFAh7m@@YO^xk6b>{rOdOw^%;>13pP`Qak=EH(;V$^I znFm?iBP<9~Rj9v{;JRN0A-%kuZE)W+gVu0M9z6ku93rLlA#%MVH--sD+l`ss8R-Et za5CeXWHl4_JA_0EU_!~ECqjkN+y<*kD`F>qqtq4$fOFv>17!iIkk!1i=`d8slZ=2O z67Jszq>d&l4ktxnu9@eJ1PRO|GlE)rBw8PISYX z@f#b>Bh0Hl3!;P$2L{y+ivLw~_Hes0^ajtJ?-^t)?v~M{cD%MO>e0uN-kDNkW8nf~ zMiXo!FkXy+o836TdF%rhjKQ7t?A~6k>G;deJtgdA_6$awMmiTPZ2+!r3~XVE5&2g^ z`oM@z#(EgW!4z0B0oraU029$;IAN*CKvbi=1?$gwXzBUUx?HIl(Sx#BIxEV}p6gr~ zrTE(CX*B$q>qpK)TwFaVBNvqRyYJKK)069DR^GsH5^PZrC8(MfE_!p0fQ=v~7z@aQ z!G-?8sR?-u8w;B1j#tBGy_r~(D2Bsq8;jx?bUy>u@^UrwlU0$$05g?cC`5EfmgIEE zo?Ji5hv+3Dy99J~N zcj=-#dadm3Suhc7Nsa-}yK947#G62TZ?<#6LlmurtbEvLZ+Gt5f#&M|o<0kRzls37 za<7b#5o&2;=F0!B6}S?NgB;8j6Yu8;G%}y*;;;U1|MwsBW-MfnQ3walv^E#ndT%7W z4K)O(r^kI1-!j_WGe_p&Y*`A*bm;hle4;YL_A{e|@nt;lAJDE;14v6NW70Kmrcn;PQkq}3e!kFh@s>g0LTlYw(2!{&QoyFEXDjV^vz zNM+^o4Hd~<@p#37!v5acYCsU>jp`!`w5sdiY_4!EqV;~f`|bBpTPWi}_JUIAQLw{- ztZ}9bf8hWJQb$c@F+^uMj)c&)HY}FA_)E|lb)MS6MASwHJ9V&hCqq@RFv$?<=7Ylv5Z;^=Uv_R1PVmu=f<@^WBUMB|@QO_U>i(HMIbEM!(f<&FKKA~zaQtSuXa?1DGDD5`@_vE3>BC@2>+x7eIS*)tjB z{*A^NrHn|J_&`RX>PCgwri}(P>L+w)-rUZ-34i%XMfVR&7rVX+O2as_S-UY3bAIKFeNj(Vtu{(4zjp+22p9b zm%+_Kyw3O7gcJi!a%3uOdy2>y)NU+7lX>72CMHQFsISXRE6=O4p2K{o4TfgiMU-T4^Svec4qIXE% zSdqCL8KQxFzA?tZdn-2sOc^b5HNYjVIpl^WEB1aLy&?GsPdR&bG#Wh!E{I!R>JU*r zK|>!pO&CxX9GMZ$64EBC+uJm0QUpq5`r6}@NoYS2IGk16o2!0fiACy|)T8u2=a-!` z_Ie}*^rN#g6AtG-4b7_#k_z-$YMn)7g^*rKD!vrx=^G$pq9{IBF_&UGOt~_O=Yz9n z8FOVlrI`W91YDdMQV6#5s)LwPzQYIH3k)<;b(-^N+$B)LF{IXH9&7@}w*`iChGUoF z&&{<4mN&5+N@GI8T(<3(zxmbuMnC-S&hS|w8$y)67*l2Gi01?&PH|fq&nq*p1@p-U;CgnGWLF7xZn&{NRUs>SbrtMLr0-@H!p+NYeIh{G z;n|yv!nvuz5D&l^aZG~Rs!48Xm6zw*Ycp4tb-fJHH=IYiJ_faM5&q<6yI^%>j%I)p zqQNK}Ry4gu&56&Y7*Do|;o6c#>b)-t9Oh|ug*vfHTb$hfi;TNh5J`nVt21&M1V52SKy;B=cSE~i#0<;?0nF26}!H2d%~7P*#(&mxrSrwL7Hca-QFmec7VT(O?yZ8nO80b^12bF))1lpY z>}D)wv(r9kj>N^rJ*~))2z%1INO*eFbx|ZvL7!w#;s7S@ThbpLOpN#K za%;$lOd%TeqHn@R1^BHA_1nya@OeN4FzVBvbR1uu}w{dt)%@!k=UKT ztPQY)ar)?s*gigl#EIZmjO}FX_O=SEJFkb)VI&890aYeP$nEiBM@sRR+K4;vN5y4y zlX5$z&i8}y!$IJbT-PW9HV)QV<2{$T){sl2sqNm04m3oB3<9RYuC*>A?jrL3m5k$ z6N|8gC?M7Si6ea+1BEIZ1HISkoX8Ul(Y<&$(zJE8p|p~twNlckEmOKES83xTjX|X4 z$h?=qR)m5^4t#YMje`1O9$CnOCbpsb);SKg3Kqu=Uu6PlNjLp(l-Wkj_Vx8(nQ;s& zX)iDq4{>E@qUcE*>EVZaGp}F@kX$d<9Go`jz~iCdB;fd3eU>-A7Uc2a-jITgpatO$ zA$d`Zw8Tm7i2n8Ek{(sqLUMxd!6{>8z(ji=a)S9PnPSVaOY0@$H$GKNDR*`=QDzk0M*fk+cFi}`+x|l?8 zRv~uq2L>F}eWSdFVl;;7V&#FtTz=OBVD;)*EtKt2q_?~Yun)Z;BXyP<#sFkPln$I@ zO`i~^1m3vP=DK?AkOOI| zmCoB#8R%eS;i$cIrUo~gx+j9#!(<|u=+e37h0}Nt4E6Fv;d_-Pd8k!y$kJ4AIYCz^ zJJDrwj?c0k2$XJ>?PJ$|`~6)&n`8oX$s^rwS&rU+zY(NA(f&jE8k+~R?K{=6{_ts+ zsyRIud$R!vAb35G<5qRMY-|Uhccb|C|NKAxXnh;xHWCrfCb~SG0{4z0qVU{|`aDxd z)E3g}#{wen54kr*R!e6Oy|L@7sfXpLMp%s=59(>|%{O;(4ZR#UySOVCy5HRG?iev} zR1OQGgNNN|?Bj^Wwa1S)HvSkkyz;|$+C+%N$xy9yqsO=C^rldV-VgA>{lnJpMQ9J1 znY|)*48!(ztIs(&D?lJ{_x9$ZdVMBUZtUcOW86DE#6Z!V4ZMay;Sj@}CS^vW2JtoS z72`}~^7?#qgA!|k<5|eVcc%Wej#6=?)H}B5B)L&$>Xi0mX4Rl*W95v@vp{U%gXu-| zvQa^cNSbT={OM?sM6!#)BO~5ke1O{2qWHG2v4`J+(;u}Wnf(QZ32p+rB=ar`Z zUR}eXK7|n}jp-|xId^83Abm$M@nE{*%=HVXi`=tiW9pD;59b=j>)l`jpIO2r5Beq9 z3e;@+UaAp>dU^_{iE3;)L{LF7(M^~ZiVO#bY&VfHOsq7D{2A+)cLXLT@jL6D3PES4 zaW?JWGnZrxERttf^Wd7v;_fbHA7Ie5r%`Ne<-k@riAiJ$^j263f*^t#B7I8JD(W8; za8t;+&#jh zTT&eQYKxtd^K6R<5Ud<)k-R)q7Sc#XZbJRnI#j^)h}HHo9)f_VVPQKhAemFuXwpmt z>fe7{8NPfuMk69N#c0B2BjdX>yxv@?3Cs-xakdc##gSqk32qMx%s2Fx=zG6>ee)>S{~H9i@a}RJg+lG4HRQm$2I0nI3pN~WjK!4 z%c~{#%Y4f)*~lwuAR@y6LXU*QUda)f`l$y=15`#9qQJ4MYF+EPJx;aV6*G1Q)8K#rB3M@3zV-uvg*KnAo&i%IoO^zj>m z$yr#KY{Os*3@&s?4^cbmhS2J|j?#`HJ>Q4c5`vn*91NuzV)7GpnF4tb;9A|!Rv9`0 z6&R3z&i;pSREEPUMtv^41?Ie?4~&Q&>rb!(U0mOjQ_n1;#+f|p#svMS!(hWagw4ZN z>~NTmks~5_J^MV6`CpNuCoqPZoT9-v?=SwI+(FlvfzYSX?3}6n{vX^q(=WznOLoru zl!u#ucIcUS5$s)>q(Nib#txUd9)U@o&1~CHJ0KX_y&gxqTAQS!?cFzhc(`|Av7O6>yJ_;1TDOq7Q2jgb?z z_G2fmF?=wvE;?Nu)t5oT%md;)VC7`Vgppti8R zow}$DEJfOi(ROA*T3yA|KA&5|iH#3&HEJEPdEMXAgrNm?X$^m!!x@bdBbFteMu)L$ zFkq!t0nXCBGNM5cZ3xI(?FWoCK({RO*@cPOchUcJ6p|5j;?_zS zNEek=Fy5}$X4LTtW#jdBk)CKIMyxY+?$zL=3KrjP_#yLR&^n^rYQ#n;OfkEp41XGO$8R-rfRtWA@lewb}B6QXxM(@P)G+Rl} zV$kPBT>AcGV+$*=-o2!&j6kaooPW4;bE>d5 zKO3G4LS#Yn}>k`Es>p{Ef~re+=*F6y|dv^ zw@?ZaeNcI*Df6?SqDQY8uoUPHtHw%vXV*x()S-fSOX776+_Po zLs%$V;L}VupDjGua~LWQS(;RH2Z%U#!%}+hIL^Wu3g7KXmH+Dh^6!2$%V~t4C`59D z`{OPK%Ctd~Bl`Dj-%)BgQr1X=-5CqsN?ZGYN0K3$tW8Vo$1YxX>rX;>>;2(FN2HtC zo!dlv^O$7E=aV)+e?1uEXEw#%{Y?}!6`8`SGE&)v66cv71`Jyf>A4qn-9t zqVif%`pVEsvJtOx1pjt65-8AGkH$*cowZTuh-E!I&__=he3+4>94?}E*iJYsY9_@y z6*$k#RNw(4iE^!@cL7RU$bC=33Ej@!scq`9)}9&w1$!EyjQ_H(a(0GVF2Od!q0@=Q z@EDBbR8bq0Pn?|DWJJ9)`2Kn}qh=CLg65k&=_~iBv>7>#o`UO2De>2fjq>mQu4vtC#{dokl|$#pT;=48Ng=<&|0Fm(EndjW#`#x+X>F8%1wRT;Ew46cXqZ-_7no znqzDz%!b-Q4iJDlmFE*@VH6)NTIlhd(VT=Z;>{xDLSirvpIt|`jZw;@&SNaTkC_%m zu(LQveiq6sP@_H7I5yo|K@fFG^~)*sug?H(Q4FO;n9NkqW$;Y%A{cf&3prxfC6r-$ zie47bW@t3U6gITR<~K1H0;iT~uPq;92F83GkLu}wlTen0wjPa;0o&1~%UQr#cQVW; zN4r%7LADygMWgdW8%VMb*h9Z*NdGX-pzh4dsqvsW<0d~^aR_5wAT8R`S3Hpkp+ z8t;IpimKfp&Coi1hufC58_5S9j9i|Q!!>OWM`cm zaNfpD32Qr%Jk$rnVT`6lq_G&A^%xSy^?G2DdCez1%$fTu`YP!5u|Gzcd$T{Qm@P9l zZ4Ca`U>PDHpb$r#yYu?zKfGCW0d-kt5kOJ5x0V$Tsh!Lp`pf5Zt6C~*vP)!r z7$c0Vhiu`~)6OIlnoU>ECKPlu5kLhYL$$Phr}szQfh(mcmiZ@$loIfx4h_VL_@_s9 z=-xkn`r?er^8aqojmf1Bq!2#DosgDqhWEeX3RoxSZqcX=IPUujSklK zEXV__j;><7DcA6(RGBFLY$~q4`*v>X*nAa{E%3&*R+NKCpzaNM2^1V3?mxJ_9%?KY z=lRmv2;u-<1UX^+acGPtr3i%~0E4Fp4`%=KAHUidhm-@|>~lTLz2KmEbf^P8$%DiB zho(t!ezlDPaWrpvk0?^uriaHn8*Q5&N3d=BaKCX;@Vt|O*R$DvymO&^xm_DdGkc?$ z8s@NyNj2jBWJ`KpfD}t2cZ!xWKFDqG9LN-|r@{4;-~4dr^cSOn;{>vCff7fi=Wu|F zKhB)C5hNq@fRp#ZLL+r?81a3EI5EPtsSLru0(LjIh3Im3w9fQ-x7w)8@_5^wOjAa_ z9Otu`hUN_QBGP6IJPS21qi=z0S&m~>-NP|Xnq!~PheMHif{|4OSOeO4P}L-TQs7}t z90x|3Gb5(|O{Rm3g3JdYP=V0Evt+9}BP{X=aCCFaNf;8SyN2hOJUER^@O{6N$pCu4 z?Q6@haL+(A>$RfFNk_KtrAl2COG`zw)?>WB+VCw@aD@&{2W`2W1?_(<;+Er_mXac; z4DP~GF(DOB-EV$(<3>K--}c>T^m7|~>I4{I0xmKF?*l`va>V<lxsVQX zZ@n08gzn{KAL`7u0hxP}9zQ%<{h()#I^$r+{({oMVP>fp3;RK;fD)R8Y|rBUc4Sp) ze_qegK@J(r1?AG&3K4#(?76=xs9Qy|7#dk+lsG)ls2fEaJ?n#DLxpQJq-eeyJhL}9 zgQ!!MkQ@{%n>xQZQ1C%=cA#r#=0sn+MwMOnA!{xuxywT-ruz9;}SGfARY7FZyrsExzV%Rza4|o zrkg~EY`Y2e+KoN-mkMn7yh1@beQ=-x=)(cezrO8UL!}}0%hR(F z8tO)@6$B3lzLS~l`l)X1MBZN8u?a6T+qL-f|Lb4=SdN>Y4B}!#I{0uF?-Q$BxQdw* zL=BeeND8f;L&pJ}Krd(?75U8fvRJKLD58deJ_|&E zZtO1K2s+vCRK!{qLE{zFbw0*ijcU}>!PuGsW(Xn%tSsnkZV#5tU@(rG4f~k&@IJr6 z^KcmnNr(JRnGUZ3k2t#1fy`0sl@q_p0peT^svm*zFISa$-DCkf&#ssVcH#3U9^1&z zF$};J6t_&@w9ItWnjkE!maNCgkyUbENU&5e=3ueEdC+Gr3TFTeD++irc~c%LSPYq+>cd<*T3(BgKI_Y!{hJQHF{D*^uejP35lI&4z4I*JS;r zK4yGCa?rur&dcEJA+6jc_)Y(d&XX zR4Sr=fiuWFq9CF^&g(EzdpplaC`VS>;IoqDk$rI%srQ(*HAKC`a~y^^Z_`mP$^($B z!m7{I^Xe6x;kYfk1Ad-@spw`wy4Wosm&Y@LVbp{ck((p23&`kuf9J@q$q2WuD|rYS z`cUU%6t^v_K2qt)Mxf++)TpvhIncs3K}P+0uoEaK1fz!Fxi}FpkOjm9lu!-;+RK;{ z2pm4>tdt>nZh^hYChDTry2~vIVu|%~DPnJQs8ujd*mJTt|D<*qIAq7pR`7~gZ+Pdef z$QZ~36cxb}U(J?w8g1K-x=@v)Lq|d5*i@)^G4QC1Sp#*9GW`DcA8hQ?*zw7^z(^A5 z7t_o|7kV`4#$Ih^OHj>qQ^GFGyB2H1B6^1+) z_M2OOIkT)e(G#-BFmZsV_WRoSrZcQrG}G0Wz(z@F!8$o;ln7qYkFsn_GfvD4%`V>W zG}{KG2;o9xP|M(w^SKyDo|n}*a|RcM!yvk1%`lDuTWZ4s!=XK;jflD?M(Tb3_xaj~ zU|CU(MvkJXu8rD37NaLIK0_XLslpxpdHSLn$Yx$yYsnHZ2)w1BWVUrUGMvMu4V@w8 zuAn|t=B=}+^@ieU{Y|Qb!B{xw=_IDY5hPGfKI^kyFN3c?r1m@S@4$pu0%DnsH7|_3ofuHkr1)m=v#~qa`eVh|`vDXf3AyYj zB#4-g?AHvD-FfarA3;gTeT$*q|Iuf1b-4;d(eoK1`yz%GCaaGt(X-R^Rg zlLTmiNtD8Y4M3~VwLL)l5{+sydKq;@V5T}01Ps-6QFFK?`~qvO8MqSxxZ;jW$Pd3C2y ze>j;DNdBQda&-46{0{){j?b!?O?dKFkG}Eu%d32#hm*O zA2!iVUd5Q?ASQ$i5777R-Ms_L^SO5e-D*8`#zGB>o*Bpr%zClH_Nlgz>9j(bq48K^ z)~Wc5fBK((G=sqs2ovMxY{1&xl+l<4(}C{nsRyy^1Dcb&1K*3&V05IpH!5bmM=pW01&tReHRDO@wlqbNgS88!;T$~zCU z?@Uqrs%rpi#Ly!2M=b(bCRYWk!PC?Ipe|3!`6cYvq4Cv@km&q*RmmBIELI%?gh%5$7n*D+nKV0-SkOOCR z2N~%5Sr@$<=V;vHUTH?=x;Zd0K`usBdImUw$@>UiIQ`Us&@a>TBMEYpcO6^+465xU znh8e;W-AAFu}IqB$$mHi-sfgAi&A!Wko@OnR0}mmj|h7f2M?>tBZZl(E*KT)gs6IU zw-sD-^|eiq9s!EN@MgilNqva@MLE28P=Rys+zNs?G9YxZrZIGgEX%bLpc!gDI0C$E zA2J{GG&F5w#AZ7&{0K)pO2g!14TR@V&4c9ePA|tOF{`A9X?N)Z+VXtf!ZP`86(k$O znGeC7v|bgY4gG1f-~IX&^)=TbxPC|?(?v*e03D4~eUEX)v9(9jQA=iGvj>6sz|VoL zn=tfb4HVvTMgFOa=E|O;eT@O+TqvkztCWIloy*{KCXsjaLG$e}{N2U%EF1~Vl>>X6 zJ`W1nI8m!VpF*e-OUZ0+XH`ePmq;J`w!QlywPoP> zI0~X1q7-m>8^SRH*AJWY-JBTDVgv!9S5LLc)5;jn;2sXG($wfyaWGSh7*{@ z<2@%)+~sgmv!Ln^6YK5m&EM36CwD34i-~ zu~Yz%()tlLhBo@^*+onQ^A;4F!BnAZ&ZFoAGl(wZb`+U=P!T=Gu@>&?KEAbf6e|y? z8EgpO=Vn_>3muh1%%Y}nMA!P9hu9YmU|=s{e2OL}tt~1Q`EGoi^8vLU1?=GhgbMIl(45o=Rx z9rIl<-gpm;gwdpA{-;q=+?ZUiPKDQ#O4GmE@Q3)#DunuXsxmKPUSk&kj3Oi z91T=NlP{)K$Zr7u0lCqAivn@ec^zURV`d{{m~B*4Wy;t^`%lF@>m0$vdHB=c3f?*S z%oto8dkdWZ=I;_D<+lR5$D2-qGhbN(BOH22hJ=AmcFwi0fm#9LfYWg#amgk zV}DfTAuCzHMUyCK^E)dyXOT_f6uP<(wvnRhOlOE}$jxt^+rpiF0;f&+Ulv|QwjHM* zGLE!IU~(4|3EkaJ^gmrW1GMzb=+qsM(36F;nMXfYK3jP1Ho;MELHo>gflL|AAUjkN zL_*cig87uJs#}F@&{X?Rb&gC~2hb7<)F2u3>rfc)fZD7-4wR}j?a%StaVwS)(cS>d zN5yuCJvYcP4b7gM$&Q@!@Q?q8|K1t>%p{iDH6%nc>8W{odhs<{!V19Znk&9hRA~vsk=6cWJP2nF>s|-bbsSs z7j${x0$;9?K0YV~rl3QYtp^7IR$MBnCRv0b;Mg%Tk za^CvG+?xIwQ|7?p^&u}$J2(8~)nM3#S;R*b!jJpT1*1=&K8L;w#r!6jVw)GOVKFGA z>oxPdua0WTY*tDU`5h6byU3vgG9DAQL=iJ^ua+E7(YyjQhbpTcHW}B8q6^D&$VsrM zzyA8$1H1vmOMpRvOT=(8p@jv!147}1>(vZ;&eH9 zlVgOtQBnfQH+luBt>8gdRR=% zS$2g*zx(>Pe`m@$j?qk`Dl)FSU21V;)zZB*W>O+53WJWijP_=qhy1yvt}UGr z3Ja+XeXNP+Pc%U{wKyJ!@#-cY5tzCM zBw6}d5)Nx({itEMgycC5boAkvF53j`)*MDB8Y7)?rq?=ZjV`WtAxVRy`uXRV^!WIw z`|V7`*}V*&g9CCv?-6|#MY(X6gD%>97VIu)y)ZeSzI=@_(j!`Px1FWO?cD7NPlDdJ z+Z#8B;u)A{Q(p>;bk?>tt%F($Aw1ngQ1; zeq+Q?>SYrl@a3Kq)L*ZKr&n3DjBZ&prif7KYoHr^7FtJO{`4D>9oXRLS|`?tN-^U? zHJ{@#=3{_sQfw!af^`*oNrR)8%HtT70^cni2;jgyU*U|V*4)k&_7zy=*XxT{Ph@flewm+x3lqU_Mw?Ic?^(>LsvUvn1dG=0fo4;A7hJ{ zA(F}~=-km&&i8XatO;`fZniV;ZrEDPmV z&qEjo$&jfaIq&)INW^C`z$p!p^^@FBXD`B`XzMNNcr2doIwCs_-r{Z`N6d70sa+QAS5gs`tYLz_6WBkR!8 z8TxLrjGXx`laMLFF}UlRwMPb>StJydnHvL1QqQ3$xS)Ye5&8rr+i@24;MXQgYxkbG zsJ9dSBjdyC@wSS7-6Y3%)E5s5;xf@<8i2^?$cEBtTOy~e0yc0J&YQj)cTY3B1r`$U zSyXylpl0l8qZ%oF4n0!{i%~t6DV<1(08L#8NH3n%La>m@Fq@jo@G1A-#O`YqgS znexRbHQrfb+}TbKbhogKNg+gl&**Yx{&eW;bHM+ zACOO(hu+is=7~Y{ml*#yrpLJ@nnMEk9m_WBWgM@_>-Zgz6A|!cvoS1V_^1qt>B)*Q zgHeDn?F~mmoj}HE{XvE4ucvR^bZ0P(6g-@w(9=fGhZ!j_P~>$_&KfGyY#p6~cb1`o z`1JEpkrKFUXu8<3agXMDM~grBp&Qt;;79X*w4U;@n8Zjy?(s6x@wT^j`mUp+cddf+zZ-b${9^$I8Uaz*?FdzU%>nbU^UW27f3B`H#g+->!)X@ zuWYEjTkYrH8r3d3@G!&ZPR0q7{W0#4i~+S;Kc|6>z>MpOrM~M?LkQz~`>?R)3_FW4 zs$01Emc5AqHO9$DcGf$a&5WNc<_HvdK$E;4gG@Bo2*>{To4J)^+ac(d6s-5B!95Sm zgGtQYeNhJ$-ud^;Y8< z!AJw89S&E+JY-^Y|B~L<)+Wo{4O=N2fePE}K%NcP#O(FEhkL`YX4)9uY33(I&=&+5>jM!G3Dn)mWB)nLSRr?hpo0VgZ`QiqW~Zfg{~t9n!`rQN%WIVK!NQj zJ#J?by%b#@&9U@;{qc{#7#=SJjKC=ijj3Jw^_M5BDBo_@(U*opM(ubPnN4SL)TpgNRH!C>y!ROW6g>`; zcAhpI9^@j_7{2@d#BWbrTl$A9x9B5M&bDUzElM;c^MzQBv&X9qUgI5nk-g!up* zIJowfAb>N?;#wwQI`Z3-;SftEFg@wGw+A)Ou8p~nF*<#D9iy@~^n74RUBWrE``#M{ zPe)XEmEm*I#Z7h59LCT0Z#yq?z9`({P9%PNzf#t5brF(C;P^#O1)8ob#rk&UW;xeP z5MNtP%{G{N{ATaZIypj}TO-MuGRXVNh`)V)^T9Sl;RNofsJsen90NWdqxQ3VQ0l;r zr{MsJG93j}p(%v0T_;06)8Ro&igZ5)2X&4NJuDr@AR7KMk|?|G4`*i!WF2OGX~Uo2 zLjAEZ=07u(faAqb!jgb#1GSN~vP&0Z(asJDUeCFqC>N(GvUefl@hk^z+4Ao1o5MFn9+?PnjuZCH0xE_Q$Lh; z9>7D<(Hr#y8VGqN$bRFj$P$Rw!UPD8vt&o>Jp;snN-GA#0Ts`96vksf5?RsC-!*vD zCe4N`ediHKm1jrcS1`p{XNMxWEt=K^2T;R(?b29#$b#~U(lC7$WTgZHy2c~Trn8`J zyV1-6Rlt?Nk?z|e%3j9!VfrS>ayBp)$6;c;j-Ci$(3o{{iP{kH_*l?4j4}>{D(NrL z^JLC_SLCCRUJ+DR8NhO!0%y@szDN5zop&RQrfflYI?sfxvyUbb&#K7W{8qR|;8ro& znNU*dJ&PK)CGZv9;{i!c%$g$ra5jJ@(+~~2MEOIx42c%^jOg>5gY6I*hT)V*GJ(#l!3i~qHz5&GyY2dr86hY^AP@-N!;9AI6k?a7ToTH@^))o6vcb-urh^v; z(9r&m4z7&$C@=%AdVSfcMmS9`ugt&6Ow}c5pKCwe-LH)rSZ2PD;Z`5NQ}*)Z)vUL@ zAj;z3{@K6(aXMQ%Er}u9y=x3kJ+H@@x~3a@e*0?N)y+7mw9#<{X+gBwHHi13ucNd+ z`V~lfSW%b&mJClZ5sIkivOh)VYuAmu@rjL;2a0QfuVb3$@qH2A1{_3WP{))gSD~LrGRw+9)9y^ z>Mk^23Za{unDWInQDn6kq8S#GDC!jvRnuHUwDI-nIS2vB6%@gtzPeWcr**XoWIqIS zL{_s}<18EN%0LnzLjrnYL-p3CDg2yRYn)aHy_KGN26GD%fep(D%VeX_S}_{7a?%F` zgv0j`Bnrq*1zgl+PQ`hgP>Ad@h7btJ19Xr#KF3&GHad?U#>hz@vcbE6+ZNdfZw}5* zTSe_wr8V4GM=wGV>b9IG&(C&0O3YcFp{ccq*$mwKoYALxEv%~9qzK82GIMs-TUtLl zkh>uS^3Kq-wJyMgSRc;M1m~h4f=nv9Wdp-z4?>bS?a!t+cg!Ww^M4R-&A%CW z%i16>zInWhfk-fw5Q+l=n}x933At#?kX#*@1oULVYe$+^YWAeZU^*GwXZqPCbjtei zI&!nX1l{SpFq@sd0UXP-bR#FQP##^s?z?a&cA~K5=ibOU7i~oH&Z3zk(q#@P+1CSI z$*`R`PxMdV0J^I){Jsqa)0`PL%*ANpJ!EZkSO7B(qxM`jW^ARh#sO@v59MCZ(opTB z;J`V{)prU?qK@EhZXBVow7CQH28NEMb2JeibN?B5WF@%K-N$OQb(WF9yn8V^U-DEd=YjG`_f82b0W`>iKDUfY0b|MXAp<={_7EnXBDviFzk zfO$iO7>`#AE?s-L+pV$^hy(=TmRHgl05$1`s1b5MoX=3?ZbnM|V8j3_K0}C5w&otM zX9D+`8&7%PUUtQE=1tmZTo2}T)O(@mcWpk-=N_De2zvTYKMtmcWx;Yf#Rtc*p3DXT zjyc#Uf>mZMSvc&xDTQ-j*((Ouo$$4kg+cDd-s! zs3a75 zY?6fvQ{C8&>j_t*ljobH~ z`ItFzHS`tA!nI{q7RzytbP5R$yJRM_F#yWYUKrQybO@OVI8nWfbQ#^vWgc_Nmx55< z_E#Gyq9hCp4Sh5Zy8nbSqa47A9*bg>O4oCsw*@ufn;R0B(go`wo49x5ZauNletF%E za``%#)4{L@9PtI29@x9bLMn>y!bp+r&T?jX^PTb97^ON7md+4jZBR>g(7&gl$>Zi~ zjPVfj#W^DcDtXq~sWfifRF?j{_w++Db5AL$D#)0%k_{+m+>5s_V-$2cx z@^vsP#gE*!pbH%}Y7Eztvxi&-W;ZVKT|iSqH2ASE5d2G4z#Zkp7n?BVxJc-%`n}nL zr&G|Yxfb?vH;kBkW(gS_gEIt*>(t=tvyDFm?NaxJL+dGOr+D~zv-e)=QA9uhRJDoW z{Nm@x-iHeRyFdM%)s*W?^Z`BUnV#hE-5lvYmAM^CRR+BkT`SMkM&|o?b^!a!Prtaf zM-YM}ONrWmp8s|$XjVb%u?cx0H$Ce!wi|-W&KUw)Y6Lgj|HCGf1um*@9(HdIw1Bse z&RK%0kg*a-j3Ta986Y@ExU`5S+TuU|`Hw#m5td`23$3R4bmdKM+L(KjkgM2?O++#J zGNc45YlwId(Ae#1xr`BhA^KtCx=CvqBN5l~v|SxsU<@S2pNB@q*((cxddsHul&6%r z2$NgsG6tkT9X0Kb=0Gsyk!ne_j)6vkd%04iL-EvgkL0WLSpY2AEVH0;E)r0Zhz^Mx);x^N~KtAtIvZc=6ptv`CbD2owyVQGm_b zWjfe&T`J2BDR*XfuOmBH&ex6t+b*ItFj(pp#xyM{!1`UxIzhh(VjzqL3R%drbImzA zL0xpohRjCg0<#6e`1>-}B%lNp+-{aCZBpr*ms9r=#i}2tppuQ2&t8=*%j+QSIv}$mn|RUHqF&bAKmV zLeDy6H_Ou0?)@oxaw-p$?>%>&K8U$(F~Lr2W*ow5P>DwgqR_v=@yoEB#yvx=4+n|- z3u?8j>v|ajqBt+CJNx1A^6Jic=0fz>m~QBq*rQ11@qG02A;TU#Q=~V+0#+K+>)Pve z90yyC!B))5uBI`Ao&iV@MBGczh5GUV8XBGEx)!p0Q(0x?_o|UmhoD=$^=l`lHq*^Z z#EIg-UXGTZ%{MXbl(`M=*WeGuQqy0f2V-#8^f5G)cr_ji>M8<`Zl0W2`nz&XAvtRx zw5C3T;Vq!IB8%Z7a%u5C_fep=1RWP6k9HFs)I&(&7y8V+j860tJEVKhJ)p>X|8 z=!lYyBDC)U8mY1<>PXpe2{A)PEBU@^HwilRL>bm~6}<+81r^yeGWO_ntoL!xz*%E` zgnim5OTS&*q=VkWASYO1pdr|jCuRRgYEXE76I}HC@|GSyJh=WtFlv3hOXGb@APS+y zB8=Co8KOwf5HK~mrjL&|?v*f^E01ZBup$Yf$)MLlCZ2$umZ}e*c7l|)k=bg`-`;LK zH4mFa9SmZ~13FEHd>49`cybG?=;LW~AwC z#JDdZ1?{PBrEeTe-qXLPv$5-VI&!i@qsJYu_-R*sGcTwMICZqeV_>a)H1wlE3lT2h zC1f%B5kA7;pM`^e|J#Md;)oV;92`^}71~I4z5U=tVCIB7L-o*KUw2-7q?vIB7*^mH z&*N_68l$y6vwZk!5|IS#hiVeC3lyK{o^?>iaQZ6hE}f#4m5lGn6Y2^xNl5)zBkCP^ zafAqgIehP6>o+o7Pa!zR!@ZpQ(9zLz`1*V>J1croqM(Je_wDVi_Vd{W_U-vC#gxCP zu=f`mSfY!<44td_+c25BQSp*ZK!!-RL^B}uBwF=hTUFz8k1?%8%V$pw+{syNq0Q|t z?zx~QfMyahKGbR2y0AS!CIhAlMg}pz>sVOjvq+8k+%3(6D8CY1SpJ}PGZ0ZenL%?M zyT3i(JB`xy;n10d&Hh4ez{Pdrw}l z?|i?Zk5qUcBFBCHsx0wtt*E=RM2DLu-(kBhdGs)INi3+)1$h8t-HrV!p8s&U#>mjI zkp3>xY1|#i*V=1MsKZWzjA6YsI_U4W4(_1rVx+CY+JzubITAa3{+Lz>yX|w+@f12se8 zB#Tsip{Ib2@t$l6!}MK@F^xGeoEKhC9fQyI;31$=2KE$V{|uspY-pP9U@UotL~oJ5 zZuexeKtEXHjz*x~QT6i)iTz5iF>2eJXJrISB zY#@r*KtsSsA0D>pm!F@a!B$uP^z}_=Wcy79zj71q)eNStFC64iivV6EcnCVSuH`om zhLdM1L0G9bMNo@R0LEozP4Vyk*?;IFl&fBMG2^GPI!F z+(ZvW9z#loQRboRLK~_dRXbfDn8&zEoWpw>o6`HC4>d{`rBmobnI2eQUCh}F&brk? zQDlZGbNf+-@g*D_p9wC%z1cVe+0)Deqya>=Sa{3WMY|Y^KB`f|NZHEyy{On^L+XO7 zpqATJD0=oWPaEfIW!aScK6++Q%%oWCak9>On)LN$H)=Y~EdjE>H1lyn9rG|4q}4~A!hs4@;(lasMQ8H<5<{qFO2xO^nX_V~z==JW zx4l0{@o*T&0AK15X`C~zl{pY~h+m#z^XR$U;aCohGZdO2qr*Fz+sMRNOV;2z!jzs; zMxf}{xgw;%^CpJ!3`{=L_Z;-R9l0YB0tsOp_~hcf zSxJ$hyOSAhG1WJik&V#b=C>bBIR}D6=KG|x(T}sfiR6)WpQ~Fwd>|R7B9_T0?1ORRv@yr_WsQ?zDH1 zNe6vqIg5p_-;xnoFt>n#GI}_0v~%XP3+~N>9flFdSsBvm$LvJcgz=_k(bCTX?oS5b zdW&8^zqRfYFf;)~J`Yt0*JG?R)r-hy8HY7jLY3hVL zpaKho1%r+3;dj6Pm_B{^Vy6Kt+m5tph*~cSBJb~R<8x(8>_{xvlBJjDqxM)m);@FB zP>#pdefAnNZzzDjHMY_bldI94huL3cE{`SY|89b@X`Jp%B^NtF$8B+ zre$773@Hls732Z>N1|jkxF~q;ftyMYOnZ z51p%(vXOlz*pa|U#__W=gf}Q=bEj=4>n&dg#)- zqt^EvbRkjbuA>G^ z1}jT#XfJ9DeaMCLTrD*o5L8BuA}gJJSazF+L-eG|2%fU(#&fhI;Em=~f*G9H@%c;Y zWHUC}Kryl*Sdo67v#A?<3)NA8jMy($&~3x^!EB=ktUX5UVls<~fYer@$MSjXVFG0o z3htGq{`|+E(ua?aw#lJ0R*u0t3etsxK+gg9NYviz;&A~4pvWwFZp|cp`SKbp%~9Ny z0KfRR|MV|^48Hi(Jbc3}HZ0LW&A+Eg17{YzONLq~u$Z&mwPPgHS`Wl2OFxYBB}x}D zInW;Z0q>oHpF6jMA~}q_{BqQR;$c@~muWsOUKov$)j-(DQWBJ8!iSF!Y`vx{{UET_w8&TCv~UFzS-kkZwW57`L#^URSo!-Hs|t9AW1 z_tZf;>qJqfVHBa6RMRNPBZp0gNR9^iRxf z&V#xMOmjPr*#%9CDT)h4N_VS??;Fv#LZHkA<_i=xP}omq;CaLA~ZM6o9?hs`>AAL-+mX7zCtO50Yamt%!Oajo7Fh@uy0-;53#^_# z2_$R~&pRKYajsgJG(dnyU}MDr^GkCZe6xAT4pj>sfP0T$y(bITZnRJJGaP}ZMha`s z*Y|>cP9gnGw{#P-FLaM%lR9Ym^~K-aQS>gxfPd_gFJU+pF(nS8?h(&AOI?M+!NSm6 zjC`z&4)kW@r4TZ7Pf_7avo%dS_w}>a+4s5UWLzv?PUm|Nc%sH;$bCpL${`Q?;?ccb z)DdZRE6UKi3Nle)>ih0^Fe8at81}#dCzJv}EOc+5zQ_^hQI}zsj;EC(DG${e2wJZ@ zpawmgm^3kWhj&2vkRQ&Ym?UV7?SS?rjm?Fp3F?~u zlexW1=2^pG;2i~18J{lP&rpt=i^CCmE@d=#;2h4Uu^}rT8)1?&1)kbwy^Sv56d6eG z0@&d6$KAKgG{Au5G0bJX4M~K0Y>~$!x~JoGwuo0W69wODr$QAO0EHkn3kD6=2iLt} zAQ59P6%CV)QfNo(1SSTs5LDUyt5U-y0)4GJz)1rat0BGpy7LSGTI&}#^Yrw;?MzFX zjch3RKMb4!Lq02AMcvl(X~A%_C^(VU-`p)+u(Fe0O}t@g;h!#a@AHsccNRqL#o}s( zSxzwvyRbeKv`dU?V?!TuCXYYd**SpQ9<(k${Pxxp^+<2clcvd$E_ZFX{UN%xCm!=U z^=7F|PtGloVKx#H<8mG}&S!L=N^^95fWdpD^;NA1U9^DgXeX3_QB#_%SZ z2-$$Zm>f=OEGK;)@)~gYLkXbweVU%#G~d#B+(D7W;o*6%7M1srHIGaV%4FPAjL3u{ z9JWgkRMg0bs87t6kRyT6U@3euF*xXXG}fVZ3*37+bYnNoMP z0`J+gSPaRwF|9B(w+0geC}6&PdG@_^rNh3XkYLC#DQ4TW9; zVcyG37|(72mKulNbI5^CIJb;1ZM$})D3>M?@OtR$rdWE+?!?BaM$K560nE9~-NCBU z+?Lk&G3B!BMraGRX73EAT+P18$&|1H$0>HDm3kZ39`orevOH>Jo>ZA!w-`+KkA_S) zt`Uu6Ypj48!iT^>i~(}fAC6#%vA8%D0uR(>dyAzBrrg}6g069W7KWg3=B;&K+<9Uh zUE}UHRyN??7MlAIr=(#Mfkpyhn*G|)a&j@a3Qe&}*#dLv!CA>E=ZlA|2H+L#wou5Xi&h<68S{Fv)|{!c6=9`C7j*Wo_%CV&(E)nD~K7XE=(7N88g|q+450yK8$;wM&_bZ8h#Hq znEJ-}tOIAI0CqXV2JgD@v&JDLhLR$pwYE%3-?W81UCwivJE!rHF$haH%PE?=z<()} z-ap1d@fm@)M-7GRu@<|&@9yEjiw_-)A}kT=={hcm4Aa-ouW|%acf^KF$Hc|gn-81x zti$aIRWy7x`uSe()1seV6xhgkBOMHVkQ%`pnl0Z+hQ-?G;C+2Mc^&Apc>P+tcuNu8 zjWED4ru7E4PXX8*W)2$)v^>ChZg`03rFEPB)Yn4u4p5-yd+59F$(k&0QpPA(RcYT; zEbZIU*}``p*6x|${m`BHLwb8uCgL@^r+CG9)T?Qk7zb)DVCpe1WGUx$4AoKh#R#fU zJ%_VX%|jX>m@yMOfx{uV>O5~WWXL!|?zF})f1_x6QbneNgfr@{GFD{7IMr9J9~ip_ zT#d5uI4$_)NOLqTB!I{mGPi7G?yUa$97Ae|(x6V?ZmM*9BWK@28}2OKj6n{i)}C7Wcr zTppd%Gyzg$FqU4%XxK3P^cU!7NOUj-4`a`mU+{iM{1N;WiH~`dgW0FA{ zo9lY|8(`D9AWuW*)O``KmF1EYlT7NddT`A{4og=5|j)FJEYpdeUY!?Vn+W8~Z{FoZYo>75*6fQRz#U!KjXgl0{>(zOG_(amUEyO9ZXu?n`C zN{5r3FX!Wj?>;z)+3&A*3fOSI2j$)W=A#@)HN-fDVlbWjIo@O@|!>LE$Y-($oq<~477d;796*p>}E(IL&e&HN8 zoEI<<%FH+w2JirxVU!Th>Rdb*R(&{yghv^$Ry9;k?P#vz@*f@-K9J9!zY3?lQ(^q# zPU79KbZ9TF*hvPtdpUTfw$nn`0y69qZKhW`wpCBKd6>HJNr4v;w4lpI10dsAd5{Ry zalR4GBU-^pOcr`*tGRJ=*h7X?CcPzr;XwQQ;L4B1SvM~lazmQ@&3y+*niKU}^h>Y3 zf7se_kY@6oK!WE(YjMD8)>{#l0z3w;ZbF8GeiT0gngI2jcB%u>g8+QN^slZ9d1D;) zYNNWx%Q1!k9S0ZZsi&A}MlriDqWKG^jm7CEZU|fomLyuj;b(@IkT_VR-3~3LsUyH@ z63t6Q*GxYH*27sd`O9K$%)o&uq9JoS9`6Gp?=oFUN9;33o_v z_tD2uAjN^YL>}W5U_-HQ>d8tOLv8&gGKP$XyGdlY{q+zHaWV!CSs;f61{WRNLqKAk z99n<=s#{gmj~+)cF~o%}osDBoscQl^Bk0KU0M0SnbF^_#Wj}rXY()*^c{$3}? zu!Eoe|7p@8VAFv1P?znbKFybtne_5QpmXvU_N&I8gA+X=5oQ+MdjWUM^ZAP zEK_RBXs$Av>EZQ}PPuoWh#3m=1zAK0S-p>q^!Je}(iyIey520(N!9(yY;adH9gu}z zGcs=Up6gx<_&pe9?-qBIb*JvThywNQ^=PKfa>F2|A+YI52%9lu+jEQ4;0PP_S9dd? zVgUN~W-`iis766yKA#GjJDLZ+SmiD()6W1SB8sFjBgARyr1aX)>;zJ})h7C)dqvNs zQ>yzYC-L<3tBqpN=>`|SH!_H?jEz0zVUVj}IxyGxd<{s;#058Jm4+gSEGIJ^(qZb9 z6&#&Wp=PJ)nizn>Jz7on+St&#--a3HP-coDD9k`jF2F+JkD67a)iclkrqdSNfc_M9 z0*vctWLhQ+jvCAqAyX^!==e9Y2DRR41Rib%RpiRVyePy4UQA#>@sB;T-c-IWYWf`R z3`odAhu85tOFP+j*s}3Fl+Lm=u;b2x)$lh*~?Lv02LlfDlea zqe_8YiLz`_ryJF!_HQT8o8TFgRR|NZ2RO?_rdLmd3@W>I)W(T&1ogmF(Z4eFXE3p` zA7_y;Oeqh2RY&gbMcK`!_*TA3uDsBk>pj?cL34?fd@q*I&c_ z<+-PHei4-1HiPZ6S&%y4`wLmYD$UIe2n7l#%E%T$(s@7u#_f`#%5iXJ>Ae zKI=*+K4^ns{6d+~!RLd|Hw*ON{Lg>&BSpG=jDqmmKtPUa@UB@Jr@93MRgBO97&K~y zY-~dlO=vw?^9d(nO6@4gk;Q0JdJ3}fgIvJwBOSL2DhCWXE??r#8-Ty0>Q)Q%MBQ+QTAgK?=v z&X5wlSB1?N6^E#yc$y#51k=FBmm9KxvuDf_d2^@^^fJxRb3fX!6I2Y>+-VzK-rO?` zCxU8Zg(4Cf>1<(q(kvwkU~)FFa8P%JF+@}f zjTTvzyi-&QZ=aTa8VX^;fNc-Khvr$mz_-?Gvnm^9R)%lV8|LSig$?QX6wZI8NQ6wo z645EMz+yEWr{49^FnBqI6uJt@-hJlKZQ(xWKpcHB zV!rU%dCm=lBdE3Ro}QV_#~hOj8Siw=?A(Ei%yu$#z=Xcpje;iVsBU1rMx!b-GjRHg z5X3VKH#RtyZoX5&UregZ zG8HmJF7aCvtBAS4;z%lm|&XwT!6Q;8VoIQ|CL1z zbB~_w!A{$7&@=`D9TmV;vMOVSWMB>8@1;yeg67t$m{?3fB1*#4}bHsss0}yA54h2 za9vt=1SYu-Y!qjc43B*bLQ?#PfAL>_j59!-3eF*M$5Dk&JT3M|cNl)G`#82`&>k&3-MKYPOv zIS}#ENQP3X=Nh*m{n5Hu+L@D2Q_5@uS3M$Apn|T6LXD|t%nG1sR0j`HK2vp-Cc7C> z(JaRLxIcSN1mEFos;PYtr}Kpu-37bUnsHRR7$44-> zouYz?40R10qd!P;BVmmJVZs%nb~N2!_=pVY_{9l_T5Mw@!o9Ay%jo*0C@1LW*Bu9^ zih({ZbapQ4+qt)$dtUBuXX#1Kik^z8g}?@5)kKhZqK~Qf6|K5v(bwVvy%Cqr(&7nrLzZ zmYmOmQpkN$a4g@)r#2z#M^xR9#sx_b((T<5CKZBeXAkzl+1=dEm2DlZq-#p7)(blB z+wKxWp)i#EnHJ7q-=$X2;9~Bm@kI>mhKG9r01j$q{hoj}X3LyjEB-w1MB{O&_)U`f$D zhm5ow&d|p>peD9^KG~W44 zizYWh0_H~$I8pcGdpUuEnzF-l)JBjMrx*=1PPca-4T==A$vg^bB)FR@kPm8bd=HI$ z2nL37tToY7vqEdjB;HX?Hn+sQ$E;!(tBB5lYzoyPhUOH|J99Ejm0gBT6gpxAEMb zhXusdnUOkkBWG!PL?(gf4sLiBV=q%gan{J!O*sA4YhyM*>xaaH z<>%BNhLNj{%mEl%P`p%NdH!l#)eR~4TbD0!K31R2LMFm9sWU{jPM+;RD=S9KQ|hc2 zMKn%brFYjgouzn87)Qz~)6H+@j@V1*q>WQ)XHiui2KwbypIf?kMb8Bh09lY}YRDrn z&)5UU+p*|edgd~;R}2!_1yD@p!*H?VW%3)#1KkVFBWfBoX3cu8*vv|Xi)d!@O{ z)yy5{%;P3AvYfD?nu!|@$tEryP1&ocymA3HSkf^U`SX_-rIhn@Lj<2iKM9{jI*CI7 zdq+_0v$B<$B3z2*ypF0t8mFeg5~B;BXXyyf@Qw^!bM^E+#LA%KqIwBrMsk09J9lEWMn!pXF1WOGTNX1 z>mSmrm^k3@JY)79-RVHHvyhUHx#(y!36|U)ggalXLxn?p-MyI(x&7fboqqY^ZupAg zGo9X+uAUk$rItsw2xtGD#l%^n2c#P@alJU*&Q~`6-UOWOZW!m>3xXhn!%(7n3hV}L z9;urySWTYCL7y|vVVrM$K`V)DsNP%eDwWYaUwTN`+|Q}Y$Fr0oi#5>`V#n^YrM{yF zBcM&>YFszMfysU}f-4ivbhC97g9)-G>*!yhKGViLdjrqa%!O@+4Ut`d7xs$!K~ExR zYMm8X-${ml@N5sA$$q47Lm*S_qJ;)a_KS@pcs;#Y*Q&AP(K%*aK>0Q8TZX(9I?8sh7X0Z_@t~a)CkT{^bANG5rGp|UD3{g+AaN=l($rKQr z#P(2p?&_-@HiQS(?d|o&fn*IaLici`dV{4wXoA%`eD|C0)B66-Hk_K-hu?lwjrKVv z9?Bk(wSN5gD9G!p&fL-p#Kph6vFr%rsGSTZdfOfBu;7u;6-iTz z=*tjQ#Czv`7(|Pr>0$16du0@>^y$}E-B&jD3}mC0(k%V_^P39tHy)JqK1ZDTz`Lfs zStzdEyZzn2!}A^WSo=+lV>pr5(Tu>pI>UhFz@{tF)@tB zzDphQ2JhobVPZ9HP_N%;M5ORdLldu|z5_&{YeSdIDh50s?djbge@*3EICY>TU@KIC zJ@Xodp00H@HX;IRRz)1@+LT-Z17$m&Hxd!JyYgo-ZkX?|%L!oa0 zm4z}`kSye&AahvUy4XxH+AOZiF?uPeSAZaNV;8-L=0w9=XcbKzRF&&{ZM8OpK2NV> z9|w~?qV{O=3;Tt_w&}!e%&HIshB|BvAJU&bbml1ZmkdKf)_zo~t@OKge&f0c9px_Y za++a1&6Y9Mkk>_Z-$R>h@Gh^aaZJ9cESR3`Ss?+H!@|md9c z!5&10$In%3c#^ZV=%*o{`dic8Rz+;i#ogVVJLp5=zm1xbZRPMyt=n@g+%GXT?Ulgs zxI>?A<-p#Wd7K&Te}Z4o4w3>(31##u#o(&v=aWa^Y9COLU1 ziutag_hh`;1>{9U*W(1c>oq($?{&5?HtNu!%p)ag97f6?hsuSqE;<6u4xu1Or#4d7 zNQcx{MW!$G-mhHfTrVevj@%>z2CR)jO=GgnT(=yQ)_?ltv&FNJzNUK{ zwbl6|qW;TyFg$Tqh5)32^zp0Gw<)57H-nW#j|ZxvbZ$@0G%#*%>66ON7-?|^GhMES z^xHpqFg97Aqi%!Y{`~o?3-d3E9B5*Dd)}ozP|}dOVP*lQNo2}c)M-p;1KWhXMHJ0o zoF_#K7e(?P9zUcKy6~4*Yw4`PJwHF$V6V*Aj&vH@A5NaGO`yMp=Nm+^8RiIG@xV&I zetvd;1oy->=Hpxvr8Ke>_spnQsP8hWD>0Y>+9J~ zmPovCP~99#UKGNcmf_ysZoFUWcL(VLcV~9W?)lAK&l70XKmD2}m(U&aJZ+t)!&6Kj zL%7ia6DrA!hP|6xBZ%T82{zFonN6lpkI}INV61z3cdVYrGIM5gHG^+RTLmICYyvrX zrp!&{+QMoxi6+u%NK619Q{y8ut!ZU2lSvs9&_X*Hx@7>8V{PsW+BeU+=|`jImVDP8 zpzmgGz?;UB%A4bbvV)Q$7QQ?>?^Hr;n^Npz*pe)`n>D*dpSTkm?0Dja1LdC z@HI_5)3|nKkea>fBCoFJ6x7mG{2r){;)rMjrU_SpG&LC_(oSbJyS|wy;gPRn2YE7t zG0mV|YvpWkk_F>=;*s=>|6CT_^)5(NG7^RFg!g!G*dm%Dps zc{C75KzA^tNDUH2YD?^}_a*_)vPTg?uH%D z#z*|cpZ(>JL8D7<@`}1a;KXiSL(LM_K@lJBh<;>gFoU%pWv$=69EOg=ZTa7>8M|pi z(iki*#+=rE9}q%6;=G7YO?U|Am4}RjH-P?7C-D5

y;Z>Dt0IjB*?*&ql4a7;JV7 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

(=r+D!=<3RU;P^u4ch6l>SnWz9?F(YDAomG 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 z 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

PYpP58Y8oisl;mG?nMRSP3f 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 literal 0 HcmV?d00001 diff --git a/packages/apps/human-app/frontend/src/assets/background-images/signin-background.png b/packages/apps/human-app/frontend/src/assets/background-images/signin-background.png new file mode 100644 index 0000000000000000000000000000000000000000..cb6c066c974f6715be81efc58c9b325dff5b5f38 GIT binary patch literal 1198902 zcmV(@K-RyBP)2o841YS(X0!8$M3>I3|ww zhU>S#$jL@^X5NfA=llL<@3q%ndvD)=@_#*=9v>gNR5I!A?`tj`kGi?JdDrjv-2B3# zJNUTo*49^DG#qko-@SF|T+U5KBbSQBUAbIw0e`^th6A^@w&7;-dHamRqXYNk(XNXm z67JR8*Dl-}yUNwId;I*ltMxlBo=m&l-5pn}*Iisc^X<3a>T~?g@AJ95KEHHx>+-X+ z?)d1?MV-$*d-;hQMuP74^4cYm8JA9{UGcQ&?n-wqr006}8E)U!1vkEb3B;luPL|!lAIM*6v-q+i|&g%DGU)1rsrS+a&>!Y#}#=zD_B9}BzoP1#MS&JFw%SG#Yx zSTO8jnS`qk+HNjC>qdj23kSlkq-W0M@~+qEIRA9whI+=)c

  • mMd&5yPYR{TJu9U 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�+>VaUoV}1%!4j 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 zĖ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¬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 z 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
    |7Og=MGbPWQw5jk|kCV07gX6$MCVM@W$X=s@ot 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

    RnvW4_Q@U8QC>(#oS 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≥YlEb(X)EUg4 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 z e!%>6(A?3bQtZNhx1oA4ly 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 z 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 xpbL&aN#04w`U@5~S%Gao@LRkWO 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�(R!JTCn`e{{hL8yB z(j)oRp|y4JWrpff=N78=9#H__bpk$Ep9|wsTH8lj^NUlPAoW^x!jPs{wMjlKOOPr* z9*f(AfgEe30)Ps^5LH7+<$Rt_&qG<8n~U_{G2H+Q{h>o)=`q~2uN z?OhpInwDDBZH9PTFW<81N3D^3hk(*(H*G#xl4?9ha%*M6v*X>~(y$}_6o5bwsp=lHpgJdB5YW-T)G6qFeDX{PlQT6%sZW) zo|ofHQC__uAukOQlR7YEo8p6^)P{8J3(=xUXMsjzI!b5XWS1tzV**xr29_^C5^o}% zobVp!&J0SmP~_)!CEsYtweQ@JqsFep&mo&E6XVM+dG`4$Vuug;8^GreoAIiHLTGw% zN(#A}YXXu8hdw`H+q02})9iQq#yK6?yq=!;;{+v*##K0O=Gv=NAUVU3SXz zKLzAW1}vFJ!&9=up1FGcg5)zfD-PTdm?PxB?9+_2h;xO?o}7JWNyd5Kl&X4IOrEd3 zkO9`?(!wIYcPQg$CgflK%YQA`uHTRn@xDkw^W>AqGLNkDa_t$cQW@!V+C~e#eDzvJ zhKEg()|?QbfSN%r(xhA{!UVD|%Ip*MQdDL{*K7f1dVY3M5?zlxS$!q$c);u-mam+* zxUZg$zxu0R$~=IkT*}Cg{?>P3EMd#Nept*2*{3*44-Z)Eef#z`Y|kJ7>mJ1j#e_Q~ z|F?hsALNhz@+t8WHO0}i(Mc`hRIybzcK)Y-=WofCo0r57Lp=&8pF4L>zP@)?{)_+Z zKLudyTQNN|c}9Nr7avnN0Ce*dg6SYkbw)n^;%m8eX9>pb6~JbXc-k^c1677DUb-N^ z{KYTL!)kGU3DA51W3@v}Y1k=7ZK2tKHNJTDvK&H~geL*WZ}(;Iup}G%`!WcqQH)TA zQCfSuCO2-}GTVkG>uP1=H8Nb(PF2?Hr|QRp2j5s*#sye49Z@qt{I0;b?`-aY1G+Ld zJe30723}c2~i<| zNuGZRo4vGQrAup(Zfc21g>=c@wu;@6B zY-V2@sZeJHY64fk6^}D$qXHbRrj4x8h3e*>gMqX)VpnTWkZNM8_tHgf>Xgk%-PsLO zS*7iWcfWru!+N?7+Br*A=+qNZB)~q&Q3opad&nfPQfi*4CmlNuZKqSKhKjlMj!mAG z+#!@NnsFC7r>29IgAS83dw_{9fJgvqdOp%0h*=e`L`DzxBh2%5MU?gP@xNV2q9vHP zQK@&S((5IjN=Q0-iX*RvilDf*abTBmp1CtY1gGwK&vggo|CIw5FMYkG2iZpcAAJ3_;QWcuHntdXi^NxHrR)8Hu zAZr@Kp+Tdk1DZQ3NkYyOB$aW~J{%_iMrAlPpY-s&(lIy85H&j$zRH{(W<%#ss<$;v<$PR zb9+>-tT&JY0g}#v0U6d2CrGj#^<2}z)#_ee&51{)thz@ENG1WR3Ry=~I%N5fq959v|#gb07950a!YK8DTSrhf+v*ev|oBs&T^3)KaXM=iAbQ zK?orm^m$*}XVr&})FH^Zy(6hYhDHH6F#w;+YhL6?2UNQY+FN^(dOU+*$04V4nA&zc zI1EVhl4yO=kX6x{e8I-BXd|$)YYi$fXO`!nO(4n;=&3&F^HJ8kzpD(TLuxQtsbEZ+ zI~!ER5eX8o_NW&9A*AZWk{o8Whooz4Q-W(x0+!WtOeIO}r5YX|wi$!NNQ_aWlRBVK zhq~$vJC&dHU_wM^4K|wwPL!$D0;;6rCiwZCy-mev*7KmJi+8rSZ4TJf>@a&%r43~0 zpf==|xi>x4%dN7N2IC{_9RON5DLWf`6a%nRN1Fh$q`Y{%OGWRMlM?b@T$|`C>U}q4}`tis2?Er?Ju3LjOnuO^X9EXWpPD>0KQvI2V#hO$OPmPMB zFggwPcLEUel*TFghupKYb=kKZuKW!XYQmnzHx2D_KBi=5S9goWCR+ z>zgoD^GJ~7rheGw5!R5thOQyE>*%ACimbfYmf16l#O*v1@rKM#j{w>yxM##_p4kL! zViπ=(1~ae@8iMuefWvV{-}@G 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%0DA6 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 z

  • -
    - -
    - - - ) : null} - - - { - setIsDrawerOpen(!isDrawerOpen); - }} - > - - - { - setIsDrawerOpen(false); - }} - open={isDrawerOpen} - > - - - - - - - + {t('components.navbar.howItWorks')} + - ) : null} - + + + ); } diff --git a/packages/apps/human-app/frontend/src/router/components/layout/unprotected/use-mobile-layout-background.ts b/packages/apps/human-app/frontend/src/router/components/layout/unprotected/use-mobile-layout-background.ts new file mode 100644 index 0000000000..5b1b0da4e6 --- /dev/null +++ b/packages/apps/human-app/frontend/src/router/components/layout/unprotected/use-mobile-layout-background.ts @@ -0,0 +1,32 @@ +import { useLocation } from 'react-router-dom'; +import signupBackground from '@/assets/background-images/signup-background-mobile.png'; +import signinBackground from '@/assets/background-images/signin-background-mobile.png'; +import { routerPaths } from '@/router/router-paths'; + +const signupRoutes = [ + routerPaths.signUp, + routerPaths.emailVerification, + routerPaths.verifyEmail, +] as string[]; + +const signinRoutes = [ + routerPaths.signIn, + routerPaths.sendResetLink, + routerPaths.resetPassword, + routerPaths.sendResetLinkSuccess, + routerPaths.resetPasswordSuccess, +] as string[]; + +export function useMobileLayoutBackground() { + const { pathname } = useLocation(); + + if (signupRoutes.includes(pathname)) { + return signupBackground; + } + + if (signinRoutes.includes(pathname)) { + return signinBackground; + } + + return undefined; +} diff --git a/packages/apps/human-app/frontend/src/router/hooks/use-is-main-page.ts b/packages/apps/human-app/frontend/src/router/hooks/use-is-main-page.ts new file mode 100644 index 0000000000..4f3d188fa4 --- /dev/null +++ b/packages/apps/human-app/frontend/src/router/hooks/use-is-main-page.ts @@ -0,0 +1,8 @@ +import { useLocation } from 'react-router-dom'; +import { routerPaths } from '../router-paths'; + +export function useIsMainPage() { + const location = useLocation(); + + return location.pathname === routerPaths.homePage; +} diff --git a/packages/apps/human-app/frontend/src/router/router-paths.ts b/packages/apps/human-app/frontend/src/router/router-paths.ts index 530a26bc7f..0183b5dbd3 100644 --- a/packages/apps/human-app/frontend/src/router/router-paths.ts +++ b/packages/apps/human-app/frontend/src/router/router-paths.ts @@ -1,28 +1,19 @@ export const routerPaths = { homePage: '/', - worker: { - signIn: '/worker/sign-in', - signUp: '/worker/sign-up', - resetPassword: '/reset-password', - resetPasswordSuccess: '/worker/reset-password-success', - sendResetLink: '/worker/send-reset-link', - sendResetLinkSuccess: '/worker/send-reset-link-success', - emailVerification: '/verify', - verifyEmail: '/worker/verify-email', - profile: '/worker/profile', - jobsDiscovery: '/worker/jobs-discovery', - jobs: '/worker/jobs-discovery', - HcaptchaLabeling: '/worker/hcaptcha-labeling', - enableLabeler: '/worker/enable-labeler', - registrationInExchangeOracle: '/worker/registration-in-exchange-oracle', - }, - operator: { - signIn: '/operator/sign-in', - connectWallet: '/operator/connect-wallet', - setUpOperator: '/operator/set-up', - addStake: '/operator/add-stake', - addKeys: '/operator/add-keys', - editExistingKeysSuccess: '/operator/edit-existing-keys-success', - profile: '/operator/profile', - }, + signIn: '/sign-in', + signUp: '/sign-up', + resetPassword: '/reset-password', + resetPasswordSuccess: '/reset-password-success', + sendResetLink: '/send-reset-link', + sendResetLinkSuccess: '/send-reset-link-success', + emailVerification: '/verify', + verifyEmail: '/verify-email', + verifyUser: '/verify-user', + profile: '/profile', + jobsDiscovery: '/jobs-discovery', + jobs: '/jobs-discovery', + myJobs: '/my-jobs', + HcaptchaLabeling: '/hcaptcha-labeling', + enableLabeler: '/enable-labeler', + registrationInExchangeOracle: '/registration-in-exchange-oracle', } as const; diff --git a/packages/apps/human-app/frontend/src/router/router.tsx b/packages/apps/human-app/frontend/src/router/router.tsx index b22c8052d8..2db694ab2b 100644 --- a/packages/apps/human-app/frontend/src/router/router.tsx +++ b/packages/apps/human-app/frontend/src/router/router.tsx @@ -1,37 +1,11 @@ import { Routes, Route, Navigate } from 'react-router-dom'; -import { - protectedRoutes, - walletConnectRoutes, - unprotectedRoutes, - web3ProtectedRoutes, -} from '@/router/routes'; + +import { protectedRoutes, unprotectedRoutes } from '@/router/routes'; import { RequireAuth } from '@/modules/auth/providers/require-auth'; -import { RequireWalletConnect } from '@/shared/contexts/wallet-connect'; -import { RequireWeb3Auth } from '@/modules/auth-web3/providers/require-web3-auth'; -import { DrawerNavigation } from '@/router/components/layout/protected/drawer-navigation'; -import { operatorDrawerBottomMenuItems } from '@/router/components/drawer-menu-items/drawer-menu-items-operator'; -import { browserAuthProvider } from '@/shared/contexts/browser-auth-provider'; -import { useAuth } from '@/modules/auth/hooks/use-auth'; -import { UserStatsDrawer } from '@/modules/worker/hcaptcha-labeling'; import { routerPaths } from './router-paths'; -import { - ProtectedLayout, - UnprotectedLayout, - workerDrawerBottomMenuItems, - workerDrawerTopMenuItems, -} from './components'; +import { ProtectedLayout, UnprotectedLayout } from './components'; export function Router() { - const { user } = useAuth(); - - const handleSignOut = () => { - browserAuthProvider.signOut({ - callback: () => { - window.location.reload(); - }, - }); - }; - return ( }> @@ -39,40 +13,12 @@ export function Router() { ))} - }> - {walletConnectRoutes.map((route) => ( - - <>{route.element} - - } - key={route.path} - path={route.path} - /> - ))} - - {protectedRoutes.map(({ routerProps, pageHeaderProps }) => { + {protectedRoutes.map(({ routerProps }) => { return ( - ( - - )} - renderHCaptchaStatisticsDrawer={(isOpen) => ( - - )} - renderGovernanceBanner - /> + } key={routerProps.path} @@ -82,31 +28,6 @@ export function Router() { ); })} - {web3ProtectedRoutes.map(({ routerProps, pageHeaderProps }) => ( - - - ( - - )} - /> - - - } - key={routerProps.path} - path={routerProps.path} - > - - - ))} } path="*" /> diff --git a/packages/apps/human-app/frontend/src/router/routes.tsx b/packages/apps/human-app/frontend/src/router/routes.tsx index 46bff008ab..fd7bb01d82 100644 --- a/packages/apps/human-app/frontend/src/router/routes.tsx +++ b/packages/apps/human-app/frontend/src/router/routes.tsx @@ -1,44 +1,30 @@ import type { RouteProps } from 'react-router-dom'; -import { t } from 'i18next'; + import { routerPaths } from '@/router/router-paths'; import { env } from '@/shared/env'; + import { RegistrationPage } from '@/modules/worker/oracle-registration'; -import { - HandIcon, - ProfileIcon, - WorkHeaderIcon, -} from '@/shared/components/ui/icons'; -import type { PageHeaderProps } from '@/router/components/layout/protected/page-header'; import { HcaptchaLabelingPage, - UserStatsAccordion, EnableLabelerPage, } from '@/modules/worker/hcaptcha-labeling'; import { - WorkerEmailVerificationProcessPage, - WorkerVerifyEmailPage, + EmailVerificationProcessPage, + VerifyEmailPage, } from '@/modules/worker/email-verification'; -import { SignInWorkerPage } from '@/modules/signin/worker'; +import { SignInPage, VerifyUserPage } from '@/modules/signin/worker'; import { JobsDiscoveryPage } from '@/modules/worker/jobs-discovery'; -import { WorkerProfilePage } from '@/modules/worker/profile'; -import { SignUpWorkerPage } from '@/modules/signup/worker'; -import { OperatorProfilePage } from '@/modules/operator/profile'; +import { MyJobsPage } from '@/modules/worker/jobs/my-jobs/my-jobs.page'; +import { ProfilePage } from '@/modules/worker/profile'; +import { SignUpPage } from '@/modules/signup/worker'; import { HomePage } from '@/modules/homepage'; import { - AddKeysOperatorPage, - AddStakeOperatorPage, - ConnectWalletOperatorPage, - EditExistingKeysSuccessPage, - SetUpOperatorPage, -} from '@/modules/signup/operator'; -import { JobsPage } from '@/modules/worker/jobs'; -import { - ResetPasswordWorkerPage, - ResetPasswordWorkerSuccessPage, + ResetPasswordPage, + ResetPasswordSuccessPage, } from '@/modules/worker/reset-password'; import { - SendResetLinkWorkerPage, - SendResetLinkWorkerSuccessPage, + SendResetLinkPage, + SendResetLinkSuccessPage, } from '@/modules/worker/send-reset-link'; export const unprotectedRoutes: RouteProps[] = [ @@ -47,146 +33,84 @@ export const unprotectedRoutes: RouteProps[] = [ element: , }, { - path: routerPaths.worker.signIn, - element: , + path: routerPaths.signIn, + element: , }, { - path: routerPaths.worker.signUp, - element: , + path: routerPaths.signUp, + element: , }, { - path: routerPaths.operator.connectWallet, - element: , + path: routerPaths.emailVerification, + element: , }, { - path: routerPaths.worker.emailVerification, - element: , + path: routerPaths.verifyEmail, + element: , }, { - path: routerPaths.worker.verifyEmail, - element: , + path: routerPaths.verifyUser, + element: , }, { - path: routerPaths.worker.sendResetLink, - element: , + path: routerPaths.sendResetLink, + element: , }, { - path: routerPaths.worker.resetPassword, - element: , + path: routerPaths.resetPassword, + element: , }, { - path: routerPaths.worker.sendResetLinkSuccess, - element: , + path: routerPaths.sendResetLinkSuccess, + element: , }, { - path: routerPaths.worker.resetPasswordSuccess, - element: , + path: routerPaths.resetPasswordSuccess, + element: , }, ]; export const protectedRoutes: { routerProps: RouteProps; - pageHeaderProps: PageHeaderProps; }[] = [ { routerProps: { - path: routerPaths.worker.jobsDiscovery, + path: routerPaths.jobsDiscovery, element: , }, - pageHeaderProps: { - headerIcon: , - headerText: t('protectedPagesHeaders.jobsDiscovery'), + }, + { + routerProps: { + path: routerPaths.myJobs, + element: , }, }, ...(env.VITE_FEATURE_FLAG_JOBS_DISCOVERY ? [ { routerProps: { - path: `${routerPaths.worker.jobs}/:address`, - element: , - }, - pageHeaderProps: { - headerIcon: , - headerText: t('protectedPagesHeaders.jobs'), - }, - }, - { - routerProps: { - path: `${routerPaths.worker.registrationInExchangeOracle}/:address`, + path: `${routerPaths.registrationInExchangeOracle}/:address`, element: , }, - pageHeaderProps: { - headerIcon: , - headerText: t('protectedPagesHeaders.registrationInExchangeOracle'), - }, }, ] : []), { routerProps: { - path: routerPaths.worker.profile, - element: , - }, - pageHeaderProps: { - headerIcon: , - headerText: t('protectedPagesHeaders.profile'), + path: routerPaths.profile, + element: , }, }, { routerProps: { - path: routerPaths.worker.HcaptchaLabeling, + path: routerPaths.HcaptchaLabeling, element: , }, - pageHeaderProps: { - headerIcon: , - headerText: t('protectedPagesHeaders.hcaptchaLabeling'), - headerItem: , - }, }, { routerProps: { - path: routerPaths.worker.enableLabeler, + path: routerPaths.enableLabeler, element: , }, - pageHeaderProps: { - headerIcon: , - headerText: t('protectedPagesHeaders.hcaptchaLabeling'), - headerItem: , - }, - }, -]; - -export const web3ProtectedRoutes: { - routerProps: RouteProps; - pageHeaderProps: PageHeaderProps; -}[] = [ - { - routerProps: { - path: routerPaths.operator.profile, - element: , - }, - pageHeaderProps: { - headerIcon: , - headerText: t('web3ProtectedPagesHeaders.profile'), - }, - }, -]; - -export const walletConnectRoutes: RouteProps[] = [ - { - path: routerPaths.operator.addStake, - element: , - }, - { - path: routerPaths.operator.addKeys, - element: , - }, - { - path: routerPaths.operator.editExistingKeysSuccess, - element: , - }, - { - path: routerPaths.operator.setUpOperator, - element: , }, ]; diff --git a/packages/apps/human-app/frontend/src/shared/components/data-entry/checkbox.tsx b/packages/apps/human-app/frontend/src/shared/components/data-entry/checkbox.tsx deleted file mode 100644 index 6a479d3d10..0000000000 --- a/packages/apps/human-app/frontend/src/shared/components/data-entry/checkbox.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { Controller } from 'react-hook-form'; -import type { CheckboxProps } from '@mui/material/Checkbox'; -import CheckboxMui from '@mui/material/Checkbox'; -import FormControlLabel from '@mui/material/FormControlLabel'; -import Stack from '@mui/material/Stack'; -import Typography from '@mui/material/Typography'; -import { useColorMode } from '@/shared/contexts/color-mode'; - -interface InputProps extends Omit { - name: string; - label?: string; -} - -export function Checkbox({ name, label = '', ...rest }: InputProps) { - const { colorPalette } = useColorMode(); - - return ( - ( - - - } - label={{label}} - /> - - )} - /> - ); -} diff --git a/packages/apps/human-app/frontend/src/shared/components/data-entry/input.tsx b/packages/apps/human-app/frontend/src/shared/components/data-entry/input.tsx index 0cab598fd8..3ae76177f2 100644 --- a/packages/apps/human-app/frontend/src/shared/components/data-entry/input.tsx +++ b/packages/apps/human-app/frontend/src/shared/components/data-entry/input.tsx @@ -32,7 +32,7 @@ export function Input({ {...field} variant="outlined" autoComplete={autoComplete ?? name} - error={Boolean(fieldState.error)} + error={!!fieldState.error} fullWidth helperText={ { - options: { label: string; value: string }[]; - name: string; - label: string; -} - -type FieldType = ControllerRenderProps; - -const CLEAR_ALL_VALUE = 'CLEAR_ALL_VALUE'; -const CHECK_ALL_VALUE = 'CHECK_ALL_VALUE'; - -export function MultiSelect({ - name, - options, - label, - ...props -}: MultiSelectProps) { - const { colorPalette } = useColorMode(); - const { t } = useTranslation(); - const context = useFormContext(); - const valuesToLabels = useMemo(() => { - const mapping: Record = {}; - for (const option of options) { - mapping[option.value] = option.label; - } - return mapping; - }, [options]); - - const isFieldChecked = (field: FieldType, option: string) => { - if (Array.isArray(field.value)) { - return field.value.includes(option); - } - return false; - }; - - const onDelete = (value: string) => { - const currentValues = context.getValues()[name] as string[]; - - context.setValue( - name, - currentValues.filter((val) => { - return val !== value; - }) - ); - }; - - const renderValue = (selected: string[]) => ( - - {selected.map((value) => ( - { - e.stopPropagation(); - }} - /> - } - key={value} - label={valuesToLabels[value]} - onDelete={() => { - onDelete(value); - }} - sx={{ backgroundColor: colorPalette.chip.main }} - /> - ))} - - ); - - const handleChange = ( - event: SelectChangeEvent, - field: FieldType - ) => { - const value = event.target.value; - - if (value.includes(CLEAR_ALL_VALUE)) { - context.setValue(name, []); - return; - } - - if ( - value[value.length - 1] === CHECK_ALL_VALUE && - Array.isArray(field.value) - ) { - context.setValue( - name, - field.value.length === options.length ? [] : options - ); - } else { - context.setValue(name, value); - } - }; - - return ( - { - return ( - - {label} - - - {fieldState.error?.message} - - - ); - }} - /> - ); -} diff --git a/packages/apps/human-app/frontend/src/shared/components/data-entry/password/password.tsx b/packages/apps/human-app/frontend/src/shared/components/data-entry/password.tsx similarity index 81% rename from packages/apps/human-app/frontend/src/shared/components/data-entry/password/password.tsx rename to packages/apps/human-app/frontend/src/shared/components/data-entry/password.tsx index 5c51a96f55..cba51984cc 100644 --- a/packages/apps/human-app/frontend/src/shared/components/data-entry/password/password.tsx +++ b/packages/apps/human-app/frontend/src/shared/components/data-entry/password.tsx @@ -1,17 +1,17 @@ +import { useState, MouseEvent } from 'react'; import Visibility from '@mui/icons-material/Visibility'; import VisibilityOff from '@mui/icons-material/VisibilityOff'; -import { useState, MouseEvent } from 'react'; -import InputAdornment from '@mui/material/InputAdornment'; -import IconButton from '@mui/material/IconButton'; +import { IconButton, InputAdornment } from '@mui/material'; import { Input, type InputProps } from '@/shared/components/data-entry/input'; -import { useColorMode } from '@/shared/contexts/color-mode'; +import { useColorMode } from '@/shared/contexts/color-mode/use-color-mode'; type PasswordProps = InputProps & { type?: never }; export function Password(props: PasswordProps) { - const { colorPalette } = useColorMode(); const [showPassword, setShowPassword] = useState(false); + const { colorPalette } = useColorMode(); + const handleClickShowPassword = () => { setShowPassword((show) => !show); }; @@ -34,9 +34,9 @@ export function Password(props: PasswordProps) { onMouseDown={handleMouseDownPassword} > {showPassword ? ( - + ) : ( - + )} diff --git a/packages/apps/human-app/frontend/src/shared/components/data-entry/radio-button.tsx b/packages/apps/human-app/frontend/src/shared/components/data-entry/radio-button.tsx deleted file mode 100644 index e3e1131bb6..0000000000 --- a/packages/apps/human-app/frontend/src/shared/components/data-entry/radio-button.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { Controller } from 'react-hook-form'; -import type { RadioGroupProps as RadioGroupPropsMui } from '@mui/material/RadioGroup'; -import RadioGroup from '@mui/material/RadioGroup'; -import FormControl from '@mui/material/FormControl'; -import FormLabel from '@mui/material/FormLabel'; -import FormControlLabel from '@mui/material/FormControlLabel'; -import Radio from '@mui/material/Radio'; -import FormHelperText from '@mui/material/FormHelperText'; - -interface RadioGroupProps extends Omit { - name: string; - ariaLabelledby?: string; - groupLabel?: string; - options: { label: string; value: string | number }[]; -} - -export function RadioButton({ - name, - ariaLabelledby, - options, - groupLabel, - ...rest -}: RadioGroupProps) { - return ( - ( - - {groupLabel ? ( - {groupLabel} - ) : null} - - {options.map(({ label, value }) => ( - } - key={value} - label={label} - value={value} - /> - ))} - - {fieldState.error?.message} - - )} - /> - ); -} diff --git a/packages/apps/human-app/frontend/src/shared/components/data-entry/select.tsx b/packages/apps/human-app/frontend/src/shared/components/data-entry/select.tsx deleted file mode 100644 index d030114f5d..0000000000 --- a/packages/apps/human-app/frontend/src/shared/components/data-entry/select.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import type { SelectProps } from '@mui/material/Select'; -import FormControl from '@mui/material/FormControl'; -import SelectMui from '@mui/material/Select'; -import MenuItem from '@mui/material/MenuItem'; -import { Controller } from 'react-hook-form'; -import InputLabel from '@mui/material/InputLabel'; -import FormHelperText from '@mui/material/FormHelperText'; -import { Chip } from '@/shared/components/ui/chip'; -import { useColorMode } from '@/shared/contexts/color-mode'; - -export interface OptionsProps { - id: number; - name: string; - value: string; -} - -interface SelectComponentProps extends Omit { - options: OptionsProps[]; - name: string; - label?: string; - ariaLabelledby?: string; - isChipRenderValue?: boolean; -} - -export function Select({ - ariaLabelledby, - name, - label, - options, - isChipRenderValue, - ...props -}: SelectComponentProps) { - const { colorPalette } = useColorMode(); - return ( - ( - - {label ? {label} : null} - - : undefined - } - > - {options.map((elem) => ( - - {elem.name} - - ))} - - {fieldState.error?.message} - - )} - /> - ); -} diff --git a/packages/apps/human-app/frontend/src/shared/components/data-entry/slider.tsx b/packages/apps/human-app/frontend/src/shared/components/data-entry/slider.tsx deleted file mode 100644 index 85214b362f..0000000000 --- a/packages/apps/human-app/frontend/src/shared/components/data-entry/slider.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { Controller } from 'react-hook-form'; -import type { SliderProps } from '@mui/material/Slider'; -import SliderMui from '@mui/material/Slider'; -import type { ReactNode } from 'react'; - -interface InputProps extends Omit { - max: number; - min: number; - step?: number; - name: string; - customMarks?: ReactNode; -} - -export function Slider({ - name, - max, - min, - step, - customMarks, - ...rest -}: InputProps) { - return ( - ( - <> - - {customMarks ? customMarks : null} - - )} - /> - ); -} diff --git a/packages/apps/human-app/frontend/src/shared/components/expiration-modal.tsx b/packages/apps/human-app/frontend/src/shared/components/expiration-modal.tsx index 8208ef17a6..50d087c3cf 100644 --- a/packages/apps/human-app/frontend/src/shared/components/expiration-modal.tsx +++ b/packages/apps/human-app/frontend/src/shared/components/expiration-modal.tsx @@ -1,69 +1,55 @@ import { t } from 'i18next'; -import { Grid, Typography } from '@mui/material'; +import { Stack, Typography } from '@mui/material'; import { useNavigate } from 'react-router-dom'; import { Button } from '@/shared/components/ui/button'; import { routerPaths } from '@/router/router-paths'; import { browserAuthProvider } from '@/shared/contexts/browser-auth-provider'; -import { breakpoints } from '@/shared/styles/breakpoints'; import { useModal } from '@/shared/contexts/modal-context'; +import { useColorMode } from '../contexts/color-mode'; export function ExpirationModal() { const { closeModal } = useModal(); const navigate = useNavigate(); + const { colorPalette } = useColorMode(); + + const handleOnSignInClick = () => { + browserAuthProvider.signOut(); + navigate(routerPaths.signIn, { replace: true }); + closeModal(); + }; return ( - - - {t('expirationModal.header')} - - + + {t('expirationModal.header')} + + + {t('expirationModal.description')} - - - + + + ); } diff --git a/packages/apps/human-app/frontend/src/shared/components/hcaptcha/h-captcha.tsx b/packages/apps/human-app/frontend/src/shared/components/hcaptcha/h-captcha.tsx index 1bcd5e3b4c..f548c4c862 100644 --- a/packages/apps/human-app/frontend/src/shared/components/hcaptcha/h-captcha.tsx +++ b/packages/apps/human-app/frontend/src/shared/components/hcaptcha/h-captcha.tsx @@ -1,7 +1,6 @@ import { forwardRef, useImperativeHandle, useRef } from 'react'; import HCaptcha from '@hcaptcha/react-hcaptcha'; import { env } from '@/shared/env'; -import { useColorMode } from '@/shared/contexts/color-mode'; export interface CustomHCaptchaRef { reset: () => void; @@ -15,7 +14,6 @@ function InternalHCaptcha( { onVerify }: CustomHCaptchaProps, ref: React.Ref ) { - const { isDarkMode } = useColorMode(); const captchaRef = useRef(null); useImperativeHandle(ref, () => ({ @@ -33,7 +31,7 @@ function InternalHCaptcha( }} ref={captchaRef} sitekey={env.VITE_H_CAPTCHA_SITE_KEY} - theme={isDarkMode ? 'dark' : 'light'} + theme="contrast" /> ); } diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/alert.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/alert.tsx index 12d26491a1..452c468e7b 100644 --- a/packages/apps/human-app/frontend/src/shared/components/ui/alert.tsx +++ b/packages/apps/human-app/frontend/src/shared/components/ui/alert.tsx @@ -1,9 +1,11 @@ import CheckCircleIcon from '@mui/icons-material/CheckCircle'; import WarningIcon from '@mui/icons-material/Warning'; import ErrorIcon from '@mui/icons-material/Error'; -import MuiAlert from '@mui/material/Alert'; -import type { AlertProps as MuiAlertProps } from '@mui/material/Alert'; -import { Typography } from '@mui/material'; +import { + Alert as MuiAlert, + type AlertProps as MuiAlertProps, + Typography, +} from '@mui/material'; import { useColorMode } from '@/shared/contexts/color-mode'; import { darkColorPalette } from '@/shared/styles/dark-color-palette'; diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/base-drawer.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/base-drawer.tsx new file mode 100644 index 0000000000..b6fd290417 --- /dev/null +++ b/packages/apps/human-app/frontend/src/shared/components/ui/base-drawer.tsx @@ -0,0 +1,74 @@ +import { useCallback, type PropsWithChildren } from 'react'; +import { Drawer, IconButton, type SxProps, type Theme } from '@mui/material'; +import CloseIcon from '@mui/icons-material/Close'; +import { useColorMode } from '@/shared/contexts/color-mode/use-color-mode'; + +type Props = { + open: boolean; + onClose: () => void; + isLoading?: boolean; + sx?: SxProps; + closeButtonSx?: SxProps; +}; + +export function BaseDrawer({ + open, + onClose, + isLoading = false, + sx, + closeButtonSx, + children, +}: PropsWithChildren) { + const { colorPalette } = useColorMode(); + + const handleClose = useCallback(() => { + if (isLoading) return; + onClose(); + }, [isLoading, onClose]); + + return ( + theme.zIndex.drawer, + }} + slotProps={{ + backdrop: { + sx: { + backdropFilter: 'blur(7px)', + background: 'rgba(0, 0, 0, 0.3)', + }, + }, + paper: { + elevation: 0, + sx: { + py: 2, + borderTopLeftRadius: '16px', + borderTopRightRadius: '16px', + border: 'none', + height: '75dvh', + bgcolor: `${colorPalette.background.paper} !important`, + ...sx, + }, + }, + }} + > + + + + {children} + + ); +} diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/chain-icon.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/chain-icon.tsx new file mode 100644 index 0000000000..2115b7196f --- /dev/null +++ b/packages/apps/human-app/frontend/src/shared/components/ui/chain-icon.tsx @@ -0,0 +1,33 @@ +import { ReactElement } from 'react'; +import { ChainId } from '@human-protocol/sdk/src/enums'; + +import { EthereumIcon, PolygonIcon } from './icons'; +import { Stack, Tooltip } from '@mui/material'; +import { getNetworkName } from '@/modules/smart-contracts/get-network-name'; + +const CHAIN_ICONS: Partial> = { + [ChainId.MAINNET]: , + [ChainId.SEPOLIA]: , + [ChainId.POLYGON]: , + [ChainId.POLYGON_AMOY]: , +}; + +export function ChainIcon({ chainId }: { chainId: number }) { + if (!CHAIN_ICONS[chainId]) { + return null; + } + + return ( + + + {CHAIN_ICONS[chainId]} + + + ); +} diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/chip.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/chip.tsx index 9289815451..876c5f4f97 100644 --- a/packages/apps/human-app/frontend/src/shared/components/ui/chip.tsx +++ b/packages/apps/human-app/frontend/src/shared/components/ui/chip.tsx @@ -19,6 +19,7 @@ export function Chip({ label, backgroundColor }: Readonly) { py: '2px', borderRadius: '16px', display: 'flex', + flexShrink: 0, wordBreak: 'break-word', }} > diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/chips.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/chips.tsx deleted file mode 100644 index 4d9baa2b9f..0000000000 --- a/packages/apps/human-app/frontend/src/shared/components/ui/chips.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { Grid } from '@mui/material'; -import { Chip } from '@/shared/components/ui/chip'; - -interface ChipsProps { - data: string[]; -} - -export function Chips({ data }: ChipsProps) { - return ( - - {data.map((chipLabel) => ( - - ))} - - ); -} diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/connect-wallet-btn.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/connect-wallet-btn.tsx deleted file mode 100644 index 13d546f536..0000000000 --- a/packages/apps/human-app/frontend/src/shared/components/ui/connect-wallet-btn.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { useTranslation } from 'react-i18next'; -import type { CustomButtonProps } from '@/shared/components/ui/button'; -import { Button } from '@/shared/components/ui/button'; -import { useWalletConnect } from '@/shared/contexts/wallet-connect'; - -export function ConnectWalletBtn(props: CustomButtonProps) { - const { openModal, isConnected } = useWalletConnect(); - const { t } = useTranslation(); - const defaultStatus = isConnected - ? t('components.wallet.connectBtn.disconnect') - : t('components.wallet.connectBtn.connect'); - const btnContent = props.children ? props.children : defaultStatus; - - return ( - - ); -} diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/copy-to-clipboard-button.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/copy-to-clipboard-button.tsx new file mode 100644 index 0000000000..6b4fb99271 --- /dev/null +++ b/packages/apps/human-app/frontend/src/shared/components/ui/copy-to-clipboard-button.tsx @@ -0,0 +1,60 @@ +import { useEffect, useRef, useState, type MouseEvent } from 'react'; +import { IconButton, SxProps, Theme, Tooltip } from '@mui/material'; +import { t } from 'i18next'; + +import { CopyIcon } from './icons'; + +type Props = { + value: string; + sx?: SxProps; +}; + +export function CopyToClipboardButton({ value, sx }: Props) { + const [isCopied, setIsCopied] = useState(false); + const timeoutRef = useRef(null); + + const handleCopyClick = (e: MouseEvent) => { + if (isCopied) return; + + e.stopPropagation(); + navigator.clipboard.writeText(value ?? ''); + setIsCopied(true); + + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + } + + timeoutRef.current = setTimeout(() => { + setIsCopied(false); + }, 1500); + }; + + useEffect(() => { + return () => { + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + timeoutRef.current = null; + } + }; + }, []); + + return ( + + + + + + ); +} diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/dark-mode-switch.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/dark-mode-switch.tsx index 6e41830d90..4d219772cd 100644 --- a/packages/apps/human-app/frontend/src/shared/components/ui/dark-mode-switch.tsx +++ b/packages/apps/human-app/frontend/src/shared/components/ui/dark-mode-switch.tsx @@ -1,27 +1,49 @@ -import { Grid, Switch } from '@mui/material'; +import { Box, IconButton } from '@mui/material'; import { MoonIcon, SunIcon } from '@/shared/components/ui/icons'; import { useColorMode } from '@/shared/contexts/color-mode'; -export function DarkModeSwitch() { - const { switchMode, isDarkMode } = useColorMode(); +export function ColorModeSwitch() { + const { switchMode, colorPalette, isDarkMode } = useColorMode(); + return ( - - - { - switchMode(); + + + + - - + onClick={switchMode} + > + + + ); } diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/empty-placeholder.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/empty-placeholder.tsx deleted file mode 100644 index af69611f13..0000000000 --- a/packages/apps/human-app/frontend/src/shared/components/ui/empty-placeholder.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import Typography from '@mui/material/Typography'; -import { t } from 'i18next'; -import { useColorMode } from '@/shared/contexts/color-mode'; - -export function EmptyPlaceholder() { - const { colorPalette } = useColorMode(); - - return ( - - {t('operator.addKeysPage.existingKeys.noValue')} - - ); -} diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/icons.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/icons.tsx index f58d0b3cba..377dc1675a 100644 --- a/packages/apps/human-app/frontend/src/shared/components/ui/icons.tsx +++ b/packages/apps/human-app/frontend/src/shared/components/ui/icons.tsx @@ -1,71 +1,30 @@ -import HomepageLogoIconLight from '@/assets/icons/icons-homepage/logo.svg'; -import HomepageLogoIconDark from '@/assets/icons-dark-mode/icons-homepage/logo.svg'; -import HomepageUserIconLight from '@/assets/icons/icons-homepage/user.svg'; -import HomepageUserIconDark from '@/assets/icons-dark-mode/icons-homepage/user.svg'; -import HomepageWorkIconLight from '@/assets/icons/icons-homepage/work.svg'; -import HomepageWorkIconDark from '@/assets/icons-dark-mode/icons-homepage/work.svg'; -import HumanLogoIconLight from '@/assets/icons/icons-human-logo/human-logo.svg'; -import HumanLogoIconDark from '@/assets/icons-dark-mode/icons-human-logo/human-logo.svg'; -import ChatIcon from '@/assets/icons/chat.svg'; -import HandIconLight from '@/assets/icons/hand.svg'; -import HandIconDark from '@/assets/icons-dark-mode/hand.svg'; +import { SvgIcon, SvgIconProps } from '@mui/material'; + +import { useColorMode } from '@/shared/contexts/color-mode'; + import RefreshIconLight from '@/assets/icons/refresh.svg'; import RefreshIconDark from '@/assets/icons-dark-mode/refresh.svg'; -import UserOutlinedIconLight from '@/assets/icons/user-outlined.svg'; -import UserOutlinedIconDark from '@/assets/icons-dark-mode/user-outlined.svg'; -import WorkIconLight from '@/assets/icons/work.svg'; -import WorkIconDark from '@/assets/icons-dark-mode/work.svg'; import HumanLogoNavbarIconLight from '@/assets/icons/icons-navbar/human-logo-navbar.svg'; import HumanLogoNavbarIconDark from '@/assets/icons-dark-mode/icons-navbar/human-logo-navbar.svg'; import HelpIconLight from '@/assets/icons/help.svg'; import HelpIconDark from '@/assets/icons-dark-mode/help.svg'; -import ProfileIconLight from '@/assets/icons/profile-icon.svg'; -import ProfileIconDark from '@/assets/icons-dark-mode/profile-icon.svg'; import CheckmarkIcon from '@/assets/icons/checkmark-icon.svg'; -import LockerIconLight from '@/assets/icons/locker-icon.svg'; -import LockerIconDark from '@/assets/icons-dark-mode/locker-icon.svg'; -import FiltersButtonIconLight from '@/assets/icons/filters-button-icon.svg'; -import FiltersButtonIconDark from '@/assets/icons-dark-mode/filters-button-icon.svg'; -import SortArrowLight from '@/assets/icons/sort-arrow.svg'; -import SortArrowDark from '@/assets/icons-dark-mode/sort-arrow.svg'; -import FiltersIconLight from '@/assets/icons/filters-icon.svg'; -import FiltersIconDark from '@/assets/icons-dark-mode/filters-icon.svg'; -import MobileHomeIconsLight from '@/assets/icons/icons-homepage/mobile-home-icons.svg'; -import MobileHomeIconsDark from '@/assets/icons-dark-mode/icons-homepage/mobile-home-icons.svg'; import SunIconDark from '@/assets/icons-dark-mode/sun.svg'; import SunIconLight from '@/assets/icons/sun.svg'; import MoonIconDark from '@/assets/icons-dark-mode/moon.svg'; import MoonIconLight from '@/assets/icons/moon.svg'; -import { useColorMode } from '@/shared/contexts/color-mode'; -import WorkHeaderDark from '@/assets/icons-dark-mode/work-header.svg'; -import WorkHeaderLight from '@/assets/icons/work-header.svg'; -import CopyIconLight from '@/assets/icons/content-copy.svg'; -import CopyIconDark from '@/assets/icons-dark-mode/content-copy.svg'; -import EditIconLight from '@/assets/icons/edit-icon.svg'; -import EditIconDark from '@/assets/icons-dark-mode/edit-icon.svg'; -import DeleteIconLight from '@/assets/icons/delete-icon.svg'; -import DeleteIconDark from '@/assets/icons-dark-mode/delete-icon.svg'; +import VeriffIconLight from '@/assets/icons/veriff.svg'; +import VeriffIconDark from '@/assets/icons-dark-mode/veriff.svg'; +import HourglassIconLight from '@/assets/icons/hourglass.svg'; +import HourglassIconDark from '@/assets/icons-dark-mode/hourglass.svg'; +import LogoutIcon from '@/assets/icons/logout.svg'; +import TriangleIcon from '@/assets/icons/triangle.svg'; +import HcaptchaIconAsset from '@/assets/icons/hcaptcha.svg'; +import HcaptchaDisabledIconLight from '@/assets/icons/hcaptcha-disabled-icon.svg'; +import HcaptchaDisabledIconDark from '@/assets/icons-dark-mode/hcaptcha-disabled-icon.svg'; +import EthereumIcon from '@/assets/icons/ethereum-icon.svg'; +import PolygonIcon from '@/assets/icons/polygon-icon.svg'; -function HomepageLogoIcon() { - const { isDarkMode } = useColorMode(); - return isDarkMode ? : ; -} -function HomepageUserIcon() { - const { isDarkMode } = useColorMode(); - return isDarkMode ? : ; -} -function HomepageWorkIcon() { - const { isDarkMode } = useColorMode(); - return isDarkMode ? : ; -} -function MobileHomeIcons() { - const { isDarkMode } = useColorMode(); - return isDarkMode ? : ; -} -function HumanLogoIcon() { - const { isDarkMode } = useColorMode(); - return isDarkMode ? : ; -} function HumanLogoNavbarIcon() { const { isDarkMode } = useColorMode(); return isDarkMode ? ( @@ -74,99 +33,295 @@ function HumanLogoNavbarIcon() { ); } -function WorkHeaderIcon() { - const { isDarkMode } = useColorMode(); - return isDarkMode ? : ; -} -function HandIcon() { - const { isDarkMode } = useColorMode(); - return isDarkMode ? : ; -} function RefreshIcon() { const { isDarkMode } = useColorMode(); return isDarkMode ? : ; } -function InverseRefreshIcon() { +function HelpIcon() { const { isDarkMode } = useColorMode(); - return isDarkMode ? : ; + return isDarkMode ? : ; } -function UserOutlinedIcon() { +function SunIcon() { const { isDarkMode } = useColorMode(); - return isDarkMode ? : ; + return isDarkMode ? : ; } -function WorkIcon() { +function MoonIcon() { const { isDarkMode } = useColorMode(); - return isDarkMode ? : ; + return isDarkMode ? : ; } -function HelpIcon() { +function VeriffIcon() { const { isDarkMode } = useColorMode(); - return isDarkMode ? : ; + return isDarkMode ? : ; } -function ProfileIcon() { +function HourglassIcon() { const { isDarkMode } = useColorMode(); - return isDarkMode ? : ; + return isDarkMode ? : ; } -function LockerIcon() { - const { isDarkMode } = useColorMode(); - return isDarkMode ? : ; +function HcaptchaIcon() { + return ; } -function FiltersButtonIcon() { +function HcaptchaDisabledIcon() { const { isDarkMode } = useColorMode(); - return isDarkMode ? : ; + return isDarkMode ? ( + + ) : ( + + ); } -function SortArrow() { - const { isDarkMode } = useColorMode(); - return isDarkMode ? : ; + +function InboxIcon(props: SvgIconProps) { + return ( + + + + + + + ); } -function FiltersIcon() { - const { isDarkMode } = useColorMode(); - return isDarkMode ? : ; + +function SuccessIcon(props: SvgIconProps) { + return ( + + + + + + ); } -function SunIcon() { - const { isDarkMode } = useColorMode(); - return isDarkMode ? : ; + +function CopyIcon(props: SvgIconProps) { + return ( + + + + + + + + + + + + ); } -function MoonIcon() { - const { isDarkMode } = useColorMode(); - return isDarkMode ? : ; + +function OracleAddressIcon(props: SvgIconProps) { + return ( + + + + + ); } -function CopyIcon() { - const { isDarkMode } = useColorMode(); - return isDarkMode ? : ; + +function OracleRewardIcon(props: SvgIconProps) { + return ( + + + + + ); } -function EditIcon() { - const { isDarkMode } = useColorMode(); - return isDarkMode ? : ; + +function MenuIcon(props: SvgIconProps) { + return ( + + + + + + ); } -function DeleteIcon() { - const { isDarkMode } = useColorMode(); - return isDarkMode ? : ; + +function FilterIcon(props: SvgIconProps) { + return ( + + + + ); +} + +function JobExpiryTimeIcon(props: SvgIconProps) { + return ( + + + + + + ); +} + +function JobStatusIcon(props: SvgIconProps) { + return ( + + + + + + ); } export { - HomepageLogoIcon, - HomepageUserIcon, - HomepageWorkIcon, - MobileHomeIcons, - HumanLogoIcon, HumanLogoNavbarIcon, - ChatIcon, - HandIcon, RefreshIcon, - InverseRefreshIcon, - UserOutlinedIcon, - WorkIcon, HelpIcon, - ProfileIcon, CheckmarkIcon, - LockerIcon, - FiltersButtonIcon, - SortArrow, - FiltersIcon, SunIcon, MoonIcon, - WorkHeaderIcon, CopyIcon, - EditIcon, - DeleteIcon, + InboxIcon, + SuccessIcon, + VeriffIcon, + HourglassIcon, + LogoutIcon, + TriangleIcon, + OracleAddressIcon, + OracleRewardIcon, + MenuIcon, + HcaptchaIcon, + HcaptchaDisabledIcon, + FilterIcon, + JobExpiryTimeIcon, + JobStatusIcon, + EthereumIcon, + PolygonIcon, }; diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/list-item.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/list-item.tsx deleted file mode 100644 index 3ea1647136..0000000000 --- a/packages/apps/human-app/frontend/src/shared/components/ui/list-item.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Typography, ListItem as MuiListItem } from '@mui/material'; - -export function ListItem({ - children, - label, -}: { - children: React.ReactElement; - label: string; -}) { - return ( - - - {label} - - {children} - - ); -} diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/loader.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/loader.tsx index 1c32b0f261..2c8b220c56 100644 --- a/packages/apps/human-app/frontend/src/shared/components/ui/loader.tsx +++ b/packages/apps/human-app/frontend/src/shared/components/ui/loader.tsx @@ -10,7 +10,7 @@ export function Loader({ ...props }: CircularProgressProps) { {...props} sx={{ '.MuiCircularProgress-circle': { - color: colorPalette.primary.main, + color: colorPalette.accent.main, }, }} /> diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/modal/base-modal.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/modal/base-modal.tsx new file mode 100644 index 0000000000..414f165a2e --- /dev/null +++ b/packages/apps/human-app/frontend/src/shared/components/ui/modal/base-modal.tsx @@ -0,0 +1,92 @@ +import { type PropsWithChildren, useCallback } from 'react'; +import CloseIcon from '@mui/icons-material/Close'; +import { + IconButton, + Modal, + Paper, + type SxProps, + type Theme, +} from '@mui/material'; + +import { useColorMode } from '@/shared/contexts/color-mode/use-color-mode'; + +type Props = { + open: boolean; + onClose: () => void; + isLoading?: boolean; + sx?: SxProps; + closeButtonSx?: SxProps; +}; + +export function BaseModal({ + open, + onClose, + isLoading = false, + sx, + closeButtonSx, + children, +}: PropsWithChildren) { + const { colorPalette } = useColorMode(); + + const handleClose = useCallback(() => { + if (isLoading) return; + onClose(); + }, [isLoading, onClose]); + + return ( + + + + + + {children} + + + ); +} diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/modal/global-modal.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/modal/global-modal.tsx index 360a2c3867..d5d91e614e 100644 --- a/packages/apps/human-app/frontend/src/shared/components/ui/modal/global-modal.tsx +++ b/packages/apps/human-app/frontend/src/shared/components/ui/modal/global-modal.tsx @@ -17,6 +17,7 @@ export function GlobalModal() { open={open} onClose={!disableClose ? closeModal : undefined} onTransitionExited={onTransitionExited} + sx={{ zIndex: (theme) => theme.zIndex.modal }} slotProps={{ paper: { sx: { diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/no-records.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/no-records.tsx index 190638947e..cf7b5fae01 100644 --- a/packages/apps/human-app/frontend/src/shared/components/ui/no-records.tsx +++ b/packages/apps/human-app/frontend/src/shared/components/ui/no-records.tsx @@ -1,4 +1,5 @@ import { Grid } from '@mui/material'; +import { t } from 'i18next'; import { useColorMode } from '@/shared/contexts/color-mode'; export function NoRecords() { @@ -7,13 +8,13 @@ export function NoRecords() { return ( - No records to display + {t('components.noRecords')} ); } diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/optional-text.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/optional-text.tsx deleted file mode 100644 index 9d016fe0ae..0000000000 --- a/packages/apps/human-app/frontend/src/shared/components/ui/optional-text.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import Grid from '@mui/material/Grid'; -import { EmptyPlaceholder } from '@/shared/components/ui/empty-placeholder'; - -export function OptionalText({ text }: { text?: string }) { - if (!text) { - return ; - } - - return ( - - {text} - - ); -} diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/page-card/back-button.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/page-card/back-button.tsx new file mode 100644 index 0000000000..1340cad033 --- /dev/null +++ b/packages/apps/human-app/frontend/src/shared/components/ui/page-card/back-button.tsx @@ -0,0 +1,31 @@ +import { IconButton } from '@mui/material'; +import ArrowBackIcon from '@mui/icons-material/ArrowBack'; +import { useColorMode } from '@/shared/contexts/color-mode'; + +export function BackButton({ onClick }: { onClick: () => void }) { + const { isDarkMode, colorPalette } = useColorMode(); + + return ( + + + + ); +} diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/page-card/page-card-error.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/page-card/page-card-error.tsx index c86e5e6d71..aeedae8122 100644 --- a/packages/apps/human-app/frontend/src/shared/components/ui/page-card/page-card-error.tsx +++ b/packages/apps/human-app/frontend/src/shared/components/ui/page-card/page-card-error.tsx @@ -1,49 +1,37 @@ -import { Grid } from '@mui/material'; import { useNavigate } from 'react-router-dom'; import { t } from 'i18next'; +import { Stack } from '@mui/material'; + import { Button } from '@/shared/components/ui/button'; -import { routerPaths } from '@/router/router-paths'; import { Alert } from '@/shared/components/ui/alert'; -import { useColorMode } from '@/shared/contexts/color-mode'; -import { commonDarkPageCardStyles, commonPageCardStyles } from './styles'; import { type ErrorMessageProps } from './types'; +import { commonStyles } from './styles'; export function PageCardError({ errorMessage, cardMaxWidth = '100%', -}: Readonly) { - const { isDarkMode } = useColorMode(); +}: ErrorMessageProps) { const navigate = useNavigate(); - const commonStyleForTheme = isDarkMode - ? commonDarkPageCardStyles - : commonPageCardStyles; - const sx = cardMaxWidth - ? { ...commonStyleForTheme, maxWidth: cardMaxWidth } - : commonStyleForTheme; + ? { ...commonStyles, maxWidth: cardMaxWidth } + : commonStyles; return ( - + {errorMessage} - - + ); } diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/page-card/page-card-loader.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/page-card/page-card-loader.tsx index fc13e4a9f0..ca6fbdb51e 100644 --- a/packages/apps/human-app/frontend/src/shared/components/ui/page-card/page-card-loader.tsx +++ b/packages/apps/human-app/frontend/src/shared/components/ui/page-card/page-card-loader.tsx @@ -1,26 +1,24 @@ -import { Grid } from '@mui/material'; +import { Stack } from '@mui/material'; + import { Loader } from '@/shared/components/ui/loader'; -import { useColorMode } from '@/shared/contexts/color-mode'; -import { commonDarkPageCardStyles, commonPageCardStyles } from './styles'; +import { useIsMobile } from '@/shared/hooks'; + +import { commonStyles } from './styles'; import { type CommonProps } from './types'; export function PageCardLoader({ cardMaxWidth = '100%' }: CommonProps) { - const { isDarkMode } = useColorMode(); - - const commonStyleForTheme = isDarkMode - ? commonDarkPageCardStyles - : commonPageCardStyles; + const isMobile = useIsMobile(); const sx = cardMaxWidth ? { - ...commonStyleForTheme, + ...commonStyles, maxWidth: cardMaxWidth, } - : commonStyleForTheme; + : commonStyles; return ( - - - + + + ); } diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/page-card/page-card.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/page-card/page-card.tsx index a1abcd6eaf..f398af4c63 100644 --- a/packages/apps/human-app/frontend/src/shared/components/ui/page-card/page-card.tsx +++ b/packages/apps/human-app/frontend/src/shared/components/ui/page-card/page-card.tsx @@ -1,28 +1,8 @@ -import { Grid, Typography, styled } from '@mui/material'; -import ArrowBackIcon from '@mui/icons-material/ArrowBack'; +import { Grid, Stack, Typography } from '@mui/material'; import { useNavigate } from 'react-router-dom'; -import { t } from 'i18next'; -import { Button } from '@/shared/components/ui/button'; -import { breakpoints } from '@/shared/styles/breakpoints'; -import { routerPaths } from '@/router/router-paths'; -import { onlyDarkModeColor } from '@/shared/styles/dark-color-palette'; -import { useColorMode } from '@/shared/contexts/color-mode'; -import { useIsMobile } from '@/shared/hooks/use-is-mobile'; -import { commonDarkPageCardStyles, commonPageCardStyles } from './styles'; -const IconWrapper = styled('div')(() => ({ - width: '40px', - height: '40px', - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - borderRadius: '50%', - cursor: 'pointer', - ':hover': { - cursor: 'pointer', - }, - fontSize: '26px', -})); +import { commonStyles } from './styles'; +import { BackButton } from './back-button'; type NavigationTarget = string | (() => void); @@ -33,8 +13,6 @@ interface PageCardProps { title?: React.JSX.Element | string; alert?: React.JSX.Element; backNavigation?: NavigationTarget; - cancelNavigation?: NavigationTarget; - showCancelButton?: boolean; showBackButton?: boolean; loader?: boolean; } @@ -46,20 +24,13 @@ export function PageCard({ backNavigation, maxContentWidth = '376px', childrenMaxWidth = '486px', - cancelNavigation = routerPaths.homePage, - showCancelButton = true, showBackButton = true, }: PageCardProps) { - const { isDarkMode, colorPalette } = useColorMode(); const navigate = useNavigate(); - const isMobile = useIsMobile('md'); const contentStyles = { - maxWidth: maxContentWidth, + maxWidth: { xs: 'unset', md: maxContentWidth }, width: '100%', - [breakpoints.mobile]: { - maxWidth: 'unset', - }, }; const goBack = (navigationTarget: NavigationTarget | undefined) => { @@ -78,48 +49,22 @@ export function PageCard({ goBack(backNavigation); }; - const handleCancelButton = () => { - goBack(cancelNavigation); - }; - return ( - - {showCancelButton && ( - - - - )} - {showBackButton && ( - - - - )} - {showCancelButton && ( - - )} + {showBackButton && } {alert && <>{alert}} @@ -181,28 +99,13 @@ export function PageCard({ - {showBackButton && ( - - - - )} + {showBackButton && } @@ -219,6 +122,6 @@ export function PageCard({ - + ); } diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/page-card/styles.ts b/packages/apps/human-app/frontend/src/shared/components/ui/page-card/styles.ts index e26f4b48a7..e084791850 100644 --- a/packages/apps/human-app/frontend/src/shared/components/ui/page-card/styles.ts +++ b/packages/apps/human-app/frontend/src/shared/components/ui/page-card/styles.ts @@ -1,29 +1,7 @@ -import type { SxProps, Theme } from '@mui/material'; -import { breakpoints } from '@/shared/styles/breakpoints'; -import { colorPalette as constColorPalette } from '@/shared/styles/color-palette'; -import { darkColorPalette as constDarkColorPalette } from '@/shared/styles/dark-color-palette'; - -export const commonPageCardStyles: SxProps = { - flexDirection: 'column', +export const commonStyles = { justifyContent: 'center', alignItems: 'center', - borderRadius: '20px', - minHeight: '70vh', maxWidth: '1600px', width: '100%', - background: constColorPalette.white, -}; - -export const commonDarkPageCardStyles: SxProps = { - flexDirection: 'column', - justifyContent: 'center', - alignItems: 'center', - borderRadius: '20px', - minHeight: '70vh', - maxWidth: '1600px', - width: '100%', - background: constDarkColorPalette.paper.main, - [breakpoints.mobile]: { - background: constDarkColorPalette.backgroundColor, - }, + background: 'transparent', }; diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/profile/index.ts b/packages/apps/human-app/frontend/src/shared/components/ui/profile/index.ts deleted file mode 100644 index 232a412eb0..0000000000 --- a/packages/apps/human-app/frontend/src/shared/components/ui/profile/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './profile-list-item'; diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/profile/profile-list-item.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/profile/profile-list-item.tsx deleted file mode 100644 index 2e0cc2471b..0000000000 --- a/packages/apps/human-app/frontend/src/shared/components/ui/profile/profile-list-item.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import { ListItem, ListItemText, Stack, Typography } from '@mui/material'; -import { useTranslation } from 'react-i18next'; -import { Button } from '@/shared/components/ui/button'; -import { CheckmarkIcon, LockerIcon } from '@/shared/components/ui/icons'; -import { Chips } from '@/shared/components/ui/chips'; -import { useColorMode } from '@/shared/contexts/color-mode'; - -interface ProfileListItemProps { - header: string; - paragraph: string | string[]; - isStatusListItem?: boolean; -} - -export function ProfileListItem({ - header, - paragraph, - isStatusListItem, -}: Readonly) { - const { colorPalette } = useColorMode(); - const { t } = useTranslation(); - - return ( - - - - {header} - - {Array.isArray(paragraph) ? ( - - ) : ( - - - {paragraph} - - {isStatusListItem === true && ( - - - - )} - {isStatusListItem === false && ( - - - - )} - - )} - {isStatusListItem === true && ( - - )} - {isStatusListItem === false && ( - - )} - - - ); -} diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/responsive-overlay.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/responsive-overlay.tsx new file mode 100644 index 0000000000..bc305d73f0 --- /dev/null +++ b/packages/apps/human-app/frontend/src/shared/components/ui/responsive-overlay.tsx @@ -0,0 +1,54 @@ +import { type PropsWithChildren } from 'react'; + +import { type SxProps, type Theme } from '@mui/material'; + +import { BaseDrawer } from './base-drawer'; +import { BaseModal } from './modal/base-modal'; +import { useIsMobile } from '@/shared/hooks/use-is-mobile'; + +type Props = { + open: boolean; + onClose: () => void; + isLoading?: boolean; + desktopSx?: SxProps; + mobileSx?: SxProps; + closeButtonSx?: SxProps; +}; + +export function ResponsiveOverlay({ + open, + onClose, + isLoading = false, + desktopSx, + mobileSx, + closeButtonSx, + children, +}: PropsWithChildren) { + const isMobile = useIsMobile(); + + if (!isMobile) { + return ( + + {children} + + ); + } + + return ( + + {children} + + ); +} diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/success-label.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/success-label.tsx deleted file mode 100644 index a7646b7de5..0000000000 --- a/packages/apps/human-app/frontend/src/shared/components/ui/success-label.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import Grid from '@mui/material/Grid'; -import CheckCircleIcon from '@mui/icons-material/CheckCircle'; -import { useColorMode } from '@/shared/contexts/color-mode'; - -export function SuccessLabel({ children }: { children: string }) { - const { colorPalette } = useColorMode(); - - return ( - - {children} - - - ); -} diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/table-button.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/table-button.tsx index 3b2d2209ce..ed203a4301 100644 --- a/packages/apps/human-app/frontend/src/shared/components/ui/table-button.tsx +++ b/packages/apps/human-app/frontend/src/shared/components/ui/table-button.tsx @@ -8,7 +8,7 @@ export function TableButton(props: CustomButtonProps) { size="small" type="button" variant="contained" - color="secondary" + color="accent" sx={{ paddingTop: '0.4rem', paddingBottom: '0.4rem', diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/table/table-header-cell.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/table/table-header-cell.tsx deleted file mode 100644 index a0dfa345b0..0000000000 --- a/packages/apps/human-app/frontend/src/shared/components/ui/table/table-header-cell.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import React, { useState } from 'react'; -import Popover from '@mui/material/Popover'; -import type { TableCellBaseProps } from '@mui/material/TableCell'; -import { type IconType, TextHeaderWithIcon } from '../text-header-with-icon'; - -type CommonProps = TableCellBaseProps & { - popoverContent: React.ReactElement; -}; - -type PropsWithIcon = CommonProps & { - headerText: string; - iconType: IconType; -}; -type PropsWithoutIcon = CommonProps & { - headerText?: never; - iconType?: never; -}; - -type HeaderCellProps = PropsWithoutIcon | PropsWithIcon; - -export function TableHeaderCell({ - popoverContent, - headerText, - iconType, -}: HeaderCellProps) { - const [anchorEl, setAnchorEl] = useState(null); - - const handleClick = ( - event: - | React.MouseEvent - | React.KeyboardEvent - ) => { - setAnchorEl(event.currentTarget); - }; - - const handleClose = () => { - setAnchorEl(null); - }; - - const open = Boolean(anchorEl); - const id = open ? 'simple-popover' : undefined; - - const getHeader = () => { - if (!iconType) { - return
    {headerText}
    ; - } - - return ( -
    - -
    - ); - }; - - return ( - <> - {getHeader()} - - {popoverContent} - - - ); -} - -TableHeaderCell.displayName = 'TableHeaderCell'; diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/table/table-header-menu/filtering.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/table/table-header-menu/filtering.tsx deleted file mode 100644 index ed71180808..0000000000 --- a/packages/apps/human-app/frontend/src/shared/components/ui/table/table-header-menu/filtering.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import Checkbox from '@mui/material/Checkbox'; -import Typography from '@mui/material/Typography'; -import List from '@mui/material/List'; -import Divider from '@mui/material/Divider'; -import ListItem from '@mui/material/ListItem'; -import { t } from 'i18next'; -import { useColorMode } from '@/shared/contexts/color-mode'; - -interface FilteringOption { - name: string; - option: T; -} - -interface FilteringProps { - filteringOptions: FilteringOption[]; - isChecked: (option: T) => boolean; - setFiltering: (option: T) => void; - clear: () => void; - showTitle?: boolean; - showClearButton?: boolean; -} - -export function Filtering({ - filteringOptions, - isChecked, - setFiltering, - clear, - showTitle = false, - showClearButton = false, -}: Readonly>) { - const { colorPalette } = useColorMode(); - - return ( - - {showTitle ? ( - - {t('components.table.filter')} - - ) : null} - {filteringOptions.map(({ option, name }) => { - return ( - - { - if (isChecked(option)) { - clear(); - return; - } - setFiltering(option); - }} - sx={{ pl: 0, ':hover': { background: 'none' } }} - /> - - - {name} - - - - ); - })} - {showClearButton ? ( - <> - - - { - clear(); - }} - > - {t('components.table.clearBtn')} - - - - ) : null} - - ); -} diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/table/table-header-menu/sorting.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/table/table-header-menu/sorting.tsx deleted file mode 100644 index 835197d3fd..0000000000 --- a/packages/apps/human-app/frontend/src/shared/components/ui/table/table-header-menu/sorting.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { Divider, Typography } from '@mui/material'; -import List from '@mui/material/List'; -import ListItemText from '@mui/material/ListItemText'; -import { t } from 'i18next'; -import { useColorMode } from '@/shared/contexts/color-mode'; - -interface SortingMenuProps { - sortingOptions: { label: string; sortCallback: () => void }[]; - clear: () => void; -} - -export function Sorting({ sortingOptions, clear }: SortingMenuProps) { - const { colorPalette } = useColorMode(); - - return ( - - - {t('components.table.sort')} - - {sortingOptions.map(({ label, sortCallback }) => { - return ( - { - sortCallback(); - }} - sx={{ padding: '0.2rem 0.5rem', cursor: 'pointer' }} - > - - {label} - - - ); - })} - - - { - clear(); - }} - > - {t('components.table.clearBtn')} - - - - ); -} diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/table/table-query-context.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/table/table-query-context.tsx deleted file mode 100644 index 50bc898ca6..0000000000 --- a/packages/apps/human-app/frontend/src/shared/components/ui/table/table-query-context.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import React, { createContext, useState } from 'react'; -import type { - MRT_SortingState, - MRT_PaginationState, -} from 'material-react-table'; - -const DEFAULT_PAGINATION = { - pageIndex: 1, - pageSize: 5, -}; - -export interface TableQueryContext { - actions: { - setSorting: React.Dispatch>; - setPagination: React.Dispatch>; - setFiltering: React.Dispatch>; - }; - fields: { - sorting: MRT_SortingState; - pagination: MRT_PaginationState; - filtering: string[]; - }; -} - -export const TableQueryContext = createContext({ - actions: { - setSorting: () => undefined, - setPagination: () => undefined, - setFiltering: () => undefined, - }, - fields: { - sorting: [], - pagination: DEFAULT_PAGINATION, - filtering: [], - }, -}); - -export function TableQueryContextProvider({ - children, -}: { - children: React.ReactNode; -}) { - const [sorting, setSorting] = useState([]); - const [pagination, setPagination] = - useState(DEFAULT_PAGINATION); - const [filtering, setFiltering] = useState([]); - - return ( - - {children} - - ); -} diff --git a/packages/apps/human-app/frontend/src/shared/components/ui/text-header-with-icon.tsx b/packages/apps/human-app/frontend/src/shared/components/ui/text-header-with-icon.tsx deleted file mode 100644 index 57a2d2b727..0000000000 --- a/packages/apps/human-app/frontend/src/shared/components/ui/text-header-with-icon.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { Grid } from '@mui/material'; -import { FiltersIcon } from '@/shared/components/ui/icons'; - -export type IconType = 'filter'; - -export function TextHeaderWithIcon({ - text, - iconType, -}: { - text: string; - iconType: IconType; -}) { - const getIcon = () => { - switch (iconType) { - case 'filter': - return ; - } - }; - - return ( - - {text} - {getIcon()} - - ); -} diff --git a/packages/apps/human-app/frontend/src/shared/consts.ts b/packages/apps/human-app/frontend/src/shared/consts.ts index 26303f2072..a6942a7de3 100644 --- a/packages/apps/human-app/frontend/src/shared/consts.ts +++ b/packages/apps/human-app/frontend/src/shared/consts.ts @@ -1,3 +1,4 @@ -import { JobType } from '@/modules/smart-contracts/EthKVStore/config'; +import { JobType } from '@/shared/types/entity.type'; export const JOB_TYPES = Object.values(JobType); +export const MOBILE_BOTTOM_TRAY_HEIGHT = '90px'; diff --git a/packages/apps/human-app/frontend/src/shared/contexts/background/background.tsx b/packages/apps/human-app/frontend/src/shared/contexts/background/background.tsx deleted file mode 100644 index 321fa666f6..0000000000 --- a/packages/apps/human-app/frontend/src/shared/contexts/background/background.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import type { ReactNode } from 'react'; -import { - createContext, - useCallback, - useEffect, - useMemo, - useState, -} from 'react'; -import type { ColorPalette } from '@/shared/styles/color-palette'; - -export interface BackgroundContextProps { - backgroundColor: string; - setWhiteBackground: () => void; - setGrayBackground: () => void; -} - -export const BackgroundContext = createContext< - BackgroundContextProps | undefined ->(undefined); - -interface BackgroundProviderProps { - children: ReactNode; - colorPalette: ColorPalette; - isDarkMode: boolean; -} - -export function BackgroundProvider({ - children, - colorPalette, - isDarkMode, -}: Readonly) { - const [backgroundColor, setBackgroundColor] = useState( - colorPalette.white - ); - - const isGrayBackground = (() => { - if (isDarkMode) { - return backgroundColor === colorPalette.backgroundColor; - } - - return backgroundColor === colorPalette.paper.main; - })(); - - const setWhiteBackground = useCallback(() => { - setBackgroundColor(colorPalette.white); - }, [colorPalette.white]); - - const setGrayBackground = useCallback(() => { - if (isDarkMode) { - setBackgroundColor(colorPalette.backgroundColor); - } else { - setBackgroundColor(colorPalette.paper.main); - } - }, [isDarkMode, colorPalette.backgroundColor, colorPalette.paper.main]); - - const setGrayBackgroundInternal = useCallback( - (_isDarkMode: boolean) => { - if (isDarkMode) { - setBackgroundColor(colorPalette.backgroundColor); - } else { - setBackgroundColor(colorPalette.paper.main); - } - }, - [colorPalette.backgroundColor, colorPalette.paper.main, isDarkMode] - ); - - useEffect(() => { - if (isGrayBackground) { - setGrayBackgroundInternal(isDarkMode); - } - }, [ - isGrayBackground, - setWhiteBackground, - isDarkMode, - setGrayBackgroundInternal, - ]); - - const contextValue = useMemo( - () => ({ backgroundColor, setWhiteBackground, setGrayBackground }), - [backgroundColor, setWhiteBackground, setGrayBackground] - ); - - return ( - - {children} - - ); -} diff --git a/packages/apps/human-app/frontend/src/shared/contexts/background/index.ts b/packages/apps/human-app/frontend/src/shared/contexts/background/index.ts deleted file mode 100644 index 3c17b2c9ef..0000000000 --- a/packages/apps/human-app/frontend/src/shared/contexts/background/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './background'; -export * from './use-background-context'; diff --git a/packages/apps/human-app/frontend/src/shared/contexts/background/use-background-context.tsx b/packages/apps/human-app/frontend/src/shared/contexts/background/use-background-context.tsx deleted file mode 100644 index 1fb0d4db2e..0000000000 --- a/packages/apps/human-app/frontend/src/shared/contexts/background/use-background-context.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { useContext } from 'react'; -import { BackgroundContext, type BackgroundContextProps } from './background'; - -export const useBackgroundContext = (): BackgroundContextProps => { - const context = useContext(BackgroundContext); - if (!context) { - throw new Error( - 'useBackgroundContext must be used within a BackgroundProvider' - ); - } - return context; -}; diff --git a/packages/apps/human-app/frontend/src/shared/contexts/browser-auth-provider.ts b/packages/apps/human-app/frontend/src/shared/contexts/browser-auth-provider.ts index b1a9a76a8a..b47a32325a 100644 --- a/packages/apps/human-app/frontend/src/shared/contexts/browser-auth-provider.ts +++ b/packages/apps/human-app/frontend/src/shared/contexts/browser-auth-provider.ts @@ -1,29 +1,21 @@ -import type { - AuthType, - BrowserAuthProvider, -} from '@/shared/types/browser-auth-provider'; +import type { BrowserAuthProvider } from '@/shared/types/browser-auth-provider'; import { type AuthTokensSuccessResponse } from '../schemas'; const accessTokenKey = 'ro_access_token'; const refreshTokenKey = 'ro_refresh_token'; -const authTypeKey = 'ro_auth_type'; const userDataKey = 'ro_extendable_user_data'; const browserAuthProvider: BrowserAuthProvider = { isAuthenticated: false, - authType: 'web2', signOutSubscription: undefined, signIn( { access_token, refresh_token }: AuthTokensSuccessResponse, - authType, signOutSubscription ) { browserAuthProvider.isAuthenticated = true; - browserAuthProvider.authType = authType; localStorage.setItem(accessTokenKey, access_token); localStorage.setItem(refreshTokenKey, refresh_token); - localStorage.setItem(authTypeKey, authType); if (signOutSubscription) { this.signOutSubscription = signOutSubscription; @@ -34,7 +26,6 @@ const browserAuthProvider: BrowserAuthProvider = { browserAuthProvider.isAuthenticated = false; localStorage.removeItem(accessTokenKey); localStorage.removeItem(refreshTokenKey); - localStorage.removeItem(authTypeKey); localStorage.removeItem(userDataKey); if (args?.callback) { @@ -67,16 +58,6 @@ const browserAuthProvider: BrowserAuthProvider = { return refreshToken; }, - getAuthType(): AuthType | null { - const authType = localStorage.getItem(authTypeKey); - - if (!authType) { - return null; - } - - return authType as AuthType; - }, - setUserData(userData) { localStorage.setItem(userDataKey, JSON.stringify(userData)); }, diff --git a/packages/apps/human-app/frontend/src/shared/contexts/color-mode/color-mode-settings.ts b/packages/apps/human-app/frontend/src/shared/contexts/color-mode/color-mode-settings.ts index 2e8b2c9134..aab57fbd6a 100644 --- a/packages/apps/human-app/frontend/src/shared/contexts/color-mode/color-mode-settings.ts +++ b/packages/apps/human-app/frontend/src/shared/contexts/color-mode/color-mode-settings.ts @@ -11,10 +11,7 @@ export const saveColorMode = (mode: ColorMode) => { export const isDarkColorMode = () => { const mode = localStorage.getItem(MODE_LOCAL_STORAGE_KEY); - if (mode === ColorMode.DARK) { - return true; - } - return false; + return mode === ColorMode.DARK; }; export const hasColorMode = () => { diff --git a/packages/apps/human-app/frontend/src/shared/contexts/color-mode/color-mode.tsx b/packages/apps/human-app/frontend/src/shared/contexts/color-mode/color-mode.tsx index faeb22e8f1..3e8bba7636 100644 --- a/packages/apps/human-app/frontend/src/shared/contexts/color-mode/color-mode.tsx +++ b/packages/apps/human-app/frontend/src/shared/contexts/color-mode/color-mode.tsx @@ -7,7 +7,6 @@ import { useCallback, } from 'react'; import { ThemeProvider, createTheme } from '@mui/material'; -import { BackgroundProvider } from '@/shared/contexts/background'; import { theme } from '@/shared/styles/theme'; import { colorPalette as defaultColorPalette } from '@/shared/styles/color-palette'; import { darkTheme } from '@/shared/styles/dark-theme'; @@ -34,9 +33,7 @@ interface ColorModeProviderProps { children: ReactNode; } -export function ColorModeProvider({ - children, -}: Readonly) { +export function ColorModeProvider({ children }: ColorModeProviderProps) { const [isDarkMode, setIsDarkMode] = useState(isDarkColorMode()); const handleColorSchemePrefsChange = (prefersDarkScheme: boolean) => { @@ -85,9 +82,7 @@ export function ColorModeProvider({ return ( - - {children} - + {children} ); diff --git a/packages/apps/human-app/frontend/src/shared/contexts/generic-auth-context.tsx b/packages/apps/human-app/frontend/src/shared/contexts/generic-auth-context.tsx index d9cec048f4..eae4bd27f5 100644 --- a/packages/apps/human-app/frontend/src/shared/contexts/generic-auth-context.tsx +++ b/packages/apps/human-app/frontend/src/shared/contexts/generic-auth-context.tsx @@ -5,8 +5,6 @@ import { useQueryClient } from '@tanstack/react-query'; import { browserAuthProvider } from '@/shared/contexts/browser-auth-provider'; import { type AuthTokensSuccessResponse } from '@/shared/schemas'; import { type UserData } from '@/modules/auth/context/auth-context'; -import { type Web3UserData } from '@/modules/auth-web3/context/web3-auth-context'; -import { type AuthType } from '../types/browser-auth-provider'; import { useExpirationModal } from '../hooks'; type AuthStatus = 'loading' | 'error' | 'success' | 'idle'; @@ -31,11 +29,10 @@ export interface UnauthenticatedUserContextType extends AuthContextType { user: null; } -export function createAuthProvider(config: { - authType: AuthType; +export function createAuthProvider(config: { schema: ZodType; }) { - const { authType, schema } = config; + const { schema } = config; const AuthContext = createContext< AuthenticatedUserContextType | UnauthenticatedUserContextType | null >(null); @@ -59,9 +56,8 @@ export function createAuthProvider(config: { const handleSignIn = () => { try { const accessToken = browserAuthProvider.getAccessToken(); - const currentAuthType = browserAuthProvider.getAuthType(); - if (!accessToken || currentAuthType !== authType) { + if (!accessToken) { setAuthState({ user: null, status: 'idle' }); return; } @@ -81,7 +77,7 @@ export function createAuthProvider(config: { }; const signIn = (signInSuccess: AuthTokensSuccessResponse) => { - browserAuthProvider.signIn(signInSuccess, authType); + browserAuthProvider.signIn(signInSuccess); handleSignIn(); }; diff --git a/packages/apps/human-app/frontend/src/shared/contexts/homepage-state/homepage-state.tsx b/packages/apps/human-app/frontend/src/shared/contexts/homepage-state/homepage-state.tsx deleted file mode 100644 index 7b5f0cabba..0000000000 --- a/packages/apps/human-app/frontend/src/shared/contexts/homepage-state/homepage-state.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React, { createContext, useMemo, useState } from 'react'; -import { useLocation } from 'react-router-dom'; -import { routerPaths } from '@/router/router-paths'; - -type HomePageStateType = 'welcome' | 'chooseSignUpAccountType'; - -interface HomePageStageContextProps { - pageView: HomePageStateType; - setPageView: (step: HomePageStateType) => void; - isMainPage: boolean; -} - -export const HomePageStateContext = - createContext(null); - -export function HomePageStateProvider({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - const [pageView, setPageView] = useState('welcome'); - - const location = useLocation(); - const isMainPage = - location.pathname === routerPaths.homePage && pageView === 'welcome'; - - const contextValue = useMemo( - () => ({ pageView, setPageView, isMainPage }), - [pageView, setPageView, isMainPage] - ); - - return ( - - {children} - - ); -} diff --git a/packages/apps/human-app/frontend/src/shared/contexts/homepage-state/index.ts b/packages/apps/human-app/frontend/src/shared/contexts/homepage-state/index.ts deleted file mode 100644 index 781cb6bd33..0000000000 --- a/packages/apps/human-app/frontend/src/shared/contexts/homepage-state/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './homepage-state'; -export * from './use-homepage-state'; diff --git a/packages/apps/human-app/frontend/src/shared/contexts/homepage-state/use-homepage-state.tsx b/packages/apps/human-app/frontend/src/shared/contexts/homepage-state/use-homepage-state.tsx deleted file mode 100644 index c228db521f..0000000000 --- a/packages/apps/human-app/frontend/src/shared/contexts/homepage-state/use-homepage-state.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { useContext } from 'react'; -import { HomePageStateContext } from './homepage-state'; - -export const useHomePageState = () => { - const context = useContext(HomePageStateContext); - if (!context) { - throw new Error( - 'useHomePageState must be used within a HomePageStageProvider' - ); - } - return context; -}; diff --git a/packages/apps/human-app/frontend/src/shared/contexts/jwt-expiration-check.tsx b/packages/apps/human-app/frontend/src/shared/contexts/jwt-expiration-check.tsx index 3fc5aef19f..7526c43f6c 100644 --- a/packages/apps/human-app/frontend/src/shared/contexts/jwt-expiration-check.tsx +++ b/packages/apps/human-app/frontend/src/shared/contexts/jwt-expiration-check.tsx @@ -2,7 +2,6 @@ import type React from 'react'; import { useEffect, useRef } from 'react'; import { useLocation } from 'react-router-dom'; import { useAccessTokenRefresh } from '@/api/hooks/use-access-token-refresh'; -import { useWeb3Auth } from '@/modules/auth-web3/hooks/use-web3-auth'; import { useAuth } from '@/modules/auth/hooks/use-auth'; export function JWTExpirationCheck({ @@ -11,45 +10,25 @@ export function JWTExpirationCheck({ children: React.ReactElement; }) { const checksOnProfile = useRef(0); - const web3Auth = useWeb3Auth(); - const web2Auth = useAuth(); + const auth = useAuth(); const location = useLocation(); const { refreshAccessToken } = useAccessTokenRefresh(); useEffect(() => { - if ( - location.pathname.includes('profile') && - (web2Auth.user ?? web3Auth.user) - ) { + if (location.pathname.includes('profile') && auth.user) { checksOnProfile.current = checksOnProfile.current + 1; } - const web3TokenExpired = Boolean( - web3Auth.user?.exp && web3Auth.user.exp < Date.now() / 1000 - ); - if (web3TokenExpired) { - refreshAccessToken({ - authType: 'web3', - throwExpirationModalOnSignOut: checksOnProfile.current < 1, - }); - } - const web2TokenExpired = Boolean( - web2Auth.user?.exp && web2Auth.user.exp < Date.now() / 1000 + const isTokenExpired = Boolean( + auth.user?.exp && auth.user.exp < Date.now() / 1000 ); - if (web2TokenExpired) { + + if (isTokenExpired) { refreshAccessToken({ - authType: 'web2', throwExpirationModalOnSignOut: checksOnProfile.current < 1, }); } - }, [ - location, - web3Auth.user?.exp, - web2Auth.user?.exp, - refreshAccessToken, - web2Auth.user, - web3Auth.user, - ]); + }, [location, auth.user?.exp, refreshAccessToken, auth.user]); return children; } diff --git a/packages/apps/human-app/frontend/src/shared/contexts/wallet-connect/index.ts b/packages/apps/human-app/frontend/src/shared/contexts/wallet-connect/index.ts index c0af686fdd..cc9dd3f1ea 100644 --- a/packages/apps/human-app/frontend/src/shared/contexts/wallet-connect/index.ts +++ b/packages/apps/human-app/frontend/src/shared/contexts/wallet-connect/index.ts @@ -1,4 +1,2 @@ export * from './wallet-connect'; export * from './use-wallet-connect'; -export * from './require-wallet-connect'; -export * from './use-connected-wallet'; diff --git a/packages/apps/human-app/frontend/src/shared/contexts/wallet-connect/require-wallet-connect.tsx b/packages/apps/human-app/frontend/src/shared/contexts/wallet-connect/require-wallet-connect.tsx deleted file mode 100644 index 8499529e71..0000000000 --- a/packages/apps/human-app/frontend/src/shared/contexts/wallet-connect/require-wallet-connect.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import type { ReactNode } from 'react'; -import { useLocation, Navigate } from 'react-router-dom'; -import { createContext } from 'react'; -import { routerPaths } from '@/router/router-paths'; -import { PageCardLoader } from '@/shared/components/ui/page-card'; -import { type WalletConnectContextConnectedAccount } from './types'; -import { useWalletConnect } from './use-wallet-connect'; - -export const ConnectedWalletContext = - createContext(null); - -export function RequireWalletConnect({ - children, -}: Readonly<{ children: ReactNode }>) { - const walletConnect = useWalletConnect(); - const location = useLocation(); - - if (walletConnect.initializing) { - return ; - } - - if (!walletConnect.isConnected) { - return ( - - ); - } - - return ( - - {children} - - ); -} diff --git a/packages/apps/human-app/frontend/src/shared/contexts/wallet-connect/use-connected-wallet.tsx b/packages/apps/human-app/frontend/src/shared/contexts/wallet-connect/use-connected-wallet.tsx deleted file mode 100644 index a550595d8e..0000000000 --- a/packages/apps/human-app/frontend/src/shared/contexts/wallet-connect/use-connected-wallet.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { useContext } from 'react'; -import { ConnectedWalletContext } from './require-wallet-connect'; - -export const useConnectedWallet = () => { - const context = useContext(ConnectedWalletContext); - - if (!context) { - throw new Error( - 'Cannot use context of useConnectedWallet. Component is not included in protectedWeb3Routes' - ); - } - - return context; -}; diff --git a/packages/apps/human-app/frontend/src/shared/env.ts b/packages/apps/human-app/frontend/src/shared/env.ts index 3be4fb921a..aa054c35f7 100644 --- a/packages/apps/human-app/frontend/src/shared/env.ts +++ b/packages/apps/human-app/frontend/src/shared/env.ts @@ -31,13 +31,6 @@ const envSchema = z.object({ }), VITE_NETWORK: z.enum(['mainnet', 'testnet']), VITE_GOVERNANCE_URL: z.string(), - VITE_H_CAPTCHA_ORACLE_ANNOTATION_TOOL: z.string(), - VITE_H_CAPTCHA_ORACLE_ROLE: z.string(), - VITE_H_CAPTCHA_ORACLE_ADDRESS: z.string(), - VITE_H_CAPTCHA_ORACLE_TASK_TYPES: z.string().transform((value) => { - const jobTypesArray = value.split(','); - return jobTypesArray; - }), VITE_FEATURE_FLAG_JOBS_DISCOVERY: z .string() .prefault('false') diff --git a/packages/apps/human-app/frontend/src/shared/hooks/index.ts b/packages/apps/human-app/frontend/src/shared/hooks/index.ts index 6f64178930..183fe9c490 100644 --- a/packages/apps/human-app/frontend/src/shared/hooks/index.ts +++ b/packages/apps/human-app/frontend/src/shared/hooks/index.ts @@ -1,7 +1,6 @@ export * from './use-combine-pages'; export * from './use-count-down'; export * from './use-handle-main-nav-icon-click'; -export * from './use-is-hcaptcha-labeling-page'; export * from './use-notification'; export * from './use-is-mobile'; export * from './use-reset-mutation-errors'; @@ -9,3 +8,4 @@ export * from './use-web3-provider'; export * from './use-expiration-modal'; export * from './use-prepare-signature'; export * from './use-get-ui-config'; +export * from './use-is-user-verified'; diff --git a/packages/apps/human-app/frontend/src/shared/hooks/use-combine-pages.ts b/packages/apps/human-app/frontend/src/shared/hooks/use-combine-pages.ts index 74a5ac32be..f36063a20e 100644 --- a/packages/apps/human-app/frontend/src/shared/hooks/use-combine-pages.ts +++ b/packages/apps/human-app/frontend/src/shared/hooks/use-combine-pages.ts @@ -1,21 +1,10 @@ -import { useEffect, useState } from 'react'; +import { useMemo } from 'react'; export function useCombinePages( - tableData: { pages: { results: T[] }[] } | undefined, - page: number + tableData: { pages: { results: T[] }[] } | undefined ) { - const [allPages, setAllPages] = useState([]); - - useEffect(() => { - if (!tableData) return; - const pagesFromRes = tableData.pages.flatMap((pages) => pages.results); - - if (page === 0) { - setAllPages(pagesFromRes); - } else { - setAllPages((state) => [...state, ...pagesFromRes]); - } - }, [tableData, page]); - - return allPages; + return useMemo( + () => tableData?.pages.flatMap((page) => page.results) ?? [], + [tableData?.pages] + ); } diff --git a/packages/apps/human-app/frontend/src/shared/hooks/use-handle-main-nav-icon-click.tsx b/packages/apps/human-app/frontend/src/shared/hooks/use-handle-main-nav-icon-click.tsx index d3577d378d..a124edf55f 100644 --- a/packages/apps/human-app/frontend/src/shared/hooks/use-handle-main-nav-icon-click.tsx +++ b/packages/apps/human-app/frontend/src/shared/hooks/use-handle-main-nav-icon-click.tsx @@ -1,27 +1,21 @@ import { useNavigate } from 'react-router-dom'; import { routerPaths } from '@/router/router-paths'; -import { useHomePageState } from '../contexts/homepage-state/use-homepage-state'; import { browserAuthProvider } from '../contexts/browser-auth-provider'; +import { useIsUserVerified } from './use-is-user-verified'; export const useHandleMainNavIconClick = () => { const navigate = useNavigate(); - const { setPageView } = useHomePageState(); + const isUserVerified = useIsUserVerified(); const handleIconClick = () => { - const type = browserAuthProvider.getAuthType(); - const isAuthenticated = browserAuthProvider.isAuthenticated; + const isAuthenticated = + browserAuthProvider.isAuthenticated && isUserVerified; - if (type === 'web3' && isAuthenticated) { - navigate(routerPaths.operator.profile); + if (isAuthenticated) { + navigate(routerPaths.profile); return; } - if (type === 'web2' && isAuthenticated) { - navigate(routerPaths.worker.profile); - return; - } - - setPageView('welcome'); navigate(routerPaths.homePage); }; diff --git a/packages/apps/human-app/frontend/src/shared/hooks/use-is-hcaptcha-labeling-page.ts b/packages/apps/human-app/frontend/src/shared/hooks/use-is-hcaptcha-labeling-page.ts deleted file mode 100644 index a5b0f95f61..0000000000 --- a/packages/apps/human-app/frontend/src/shared/hooks/use-is-hcaptcha-labeling-page.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { useLocation } from 'react-router-dom'; -import { routerPaths } from '@/router/router-paths'; - -export function useIsHCaptchaLabelingPage() { - const location = useLocation(); - return location.pathname === routerPaths.worker.HcaptchaLabeling; -} diff --git a/packages/apps/human-app/frontend/src/shared/hooks/use-is-user-verified.tsx b/packages/apps/human-app/frontend/src/shared/hooks/use-is-user-verified.tsx new file mode 100644 index 0000000000..a5727e4275 --- /dev/null +++ b/packages/apps/human-app/frontend/src/shared/hooks/use-is-user-verified.tsx @@ -0,0 +1,11 @@ +import { useAuth } from '@/modules/auth/hooks/use-auth'; +import { KycStatus } from '@/modules/worker/profile/types/profile-types'; + +export function useIsUserVerified() { + const { user } = useAuth(); + + const kycStatus = user?.kyc_status as KycStatus; + const hasWalletAddress = !!user?.wallet_address; + + return user && kycStatus === KycStatus.APPROVED && hasWalletAddress; +} diff --git a/packages/apps/human-app/frontend/src/shared/hooks/use-notification.tsx b/packages/apps/human-app/frontend/src/shared/hooks/use-notification.tsx index a3e465c621..af58faf423 100644 --- a/packages/apps/human-app/frontend/src/shared/hooks/use-notification.tsx +++ b/packages/apps/human-app/frontend/src/shared/hooks/use-notification.tsx @@ -1,11 +1,13 @@ import { useCallback } from 'react'; import { type SnackbarKey, useSnackbar } from 'notistack'; import CloseIcon from '@mui/icons-material/Close'; -import { useColorMode } from '@/shared/contexts/color-mode'; -import { colorPalette as lightColorPalette } from '@/shared/styles/color-palette'; + +import { ColorPalette } from '@/shared/styles/color-palette'; +import { useColorMode } from '../contexts/color-mode'; export enum TopNotificationType { SUCCESS = 'success', + ERROR = 'error', WARNING = 'warning', } @@ -16,11 +18,26 @@ export interface ShowNotifProps { } const AUTO_HIDE_NOTIFICATION_MS = 6000; -const FONT_COLOR = lightColorPalette.white; + +const mapTopNotificationTypeToColor = ( + type: TopNotificationType, + colorPalette: ColorPalette +) => { + switch (type) { + case TopNotificationType.SUCCESS: + return colorPalette.success.main; + case TopNotificationType.WARNING: + return colorPalette.secondary.main; + case TopNotificationType.ERROR: + return '#FF6262'; + default: + return colorPalette.secondary.main; + } +}; export const useNotification = () => { - const { colorPalette } = useColorMode(); const { enqueueSnackbar, closeSnackbar } = useSnackbar(); + const { colorPalette } = useColorMode(); const action = useCallback( (snackbarId: SnackbarKey) => ( @@ -55,11 +72,8 @@ export const useNotification = () => { flexWrap: 'nowrap', width: '100%', maxWidth: '100%', - backgroundColor: - type === TopNotificationType.SUCCESS - ? colorPalette.success.main - : colorPalette.secondary.main, - color: FONT_COLOR, + backgroundColor: mapTopNotificationTypeToColor(type, colorPalette), + color: colorPalette.white, fontSize: 14, fontWeight: 600, letterSpacing: 0.1, @@ -67,7 +81,7 @@ export const useNotification = () => { action, }); }, - [enqueueSnackbar, colorPalette, action] + [enqueueSnackbar, action, colorPalette] ); return { showNotification }; diff --git a/packages/apps/human-app/frontend/src/shared/i18n/en.json b/packages/apps/human-app/frontend/src/shared/i18n/en.json index 127b9c1d4e..d9f1bd89fe 100644 --- a/packages/apps/human-app/frontend/src/shared/i18n/en.json +++ b/packages/apps/human-app/frontend/src/shared/i18n/en.json @@ -1,20 +1,15 @@ { - "humanCurrencySymbol": "HMT", "inputMasks": { "humanCurrencySuffix": "HMT", "percentSuffix": "%", "plusPrefix": "+" }, - "dashboard": {}, "protectedPagesHeaders": { "profile": "Profile", "jobsDiscovery": "Tasks", "hcaptchaLabeling": "Labeling", "jobs": "Tasks", - "registrationInExchangeOracle": "Registration in Exchange Oracle" - }, - "web3ProtectedPagesHeaders": { - "profile": "Profile" + "registrationInExchangeOracle": "Registration in Oracle" }, "validation": { "required": "Required", @@ -45,22 +40,20 @@ "cannotSignMessage": "Cannot sign message." }, "components": { - "multiSelect": { - "allFields": "All fields", - "andMore": "(and {{number}} more)", - "clearAll": "Clear all" - }, "breadcrumb": { "back": "Back" }, "navbar": { "humanProtocol": "HUMAN Protocol", - "howItWorks": "How It Works" + "howItWorks": "How It Works", + "home": "Home" }, "DrawerNavigation": { "jobs": "Tasks", "captchaLabeling": "hCaptcha labeling", "jobsDiscovery": "Jobs discovery", + "availableJobs": "Available Jobs", + "myJobs": "My Jobs", "profile": "Profile", "help": "Help", "logout": "Log Out" @@ -71,16 +64,6 @@ "humanProtocol": "HUMAN Protocol", "copyrightNote": "© 2021 HPF. HUMAN Protocol® is a registered trademark" }, - "table": { - "clearBtn": "Clear", - "sort": "Sort", - "filter": "Filter" - }, - "modal": { - "header": { - "closeBtn": "Cancel" - } - }, "wallet": { "connectBtn": { "disconnect": "Disconnect Wallet", @@ -91,29 +74,14 @@ "reload": "Reload", "goHome": "Home Page" }, - "copyToClipboard": "Copied" + "copyToClipboard": "Copied", + "noRecords": "No records to display" }, "homepage": { "humanApp": "HUMAN App", "completeJobs": "Complete jobs, earn HMT.", - "logIn": "Log In", "signUp": "Sign Up", - "signIn": "Sign In", - "workerSignIn": "Worker Sign In", - "operatorSignIn": "Operator Sign In", - "welcome": "Welcome", - "howWillUse": "How will you use HUMAN App?", - "selectOption": "Please select an option below.", - "iWantToEarn": "I want to complete tasks, and earn HMT", - "completeTask": "Complete multiple task types, and get paid.", - "workAnywhere": "Work anywhere, any time.", - "signUpToComplete": "Worker Sign Up", - "joinAsOperator": "I want to join as an operator", - "runAsOracle": "Run an oracle, or other essential service, and earn fees.", - "becomePartner": "Become a HUMAN App operator.", - "signAsOperator": "Operator Sign Up", - "termsAndConditions": "Terms & conditions", - "cancel": "Cancel" + "signIn": "Sign In" }, "worker": { "signUpForm": { @@ -129,7 +97,10 @@ "title": "Sign Up", "submitBtn": "Sign Up", "passwordDetailedValidation": "Password must contain at least:", - "termsOfServiceAndPrivacyPolicy": "By clicking Sign Up, you agree to our <1>Terms of Service and that you have read our <2>Privacy Policy" + "termsOfServiceAndPrivacyPolicy": "By clicking Sign Up, you agree to our <1>Terms of Service and that you have read our <2>Privacy Policy", + "or": "Or", + "alreadyHaveAccount": "Already have an account?", + "signIn": "Sign In" }, "signInForm": { "fields": { @@ -141,22 +112,24 @@ }, "title": "Sign In", "submitBtn": "Sign In", - "forgotPassword": "Forgot Password?" + "forgotPassword": "Forgot Password?", + "or": "Or", + "dontHaveAccount": "Don't have an account?", + "signUp": "Sign Up" }, "verifyEmail": { "title": "Verify Email", - "btn": "Resend Verification Email", - "paragraph1": "We've sent an email to <1>{{email}}, please check your inbox and verify your email.", - "paragraph2": "The verification link is valid for 24 hours.", - "paragraph3": "<1>Can't find our email? If you can't find the email in your inbox please check the spam folder.", - "paragraph4": "<1>Having trouble? Please <2>Contact Support", + "checkYourInbox": "Check your inbox", + "backToSignUp": "Back to Sign Up", + "btn": "Resend Email", + "paragraph1": "We sent a verification link to <1>{{email}}", + "paragraph2": "Click the link in the email to verify your account. The link expires in 24 hours.", "successResent": "Verification email has been successfully resent.", "authError": "Log in before you resend email verification", "emailError": "No email provided." }, "emailVerification": { - "title": "Email Verified", - "description": "You are ready to go. Your email has been successfully verified!", + "title": "Verified", "btn": "Sign In", "errors": { "noToken": "No token provided." @@ -197,24 +170,33 @@ "btn": "Sign In" }, "profile": { - "profileHeader": "Profile", + "profileHeader": "Account", + "accountVerified": "Account verified", "email": "Email", "password": "Password", "wallet": "Wallet", + "walletAddress": "Wallet address", "resetPassword": "Reset Password", + "logout": "Logout", + "beforeWeGetStarted": "Before we get started", + "identityVerification": "Identity verification", + "veriffCopy": "We use Veriff to verify your identity. You'll need: keep your phone & Government ID handy.", + "poweredBy": "Powered by", "completeIdentityVerification": "Complete Identity Verification", - "identityVerificationInProgress": "Identity verification in progress", + "verificationOpenedInNewTab": "Verification opened in a new tab", + "completeYourVerification": "Complete your verification there, then return here to continue", + "waitingForVerification": "Waiting for verification...", + "checkVerificationStatus": "Check Verification Status", + "verificationDeclined": "We were unable to verify your identity with the information provided. Please <1>contact support", "confirmEmail": "Confirm email", - "identityVerificationStatus": "Identity verification", "walletAddressMessage": "This address is the wallet address where you will receive payments for completing tasks.", + "connectYourWallet": "Connect your wallet", "connectWallet": "Connect Wallet", "walletConnected": "Connected", "addKYCInfoOnChain": "Add KYC Info On-chain", "wrongWalletAddress": "Selected wallet address doesn't match the address assigned to the account.", - "kycInfoOnChainAdded": "KYC Info On-Chain Added", "registerAddress": "Register Address", "emailNotifications": "Email Notifications", - "notificationsConsent": "I would like to be notified about News and Offers", "topNotifications": { "completeSteps": "Please set up your profile by completing the steps below." }, @@ -228,6 +210,16 @@ "abandoned": "Abandoned" } }, + "oraclesList": { + "jobOracles": "Job Oracles", + "address": "Address", + "reward": "Reward", + "tasks": "Tasks", + "task": "Task", + "exploreTasks": "Explore Tasks", + "source": "source", + "sources": "sources" + }, "oraclesTable": { "annotationTool": "Annotation tool", "oracleAddress": "Oracle address", @@ -238,6 +230,16 @@ "gettingOracles": "There was an error while fetching oracles, please try again later." } }, + "hcaptchaWidget": { + "title": "hCaptcha task available!", + "titleDisabled": "No hCaptcha task available", + "description": "Complete image labeling challenges and earn rewards by helping train privacy-preserving hCaptcha models.", + "shortDescription": "Complete image labeling challenges and earn rewards.", + "descriptionDisabled": "You have reached the daily limit for the hCaptcha tasks, please come back later.", + "startTask": "Start Task", + "nextAvailable": "Next Available in", + "nextIn": "Next in" + }, "registrationInExchangeOracle": { "requiredMessage": "This oracle requires a registration process. Click on the button below to see the registration tutorial:", "instructionsButton": "See registration tutorial", @@ -245,57 +247,53 @@ "completeButton": "Complete" }, "jobs": { - "successFullyAssignedJob": "Successfully assigned a task!", + "hCaptcha": "hCaptcha", + "successfullyAssignedJob": "Successfully claimed the task!", "errorFetchingData": "There was an error while fetching data, please try again", - "availableJobs": "Available Tasks", - "myJobs": "My Tasks", + "availableJobs": "Available Jobs", + "myJobs": "My Jobs", "jobsDiscovery": "Jobs Discovery", "jobDescription": "Job description", + "action": "Action", + "taskDescription": "Task Desc.", + "taskDescriptionTitle": "Task Description", + "oracles": "Oracles", + "address": "Address", "escrowAddress": "Escrow address", "network": "Network", + "reward": "Reward", "rewardAmount": "Reward amount", "jobType": "Task type", "expiresAt": "Expires at", + "expiryTime": "Expiry Time", + "expired": "Expired", "refresh": "Refresh", "status": "Status", "selectJob": "Select Task", + "claimTask": "Claim Task", "searchEscrowAddress": "Search escrow address", "resign": "Resign", "solve": "Solve", "filter": "Filter", + "jobsFilter": "Jobs Filter", + "applyFilters": "Apply Filters", "escrowAddressColumnId": "escrowAddress", + "statusFilter": { + "all": "All", + "inProgress": "In Progress", + "completed": "Completed" + }, "Ethereum": "Ethereum", "Polygon": "Polygon", - "sortDirection": { - "fromHighest": "From highest", - "fromLowest": "From lowest", - "furthestToNow": "Furthest to now", - "closestToNow": "Closest to now" - }, - "mobileFilterDrawer": { - "sortBy": "Sort by", - "filters": "Filters", - "jobsStatus": { - "active": "Active", - "validation": "Validation", - "completed": "Completed", - "expired": "Expired", - "canceled": "Canceled", - "rejected": "Rejected" - }, - "network": { - "matic": "Matic", - "polygon": "Polygon" - }, - "jobType": { - "fortune": "Fortune" - } - }, - "next": "Next" + "next": "Next", + "jobsFor": "Jobs for" }, "hcaptchaLabeling": { "description": "HMT payouts are automatically computed by an oracle based on correctness and volume of tasks completed. Payout timing depends on total job size, and can take as little as an hour or as long as a week or so, depending on overall job status.", - "noJobs": "No jobs available at the moment. Please come back in:" + "noJobs": "You have reached the daily limit for the hCaptcha tasks, please come back later.", + "waitFor": "Wait for", + "browseAvailableJobs": "Browse Available Jobs", + "or": "Or" }, "enableHCaptchaLabeling": { "description": "CAPTCHA tasks involve the correct labeling of images in a group of images. Read the instructional prompt, and select the images that best correspond to that prompt.", @@ -345,111 +343,6 @@ } } }, - "operator": { - "profile": { - "profileHeader": "Profile", - "about": { - "header": "About", - "role": "Role", - "status": { - "statusHeader": "Status", - "statusActivated": "Active", - "statusDeactivated": "Deactivated", - "statusActivateButton": "Activate", - "statusDeactivateButton": "Deactivate" - }, - "fee": "Fee", - "url": "URL", - "webhookUrl": "Webhook URL", - "jobTypes": "Job Types", - "publicKey": "Public Key" - }, - "activate": { - "activateBtn": "Activate", - "cannotActivate": "Cannot activate operator" - }, - "disable": { - "disableBtn": "Deactivate", - "cannotDisable": "Cannot deactivate operator" - }, - "statistics": { - "header": "Statistics", - "escrowsProcessed": "Escrows processed", - "escrowsActive": "Escrows active", - "escrowsCancelled": "Escrows cancelled", - "workersAmount": "Workers amount", - "assignmentsCompleted": "Assignments completed", - "assignmentsRejected": "Assignments rejected", - "assignmentsExpired": "Assignments expired" - } - }, - "connectWallet": { - "title": "Setup Operator", - "description": "Please use the button below to connect your wallet and sign up as an operator.", - "connect": "Connect Wallet", - "disconnect": "Disconnect", - "successAlert": "Wallet successfully connected", - "setupOperator": "Setup Operator" - }, - "addStake": { - "title": "Setup Operator", - "formHeader": "Stake", - "label": "Staked amount", - "description": "Please add the amount to stake below", - "actionBtn": "Add Stake", - "nextBtn": "Next", - "skipBtn": "Skip" - }, - "stakeForm": { - "formBtn": "Add Stake", - "skipBtn": "Skip", - "nextBtn": "Next", - "label": "Stake amount", - "description": "Please add the amount to stake below", - "successAlert": "You have successfully staked {{amount}} HMT", - "invalidDecimals": "Incorrect decimal expansion. HMT token has {{decimals}} decimals" - }, - "addKeysPage": { - "title": "Setup Operator", - "btn": " Add New Keys to KVStore", - "skipBtn": "Skip", - "pendingKeys": { - "title": "Pending Keys", - "fee": "Fee", - "publicKey": "Public Key", - "webhookUrl": "Webhook URL", - "role": "Role", - "jobType": "Job type" - }, - "existingKeys": { - "title": "Existing keys", - "fee": "Fee", - "publicKey": "Public Key", - "url": "Url", - "webhookUrl": "Webhook URL", - "role": "Role", - "jobType": "Job type", - "noValue": "no value", - "editBtn": "Edit" - }, - "editKeysForm": { - "btn": "Save", - "error": "No changes" - } - }, - "editExistingKeysSuccess": { - "title": "Setup Operator", - "paragraph1": "Congratulations 🎉!", - "paragraph2": "Operator setup is completed, please press the button below to finish sign up.", - "btn": "Finish" - } - }, - "walletConnectModal": { - "header": "Connect Wallet", - "paragraph": "HUMAN App is a multichain platform, please provide a wallet address which will be compatible with different chains.", - "connectBtn": "Connect Wallet", - "cancelBtn": "Cancel" - }, "expirationModal": { "header": "Session Expired", "description": "Please log in again to continue using the app.", diff --git a/packages/apps/human-app/frontend/src/shared/providers/notifications-provider.tsx b/packages/apps/human-app/frontend/src/shared/providers/notifications-provider.tsx index 17aabba253..cefcc9f884 100644 --- a/packages/apps/human-app/frontend/src/shared/providers/notifications-provider.tsx +++ b/packages/apps/human-app/frontend/src/shared/providers/notifications-provider.tsx @@ -2,6 +2,7 @@ import { type ReactNode } from 'react'; import { SnackbarProvider } from 'notistack'; import CheckCircleIcon from '@mui/icons-material/CheckCircle'; import ErrorIcon from '@mui/icons-material/Error'; +import WarningIcon from '@mui/icons-material/Warning'; import { TopNotificationType } from '@/shared/hooks/use-notification'; import { colorPalette as lightColorPalette } from '@/shared/styles/color-palette'; import { handleUnreachableCase } from '@/shared/helpers/handle-unreachable-case'; @@ -21,8 +22,9 @@ const getNotificationIconByType = ( switch (type) { case TopNotificationType.SUCCESS: return ; - case TopNotificationType.WARNING: + return ; + case TopNotificationType.ERROR: return ; default: { @@ -34,7 +36,7 @@ const getNotificationIconByType = ( export function NotificationProvider({ children, maxSnacks = MAX_NOTIFICATIONS_VISIBLE, -}: Readonly) { +}: NotificationProviderProps) { const isMobile = useIsMobile(); return ( diff --git a/packages/apps/human-app/frontend/src/shared/schemas/index.ts b/packages/apps/human-app/frontend/src/shared/schemas/index.ts index 73ec748501..b01302d0ab 100644 --- a/packages/apps/human-app/frontend/src/shared/schemas/index.ts +++ b/packages/apps/human-app/frontend/src/shared/schemas/index.ts @@ -1,3 +1 @@ -export * from './validate-address-schema'; -export * from './url-domain-schema'; export * from './auth-tokens-schema'; diff --git a/packages/apps/human-app/frontend/src/shared/schemas/url-domain-schema.ts b/packages/apps/human-app/frontend/src/shared/schemas/url-domain-schema.ts deleted file mode 100644 index d5946b70b7..0000000000 --- a/packages/apps/human-app/frontend/src/shared/schemas/url-domain-schema.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { t } from 'i18next'; -import { z } from 'zod'; - -export const urlDomainSchema = z.string().refine( - (url) => { - try { - const newUrl = new URL(url); - return newUrl.protocol === 'http:' || newUrl.protocol === 'https:'; - } catch { - return false; - } - }, - { message: t('validation.urlValidationError') } -); diff --git a/packages/apps/human-app/frontend/src/shared/schemas/validate-address-schema.ts b/packages/apps/human-app/frontend/src/shared/schemas/validate-address-schema.ts deleted file mode 100644 index 1ae412c00b..0000000000 --- a/packages/apps/human-app/frontend/src/shared/schemas/validate-address-schema.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { t } from 'i18next'; -import { z } from 'zod'; - -export const addressSchemaOrEmptyString = z.string().refine( - (value) => { - if (value === '') { - return true; - } - return /^0x[0-9a-fA-F]{40}$/.test(value); - }, - { - message: t('errors.invalidEscrowAddress'), - } -); diff --git a/packages/apps/human-app/frontend/src/shared/styles/color-palette.ts b/packages/apps/human-app/frontend/src/shared/styles/color-palette.ts index 350f9a6933..1cf299c20b 100644 --- a/packages/apps/human-app/frontend/src/shared/styles/color-palette.ts +++ b/packages/apps/human-app/frontend/src/shared/styles/color-palette.ts @@ -5,8 +5,11 @@ export const colorPalette = { text: { primary: '#320A8D', secondary: '#B2AFC1', + light: '#6309ff', disabled: '#CBCFE6', disabledSecondary: '#8494C3', + auxiliary100: '#000000', + auxiliary200: '#676767', }, primary: { main: '#320A8D', @@ -21,17 +24,29 @@ export const colorPalette = { light: '#8409FF', contrastText: '#FFFFFF', }, + background: { + default: '#f6f7fe', + paper: '#ffffff', + subtle: '#fcfcfc', + }, + accent: { + main: '#fa2a75', + dark: '#af1d51', + contrastText: '#ffffff', + }, + border: { + main: '#d9d9d9', + strong: 'rgba(50, 10, 141, 0.30)', + }, error: { - main: '#FA2A75', - dark: '#F20D5F', - light: '#FF5995', - contrastText: '#FFFFFF', + main: '#ff6262', + dark: '#ff6262cc', + contrastText: '#ffffff', }, success: { - main: '#0AD397', - dark: '#0E976E', - light: '#00EDA6', - contrastText: '#FFFFFF', + main: '#43ba96', + dark: '#43ba96cc', + contrastText: '#ffffff', }, paper: { main: '#F6F7FE', diff --git a/packages/apps/human-app/frontend/src/shared/styles/create-table-dark-mode.tsx b/packages/apps/human-app/frontend/src/shared/styles/create-table-dark-mode.tsx index 9c1a6da968..dd8be85d28 100644 --- a/packages/apps/human-app/frontend/src/shared/styles/create-table-dark-mode.tsx +++ b/packages/apps/human-app/frontend/src/shared/styles/create-table-dark-mode.tsx @@ -41,6 +41,7 @@ export const createTableDarkMode = (colorPalette: ColorPalette) => { muiTablePaperProps: { sx: { boxShadow: 'none', + transition: 'none !important', }, }, }; diff --git a/packages/apps/human-app/frontend/src/shared/styles/dark-color-palette.ts b/packages/apps/human-app/frontend/src/shared/styles/dark-color-palette.ts index dfad3f0edd..0b13c7d654 100644 --- a/packages/apps/human-app/frontend/src/shared/styles/dark-color-palette.ts +++ b/packages/apps/human-app/frontend/src/shared/styles/dark-color-palette.ts @@ -3,12 +3,15 @@ import type { colorPalette } from '@/shared/styles/color-palette'; export const darkColorPalette = { white: '#FFFFFF', black: '#000000', - backgroundColor: 'rgba(16, 7, 53, 1)', + backgroundColor: '#100735', text: { primary: '#D4CFFF', secondary: '#6C6978', + light: '#9387ff', disabled: 'rgba(212, 207, 255, 0.5)', disabledSecondary: 'rgba(147, 135, 255, 1)', + auxiliary100: '#ffffff', + auxiliary200: '#a0a0a0', }, primary: { main: '#CDC7FF', @@ -23,17 +26,29 @@ export const darkColorPalette = { light: '#BB94FF', contrastText: 'rgba(255, 255, 255, 0.87)', }, + background: { + default: '#100735', + paper: '#251d47', + subtle: '#2d284e', + }, + accent: { + main: '#fa2a75', + dark: '#af1d51', + contrastText: '#ffffff', + }, + border: { + main: 'rgba(255, 255, 255, 0.07)', + strong: '#3a2e6f', + }, error: { - main: '#F65A93', - dark: '#F3206E', - light: '#F76DA0', - contrastText: '#FFFFFF', + main: '#ff6262', + dark: '#ff6262cc', + contrastText: '#ffffff', }, success: { - main: '#58CAA8', - dark: '#1F916F', - light: '#5FD1AF', - contrastText: 'rgba(255, 255, 255, 0.87)', + main: '#43ba96', + dark: '#43ba96cc', + contrastText: '#ffffff', }, paper: { main: '#1c133f', @@ -58,11 +73,3 @@ export const darkColorPalette = { // for 'warning', 'info' native colors from MUI were pointed as expected // 'info' native colors from MUI were pointed as expected } satisfies typeof colorPalette; - -// if Figma design was inconsistent for some reasons and there are extra colors for dark mode should be included in this object -export const onlyDarkModeColor = { - backArrowBg: 'rgba(246, 247, 254, 0.1)', - additionalTextColor: '#9387FF', - mainColorWithOpacity: '#CDC7FFCC', - listItemColor: '#CDC7FF29', -}; diff --git a/packages/apps/human-app/frontend/src/shared/styles/dark-theme.ts b/packages/apps/human-app/frontend/src/shared/styles/dark-theme.ts index 56a635b86c..6bb3fb5298 100644 --- a/packages/apps/human-app/frontend/src/shared/styles/dark-theme.ts +++ b/packages/apps/human-app/frontend/src/shared/styles/dark-theme.ts @@ -1,8 +1,5 @@ import type { ThemeOptions } from '@mui/material'; -import { - darkColorPalette, - onlyDarkModeColor, -} from '@/shared/styles/dark-color-palette'; +import { darkColorPalette } from '@/shared/styles/dark-color-palette'; import { typography } from '@/shared/styles/typography'; import { breakpoints } from '@/shared/styles/breakpoints'; @@ -23,7 +20,6 @@ export const darkTheme: ThemeOptions = { variantMapping: { subtitle1: 'p', subtitle2: 'p', - textField: 'p', }, }, }, @@ -154,7 +150,7 @@ export const darkTheme: ThemeOptions = { MuiInputBase: { styleOverrides: { root: { - borderColor: onlyDarkModeColor.mainColorWithOpacity, + borderColor: '#cdc7ffcc', '&:hover': { borderColor: 'white', }, diff --git a/packages/apps/human-app/frontend/src/shared/styles/theme.ts b/packages/apps/human-app/frontend/src/shared/styles/theme.ts index b655c57dc4..36cf5f3331 100644 --- a/packages/apps/human-app/frontend/src/shared/styles/theme.ts +++ b/packages/apps/human-app/frontend/src/shared/styles/theme.ts @@ -2,6 +2,18 @@ import type { ThemeOptions } from '@mui/material'; import { colorPalette } from '@/shared/styles/color-palette'; import { typography } from '@/shared/styles/typography'; +declare module '@mui/material/Button' { + interface ButtonPropsColorOverrides { + accent: true; + } +} + +declare module '@mui/material/Radio' { + interface RadioPropsColorOverrides { + accent: true; + } +} + export const theme: ThemeOptions = { typography, components: { @@ -12,7 +24,6 @@ export const theme: ThemeOptions = { variantMapping: { subtitle1: 'p', subtitle2: 'p', - textField: 'p', }, }, }, @@ -24,6 +35,10 @@ export const theme: ThemeOptions = { fontSize: '14px', fontWeight: 600, textTransform: 'none', + boxShadow: 'none', + '&:hover': { + boxShadow: 'none', + }, '&.Mui-disabled': { backgroundColor: colorPalette.button.disabled, color: colorPalette.text.secondary, @@ -83,8 +98,28 @@ export const theme: ThemeOptions = { }, MuiOutlinedInput: { styleOverrides: { + root: { + color: '#000000', + '&:hover fieldset': { + borderColor: '#000000 !important', + }, + '&.Mui-focused .MuiOutlinedInput-notchedOutline': { + borderColor: '#000000', + }, + }, notchedOutline: { - borderColor: colorPalette.primary.main, + //borderColor: colorPalette.primary.main, + borderColor: '#676767', + }, + }, + }, + MuiInputLabel: { + styleOverrides: { + root: { + color: '#676767', + '&.Mui-focused': { + color: '#000000', + }, }, }, }, diff --git a/packages/apps/human-app/frontend/src/shared/styles/typography.ts b/packages/apps/human-app/frontend/src/shared/styles/typography.ts index 6d53f178e9..fdc40128b4 100644 --- a/packages/apps/human-app/frontend/src/shared/styles/typography.ts +++ b/packages/apps/human-app/frontend/src/shared/styles/typography.ts @@ -4,22 +4,13 @@ import { breakpoints } from '@/shared/styles/breakpoints'; declare module '@mui/material/Typography' { interface TypographyPropsVariantOverrides { - textField: true; - body3: true; body4: true; body5: true; - body6: true; body7: true; body8: true; buttonLarge: true; buttonMedium: true; - buttonSmall: true; - inputLabel: true; helperText: true; - avatarLetter: true; - inputText: true; - tooltip: true; - inputUnderline: true; chip: true; mobileHeaderLarge: true; mobileHeaderMid: true; @@ -29,21 +20,13 @@ declare module '@mui/material/Typography' { declare module '@mui/material/styles' { interface TypographyVariants { textField: CSSProperties; - body3: CSSProperties; body4: CSSProperties; body5: CSSProperties; - body6: CSSProperties; body7: CSSProperties; body8: CSSProperties; buttonLarge: CSSProperties; buttonMedium: CSSProperties; - buttonSmall: CSSProperties; - inputLabel: CSSProperties; helperText: CSSProperties; - avatarLetter: CSSProperties; - inputText: CSSProperties; - tooltip: CSSProperties; - inputUnderline: CSSProperties; chip: CSSProperties; mobileHeaderLarge: CSSProperties; mobileHeaderMid: CSSProperties; @@ -51,21 +34,13 @@ declare module '@mui/material/styles' { interface TypographyVariantsOptions { textField?: CSSProperties; - body3?: CSSProperties; body4?: CSSProperties; body5?: CSSProperties; - body6?: CSSProperties; body7?: CSSProperties; body8?: CSSProperties; buttonLarge?: CSSProperties; buttonMedium?: CSSProperties; - buttonSmall?: CSSProperties; - inputLabel?: CSSProperties; helperText?: CSSProperties; - avatarLetter?: CSSProperties; - inputText?: CSSProperties; - tooltip?: CSSProperties; - inputUnderline?: CSSProperties; chip?: CSSProperties; mobileHeaderLarge?: CSSProperties; mobileHeaderMid?: CSSProperties; @@ -102,12 +77,13 @@ export const typography: ThemeOptions['typography'] = { }, h4: { fontSize: 34, - fontWeight: 600, - letterSpacing: 0.25, + fontWeight: 800, + lineHeight: 'normal', + letterSpacing: 0, [breakpoints.mobile]: { - fontSize: 28, - fontWeight: 600, - letterSpacing: 0.15, + fontSize: 20, + fontWeight: 700, + lineHeight: '150%', }, }, mobileHeaderLarge: { @@ -119,9 +95,6 @@ export const typography: ThemeOptions['typography'] = { fontSize: 24, fontWeight: 400, letterSpacing: 0, - [breakpoints.mobile]: { - fontSize: 24, - }, }, mobileHeaderMid: { fontSize: 22, @@ -131,10 +104,8 @@ export const typography: ThemeOptions['typography'] = { h6: { fontSize: 20, fontWeight: 500, - letterSpacing: 0.15, - [breakpoints.mobile]: { - fontSize: 20, - }, + lineHeight: 'normal', + letterSpacing: 0.12, }, subtitle1: { fontSize: 16, @@ -155,23 +126,14 @@ export const typography: ThemeOptions['typography'] = { body1: { fontSize: 16, fontWeight: 400, - letterSpacing: 0.15, - [breakpoints.mobile]: { - fontSize: 16, - }, + lineHeight: 'normal', + letterSpacing: 0.12, }, body2: { fontSize: 14, fontWeight: 400, - letterSpacing: 0.15, - [breakpoints.mobile]: { - fontSize: 14, - }, - }, - body3: { - fontSize: 16, - fontWeight: 500, - letterSpacing: 0.15, + lineHeight: 'normal', + letterSpacing: 0.12, }, body4: { fontSize: 24, @@ -183,11 +145,6 @@ export const typography: ThemeOptions['typography'] = { fontWeight: 500, letterSpacing: 0.15, }, - body6: { - fontSize: 24, - fontWeight: 600, - letterSpacing: 0.15, - }, body7: { fontSize: 18, fontWeight: 500, @@ -210,53 +167,16 @@ export const typography: ThemeOptions['typography'] = { fontWeight: 600, letterSpacing: 0.1, }, - buttonSmall: { - fontSize: 13, - fontWeight: 600, - letterSpacing: 0.1, - }, caption: { fontSize: 12, fontWeight: 400, letterSpacing: 0.4, }, - overline: { - fontSize: 12, - fontWeight: 400, - letterSpacing: 0.4, - textTransform: 'uppercase', - }, - avatarLetter: { - fontSize: 20, - fontWeight: 400, - letterSpacing: 0.14, - }, - inputLabel: { - fontSize: 12, - fontWeight: 400, - letterSpacing: 0.15, - }, helperText: { fontSize: 12, fontWeight: 400, letterSpacing: 0.4, }, - inputText: { - fontSize: 16, - fontWeight: 400, - letterSpacing: 0.15, - }, - tooltip: { - fontSize: 10, - fontWeight: 500, - letterSpacing: 0, - }, - inputUnderline: { - fontSize: 12, - fontWeight: 600, - letterSpacing: 0.15, - textDecoration: 'underline', - }, chip: { fontSize: 13, fontWeight: 400, diff --git a/packages/apps/human-app/frontend/src/shared/types/browser-auth-provider.ts b/packages/apps/human-app/frontend/src/shared/types/browser-auth-provider.ts index ce014570a9..b004f8c3c6 100644 --- a/packages/apps/human-app/frontend/src/shared/types/browser-auth-provider.ts +++ b/packages/apps/human-app/frontend/src/shared/types/browser-auth-provider.ts @@ -1,15 +1,11 @@ -import type { Web3UserData } from '@/modules/auth-web3/context/web3-auth-context'; import type { UserData } from '@/modules/auth/context/auth-context'; import { type AuthTokensSuccessResponse } from '../schemas'; -export type AuthType = 'web2' | 'web3'; type SubscriptionCallback = () => void; export interface BrowserAuthProvider { isAuthenticated: boolean; - authType: AuthType; signIn: ( singInSuccessData: AuthTokensSuccessResponse, - authType: AuthType, signOutSubscription?: SubscriptionCallback ) => void; signOut: (args?: { @@ -19,7 +15,6 @@ export interface BrowserAuthProvider { signOutSubscription?: SubscriptionCallback; getAccessToken: () => string | null; getRefreshToken: () => string | null; - getAuthType: () => AuthType | null; - setUserData: (userData: UserData | Web3UserData) => void; + setUserData: (userData: UserData) => void; getUserData: () => { data: unknown }; } diff --git a/packages/apps/human-app/frontend/src/shared/types/entity.type.ts b/packages/apps/human-app/frontend/src/shared/types/entity.type.ts index 03ec2ffb9e..2e9c93cc04 100644 --- a/packages/apps/human-app/frontend/src/shared/types/entity.type.ts +++ b/packages/apps/human-app/frontend/src/shared/types/entity.type.ts @@ -1 +1,14 @@ export type PageSize = 5 | 10; + +export enum JobType { + FORTUNE = 'fortune', + POINTS = 'image_points', + BOUNDING_BOXES = 'image_boxes', + BOUNDING_BOXES_FROM_POINTS = 'image_boxes_from_points', + SKELETONS_FROM_BOUNDING_BOXES = 'image_skeletons_from_boxes', + POLYGONS = 'image_polygons', + AUDIO_TRANSCRIPTION = 'audio_transcription', + AUDIO_ATTRIBUTE_ANNOTATION = 'audio_attribute_annotation', + SOCIAL_MEDIA_PROMOTION = 'social_media_promotion', + SOCIAL_MEDIA_ENGAGEMENT = 'social_media_engagement', +} diff --git a/packages/apps/human-app/frontend/src/shared/types/global.type.ts b/packages/apps/human-app/frontend/src/shared/types/global.type.ts index c5ebc70959..8d51324795 100644 --- a/packages/apps/human-app/frontend/src/shared/types/global.type.ts +++ b/packages/apps/human-app/frontend/src/shared/types/global.type.ts @@ -4,6 +4,21 @@ import { type ApiClientError } from '@/api'; export type ResponseError = ApiClientError | Error | ZodError | JsonRpcError; +declare global { + interface Window { + $zoho?: { + salesiq?: { + chat?: { + start?: () => void; + }; + floatbutton?: { + visible?: (state: 'show' | 'hide' | number) => void; + }; + }; + }; + } +} + declare module '@tanstack/react-query' { interface Register { defaultError: ResponseError; diff --git a/yarn.lock b/yarn.lock index 82951c67a1..e3202dc541 100644 --- a/yarn.lock +++ b/yarn.lock @@ -430,16 +430,11 @@ __metadata: "@mui/x-date-pickers": "npm:^9.9.0" "@reown/appkit": "npm:^1.8.20" "@reown/appkit-adapter-wagmi": "npm:^1.8.20" - "@synaps-io/verify-sdk": "npm:^4.0.45" - "@tanstack/eslint-plugin-query": "npm:^5.60.1" "@tanstack/react-query": "npm:^5.91.3" - "@tanstack/react-query-devtools": "npm:^5.59.16" "@types/lodash": "npm:^4.17.24" "@types/node": "npm:^22.10.5" - "@types/prop-types": "npm:^15" "@types/react": "npm:^19.2.15" "@types/react-dom": "npm:^19.2.3" - "@vercel/style-guide": "npm:^6.0.0" "@vitejs/plugin-react": "npm:^4.2.1" "@wagmi/core": "npm:^3.4.0" date-fns: "npm:^4.1.0" @@ -448,10 +443,8 @@ __metadata: eslint-plugin-jsx-a11y: "npm:^6.10.2" eslint-plugin-prettier: "npm:^5.5.6" eslint-plugin-react-hooks: "npm:^5.2.0" - eslint-plugin-react-refresh: "npm:^0.5.2" ethers: "npm:^6.17.0" globals: "npm:^17.7.0" - husky: "npm:^9.1.6" i18next: "npm:^25.8.0" jsdom: "npm:^29.1.1" jwt-decode: "npm:^4.0.0" @@ -459,13 +452,11 @@ __metadata: material-react-table: "npm:3.0.1" notistack: "npm:^3.0.1" prettier: "npm:^3.8.1" - prop-types: "npm:^15.8.1" query-string: "npm:^9.0.0" react: "npm:^19.2.6" react-dom: "npm:^19.2.6" react-hook-form: "npm:^7.71.1" react-i18next: "npm:^15.1.0" - react-imask: "npm:^7.4.0" react-number-format: "npm:^5.4.5" react-router-dom: "npm:^7.18.1" serve: "npm:^14.2.6" @@ -1428,7 +1419,7 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.16.0, @babel/core@npm:^7.21.3, @babel/core@npm:^7.23.9, @babel/core@npm:^7.24.0, @babel/core@npm:^7.28.0": +"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.16.0, @babel/core@npm:^7.21.3, @babel/core@npm:^7.23.9, @babel/core@npm:^7.28.0": version: 7.28.5 resolution: "@babel/core@npm:7.28.5" dependencies: @@ -1474,7 +1465,7 @@ __metadata: languageName: node linkType: hard -"@babel/eslint-parser@npm:^7.16.3, @babel/eslint-parser@npm:^7.23.10": +"@babel/eslint-parser@npm:^7.16.3": version: 7.28.5 resolution: "@babel/eslint-parser@npm:7.28.5" dependencies: @@ -1723,7 +1714,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.22.20, @babel/helper-validator-identifier@npm:^7.27.1, @babel/helper-validator-identifier@npm:^7.28.5": +"@babel/helper-validator-identifier@npm:^7.27.1, @babel/helper-validator-identifier@npm:^7.28.5": version: 7.28.5 resolution: "@babel/helper-validator-identifier@npm:7.28.5" checksum: 10c0/42aaebed91f739a41f3d80b72752d1f95fd7c72394e8e4bd7cdd88817e0774d80a432451bcba17c2c642c257c483bf1d409dd4548883429ea9493a3bc4ab0847 @@ -3028,15 +3019,6 @@ __metadata: languageName: node linkType: hard -"@babel/runtime-corejs3@npm:^7.24.4": - version: 7.28.4 - resolution: "@babel/runtime-corejs3@npm:7.28.4" - dependencies: - core-js-pure: "npm:^3.43.0" - checksum: 10c0/0a7fe2d4e36d345acf090dd685b5c6ed55af3ead69a84e2cfca56631815dd757f3a362031b376cc746f63f0fd856e7a5280807833f7fa9a5b7f1febd97f8c0da - languageName: node - linkType: hard - "@babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.17.9, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.25.0, @babel/runtime@npm:^7.26.0, @babel/runtime@npm:^7.27.6, @babel/runtime@npm:^7.28.4, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.7": version: 7.28.4 resolution: "@babel/runtime@npm:7.28.4" @@ -4163,7 +4145,7 @@ __metadata: languageName: node linkType: hard -"@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0, @eslint-community/eslint-utils@npm:^4.7.0, @eslint-community/eslint-utils@npm:^4.8.0": +"@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.8.0": version: 4.9.0 resolution: "@eslint-community/eslint-utils@npm:4.9.0" dependencies: @@ -4185,7 +4167,7 @@ __metadata: languageName: node linkType: hard -"@eslint-community/regexpp@npm:^4.10.0, @eslint-community/regexpp@npm:^4.12.2, @eslint-community/regexpp@npm:^4.4.0": +"@eslint-community/regexpp@npm:^4.12.2, @eslint-community/regexpp@npm:^4.4.0": version: 4.12.2 resolution: "@eslint-community/regexpp@npm:4.12.2" checksum: 10c0/fddcbc66851b308478d04e302a4d771d6917a0b3740dc351513c0da9ca2eab8a1adf99f5e0aa7ab8b13fa0df005c81adeee7e63a92f3effd7d367a163b721c2d @@ -4221,23 +4203,6 @@ __metadata: languageName: node linkType: hard -"@eslint/eslintrc@npm:^2.1.4": - version: 2.1.4 - resolution: "@eslint/eslintrc@npm:2.1.4" - dependencies: - ajv: "npm:^6.12.4" - debug: "npm:^4.3.2" - espree: "npm:^9.6.0" - globals: "npm:^13.19.0" - ignore: "npm:^5.2.0" - import-fresh: "npm:^3.2.1" - js-yaml: "npm:^4.1.0" - minimatch: "npm:^3.1.2" - strip-json-comments: "npm:^3.1.1" - checksum: 10c0/32f67052b81768ae876c84569ffd562491ec5a5091b0c1e1ca1e0f3c24fb42f804952fdd0a137873bc64303ba368a71ba079a6f691cee25beee9722d94cc8573 - languageName: node - linkType: hard - "@eslint/js@npm:^10.0.1": version: 10.0.1 resolution: "@eslint/js@npm:10.0.1" @@ -7002,25 +6967,6 @@ __metadata: languageName: node linkType: hard -"@microsoft/tsdoc-config@npm:0.16.2": - version: 0.16.2 - resolution: "@microsoft/tsdoc-config@npm:0.16.2" - dependencies: - "@microsoft/tsdoc": "npm:0.14.2" - ajv: "npm:~6.12.6" - jju: "npm:~1.4.0" - resolve: "npm:~1.19.0" - checksum: 10c0/9e8c176b68f01c8bb38e6365d5b543e471bba59fced6070d9bd35b32461fbd650c2e1a6f686e8dca0cf22bc5e7d796e4213e66bce4426c8cb9864c1f6ca6836c - languageName: node - linkType: hard - -"@microsoft/tsdoc@npm:0.14.2": - version: 0.14.2 - resolution: "@microsoft/tsdoc@npm:0.14.2" - checksum: 10c0/c018857ad439144559ce34a397a29ace7cf5b24b999b8e3c1b88d878338088b3a453eaac4435beaf2c7eae13c4c0aac81e42f96f0f1d48e8d4eeb438eb3bb82f - languageName: node - linkType: hard - "@microsoft/tsdoc@npm:0.16.0": version: 0.16.0 resolution: "@microsoft/tsdoc@npm:0.16.0" @@ -8481,13 +8427,6 @@ __metadata: languageName: node linkType: hard -"@nolyfill/is-core-module@npm:1.0.39": - version: 1.0.39 - resolution: "@nolyfill/is-core-module@npm:1.0.39" - checksum: 10c0/34ab85fdc2e0250879518841f74a30c276bca4f6c3e13526d2d1fe515e1adf6d46c25fcd5989d22ea056d76f7c39210945180b4859fc83b050e2da411aa86289 - languageName: node - linkType: hard - "@nomicfoundation/edr-darwin-arm64@npm:0.11.3": version: 0.11.3 resolution: "@nomicfoundation/edr-darwin-arm64@npm:0.11.3" @@ -9226,13 +9165,6 @@ __metadata: languageName: node linkType: hard -"@pkgr/core@npm:^0.2.9": - version: 0.2.9 - resolution: "@pkgr/core@npm:0.2.9" - checksum: 10c0/ac8e4e8138b1a7a4ac6282873aef7389c352f1f8b577b4850778f5182e4a39a5241facbe48361fec817f56d02b51691b383010843fb08b34a8e8ea3614688fd5 - languageName: node - linkType: hard - "@pkgr/core@npm:^0.3.6": version: 0.3.6 resolution: "@pkgr/core@npm:0.3.6" @@ -9924,7 +9856,7 @@ __metadata: languageName: node linkType: hard -"@rushstack/eslint-patch@npm:^1.1.0, @rushstack/eslint-patch@npm:^1.7.2": +"@rushstack/eslint-patch@npm:^1.1.0": version: 1.14.1 resolution: "@rushstack/eslint-patch@npm:1.14.1" checksum: 10c0/ec5014494e4fa2dcdc555b62d5db3ebcd146562863a7e75cdacbac96dd1699e93f47dfc3f2185462a21c06987728d73258e32088e93315392e4f79234250b276 @@ -11742,24 +11674,6 @@ __metadata: languageName: node linkType: hard -"@synaps-io/verify-sdk@npm:^4.0.45": - version: 4.0.48 - resolution: "@synaps-io/verify-sdk@npm:4.0.48" - checksum: 10c0/a1a520dd951ba2824bbac891ddae60c049eb9164e373f18cc68cfdb5a5eb2f09009b0c763fc11f39503ca6246a4d65895106180e0d39f6f52889b66a791ec42e - languageName: node - linkType: hard - -"@tanstack/eslint-plugin-query@npm:^5.60.1": - version: 5.91.2 - resolution: "@tanstack/eslint-plugin-query@npm:5.91.2" - dependencies: - "@typescript-eslint/utils": "npm:^8.44.1" - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - checksum: 10c0/d839f37ae99ea776a2d1c03514d0e57a73890f449046e53b9497e919365bb14a13277f152cdb532f6714d60399b280daeedcaf55559d23b90b6beaa352fe15c8 - languageName: node - linkType: hard - "@tanstack/match-sorter-utils@npm:8.19.4": version: 8.19.4 resolution: "@tanstack/match-sorter-utils@npm:8.19.4" @@ -11790,13 +11704,6 @@ __metadata: languageName: node linkType: hard -"@tanstack/query-devtools@npm:5.90.1": - version: 5.90.1 - resolution: "@tanstack/query-devtools@npm:5.90.1" - checksum: 10c0/3b69e5441438acf0e753adbf187abf54b5b2e19d7c6d1e465d97278cb8c248bb86d3be193092d50414e4093cbf014093103517cb523daae003e53c867f3c11c2 - languageName: node - linkType: hard - "@tanstack/query-persist-client-core@npm:5.101.2": version: 5.101.2 resolution: "@tanstack/query-persist-client-core@npm:5.101.2" @@ -11825,18 +11732,6 @@ __metadata: languageName: node linkType: hard -"@tanstack/react-query-devtools@npm:^5.59.16": - version: 5.90.2 - resolution: "@tanstack/react-query-devtools@npm:5.90.2" - dependencies: - "@tanstack/query-devtools": "npm:5.90.1" - peerDependencies: - "@tanstack/react-query": ^5.90.2 - react: ^18 || ^19 - checksum: 10c0/526d529bf995426ace7511f51a425ce92dfc1b6dd74c9956a3cd7d68950119e97291bced2ff17173bcdb329eae36c68abc211a4dec32d6e92ab537b41c0533c2 - languageName: node - linkType: hard - "@tanstack/react-query-persist-client@npm:^5.80.7": version: 5.90.8 resolution: "@tanstack/react-query-persist-client@npm:5.90.8" @@ -12611,13 +12506,6 @@ __metadata: languageName: node linkType: hard -"@types/normalize-package-data@npm:^2.4.0": - version: 2.4.4 - resolution: "@types/normalize-package-data@npm:2.4.4" - checksum: 10c0/aef7bb9b015883d6f4119c423dd28c4bdc17b0e8a0ccf112c78b4fe0e91fbc4af7c6204b04bba0e199a57d2f3fbbd5b4a14bf8739bf9d2a39b2a0aad545e0f86 - languageName: node - linkType: hard - "@types/parse-json@npm:^4.0.0": version: 4.0.2 resolution: "@types/parse-json@npm:4.0.2" @@ -12681,7 +12569,7 @@ __metadata: languageName: node linkType: hard -"@types/prop-types@npm:^15, @types/prop-types@npm:^15.7.12, @types/prop-types@npm:^15.7.15": +"@types/prop-types@npm:^15.7.12, @types/prop-types@npm:^15.7.15": version: 15.7.15 resolution: "@types/prop-types@npm:15.7.15" checksum: 10c0/b59aad1ad19bf1733cf524fd4e618196c6c7690f48ee70a327eb450a42aab8e8a063fbe59ca0a5701aebe2d92d582292c0fb845ea57474f6a15f6994b0e260b2 @@ -13012,29 +12900,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^7.1.1": - version: 7.18.0 - resolution: "@typescript-eslint/eslint-plugin@npm:7.18.0" - dependencies: - "@eslint-community/regexpp": "npm:^4.10.0" - "@typescript-eslint/scope-manager": "npm:7.18.0" - "@typescript-eslint/type-utils": "npm:7.18.0" - "@typescript-eslint/utils": "npm:7.18.0" - "@typescript-eslint/visitor-keys": "npm:7.18.0" - graphemer: "npm:^1.4.0" - ignore: "npm:^5.3.1" - natural-compare: "npm:^1.4.0" - ts-api-utils: "npm:^1.3.0" - peerDependencies: - "@typescript-eslint/parser": ^7.0.0 - eslint: ^8.56.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/2b37948fa1b0dab77138909dabef242a4d49ab93e4019d4ef930626f0a7d96b03e696cd027fa0087881c20e73be7be77c942606b4a76fa599e6b37f6985304c3 - languageName: node - linkType: hard - "@typescript-eslint/experimental-utils@npm:^5.0.0": version: 5.62.0 resolution: "@typescript-eslint/experimental-utils@npm:5.62.0" @@ -13079,37 +12944,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/parser@npm:^7.1.1": - version: 7.18.0 - resolution: "@typescript-eslint/parser@npm:7.18.0" - dependencies: - "@typescript-eslint/scope-manager": "npm:7.18.0" - "@typescript-eslint/types": "npm:7.18.0" - "@typescript-eslint/typescript-estree": "npm:7.18.0" - "@typescript-eslint/visitor-keys": "npm:7.18.0" - debug: "npm:^4.3.4" - peerDependencies: - eslint: ^8.56.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/370e73fca4278091bc1b657f85e7d74cd52b24257ea20c927a8e17546107ce04fbf313fec99aed0cc2a145ddbae1d3b12e9cc2c1320117636dc1281bcfd08059 - languageName: node - linkType: hard - -"@typescript-eslint/project-service@npm:8.46.2": - version: 8.46.2 - resolution: "@typescript-eslint/project-service@npm:8.46.2" - dependencies: - "@typescript-eslint/tsconfig-utils": "npm:^8.46.2" - "@typescript-eslint/types": "npm:^8.46.2" - debug: "npm:^4.3.4" - peerDependencies: - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/03e87bcbca6af3f95bf54d4047a8b4d12434126c27d7312e804499a9459e1c847fe045f83fe8e3b22c3dc3925baad0aa2a1a5476d0d51f73a493dc5909a53dbf - languageName: node - linkType: hard - "@typescript-eslint/project-service@npm:8.57.1": version: 8.57.1 resolution: "@typescript-eslint/project-service@npm:8.57.1" @@ -13133,26 +12967,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:7.18.0": - version: 7.18.0 - resolution: "@typescript-eslint/scope-manager@npm:7.18.0" - dependencies: - "@typescript-eslint/types": "npm:7.18.0" - "@typescript-eslint/visitor-keys": "npm:7.18.0" - checksum: 10c0/038cd58c2271de146b3a594afe2c99290034033326d57ff1f902976022c8b0138ffd3cb893ae439ae41003b5e4bcc00cabf6b244ce40e8668f9412cc96d97b8e - languageName: node - linkType: hard - -"@typescript-eslint/scope-manager@npm:8.46.2": - version: 8.46.2 - resolution: "@typescript-eslint/scope-manager@npm:8.46.2" - dependencies: - "@typescript-eslint/types": "npm:8.46.2" - "@typescript-eslint/visitor-keys": "npm:8.46.2" - checksum: 10c0/42f52ee621a3a0ef2233e7d3384d9dbd76218f5c906a9cce3152a1f55c060a3d3614c7b8fff5270bdf48e8fcc003e732d3f003f283ea6fb204d64a2f6bb3ea9c - languageName: node - linkType: hard - "@typescript-eslint/scope-manager@npm:8.57.1": version: 8.57.1 resolution: "@typescript-eslint/scope-manager@npm:8.57.1" @@ -13163,15 +12977,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/tsconfig-utils@npm:8.46.2, @typescript-eslint/tsconfig-utils@npm:^8.46.2": - version: 8.46.2 - resolution: "@typescript-eslint/tsconfig-utils@npm:8.46.2" - peerDependencies: - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/23e34ad296347417e42234945138022fb045d180fde69941483884a38e85fa55d5449420d2a660c0ebf1794a445add2f13e171c8dd64e4e83f594e2c4e35bf4d - languageName: node - linkType: hard - "@typescript-eslint/tsconfig-utils@npm:8.57.1, @typescript-eslint/tsconfig-utils@npm:^8.57.1": version: 8.57.1 resolution: "@typescript-eslint/tsconfig-utils@npm:8.57.1" @@ -13198,23 +13003,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:7.18.0": - version: 7.18.0 - resolution: "@typescript-eslint/type-utils@npm:7.18.0" - dependencies: - "@typescript-eslint/typescript-estree": "npm:7.18.0" - "@typescript-eslint/utils": "npm:7.18.0" - debug: "npm:^4.3.4" - ts-api-utils: "npm:^1.3.0" - peerDependencies: - eslint: ^8.56.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/ad92a38007be620f3f7036f10e234abdc2fdc518787b5a7227e55fd12896dacf56e8b34578723fbf9bea8128df2510ba8eb6739439a3879eda9519476d5783fd - languageName: node - linkType: hard - "@typescript-eslint/type-utils@npm:8.57.1": version: 8.57.1 resolution: "@typescript-eslint/type-utils@npm:8.57.1" @@ -13238,20 +13026,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/types@npm:7.18.0": - version: 7.18.0 - resolution: "@typescript-eslint/types@npm:7.18.0" - checksum: 10c0/eb7371ac55ca77db8e59ba0310b41a74523f17e06f485a0ef819491bc3dd8909bb930120ff7d30aaf54e888167e0005aa1337011f3663dc90fb19203ce478054 - languageName: node - linkType: hard - -"@typescript-eslint/types@npm:8.46.2, @typescript-eslint/types@npm:^8.46.2": - version: 8.46.2 - resolution: "@typescript-eslint/types@npm:8.46.2" - checksum: 10c0/611716bae2369a1b8001c7f6cc03c5ecadfb956643cbbe27269defd28a61d43fe52eda008d7a09568b0be50c502e8292bf767b246366004283476e9a971b6fbc - languageName: node - linkType: hard - "@typescript-eslint/types@npm:8.57.1, @typescript-eslint/types@npm:^8.56.0, @typescript-eslint/types@npm:^8.57.1": version: 8.57.1 resolution: "@typescript-eslint/types@npm:8.57.1" @@ -13277,45 +13051,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:7.18.0": - version: 7.18.0 - resolution: "@typescript-eslint/typescript-estree@npm:7.18.0" - dependencies: - "@typescript-eslint/types": "npm:7.18.0" - "@typescript-eslint/visitor-keys": "npm:7.18.0" - debug: "npm:^4.3.4" - globby: "npm:^11.1.0" - is-glob: "npm:^4.0.3" - minimatch: "npm:^9.0.4" - semver: "npm:^7.6.0" - ts-api-utils: "npm:^1.3.0" - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/0c7f109a2e460ec8a1524339479cf78ff17814d23c83aa5112c77fb345e87b3642616291908dcddea1e671da63686403dfb712e4a4435104f92abdfddf9aba81 - languageName: node - linkType: hard - -"@typescript-eslint/typescript-estree@npm:8.46.2": - version: 8.46.2 - resolution: "@typescript-eslint/typescript-estree@npm:8.46.2" - dependencies: - "@typescript-eslint/project-service": "npm:8.46.2" - "@typescript-eslint/tsconfig-utils": "npm:8.46.2" - "@typescript-eslint/types": "npm:8.46.2" - "@typescript-eslint/visitor-keys": "npm:8.46.2" - debug: "npm:^4.3.4" - fast-glob: "npm:^3.3.2" - is-glob: "npm:^4.0.3" - minimatch: "npm:^9.0.4" - semver: "npm:^7.6.0" - ts-api-utils: "npm:^2.1.0" - peerDependencies: - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/ad7dbf352982bc6e16473ef19fc7d209fffeb147a732db8a2464e0ec33e7fbbc24ce3f23d01bdf99d503626c582a476debf4c90c527d755eeb99b863476d9f5f - languageName: node - linkType: hard - "@typescript-eslint/typescript-estree@npm:8.57.1": version: 8.57.1 resolution: "@typescript-eslint/typescript-estree@npm:8.57.1" @@ -13335,7 +13070,7 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@npm:5.62.0, @typescript-eslint/utils@npm:^5.10.0, @typescript-eslint/utils@npm:^5.58.0, @typescript-eslint/utils@npm:^5.62.0": +"@typescript-eslint/utils@npm:5.62.0, @typescript-eslint/utils@npm:^5.58.0": version: 5.62.0 resolution: "@typescript-eslint/utils@npm:5.62.0" dependencies: @@ -13353,20 +13088,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@npm:7.18.0, @typescript-eslint/utils@npm:^7.1.1": - version: 7.18.0 - resolution: "@typescript-eslint/utils@npm:7.18.0" - dependencies: - "@eslint-community/eslint-utils": "npm:^4.4.0" - "@typescript-eslint/scope-manager": "npm:7.18.0" - "@typescript-eslint/types": "npm:7.18.0" - "@typescript-eslint/typescript-estree": "npm:7.18.0" - peerDependencies: - eslint: ^8.56.0 - checksum: 10c0/a25a6d50eb45c514469a01ff01f215115a4725fb18401055a847ddf20d1b681409c4027f349033a95c4ff7138d28c3b0a70253dfe8262eb732df4b87c547bd1e - languageName: node - linkType: hard - "@typescript-eslint/utils@npm:8.57.1, @typescript-eslint/utils@npm:^8.0.0": version: 8.57.1 resolution: "@typescript-eslint/utils@npm:8.57.1" @@ -13382,21 +13103,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@npm:^8.44.1": - version: 8.46.2 - resolution: "@typescript-eslint/utils@npm:8.46.2" - dependencies: - "@eslint-community/eslint-utils": "npm:^4.7.0" - "@typescript-eslint/scope-manager": "npm:8.46.2" - "@typescript-eslint/types": "npm:8.46.2" - "@typescript-eslint/typescript-estree": "npm:8.46.2" - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/600b70730077ed85a6e278e06771f3933cdafce242f979e4af1c1b41290bf1efb14d20823c25c38a3a792def69b18eb9410af28bb228fe86027ad7859753c62d - languageName: node - linkType: hard - "@typescript-eslint/visitor-keys@npm:5.62.0": version: 5.62.0 resolution: "@typescript-eslint/visitor-keys@npm:5.62.0" @@ -13407,26 +13113,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:7.18.0": - version: 7.18.0 - resolution: "@typescript-eslint/visitor-keys@npm:7.18.0" - dependencies: - "@typescript-eslint/types": "npm:7.18.0" - eslint-visitor-keys: "npm:^3.4.3" - checksum: 10c0/538b645f8ff1d9debf264865c69a317074eaff0255e63d7407046176b0f6a6beba34a6c51d511f12444bae12a98c69891eb6f403c9f54c6c2e2849d1c1cb73c0 - languageName: node - linkType: hard - -"@typescript-eslint/visitor-keys@npm:8.46.2": - version: 8.46.2 - resolution: "@typescript-eslint/visitor-keys@npm:8.46.2" - dependencies: - "@typescript-eslint/types": "npm:8.46.2" - eslint-visitor-keys: "npm:^4.2.1" - checksum: 10c0/2067cd9a3c90b3817242cc49b5fa77428e1b92b28e16a12f45c2b399acbba7bd17e503553e5e68924e40078477a5c247dfa12e7709c24fe11c0b17a0c8486c33 - languageName: node - linkType: hard - "@typescript-eslint/visitor-keys@npm:8.57.1": version: 8.57.1 resolution: "@typescript-eslint/visitor-keys@npm:8.57.1" @@ -13572,48 +13258,6 @@ __metadata: languageName: node linkType: hard -"@vercel/style-guide@npm:^6.0.0": - version: 6.0.0 - resolution: "@vercel/style-guide@npm:6.0.0" - dependencies: - "@babel/core": "npm:^7.24.0" - "@babel/eslint-parser": "npm:^7.23.10" - "@rushstack/eslint-patch": "npm:^1.7.2" - "@typescript-eslint/eslint-plugin": "npm:^7.1.1" - "@typescript-eslint/parser": "npm:^7.1.1" - eslint-config-prettier: "npm:^9.1.0" - eslint-import-resolver-alias: "npm:^1.1.2" - eslint-import-resolver-typescript: "npm:^3.6.1" - eslint-plugin-eslint-comments: "npm:^3.2.0" - eslint-plugin-import: "npm:^2.29.1" - eslint-plugin-jest: "npm:^27.9.0" - eslint-plugin-jsx-a11y: "npm:^6.8.0" - eslint-plugin-playwright: "npm:^1.5.2" - eslint-plugin-react: "npm:^7.34.0" - eslint-plugin-react-hooks: "npm:^4.6.0" - eslint-plugin-testing-library: "npm:^6.2.0" - eslint-plugin-tsdoc: "npm:^0.2.17" - eslint-plugin-unicorn: "npm:^51.0.1" - eslint-plugin-vitest: "npm:^0.3.22" - prettier-plugin-packagejson: "npm:^2.4.12" - peerDependencies: - "@next/eslint-plugin-next": ">=12.3.0 <15.0.0-0" - eslint: ">=8.48.0 <9" - prettier: ">=3.0.0 <4" - typescript: ">=4.8.0 <6" - peerDependenciesMeta: - "@next/eslint-plugin-next": - optional: true - eslint: - optional: true - prettier: - optional: true - typescript: - optional: true - checksum: 10c0/92729f1c057a46cdb28f603c8f52f33791e5f9628b4b25c1705cea18ec552553db4638ce1b0a0da0b3febc7d85680c2de5e41344368adc6724ec0b63659147ba - languageName: node - linkType: hard - "@vitejs/plugin-react@npm:^4.2.1, @vitejs/plugin-react@npm:^4.3.1, @vitejs/plugin-react@npm:^4.3.4": version: 4.7.0 resolution: "@vitejs/plugin-react@npm:4.7.0" @@ -14758,7 +14402,7 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.11.0, acorn@npm:^8.15.0, acorn@npm:^8.4.1, acorn@npm:^8.9.0": +"acorn@npm:^8.11.0, acorn@npm:^8.15.0, acorn@npm:^8.4.1": version: 8.15.0 resolution: "acorn@npm:8.15.0" bin: @@ -14904,7 +14548,7 @@ __metadata: languageName: node linkType: hard -"ajv@npm:^6.12.4, ajv@npm:^6.12.5, ajv@npm:~6.12.6": +"ajv@npm:^6.12.5": version: 6.12.6 resolution: "ajv@npm:6.12.6" dependencies: @@ -16266,13 +15910,6 @@ __metadata: languageName: node linkType: hard -"builtin-modules@npm:^3.3.0": - version: 3.3.0 - resolution: "builtin-modules@npm:3.3.0" - checksum: 10c0/2cb3448b4f7306dc853632a4fcddc95e8d4e4b9868c139400027b71938fc6806d4ff44007deffb362ac85724bd40c2c6452fb6a0aa4531650eeddb98d8e5ee8a - languageName: node - linkType: hard - "builtin-status-codes@npm:^3.0.0": version: 3.0.0 resolution: "builtin-status-codes@npm:3.0.0" @@ -16683,7 +16320,7 @@ __metadata: languageName: node linkType: hard -"ci-info@npm:^4.0.0, ci-info@npm:^4.2.0": +"ci-info@npm:^4.2.0": version: 4.3.1 resolution: "ci-info@npm:4.3.1" checksum: 10c0/7dd82000f514d76ddfe7775e4cb0d66e5c638f5fa0e2a3be29557e898da0d32ac04f231217d414d07fb968b1fbc6d980ee17ddde0d2c516f23da9cfff608f6c1 @@ -16737,15 +16374,6 @@ __metadata: languageName: node linkType: hard -"clean-regexp@npm:^1.0.0": - version: 1.0.0 - resolution: "clean-regexp@npm:1.0.0" - dependencies: - escape-string-regexp: "npm:^1.0.5" - checksum: 10c0/fd9c7446551b8fc536f95e8a286d431017cd4ba1ec2e53997ec9159385e9c317672f6dfc4d49fdb97449fdb53b0bacd0a8bab9343b8fdd2e46c7ddf6173d0db7 - languageName: node - linkType: hard - "clean-stack@npm:^2.0.0": version: 2.2.0 resolution: "clean-stack@npm:2.2.0" @@ -17268,7 +16896,7 @@ __metadata: languageName: node linkType: hard -"core-js-compat@npm:^3.34.0, core-js-compat@npm:^3.43.0": +"core-js-compat@npm:^3.43.0": version: 3.46.0 resolution: "core-js-compat@npm:3.46.0" dependencies: @@ -17277,13 +16905,6 @@ __metadata: languageName: node linkType: hard -"core-js-pure@npm:^3.43.0": - version: 3.46.0 - resolution: "core-js-pure@npm:3.46.0" - checksum: 10c0/8cf5016f92af5d23c6440649f46fc793ba0201e1687e696cee0341af8e8c6a2e9958b078f23af3a7440edf1ced63ce23a511f7b1357e4793c1101b907bf6ff87 - languageName: node - linkType: hard - "core-util-is@npm:^1.0.3, core-util-is@npm:~1.0.0": version: 1.0.3 resolution: "core-util-is@npm:1.0.3" @@ -18106,13 +17727,6 @@ __metadata: languageName: node linkType: hard -"detect-indent@npm:^7.0.1": - version: 7.0.2 - resolution: "detect-indent@npm:7.0.2" - checksum: 10c0/adb1334ca3fe516dc6817aff0a777540b88643ab92fe13a72d0f5d12721ca796ffdd0e5fedb7b45e6e82657156c6ad44f5d5758157f0439532ae7d07b595146b - languageName: node - linkType: hard - "detect-libc@npm:^1.0.3": version: 1.0.3 resolution: "detect-libc@npm:1.0.3" @@ -18129,13 +17743,6 @@ __metadata: languageName: node linkType: hard -"detect-newline@npm:^4.0.1": - version: 4.0.1 - resolution: "detect-newline@npm:4.0.1" - checksum: 10c0/1cc1082e88ad477f30703ae9f23bd3e33816ea2db6a35333057e087d72d466f5a777809b71f560118ecff935d2c712f5b59e1008a8b56a900909d8fd4621c603 - languageName: node - linkType: hard - "diff-sequences@npm:^29.6.3": version: 29.6.3 resolution: "diff-sequences@npm:29.6.3" @@ -19054,15 +18661,6 @@ __metadata: languageName: node linkType: hard -"eslint-import-resolver-alias@npm:^1.1.2": - version: 1.1.2 - resolution: "eslint-import-resolver-alias@npm:1.1.2" - peerDependencies: - eslint-plugin-import: ">=1.4.0" - checksum: 10c0/71f156e131242db509fe1cfdb410cca665cc9c6e4201e20609689016414e3c6c0b9df27a74b83367694b8ccc5f41687abde26b6cd2c96f961ba16152aca40e43 - languageName: node - linkType: hard - "eslint-import-resolver-node@npm:^0.3.9": version: 0.3.9 resolution: "eslint-import-resolver-node@npm:0.3.9" @@ -19074,30 +18672,6 @@ __metadata: languageName: node linkType: hard -"eslint-import-resolver-typescript@npm:^3.6.1": - version: 3.10.1 - resolution: "eslint-import-resolver-typescript@npm:3.10.1" - dependencies: - "@nolyfill/is-core-module": "npm:1.0.39" - debug: "npm:^4.4.0" - get-tsconfig: "npm:^4.10.0" - is-bun-module: "npm:^2.0.0" - stable-hash: "npm:^0.0.5" - tinyglobby: "npm:^0.2.13" - unrs-resolver: "npm:^1.6.2" - peerDependencies: - eslint: "*" - eslint-plugin-import: "*" - eslint-plugin-import-x: "*" - peerDependenciesMeta: - eslint-plugin-import: - optional: true - eslint-plugin-import-x: - optional: true - checksum: 10c0/02ba72cf757753ab9250806c066d09082e00807b7b6525d7687e1c0710bc3f6947e39120227fe1f93dabea3510776d86fb3fd769466ba3c46ce67e9f874cb702 - languageName: node - linkType: hard - "eslint-import-resolver-typescript@npm:^4.4.4": version: 4.4.4 resolution: "eslint-import-resolver-typescript@npm:4.4.4" @@ -19134,18 +18708,6 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-eslint-comments@npm:^3.2.0": - version: 3.2.0 - resolution: "eslint-plugin-eslint-comments@npm:3.2.0" - dependencies: - escape-string-regexp: "npm:^1.0.5" - ignore: "npm:^5.0.5" - peerDependencies: - eslint: ">=4.19.1" - checksum: 10c0/c71db824592dc8ea498021572a0bd33d763ef26126bdb3b84a027ca75a1adbe0894ec95024f7de39ef12308560e62cbf8af0d06ffe472be5ba8bd9169c928e96 - languageName: node - linkType: hard - "eslint-plugin-flowtype@npm:^8.0.3": version: 8.0.3 resolution: "eslint-plugin-flowtype@npm:8.0.3" @@ -19187,7 +18749,7 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-import@npm:^2.25.3, eslint-plugin-import@npm:^2.29.1": +"eslint-plugin-import@npm:^2.25.3": version: 2.32.0 resolution: "eslint-plugin-import@npm:2.32.0" dependencies: @@ -19233,24 +18795,6 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-jest@npm:^27.9.0": - version: 27.9.0 - resolution: "eslint-plugin-jest@npm:27.9.0" - dependencies: - "@typescript-eslint/utils": "npm:^5.10.0" - peerDependencies: - "@typescript-eslint/eslint-plugin": ^5.0.0 || ^6.0.0 || ^7.0.0 - eslint: ^7.0.0 || ^8.0.0 - jest: "*" - peerDependenciesMeta: - "@typescript-eslint/eslint-plugin": - optional: true - jest: - optional: true - checksum: 10c0/b8b09f7d8ba3d84a8779a6e95702a6e4dce45ab034e4edf5ddb631e77cd38dcdf791dfd9228e0a0d1d80d1eb2d278deb62ad2ec39f10fb8fd43cec07304e0c38 - languageName: node - linkType: hard - "eslint-plugin-jest@npm:^29.15.2": version: 29.15.2 resolution: "eslint-plugin-jest@npm:29.15.2" @@ -19272,7 +18816,7 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-jsx-a11y@npm:^6.10.2, eslint-plugin-jsx-a11y@npm:^6.5.1, eslint-plugin-jsx-a11y@npm:^6.8.0": +"eslint-plugin-jsx-a11y@npm:^6.10.2, eslint-plugin-jsx-a11y@npm:^6.5.1": version: 6.10.2 resolution: "eslint-plugin-jsx-a11y@npm:6.10.2" dependencies: @@ -19297,21 +18841,6 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-playwright@npm:^1.5.2": - version: 1.8.3 - resolution: "eslint-plugin-playwright@npm:1.8.3" - dependencies: - globals: "npm:^13.23.0" - peerDependencies: - eslint: ">=8.40.0" - eslint-plugin-jest: ">=25" - peerDependenciesMeta: - eslint-plugin-jest: - optional: true - checksum: 10c0/41c90ad82d7bfd336b11d88a7dd4aee3832878f3abc5df0c7e988124ac3d4e0ffc7de760f4e986a275bf088da2a360d177e8a48d6b3193dcb5f60b17138cf0fe - languageName: node - linkType: hard - "eslint-plugin-prettier@npm:^5.5.6": version: 5.5.6 resolution: "eslint-plugin-prettier@npm:5.5.6" @@ -19332,7 +18861,7 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-react-hooks@npm:^4.3.0, eslint-plugin-react-hooks@npm:^4.6.0": +"eslint-plugin-react-hooks@npm:^4.3.0": version: 4.6.2 resolution: "eslint-plugin-react-hooks@npm:4.6.2" peerDependencies: @@ -19359,7 +18888,7 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-react@npm:^7.27.1, eslint-plugin-react@npm:^7.34.0, eslint-plugin-react@npm:^7.34.3, eslint-plugin-react@npm:^7.37.5": +"eslint-plugin-react@npm:^7.27.1, eslint-plugin-react@npm:^7.34.3, eslint-plugin-react@npm:^7.37.5": version: 7.37.5 resolution: "eslint-plugin-react@npm:7.37.5" dependencies: @@ -19398,70 +18927,6 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-testing-library@npm:^6.2.0": - version: 6.5.0 - resolution: "eslint-plugin-testing-library@npm:6.5.0" - dependencies: - "@typescript-eslint/utils": "npm:^5.62.0" - peerDependencies: - eslint: ^7.5.0 || ^8.0.0 || ^9.0.0 - checksum: 10c0/d5d6f3e11c7a7fe90f19879fb8ff456889aed66668722b8fcb5e13f4a2f1ff2ce8cda3d4c2f5ff5072280378cf262096bdde226d7934ea47500c8fc042a0308a - languageName: node - linkType: hard - -"eslint-plugin-tsdoc@npm:^0.2.17": - version: 0.2.17 - resolution: "eslint-plugin-tsdoc@npm:0.2.17" - dependencies: - "@microsoft/tsdoc": "npm:0.14.2" - "@microsoft/tsdoc-config": "npm:0.16.2" - checksum: 10c0/26cad40b22f3dc0adfb06b1ea12f7d3c9cb257ac8bb56ad6a023e3b3bdfc6144d95a8b01323563e75283cca90baaf4d68816f5cea6994c6cd660a642e820847a - languageName: node - linkType: hard - -"eslint-plugin-unicorn@npm:^51.0.1": - version: 51.0.1 - resolution: "eslint-plugin-unicorn@npm:51.0.1" - dependencies: - "@babel/helper-validator-identifier": "npm:^7.22.20" - "@eslint-community/eslint-utils": "npm:^4.4.0" - "@eslint/eslintrc": "npm:^2.1.4" - ci-info: "npm:^4.0.0" - clean-regexp: "npm:^1.0.0" - core-js-compat: "npm:^3.34.0" - esquery: "npm:^1.5.0" - indent-string: "npm:^4.0.0" - is-builtin-module: "npm:^3.2.1" - jsesc: "npm:^3.0.2" - pluralize: "npm:^8.0.0" - read-pkg-up: "npm:^7.0.1" - regexp-tree: "npm:^0.1.27" - regjsparser: "npm:^0.10.0" - semver: "npm:^7.5.4" - strip-indent: "npm:^3.0.0" - peerDependencies: - eslint: ">=8.56.0" - checksum: 10c0/e3b019e55d60511c18aec081ff512366f917d0162db3ee122e1f881657b9a1c89e0d505bb7aec968d612ff3c757c055d5b734aaf0b3078a283315bb7db56ca04 - languageName: node - linkType: hard - -"eslint-plugin-vitest@npm:^0.3.22": - version: 0.3.26 - resolution: "eslint-plugin-vitest@npm:0.3.26" - dependencies: - "@typescript-eslint/utils": "npm:^7.1.1" - peerDependencies: - eslint: ">=8.0.0" - vitest: "*" - peerDependenciesMeta: - "@typescript-eslint/eslint-plugin": - optional: true - vitest: - optional: true - checksum: 10c0/8f83c65243b0c0f143194eb9585b18f7316ebb6aa9ada0e1ef9cf69bc1ebff84de08df4c0064c151ebfe5e2a14b8f47a6808276a5af4549869652db5667156c9 - languageName: node - linkType: hard - "eslint-scope@npm:5.1.1, eslint-scope@npm:^5.1.1": version: 5.1.1 resolution: "eslint-scope@npm:5.1.1" @@ -19491,20 +18956,13 @@ __metadata: languageName: node linkType: hard -"eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.1, eslint-visitor-keys@npm:^3.4.3": +"eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.3": version: 3.4.3 resolution: "eslint-visitor-keys@npm:3.4.3" checksum: 10c0/92708e882c0a5ffd88c23c0b404ac1628cf20104a108c745f240a13c332a11aac54f49a22d5762efbffc18ecbc9a580d1b7ad034bf5f3cc3307e5cbff2ec9820 languageName: node linkType: hard -"eslint-visitor-keys@npm:^4.2.1": - version: 4.2.1 - resolution: "eslint-visitor-keys@npm:4.2.1" - checksum: 10c0/fcd43999199d6740db26c58dbe0c2594623e31ca307e616ac05153c9272f12f1364f5a0b1917a8e962268fdecc6f3622c1c2908b4fcc2e047a106fe6de69dc43 - languageName: node - linkType: hard - "eslint-visitor-keys@npm:^5.0.0, eslint-visitor-keys@npm:^5.0.1": version: 5.0.1 resolution: "eslint-visitor-keys@npm:5.0.1" @@ -19568,17 +19026,6 @@ __metadata: languageName: node linkType: hard -"espree@npm:^9.6.0": - version: 9.6.1 - resolution: "espree@npm:9.6.1" - dependencies: - acorn: "npm:^8.9.0" - acorn-jsx: "npm:^5.3.2" - eslint-visitor-keys: "npm:^3.4.1" - checksum: 10c0/1a2e9b4699b715347f62330bcc76aee224390c28bb02b31a3752e9d07549c473f5f986720483c6469cf3cfb3c9d05df612ffc69eb1ee94b54b739e67de9bb460 - languageName: node - linkType: hard - "esprima@npm:2.7.x, esprima@npm:^2.7.1": version: 2.7.3 resolution: "esprima@npm:2.7.3" @@ -19599,15 +19046,6 @@ __metadata: languageName: node linkType: hard -"esquery@npm:^1.5.0": - version: 1.6.0 - resolution: "esquery@npm:1.6.0" - dependencies: - estraverse: "npm:^5.1.0" - checksum: 10c0/cb9065ec605f9da7a76ca6dadb0619dfb611e37a81e318732977d90fab50a256b95fee2d925fba7c2f3f0523aa16f91587246693bc09bc34d5a59575fe6e93d2 - languageName: node - linkType: hard - "esquery@npm:^1.7.0": version: 1.7.0 resolution: "esquery@npm:1.7.0" @@ -20135,7 +19573,7 @@ __metadata: languageName: node linkType: hard -"fast-glob@npm:^3.0.3, fast-glob@npm:^3.2.12, fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.2, fast-glob@npm:^3.3.3": +"fast-glob@npm:^3.0.3, fast-glob@npm:^3.2.12, fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.3": version: 3.3.3 resolution: "fast-glob@npm:3.3.3" dependencies: @@ -20833,7 +20271,7 @@ __metadata: languageName: node linkType: hard -"get-tsconfig@npm:^4.10.0, get-tsconfig@npm:^4.10.1": +"get-tsconfig@npm:^4.10.1": version: 4.13.0 resolution: "get-tsconfig@npm:4.13.0" dependencies: @@ -20854,13 +20292,6 @@ __metadata: languageName: node linkType: hard -"git-hooks-list@npm:^4.0.0": - version: 4.1.1 - resolution: "git-hooks-list@npm:4.1.1" - checksum: 10c0/74d87b1ed457214599566032e3bb79d75ec1605729e83fa6182b889900dd94fc14aafe7b8c66b40562ab9fdeea0e0d8035c23a64d8eb9d3917d1f1d6c06c8e4d - languageName: node - linkType: hard - "glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2": version: 5.1.2 resolution: "glob-parent@npm:5.1.2" @@ -21019,15 +20450,6 @@ __metadata: languageName: node linkType: hard -"globals@npm:^13.19.0, globals@npm:^13.23.0": - version: 13.24.0 - resolution: "globals@npm:13.24.0" - dependencies: - type-fest: "npm:^0.20.2" - checksum: 10c0/d3c11aeea898eb83d5ec7a99508600fbe8f83d2cf00cbb77f873dbf2bcb39428eff1b538e4915c993d8a3b3473fa71eeebfe22c9bb3a3003d1e26b1f2c8a42cd - languageName: node - linkType: hard - "globals@npm:^17.7.0": version: 17.7.0 resolution: "globals@npm:17.7.0" @@ -21708,13 +21130,6 @@ __metadata: languageName: node linkType: hard -"hosted-git-info@npm:^2.1.4": - version: 2.8.9 - resolution: "hosted-git-info@npm:2.8.9" - checksum: 10c0/317cbc6b1bbbe23c2a40ae23f3dafe9fa349ce42a89a36f930e3f9c0530c179a3882d2ef1e4141a4c3674d6faaea862138ec55b43ad6f75e387fda2483a13c70 - languageName: node - linkType: hard - "hosted-git-info@npm:^7.0.0": version: 7.0.2 resolution: "hosted-git-info@npm:7.0.2" @@ -21967,7 +21382,7 @@ __metadata: languageName: node linkType: hard -"ignore@npm:^5.0.5, ignore@npm:^5.1.1, ignore@npm:^5.2.0, ignore@npm:^5.3.1": +"ignore@npm:^5.1.1, ignore@npm:^5.2.0": version: 5.3.2 resolution: "ignore@npm:5.3.2" checksum: 10c0/f9f652c957983634ded1e7f02da3b559a0d4cc210fca3792cb67f1b153623c9c42efdc1c4121af171e295444459fc4a9201101fb041b1104a3c000bccb188337 @@ -21981,15 +21396,6 @@ __metadata: languageName: node linkType: hard -"imask@npm:^7.6.1": - version: 7.6.1 - resolution: "imask@npm:7.6.1" - dependencies: - "@babel/runtime-corejs3": "npm:^7.24.4" - checksum: 10c0/cda75bb5036bf65b1028a39ee5fe7bb1a654838213e8f85288c5899a9e5eb84ce7d2b37ae2d9d600f553b7b0e9fd2f4ba2cbdb03a2c46cf0fa60075bc0c21f0c - languageName: node - linkType: hard - "immer@npm:10.0.2": version: 10.0.2 resolution: "immer@npm:10.0.2" @@ -22264,15 +21670,6 @@ __metadata: languageName: node linkType: hard -"is-builtin-module@npm:^3.2.1": - version: 3.2.1 - resolution: "is-builtin-module@npm:3.2.1" - dependencies: - builtin-modules: "npm:^3.3.0" - checksum: 10c0/5a66937a03f3b18803381518f0ef679752ac18cdb7dd53b5e23ee8df8d440558737bd8dcc04d2aae555909d2ecb4a81b5c0d334d119402584b61e6a003e31af1 - languageName: node - linkType: hard - "is-bun-module@npm:^2.0.0": version: 2.0.0 resolution: "is-bun-module@npm:2.0.0" @@ -22289,7 +21686,7 @@ __metadata: languageName: node linkType: hard -"is-core-module@npm:^2.1.0, is-core-module@npm:^2.13.0, is-core-module@npm:^2.16.1": +"is-core-module@npm:^2.13.0, is-core-module@npm:^2.16.1": version: 2.16.1 resolution: "is-core-module@npm:2.16.1" dependencies: @@ -22492,13 +21889,6 @@ __metadata: languageName: node linkType: hard -"is-plain-obj@npm:^4.1.0": - version: 4.1.0 - resolution: "is-plain-obj@npm:4.1.0" - checksum: 10c0/32130d651d71d9564dc88ba7e6fda0e91a1010a3694648e9f4f47bb6080438140696d3e3e15c741411d712e47ac9edc1a8a9de1fe76f3487b0d90be06ac9975e - languageName: node - linkType: hard - "is-port-reachable@npm:4.0.0": version: 4.0.0 resolution: "is-port-reachable@npm:4.0.0" @@ -23512,13 +22902,6 @@ __metadata: languageName: node linkType: hard -"jju@npm:~1.4.0": - version: 1.4.0 - resolution: "jju@npm:1.4.0" - checksum: 10c0/f3f444557e4364cfc06b1abf8331bf3778b26c0c8552ca54429bc0092652172fdea26cbffe33e1017b303d5aa506f7ede8571857400efe459cb7439180e2acad - languageName: node - linkType: hard - "joi@npm:^17.13.3": version: 17.13.3 resolution: "joi@npm:17.13.3" @@ -23644,15 +23027,6 @@ __metadata: languageName: node linkType: hard -"jsesc@npm:~0.5.0": - version: 0.5.0 - resolution: "jsesc@npm:0.5.0" - bin: - jsesc: bin/jsesc - checksum: 10c0/f93792440ae1d80f091b65f8ceddf8e55c4bb7f1a09dee5dcbdb0db5612c55c0f6045625aa6b7e8edb2e0a4feabd80ee48616dbe2d37055573a84db3d24f96d9 - languageName: node - linkType: hard - "json-bigint@npm:^1.0.0": version: 1.0.0 resolution: "json-bigint@npm:1.0.0" @@ -24919,13 +24293,6 @@ __metadata: languageName: node linkType: hard -"min-indent@npm:^1.0.0": - version: 1.0.1 - resolution: "min-indent@npm:1.0.1" - checksum: 10c0/7e207bd5c20401b292de291f02913230cb1163abca162044f7db1d951fa245b174dc00869d40dd9a9f32a885ad6a5f3e767ee104cf278f399cb4e92d3f582d5c - languageName: node - linkType: hard - "minimalistic-assert@npm:^1.0.0, minimalistic-assert@npm:^1.0.1": version: 1.0.1 resolution: "minimalistic-assert@npm:1.0.1" @@ -25666,18 +25033,6 @@ __metadata: languageName: node linkType: hard -"normalize-package-data@npm:^2.5.0": - version: 2.5.0 - resolution: "normalize-package-data@npm:2.5.0" - dependencies: - hosted-git-info: "npm:^2.1.4" - resolve: "npm:^1.10.0" - semver: "npm:2 || 3 || 4 || 5" - validate-npm-package-license: "npm:^3.0.1" - checksum: 10c0/357cb1646deb42f8eb4c7d42c4edf0eec312f3628c2ef98501963cc4bbe7277021b2b1d977f982b2edce78f5a1014613ce9cf38085c3df2d76730481357ca504 - languageName: node - linkType: hard - "normalize-path@npm:^2.1.1": version: 2.1.1 resolution: "normalize-path@npm:2.1.1" @@ -27101,21 +26456,6 @@ __metadata: languageName: node linkType: hard -"prettier-plugin-packagejson@npm:^2.4.12": - version: 2.5.19 - resolution: "prettier-plugin-packagejson@npm:2.5.19" - dependencies: - sort-package-json: "npm:3.4.0" - synckit: "npm:0.11.11" - peerDependencies: - prettier: ">= 1.16.0" - peerDependenciesMeta: - prettier: - optional: true - checksum: 10c0/288b8658fae8c620d3a7175f64026af8f450f053b8357b86b7d4c697287eae7e706c825d6819959bae1b539103a586f72d8b829574970392d0082f6ec5520d3f - languageName: node - linkType: hard - "prettier-plugin-solidity@npm:^1.3.1": version: 1.4.3 resolution: "prettier-plugin-solidity@npm:1.4.3" @@ -27678,18 +27018,6 @@ __metadata: languageName: node linkType: hard -"react-imask@npm:^7.4.0": - version: 7.6.1 - resolution: "react-imask@npm:7.6.1" - dependencies: - imask: "npm:^7.6.1" - prop-types: "npm:^15.8.1" - peerDependencies: - react: ">=0.14.0" - checksum: 10c0/48b8c234fb77e4d8b8446712695c63f2b0351a896b17623510a648408dd1b7ab506496124453a821528781b05fe2f5b04514f902e260f8b7f4486c972061da88 - languageName: node - linkType: hard - "react-is@npm:^16.13.1, react-is@npm:^16.7.0": version: 16.13.1 resolution: "react-is@npm:16.13.1" @@ -27850,29 +27178,6 @@ __metadata: languageName: node linkType: hard -"read-pkg-up@npm:^7.0.1": - version: 7.0.1 - resolution: "read-pkg-up@npm:7.0.1" - dependencies: - find-up: "npm:^4.1.0" - read-pkg: "npm:^5.2.0" - type-fest: "npm:^0.8.1" - checksum: 10c0/82b3ac9fd7c6ca1bdc1d7253eb1091a98ff3d195ee0a45386582ce3e69f90266163c34121e6a0a02f1630073a6c0585f7880b3865efcae9c452fa667f02ca385 - languageName: node - linkType: hard - -"read-pkg@npm:^5.2.0": - version: 5.2.0 - resolution: "read-pkg@npm:5.2.0" - dependencies: - "@types/normalize-package-data": "npm:^2.4.0" - normalize-package-data: "npm:^2.5.0" - parse-json: "npm:^5.0.0" - type-fest: "npm:^0.6.0" - checksum: 10c0/b51a17d4b51418e777029e3a7694c9bd6c578a5ab99db544764a0b0f2c7c0f58f8a6bc101f86a6fceb8ba6d237d67c89acf6170f6b98695d0420ddc86cf109fb - languageName: node - linkType: hard - "read-yaml-file@npm:^1.1.0": version: 1.1.0 resolution: "read-yaml-file@npm:1.1.0" @@ -28069,15 +27374,6 @@ __metadata: languageName: node linkType: hard -"regexp-tree@npm:^0.1.27": - version: 0.1.27 - resolution: "regexp-tree@npm:0.1.27" - bin: - regexp-tree: bin/regexp-tree - checksum: 10c0/f636f44b4a0d93d7d6926585ecd81f63e4ce2ac895bc417b2ead0874cd36b337dcc3d0fedc63f69bf5aaeaa4340f36ca7e750c9687cceaf8087374e5284e843c - languageName: node - linkType: hard - "regexp.prototype.flags@npm:^1.5.3, regexp.prototype.flags@npm:^1.5.4": version: 1.5.4 resolution: "regexp.prototype.flags@npm:1.5.4" @@ -28141,17 +27437,6 @@ __metadata: languageName: node linkType: hard -"regjsparser@npm:^0.10.0": - version: 0.10.0 - resolution: "regjsparser@npm:0.10.0" - dependencies: - jsesc: "npm:~0.5.0" - bin: - regjsparser: bin/parser - checksum: 10c0/0f0508c142eddbceae55dab9715e714305c19e1e130db53168e8fa5f9f7ff9a4901f674cf6f71e04a0973b2f883882ba05808c80778b2d52b053d925050010f4 - languageName: node - linkType: hard - "regjsparser@npm:^0.13.0": version: 0.13.0 resolution: "regjsparser@npm:0.13.0" @@ -28279,7 +27564,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.1.6, resolve@npm:^1.10.0, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.10, resolve@npm:^1.22.4": +"resolve@npm:^1.1.6, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.10, resolve@npm:^1.22.4": version: 1.22.11 resolution: "resolve@npm:1.22.11" dependencies: @@ -28305,16 +27590,6 @@ __metadata: languageName: node linkType: hard -"resolve@npm:~1.19.0": - version: 1.19.0 - resolution: "resolve@npm:1.19.0" - dependencies: - is-core-module: "npm:^2.1.0" - path-parse: "npm:^1.0.6" - checksum: 10c0/1c8afdfb88c9adab0a19b6f16756d47f5917f64047bf5a38c17aa543aae5ccca2a0631671b19ce8460a7a3e65ead98ee70e046d3056ec173d3377a27487848a8 - languageName: node - linkType: hard - "resolve@patch:resolve@npm%3A1.1.x#optional!builtin": version: 1.1.7 resolution: "resolve@patch:resolve@npm%3A1.1.7#optional!builtin::version=1.1.7&hash=3bafbf" @@ -28331,7 +27606,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.1.6#optional!builtin, resolve@patch:resolve@npm%3A^1.10.0#optional!builtin, resolve@patch:resolve@npm%3A^1.17.0#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.10#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": +"resolve@patch:resolve@npm%3A^1.1.6#optional!builtin, resolve@patch:resolve@npm%3A^1.17.0#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.10#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": version: 1.22.11 resolution: "resolve@patch:resolve@npm%3A1.22.11#optional!builtin::version=1.22.11&hash=c3c19d" dependencies: @@ -28357,16 +27632,6 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A~1.19.0#optional!builtin": - version: 1.19.0 - resolution: "resolve@patch:resolve@npm%3A1.19.0#optional!builtin::version=1.19.0&hash=c3c19d" - dependencies: - is-core-module: "npm:^2.1.0" - path-parse: "npm:^1.0.6" - checksum: 10c0/254980f60dd9fdb28b34a511e70df6e3027d9627efce86a40757eea9b87252d172829c84517554560c4541ebfe207868270c19a0f086997b41209367aa8ef74f - languageName: node - linkType: hard - "restore-cursor@npm:^3.1.0": version: 3.1.0 resolution: "restore-cursor@npm:3.1.0" @@ -28795,15 +28060,6 @@ __metadata: languageName: node linkType: hard -"semver@npm:2 || 3 || 4 || 5, semver@npm:^5.5.0": - version: 5.7.2 - resolution: "semver@npm:5.7.2" - bin: - semver: bin/semver - checksum: 10c0/e4cf10f86f168db772ae95d86ba65b3fd6c5967c94d97c708ccb463b778c2ee53b914cd7167620950fc07faf5a564e6efe903836639e512a1aa15fbc9667fa25 - languageName: node - linkType: hard - "semver@npm:7.7.2": version: 7.7.2 resolution: "semver@npm:7.7.2" @@ -28813,6 +28069,15 @@ __metadata: languageName: node linkType: hard +"semver@npm:^5.5.0": + version: 5.7.2 + resolution: "semver@npm:5.7.2" + bin: + semver: bin/semver + checksum: 10c0/e4cf10f86f168db772ae95d86ba65b3fd6c5967c94d97c708ccb463b778c2ee53b914cd7167620950fc07faf5a564e6efe903836639e512a1aa15fbc9667fa25 + languageName: node + linkType: hard + "semver@npm:^6.3.0, semver@npm:^6.3.1": version: 6.3.1 resolution: "semver@npm:6.3.1" @@ -28822,7 +28087,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.2, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.6.3, semver@npm:^7.7.1, semver@npm:^7.7.3": +"semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.2, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.3, semver@npm:^7.7.1, semver@npm:^7.7.3": version: 7.7.3 resolution: "semver@npm:7.7.3" bin: @@ -29314,30 +28579,6 @@ __metadata: languageName: node linkType: hard -"sort-object-keys@npm:^1.1.3": - version: 1.1.3 - resolution: "sort-object-keys@npm:1.1.3" - checksum: 10c0/3bf62398658d3ff4bbca0db4ed8f42f98abc41433859f63d02fb0ab953fbe5526be240ec7e5d85aa50fcab6c937f3fa7015abf1ecdeb3045a2281c53953886bf - languageName: node - linkType: hard - -"sort-package-json@npm:3.4.0": - version: 3.4.0 - resolution: "sort-package-json@npm:3.4.0" - dependencies: - detect-indent: "npm:^7.0.1" - detect-newline: "npm:^4.0.1" - git-hooks-list: "npm:^4.0.0" - is-plain-obj: "npm:^4.1.0" - semver: "npm:^7.7.1" - sort-object-keys: "npm:^1.1.3" - tinyglobby: "npm:^0.2.12" - bin: - sort-package-json: cli.js - checksum: 10c0/1adb7860eee770fa51ac1c810c2fa2483ab47bf150d1fc2437ef28314ee928142a51245ba22aac8a8c662f431609fc633d404bcdd93acbf54d5a056253741218 - languageName: node - linkType: hard - "source-map-js@npm:>=0.6.2 <2.0.0, source-map-js@npm:^1.2.1": version: 1.2.1 resolution: "source-map-js@npm:1.2.1" @@ -29405,40 +28646,6 @@ __metadata: languageName: node linkType: hard -"spdx-correct@npm:^3.0.0": - version: 3.2.0 - resolution: "spdx-correct@npm:3.2.0" - dependencies: - spdx-expression-parse: "npm:^3.0.0" - spdx-license-ids: "npm:^3.0.0" - checksum: 10c0/49208f008618b9119208b0dadc9208a3a55053f4fd6a0ae8116861bd22696fc50f4142a35ebfdb389e05ccf2de8ad142573fefc9e26f670522d899f7b2fe7386 - languageName: node - linkType: hard - -"spdx-exceptions@npm:^2.1.0": - version: 2.5.0 - resolution: "spdx-exceptions@npm:2.5.0" - checksum: 10c0/37217b7762ee0ea0d8b7d0c29fd48b7e4dfb94096b109d6255b589c561f57da93bf4e328c0290046115961b9209a8051ad9f525e48d433082fc79f496a4ea940 - languageName: node - linkType: hard - -"spdx-expression-parse@npm:^3.0.0": - version: 3.0.1 - resolution: "spdx-expression-parse@npm:3.0.1" - dependencies: - spdx-exceptions: "npm:^2.1.0" - spdx-license-ids: "npm:^3.0.0" - checksum: 10c0/6f8a41c87759fa184a58713b86c6a8b028250f158159f1d03ed9d1b6ee4d9eefdc74181c8ddc581a341aa971c3e7b79e30b59c23b05d2436d5de1c30bdef7171 - languageName: node - linkType: hard - -"spdx-license-ids@npm:^3.0.0": - version: 3.0.22 - resolution: "spdx-license-ids@npm:3.0.22" - checksum: 10c0/4a85e44c2ccfc06eebe63239193f526508ebec1abc7cf7bca8ee43923755636234395447c2c87f40fb672cf580a9c8e684513a676bfb2da3d38a4983684bbb38 - languageName: node - linkType: hard - "split-on-first@npm:^1.0.0": version: 1.1.0 resolution: "split-on-first@npm:1.1.0" @@ -29508,13 +28715,6 @@ __metadata: languageName: node linkType: hard -"stable-hash@npm:^0.0.5": - version: 0.0.5 - resolution: "stable-hash@npm:0.0.5" - checksum: 10c0/ca670cb6d172f1c834950e4ec661e2055885df32fee3ebf3647c5df94993b7c2666a5dbc1c9a62ee11fc5c24928579ec5e81bb5ad31971d355d5a341aab493b3 - languageName: node - linkType: hard - "stack-utils@npm:^2.0.3, stack-utils@npm:^2.0.6": version: 2.0.6 resolution: "stack-utils@npm:2.0.6" @@ -29891,15 +29091,6 @@ __metadata: languageName: node linkType: hard -"strip-indent@npm:^3.0.0": - version: 3.0.0 - resolution: "strip-indent@npm:3.0.0" - dependencies: - min-indent: "npm:^1.0.0" - checksum: 10c0/ae0deaf41c8d1001c5d4fbe16cb553865c1863da4fae036683b474fa926af9fc121e155cb3fc57a68262b2ae7d5b8420aa752c97a6428c315d00efe2a3875679 - languageName: node - linkType: hard - "strip-json-comments@npm:^3.1.1": version: 3.1.1 resolution: "strip-json-comments@npm:3.1.1" @@ -30130,15 +29321,6 @@ __metadata: languageName: node linkType: hard -"synckit@npm:0.11.11": - version: 0.11.11 - resolution: "synckit@npm:0.11.11" - dependencies: - "@pkgr/core": "npm:^0.2.9" - checksum: 10c0/f0761495953d12d94a86edf6326b3a565496c72f9b94c02549b6961fb4d999f4ca316ce6b3eb8ed2e4bfc5056a8de65cda0bd03a233333a35221cd2fdc0e196b - languageName: node - linkType: hard - "synckit@npm:^0.11.13": version: 0.11.13 resolution: "synckit@npm:0.11.13" @@ -30551,24 +29733,6 @@ __metadata: languageName: node linkType: hard -"ts-api-utils@npm:^1.3.0": - version: 1.4.3 - resolution: "ts-api-utils@npm:1.4.3" - peerDependencies: - typescript: ">=4.2.0" - checksum: 10c0/e65dc6e7e8141140c23e1dc94984bf995d4f6801919c71d6dc27cf0cd51b100a91ffcfe5217626193e5bea9d46831e8586febdc7e172df3f1091a7384299e23a - languageName: node - linkType: hard - -"ts-api-utils@npm:^2.1.0": - version: 2.1.0 - resolution: "ts-api-utils@npm:2.1.0" - peerDependencies: - typescript: ">=4.8.4" - checksum: 10c0/9806a38adea2db0f6aa217ccc6bc9c391ddba338a9fe3080676d0d50ed806d305bb90e8cef0276e793d28c8a929f400abb184ddd7ff83a416959c0f4d2ce754f - languageName: node - linkType: hard - "ts-api-utils@npm:^2.4.0": version: 2.4.0 resolution: "ts-api-utils@npm:2.4.0" @@ -30829,13 +29993,6 @@ __metadata: languageName: node linkType: hard -"type-fest@npm:^0.6.0": - version: 0.6.0 - resolution: "type-fest@npm:0.6.0" - checksum: 10c0/0c585c26416fce9ecb5691873a1301b5aff54673c7999b6f925691ed01f5b9232db408cdbb0bd003d19f5ae284322523f44092d1f81ca0a48f11f7cf0be8cd38 - languageName: node - linkType: hard - "type-fest@npm:^0.7.1": version: 0.7.1 resolution: "type-fest@npm:0.7.1" @@ -30843,13 +30000,6 @@ __metadata: languageName: node linkType: hard -"type-fest@npm:^0.8.1": - version: 0.8.1 - resolution: "type-fest@npm:0.8.1" - checksum: 10c0/dffbb99329da2aa840f506d376c863bd55f5636f4741ad6e65e82f5ce47e6914108f44f340a0b74009b0cb5d09d6752ae83203e53e98b1192cf80ecee5651636 - languageName: node - linkType: hard - "type-fest@npm:^2.13.0, type-fest@npm:^2.19.0": version: 2.19.0 resolution: "type-fest@npm:2.19.0" @@ -31414,7 +30564,7 @@ __metadata: languageName: node linkType: hard -"unrs-resolver@npm:^1.6.2, unrs-resolver@npm:^1.7.11, unrs-resolver@npm:^1.9.2": +"unrs-resolver@npm:^1.7.11, unrs-resolver@npm:^1.9.2": version: 1.11.1 resolution: "unrs-resolver@npm:1.11.1" dependencies: @@ -31745,16 +30895,6 @@ __metadata: languageName: node linkType: hard -"validate-npm-package-license@npm:^3.0.1": - version: 3.0.4 - resolution: "validate-npm-package-license@npm:3.0.4" - dependencies: - spdx-correct: "npm:^3.0.0" - spdx-expression-parse: "npm:^3.0.0" - checksum: 10c0/7b91e455a8de9a0beaa9fe961e536b677da7f48c9a493edf4d4d4a87fd80a7a10267d438723364e432c2fcd00b5650b5378275cded362383ef570276e6312f4f - languageName: node - linkType: hard - "validate-npm-package-name@npm:^5.0.0": version: 5.0.1 resolution: "validate-npm-package-name@npm:5.0.1" From 1c66b7b165690c8a2da7504f23cdc253c6581929 Mon Sep 17 00:00:00 2001 From: Dmitry Nechay Date: Fri, 7 Aug 2026 18:30:30 +0300 Subject: [PATCH 32/33] chore: ignore react-dom server vulnerability (#3999) --- .github/workflows/ci-dependency-review.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci-dependency-review.yaml b/.github/workflows/ci-dependency-review.yaml index 4ce01c8511..8a05160424 100644 --- a/.github/workflows/ci-dependency-review.yaml +++ b/.github/workflows/ci-dependency-review.yaml @@ -17,3 +17,5 @@ jobs: uses: actions/dependency-review-action@v5.0.0 with: show-openssf-scorecard: false + allow-ghsas: + - GHSA-qwww-vcr4-c8h2 # we don't use vulnerable functionality From ca82e57f27d75e03ebc8269cfbc671e2bffba923 Mon Sep 17 00:00:00 2001 From: Dmitry Nechay Date: Fri, 7 Aug 2026 18:41:09 +0300 Subject: [PATCH 33/33] chore: use config file for dep review (#4000) --- .github/dependency-review-config.yml | 4 ++++ .github/workflows/ci-dependency-review.yaml | 5 ++--- 2 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 .github/dependency-review-config.yml diff --git a/.github/dependency-review-config.yml b/.github/dependency-review-config.yml new file mode 100644 index 0000000000..6c8f51e130 --- /dev/null +++ b/.github/dependency-review-config.yml @@ -0,0 +1,4 @@ +show-openssf-scorecard: false +fail-on-severity: 'high' +allow-ghsas: + - GHSA-qwww-vcr4-c8h2 # we don't use vulnerable functionality \ No newline at end of file diff --git a/.github/workflows/ci-dependency-review.yaml b/.github/workflows/ci-dependency-review.yaml index 8a05160424..6583ab0c67 100644 --- a/.github/workflows/ci-dependency-review.yaml +++ b/.github/workflows/ci-dependency-review.yaml @@ -16,6 +16,5 @@ jobs: - name: Dependency Review uses: actions/dependency-review-action@v5.0.0 with: - show-openssf-scorecard: false - allow-ghsas: - - GHSA-qwww-vcr4-c8h2 # we don't use vulnerable functionality + config-file: './.github/dependency-review-config.yml' +