diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 31680ef9..682e89fb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: trailing-whitespace - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.8.2 + rev: v0.8.3 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] @@ -23,7 +23,7 @@ repos: args: [-l, '79', -t, py312] - repo: https://github.com/pre-commit/mirrors-eslint - rev: v9.16.0 + rev: v9.17.0 hooks: - id: eslint additional_dependencies: diff --git a/pyproject.toml b/pyproject.toml index 3ae79d7c..3955ca19 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,18 +21,13 @@ classifiers = [ ] requires-python = ">=3.12" dependencies = [ - # FastAPI including some optional features - "fastapi>=0.100", - "python-multipart", - "starlette", - "uvicorn[standard]", - # Other dependencies "alembic[tz]", "asyncpg", "bonsai>=1.5.0", "cachetools", "click>8.1.4", "cryptography", + "fastapi>=0.100", "google-cloud-firestore", "httpx", "kopf", @@ -40,13 +35,16 @@ dependencies = [ "jinja2", "pydantic>=2.10", "pydantic-settings!=2.6.0", + "python-multipart", "pyjwt", "pyyaml", "redis>=4.2.0", - "safir[db,kubernetes]>=8.0.0", + "safir[db,kubernetes]>=9.1.0", "sentry-sdk[fastapi]", "sqlalchemy>=2.0.0", + "starlette", "structlog", + "uvicorn[standard]", ] dynamic = ["version"] diff --git a/requirements/dev.txt b/requirements/dev.txt index 93274b0d..58432a9f 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -28,9 +28,9 @@ asttokens==3.0.0 \ --hash=sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7 \ --hash=sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2 # via stack-data -attrs==24.2.0 \ - --hash=sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346 \ - --hash=sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2 +attrs==24.3.0 \ + --hash=sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff \ + --hash=sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308 # via # -c requirements/main.txt # jsonschema @@ -183,9 +183,9 @@ brotli==1.1.0 \ --hash=sha256:fd5f17ff8f14003595ab414e45fce13d073e0762394f957182e69035c9f3d7c2 \ --hash=sha256:fdc3ff3bfccdc6b9cc7c342c03aa2400683f0cb891d46e94b64a197910dc4064 # via selenium-wire -certifi==2024.8.30 \ - --hash=sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 \ - --hash=sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9 +certifi==2024.12.14 \ + --hash=sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56 \ + --hash=sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db # via # -c requirements/main.txt # httpcore @@ -470,64 +470,64 @@ coverage==7.6.9 \ # via # -r requirements/dev.in # pytest-cov -cryptography==43.0.3 \ - --hash=sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362 \ - --hash=sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4 \ - --hash=sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa \ - --hash=sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83 \ - --hash=sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff \ - --hash=sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805 \ - --hash=sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6 \ - --hash=sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664 \ - --hash=sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08 \ - --hash=sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e \ - --hash=sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18 \ - --hash=sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f \ - --hash=sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73 \ - --hash=sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5 \ - --hash=sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984 \ - --hash=sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd \ - --hash=sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3 \ - --hash=sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e \ - --hash=sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405 \ - --hash=sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2 \ - --hash=sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c \ - --hash=sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995 \ - --hash=sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73 \ - --hash=sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16 \ - --hash=sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7 \ - --hash=sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd \ - --hash=sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7 +cryptography==44.0.0 \ + --hash=sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7 \ + --hash=sha256:37d76e6863da3774cd9db5b409a9ecfd2c71c981c38788d3fcfaf177f447b731 \ + --hash=sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b \ + --hash=sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc \ + --hash=sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543 \ + --hash=sha256:62901fb618f74d7d81bf408c8719e9ec14d863086efe4185afd07c352aee1d2c \ + --hash=sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591 \ + --hash=sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede \ + --hash=sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb \ + --hash=sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f \ + --hash=sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123 \ + --hash=sha256:8b3e6eae66cf54701ee7d9c83c30ac0a1e3fa17be486033000f2a73a12ab507c \ + --hash=sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c \ + --hash=sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285 \ + --hash=sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd \ + --hash=sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092 \ + --hash=sha256:be4ce505894d15d5c5037167ffb7f0ae90b7be6f2a98f9a5c3442395501c32fa \ + --hash=sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289 \ + --hash=sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02 \ + --hash=sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64 \ + --hash=sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053 \ + --hash=sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417 \ + --hash=sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e \ + --hash=sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e \ + --hash=sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7 \ + --hash=sha256:f5e7cb1e5e56ca0933b4873c0220a78b773b24d40d186b6738080b73d3d0a756 \ + --hash=sha256:f677e1268c4e23420c3acade68fac427fffcb8d19d7df95ed7ad17cdef8404f4 # via # -c requirements/main.txt # pyopenssl -debugpy==1.8.9 \ - --hash=sha256:1339e14c7d980407248f09824d1b25ff5c5616651689f1e0f0e51bdead3ea13e \ - --hash=sha256:17c5e0297678442511cf00a745c9709e928ea4ca263d764e90d233208889a19e \ - --hash=sha256:1efbb3ff61487e2c16b3e033bc8595aea578222c08aaf3c4bf0f93fadbd662ee \ - --hash=sha256:365e556a4772d7d0d151d7eb0e77ec4db03bcd95f26b67b15742b88cacff88e9 \ - --hash=sha256:3d9755e77a2d680ce3d2c5394a444cf42be4a592caaf246dbfbdd100ffcf7ae5 \ - --hash=sha256:3e59842d6c4569c65ceb3751075ff8d7e6a6ada209ceca6308c9bde932bcef11 \ - --hash=sha256:472a3994999fe6c0756945ffa359e9e7e2d690fb55d251639d07208dbc37caea \ - --hash=sha256:54a7e6d3014c408eb37b0b06021366ee985f1539e12fe49ca2ee0d392d9ceca5 \ - --hash=sha256:5e565fc54b680292b418bb809f1386f17081d1346dca9a871bf69a8ac4071afe \ - --hash=sha256:62d22dacdb0e296966d7d74a7141aaab4bec123fa43d1a35ddcb39bf9fd29d70 \ - --hash=sha256:66eeae42f3137eb428ea3a86d4a55f28da9bd5a4a3d369ba95ecc3a92c1bba53 \ - --hash=sha256:6953b335b804a41f16a192fa2e7851bdcfd92173cbb2f9f777bb934f49baab65 \ - --hash=sha256:7c4d65d03bee875bcb211c76c1d8f10f600c305dbd734beaed4077e902606fee \ - --hash=sha256:7e646e62d4602bb8956db88b1e72fe63172148c1e25c041e03b103a25f36673c \ - --hash=sha256:7e8b079323a56f719977fde9d8115590cb5e7a1cba2fcee0986ef8817116e7c1 \ - --hash=sha256:8138efff315cd09b8dcd14226a21afda4ca582284bf4215126d87342bba1cc66 \ - --hash=sha256:8e99c0b1cc7bf86d83fb95d5ccdc4ad0586d4432d489d1f54e4055bcc795f693 \ - --hash=sha256:957363d9a7a6612a37458d9a15e72d03a635047f946e5fceee74b50d52a9c8e2 \ - --hash=sha256:957ecffff80d47cafa9b6545de9e016ae8c9547c98a538ee96ab5947115fb3dd \ - --hash=sha256:ada7fb65102a4d2c9ab62e8908e9e9f12aed9d76ef44880367bc9308ebe49a0f \ - --hash=sha256:b74a49753e21e33e7cf030883a92fa607bddc4ede1aa4145172debc637780040 \ - --hash=sha256:c36856343cbaa448171cba62a721531e10e7ffb0abff838004701454149bc037 \ - --hash=sha256:cc37a6c9987ad743d9c3a14fa1b1a14b7e4e6041f9dd0c8abf8895fe7a97b899 \ - --hash=sha256:cfe1e6c6ad7178265f74981edf1154ffce97b69005212fbc90ca22ddfe3d017e \ - --hash=sha256:e46b420dc1bea64e5bbedd678148be512442bc589b0111bd799367cde051e71a \ - --hash=sha256:ff54ef77ad9f5c425398efb150239f6fe8e20c53ae2f68367eba7ece1e96226d +debugpy==1.8.11 \ + --hash=sha256:0e22f846f4211383e6a416d04b4c13ed174d24cc5d43f5fd52e7821d0ebc8920 \ + --hash=sha256:116bf8342062246ca749013df4f6ea106f23bc159305843491f64672a55af2e5 \ + --hash=sha256:189058d03a40103a57144752652b3ab08ff02b7595d0ce1f651b9acc3a3a35a0 \ + --hash=sha256:23dc34c5e03b0212fa3c49a874df2b8b1b8fda95160bd79c01eb3ab51ea8d851 \ + --hash=sha256:28e45b3f827d3bf2592f3cf7ae63282e859f3259db44ed2b129093ca0ac7940b \ + --hash=sha256:2b26fefc4e31ff85593d68b9022e35e8925714a10ab4858fb1b577a8a48cb8cd \ + --hash=sha256:32db46ba45849daed7ccf3f2e26f7a386867b077f39b2a974bb5c4c2c3b0a280 \ + --hash=sha256:40499a9979c55f72f4eb2fc38695419546b62594f8af194b879d2a18439c97a9 \ + --hash=sha256:44b1b8e6253bceada11f714acf4309ffb98bfa9ac55e4fce14f9e5d4484287a1 \ + --hash=sha256:52c3cf9ecda273a19cc092961ee34eb9ba8687d67ba34cc7b79a521c1c64c4c0 \ + --hash=sha256:52d8a3166c9f2815bfae05f386114b0b2d274456980d41f320299a8d9a5615a7 \ + --hash=sha256:61bc8b3b265e6949855300e84dc93d02d7a3a637f2aec6d382afd4ceb9120c9f \ + --hash=sha256:654130ca6ad5de73d978057eaf9e582244ff72d4574b3e106fb8d3d2a0d32458 \ + --hash=sha256:6ad2688b69235c43b020e04fecccdf6a96c8943ca9c2fb340b8adc103c655e57 \ + --hash=sha256:6c1f6a173d1140e557347419767d2b14ac1c9cd847e0b4c5444c7f3144697e4e \ + --hash=sha256:84e511a7545d11683d32cdb8f809ef63fc17ea2a00455cc62d0a4dbb4ed1c308 \ + --hash=sha256:85de8474ad53ad546ff1c7c7c89230db215b9b8a02754d41cb5a76f70d0be296 \ + --hash=sha256:8988f7163e4381b0da7696f37eec7aca19deb02e500245df68a7159739bbd0d3 \ + --hash=sha256:8da1db4ca4f22583e834dcabdc7832e56fe16275253ee53ba66627b86e304da1 \ + --hash=sha256:8ffc382e4afa4aee367bf413f55ed17bd91b191dcaf979890af239dda435f2a1 \ + --hash=sha256:987bce16e86efa86f747d5151c54e91b3c1e36acc03ce1ddb50f9d09d16ded0e \ + --hash=sha256:ad7efe588c8f5cf940f40c3de0cd683cc5b76819446abaa50dc0829a30c094db \ + --hash=sha256:bb3b15e25891f38da3ca0740271e63ab9db61f41d4d8541745cfc1824252cb28 \ + --hash=sha256:c928bbf47f65288574b78518449edaa46c82572d340e2750889bbf8cd92f3737 \ + --hash=sha256:ce291a5aca4985d82875d6779f61375e959208cdf09fcec40001e65fb0a54768 \ + --hash=sha256:d8768edcbeb34da9e11bcb8b5c2e0958d25218df7a6e56adf415ef262cd7b6d1 # via ipykernel decorator==5.1.1 \ --hash=sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330 \ @@ -1129,9 +1129,9 @@ pydantic-core==2.27.1 \ # via # -c requirements/main.txt # pydantic -pydantic-settings==2.6.1 \ - --hash=sha256:7fb0637c786a558d3103436278a7c4f1cfd29ba8973238a50c5bb9a55387da87 \ - --hash=sha256:e0f92546d8a9923cb8941689abf85d6601a8c19a23e97a34b2964a2e3f813ca0 +pydantic-settings==2.7.0 \ + --hash=sha256:ac4bfd4a36831a48dbf8b2d9325425b549a0a6f18cea118436d728eb4f1c4d66 \ + --hash=sha256:e00c05d5fa6cbbb227c84bd7487c5c1065084119b750df7c8c1a554aed236eb5 # via # -c requirements/main.txt # autodoc-pydantic @@ -1177,9 +1177,9 @@ pytest==8.3.4 \ # pytest-asyncio # pytest-cov # pytest-sugar -pytest-asyncio==0.24.0 \ - --hash=sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b \ - --hash=sha256:d081d828e576d85f875399194281e92bf8a68d60d72d1a2faf2feddb6c46b276 +pytest-asyncio==0.25.0 \ + --hash=sha256:8c0610303c9e0442a5db8604505fc0f545456ba1528824842b37b4a626cbf609 \ + --hash=sha256:db5432d18eac6b7e28b46dcd9b69921b55c3b1086e85febfe04e70b18d9e81b3 # via -r requirements/dev.in pytest-cov==6.0.0 \ --hash=sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35 \ diff --git a/requirements/main.txt b/requirements/main.txt index 23377936..3551b5ea 100644 --- a/requirements/main.txt +++ b/requirements/main.txt @@ -121,9 +121,9 @@ aiokafka==0.12.0 \ --hash=sha256:fdbd69ec70eea4a8dfaa5c35ff4852e90e1277fcc426b9380f0b499b77f13b16 \ --hash=sha256:ff63689cafcd6dd642a15de75b7ae121071d6162cccba16d091bcb28b3886307 # via safir -aiosignal==1.3.1 \ - --hash=sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc \ - --hash=sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17 +aiosignal==1.3.2 \ + --hash=sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5 \ + --hash=sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54 # via aiohttp alembic==1.14.0 \ --hash=sha256:99bd884ca390466db5e27ffccff1d179ec5c05c965cfefc0607e69f9e411cb25 \ @@ -201,9 +201,9 @@ asyncpg==0.30.0 \ # via # gafaelfawr (pyproject.toml) # safir -attrs==24.2.0 \ - --hash=sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346 \ - --hash=sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2 +attrs==24.3.0 \ + --hash=sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff \ + --hash=sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308 # via # aiohttp # jsonschema @@ -233,13 +233,13 @@ cachetools==5.5.0 \ # via # gafaelfawr (pyproject.toml) # google-auth -casefy==0.1.7 \ - --hash=sha256:6accce985a64b9edb2a610a29ac489d78fac80e52ff8f2d137e294f2f92b8027 \ - --hash=sha256:ab05ff1c67f2a8e62d9f8986fa9a849416d61ac5413ec57d1f827b4f36589cf6 +casefy==1.0.0 \ + --hash=sha256:bc99428475c2089c5f6a21297b4cfe4e83dff132cf3bb06655ddcb90632af1ed \ + --hash=sha256:c89f96fb0fbd13691073b7a65c1e668e81453247d647479a3db105e86d7b0df9 # via dataclasses-avroschema -certifi==2024.8.30 \ - --hash=sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 \ - --hash=sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9 +certifi==2024.12.14 \ + --hash=sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56 \ + --hash=sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db # via # httpcore # httpx @@ -436,34 +436,34 @@ colorama==0.4.6 ; platform_system == 'Windows' or sys_platform == 'win32' \ # via # click # uvicorn -cryptography==43.0.3 \ - --hash=sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362 \ - --hash=sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4 \ - --hash=sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa \ - --hash=sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83 \ - --hash=sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff \ - --hash=sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805 \ - --hash=sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6 \ - --hash=sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664 \ - --hash=sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08 \ - --hash=sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e \ - --hash=sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18 \ - --hash=sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f \ - --hash=sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73 \ - --hash=sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5 \ - --hash=sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984 \ - --hash=sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd \ - --hash=sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3 \ - --hash=sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e \ - --hash=sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405 \ - --hash=sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2 \ - --hash=sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c \ - --hash=sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995 \ - --hash=sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73 \ - --hash=sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16 \ - --hash=sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7 \ - --hash=sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd \ - --hash=sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7 +cryptography==44.0.0 \ + --hash=sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7 \ + --hash=sha256:37d76e6863da3774cd9db5b409a9ecfd2c71c981c38788d3fcfaf177f447b731 \ + --hash=sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b \ + --hash=sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc \ + --hash=sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543 \ + --hash=sha256:62901fb618f74d7d81bf408c8719e9ec14d863086efe4185afd07c352aee1d2c \ + --hash=sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591 \ + --hash=sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede \ + --hash=sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb \ + --hash=sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f \ + --hash=sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123 \ + --hash=sha256:8b3e6eae66cf54701ee7d9c83c30ac0a1e3fa17be486033000f2a73a12ab507c \ + --hash=sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c \ + --hash=sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285 \ + --hash=sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd \ + --hash=sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092 \ + --hash=sha256:be4ce505894d15d5c5037167ffb7f0ae90b7be6f2a98f9a5c3442395501c32fa \ + --hash=sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289 \ + --hash=sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02 \ + --hash=sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64 \ + --hash=sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053 \ + --hash=sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417 \ + --hash=sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e \ + --hash=sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e \ + --hash=sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7 \ + --hash=sha256:f5e7cb1e5e56ca0933b4873c0220a78b773b24d40d186b6738080b73d3d0a756 \ + --hash=sha256:f677e1268c4e23420c3acade68fac427fffcb8d19d7df95ed7ad17cdef8404f4 # via # gafaelfawr (pyproject.toml) # pyjwt @@ -471,9 +471,9 @@ cryptography==43.0.3 \ dacite==1.8.1 \ --hash=sha256:cc31ad6fdea1f49962ea42db9421772afe01ac5442380d9a99fcf3d188c61afe # via dataclasses-avroschema -dataclasses-avroschema==0.65.6 \ - --hash=sha256:96d09278e9d770229c2f6e6eb58656d0b59f460d6098f2761d1c04faf96f6a40 \ - --hash=sha256:a4527afb3d1fe83fa4b811a77e5ed200cad776c11635868edd68626e46814515 +dataclasses-avroschema==0.65.7 \ + --hash=sha256:62b874f020b57294f65e7aced4a634757502e1b410bdb1d6f8e0515eb3fc5c3e \ + --hash=sha256:e59a8a962e1956533a9083468a08dd3958553738e3f87f6bc516fe525901302f # via safir fast-depends==2.4.12 \ --hash=sha256:9393e6de827f7afa0141e54fa9553b737396aaf06bd0040e159d1f790487b16d \ @@ -880,13 +880,13 @@ jsonschema-specifications==2024.10.1 \ --hash=sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272 \ --hash=sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf # via jsonschema -kopf==1.37.3 \ - --hash=sha256:8d45ef8c4eff8fbccfa72da47df55208a65d5b5642ff22bff9b1ff8d9e6f1f15 \ - --hash=sha256:ed6338db46a7243e1e5ea86e978914ffa2b6e9cd3ba4daf374b4cedaeff3f523 +kopf==1.37.4 \ + --hash=sha256:0e0f9984eca5d50e4b5f1fd646bdbbd9f3cf164fab9ab86a437a5e69cde629d1 \ + --hash=sha256:a940f7af4b31e345bfd052b14be330dd891173a90a2179a63d566e6f278bed63 # via gafaelfawr (pyproject.toml) -kubernetes-asyncio==30.3.1 \ - --hash=sha256:53efb902e89149a9720e00b45f964b87ea7cb8ec4110110c574d028817da1764 \ - --hash=sha256:9c65f79aef0a0c36149c562cec036dd21466dc64dca2ebd36b02d8ae2954d897 +kubernetes-asyncio==31.1.1 \ + --hash=sha256:393bb60a2740d482651d474956296b341348c3e4f883b171740e5a4bf105a87b \ + --hash=sha256:d5e441674fde5dd8d0366cb6a204d7fbaef8d0dce7ca7a34c0791af0d13b6ff1 # via # gafaelfawr (pyproject.toml) # safir @@ -1296,9 +1296,9 @@ pydantic-core==2.27.1 \ # via # pydantic # safir -pydantic-settings==2.6.1 \ - --hash=sha256:7fb0637c786a558d3103436278a7c4f1cfd29ba8973238a50c5bb9a55387da87 \ - --hash=sha256:e0f92546d8a9923cb8941689abf85d6601a8c19a23e97a34b2964a2e3f813ca0 +pydantic-settings==2.7.0 \ + --hash=sha256:ac4bfd4a36831a48dbf8b2d9325425b549a0a6f18cea118436d728eb4f1c4d66 \ + --hash=sha256:e00c05d5fa6cbbb227c84bd7487c5c1065084119b750df7c8c1a554aed236eb5 # via # gafaelfawr (pyproject.toml) # safir @@ -1320,13 +1320,13 @@ python-dotenv==1.0.1 \ # via # pydantic-settings # uvicorn -python-json-logger==2.0.7 \ - --hash=sha256:23e7ec02d34237c5aa1e29a070193a4ea87583bb4e7f8fd06d3de8264c4b2e1c \ - --hash=sha256:f380b826a991ebbe3de4d897aeec42760035ac760345e57b812938dc8b35e2bd +python-json-logger==3.2.1 \ + --hash=sha256:8eb0554ea17cb75b05d2848bc14fb02fbdbd9d6972120781b974380bfa162008 \ + --hash=sha256:cdc17047eb5374bd311e748b42f99d71223f3b0e186f4206cc5d52aefe85b090 # via kopf -python-multipart==0.0.19 \ - --hash=sha256:905502ef39050557b7a6af411f454bc19526529ca46ae6831508438890ce12cc \ - --hash=sha256:f8d5b0b9c618575bf9df01c684ded1d94a338839bdd8223838afacfb4bb2082d +python-multipart==0.0.20 \ + --hash=sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104 \ + --hash=sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13 # via gafaelfawr (pyproject.toml) python-schema-registry-client==2.6.0 \ --hash=sha256:a0688a9cd6e2a616a79fb46a6615c531cd5f9e2a5145f5c95932f792417731cb \ @@ -1516,13 +1516,13 @@ rsa==4.9 \ --hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \ --hash=sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21 # via google-auth -safir==8.0.0 \ - --hash=sha256:2a08fda7117060f1049ca2082080456442baf18120194c6670a4d228933a338e \ - --hash=sha256:f3a19fb4a28ce956ea50297281c6a0e468c786b047ad3ac577162528a98f03d9 +safir==9.1.0 \ + --hash=sha256:38718de0d2e5f9623eddc511700a15fb56fee88da7bba0e1210dc831276aa9aa \ + --hash=sha256:630b2e59ae87edab25fb2c3d5ccd6ca156c0d525eb543624532bbf4fd3c85536 # via gafaelfawr (pyproject.toml) -safir-logging==6.5.1 \ - --hash=sha256:b056306de26627e29bd6a6d04b1144456a1319ec0e15a67ebbc12b43362a27cd \ - --hash=sha256:ff591f0247fda10842835e714a6dbf601a894432d33d6d98e20fe035a5ad952c +safir-logging==9.0.1 \ + --hash=sha256:775ab8b2c1a62fe5779f8d4504797df7affb5dbebc70fcad00307cda419d637e \ + --hash=sha256:e5dfdfbdafb0a60dd2b8cdd63f8171cb703830cd5d433d60c27028cc9a4044f1 # via safir sentry-sdk==2.19.2 \ --hash=sha256:467df6e126ba242d39952375dd816fbee0f217d119bf454a8ce74cf1e7909e8d \ @@ -1641,9 +1641,9 @@ urllib3==2.2.3 \ # kubernetes-asyncio # requests # sentry-sdk -uvicorn==0.32.1 \ - --hash=sha256:82ad92fd58da0d12af7482ecdb5f2470a04c9c9a53ced65b9bbb4a205377602e \ - --hash=sha256:ee9519c246a72b1c084cea8d3b44ed6026e78a4a309cbedae9c37e4cb9fbb175 +uvicorn==0.34.0 \ + --hash=sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4 \ + --hash=sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9 # via gafaelfawr (pyproject.toml) uvloop==0.21.0 ; platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32' \ --hash=sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0 \ diff --git a/requirements/tox.txt b/requirements/tox.txt index 2b9d21a1..4abf8403 100644 --- a/requirements/tox.txt +++ b/requirements/tox.txt @@ -6,9 +6,9 @@ cachetools==5.5.0 \ # via # -c requirements/main.txt # tox -certifi==2024.8.30 \ - --hash=sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 \ - --hash=sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9 +certifi==2024.12.14 \ + --hash=sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56 \ + --hash=sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db # via # -c requirements/dev.txt # -c requirements/main.txt @@ -233,24 +233,24 @@ urllib3==2.2.3 \ # -c requirements/main.txt # docker # requests -uv==0.5.8 \ - --hash=sha256:0f2bcdd00a49ad1669e217a2787448cac1653c9968d74bfa3732f3c25ca26f69 \ - --hash=sha256:2b3076c79746d4f83257c9dea5ba0833b0711aeff8e6695670eadd140a0cf67f \ - --hash=sha256:2ee40bc9c08fea0e71092838c0fc36df83f741807d8be9acf2fd4c4757b3171e \ - --hash=sha256:365eb6bbb551c5623a73b1ed530f4e69083016f70f0cf5ca1a30ec66413bcda2 \ - --hash=sha256:4a3325af8ed1effa7076967472c063b0000d609fd6f561c7751e43bab30297f1 \ - --hash=sha256:56715389d240ac989af2188cd3bfc2b603d31b42330e915dacfe113b34d8e65b \ - --hash=sha256:5989bbbbca072edc1875036c76aed74ec3dfc4741de7d1f060e181717efea6ac \ - --hash=sha256:8058ab06d2f69355694f6e9a36edc45164474c516b4e2895bd67f8232d9022ed \ - --hash=sha256:84f26ce1736d075d1df34f7c3f6b0b728cecd9a4da3e5160d5d887587830e7ce \ - --hash=sha256:8a8cbe1ffa0ef5c2f1c90622e07211a8f93f48daa2be1bd4592bb8cda52b0285 \ - --hash=sha256:a7956787658fb9253fba49741886409402a48039bee64b1697397d27284919af \ - --hash=sha256:aa03c338e19456d3a6544a94293bd2905837ae22720cc161c83ea0fd13c3b09f \ - --hash=sha256:c56022edc0f61febbdef89e6f699a0e991932c493b7293635b4814e102d040d2 \ - --hash=sha256:c91d0a2b8218af2aa0385b867da8c13a620db22077686793c7231f012cb40619 \ - --hash=sha256:defd5da3685f43f74698634ffc197aaf9b836b8ba0de0e57b34d7bc74d856fa9 \ - --hash=sha256:e146062e4cc39db334cbde38d56d2c6301dd9cf6739ce07ce5a4d71b4cbc2d00 \ - --hash=sha256:f8ade0430b6618ae0e21e52f61f6f3943dd6f3184ef6dc4491087b27940427f9 +uv==0.5.10 \ + --hash=sha256:064e977957e61aaaf7215bbd8f8566bcb22d7662c8adc929d039010fdb686436 \ + --hash=sha256:06eb14988a75cc178241747a9437d23faad7d62e2d9b955db7e8a8098853341a \ + --hash=sha256:253a02e03bf83bc0ec4e17242f54a4af2fef6191fcfb392b2613defd2b2a2f89 \ + --hash=sha256:27f27eba58b9a71c3a7905ca966c69adf5a4a1df1dd14ef4d064c40cbaabc49e \ + --hash=sha256:326603d44454a8856a5660bb406e99194f3c8d2cc4504c97c99871da59575022 \ + --hash=sha256:4e0b91598e67d8c1228b47894a61fffb9d82caf8f1080bb9f21df49530118db6 \ + --hash=sha256:502d9d10f5f139c850b1f6085a0c5719d49dd39d767504ce7c4245b47531f156 \ + --hash=sha256:5890ca6703c371cecc88c2a7bf32fc47187a865fc577df0d40d390fcbdec76f0 \ + --hash=sha256:68a6b992b7ebae9f3fa2f395348c95e6f05745246b067a26e7597a6730fcb690 \ + --hash=sha256:7337ed40bae6f37d9335bf7f83bb43d08b6c141212b1ca3b15a9194c4d438ffe \ + --hash=sha256:87dd4473ebf585fcd78a818bf8735ab39a157bef4f712e8b22e753b7344f6290 \ + --hash=sha256:8bc47bd623b1f8fa883b7afbf480286b946512d9ac7bf23105e7d63ef702ea7b \ + --hash=sha256:936759d8de8f78969756ee2b1558b4e9bd4b059922d0840cdd162a190c95ac50 \ + --hash=sha256:adc0dad56118127b3a1cc0126149a9b8c643fd4e4c5fa37be6af4bd84d33d30c \ + --hash=sha256:b61812ee4765f07db02ff616d4aac9c514857c0648459242a286243fe92d6223 \ + --hash=sha256:d0d0e75a4337076f43936b11d6cc4cb11e261948c719adb8e208b78454a122a0 \ + --hash=sha256:fa8607cc07cc9e666e531a9533b02d45bbb376ae314721434643c328298709b4 # via tox-uv virtualenv==20.28.0 \ --hash=sha256:23eae1b4516ecd610481eda647f3a7c09aea295055337331bb4e6892ecce47b0 \ diff --git a/src/gafaelfawr/models/history.py b/src/gafaelfawr/models/history.py index f9f93ebc..c225b1a6 100644 --- a/src/gafaelfawr/models/history.py +++ b/src/gafaelfawr/models/history.py @@ -4,10 +4,10 @@ from dataclasses import dataclass from datetime import datetime # noqa: F401: needed for docs -from typing import Any, Generic, Self, TypeVar +from typing import Any, Self, TypeVar from pydantic import BaseModel, Field -from safir.database import DatetimeIdCursor, PaginatedList, PaginationCursor +from safir.database import DatetimeIdCursor, PaginationCursor from safir.datetime import current_datetime from sqlalchemy.orm import InstrumentedAttribute @@ -27,7 +27,6 @@ __all__ = [ "AdminHistoryEntry", "E", - "PaginatedHistory", "TokenChangeHistoryCursor", "TokenChangeHistoryEntry", "TokenChangeHistoryRecord", @@ -256,14 +255,6 @@ class TokenChangeHistoryRecord(TokenChangeHistoryEntry): ) -@dataclass -class PaginatedHistory(PaginatedList, Generic[E]): - """A paginated list of history entries, including total count.""" - - count: int | None = None - """Total count of entries.""" - - @dataclass class TokenChangeHistoryCursor(DatetimeIdCursor[TokenChangeHistoryRecord]): """Pagination cursor for token history entries.""" diff --git a/src/gafaelfawr/services/token.py b/src/gafaelfawr/services/token.py index 37e19a8f..06b3a7dd 100644 --- a/src/gafaelfawr/services/token.py +++ b/src/gafaelfawr/services/token.py @@ -7,6 +7,7 @@ from collections.abc import Iterable from datetime import datetime, timedelta +from safir.database import CountedPaginatedList from safir.datetime import current_datetime, format_datetime_for_logging from sqlalchemy.ext.asyncio import async_scoped_session from structlog.stdlib import BoundLogger @@ -30,7 +31,6 @@ ) from ..models.enums import TokenChange, TokenType from ..models.history import ( - PaginatedHistory, TokenChangeHistoryCursor, TokenChangeHistoryEntry, TokenChangeHistoryRecord, @@ -668,7 +668,9 @@ async def get_change_history( token: str | None = None, token_type: TokenType | None = None, ip_or_cidr: str | None = None, - ) -> PaginatedHistory[TokenChangeHistoryRecord]: + ) -> CountedPaginatedList[ + TokenChangeHistoryRecord, TokenChangeHistoryCursor + ]: """Retrieve the change history of a token. Parameters @@ -701,7 +703,7 @@ async def get_change_history( Returns ------- - PaginatedHistory + CountedPaginatedList of TokenChangeHistoryEntry A list of changes matching the search criteria. Raises diff --git a/src/gafaelfawr/storage/history.py b/src/gafaelfawr/storage/history.py index afce140f..99e31a0f 100644 --- a/src/gafaelfawr/storage/history.py +++ b/src/gafaelfawr/storage/history.py @@ -4,7 +4,11 @@ from datetime import datetime -from safir.database import PaginatedQueryRunner, datetime_to_db +from safir.database import ( + CountedPaginatedList, + CountedPaginatedQueryRunner, + datetime_to_db, +) from sqlalchemy import delete, or_, select from sqlalchemy.ext.asyncio import async_scoped_session from sqlalchemy.sql import Select, text @@ -12,7 +16,6 @@ from ..models.enums import TokenType from ..models.history import ( AdminHistoryEntry, - PaginatedHistory, TokenChangeHistoryCursor, TokenChangeHistoryEntry, TokenChangeHistoryRecord, @@ -58,7 +61,7 @@ class TokenChangeHistoryStore: def __init__(self, session: async_scoped_session) -> None: self._session = session - self._paginated_runner = PaginatedQueryRunner( + self._paginated_runner = CountedPaginatedQueryRunner( TokenChangeHistoryRecord, TokenChangeHistoryCursor ) @@ -110,7 +113,9 @@ async def list( token: str | None = None, token_type: TokenType | None = None, ip_or_cidr: str | None = None, - ) -> PaginatedHistory[TokenChangeHistoryRecord]: + ) -> CountedPaginatedList[ + TokenChangeHistoryRecord, TokenChangeHistoryCursor + ]: """Return all changes to a specific token. Parameters @@ -142,7 +147,7 @@ async def list( Returns ------- - PaginatedHistory of TokenChangeHistoryEntry + CountedPaginatedList of TokenChangeHistoryEntry List of change history entries, which may be empty. """ stmt = select(TokenChangeHistory) @@ -171,16 +176,9 @@ async def list( stmt = self._apply_ip_or_cidr_filter(stmt, ip_or_cidr) # Perform the paginated query. - result = await self._paginated_runner.query_object( + return await self._paginated_runner.query_object( self._session, stmt, cursor=cursor, limit=limit ) - count = await self._paginated_runner.query_count(self._session, stmt) - return PaginatedHistory[TokenChangeHistoryRecord]( - entries=result.entries, - next_cursor=result.next_cursor, - prev_cursor=result.prev_cursor, - count=count, - ) def _apply_ip_or_cidr_filter( self, stmt: Select, ip_or_cidr: str diff --git a/tests/handlers/api_history_test.py b/tests/handlers/api_history_test.py index ae3591c4..56e46b44 100644 --- a/tests/handlers/api_history_test.py +++ b/tests/handlers/api_history_test.py @@ -3,7 +3,7 @@ from __future__ import annotations import json -from collections.abc import Callable +from collections.abc import Callable, Sequence from datetime import timedelta from ipaddress import ip_address, ip_network from typing import Any @@ -18,7 +18,10 @@ from gafaelfawr.factory import Factory from gafaelfawr.models.enums import TokenType -from gafaelfawr.models.history import TokenChangeHistoryEntry +from gafaelfawr.models.history import ( + TokenChangeHistoryEntry, + TokenChangeHistoryRecord, +) from gafaelfawr.models.token import AdminTokenRequest, TokenData, TokenUserInfo from gafaelfawr.schema import TokenChangeHistory @@ -27,7 +30,7 @@ from ..support.tokens import create_session_token -async def build_history(factory: Factory) -> list[TokenChangeHistoryEntry]: +async def build_history(factory: Factory) -> list[TokenChangeHistoryRecord]: """Perform a bunch of token manipulations and return the history entries. Assume that all token manipulations generate the correct history entries, @@ -166,7 +169,7 @@ def entry_to_dict(entry: TokenChangeHistoryEntry) -> dict[str, Any]: async def check_history_request( client: AsyncClient, query: dict[str, str | int], - history: list[TokenChangeHistoryEntry], + history: Sequence[TokenChangeHistoryEntry], selector: Callable[[TokenChangeHistoryEntry], bool], *, username: str | None = None, @@ -190,7 +193,7 @@ async def check_history_request( async def check_pagination( client: AsyncClient, - history: list[TokenChangeHistoryEntry], + history: Sequence[TokenChangeHistoryEntry], *, username: str | None = None, ) -> None: