From ebd50def4d9f2c7f9f403b25bb34c3a81c2d0ac9 Mon Sep 17 00:00:00 2001 From: TheByronHimes Date: Fri, 10 May 2024 10:10:39 +0000 Subject: [PATCH 01/11] Use User model from ghga-event-schemas --- .pre-commit-config.yaml | 2 +- lock/requirements-dev.txt | 418 ++++++++++++++-------------- lock/requirements.txt | 346 +++++++++++------------ src/nos/core/models.py | 58 ---- src/nos/core/orchestrator.py | 21 +- src/nos/ports/outbound/dao.py | 5 +- src/nos/translators/outbound/dao.py | 4 +- tests/conftest.py | 11 +- 8 files changed, 407 insertions(+), 458 deletions(-) delete mode 100644 src/nos/core/models.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f631e9e..b12f933 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -45,7 +45,7 @@ repos: - id: no-commit-to-branch args: [--branch, dev, --branch, int, --branch, main] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.4.3 + rev: v0.4.4 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/lock/requirements-dev.txt b/lock/requirements-dev.txt index 7ff211d..414f37b 100644 --- a/lock/requirements-dev.txt +++ b/lock/requirements-dev.txt @@ -52,13 +52,13 @@ attrs==23.2.0 \ # via # jsonschema # referencing -boto3==1.34.98 \ - --hash=sha256:030e43b8efe22b4cf10b9f3ef9e30cd4cf9ef9784b26efe9a4583339f2b2bcec \ - --hash=sha256:28c10956033fa79e64529f48c3b62db86d5e4b77024a7343764b6bde6b553543 +boto3==1.34.102 \ + --hash=sha256:1c1fb2884f85c0ec6b62e6e7ed5a2a6635e1188f3ab5d2b700f7db1cf8464484 \ + --hash=sha256:65e4b9fb9ceefe19976e8822ac0cd68d28946d4697e538741d2bbdb5b45ae42f # via hexkit -botocore==1.34.98 \ - --hash=sha256:4cee65df02f4b0be08ad1401965cc89efafebc50ef0727d2d17083c7f1ed2831 \ - --hash=sha256:631c0031d8ce922b5752ab395ead896a0281b0dc74745a754d0351a27c5d83de +botocore==1.34.102 \ + --hash=sha256:79ac7fc2729294395c70eff9c23510f00785ad2acd78d6130cb4379e9f27da86 \ + --hash=sha256:e2f8a9f4bac6f7b568e6e981ac2a2500bc992329c85dde8546f0cae8605dd009 # via # boto3 # hexkit @@ -252,9 +252,9 @@ filelock==3.14.0 \ --hash=sha256:43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f \ --hash=sha256:6ea72da3be9b8c82afd3edcf99f2fffbb5076335a5ae4d03248bb5b6c3eae78a # via virtualenv -ghga-event-schemas==3.2.0 \ - --hash=sha256:66ccf599967722163b06a98a665a9393de012e4db92059e8fd5a312785f21071 \ - --hash=sha256:d6f9ad7a9132f5aaff2003e3db07d2a9a223b27270d0afb256d698a639fd6f2c +ghga-event-schemas==3.3.0 \ + --hash=sha256:852a04ebadf311e1e04d9b95a6286716a2e80f1e6c135795c3f207fc58011290 \ + --hash=sha256:d98b82d3fb92698a7ee0505740ed2469d62c4577c651b5f98d561720a27db8cf ghga-service-commons==3.1.3 \ --hash=sha256:4f7c2b56ae24594dd60cb28719f040351056c06d59b2d8f74f46eb9005b770f2 \ --hash=sha256:8b2e255506ac11cfafba3a18f58c0471a0b1b0c89893f6489a8a2f9af4dd6c0b @@ -264,9 +264,9 @@ h11==0.14.0 \ # via # httpcore # uvicorn -hexkit==3.0.0 \ - --hash=sha256:300d8da001cfb79ba818ec36378f95b5d81b0481099b72cc47ad2f47be93131b \ - --hash=sha256:b9810a834daa910a9659c930a16f8fbb319ea0a15a1b2303ba8ea6dd617d753c +hexkit==3.0.1 \ + --hash=sha256:0d854aa8c0f5539338a50ed363557d4bbf720ca01afde9f07512cb76a7be398d \ + --hash=sha256:61347f4564eb557bb4dea176a0085dc85391a4a5eb32681433b7afc1487df3aa # via ghga-service-commons httpcore==1.0.5 \ --hash=sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61 \ @@ -516,67 +516,67 @@ pygments==2.18.0 \ --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a # via rich -pymongo==4.7.1 \ - --hash=sha256:11f74dafde63ad2dc30c01f40b4c69d9af157f8ba5224b0c9d4de7158537266f \ - --hash=sha256:13fc201e073644acd77860d9e91ccfc27addf510563e07381cadc9a55ac3a894 \ - --hash=sha256:1bd1eef70c1eda838b26397ef75c9580d7a97fd94b6324971d7f3d2ad3552e9a \ - --hash=sha256:24c8f1dd545360ec1b79007a3ba6573af565df6fde49f6dfc53813f3f475a751 \ - --hash=sha256:253ed8fd6e7f4b2a1caa89e6b287b9e04f42613319ee1e1240c2db2afe1637e7 \ - --hash=sha256:263c169302df636f9086b584994a51d0adfc8738fe27d7b8e2aacf46fd68b6cb \ - --hash=sha256:297cdc87c4b4168782b571c8643540e9b0ad1d09266b43d2f5954f8632280835 \ - --hash=sha256:2ccc8dd4fe9aac18dde27c33a53271c6c90159b74c43fbdab1d33d5efc36c2f5 \ - --hash=sha256:30a9d891631d7e847b24f551b1d89ff2033539e7cd8e9af29714b4d0db7abb06 \ - --hash=sha256:31ed8ba3da0366346264604b3a443f5a4232cab5ed45f520bead6184cf0851a1 \ - --hash=sha256:337d99f88d32a5f8056d6d2bc365ccf09d09583f3942882c50cf11b459e8fbc0 \ - --hash=sha256:3ef32a7cfe748c0c72fdad9e51459de5e0c6b16c5288b39f863abfff23503847 \ - --hash=sha256:455f9d603ed0990a787773d5718e871300bddf585ce543baf129c9f5ca3adb02 \ - --hash=sha256:45ac46f0d6bdc2baac34ced60aae27b2083170d77397330eff0ac5689ea29d38 \ - --hash=sha256:4c7e05454cdc5aa4702e03cad0df4205daccd6fd631bbbf0a85bbe598129a6cc \ - --hash=sha256:4d227555be35078b53f506f6b58bd0b0e8fd4513e89e6f29e83a97efab439250 \ - --hash=sha256:4dd998e9f0f7694032c1648c7f57fccaa78903df6329b8f8ae20cfa7c4ceca34 \ - --hash=sha256:5119c66af8c4197c8757b4b7d98c443e5b127c224ac92fb657dbe2b512ae2713 \ - --hash=sha256:57b5b485ef89270ed2e603814f43f0fdd9b8ba5d4039124d90878cdc2327000c \ - --hash=sha256:58989bcb94233233a71645236b972835d4f87a6bb1b7e818d38a7e6e6d4630de \ - --hash=sha256:5a58b6cd7c423ba49db10d8445756062c931ad2246ba0da1e705bf22962fd9e9 \ - --hash=sha256:5ae1aeeb405c29885266666dc7115792d647ed68cfdb6ed02e2e211d12f2e1c8 \ - --hash=sha256:5bc87db2e9563295c4e45602ab978a2fcbaba3ab89e745503b24f895cddeb755 \ - --hash=sha256:5ff6d56ca1f0cd3687a13ce90a32a8efb3cc3a53728e5ac160c4c30d10385a72 \ - --hash=sha256:615c7573d7a9c4837332a673fdc5a5f214b474dd52d846bcf4cc3d011550bee1 \ - --hash=sha256:64b69b9cd8a6d23881a80490d575e92918f9afca43096a7d6c1013d6b3e5c75c \ - --hash=sha256:65c45682d5ed8c6618bde22cd6716b47a197f4ef800a025213b28d13a59e5fca \ - --hash=sha256:67cbee427c263a4483e3249fef480788ccc16edb1a4fc330c4c6cb0cb9db94a8 \ - --hash=sha256:7247c1dc7d8eed4e24eb1dd92c4c58ebf1e5159500015652552acfdebdeed256 \ - --hash=sha256:73bf96ece4999b0bbab7169cb2b9c60918b434487009e48be4bd47eeb2aa7b14 \ - --hash=sha256:7b10603ba64af08f5af7eb9a69d6b24e3c69d91fdd48c54b95e284686c1c582d \ - --hash=sha256:811a07bba9d35f1e34159ede632ac71dbc429b372a20004e32d6578af872db1a \ - --hash=sha256:811c41c6227b7548afcb53e1b996c25262d837b5e5f519e2ddc2c7e59d8728a5 \ - --hash=sha256:85b8dd3756b73993b1e3ab6b1cba826b9e4987a094a5d5b6d37313776458cd94 \ - --hash=sha256:887d043ecc0c7d5591925bbc7abb67caf21c94d6e6e5d442cb49eb5d9d8ee76b \ - --hash=sha256:8cee62188127a126f59ea45d3981868a5e35343be4ef4ad8712eaf42be37a00b \ - --hash=sha256:9e0a30a022ac8a9164ee5a4b761e13dbb3d10a21845f7258011e3415151fb645 \ - --hash=sha256:9e99dac3c7c2cb498937cc1767361851099da38861e921113318c87d71e3d127 \ - --hash=sha256:a46c08ef0b273c415b1e8933f6739596be264ae700a4927f84e0b84e70fdf0eb \ - --hash=sha256:a848249d5b4763497add62f7dd7bd0ce1538129bf42f4cb132a76d24c61bf98d \ - --hash=sha256:aa354933a158e57494c98b592f46d5d24d1b109e6ba05a05179cde719d9f7fd3 \ - --hash=sha256:ad360630c221aee7c0841a51851496a3ca6fdea87007098a982c1aa26e34083a \ - --hash=sha256:b897b60b2d55c26f3efea0effc11b655db68125c3731274bc3953375e9ccab73 \ - --hash=sha256:b8b95e2163b73d03a913efa89b0f7c5012be82efd4e9dbce8aa62010a75a277c \ - --hash=sha256:bfd5c7e5bb87171a5296fa32205adb50b27704a612036ec4395c3cd316fc0e91 \ - --hash=sha256:c808098f2cdb87d4035144e536ba5fa7709d0420c17b68e6ace5da18c38ded5f \ - --hash=sha256:d1829a7db720ff586aaf59c806e89e0a388548063aa844d21a570a231ad8ca87 \ - --hash=sha256:d50969de00d3522b2c394f7e59b843871e2be4b525af92066da7f3bd02799fdc \ - --hash=sha256:d63f38454a2e23c117d3ceab3b661568f2418536825787256ad24e5baaedfd27 \ - --hash=sha256:d804eaf19a65211cc2c8c5db75be685c3f31c64cdab639794f66f13f8e258ba6 \ - --hash=sha256:daf35ab13b86aba7cc8c4b019882f1fa8d287a26f586ef5eaf60a5233d3eaa52 \ - --hash=sha256:dbc32217c81d87750401fa1c2bc9450e854b23e6e30243c82d3514b8e58f39e3 \ - --hash=sha256:e175d74c52b6c8414a4b4504a2dd42b0202d101b2eb9508a34c137357683864e \ - --hash=sha256:e4a63ba6813a2168ebd35ea5369f6c33f7787525986cd77668b7956acc3d2a38 \ - --hash=sha256:e935712b17e7a42831022353bac91a346a792658a54e12bec907ec11695cc899 \ - --hash=sha256:ec94d29103317aa920dae59ed385de9604cb0ef840b5b7137b5eaa7a2042580a \ - --hash=sha256:ed6b3a0740efe98bb03ccf054578e9788ebcd06d021d548b8217ab2c82e45975 \ - --hash=sha256:f2a720e787c9b9b912db5bb4c3e7123ccff1352d6c3ac0cb2c7ee392cdc95c00 \ - --hash=sha256:f8822614975038e0cece47d12e7634a79c2ee590a0ae78ae64c37b9c6610a14c \ - --hash=sha256:fb1a884b1c6aeac5ffeb8ccb696fbc242a7ae1bba36f2328c01f76fab7221b94 +pymongo==4.7.2 \ + --hash=sha256:02efd1bb3397e24ef2af45923888b41a378ce00cb3a4259c5f4fc3c70497a22f \ + --hash=sha256:0d833651f1ba938bb7501f13e326b96cfbb7d98867b2d545ca6d69c7664903e0 \ + --hash=sha256:12c466e02133b7f8f4ff1045c6b5916215c5f7923bc83fd6e28e290cba18f9f6 \ + --hash=sha256:12d1fef77d25640cb78893d07ff7d2fac4c4461d8eec45bd3b9ad491a1115d6e \ + --hash=sha256:194065c9d445017b3c82fb85f89aa2055464a080bde604010dc8eb932a6b3c95 \ + --hash=sha256:1c78f156edc59b905c80c9003e022e1a764c54fd40ac4fea05b0764f829790e2 \ + --hash=sha256:1e37faf298a37ffb3e0809e77fbbb0a32b6a2d18a83c59cfc2a7b794ea1136b0 \ + --hash=sha256:25eeb2c18ede63891cbd617943dd9e6b9cbccc54f276e0b2e693a0cc40f243c5 \ + --hash=sha256:268d8578c0500012140c5460755ea405cbfe541ef47c81efa9d6744f0f99aeca \ + --hash=sha256:2cb77d09bd012cb4b30636e7e38d00b5f9be5eb521c364bde66490c45ee6c4b4 \ + --hash=sha256:347c49cf7f0ba49ea87c1a5a1984187ecc5516b7c753f31938bf7b37462824fd \ + --hash=sha256:35b3f0c7d49724859d4df5f0445818d525824a6cd55074c42573d9b50764df67 \ + --hash=sha256:37e9ea81fa59ee9274457ed7d59b6c27f6f2a5fe8e26f184ecf58ea52a019cb8 \ + --hash=sha256:47a1a4832ef2f4346dcd1a10a36ade7367ad6905929ddb476459abb4fd1b98cb \ + --hash=sha256:4bdb5ffe1cd3728c9479671a067ef44dacafc3743741d4dc700c377c4231356f \ + --hash=sha256:4ffd1519edbe311df73c74ec338de7d294af535b2748191c866ea3a7c484cd15 \ + --hash=sha256:5239776633f7578b81207e5646245415a5a95f6ae5ef5dff8e7c2357e6264bfc \ + --hash=sha256:5239ef7e749f1326ea7564428bf861d5250aa39d7f26d612741b1b1273227062 \ + --hash=sha256:56bf8b706946952acdea0fe478f8e44f1ed101c4b87f046859e6c3abe6c0a9f4 \ + --hash=sha256:65b4c00dedbd333698b83cd2095a639a6f0d7c4e2a617988f6c65fb46711f028 \ + --hash=sha256:6a87eef394039765679f75c6a47455a4030870341cb76eafc349c5944408c882 \ + --hash=sha256:727ad07952c155cd20045f2ce91143c7dc4fb01a5b4e8012905a89a7da554b0c \ + --hash=sha256:730778b6f0964b164c187289f906bbc84cb0524df285b7a85aa355bbec43eb21 \ + --hash=sha256:743552033c63f0afdb56b9189ab04b5c1dbffd7310cf7156ab98eebcecf24621 \ + --hash=sha256:7e9d9d2c0aae73aa4369bd373ac2ac59f02c46d4e56c4b6d6e250cfe85f76802 \ + --hash=sha256:82102e353be13f1a6769660dd88115b1da382447672ba1c2662a0fbe3df1d861 \ + --hash=sha256:827611beb6c483260d520cfa6a49662d980dfa5368a04296f65fa39e78fccea7 \ + --hash=sha256:84bc00200c3cbb6c98a2bb964c9e8284b641e4a33cf10c802390552575ee21de \ + --hash=sha256:87032f818bf5052ab742812c715eff896621385c43f8f97cdd37d15b5d394e95 \ + --hash=sha256:87832d6076c2c82f42870157414fd876facbb6554d2faf271ffe7f8f30ce7bed \ + --hash=sha256:87bb453ac3eb44db95cb6d5a616fbc906c1c00661eec7f55696253a6245beb8a \ + --hash=sha256:9024e1661c6e40acf468177bf90ce924d1bc681d2b244adda3ed7b2f4c4d17d7 \ + --hash=sha256:9349f0bb17a31371d4cacb64b306e4ca90413a3ad1fffe73ac7cd495570d94b5 \ + --hash=sha256:9385654f01a90f73827af4db90c290a1519f7d9102ba43286e187b373e9a78e9 \ + --hash=sha256:9a8bd37f5dabc86efceb8d8cbff5969256523d42d08088f098753dba15f3b37a \ + --hash=sha256:9d892fb91e81cccb83f507cdb2ea0aa026ec3ced7f12a1d60f6a5bf0f20f9c1f \ + --hash=sha256:a754e366c404d19ff3f077ddeed64be31e0bb515e04f502bf11987f1baa55a16 \ + --hash=sha256:b48a5650ee5320d59f6d570bd99a8d5c58ac6f297a4e9090535f6561469ac32e \ + --hash=sha256:bcf337d1b252405779d9c79978d6ca15eab3cdaa2f44c100a79221bddad97c8a \ + --hash=sha256:c44efab10d9a3db920530f7bcb26af8f408b7273d2f0214081d3891979726328 \ + --hash=sha256:c72d16fede22efe7cdd1f422e8da15760e9498024040429362886f946c10fe95 \ + --hash=sha256:cb6e00a79dff22c9a72212ad82021b54bdb3b85f38a85f4fc466bde581d7d17a \ + --hash=sha256:ce1a374ea0e49808e0380ffc64284c0ce0f12bd21042b4bef1af3eb7bdf49054 \ + --hash=sha256:cecd2df037249d1c74f0af86fb5b766104a5012becac6ff63d85d1de53ba8b98 \ + --hash=sha256:cf17ea9cea14d59b0527403dd7106362917ced7c4ec936c4ba22bd36c912c8e0 \ + --hash=sha256:cf28430ec1924af1bffed37b69a812339084697fd3f3e781074a0148e6475803 \ + --hash=sha256:d1bcd58669e56c08f1e72c5758868b5df169fe267501c949ee83c418e9df9155 \ + --hash=sha256:d275596f840018858757561840767b39272ac96436fcb54f5cac6d245393fd97 \ + --hash=sha256:d2dcf608d35644e8d276d61bf40a93339d8d66a0e5f3e3f75b2c155a421a1b71 \ + --hash=sha256:d4d59776f435564159196d971aa89422ead878174aff8fe18e06d9a0bc6d648c \ + --hash=sha256:d9b6cbc037108ff1a0a867e7670d8513c37f9bcd9ee3d2464411bfabf70ca002 \ + --hash=sha256:db4380d1e69fdad1044a4b8f3bb105200542c49a0dde93452d938ff9db1d6d29 \ + --hash=sha256:e004527ea42a6b99a8b8d5b42b42762c3bdf80f88fbdb5c3a9d47f3808495b86 \ + --hash=sha256:e6eab12c6385526d386543d6823b07187fefba028f0da216506e00f0e1855119 \ + --hash=sha256:eb0642e5f0dd7e86bb358749cc278e70b911e617f519989d346f742dc9520dfb \ + --hash=sha256:f91073049c43d14e66696970dd708d319b86ee57ef9af359294eee072abaac79 \ + --hash=sha256:fadc6e8db7707c861ebe25b13ad6aca19ea4d2c56bf04a26691f46c23dadf6e4 \ + --hash=sha256:fc5af24fcf5fc6f7f40d65446400d45dd12bea933d0299dc9e90c5b22197f1e9 \ + --hash=sha256:fcaf8c911cb29316a02356f89dbc0e0dfcc6a712ace217b6b543805690d2aefd \ + --hash=sha256:ffd4d7cb2e6c6e100e2b39606d38a9ffc934e18593dc9bb326196afc7d93ce3d # via motor pytest==8.2.0 \ --hash=sha256:1733f0620f6cda4095bbf0d9ff8022486e91892245bb9e7d5542c018f612f233 \ @@ -675,127 +675,127 @@ rich==13.7.1 \ --hash=sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222 \ --hash=sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432 # via typer -rpds-py==0.18.0 \ - --hash=sha256:01e36a39af54a30f28b73096dd39b6802eddd04c90dbe161c1b8dbe22353189f \ - --hash=sha256:044a3e61a7c2dafacae99d1e722cc2d4c05280790ec5a05031b3876809d89a5c \ - --hash=sha256:08231ac30a842bd04daabc4d71fddd7e6d26189406d5a69535638e4dcb88fe76 \ - --hash=sha256:08f9ad53c3f31dfb4baa00da22f1e862900f45908383c062c27628754af2e88e \ - --hash=sha256:0ab39c1ba9023914297dd88ec3b3b3c3f33671baeb6acf82ad7ce883f6e8e157 \ - --hash=sha256:0af039631b6de0397ab2ba16eaf2872e9f8fca391b44d3d8cac317860a700a3f \ - --hash=sha256:0b8612cd233543a3781bc659c731b9d607de65890085098986dfd573fc2befe5 \ - --hash=sha256:11a8c85ef4a07a7638180bf04fe189d12757c696eb41f310d2426895356dcf05 \ - --hash=sha256:1374f4129f9bcca53a1bba0bb86bf78325a0374577cf7e9e4cd046b1e6f20e24 \ - --hash=sha256:1d4acf42190d449d5e89654d5c1ed3a4f17925eec71f05e2a41414689cda02d1 \ - --hash=sha256:1d9a5be316c15ffb2b3c405c4ff14448c36b4435be062a7f578ccd8b01f0c4d8 \ - --hash=sha256:1df3659d26f539ac74fb3b0c481cdf9d725386e3552c6fa2974f4d33d78e544b \ - --hash=sha256:22806714311a69fd0af9b35b7be97c18a0fc2826e6827dbb3a8c94eac6cf7eeb \ - --hash=sha256:2644e47de560eb7bd55c20fc59f6daa04682655c58d08185a9b95c1970fa1e07 \ - --hash=sha256:2e6d75ab12b0bbab7215e5d40f1e5b738aa539598db27ef83b2ec46747df90e1 \ - --hash=sha256:30f43887bbae0d49113cbaab729a112251a940e9b274536613097ab8b4899cf6 \ - --hash=sha256:34b18ba135c687f4dac449aa5157d36e2cbb7c03cbea4ddbd88604e076aa836e \ - --hash=sha256:36b3ee798c58ace201289024b52788161e1ea133e4ac93fba7d49da5fec0ef9e \ - --hash=sha256:39514da80f971362f9267c600b6d459bfbbc549cffc2cef8e47474fddc9b45b1 \ - --hash=sha256:39f5441553f1c2aed4de4377178ad8ff8f9d733723d6c66d983d75341de265ab \ - --hash=sha256:3a96e0c6a41dcdba3a0a581bbf6c44bb863f27c541547fb4b9711fd8cf0ffad4 \ - --hash=sha256:3f26b5bd1079acdb0c7a5645e350fe54d16b17bfc5e71f371c449383d3342e17 \ - --hash=sha256:41ef53e7c58aa4ef281da975f62c258950f54b76ec8e45941e93a3d1d8580594 \ - --hash=sha256:42821446ee7a76f5d9f71f9e33a4fb2ffd724bb3e7f93386150b61a43115788d \ - --hash=sha256:43fbac5f22e25bee1d482c97474f930a353542855f05c1161fd804c9dc74a09d \ - --hash=sha256:4457a94da0d5c53dc4b3e4de1158bdab077db23c53232f37a3cb7afdb053a4e3 \ - --hash=sha256:465a3eb5659338cf2a9243e50ad9b2296fa15061736d6e26240e713522b6235c \ - --hash=sha256:482103aed1dfe2f3b71a58eff35ba105289b8d862551ea576bd15479aba01f66 \ - --hash=sha256:4832d7d380477521a8c1644bbab6588dfedea5e30a7d967b5fb75977c45fd77f \ - --hash=sha256:4901165d170a5fde6f589acb90a6b33629ad1ec976d4529e769c6f3d885e3e80 \ - --hash=sha256:5307def11a35f5ae4581a0b658b0af8178c65c530e94893345bebf41cc139d33 \ - --hash=sha256:5417558f6887e9b6b65b4527232553c139b57ec42c64570569b155262ac0754f \ - --hash=sha256:56a737287efecafc16f6d067c2ea0117abadcd078d58721f967952db329a3e5c \ - --hash=sha256:586f8204935b9ec884500498ccc91aa869fc652c40c093bd9e1471fbcc25c022 \ - --hash=sha256:5b4e7d8d6c9b2e8ee2d55c90b59c707ca59bc30058269b3db7b1f8df5763557e \ - --hash=sha256:5ddcba87675b6d509139d1b521e0c8250e967e63b5909a7e8f8944d0f90ff36f \ - --hash=sha256:618a3d6cae6ef8ec88bb76dd80b83cfe415ad4f1d942ca2a903bf6b6ff97a2da \ - --hash=sha256:635dc434ff724b178cb192c70016cc0ad25a275228f749ee0daf0eddbc8183b1 \ - --hash=sha256:661d25cbffaf8cc42e971dd570d87cb29a665f49f4abe1f9e76be9a5182c4688 \ - --hash=sha256:66e6a3af5a75363d2c9a48b07cb27c4ea542938b1a2e93b15a503cdfa8490795 \ - --hash=sha256:67071a6171e92b6da534b8ae326505f7c18022c6f19072a81dcf40db2638767c \ - --hash=sha256:685537e07897f173abcf67258bee3c05c374fa6fff89d4c7e42fb391b0605e98 \ - --hash=sha256:69e64831e22a6b377772e7fb337533c365085b31619005802a79242fee620bc1 \ - --hash=sha256:6b0817e34942b2ca527b0e9298373e7cc75f429e8da2055607f4931fded23e20 \ - --hash=sha256:6c81e5f372cd0dc5dc4809553d34f832f60a46034a5f187756d9b90586c2c307 \ - --hash=sha256:6d7faa6f14017c0b1e69f5e2c357b998731ea75a442ab3841c0dbbbfe902d2c4 \ - --hash=sha256:6ef0befbb5d79cf32d0266f5cff01545602344eda89480e1dd88aca964260b18 \ - --hash=sha256:6ef687afab047554a2d366e112dd187b62d261d49eb79b77e386f94644363294 \ - --hash=sha256:7223a2a5fe0d217e60a60cdae28d6949140dde9c3bcc714063c5b463065e3d66 \ - --hash=sha256:77f195baa60a54ef9d2de16fbbfd3ff8b04edc0c0140a761b56c267ac11aa467 \ - --hash=sha256:793968759cd0d96cac1e367afd70c235867831983f876a53389ad869b043c948 \ - --hash=sha256:7bd339195d84439cbe5771546fe8a4e8a7a045417d8f9de9a368c434e42a721e \ - --hash=sha256:7cd863afe7336c62ec78d7d1349a2f34c007a3cc6c2369d667c65aeec412a5b1 \ - --hash=sha256:7f2facbd386dd60cbbf1a794181e6aa0bd429bd78bfdf775436020172e2a23f0 \ - --hash=sha256:84ffab12db93b5f6bad84c712c92060a2d321b35c3c9960b43d08d0f639d60d7 \ - --hash=sha256:8c8370641f1a7f0e0669ddccca22f1da893cef7628396431eb445d46d893e5cd \ - --hash=sha256:8db715ebe3bb7d86d77ac1826f7d67ec11a70dbd2376b7cc214199360517b641 \ - --hash=sha256:8e8916ae4c720529e18afa0b879473049e95949bf97042e938530e072fde061d \ - --hash=sha256:8f03bccbd8586e9dd37219bce4d4e0d3ab492e6b3b533e973fa08a112cb2ffc9 \ - --hash=sha256:8f2fc11e8fe034ee3c34d316d0ad8808f45bc3b9ce5857ff29d513f3ff2923a1 \ - --hash=sha256:923d39efa3cfb7279a0327e337a7958bff00cc447fd07a25cddb0a1cc9a6d2da \ - --hash=sha256:93df1de2f7f7239dc9cc5a4a12408ee1598725036bd2dedadc14d94525192fc3 \ - --hash=sha256:998e33ad22dc7ec7e030b3df701c43630b5bc0d8fbc2267653577e3fec279afa \ - --hash=sha256:99f70b740dc04d09e6b2699b675874367885217a2e9f782bdf5395632ac663b7 \ - --hash=sha256:9a00312dea9310d4cb7dbd7787e722d2e86a95c2db92fbd7d0155f97127bcb40 \ - --hash=sha256:9d54553c1136b50fd12cc17e5b11ad07374c316df307e4cfd6441bea5fb68496 \ - --hash=sha256:9dbbeb27f4e70bfd9eec1be5477517365afe05a9b2c441a0b21929ee61048124 \ - --hash=sha256:a1ce3ba137ed54f83e56fb983a5859a27d43a40188ba798993812fed73c70836 \ - --hash=sha256:a34d557a42aa28bd5c48a023c570219ba2593bcbbb8dc1b98d8cf5d529ab1434 \ - --hash=sha256:a5f446dd5055667aabaee78487f2b5ab72e244f9bc0b2ffebfeec79051679984 \ - --hash=sha256:ad36cfb355e24f1bd37cac88c112cd7730873f20fb0bdaf8ba59eedf8216079f \ - --hash=sha256:aec493917dd45e3c69d00a8874e7cbed844efd935595ef78a0f25f14312e33c6 \ - --hash=sha256:b316144e85316da2723f9d8dc75bada12fa58489a527091fa1d5a612643d1a0e \ - --hash=sha256:b34ae4636dfc4e76a438ab826a0d1eed2589ca7d9a1b2d5bb546978ac6485461 \ - --hash=sha256:b34b7aa8b261c1dbf7720b5d6f01f38243e9b9daf7e6b8bc1fd4657000062f2c \ - --hash=sha256:bc362ee4e314870a70f4ae88772d72d877246537d9f8cb8f7eacf10884862432 \ - --hash=sha256:bed88b9a458e354014d662d47e7a5baafd7ff81c780fd91584a10d6ec842cb73 \ - --hash=sha256:c0013fe6b46aa496a6749c77e00a3eb07952832ad6166bd481c74bda0dcb6d58 \ - --hash=sha256:c0b5dcf9193625afd8ecc92312d6ed78781c46ecbf39af9ad4681fc9f464af88 \ - --hash=sha256:c4325ff0442a12113a6379af66978c3fe562f846763287ef66bdc1d57925d337 \ - --hash=sha256:c463ed05f9dfb9baebef68048aed8dcdc94411e4bf3d33a39ba97e271624f8f7 \ - --hash=sha256:c8362467a0fdeccd47935f22c256bec5e6abe543bf0d66e3d3d57a8fb5731863 \ - --hash=sha256:cd5bf1af8efe569654bbef5a3e0a56eca45f87cfcffab31dd8dde70da5982475 \ - --hash=sha256:cf1ea2e34868f6fbf070e1af291c8180480310173de0b0c43fc38a02929fc0e3 \ - --hash=sha256:d62dec4976954a23d7f91f2f4530852b0c7608116c257833922a896101336c51 \ - --hash=sha256:d68c93e381010662ab873fea609bf6c0f428b6d0bb00f2c6939782e0818d37bf \ - --hash=sha256:d7c36232a90d4755b720fbd76739d8891732b18cf240a9c645d75f00639a9024 \ - --hash=sha256:dd18772815d5f008fa03d2b9a681ae38d5ae9f0e599f7dda233c439fcaa00d40 \ - --hash=sha256:ddc2f4dfd396c7bfa18e6ce371cba60e4cf9d2e5cdb71376aa2da264605b60b9 \ - --hash=sha256:e003b002ec72c8d5a3e3da2989c7d6065b47d9eaa70cd8808b5384fbb970f4ec \ - --hash=sha256:e32a92116d4f2a80b629778280103d2a510a5b3f6314ceccd6e38006b5e92dcb \ - --hash=sha256:e4461d0f003a0aa9be2bdd1b798a041f177189c1a0f7619fe8c95ad08d9a45d7 \ - --hash=sha256:e541ec6f2ec456934fd279a3120f856cd0aedd209fc3852eca563f81738f6861 \ - --hash=sha256:e546e768d08ad55b20b11dbb78a745151acbd938f8f00d0cfbabe8b0199b9880 \ - --hash=sha256:ea7d4a99f3b38c37eac212dbd6ec42b7a5ec51e2c74b5d3223e43c811609e65f \ - --hash=sha256:ed4eb745efbff0a8e9587d22a84be94a5eb7d2d99c02dacf7bd0911713ed14dd \ - --hash=sha256:f8a2f084546cc59ea99fda8e070be2fd140c3092dc11524a71aa8f0f3d5a55ca \ - --hash=sha256:fcb25daa9219b4cf3a0ab24b0eb9a5cc8949ed4dc72acb8fa16b7e1681aa3c58 \ - --hash=sha256:fdea4952db2793c4ad0bdccd27c1d8fdd1423a92f04598bc39425bcc2b8ee46e +rpds-py==0.18.1 \ + --hash=sha256:05f3d615099bd9b13ecf2fc9cf2d839ad3f20239c678f461c753e93755d629ee \ + --hash=sha256:06d218939e1bf2ca50e6b0ec700ffe755e5216a8230ab3e87c059ebb4ea06afc \ + --hash=sha256:07f2139741e5deb2c5154a7b9629bc5aa48c766b643c1a6750d16f865a82c5fc \ + --hash=sha256:08d74b184f9ab6289b87b19fe6a6d1a97fbfea84b8a3e745e87a5de3029bf944 \ + --hash=sha256:0abeee75434e2ee2d142d650d1e54ac1f8b01e6e6abdde8ffd6eeac6e9c38e20 \ + --hash=sha256:154bf5c93d79558b44e5b50cc354aa0459e518e83677791e6adb0b039b7aa6a7 \ + --hash=sha256:17c6d2155e2423f7e79e3bb18151c686d40db42d8645e7977442170c360194d4 \ + --hash=sha256:1805d5901779662d599d0e2e4159d8a82c0b05faa86ef9222bf974572286b2b6 \ + --hash=sha256:19ba472b9606c36716062c023afa2484d1e4220548751bda14f725a7de17b4f6 \ + --hash=sha256:19e515b78c3fc1039dd7da0a33c28c3154458f947f4dc198d3c72db2b6b5dc93 \ + --hash=sha256:1d54f74f40b1f7aaa595a02ff42ef38ca654b1469bef7d52867da474243cc633 \ + --hash=sha256:207c82978115baa1fd8d706d720b4a4d2b0913df1c78c85ba73fe6c5804505f0 \ + --hash=sha256:2625f03b105328729f9450c8badda34d5243231eef6535f80064d57035738360 \ + --hash=sha256:27bba383e8c5231cd559affe169ca0b96ec78d39909ffd817f28b166d7ddd4d8 \ + --hash=sha256:2c3caec4ec5cd1d18e5dd6ae5194d24ed12785212a90b37f5f7f06b8bedd7139 \ + --hash=sha256:2cc7c1a47f3a63282ab0f422d90ddac4aa3034e39fc66a559ab93041e6505da7 \ + --hash=sha256:2fc24a329a717f9e2448f8cd1f960f9dac4e45b6224d60734edeb67499bab03a \ + --hash=sha256:312fe69b4fe1ffbe76520a7676b1e5ac06ddf7826d764cc10265c3b53f96dbe9 \ + --hash=sha256:32b7daaa3e9389db3695964ce8e566e3413b0c43e3394c05e4b243a4cd7bef26 \ + --hash=sha256:338dee44b0cef8b70fd2ef54b4e09bb1b97fc6c3a58fea5db6cc083fd9fc2724 \ + --hash=sha256:352a88dc7892f1da66b6027af06a2e7e5d53fe05924cc2cfc56495b586a10b72 \ + --hash=sha256:35b2b771b13eee8729a5049c976197ff58a27a3829c018a04341bcf1ae409b2b \ + --hash=sha256:38e14fb4e370885c4ecd734f093a2225ee52dc384b86fa55fe3f74638b2cfb09 \ + --hash=sha256:3c20f05e8e3d4fc76875fc9cb8cf24b90a63f5a1b4c5b9273f0e8225e169b100 \ + --hash=sha256:3dd3cd86e1db5aadd334e011eba4e29d37a104b403e8ca24dcd6703c68ca55b3 \ + --hash=sha256:489bdfe1abd0406eba6b3bb4fdc87c7fa40f1031de073d0cfb744634cc8fa261 \ + --hash=sha256:48c2faaa8adfacefcbfdb5f2e2e7bdad081e5ace8d182e5f4ade971f128e6bb3 \ + --hash=sha256:4a98a1f0552b5f227a3d6422dbd61bc6f30db170939bd87ed14f3c339aa6c7c9 \ + --hash=sha256:4adec039b8e2928983f885c53b7cc4cda8965b62b6596501a0308d2703f8af1b \ + --hash=sha256:4e0ee01ad8260184db21468a6e1c37afa0529acc12c3a697ee498d3c2c4dcaf3 \ + --hash=sha256:51584acc5916212e1bf45edd17f3a6b05fe0cbb40482d25e619f824dccb679de \ + --hash=sha256:531796fb842b53f2695e94dc338929e9f9dbf473b64710c28af5a160b2a8927d \ + --hash=sha256:5463c47c08630007dc0fe99fb480ea4f34a89712410592380425a9b4e1611d8e \ + --hash=sha256:5c45a639e93a0c5d4b788b2613bd637468edd62f8f95ebc6fcc303d58ab3f0a8 \ + --hash=sha256:6031b25fb1b06327b43d841f33842b383beba399884f8228a6bb3df3088485ff \ + --hash=sha256:607345bd5912aacc0c5a63d45a1f73fef29e697884f7e861094e443187c02be5 \ + --hash=sha256:618916f5535784960f3ecf8111581f4ad31d347c3de66d02e728de460a46303c \ + --hash=sha256:636a15acc588f70fda1661234761f9ed9ad79ebed3f2125d44be0862708b666e \ + --hash=sha256:673fdbbf668dd958eff750e500495ef3f611e2ecc209464f661bc82e9838991e \ + --hash=sha256:6afd80f6c79893cfc0574956f78a0add8c76e3696f2d6a15bca2c66c415cf2d4 \ + --hash=sha256:6b5ff7e1d63a8281654b5e2896d7f08799378e594f09cf3674e832ecaf396ce8 \ + --hash=sha256:6c4c4c3f878df21faf5fac86eda32671c27889e13570645a9eea0a1abdd50922 \ + --hash=sha256:6cd8098517c64a85e790657e7b1e509b9fe07487fd358e19431cb120f7d96338 \ + --hash=sha256:6d1e42d2735d437e7e80bab4d78eb2e459af48c0a46e686ea35f690b93db792d \ + --hash=sha256:6e30ac5e329098903262dc5bdd7e2086e0256aa762cc8b744f9e7bf2a427d3f8 \ + --hash=sha256:70a838f7754483bcdc830444952fd89645569e7452e3226de4a613a4c1793fb2 \ + --hash=sha256:720edcb916df872d80f80a1cc5ea9058300b97721efda8651efcd938a9c70a72 \ + --hash=sha256:732672fbc449bab754e0b15356c077cc31566df874964d4801ab14f71951ea80 \ + --hash=sha256:740884bc62a5e2bbb31e584f5d23b32320fd75d79f916f15a788d527a5e83644 \ + --hash=sha256:7700936ef9d006b7ef605dc53aa364da2de5a3aa65516a1f3ce73bf82ecfc7ae \ + --hash=sha256:7732770412bab81c5a9f6d20aeb60ae943a9b36dcd990d876a773526468e7163 \ + --hash=sha256:7750569d9526199c5b97e5a9f8d96a13300950d910cf04a861d96f4273d5b104 \ + --hash=sha256:7f1944ce16401aad1e3f7d312247b3d5de7981f634dc9dfe90da72b87d37887d \ + --hash=sha256:81c5196a790032e0fc2464c0b4ab95f8610f96f1f2fa3d4deacce6a79852da60 \ + --hash=sha256:8352f48d511de5f973e4f2f9412736d7dea76c69faa6d36bcf885b50c758ab9a \ + --hash=sha256:8927638a4d4137a289e41d0fd631551e89fa346d6dbcfc31ad627557d03ceb6d \ + --hash=sha256:8c7672e9fba7425f79019db9945b16e308ed8bc89348c23d955c8c0540da0a07 \ + --hash=sha256:8d2e182c9ee01135e11e9676e9a62dfad791a7a467738f06726872374a83db49 \ + --hash=sha256:910e71711d1055b2768181efa0a17537b2622afeb0424116619817007f8a2b10 \ + --hash=sha256:942695a206a58d2575033ff1e42b12b2aece98d6003c6bc739fbf33d1773b12f \ + --hash=sha256:9437ca26784120a279f3137ee080b0e717012c42921eb07861b412340f85bae2 \ + --hash=sha256:967342e045564cef76dfcf1edb700b1e20838d83b1aa02ab313e6a497cf923b8 \ + --hash=sha256:998125738de0158f088aef3cb264a34251908dd2e5d9966774fdab7402edfab7 \ + --hash=sha256:9e6934d70dc50f9f8ea47081ceafdec09245fd9f6032669c3b45705dea096b88 \ + --hash=sha256:a3d456ff2a6a4d2adcdf3c1c960a36f4fd2fec6e3b4902a42a384d17cf4e7a65 \ + --hash=sha256:a7b28c5b066bca9a4eb4e2f2663012debe680f097979d880657f00e1c30875a0 \ + --hash=sha256:a888e8bdb45916234b99da2d859566f1e8a1d2275a801bb8e4a9644e3c7e7909 \ + --hash=sha256:aa3679e751408d75a0b4d8d26d6647b6d9326f5e35c00a7ccd82b78ef64f65f8 \ + --hash=sha256:aaa71ee43a703c321906813bb252f69524f02aa05bf4eec85f0c41d5d62d0f4c \ + --hash=sha256:b646bf655b135ccf4522ed43d6902af37d3f5dbcf0da66c769a2b3938b9d8184 \ + --hash=sha256:b906b5f58892813e5ba5c6056d6a5ad08f358ba49f046d910ad992196ea61397 \ + --hash=sha256:b9bb1f182a97880f6078283b3505a707057c42bf55d8fca604f70dedfdc0772a \ + --hash=sha256:bd1105b50ede37461c1d51b9698c4f4be6e13e69a908ab7751e3807985fc0346 \ + --hash=sha256:bf18932d0003c8c4d51a39f244231986ab23ee057d235a12b2684ea26a353590 \ + --hash=sha256:c273e795e7a0f1fddd46e1e3cb8be15634c29ae8ff31c196debb620e1edb9333 \ + --hash=sha256:c69882964516dc143083d3795cb508e806b09fc3800fd0d4cddc1df6c36e76bb \ + --hash=sha256:c827576e2fa017a081346dce87d532a5310241648eb3700af9a571a6e9fc7e74 \ + --hash=sha256:cbfbea39ba64f5e53ae2915de36f130588bba71245b418060ec3330ebf85678e \ + --hash=sha256:ce0bb20e3a11bd04461324a6a798af34d503f8d6f1aa3d2aa8901ceaf039176d \ + --hash=sha256:d0cee71bc618cd93716f3c1bf56653740d2d13ddbd47673efa8bf41435a60daa \ + --hash=sha256:d21be4770ff4e08698e1e8e0bce06edb6ea0626e7c8f560bc08222880aca6a6f \ + --hash=sha256:d31dea506d718693b6b2cffc0648a8929bdc51c70a311b2770f09611caa10d53 \ + --hash=sha256:d44607f98caa2961bab4fa3c4309724b185b464cdc3ba6f3d7340bac3ec97cc1 \ + --hash=sha256:d58ad6317d188c43750cb76e9deacf6051d0f884d87dc6518e0280438648a9ac \ + --hash=sha256:d70129cef4a8d979caa37e7fe957202e7eee8ea02c5e16455bc9808a59c6b2f0 \ + --hash=sha256:d85164315bd68c0806768dc6bb0429c6f95c354f87485ee3593c4f6b14def2bd \ + --hash=sha256:d960de62227635d2e61068f42a6cb6aae91a7fe00fca0e3aeed17667c8a34611 \ + --hash=sha256:dc48b479d540770c811fbd1eb9ba2bb66951863e448efec2e2c102625328e92f \ + --hash=sha256:e1735502458621921cee039c47318cb90b51d532c2766593be6207eec53e5c4c \ + --hash=sha256:e2be6e9dd4111d5b31ba3b74d17da54a8319d8168890fbaea4b9e5c3de630ae5 \ + --hash=sha256:e4c39ad2f512b4041343ea3c7894339e4ca7839ac38ca83d68a832fc8b3748ab \ + --hash=sha256:ed402d6153c5d519a0faf1bb69898e97fb31613b49da27a84a13935ea9164dfc \ + --hash=sha256:ee17cd26b97d537af8f33635ef38be873073d516fd425e80559f4585a7b90c43 \ + --hash=sha256:f3027be483868c99b4985fda802a57a67fdf30c5d9a50338d9db646d590198da \ + --hash=sha256:f5bab211605d91db0e2995a17b5c6ee5edec1270e46223e513eaa20da20076ac \ + --hash=sha256:f6f8e3fecca256fefc91bb6765a693d96692459d7d4c644660a9fff32e517843 \ + --hash=sha256:f7afbfee1157e0f9376c00bb232e80a60e59ed716e3211a80cb8506550671e6e \ + --hash=sha256:fa242ac1ff583e4ec7771141606aafc92b361cd90a05c30d93e343a0c2d82a89 \ + --hash=sha256:fab6ce90574645a0d6c58890e9bcaac8d94dff54fb51c69e5522a7358b80ab64 # via # jsonschema # referencing -ruff==0.4.3 \ - --hash=sha256:08a0d6a22918ab2552ace96adeaca308833873a4d7d1d587bb1d37bae8728eb3 \ - --hash=sha256:0bfc9e955e6dc6359eb6f82ea150c4f4e82b660e5b58d9a20a0e42ec3bb6342b \ - --hash=sha256:18b00e0bcccf0fc8d7186ed21e311dffd19761cb632241a6e4fe4477cc80ef6e \ - --hash=sha256:25cacda2155778beb0d064e0ec5a3944dcca9c12715f7c4634fd9d93ac33fd30 \ - --hash=sha256:262f5635e2c74d80b7507fbc2fac28fe0d4fef26373bbc62039526f7722bca1b \ - --hash=sha256:29efff25bf9ee685c2c8390563a5b5c006a3fee5230d28ea39f4f75f9d0b6f2f \ - --hash=sha256:510a67d232d2ebe983fddea324dbf9d69b71c4d2dfeb8a862f4a127536dd4cfb \ - --hash=sha256:71ca5f8ccf1121b95a59649482470c5601c60a416bf189d553955b0338e34614 \ - --hash=sha256:7363691198719c26459e08cc17c6a3dac6f592e9ea3d2fa772f4e561b5fe82a3 \ - --hash=sha256:7a1c3a450bc6539ef00da6c819fb1b76b6b065dec585f91456e7c0d6a0bbc725 \ - --hash=sha256:819fb06d535cc76dfddbfe8d3068ff602ddeb40e3eacbc90e0d1272bb8d97113 \ - --hash=sha256:927b11c1e4d0727ce1a729eace61cee88a334623ec424c0b1c8fe3e5f9d3c865 \ - --hash=sha256:b70800c290f14ae6fcbb41bbe201cf62dfca024d124a1f373e76371a007454ce \ - --hash=sha256:dc9ff11cd9a092ee7680a56d21f302bdda14327772cd870d806610a3503d001f \ - --hash=sha256:eba1f14df3c758dd7de5b55fbae7e1c8af238597961e5fb628f3de446c3c40c5 \ - --hash=sha256:eeb039f8428fcb6725bb63cbae92ad67b0559e68b5d80f840f11914afd8ddf7f \ - --hash=sha256:ff0a3ef2e3c4b6d133fbedcf9586abfbe38d076041f2dc18ffb2c7e0485d5a07 +ruff==0.4.4 \ + --hash=sha256:1aecced1269481ef2894cc495647392a34b0bf3e28ff53ed95a385b13aa45768 \ + --hash=sha256:29d44ef5bb6a08e235c8249294fa8d431adc1426bfda99ed493119e6f9ea1bf6 \ + --hash=sha256:39df0537b47d3b597293edbb95baf54ff5b49589eb7ff41926d8243caa995ea6 \ + --hash=sha256:424e5b72597482543b684c11def82669cc6b395aa8cc69acc1858b5ef3e5daae \ + --hash=sha256:4c8e2f1e8fc12d07ab521a9005d68a969e167b589cbcaee354cb61e9d9de9c15 \ + --hash=sha256:60ed88b636a463214905c002fa3eaab19795679ed55529f91e488db3fe8976ab \ + --hash=sha256:8e7e6ebc10ef16dcdc77fd5557ee60647512b400e4a60bdc4849468f076f6eef \ + --hash=sha256:958b4ea5589706a81065e2a776237de2ecc3e763342e5cc8e02a4a4d8a5e6f95 \ + --hash=sha256:9da73eb616b3241a307b837f32756dc20a0b07e2bcb694fec73699c93d04a69e \ + --hash=sha256:b1867ee9bf3acc21778dcb293db504692eda5f7a11a6e6cc40890182a9f9e595 \ + --hash=sha256:b5eb0a4bfd6400b7d07c09a7725e1a98c3b838be557fee229ac0f84d9aa49c36 \ + --hash=sha256:b90fc5e170fc71c712cc4d9ab0e24ea505c6a9e4ebf346787a67e691dfb72e85 \ + --hash=sha256:b9ddb2c494fb79fc208cd15ffe08f32b7682519e067413dbaf5f4b01a6087bcd \ + --hash=sha256:c4efe62b5bbb24178c950732ddd40712b878a9b96b1d02b0ff0b08a090cbd891 \ + --hash=sha256:c51c928a14f9f0a871082603e25a1588059b7e08a920f2f9fa7157b5bf08cfe9 \ + --hash=sha256:cb53473849f011bca6e754f2cdf47cafc9c4f4ff4570003a0dad0b9b6890e876 \ + --hash=sha256:f87ea42d5cdebdc6a69761a9d0bc83ae9b3b30d0ad78952005ba6568d6c022af s3transfer==0.10.1 \ --hash=sha256:5683916b4c724f799e600f41dd9e10a9ff19871bf87623cc8f491cb4f5fa0a19 \ --hash=sha256:ceb252b11bcf87080fb7850a224fb6e05c8a776bab8f2b64b7f25b969464839d @@ -867,24 +867,24 @@ urllib3==2.2.1 \ # docker # requests # testcontainers -uv==0.1.39 \ - --hash=sha256:2333dd52e6734e0da6722bdd7b7257d0f8beeac89623c5cfc3888b4c56bc812e \ - --hash=sha256:2ae930189742536f8178617c4ec05cb10271cb3886f6039abd36ee6ab511b160 \ - --hash=sha256:2bda6686a9bb1370d7f53436d34f8ede0fa1b9877b5e152aedd9b22fc3cb33a9 \ - --hash=sha256:3330bd7ab8a6160d815fdc36f48479edf6db8b58d39d20959555095ea7eb63c5 \ - --hash=sha256:3365e0631a738a482d2379e565a230b135f7c5665394313829ccabf7c76c1362 \ - --hash=sha256:388018659e5d73fdeb8ce13c1d812391ec981bf446ab86fb9c0e3d227f727da2 \ - --hash=sha256:4c6ee1148f23aa5d6edf1a1106cc33c4aa57bdbfe8d4c5068c672105415d3b99 \ - --hash=sha256:6b2acc907f7a1735dd9ffeb20d8c7aeeb86b1e5ba0a999e09433ad7f2789dc78 \ - --hash=sha256:7848d703201e6867ae2c70d611e6ffd53d5e5adfc2c9abe89b6d021975e43e81 \ - --hash=sha256:7ee426e0c5fa048cc44f3ac78e476121ef4365bb8bc9199d3cbffc372a80e55d \ - --hash=sha256:88f5601ee957f9be2efc7a24d186f9d2641053806e107e0e42c5e522882c89e0 \ - --hash=sha256:93217578e68a431df235173e390ad7df090499367cd7f5c811520fd4ea3d5047 \ - --hash=sha256:c131dba5fe5079d9c5f06846649e35662901a9afd9b31de17714c63e042d91d2 \ - --hash=sha256:c20b9023dac12ee518de79c91df313be7abb052440cb78f8ffb20dea81d3289e \ - --hash=sha256:cd6d9629ab0e22ab2336b8d6363573ea5a7060ef82ff5d3e6da4b1b30522ef13 \ - --hash=sha256:ce911087f56edc97a5792c17f682ed7611fedead0ea117f56bb6f3942eb3e7b3 \ - --hash=sha256:fba96b3049aea5c1394cd360e5900e4af39829df48ed6fc55eba115c00c8195a +uv==0.1.42 \ + --hash=sha256:199e28690da15326ff9391f10a4d316ac515e95a328ad6a046908d829e0b77c9 \ + --hash=sha256:1c6d7e2916c83d42bf6cd37e121c5c42d6033d4b4469fe5238c85420d9d184cf \ + --hash=sha256:29a34a1a9b9e414fd075c2cac772722443fada50d7221c0c855f4e83a01a2939 \ + --hash=sha256:34a749742b57f357e2a0795790a6408bfdacefa184d21b060ea4df2d8736a4d6 \ + --hash=sha256:40a9664ec199ad21c1a4fe3a665ffb75ff641dd8af7a16381fa462ca14e02474 \ + --hash=sha256:5bcb0937279c84c051e08e3893b9bde3c4bca05455b9c68d173d67f01c136cf9 \ + --hash=sha256:8583204cbe97ede7bf3250f5f84722f0f9027d3bf025b91bb2a00f09348010ec \ + --hash=sha256:877d7fd26aa46b693571b4b7e84b44b4eb36a3e3902fc291a6c1c8af6fe8372a \ + --hash=sha256:9dcd7fd148b958b24507a5f6402db91a5a37f04bb5bd9941e149acbf82b390b0 \ + --hash=sha256:a31e8d4fca0031eadeeceafbf742532344c2f7aaaf7d95e3f00316a2d1a633c6 \ + --hash=sha256:af9711bd667c2effa89319ad2a0b312c6754d153f0d44f8a410d66ebbf2fa104 \ + --hash=sha256:b3dbd7f50b2f0e4e50ea0cfbf7b3f7fdc2a28e76e2643d3c4060842263bf6c36 \ + --hash=sha256:c59ad07b9a660173cc255daf1a764400d62234a345d4308194ff4af84f06cf67 \ + --hash=sha256:c873475f4409d36c4722f31e7d34039b99fab7224a157d33c30bb26a91b19482 \ + --hash=sha256:d795560b1fcc9d504781fd727178b80afeed1b5f79aef71b73058b3d8e47bb08 \ + --hash=sha256:dab260d7eb28f6aa290bc93f7c05d05b28e841f830f299234d22dd5c3a00d163 \ + --hash=sha256:e490004734e101ec6f00ac5d28e31b5cb8eb7579634d38963c33e62c570b3747 uvicorn==0.29.0 \ --hash=sha256:2c2aac7ff4f4365c206fd773a39bf4ebd1047c238f8b8268ad996829323473de \ --hash=sha256:6a69214c0b6a087462412670b3ef21224fa48cae0e452b5883e8e8bdfdd11dd0 diff --git a/lock/requirements.txt b/lock/requirements.txt index 8eec6b1..9ade134 100644 --- a/lock/requirements.txt +++ b/lock/requirements.txt @@ -51,13 +51,13 @@ attrs==23.2.0 \ # via # jsonschema # referencing -boto3==1.34.98 \ - --hash=sha256:030e43b8efe22b4cf10b9f3ef9e30cd4cf9ef9784b26efe9a4583339f2b2bcec \ - --hash=sha256:28c10956033fa79e64529f48c3b62db86d5e4b77024a7343764b6bde6b553543 +boto3==1.34.102 \ + --hash=sha256:1c1fb2884f85c0ec6b62e6e7ed5a2a6635e1188f3ab5d2b700f7db1cf8464484 \ + --hash=sha256:65e4b9fb9ceefe19976e8822ac0cd68d28946d4697e538741d2bbdb5b45ae42f # via hexkit -botocore==1.34.98 \ - --hash=sha256:4cee65df02f4b0be08ad1401965cc89efafebc50ef0727d2d17083c7f1ed2831 \ - --hash=sha256:631c0031d8ce922b5752ab395ead896a0281b0dc74745a754d0351a27c5d83de +botocore==1.34.102 \ + --hash=sha256:79ac7fc2729294395c70eff9c23510f00785ad2acd78d6130cb4379e9f27da86 \ + --hash=sha256:e2f8a9f4bac6f7b568e6e981ac2a2500bc992329c85dde8546f0cae8605dd009 # via # boto3 # hexkit @@ -82,9 +82,9 @@ fastapi==0.110.3 \ --hash=sha256:555700b0159379e94fdbfc6bb66a0f1c43f4cf7060f25239af3d84b63a656626 \ --hash=sha256:fd7600612f755e4050beb74001310b5a7e1796d149c2ee363124abdfa0289d32 # via ghga-service-commons -ghga-event-schemas==3.2.0 \ - --hash=sha256:66ccf599967722163b06a98a665a9393de012e4db92059e8fd5a312785f21071 \ - --hash=sha256:d6f9ad7a9132f5aaff2003e3db07d2a9a223b27270d0afb256d698a639fd6f2c +ghga-event-schemas==3.3.0 \ + --hash=sha256:852a04ebadf311e1e04d9b95a6286716a2e80f1e6c135795c3f207fc58011290 \ + --hash=sha256:d98b82d3fb92698a7ee0505740ed2469d62c4577c651b5f98d561720a27db8cf ghga-service-commons==3.1.3 \ --hash=sha256:4f7c2b56ae24594dd60cb28719f040351056c06d59b2d8f74f46eb9005b770f2 \ --hash=sha256:8b2e255506ac11cfafba3a18f58c0471a0b1b0c89893f6489a8a2f9af4dd6c0b @@ -92,9 +92,9 @@ h11==0.14.0 \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 # via uvicorn -hexkit==3.0.0 \ - --hash=sha256:300d8da001cfb79ba818ec36378f95b5d81b0481099b72cc47ad2f47be93131b \ - --hash=sha256:b9810a834daa910a9659c930a16f8fbb319ea0a15a1b2303ba8ea6dd617d753c +hexkit==3.0.1 \ + --hash=sha256:0d854aa8c0f5539338a50ed363557d4bbf720ca01afde9f07512cb76a7be398d \ + --hash=sha256:61347f4564eb557bb4dea176a0085dc85391a4a5eb32681433b7afc1487df3aa # via ghga-service-commons httptools==0.6.1 \ --hash=sha256:00d5d4b68a717765b1fabfd9ca755bd12bf44105eeb806c03d1962acd9b8e563 \ @@ -270,67 +270,67 @@ pygments==2.18.0 \ --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a # via rich -pymongo==4.7.1 \ - --hash=sha256:11f74dafde63ad2dc30c01f40b4c69d9af157f8ba5224b0c9d4de7158537266f \ - --hash=sha256:13fc201e073644acd77860d9e91ccfc27addf510563e07381cadc9a55ac3a894 \ - --hash=sha256:1bd1eef70c1eda838b26397ef75c9580d7a97fd94b6324971d7f3d2ad3552e9a \ - --hash=sha256:24c8f1dd545360ec1b79007a3ba6573af565df6fde49f6dfc53813f3f475a751 \ - --hash=sha256:253ed8fd6e7f4b2a1caa89e6b287b9e04f42613319ee1e1240c2db2afe1637e7 \ - --hash=sha256:263c169302df636f9086b584994a51d0adfc8738fe27d7b8e2aacf46fd68b6cb \ - --hash=sha256:297cdc87c4b4168782b571c8643540e9b0ad1d09266b43d2f5954f8632280835 \ - --hash=sha256:2ccc8dd4fe9aac18dde27c33a53271c6c90159b74c43fbdab1d33d5efc36c2f5 \ - --hash=sha256:30a9d891631d7e847b24f551b1d89ff2033539e7cd8e9af29714b4d0db7abb06 \ - --hash=sha256:31ed8ba3da0366346264604b3a443f5a4232cab5ed45f520bead6184cf0851a1 \ - --hash=sha256:337d99f88d32a5f8056d6d2bc365ccf09d09583f3942882c50cf11b459e8fbc0 \ - --hash=sha256:3ef32a7cfe748c0c72fdad9e51459de5e0c6b16c5288b39f863abfff23503847 \ - --hash=sha256:455f9d603ed0990a787773d5718e871300bddf585ce543baf129c9f5ca3adb02 \ - --hash=sha256:45ac46f0d6bdc2baac34ced60aae27b2083170d77397330eff0ac5689ea29d38 \ - --hash=sha256:4c7e05454cdc5aa4702e03cad0df4205daccd6fd631bbbf0a85bbe598129a6cc \ - --hash=sha256:4d227555be35078b53f506f6b58bd0b0e8fd4513e89e6f29e83a97efab439250 \ - --hash=sha256:4dd998e9f0f7694032c1648c7f57fccaa78903df6329b8f8ae20cfa7c4ceca34 \ - --hash=sha256:5119c66af8c4197c8757b4b7d98c443e5b127c224ac92fb657dbe2b512ae2713 \ - --hash=sha256:57b5b485ef89270ed2e603814f43f0fdd9b8ba5d4039124d90878cdc2327000c \ - --hash=sha256:58989bcb94233233a71645236b972835d4f87a6bb1b7e818d38a7e6e6d4630de \ - --hash=sha256:5a58b6cd7c423ba49db10d8445756062c931ad2246ba0da1e705bf22962fd9e9 \ - --hash=sha256:5ae1aeeb405c29885266666dc7115792d647ed68cfdb6ed02e2e211d12f2e1c8 \ - --hash=sha256:5bc87db2e9563295c4e45602ab978a2fcbaba3ab89e745503b24f895cddeb755 \ - --hash=sha256:5ff6d56ca1f0cd3687a13ce90a32a8efb3cc3a53728e5ac160c4c30d10385a72 \ - --hash=sha256:615c7573d7a9c4837332a673fdc5a5f214b474dd52d846bcf4cc3d011550bee1 \ - --hash=sha256:64b69b9cd8a6d23881a80490d575e92918f9afca43096a7d6c1013d6b3e5c75c \ - --hash=sha256:65c45682d5ed8c6618bde22cd6716b47a197f4ef800a025213b28d13a59e5fca \ - --hash=sha256:67cbee427c263a4483e3249fef480788ccc16edb1a4fc330c4c6cb0cb9db94a8 \ - --hash=sha256:7247c1dc7d8eed4e24eb1dd92c4c58ebf1e5159500015652552acfdebdeed256 \ - --hash=sha256:73bf96ece4999b0bbab7169cb2b9c60918b434487009e48be4bd47eeb2aa7b14 \ - --hash=sha256:7b10603ba64af08f5af7eb9a69d6b24e3c69d91fdd48c54b95e284686c1c582d \ - --hash=sha256:811a07bba9d35f1e34159ede632ac71dbc429b372a20004e32d6578af872db1a \ - --hash=sha256:811c41c6227b7548afcb53e1b996c25262d837b5e5f519e2ddc2c7e59d8728a5 \ - --hash=sha256:85b8dd3756b73993b1e3ab6b1cba826b9e4987a094a5d5b6d37313776458cd94 \ - --hash=sha256:887d043ecc0c7d5591925bbc7abb67caf21c94d6e6e5d442cb49eb5d9d8ee76b \ - --hash=sha256:8cee62188127a126f59ea45d3981868a5e35343be4ef4ad8712eaf42be37a00b \ - --hash=sha256:9e0a30a022ac8a9164ee5a4b761e13dbb3d10a21845f7258011e3415151fb645 \ - --hash=sha256:9e99dac3c7c2cb498937cc1767361851099da38861e921113318c87d71e3d127 \ - --hash=sha256:a46c08ef0b273c415b1e8933f6739596be264ae700a4927f84e0b84e70fdf0eb \ - --hash=sha256:a848249d5b4763497add62f7dd7bd0ce1538129bf42f4cb132a76d24c61bf98d \ - --hash=sha256:aa354933a158e57494c98b592f46d5d24d1b109e6ba05a05179cde719d9f7fd3 \ - --hash=sha256:ad360630c221aee7c0841a51851496a3ca6fdea87007098a982c1aa26e34083a \ - --hash=sha256:b897b60b2d55c26f3efea0effc11b655db68125c3731274bc3953375e9ccab73 \ - --hash=sha256:b8b95e2163b73d03a913efa89b0f7c5012be82efd4e9dbce8aa62010a75a277c \ - --hash=sha256:bfd5c7e5bb87171a5296fa32205adb50b27704a612036ec4395c3cd316fc0e91 \ - --hash=sha256:c808098f2cdb87d4035144e536ba5fa7709d0420c17b68e6ace5da18c38ded5f \ - --hash=sha256:d1829a7db720ff586aaf59c806e89e0a388548063aa844d21a570a231ad8ca87 \ - --hash=sha256:d50969de00d3522b2c394f7e59b843871e2be4b525af92066da7f3bd02799fdc \ - --hash=sha256:d63f38454a2e23c117d3ceab3b661568f2418536825787256ad24e5baaedfd27 \ - --hash=sha256:d804eaf19a65211cc2c8c5db75be685c3f31c64cdab639794f66f13f8e258ba6 \ - --hash=sha256:daf35ab13b86aba7cc8c4b019882f1fa8d287a26f586ef5eaf60a5233d3eaa52 \ - --hash=sha256:dbc32217c81d87750401fa1c2bc9450e854b23e6e30243c82d3514b8e58f39e3 \ - --hash=sha256:e175d74c52b6c8414a4b4504a2dd42b0202d101b2eb9508a34c137357683864e \ - --hash=sha256:e4a63ba6813a2168ebd35ea5369f6c33f7787525986cd77668b7956acc3d2a38 \ - --hash=sha256:e935712b17e7a42831022353bac91a346a792658a54e12bec907ec11695cc899 \ - --hash=sha256:ec94d29103317aa920dae59ed385de9604cb0ef840b5b7137b5eaa7a2042580a \ - --hash=sha256:ed6b3a0740efe98bb03ccf054578e9788ebcd06d021d548b8217ab2c82e45975 \ - --hash=sha256:f2a720e787c9b9b912db5bb4c3e7123ccff1352d6c3ac0cb2c7ee392cdc95c00 \ - --hash=sha256:f8822614975038e0cece47d12e7634a79c2ee590a0ae78ae64c37b9c6610a14c \ - --hash=sha256:fb1a884b1c6aeac5ffeb8ccb696fbc242a7ae1bba36f2328c01f76fab7221b94 +pymongo==4.7.2 \ + --hash=sha256:02efd1bb3397e24ef2af45923888b41a378ce00cb3a4259c5f4fc3c70497a22f \ + --hash=sha256:0d833651f1ba938bb7501f13e326b96cfbb7d98867b2d545ca6d69c7664903e0 \ + --hash=sha256:12c466e02133b7f8f4ff1045c6b5916215c5f7923bc83fd6e28e290cba18f9f6 \ + --hash=sha256:12d1fef77d25640cb78893d07ff7d2fac4c4461d8eec45bd3b9ad491a1115d6e \ + --hash=sha256:194065c9d445017b3c82fb85f89aa2055464a080bde604010dc8eb932a6b3c95 \ + --hash=sha256:1c78f156edc59b905c80c9003e022e1a764c54fd40ac4fea05b0764f829790e2 \ + --hash=sha256:1e37faf298a37ffb3e0809e77fbbb0a32b6a2d18a83c59cfc2a7b794ea1136b0 \ + --hash=sha256:25eeb2c18ede63891cbd617943dd9e6b9cbccc54f276e0b2e693a0cc40f243c5 \ + --hash=sha256:268d8578c0500012140c5460755ea405cbfe541ef47c81efa9d6744f0f99aeca \ + --hash=sha256:2cb77d09bd012cb4b30636e7e38d00b5f9be5eb521c364bde66490c45ee6c4b4 \ + --hash=sha256:347c49cf7f0ba49ea87c1a5a1984187ecc5516b7c753f31938bf7b37462824fd \ + --hash=sha256:35b3f0c7d49724859d4df5f0445818d525824a6cd55074c42573d9b50764df67 \ + --hash=sha256:37e9ea81fa59ee9274457ed7d59b6c27f6f2a5fe8e26f184ecf58ea52a019cb8 \ + --hash=sha256:47a1a4832ef2f4346dcd1a10a36ade7367ad6905929ddb476459abb4fd1b98cb \ + --hash=sha256:4bdb5ffe1cd3728c9479671a067ef44dacafc3743741d4dc700c377c4231356f \ + --hash=sha256:4ffd1519edbe311df73c74ec338de7d294af535b2748191c866ea3a7c484cd15 \ + --hash=sha256:5239776633f7578b81207e5646245415a5a95f6ae5ef5dff8e7c2357e6264bfc \ + --hash=sha256:5239ef7e749f1326ea7564428bf861d5250aa39d7f26d612741b1b1273227062 \ + --hash=sha256:56bf8b706946952acdea0fe478f8e44f1ed101c4b87f046859e6c3abe6c0a9f4 \ + --hash=sha256:65b4c00dedbd333698b83cd2095a639a6f0d7c4e2a617988f6c65fb46711f028 \ + --hash=sha256:6a87eef394039765679f75c6a47455a4030870341cb76eafc349c5944408c882 \ + --hash=sha256:727ad07952c155cd20045f2ce91143c7dc4fb01a5b4e8012905a89a7da554b0c \ + --hash=sha256:730778b6f0964b164c187289f906bbc84cb0524df285b7a85aa355bbec43eb21 \ + --hash=sha256:743552033c63f0afdb56b9189ab04b5c1dbffd7310cf7156ab98eebcecf24621 \ + --hash=sha256:7e9d9d2c0aae73aa4369bd373ac2ac59f02c46d4e56c4b6d6e250cfe85f76802 \ + --hash=sha256:82102e353be13f1a6769660dd88115b1da382447672ba1c2662a0fbe3df1d861 \ + --hash=sha256:827611beb6c483260d520cfa6a49662d980dfa5368a04296f65fa39e78fccea7 \ + --hash=sha256:84bc00200c3cbb6c98a2bb964c9e8284b641e4a33cf10c802390552575ee21de \ + --hash=sha256:87032f818bf5052ab742812c715eff896621385c43f8f97cdd37d15b5d394e95 \ + --hash=sha256:87832d6076c2c82f42870157414fd876facbb6554d2faf271ffe7f8f30ce7bed \ + --hash=sha256:87bb453ac3eb44db95cb6d5a616fbc906c1c00661eec7f55696253a6245beb8a \ + --hash=sha256:9024e1661c6e40acf468177bf90ce924d1bc681d2b244adda3ed7b2f4c4d17d7 \ + --hash=sha256:9349f0bb17a31371d4cacb64b306e4ca90413a3ad1fffe73ac7cd495570d94b5 \ + --hash=sha256:9385654f01a90f73827af4db90c290a1519f7d9102ba43286e187b373e9a78e9 \ + --hash=sha256:9a8bd37f5dabc86efceb8d8cbff5969256523d42d08088f098753dba15f3b37a \ + --hash=sha256:9d892fb91e81cccb83f507cdb2ea0aa026ec3ced7f12a1d60f6a5bf0f20f9c1f \ + --hash=sha256:a754e366c404d19ff3f077ddeed64be31e0bb515e04f502bf11987f1baa55a16 \ + --hash=sha256:b48a5650ee5320d59f6d570bd99a8d5c58ac6f297a4e9090535f6561469ac32e \ + --hash=sha256:bcf337d1b252405779d9c79978d6ca15eab3cdaa2f44c100a79221bddad97c8a \ + --hash=sha256:c44efab10d9a3db920530f7bcb26af8f408b7273d2f0214081d3891979726328 \ + --hash=sha256:c72d16fede22efe7cdd1f422e8da15760e9498024040429362886f946c10fe95 \ + --hash=sha256:cb6e00a79dff22c9a72212ad82021b54bdb3b85f38a85f4fc466bde581d7d17a \ + --hash=sha256:ce1a374ea0e49808e0380ffc64284c0ce0f12bd21042b4bef1af3eb7bdf49054 \ + --hash=sha256:cecd2df037249d1c74f0af86fb5b766104a5012becac6ff63d85d1de53ba8b98 \ + --hash=sha256:cf17ea9cea14d59b0527403dd7106362917ced7c4ec936c4ba22bd36c912c8e0 \ + --hash=sha256:cf28430ec1924af1bffed37b69a812339084697fd3f3e781074a0148e6475803 \ + --hash=sha256:d1bcd58669e56c08f1e72c5758868b5df169fe267501c949ee83c418e9df9155 \ + --hash=sha256:d275596f840018858757561840767b39272ac96436fcb54f5cac6d245393fd97 \ + --hash=sha256:d2dcf608d35644e8d276d61bf40a93339d8d66a0e5f3e3f75b2c155a421a1b71 \ + --hash=sha256:d4d59776f435564159196d971aa89422ead878174aff8fe18e06d9a0bc6d648c \ + --hash=sha256:d9b6cbc037108ff1a0a867e7670d8513c37f9bcd9ee3d2464411bfabf70ca002 \ + --hash=sha256:db4380d1e69fdad1044a4b8f3bb105200542c49a0dde93452d938ff9db1d6d29 \ + --hash=sha256:e004527ea42a6b99a8b8d5b42b42762c3bdf80f88fbdb5c3a9d47f3808495b86 \ + --hash=sha256:e6eab12c6385526d386543d6823b07187fefba028f0da216506e00f0e1855119 \ + --hash=sha256:eb0642e5f0dd7e86bb358749cc278e70b911e617f519989d346f742dc9520dfb \ + --hash=sha256:f91073049c43d14e66696970dd708d319b86ee57ef9af359294eee072abaac79 \ + --hash=sha256:fadc6e8db7707c861ebe25b13ad6aca19ea4d2c56bf04a26691f46c23dadf6e4 \ + --hash=sha256:fc5af24fcf5fc6f7f40d65446400d45dd12bea933d0299dc9e90c5b22197f1e9 \ + --hash=sha256:fcaf8c911cb29316a02356f89dbc0e0dfcc6a712ace217b6b543805690d2aefd \ + --hash=sha256:ffd4d7cb2e6c6e100e2b39606d38a9ffc934e18593dc9bb326196afc7d93ce3d # via motor python-dateutil==2.9.0.post0 \ --hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \ @@ -407,106 +407,106 @@ rich==13.7.1 \ --hash=sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222 \ --hash=sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432 # via typer -rpds-py==0.18.0 \ - --hash=sha256:01e36a39af54a30f28b73096dd39b6802eddd04c90dbe161c1b8dbe22353189f \ - --hash=sha256:044a3e61a7c2dafacae99d1e722cc2d4c05280790ec5a05031b3876809d89a5c \ - --hash=sha256:08231ac30a842bd04daabc4d71fddd7e6d26189406d5a69535638e4dcb88fe76 \ - --hash=sha256:08f9ad53c3f31dfb4baa00da22f1e862900f45908383c062c27628754af2e88e \ - --hash=sha256:0ab39c1ba9023914297dd88ec3b3b3c3f33671baeb6acf82ad7ce883f6e8e157 \ - --hash=sha256:0af039631b6de0397ab2ba16eaf2872e9f8fca391b44d3d8cac317860a700a3f \ - --hash=sha256:0b8612cd233543a3781bc659c731b9d607de65890085098986dfd573fc2befe5 \ - --hash=sha256:11a8c85ef4a07a7638180bf04fe189d12757c696eb41f310d2426895356dcf05 \ - --hash=sha256:1374f4129f9bcca53a1bba0bb86bf78325a0374577cf7e9e4cd046b1e6f20e24 \ - --hash=sha256:1d4acf42190d449d5e89654d5c1ed3a4f17925eec71f05e2a41414689cda02d1 \ - --hash=sha256:1d9a5be316c15ffb2b3c405c4ff14448c36b4435be062a7f578ccd8b01f0c4d8 \ - --hash=sha256:1df3659d26f539ac74fb3b0c481cdf9d725386e3552c6fa2974f4d33d78e544b \ - --hash=sha256:22806714311a69fd0af9b35b7be97c18a0fc2826e6827dbb3a8c94eac6cf7eeb \ - --hash=sha256:2644e47de560eb7bd55c20fc59f6daa04682655c58d08185a9b95c1970fa1e07 \ - --hash=sha256:2e6d75ab12b0bbab7215e5d40f1e5b738aa539598db27ef83b2ec46747df90e1 \ - --hash=sha256:30f43887bbae0d49113cbaab729a112251a940e9b274536613097ab8b4899cf6 \ - --hash=sha256:34b18ba135c687f4dac449aa5157d36e2cbb7c03cbea4ddbd88604e076aa836e \ - --hash=sha256:36b3ee798c58ace201289024b52788161e1ea133e4ac93fba7d49da5fec0ef9e \ - --hash=sha256:39514da80f971362f9267c600b6d459bfbbc549cffc2cef8e47474fddc9b45b1 \ - --hash=sha256:39f5441553f1c2aed4de4377178ad8ff8f9d733723d6c66d983d75341de265ab \ - --hash=sha256:3a96e0c6a41dcdba3a0a581bbf6c44bb863f27c541547fb4b9711fd8cf0ffad4 \ - --hash=sha256:3f26b5bd1079acdb0c7a5645e350fe54d16b17bfc5e71f371c449383d3342e17 \ - --hash=sha256:41ef53e7c58aa4ef281da975f62c258950f54b76ec8e45941e93a3d1d8580594 \ - --hash=sha256:42821446ee7a76f5d9f71f9e33a4fb2ffd724bb3e7f93386150b61a43115788d \ - --hash=sha256:43fbac5f22e25bee1d482c97474f930a353542855f05c1161fd804c9dc74a09d \ - --hash=sha256:4457a94da0d5c53dc4b3e4de1158bdab077db23c53232f37a3cb7afdb053a4e3 \ - --hash=sha256:465a3eb5659338cf2a9243e50ad9b2296fa15061736d6e26240e713522b6235c \ - --hash=sha256:482103aed1dfe2f3b71a58eff35ba105289b8d862551ea576bd15479aba01f66 \ - --hash=sha256:4832d7d380477521a8c1644bbab6588dfedea5e30a7d967b5fb75977c45fd77f \ - --hash=sha256:4901165d170a5fde6f589acb90a6b33629ad1ec976d4529e769c6f3d885e3e80 \ - --hash=sha256:5307def11a35f5ae4581a0b658b0af8178c65c530e94893345bebf41cc139d33 \ - --hash=sha256:5417558f6887e9b6b65b4527232553c139b57ec42c64570569b155262ac0754f \ - --hash=sha256:56a737287efecafc16f6d067c2ea0117abadcd078d58721f967952db329a3e5c \ - --hash=sha256:586f8204935b9ec884500498ccc91aa869fc652c40c093bd9e1471fbcc25c022 \ - --hash=sha256:5b4e7d8d6c9b2e8ee2d55c90b59c707ca59bc30058269b3db7b1f8df5763557e \ - --hash=sha256:5ddcba87675b6d509139d1b521e0c8250e967e63b5909a7e8f8944d0f90ff36f \ - --hash=sha256:618a3d6cae6ef8ec88bb76dd80b83cfe415ad4f1d942ca2a903bf6b6ff97a2da \ - --hash=sha256:635dc434ff724b178cb192c70016cc0ad25a275228f749ee0daf0eddbc8183b1 \ - --hash=sha256:661d25cbffaf8cc42e971dd570d87cb29a665f49f4abe1f9e76be9a5182c4688 \ - --hash=sha256:66e6a3af5a75363d2c9a48b07cb27c4ea542938b1a2e93b15a503cdfa8490795 \ - --hash=sha256:67071a6171e92b6da534b8ae326505f7c18022c6f19072a81dcf40db2638767c \ - --hash=sha256:685537e07897f173abcf67258bee3c05c374fa6fff89d4c7e42fb391b0605e98 \ - --hash=sha256:69e64831e22a6b377772e7fb337533c365085b31619005802a79242fee620bc1 \ - --hash=sha256:6b0817e34942b2ca527b0e9298373e7cc75f429e8da2055607f4931fded23e20 \ - --hash=sha256:6c81e5f372cd0dc5dc4809553d34f832f60a46034a5f187756d9b90586c2c307 \ - --hash=sha256:6d7faa6f14017c0b1e69f5e2c357b998731ea75a442ab3841c0dbbbfe902d2c4 \ - --hash=sha256:6ef0befbb5d79cf32d0266f5cff01545602344eda89480e1dd88aca964260b18 \ - --hash=sha256:6ef687afab047554a2d366e112dd187b62d261d49eb79b77e386f94644363294 \ - --hash=sha256:7223a2a5fe0d217e60a60cdae28d6949140dde9c3bcc714063c5b463065e3d66 \ - --hash=sha256:77f195baa60a54ef9d2de16fbbfd3ff8b04edc0c0140a761b56c267ac11aa467 \ - --hash=sha256:793968759cd0d96cac1e367afd70c235867831983f876a53389ad869b043c948 \ - --hash=sha256:7bd339195d84439cbe5771546fe8a4e8a7a045417d8f9de9a368c434e42a721e \ - --hash=sha256:7cd863afe7336c62ec78d7d1349a2f34c007a3cc6c2369d667c65aeec412a5b1 \ - --hash=sha256:7f2facbd386dd60cbbf1a794181e6aa0bd429bd78bfdf775436020172e2a23f0 \ - --hash=sha256:84ffab12db93b5f6bad84c712c92060a2d321b35c3c9960b43d08d0f639d60d7 \ - --hash=sha256:8c8370641f1a7f0e0669ddccca22f1da893cef7628396431eb445d46d893e5cd \ - --hash=sha256:8db715ebe3bb7d86d77ac1826f7d67ec11a70dbd2376b7cc214199360517b641 \ - --hash=sha256:8e8916ae4c720529e18afa0b879473049e95949bf97042e938530e072fde061d \ - --hash=sha256:8f03bccbd8586e9dd37219bce4d4e0d3ab492e6b3b533e973fa08a112cb2ffc9 \ - --hash=sha256:8f2fc11e8fe034ee3c34d316d0ad8808f45bc3b9ce5857ff29d513f3ff2923a1 \ - --hash=sha256:923d39efa3cfb7279a0327e337a7958bff00cc447fd07a25cddb0a1cc9a6d2da \ - --hash=sha256:93df1de2f7f7239dc9cc5a4a12408ee1598725036bd2dedadc14d94525192fc3 \ - --hash=sha256:998e33ad22dc7ec7e030b3df701c43630b5bc0d8fbc2267653577e3fec279afa \ - --hash=sha256:99f70b740dc04d09e6b2699b675874367885217a2e9f782bdf5395632ac663b7 \ - --hash=sha256:9a00312dea9310d4cb7dbd7787e722d2e86a95c2db92fbd7d0155f97127bcb40 \ - --hash=sha256:9d54553c1136b50fd12cc17e5b11ad07374c316df307e4cfd6441bea5fb68496 \ - --hash=sha256:9dbbeb27f4e70bfd9eec1be5477517365afe05a9b2c441a0b21929ee61048124 \ - --hash=sha256:a1ce3ba137ed54f83e56fb983a5859a27d43a40188ba798993812fed73c70836 \ - --hash=sha256:a34d557a42aa28bd5c48a023c570219ba2593bcbbb8dc1b98d8cf5d529ab1434 \ - --hash=sha256:a5f446dd5055667aabaee78487f2b5ab72e244f9bc0b2ffebfeec79051679984 \ - --hash=sha256:ad36cfb355e24f1bd37cac88c112cd7730873f20fb0bdaf8ba59eedf8216079f \ - --hash=sha256:aec493917dd45e3c69d00a8874e7cbed844efd935595ef78a0f25f14312e33c6 \ - --hash=sha256:b316144e85316da2723f9d8dc75bada12fa58489a527091fa1d5a612643d1a0e \ - --hash=sha256:b34ae4636dfc4e76a438ab826a0d1eed2589ca7d9a1b2d5bb546978ac6485461 \ - --hash=sha256:b34b7aa8b261c1dbf7720b5d6f01f38243e9b9daf7e6b8bc1fd4657000062f2c \ - --hash=sha256:bc362ee4e314870a70f4ae88772d72d877246537d9f8cb8f7eacf10884862432 \ - --hash=sha256:bed88b9a458e354014d662d47e7a5baafd7ff81c780fd91584a10d6ec842cb73 \ - --hash=sha256:c0013fe6b46aa496a6749c77e00a3eb07952832ad6166bd481c74bda0dcb6d58 \ - --hash=sha256:c0b5dcf9193625afd8ecc92312d6ed78781c46ecbf39af9ad4681fc9f464af88 \ - --hash=sha256:c4325ff0442a12113a6379af66978c3fe562f846763287ef66bdc1d57925d337 \ - --hash=sha256:c463ed05f9dfb9baebef68048aed8dcdc94411e4bf3d33a39ba97e271624f8f7 \ - --hash=sha256:c8362467a0fdeccd47935f22c256bec5e6abe543bf0d66e3d3d57a8fb5731863 \ - --hash=sha256:cd5bf1af8efe569654bbef5a3e0a56eca45f87cfcffab31dd8dde70da5982475 \ - --hash=sha256:cf1ea2e34868f6fbf070e1af291c8180480310173de0b0c43fc38a02929fc0e3 \ - --hash=sha256:d62dec4976954a23d7f91f2f4530852b0c7608116c257833922a896101336c51 \ - --hash=sha256:d68c93e381010662ab873fea609bf6c0f428b6d0bb00f2c6939782e0818d37bf \ - --hash=sha256:d7c36232a90d4755b720fbd76739d8891732b18cf240a9c645d75f00639a9024 \ - --hash=sha256:dd18772815d5f008fa03d2b9a681ae38d5ae9f0e599f7dda233c439fcaa00d40 \ - --hash=sha256:ddc2f4dfd396c7bfa18e6ce371cba60e4cf9d2e5cdb71376aa2da264605b60b9 \ - --hash=sha256:e003b002ec72c8d5a3e3da2989c7d6065b47d9eaa70cd8808b5384fbb970f4ec \ - --hash=sha256:e32a92116d4f2a80b629778280103d2a510a5b3f6314ceccd6e38006b5e92dcb \ - --hash=sha256:e4461d0f003a0aa9be2bdd1b798a041f177189c1a0f7619fe8c95ad08d9a45d7 \ - --hash=sha256:e541ec6f2ec456934fd279a3120f856cd0aedd209fc3852eca563f81738f6861 \ - --hash=sha256:e546e768d08ad55b20b11dbb78a745151acbd938f8f00d0cfbabe8b0199b9880 \ - --hash=sha256:ea7d4a99f3b38c37eac212dbd6ec42b7a5ec51e2c74b5d3223e43c811609e65f \ - --hash=sha256:ed4eb745efbff0a8e9587d22a84be94a5eb7d2d99c02dacf7bd0911713ed14dd \ - --hash=sha256:f8a2f084546cc59ea99fda8e070be2fd140c3092dc11524a71aa8f0f3d5a55ca \ - --hash=sha256:fcb25daa9219b4cf3a0ab24b0eb9a5cc8949ed4dc72acb8fa16b7e1681aa3c58 \ - --hash=sha256:fdea4952db2793c4ad0bdccd27c1d8fdd1423a92f04598bc39425bcc2b8ee46e +rpds-py==0.18.1 \ + --hash=sha256:05f3d615099bd9b13ecf2fc9cf2d839ad3f20239c678f461c753e93755d629ee \ + --hash=sha256:06d218939e1bf2ca50e6b0ec700ffe755e5216a8230ab3e87c059ebb4ea06afc \ + --hash=sha256:07f2139741e5deb2c5154a7b9629bc5aa48c766b643c1a6750d16f865a82c5fc \ + --hash=sha256:08d74b184f9ab6289b87b19fe6a6d1a97fbfea84b8a3e745e87a5de3029bf944 \ + --hash=sha256:0abeee75434e2ee2d142d650d1e54ac1f8b01e6e6abdde8ffd6eeac6e9c38e20 \ + --hash=sha256:154bf5c93d79558b44e5b50cc354aa0459e518e83677791e6adb0b039b7aa6a7 \ + --hash=sha256:17c6d2155e2423f7e79e3bb18151c686d40db42d8645e7977442170c360194d4 \ + --hash=sha256:1805d5901779662d599d0e2e4159d8a82c0b05faa86ef9222bf974572286b2b6 \ + --hash=sha256:19ba472b9606c36716062c023afa2484d1e4220548751bda14f725a7de17b4f6 \ + --hash=sha256:19e515b78c3fc1039dd7da0a33c28c3154458f947f4dc198d3c72db2b6b5dc93 \ + --hash=sha256:1d54f74f40b1f7aaa595a02ff42ef38ca654b1469bef7d52867da474243cc633 \ + --hash=sha256:207c82978115baa1fd8d706d720b4a4d2b0913df1c78c85ba73fe6c5804505f0 \ + --hash=sha256:2625f03b105328729f9450c8badda34d5243231eef6535f80064d57035738360 \ + --hash=sha256:27bba383e8c5231cd559affe169ca0b96ec78d39909ffd817f28b166d7ddd4d8 \ + --hash=sha256:2c3caec4ec5cd1d18e5dd6ae5194d24ed12785212a90b37f5f7f06b8bedd7139 \ + --hash=sha256:2cc7c1a47f3a63282ab0f422d90ddac4aa3034e39fc66a559ab93041e6505da7 \ + --hash=sha256:2fc24a329a717f9e2448f8cd1f960f9dac4e45b6224d60734edeb67499bab03a \ + --hash=sha256:312fe69b4fe1ffbe76520a7676b1e5ac06ddf7826d764cc10265c3b53f96dbe9 \ + --hash=sha256:32b7daaa3e9389db3695964ce8e566e3413b0c43e3394c05e4b243a4cd7bef26 \ + --hash=sha256:338dee44b0cef8b70fd2ef54b4e09bb1b97fc6c3a58fea5db6cc083fd9fc2724 \ + --hash=sha256:352a88dc7892f1da66b6027af06a2e7e5d53fe05924cc2cfc56495b586a10b72 \ + --hash=sha256:35b2b771b13eee8729a5049c976197ff58a27a3829c018a04341bcf1ae409b2b \ + --hash=sha256:38e14fb4e370885c4ecd734f093a2225ee52dc384b86fa55fe3f74638b2cfb09 \ + --hash=sha256:3c20f05e8e3d4fc76875fc9cb8cf24b90a63f5a1b4c5b9273f0e8225e169b100 \ + --hash=sha256:3dd3cd86e1db5aadd334e011eba4e29d37a104b403e8ca24dcd6703c68ca55b3 \ + --hash=sha256:489bdfe1abd0406eba6b3bb4fdc87c7fa40f1031de073d0cfb744634cc8fa261 \ + --hash=sha256:48c2faaa8adfacefcbfdb5f2e2e7bdad081e5ace8d182e5f4ade971f128e6bb3 \ + --hash=sha256:4a98a1f0552b5f227a3d6422dbd61bc6f30db170939bd87ed14f3c339aa6c7c9 \ + --hash=sha256:4adec039b8e2928983f885c53b7cc4cda8965b62b6596501a0308d2703f8af1b \ + --hash=sha256:4e0ee01ad8260184db21468a6e1c37afa0529acc12c3a697ee498d3c2c4dcaf3 \ + --hash=sha256:51584acc5916212e1bf45edd17f3a6b05fe0cbb40482d25e619f824dccb679de \ + --hash=sha256:531796fb842b53f2695e94dc338929e9f9dbf473b64710c28af5a160b2a8927d \ + --hash=sha256:5463c47c08630007dc0fe99fb480ea4f34a89712410592380425a9b4e1611d8e \ + --hash=sha256:5c45a639e93a0c5d4b788b2613bd637468edd62f8f95ebc6fcc303d58ab3f0a8 \ + --hash=sha256:6031b25fb1b06327b43d841f33842b383beba399884f8228a6bb3df3088485ff \ + --hash=sha256:607345bd5912aacc0c5a63d45a1f73fef29e697884f7e861094e443187c02be5 \ + --hash=sha256:618916f5535784960f3ecf8111581f4ad31d347c3de66d02e728de460a46303c \ + --hash=sha256:636a15acc588f70fda1661234761f9ed9ad79ebed3f2125d44be0862708b666e \ + --hash=sha256:673fdbbf668dd958eff750e500495ef3f611e2ecc209464f661bc82e9838991e \ + --hash=sha256:6afd80f6c79893cfc0574956f78a0add8c76e3696f2d6a15bca2c66c415cf2d4 \ + --hash=sha256:6b5ff7e1d63a8281654b5e2896d7f08799378e594f09cf3674e832ecaf396ce8 \ + --hash=sha256:6c4c4c3f878df21faf5fac86eda32671c27889e13570645a9eea0a1abdd50922 \ + --hash=sha256:6cd8098517c64a85e790657e7b1e509b9fe07487fd358e19431cb120f7d96338 \ + --hash=sha256:6d1e42d2735d437e7e80bab4d78eb2e459af48c0a46e686ea35f690b93db792d \ + --hash=sha256:6e30ac5e329098903262dc5bdd7e2086e0256aa762cc8b744f9e7bf2a427d3f8 \ + --hash=sha256:70a838f7754483bcdc830444952fd89645569e7452e3226de4a613a4c1793fb2 \ + --hash=sha256:720edcb916df872d80f80a1cc5ea9058300b97721efda8651efcd938a9c70a72 \ + --hash=sha256:732672fbc449bab754e0b15356c077cc31566df874964d4801ab14f71951ea80 \ + --hash=sha256:740884bc62a5e2bbb31e584f5d23b32320fd75d79f916f15a788d527a5e83644 \ + --hash=sha256:7700936ef9d006b7ef605dc53aa364da2de5a3aa65516a1f3ce73bf82ecfc7ae \ + --hash=sha256:7732770412bab81c5a9f6d20aeb60ae943a9b36dcd990d876a773526468e7163 \ + --hash=sha256:7750569d9526199c5b97e5a9f8d96a13300950d910cf04a861d96f4273d5b104 \ + --hash=sha256:7f1944ce16401aad1e3f7d312247b3d5de7981f634dc9dfe90da72b87d37887d \ + --hash=sha256:81c5196a790032e0fc2464c0b4ab95f8610f96f1f2fa3d4deacce6a79852da60 \ + --hash=sha256:8352f48d511de5f973e4f2f9412736d7dea76c69faa6d36bcf885b50c758ab9a \ + --hash=sha256:8927638a4d4137a289e41d0fd631551e89fa346d6dbcfc31ad627557d03ceb6d \ + --hash=sha256:8c7672e9fba7425f79019db9945b16e308ed8bc89348c23d955c8c0540da0a07 \ + --hash=sha256:8d2e182c9ee01135e11e9676e9a62dfad791a7a467738f06726872374a83db49 \ + --hash=sha256:910e71711d1055b2768181efa0a17537b2622afeb0424116619817007f8a2b10 \ + --hash=sha256:942695a206a58d2575033ff1e42b12b2aece98d6003c6bc739fbf33d1773b12f \ + --hash=sha256:9437ca26784120a279f3137ee080b0e717012c42921eb07861b412340f85bae2 \ + --hash=sha256:967342e045564cef76dfcf1edb700b1e20838d83b1aa02ab313e6a497cf923b8 \ + --hash=sha256:998125738de0158f088aef3cb264a34251908dd2e5d9966774fdab7402edfab7 \ + --hash=sha256:9e6934d70dc50f9f8ea47081ceafdec09245fd9f6032669c3b45705dea096b88 \ + --hash=sha256:a3d456ff2a6a4d2adcdf3c1c960a36f4fd2fec6e3b4902a42a384d17cf4e7a65 \ + --hash=sha256:a7b28c5b066bca9a4eb4e2f2663012debe680f097979d880657f00e1c30875a0 \ + --hash=sha256:a888e8bdb45916234b99da2d859566f1e8a1d2275a801bb8e4a9644e3c7e7909 \ + --hash=sha256:aa3679e751408d75a0b4d8d26d6647b6d9326f5e35c00a7ccd82b78ef64f65f8 \ + --hash=sha256:aaa71ee43a703c321906813bb252f69524f02aa05bf4eec85f0c41d5d62d0f4c \ + --hash=sha256:b646bf655b135ccf4522ed43d6902af37d3f5dbcf0da66c769a2b3938b9d8184 \ + --hash=sha256:b906b5f58892813e5ba5c6056d6a5ad08f358ba49f046d910ad992196ea61397 \ + --hash=sha256:b9bb1f182a97880f6078283b3505a707057c42bf55d8fca604f70dedfdc0772a \ + --hash=sha256:bd1105b50ede37461c1d51b9698c4f4be6e13e69a908ab7751e3807985fc0346 \ + --hash=sha256:bf18932d0003c8c4d51a39f244231986ab23ee057d235a12b2684ea26a353590 \ + --hash=sha256:c273e795e7a0f1fddd46e1e3cb8be15634c29ae8ff31c196debb620e1edb9333 \ + --hash=sha256:c69882964516dc143083d3795cb508e806b09fc3800fd0d4cddc1df6c36e76bb \ + --hash=sha256:c827576e2fa017a081346dce87d532a5310241648eb3700af9a571a6e9fc7e74 \ + --hash=sha256:cbfbea39ba64f5e53ae2915de36f130588bba71245b418060ec3330ebf85678e \ + --hash=sha256:ce0bb20e3a11bd04461324a6a798af34d503f8d6f1aa3d2aa8901ceaf039176d \ + --hash=sha256:d0cee71bc618cd93716f3c1bf56653740d2d13ddbd47673efa8bf41435a60daa \ + --hash=sha256:d21be4770ff4e08698e1e8e0bce06edb6ea0626e7c8f560bc08222880aca6a6f \ + --hash=sha256:d31dea506d718693b6b2cffc0648a8929bdc51c70a311b2770f09611caa10d53 \ + --hash=sha256:d44607f98caa2961bab4fa3c4309724b185b464cdc3ba6f3d7340bac3ec97cc1 \ + --hash=sha256:d58ad6317d188c43750cb76e9deacf6051d0f884d87dc6518e0280438648a9ac \ + --hash=sha256:d70129cef4a8d979caa37e7fe957202e7eee8ea02c5e16455bc9808a59c6b2f0 \ + --hash=sha256:d85164315bd68c0806768dc6bb0429c6f95c354f87485ee3593c4f6b14def2bd \ + --hash=sha256:d960de62227635d2e61068f42a6cb6aae91a7fe00fca0e3aeed17667c8a34611 \ + --hash=sha256:dc48b479d540770c811fbd1eb9ba2bb66951863e448efec2e2c102625328e92f \ + --hash=sha256:e1735502458621921cee039c47318cb90b51d532c2766593be6207eec53e5c4c \ + --hash=sha256:e2be6e9dd4111d5b31ba3b74d17da54a8319d8168890fbaea4b9e5c3de630ae5 \ + --hash=sha256:e4c39ad2f512b4041343ea3c7894339e4ca7839ac38ca83d68a832fc8b3748ab \ + --hash=sha256:ed402d6153c5d519a0faf1bb69898e97fb31613b49da27a84a13935ea9164dfc \ + --hash=sha256:ee17cd26b97d537af8f33635ef38be873073d516fd425e80559f4585a7b90c43 \ + --hash=sha256:f3027be483868c99b4985fda802a57a67fdf30c5d9a50338d9db646d590198da \ + --hash=sha256:f5bab211605d91db0e2995a17b5c6ee5edec1270e46223e513eaa20da20076ac \ + --hash=sha256:f6f8e3fecca256fefc91bb6765a693d96692459d7d4c644660a9fff32e517843 \ + --hash=sha256:f7afbfee1157e0f9376c00bb232e80a60e59ed716e3211a80cb8506550671e6e \ + --hash=sha256:fa242ac1ff583e4ec7771141606aafc92b361cd90a05c30d93e343a0c2d82a89 \ + --hash=sha256:fab6ce90574645a0d6c58890e9bcaac8d94dff54fb51c69e5522a7358b80ab64 # via # jsonschema # referencing diff --git a/src/nos/core/models.py b/src/nos/core/models.py deleted file mode 100644 index a7b4595..0000000 --- a/src/nos/core/models.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright 2021 - 2024 Universität Tübingen, DKFZ, EMBL, and Universität zu Köln -# for the German Human Genome-Phenome Archive (GHGA) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -"""Contains models relevant to the core domain""" - -from enum import Enum - -from pydantic import BaseModel, EmailStr, Field - - -class AcademicTitle(str, Enum): - """Academic title""" - - DR = "Dr." - PROF = "Prof." - - -class BaseDto(BaseModel): - """Base model pre-configured for use as Dto.""" - - model_config = {"extra": "forbid", "frozen": True} - - -class UserData(BaseDto): - """Basic data of a user""" - - name: str = Field( - default=..., - description="Full name of the user", - examples=["Rosalind Franklin"], - ) - title: AcademicTitle | None = Field( - default=None, title="Academic title", description="Academic title of the user" - ) - email: EmailStr = Field( - default=..., - description="Preferred e-mail address of the user", - examples=["user@home.org"], - ) - - -class User(UserData): - """Complete user model with ID""" - - id: str = Field(default=..., description="Internally used ID") # actually UUID diff --git a/src/nos/core/orchestrator.py b/src/nos/core/orchestrator.py index 54c2775..6ecc76f 100644 --- a/src/nos/core/orchestrator.py +++ b/src/nos/core/orchestrator.py @@ -24,7 +24,6 @@ from nos.config import Config from nos.core import notifications -from nos.core.models import User from nos.ports.inbound.orchestrator import OrchestratorPort from nos.ports.outbound.dao import ResourceNotFoundError, UserDaoPort from nos.ports.outbound.notification_emitter import NotificationEmitterPort @@ -79,7 +78,9 @@ async def process_access_request_notification( await method_map[event_type](user=user, dataset_id=dataset_id) - async def _access_request_created(self, *, user: User, dataset_id: str): + async def _access_request_created( + self, *, user: event_schemas.User, dataset_id: str + ): """Processes an Access Request Created event. One notification is sent to the data requester to confirm that their request @@ -112,7 +113,9 @@ async def _access_request_created(self, *, user: User, dataset_id: str): ) log.info("Sent Access Request Created notification to data steward") - async def _access_request_allowed(self, *, user: User, dataset_id: str): + async def _access_request_allowed( + self, *, user: event_schemas.User, dataset_id: str + ): """Process an Access Request Allowed event. One notification is sent to the data requester to inform them that the request @@ -146,7 +149,9 @@ async def _access_request_allowed(self, *, user: User, dataset_id: str): ) log.info("Sent Access Request Allowed notification to data steward") - async def _access_request_denied(self, *, user: User, dataset_id: str): + async def _access_request_denied( + self, *, user: event_schemas.User, dataset_id: str + ): """Process an Access Request Denied event. One notification is sent to the data requester telling them that the request @@ -189,7 +194,7 @@ async def process_file_registered_notification(self, *, file_id: str): ) log.info("Sent File Upload Completed notification to data steward") - async def _iva_code_requested(self, *, user: User): + async def _iva_code_requested(self, *, user: event_schemas.User): """Send notifications relaying that an IVA code has been requested. One notification is sent to the user to confirm that their request was received. @@ -212,7 +217,7 @@ async def _iva_code_requested(self, *, user: User): ), ) - async def _iva_code_transmitted(self, *, user: User): + async def _iva_code_transmitted(self, *, user: event_schemas.User): """Send a notification that an IVA code has been transmitted to the user.""" await self._notification_emitter.notify( email=user.email, @@ -220,7 +225,7 @@ async def _iva_code_transmitted(self, *, user: User): notification=notifications.IVA_CODE_TRANSMITTED_TO_USER, ) - async def _iva_code_validated(self, *, user: User): + async def _iva_code_validated(self, *, user: event_schemas.User): """Send a notification to the data steward that an IVA code has been validated.""" await self._notification_emitter.notify( email=self._config.central_data_stewardship_email, @@ -234,7 +239,7 @@ async def _iva_unverified( self, *, iva_type: str, - user: User, + user: event_schemas.User, ): """Send notifications for IVAs set to 'unverified'. diff --git a/src/nos/ports/outbound/dao.py b/src/nos/ports/outbound/dao.py index ab61826..d71f057 100644 --- a/src/nos/ports/outbound/dao.py +++ b/src/nos/ports/outbound/dao.py @@ -16,11 +16,10 @@ """DAO interface for accessing the database.""" +from ghga_event_schemas import pydantic_ as event_schemas from hexkit.protocols.dao import DaoNaturalId, ResourceNotFoundError -from nos.core import models - __all__ = ["UserDaoPort", "ResourceNotFoundError"] # ports described by type aliases: -UserDaoPort = DaoNaturalId[models.User] +UserDaoPort = DaoNaturalId[event_schemas.User] diff --git a/src/nos/translators/outbound/dao.py b/src/nos/translators/outbound/dao.py index 3b3027a..9b7d322 100644 --- a/src/nos/translators/outbound/dao.py +++ b/src/nos/translators/outbound/dao.py @@ -16,9 +16,9 @@ """DAO translator constructor""" +from ghga_event_schemas import pydantic_ as event_schemas from hexkit.protocols.dao import DaoFactoryProtocol -from nos.core import models from nos.ports.outbound.dao import UserDaoPort @@ -26,6 +26,6 @@ async def user_dao_factory(*, dao_factory: DaoFactoryProtocol) -> UserDaoPort: """Construct a UserDaoPort from the provided dao_factory""" return await dao_factory.get_dao( name="users", - dto_model=models.User, + dto_model=event_schemas.User, id_field="id", ) diff --git a/tests/conftest.py b/tests/conftest.py index a6fa703..7bc99f9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -16,17 +16,20 @@ """Test-suite-wide fixture declaration.""" import pytest_asyncio +from ghga_event_schemas import pydantic_ as event_schemas from hexkit.providers.akafka.testutils import get_kafka_fixture from hexkit.providers.mongodb.testutils import get_mongodb_fixture -from nos.core.models import AcademicTitle, User from tests.fixtures.joint import JointFixture, get_joint_fixture mongodb_fixture = get_mongodb_fixture(scope="module") kafka_fixture = get_kafka_fixture(scope="module") joint_fixture = get_joint_fixture(scope="module") -TEST_USER = User( - id="test", name="test user", title=AcademicTitle.DR, email="test@test.abc" +TEST_USER = event_schemas.User( + user_id="test_id", + name="test user", + title=event_schemas.AcademicTitle.DR, + email="test@test.abc", ) @@ -40,4 +43,4 @@ async def insert_test_data(joint_fixture: JointFixture): """ await joint_fixture.user_dao.insert(TEST_USER) yield - await joint_fixture.user_dao.delete(id_=TEST_USER.id) + await joint_fixture.user_dao.delete(id_=TEST_USER.user_id) From 5318ee1a669fcf92de840542f07208206ef9944a Mon Sep 17 00:00:00 2001 From: TheByronHimes Date: Fri, 10 May 2024 10:51:43 +0000 Subject: [PATCH 02/11] Add the outbox subscriber --- .devcontainer/.dev_config.yaml | 1 + config_schema.json | 9 +++++ example_config.yaml | 1 + src/nos/config.py | 6 ++- src/nos/core/notifications.py | 10 +++++ src/nos/core/orchestrator.py | 48 ++++++++++++++++++++++++ src/nos/inject.py | 35 ++++++++++++++++- src/nos/main.py | 19 ++++++++-- src/nos/ports/inbound/orchestrator.py | 19 ++++++++++ src/nos/translators/inbound/event_sub.py | 38 +++++++++++++++++++ src/nos/translators/outbound/dao.py | 2 +- tests/fixtures/test_config.yaml | 1 + 12 files changed, 182 insertions(+), 7 deletions(-) diff --git a/.devcontainer/.dev_config.yaml b/.devcontainer/.dev_config.yaml index 9b525e4..4fc929a 100644 --- a/.devcontainer/.dev_config.yaml +++ b/.devcontainer/.dev_config.yaml @@ -13,3 +13,4 @@ file_registered_event_topic: internal_file_registry file_registered_event_type: file_registered iva_events_topic: ivas iva_state_changed_event_type: iva_state_changed +user_data_event_topic: user_events diff --git a/config_schema.json b/config_schema.json index 88056cf..1cc3791 100644 --- a/config_schema.json +++ b/config_schema.json @@ -36,6 +36,14 @@ "title": "Notification Event Type", "type": "string" }, + "user_data_event_topic": { + "description": "The name of the topic containing user data events.", + "examples": [ + "user_data_events" + ], + "title": "User Data Event Topic", + "type": "string" + }, "access_request_events_topic": { "description": "Name of the event topic used to consume access request events", "examples": [ @@ -215,6 +223,7 @@ "db_name", "notification_event_topic", "notification_event_type", + "user_data_event_topic", "access_request_events_topic", "access_request_created_event_type", "access_request_allowed_event_type", diff --git a/example_config.yaml b/example_config.yaml index 00082ca..f298920 100644 --- a/example_config.yaml +++ b/example_config.yaml @@ -23,3 +23,4 @@ notification_event_topic: notification_events notification_event_type: notification service_instance_id: '1' service_name: nos +user_data_event_topic: user_events diff --git a/src/nos/config.py b/src/nos/config.py index 2b40fac..5864625 100644 --- a/src/nos/config.py +++ b/src/nos/config.py @@ -21,7 +21,10 @@ from hexkit.providers.mongodb import MongoDbConfig from pydantic import Field -from nos.translators.inbound.event_sub import EventSubTranslatorConfig +from nos.translators.inbound.event_sub import ( + EventSubTranslatorConfig, + OutboxSubTranslatorConfig, +) from nos.translators.outbound.event_pub import NotificationEmitterConfig SERVICE_NAME: str = "nos" @@ -32,6 +35,7 @@ class Config( LoggingConfig, KafkaConfig, EventSubTranslatorConfig, + OutboxSubTranslatorConfig, NotificationEmitterConfig, MongoDbConfig, ): diff --git a/src/nos/core/notifications.py b/src/nos/core/notifications.py index a6a17b1..66b3d04 100644 --- a/src/nos/core/notifications.py +++ b/src/nos/core/notifications.py @@ -187,3 +187,13 @@ def formatted(self, **kwargs) -> "Notification": The specified contact email address is: {email}. """, ) + +USER_REREGISTERED_TO_USER = Notification( + "Account Details Changed", + """ +Your account details were recently updated. The changed details include: {changed_details}. + +If you did not make the following changes or have +please contact the GHGA immediately at {support_email}. +""", +) diff --git a/src/nos/core/orchestrator.py b/src/nos/core/orchestrator.py index 6ecc76f..6de2ef2 100644 --- a/src/nos/core/orchestrator.py +++ b/src/nos/core/orchestrator.py @@ -18,6 +18,7 @@ import logging from collections.abc import Callable +from contextlib import suppress from functools import partial from ghga_event_schemas import pydantic_ as event_schemas @@ -325,3 +326,50 @@ async def process_iva_state_change(self, *, user_iva: event_schemas.UserIvaState raise error from err await method_map[user_iva.state][0](user=user) + + def _changed_info( + self, existing_user: event_schemas.User, new_user: event_schemas.User + ) -> str: + """Check if critical user information has changed. + + Critical information includes the user's email address and name. + """ + changed = [] + for field in ["email", "name"]: + if getattr(existing_user, field) != getattr(new_user, field): + changed.append(field) + return " and ".join(changed) + + async def upsert_user_data( + self, resource_id: str, update: event_schemas.User + ) -> None: + """Upsert the user data. + + This method will also examine the user data and send out notifications for + user re-registration. + """ + with suppress(ResourceNotFoundError): + existing_user = await self._user_dao.get_by_id(resource_id) + if changed_details := self._changed_info(existing_user, update): + await self._notification_emitter.notify( + email=existing_user.email, + full_name=existing_user.name, + notification=notifications.USER_REREGISTERED_TO_USER.formatted( + support_email=self._config.central_data_stewardship_email, + changed_details=changed_details, + ), + ) + log.info("Sent User Re-registered notification to user") + await self._user_dao.upsert(dto=update) + + async def delete_user_data(self, resource_id: str) -> None: + """Delete the user data. + + In the case that the user ID does not exist in the database, this method will + log the fact but not raise an error. + """ + try: + await self._user_dao.delete(id_=resource_id) + except ResourceNotFoundError: + # do not raise an error if the user is not found, just log it. + log.warning("User not found for deletion", extra={"user_id": resource_id}) diff --git a/src/nos/inject.py b/src/nos/inject.py index a7c57ca..21631e9 100644 --- a/src/nos/inject.py +++ b/src/nos/inject.py @@ -19,13 +19,20 @@ from contextlib import asynccontextmanager from ghga_service_commons.utils.context import asyncnullcontext -from hexkit.providers.akafka import KafkaEventPublisher, KafkaEventSubscriber +from hexkit.providers.akafka import ( + KafkaEventPublisher, + KafkaEventSubscriber, + KafkaOutboxSubscriber, +) from hexkit.providers.mongodb import MongoDbDaoFactory from nos.config import Config from nos.core.orchestrator import Orchestrator from nos.ports.inbound.orchestrator import OrchestratorPort -from nos.translators.inbound.event_sub import EventSubTranslator +from nos.translators.inbound.event_sub import ( + EventSubTranslator, + OutboxSubTranslator, +) from nos.translators.outbound.dao import user_dao_factory from nos.translators.outbound.event_pub import NotificationEmitter @@ -87,3 +94,27 @@ async def prepare_event_subscriber( config=config, translator=event_sub_translator ) as event_subscriber: yield event_subscriber + + +@asynccontextmanager +async def prepare_outbox_subscriber( + *, + config: Config, + core_override: OrchestratorPort | None = None, +) -> AsyncGenerator[KafkaOutboxSubscriber, None]: + """Construct and initialize an outbox subscriber with all its dependencies. + By default, the core dependencies are automatically prepared but you can also + provide them using the override parameter. + """ + async with prepare_core_with_override( + config=config, core_override=core_override + ) as orchestrator: + outbox_sub_translator = OutboxSubTranslator( + orchestrator=orchestrator, + config=config, + ) + + async with KafkaOutboxSubscriber.construct( + config=config, translators=[outbox_sub_translator] + ) as outbox_subscriber: + yield outbox_subscriber diff --git a/src/nos/main.py b/src/nos/main.py index 2a5bdb0..c8e04dc 100644 --- a/src/nos/main.py +++ b/src/nos/main.py @@ -15,10 +15,13 @@ # """Top-level functions for the service""" +import asyncio +import asyncio.taskgroups + from hexkit.log import configure_logging from nos.config import Config -from nos.inject import prepare_event_subscriber +from nos.inject import prepare_event_subscriber, prepare_outbox_subscriber async def consume_events(run_forever: bool = True): @@ -27,5 +30,15 @@ async def consume_events(run_forever: bool = True): configure_logging(config=config) - async with prepare_event_subscriber(config=config) as event_subscriber: - await event_subscriber.run(forever=run_forever) + async with asyncio.taskgroups.TaskGroup() as tg: + # Run the event consumer + async with prepare_event_subscriber(config=config) as event_subscriber: + tg.create_task( + event_subscriber.run(forever=run_forever), name="events_task" + ) + + # Run the outbox consumer + async with prepare_outbox_subscriber(config=config) as outbox_subscriber: + tg.create_task( + outbox_subscriber.run(forever=run_forever), name="outbox_task" + ) diff --git a/src/nos/ports/inbound/orchestrator.py b/src/nos/ports/inbound/orchestrator.py index 44c2602..d8d3386 100644 --- a/src/nos/ports/inbound/orchestrator.py +++ b/src/nos/ports/inbound/orchestrator.py @@ -66,3 +66,22 @@ async def process_all_ivas_invalidated(self, *, user_id: str): @abstractmethod async def process_iva_state_change(self, *, user_iva: event_schemas.UserIvaState): """Handle notifications for IVA state changes.""" + + @abstractmethod + async def upsert_user_data( + self, resource_id: str, update: event_schemas.User + ) -> None: + """Upsert the user data. + + This method will also examine the user data and send out notifications for the + following: + - User re-registration + """ + + @abstractmethod + async def delete_user_data(self, resource_id: str) -> None: + """Delete the user data. + + In the case that the user ID does not exist in the database, this method will + log the fact but not raise an error. + """ diff --git a/src/nos/translators/inbound/event_sub.py b/src/nos/translators/inbound/event_sub.py index 52c87c6..767afd3 100644 --- a/src/nos/translators/inbound/event_sub.py +++ b/src/nos/translators/inbound/event_sub.py @@ -18,6 +18,7 @@ from ghga_event_schemas import pydantic_ as event_schemas from ghga_event_schemas.validation import get_validated_payload from hexkit.custom_types import Ascii, JsonObject +from hexkit.protocols.daosub import DaoSubscriberProtocol from hexkit.protocols.eventsub import EventSubscriberProtocol from pydantic import Field from pydantic_settings import BaseSettings @@ -141,3 +142,40 @@ async def _consume_validated( await self._handle_all_ivas_reset(payload=payload) else: await self._handle_iva_state_change(payload=payload) + + +class OutboxSubTranslatorConfig(BaseSettings): + """Config for the outbox subscriber""" + + user_data_event_topic: str = Field( + default=..., + description="The name of the topic containing user data events.", + examples=["user_data_events"], + ) + + +class OutboxSubTranslator(DaoSubscriberProtocol[event_schemas.User]): + """A class that consumes events conveying changes in DB resources.""" + + event_topic: str + dto_model = event_schemas.User + + def __init__( + self, + *, + config: OutboxSubTranslatorConfig, + orchestrator: OrchestratorPort, + ): + self._config = config + self._orchestrator = orchestrator + self.event_topic = config.user_data_event_topic + + async def changed(self, resource_id: str, update: event_schemas.User) -> None: + """Consume change event (created or updated) for user data.""" + await self._orchestrator.upsert_user_data( + resource_id=resource_id, update=update + ) + + async def deleted(self, resource_id: str) -> None: + """Consume event indicating the deletion of a user.""" + await self._orchestrator.delete_user_data(resource_id=resource_id) diff --git a/src/nos/translators/outbound/dao.py b/src/nos/translators/outbound/dao.py index 9b7d322..5208b12 100644 --- a/src/nos/translators/outbound/dao.py +++ b/src/nos/translators/outbound/dao.py @@ -27,5 +27,5 @@ async def user_dao_factory(*, dao_factory: DaoFactoryProtocol) -> UserDaoPort: return await dao_factory.get_dao( name="users", dto_model=event_schemas.User, - id_field="id", + id_field="user_id", ) diff --git a/tests/fixtures/test_config.yaml b/tests/fixtures/test_config.yaml index 9b525e4..4fc929a 100644 --- a/tests/fixtures/test_config.yaml +++ b/tests/fixtures/test_config.yaml @@ -13,3 +13,4 @@ file_registered_event_topic: internal_file_registry file_registered_event_type: file_registered iva_events_topic: ivas iva_state_changed_event_type: iva_state_changed +user_data_event_topic: user_events From 739b5df3162bc524440bd1c4dc96c644d4d6d202 Mon Sep 17 00:00:00 2001 From: TheByronHimes Date: Fri, 10 May 2024 11:01:45 +0000 Subject: [PATCH 03/11] Add tests and adapt joint fixture --- README.md | 10 +++++++ tests/conftest.py | 6 +++- tests/fixtures/joint.py | 17 +++++++---- tests/test_outbox_subscriber.py | 53 +++++++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 tests/test_outbox_subscriber.py diff --git a/README.md b/README.md index 39b1ec7..a95ed7f 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,16 @@ The service requires the following configuration parameters: ``` +- **`user_data_event_topic`** *(string)*: The name of the topic containing user data events. + + + Examples: + + ```json + "user_data_events" + ``` + + - **`access_request_events_topic`** *(string)*: Name of the event topic used to consume access request events. diff --git a/tests/conftest.py b/tests/conftest.py index 7bc99f9..2b0c0d4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -17,6 +17,7 @@ import pytest_asyncio from ghga_event_schemas import pydantic_ as event_schemas +from hexkit.protocols.dao import ResourceNotFoundError from hexkit.providers.akafka.testutils import get_kafka_fixture from hexkit.providers.mongodb.testutils import get_mongodb_fixture @@ -43,4 +44,7 @@ async def insert_test_data(joint_fixture: JointFixture): """ await joint_fixture.user_dao.insert(TEST_USER) yield - await joint_fixture.user_dao.delete(id_=TEST_USER.user_id) + try: + await joint_fixture.user_dao.delete(id_=TEST_USER.user_id) + except ResourceNotFoundError: + pass diff --git a/tests/fixtures/joint.py b/tests/fixtures/joint.py index f3750d5..c90a1bc 100644 --- a/tests/fixtures/joint.py +++ b/tests/fixtures/joint.py @@ -21,12 +21,12 @@ import pytest_asyncio from hexkit.custom_types import PytestScope -from hexkit.providers.akafka import KafkaEventSubscriber +from hexkit.providers.akafka import KafkaEventSubscriber, KafkaOutboxSubscriber from hexkit.providers.akafka.testutils import KafkaFixture from hexkit.providers.mongodb.testutils import MongoDbFixture from nos.config import Config -from nos.inject import prepare_core, prepare_event_subscriber +from nos.inject import prepare_core, prepare_event_subscriber, prepare_outbox_subscriber from nos.ports.inbound.orchestrator import OrchestratorPort from nos.ports.outbound.dao import UserDaoPort from nos.translators.outbound.dao import user_dao_factory @@ -40,6 +40,7 @@ class JointFixture: config: Config orchestrator: OrchestratorPort event_subscriber: KafkaEventSubscriber + outbox_subscriber: KafkaOutboxSubscriber kafka: KafkaFixture mongodb: MongoDbFixture user_dao: UserDaoPort @@ -57,13 +58,19 @@ async def joint_fixture_function( # create a DI container instance:translators async with prepare_core(config=config) as orchestrator: - async with prepare_event_subscriber( - config=config, core_override=orchestrator - ) as event_subscriber: + async with ( + prepare_event_subscriber( + config=config, core_override=orchestrator + ) as event_subscriber, + prepare_outbox_subscriber( + config=config, core_override=orchestrator + ) as outbox_subscriber, + ): yield JointFixture( config=config, orchestrator=orchestrator, event_subscriber=event_subscriber, + outbox_subscriber=outbox_subscriber, kafka=kafka_fixture, mongodb=mongodb_fixture, user_dao=await user_dao_factory( diff --git a/tests/test_outbox_subscriber.py b/tests/test_outbox_subscriber.py new file mode 100644 index 0000000..4598d0e --- /dev/null +++ b/tests/test_outbox_subscriber.py @@ -0,0 +1,53 @@ +# Copyright 2021 - 2024 Universität Tübingen, DKFZ, EMBL, and Universität zu Köln +# for the German Human Genome-Phenome Archive (GHGA) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Verify functionality related to the consumption of KafkaOutbox events.""" + +import pytest +from hexkit.protocols.dao import ResourceNotFoundError + +from tests.fixtures.joint import JointFixture + +CHANGE_EVENT_TYPE = "upserted" +DELETE_EVENT_TYPE = "deleted" + + +@pytest.mark.parametrize("user_id", ["test_id", "does_not_exist"]) +@pytest.mark.asyncio(scope="module") +async def test_user_data_deletion(joint_fixture: JointFixture, user_id: str): + """Ensure that the `delete` function works correctly. + + The event should trigger the deletion of the user data via the orchestrator. + The user_id 'test_id' should be found and deleted. + The user_id 'does_not_exist' should not be found but also not raise an error. + """ + # 1. Prepare the test by setting up the core and the event subscriber. + if user_id == "test_id": + assert await joint_fixture.user_dao.get_by_id(user_id) + + # 2. Publish the event. + await joint_fixture.kafka.publish_event( + payload={}, + type_=DELETE_EVENT_TYPE, + topic=joint_fixture.config.user_data_event_topic, + key=user_id, + ) + + # 3. Run the outbox subscriber. + await joint_fixture.outbox_subscriber.run(forever=False) + + # 4. Check that the user data is not found. + with pytest.raises(ResourceNotFoundError): + await joint_fixture.user_dao.get_by_id(user_id) From 4b6e0186ef57d682959714027c4094da566ab809 Mon Sep 17 00:00:00 2001 From: TheByronHimes Date: Fri, 10 May 2024 15:31:46 +0000 Subject: [PATCH 04/11] Remove __all__ from notifications --- src/nos/core/notifications.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/nos/core/notifications.py b/src/nos/core/notifications.py index 66b3d04..8bc768f 100644 --- a/src/nos/core/notifications.py +++ b/src/nos/core/notifications.py @@ -20,23 +20,6 @@ log = logging.getLogger(__name__) -__all__ = [ - "Notification", - "ACCESS_REQUEST_CREATED_TO_USER", - "ACCESS_REQUEST_CREATED_TO_DS", - "ACCESS_REQUEST_ALLOWED_TO_USER", - "ACCESS_REQUEST_ALLOWED_TO_DS", - "ACCESS_REQUEST_DENIED_TO_USER", - "ACCESS_REQUEST_DENIED_TO_DS", - "FILE_REGISTERED_TO_DS", - "ALL_IVAS_INVALIDATED_TO_USER", - "IVA_CODE_REQUESTED_TO_USER", - "IVA_CODE_REQUESTED_TO_DS", - "IVA_CODE_TRANSMITTED_TO_USER", - "IVA_CODE_SUBMITTED_TO_DS", - "IVA_UNVERIFIED_TO_DS", -] - class NotificationError(RuntimeError): """Raised for notification-related errors.""" From df5d9eba98d6dd532ef722b8e619db0ac08c5e62 Mon Sep 17 00:00:00 2001 From: TheByronHimes Date: Fri, 10 May 2024 15:32:21 +0000 Subject: [PATCH 05/11] Use new name on update --- src/nos/core/orchestrator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nos/core/orchestrator.py b/src/nos/core/orchestrator.py index 6de2ef2..ad10317 100644 --- a/src/nos/core/orchestrator.py +++ b/src/nos/core/orchestrator.py @@ -353,7 +353,7 @@ async def upsert_user_data( if changed_details := self._changed_info(existing_user, update): await self._notification_emitter.notify( email=existing_user.email, - full_name=existing_user.name, + full_name=update.name, notification=notifications.USER_REREGISTERED_TO_USER.formatted( support_email=self._config.central_data_stewardship_email, changed_details=changed_details, From 39a2d8de04b1273e0af1dfbf09afb95e417755a2 Mon Sep 17 00:00:00 2001 From: TheByronHimes Date: Fri, 10 May 2024 15:34:14 +0000 Subject: [PATCH 06/11] Use separated container and client fixtures --- tests/conftest.py | 116 ++++++++++++++++++++++++++++++-- tests/fixtures/joint.py | 12 ++-- tests/test_orchestrator.py | 26 +++---- tests/test_outbox_subscriber.py | 2 +- 4 files changed, 129 insertions(+), 27 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 2b0c0d4..d7b3ab4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -15,17 +15,28 @@ # """Test-suite-wide fixture declaration.""" +from collections.abc import AsyncGenerator, Generator +from typing import Any, Self + +import pytest import pytest_asyncio from ghga_event_schemas import pydantic_ as event_schemas from hexkit.protocols.dao import ResourceNotFoundError -from hexkit.providers.akafka.testutils import get_kafka_fixture -from hexkit.providers.mongodb.testutils import get_mongodb_fixture +from hexkit.providers.akafka import KafkaConfig +from hexkit.providers.akafka.provider import KafkaEventPublisher +from hexkit.providers.akafka.testcontainer import DEFAULT_IMAGE as KAFKA_IMAGE +from hexkit.providers.akafka.testutils import KafkaFixture +from hexkit.providers.mongodb.provider import MongoDbDaoFactory +from hexkit.providers.mongodb.testutils import ( + MongoDbFixture, + config_from_mongodb_container, +) +from testcontainers.kafka import KafkaContainer +from testcontainers.mongodb import MongoDbContainer from tests.fixtures.joint import JointFixture, get_joint_fixture -mongodb_fixture = get_mongodb_fixture(scope="module") -kafka_fixture = get_kafka_fixture(scope="module") -joint_fixture = get_joint_fixture(scope="module") +joint_fixture = get_joint_fixture() TEST_USER = event_schemas.User( user_id="test_id", name="test user", @@ -34,7 +45,7 @@ ) -@pytest_asyncio.fixture(autouse=True, scope="module") +@pytest_asyncio.fixture(autouse=True) async def insert_test_data(joint_fixture: JointFixture): """Fixture that inserts TEST_USER into the database and deletes it after the tests are done. @@ -48,3 +59,96 @@ async def insert_test_data(joint_fixture: JointFixture): await joint_fixture.user_dao.delete(id_=TEST_USER.user_id) except ResourceNotFoundError: pass + + +class KafkaContainerFixture(KafkaContainer): + """Kafka container with config and command execution.""" + + kafka_config: KafkaConfig + + def __init__(self, port: int = 9093, **kwargs: Any) -> None: + """Initialize the container.""" + super().__init__(image=KAFKA_IMAGE, port=port, **kwargs) + + def __enter__(self) -> Self: + """Enter the container context.""" + super().__enter__() + kafka_servers = [self.get_bootstrap_server()] + self.kafka_config = KafkaConfig( + service_name="test_publisher", + service_instance_id="001", + kafka_servers=kafka_servers, + ) + return self + + def wrapped_exec_run(self, command: str, run_in_shell: bool): + """Run the given command in the kafka testcontainer. + + Args: + - `command`: The full command to run. + - `run_in_shell`: If True, will run the command in a shell. + + Raises: + - `RuntimeError`: when the exit code returned by the command is not zero. + """ + cmd = ["sh", "-c", command] if run_in_shell else command + exit_code, output = self.get_wrapped_container().exec_run(cmd) + + if exit_code != 0: + raise RuntimeError(f"result: {exit_code}, output: {output.decode('utf-8')}") + + +@pytest.fixture(name="kafka_container", scope="session") +def kafka_container_fixture() -> Generator[KafkaContainerFixture, None, None]: + """Fixture for getting a running Kafka test container.""" + with KafkaContainerFixture() as kafka_container: + yield kafka_container + + +@pytest.fixture(name="mongodb_container", scope="session") +def mongodb_container_fixture() -> Generator[MongoDbContainer, None, None]: + """Fixture for getting a running MongoDB test container.""" + with MongoDbContainer(image="mongo:6.0.3") as mongodb_container: + yield mongodb_container + + +@pytest_asyncio.fixture(name="kafka") +async def empty_kafka_fixture( + kafka_container: KafkaContainerFixture, +) -> AsyncGenerator[KafkaFixture, None]: + """Pytest fixture for tests depending on the Kafka-base providers. + + This function-scoped fixture also clears all the Kafka topics. + """ + config = kafka_container.kafka_config + async with KafkaEventPublisher.construct(config=config) as publisher: + kafka_fixture = KafkaFixture( + config=config, + kafka_servers=config.kafka_servers, + cmd_exec_func=kafka_container.wrapped_exec_run, + publisher=publisher, + ) + await kafka_fixture.clear_topics() + yield kafka_fixture + + +@pytest.fixture(name="mongodb") +def empty_mongodb_fixture( + mongodb_container: MongoDbContainer, +) -> Generator[MongoDbFixture, None, None]: + """Pytest fixture for tests depending on the MongoDbDaoFactory DAO. + + This function-scoped fixture also empties all the MongoDB collections. + """ + config = config_from_mongodb_container(mongodb_container) + dao_factory = MongoDbDaoFactory(config=config) + client = mongodb_container.get_connection_client() + mongodb_fixture = MongoDbFixture( + client=client, + config=config, + dao_factory=dao_factory, + ) + mongodb_fixture.empty_collections() + yield mongodb_fixture + + client.close() diff --git a/tests/fixtures/joint.py b/tests/fixtures/joint.py index c90a1bc..28fb5ed 100644 --- a/tests/fixtures/joint.py +++ b/tests/fixtures/joint.py @@ -47,14 +47,14 @@ class JointFixture: async def joint_fixture_function( - mongodb_fixture: MongoDbFixture, kafka_fixture: KafkaFixture + mongodb: MongoDbFixture, kafka: KafkaFixture ) -> AsyncGenerator[JointFixture, None]: """A fixture that embeds all other fixtures for API-level integration testing **Do not call directly** Instead, use get_joint_fixture(). """ # merge configs from different sources with the default one: - config = get_config(sources=[mongodb_fixture.config, kafka_fixture.config]) + config = get_config(sources=[mongodb.config, kafka.config]) # create a DI container instance:translators async with prepare_core(config=config) as orchestrator: @@ -71,11 +71,9 @@ async def joint_fixture_function( orchestrator=orchestrator, event_subscriber=event_subscriber, outbox_subscriber=outbox_subscriber, - kafka=kafka_fixture, - mongodb=mongodb_fixture, - user_dao=await user_dao_factory( - dao_factory=mongodb_fixture.dao_factory - ), + kafka=kafka, + mongodb=mongodb, + user_dao=await user_dao_factory(dao_factory=mongodb.dao_factory), ) diff --git a/tests/test_orchestrator.py b/tests/test_orchestrator.py index d9d3b84..a21070e 100644 --- a/tests/test_orchestrator.py +++ b/tests/test_orchestrator.py @@ -83,7 +83,7 @@ def iva_state_payload(user_id: str, state: event_schemas.IvaState) -> dict[str, ), ], ) -@pytest.mark.asyncio(scope="module") +@pytest.mark.asyncio async def test_access_request( joint_fixture: JointFixture, user_notification_content: notifications.Notification, @@ -96,7 +96,7 @@ async def test_access_request( Test will also check idempotence. """ - test_user = await joint_fixture.user_dao.get_by_id(TEST_USER.id) + test_user = await joint_fixture.user_dao.get_by_id(TEST_USER.user_id) event_type_to_use = getattr( joint_fixture.config, f"access_request_{event_type}_event_type" @@ -133,7 +133,7 @@ async def test_access_request( # Create the kafka event that would be published by the access request service await joint_fixture.kafka.publish_event( - payload=access_request_payload(test_user.id), + payload=access_request_payload(test_user.user_id), type_=event_type_to_use, topic=joint_fixture.config.access_request_events_topic, ) @@ -147,7 +147,7 @@ async def test_access_request( # Publish and consume event again to check idempotence await joint_fixture.kafka.publish_event( - payload=access_request_payload(test_user.id), + payload=access_request_payload(test_user.user_id), type_=event_type_to_use, topic=joint_fixture.config.access_request_events_topic, ) @@ -159,7 +159,7 @@ async def test_access_request( await joint_fixture.event_subscriber.run(forever=False) -@pytest.mark.asyncio(scope="module") +@pytest.mark.asyncio async def test_missing_user_id_access_requests( joint_fixture: JointFixture, logot: Logot ): @@ -191,7 +191,7 @@ async def test_missing_user_id_access_requests( ) -@pytest.mark.asyncio(scope="module") +@pytest.mark.asyncio async def test_missing_user_id_iva_state_changes( joint_fixture: JointFixture, logot: Logot ): @@ -228,7 +228,7 @@ async def test_missing_user_id_iva_state_changes( ) -@pytest.mark.asyncio(scope="module") +@pytest.mark.asyncio async def test_file_registered(joint_fixture: JointFixture): """Test that the file registered events are translated into a notification.""" # Prepare triggering event (the file registration event). @@ -302,7 +302,7 @@ async def test_file_registered(joint_fixture: JointFixture): ), ], ) -@pytest.mark.asyncio(scope="module") +@pytest.mark.asyncio async def test_iva_state_change( joint_fixture: JointFixture, iva_state: event_schemas.IvaState, @@ -316,7 +316,7 @@ async def test_iva_state_change( """ # Prepare triggering event (the IVA state change event). trigger_event = event_schemas.UserIvaState( - user_id=TEST_USER.id, + user_id=TEST_USER.user_id, state=iva_state, value=None, type=event_schemas.IvaType.FAX, @@ -327,7 +327,7 @@ async def test_iva_state_change( payload=trigger_event.model_dump(), type_=joint_fixture.config.iva_state_changed_event_type, topic=joint_fixture.config.iva_events_topic, - key=TEST_USER.id, + key=TEST_USER.user_id, ) # Build a notification payload for the user, if applicable @@ -377,12 +377,12 @@ async def test_iva_state_change( await joint_fixture.event_subscriber.run(forever=False) -@pytest.mark.asyncio(scope="module") +@pytest.mark.asyncio async def test_all_ivas_reset(joint_fixture: JointFixture): """Test that the 'all IVA invalidated' events are translated into a notification.""" # Prepare triggering event (the IVA state change event). trigger_event = event_schemas.UserIvaState( - user_id=TEST_USER.id, + user_id=TEST_USER.user_id, state=event_schemas.IvaState.UNVERIFIED, value=None, type=None, @@ -393,7 +393,7 @@ async def test_all_ivas_reset(joint_fixture: JointFixture): payload=trigger_event.model_dump(), type_=joint_fixture.config.iva_state_changed_event_type, topic=joint_fixture.config.iva_events_topic, - key=f"all-{TEST_USER.id}", + key=f"all-{TEST_USER.user_id}", ) # Define the event that should be published by the NOS when the trigger is consumed diff --git a/tests/test_outbox_subscriber.py b/tests/test_outbox_subscriber.py index 4598d0e..0ea339f 100644 --- a/tests/test_outbox_subscriber.py +++ b/tests/test_outbox_subscriber.py @@ -25,7 +25,7 @@ @pytest.mark.parametrize("user_id", ["test_id", "does_not_exist"]) -@pytest.mark.asyncio(scope="module") +@pytest.mark.asyncio async def test_user_data_deletion(joint_fixture: JointFixture, user_id: str): """Ensure that the `delete` function works correctly. From 411a652609b0681641f5f14d01c455fcc74e29a6 Mon Sep 17 00:00:00 2001 From: TheByronHimes Date: Fri, 10 May 2024 15:34:58 +0000 Subject: [PATCH 07/11] Add test for user account update notifications --- tests/test_outbox_subscriber.py | 119 +++++++++++++++++++++++++++++++- 1 file changed, 118 insertions(+), 1 deletion(-) diff --git a/tests/test_outbox_subscriber.py b/tests/test_outbox_subscriber.py index 0ea339f..2105790 100644 --- a/tests/test_outbox_subscriber.py +++ b/tests/test_outbox_subscriber.py @@ -16,8 +16,12 @@ """Verify functionality related to the consumption of KafkaOutbox events.""" import pytest +from ghga_event_schemas import pydantic_ as event_schemas from hexkit.protocols.dao import ResourceNotFoundError +from hexkit.providers.akafka.testutils import ExpectedEvent +from nos.core import notifications +from tests.conftest import TEST_USER from tests.fixtures.joint import JointFixture CHANGE_EVENT_TYPE = "upserted" @@ -33,7 +37,7 @@ async def test_user_data_deletion(joint_fixture: JointFixture, user_id: str): The user_id 'test_id' should be found and deleted. The user_id 'does_not_exist' should not be found but also not raise an error. """ - # 1. Prepare the test by setting up the core and the event subscriber. + # 1. Double check that the user data is found before running deletion. if user_id == "test_id": assert await joint_fixture.user_dao.get_by_id(user_id) @@ -51,3 +55,116 @@ async def test_user_data_deletion(joint_fixture: JointFixture, user_id: str): # 4. Check that the user data is not found. with pytest.raises(ResourceNotFoundError): await joint_fixture.user_dao.get_by_id(user_id) + + +@pytest.mark.parametrize( + "user", + [ + TEST_USER.model_copy( + update={ + "name": "new name", + "academic_title": event_schemas.AcademicTitle.PROF, + "email": "modified@test.com", + } + ), + event_schemas.User( + user_id="new_user", name="new user", email="new_user@xyz.com" + ), + ], + ids=["modified user", "new user"], +) +@pytest.mark.asyncio +async def test_user_data_upsert( + joint_fixture: JointFixture, + user: event_schemas.User, +): + """Ensure that the `upsert` function works correctly. + + The 'upserted' event should trigger the upsertion of the user data via the + orchestrator. This does not test for resulting notifications, only upsertion. + """ + # Check that the user is found if it's the test user, otherwise not. + if user.user_id == TEST_USER.user_id: + assert await joint_fixture.user_dao.get_by_id(user.user_id) + else: + with pytest.raises(ResourceNotFoundError): + assert await joint_fixture.user_dao.get_by_id(user.user_id) + + # Publish the change event. + await joint_fixture.kafka.publish_event( + payload=user.model_dump(), + type_=CHANGE_EVENT_TYPE, + topic=joint_fixture.config.user_data_event_topic, + key=user.user_id, + ) + + # Run the outbox subscriber. + await joint_fixture.outbox_subscriber.run(forever=False) + + # 4. Check that the user data is found. + result = await joint_fixture.user_dao.get_by_id(user.user_id) + assert result == user + + +@pytest.mark.parametrize( + "changed_details", + [ + {"name": "new name"}, + {"email": "different@example.com"}, + {"name": "another name", "email": "anders@example.com"}, + {}, + ], + ids=["name", "email", "both", "neither"], +) +@pytest.mark.asyncio +async def test_user_reregistration_notifications( + joint_fixture: JointFixture, + changed_details: dict[str, str], +): + """Test that upsertion emits the expected notifications. + + When a name changes, ensure the new name is used. + When an email changes, ensure the old email is used. + When neither changes, ensure no notification is emitted. + """ + user = TEST_USER.model_copy(update=changed_details) + + # Publish the change event. + await joint_fixture.kafka.publish_event( + payload=user.model_dump(), + type_=CHANGE_EVENT_TYPE, + topic=joint_fixture.config.user_data_event_topic, + key=user.user_id, + ) + + # Prepare the expected notification. + expected_notifications = [] + if changed_details: + expected_notifications.append( + event_schemas.Notification( + recipient_email=TEST_USER.email + if "email" in changed_details + else user.email, + subject="Account Details Changed", + recipient_name=user.name, + plaintext_body=notifications.USER_REREGISTERED_TO_USER.text.format( + changed_details=" and ".join(sorted(changed_details.keys())), + support_email=joint_fixture.config.central_data_stewardship_email, + ), + ) + ) + + # Compile expected events list + topic = joint_fixture.config.notification_event_topic + expected_events = [ + ExpectedEvent( + type_=joint_fixture.config.notification_event_type, + payload=notification.model_dump(), + key=notification.recipient_email, + ) + for notification in expected_notifications + ] + + # Run the outbox subscriber and check that the expected notifications were emitted. + async with joint_fixture.kafka.expect_events(expected_events, in_topic=topic): + await joint_fixture.outbox_subscriber.run(forever=False) From b11488938e247b67f88743cfa74b50a89d683cee Mon Sep 17 00:00:00 2001 From: TheByronHimes Date: Fri, 10 May 2024 15:41:46 +0000 Subject: [PATCH 08/11] Remove id_ keyword in dao.delete call --- lock/requirements-dev.txt | 6 +++--- lock/requirements.txt | 6 +++--- src/nos/core/orchestrator.py | 2 +- tests/conftest.py | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lock/requirements-dev.txt b/lock/requirements-dev.txt index 414f37b..dda69f7 100644 --- a/lock/requirements-dev.txt +++ b/lock/requirements-dev.txt @@ -264,9 +264,9 @@ h11==0.14.0 \ # via # httpcore # uvicorn -hexkit==3.0.1 \ - --hash=sha256:0d854aa8c0f5539338a50ed363557d4bbf720ca01afde9f07512cb76a7be398d \ - --hash=sha256:61347f4564eb557bb4dea176a0085dc85391a4a5eb32681433b7afc1487df3aa +hexkit==3.0.2 \ + --hash=sha256:172c55b756ea0a5ff5e83ba97860947408a132bb37800404e6e7b1cabab9d3e7 \ + --hash=sha256:d8cb77d64c6021725f6e40e87d62792e22a8928810de983f96a6ecfe9245f1f8 # via ghga-service-commons httpcore==1.0.5 \ --hash=sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61 \ diff --git a/lock/requirements.txt b/lock/requirements.txt index 9ade134..efb48a4 100644 --- a/lock/requirements.txt +++ b/lock/requirements.txt @@ -92,9 +92,9 @@ h11==0.14.0 \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 # via uvicorn -hexkit==3.0.1 \ - --hash=sha256:0d854aa8c0f5539338a50ed363557d4bbf720ca01afde9f07512cb76a7be398d \ - --hash=sha256:61347f4564eb557bb4dea176a0085dc85391a4a5eb32681433b7afc1487df3aa +hexkit==3.0.2 \ + --hash=sha256:172c55b756ea0a5ff5e83ba97860947408a132bb37800404e6e7b1cabab9d3e7 \ + --hash=sha256:d8cb77d64c6021725f6e40e87d62792e22a8928810de983f96a6ecfe9245f1f8 # via ghga-service-commons httptools==0.6.1 \ --hash=sha256:00d5d4b68a717765b1fabfd9ca755bd12bf44105eeb806c03d1962acd9b8e563 \ diff --git a/src/nos/core/orchestrator.py b/src/nos/core/orchestrator.py index ad10317..686f197 100644 --- a/src/nos/core/orchestrator.py +++ b/src/nos/core/orchestrator.py @@ -369,7 +369,7 @@ async def delete_user_data(self, resource_id: str) -> None: log the fact but not raise an error. """ try: - await self._user_dao.delete(id_=resource_id) + await self._user_dao.delete(resource_id) except ResourceNotFoundError: # do not raise an error if the user is not found, just log it. log.warning("User not found for deletion", extra={"user_id": resource_id}) diff --git a/tests/conftest.py b/tests/conftest.py index d7b3ab4..b62056d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -56,7 +56,7 @@ async def insert_test_data(joint_fixture: JointFixture): await joint_fixture.user_dao.insert(TEST_USER) yield try: - await joint_fixture.user_dao.delete(id_=TEST_USER.user_id) + await joint_fixture.user_dao.delete(TEST_USER.user_id) except ResourceNotFoundError: pass From 27888e4c1447a2ed270f818e6e6a0455adff1986 Mon Sep 17 00:00:00 2001 From: TheByronHimes Date: Mon, 13 May 2024 13:23:29 +0000 Subject: [PATCH 09/11] Set config default and tweak name Fix notification wording Fix _changed_info docstring Use pytestmark in test modules --- .devcontainer/.dev_config.yaml | 2 +- README.md | 10 +--------- config_schema.json | 11 ++++------- example_config.yaml | 2 +- src/nos/core/notifications.py | 3 +-- src/nos/core/orchestrator.py | 2 +- src/nos/translators/inbound/event_sub.py | 9 ++++----- tests/fixtures/test_config.yaml | 2 +- tests/test_orchestrator.py | 7 +------ tests/test_outbox_subscriber.py | 13 ++++++------- 10 files changed, 21 insertions(+), 40 deletions(-) diff --git a/.devcontainer/.dev_config.yaml b/.devcontainer/.dev_config.yaml index 4fc929a..54c6ec7 100644 --- a/.devcontainer/.dev_config.yaml +++ b/.devcontainer/.dev_config.yaml @@ -13,4 +13,4 @@ file_registered_event_topic: internal_file_registry file_registered_event_type: file_registered iva_events_topic: ivas iva_state_changed_event_type: iva_state_changed -user_data_event_topic: user_events +user_events_topic: users diff --git a/README.md b/README.md index a95ed7f..8d3e782 100644 --- a/README.md +++ b/README.md @@ -91,15 +91,7 @@ The service requires the following configuration parameters: ``` -- **`user_data_event_topic`** *(string)*: The name of the topic containing user data events. - - - Examples: - - ```json - "user_data_events" - ``` - +- **`user_events_topic`** *(string)*: The name of the topic containing user events. Default: `"users"`. - **`access_request_events_topic`** *(string)*: Name of the event topic used to consume access request events. diff --git a/config_schema.json b/config_schema.json index 1cc3791..07f7622 100644 --- a/config_schema.json +++ b/config_schema.json @@ -36,12 +36,10 @@ "title": "Notification Event Type", "type": "string" }, - "user_data_event_topic": { - "description": "The name of the topic containing user data events.", - "examples": [ - "user_data_events" - ], - "title": "User Data Event Topic", + "user_events_topic": { + "default": "users", + "description": "The name of the topic containing user events.", + "title": "User Events Topic", "type": "string" }, "access_request_events_topic": { @@ -223,7 +221,6 @@ "db_name", "notification_event_topic", "notification_event_type", - "user_data_event_topic", "access_request_events_topic", "access_request_created_event_type", "access_request_allowed_event_type", diff --git a/example_config.yaml b/example_config.yaml index f298920..d6346d5 100644 --- a/example_config.yaml +++ b/example_config.yaml @@ -23,4 +23,4 @@ notification_event_topic: notification_events notification_event_type: notification service_instance_id: '1' service_name: nos -user_data_event_topic: user_events +user_events_topic: users diff --git a/src/nos/core/notifications.py b/src/nos/core/notifications.py index 8bc768f..e3f80e1 100644 --- a/src/nos/core/notifications.py +++ b/src/nos/core/notifications.py @@ -176,7 +176,6 @@ def formatted(self, **kwargs) -> "Notification": """ Your account details were recently updated. The changed details include: {changed_details}. -If you did not make the following changes or have -please contact the GHGA immediately at {support_email}. +If you did not make these changes or have questions, please contact the GHGA immediately at {support_email}. """, ) diff --git a/src/nos/core/orchestrator.py b/src/nos/core/orchestrator.py index 686f197..b9c2f64 100644 --- a/src/nos/core/orchestrator.py +++ b/src/nos/core/orchestrator.py @@ -330,7 +330,7 @@ async def process_iva_state_change(self, *, user_iva: event_schemas.UserIvaState def _changed_info( self, existing_user: event_schemas.User, new_user: event_schemas.User ) -> str: - """Check if critical user information has changed. + """Check what critical user information has changed (if any). Critical information includes the user's email address and name. """ diff --git a/src/nos/translators/inbound/event_sub.py b/src/nos/translators/inbound/event_sub.py index 767afd3..85f67de 100644 --- a/src/nos/translators/inbound/event_sub.py +++ b/src/nos/translators/inbound/event_sub.py @@ -147,10 +147,9 @@ async def _consume_validated( class OutboxSubTranslatorConfig(BaseSettings): """Config for the outbox subscriber""" - user_data_event_topic: str = Field( - default=..., - description="The name of the topic containing user data events.", - examples=["user_data_events"], + user_events_topic: str = Field( + default="users", + description="The name of the topic containing user events.", ) @@ -168,7 +167,7 @@ def __init__( ): self._config = config self._orchestrator = orchestrator - self.event_topic = config.user_data_event_topic + self.event_topic = config.user_events_topic async def changed(self, resource_id: str, update: event_schemas.User) -> None: """Consume change event (created or updated) for user data.""" diff --git a/tests/fixtures/test_config.yaml b/tests/fixtures/test_config.yaml index 4fc929a..54c6ec7 100644 --- a/tests/fixtures/test_config.yaml +++ b/tests/fixtures/test_config.yaml @@ -13,4 +13,4 @@ file_registered_event_topic: internal_file_registry file_registered_event_type: file_registered iva_events_topic: ivas iva_state_changed_event_type: iva_state_changed -user_data_event_topic: user_events +user_events_topic: users diff --git a/tests/test_orchestrator.py b/tests/test_orchestrator.py index a21070e..77966ec 100644 --- a/tests/test_orchestrator.py +++ b/tests/test_orchestrator.py @@ -28,6 +28,7 @@ from tests.fixtures.joint import JointFixture DATASET_ID = "dataset1" +pytestmark = pytest.mark.asyncio() def access_request_payload(user_id: str) -> dict[str, Any]: @@ -83,7 +84,6 @@ def iva_state_payload(user_id: str, state: event_schemas.IvaState) -> dict[str, ), ], ) -@pytest.mark.asyncio async def test_access_request( joint_fixture: JointFixture, user_notification_content: notifications.Notification, @@ -159,7 +159,6 @@ async def test_access_request( await joint_fixture.event_subscriber.run(forever=False) -@pytest.mark.asyncio async def test_missing_user_id_access_requests( joint_fixture: JointFixture, logot: Logot ): @@ -191,7 +190,6 @@ async def test_missing_user_id_access_requests( ) -@pytest.mark.asyncio async def test_missing_user_id_iva_state_changes( joint_fixture: JointFixture, logot: Logot ): @@ -228,7 +226,6 @@ async def test_missing_user_id_iva_state_changes( ) -@pytest.mark.asyncio async def test_file_registered(joint_fixture: JointFixture): """Test that the file registered events are translated into a notification.""" # Prepare triggering event (the file registration event). @@ -302,7 +299,6 @@ async def test_file_registered(joint_fixture: JointFixture): ), ], ) -@pytest.mark.asyncio async def test_iva_state_change( joint_fixture: JointFixture, iva_state: event_schemas.IvaState, @@ -377,7 +373,6 @@ async def test_iva_state_change( await joint_fixture.event_subscriber.run(forever=False) -@pytest.mark.asyncio async def test_all_ivas_reset(joint_fixture: JointFixture): """Test that the 'all IVA invalidated' events are translated into a notification.""" # Prepare triggering event (the IVA state change event). diff --git a/tests/test_outbox_subscriber.py b/tests/test_outbox_subscriber.py index 2105790..d1db2bc 100644 --- a/tests/test_outbox_subscriber.py +++ b/tests/test_outbox_subscriber.py @@ -27,9 +27,10 @@ CHANGE_EVENT_TYPE = "upserted" DELETE_EVENT_TYPE = "deleted" +pytestmark = pytest.mark.asyncio() + @pytest.mark.parametrize("user_id", ["test_id", "does_not_exist"]) -@pytest.mark.asyncio async def test_user_data_deletion(joint_fixture: JointFixture, user_id: str): """Ensure that the `delete` function works correctly. @@ -45,7 +46,7 @@ async def test_user_data_deletion(joint_fixture: JointFixture, user_id: str): await joint_fixture.kafka.publish_event( payload={}, type_=DELETE_EVENT_TYPE, - topic=joint_fixture.config.user_data_event_topic, + topic=joint_fixture.config.user_events_topic, key=user_id, ) @@ -73,7 +74,6 @@ async def test_user_data_deletion(joint_fixture: JointFixture, user_id: str): ], ids=["modified user", "new user"], ) -@pytest.mark.asyncio async def test_user_data_upsert( joint_fixture: JointFixture, user: event_schemas.User, @@ -94,14 +94,14 @@ async def test_user_data_upsert( await joint_fixture.kafka.publish_event( payload=user.model_dump(), type_=CHANGE_EVENT_TYPE, - topic=joint_fixture.config.user_data_event_topic, + topic=joint_fixture.config.user_events_topic, key=user.user_id, ) # Run the outbox subscriber. await joint_fixture.outbox_subscriber.run(forever=False) - # 4. Check that the user data is found. + # Check that the user data is found. result = await joint_fixture.user_dao.get_by_id(user.user_id) assert result == user @@ -116,7 +116,6 @@ async def test_user_data_upsert( ], ids=["name", "email", "both", "neither"], ) -@pytest.mark.asyncio async def test_user_reregistration_notifications( joint_fixture: JointFixture, changed_details: dict[str, str], @@ -133,7 +132,7 @@ async def test_user_reregistration_notifications( await joint_fixture.kafka.publish_event( payload=user.model_dump(), type_=CHANGE_EVENT_TYPE, - topic=joint_fixture.config.user_data_event_topic, + topic=joint_fixture.config.user_events_topic, key=user.user_id, ) From 0a9672de3296199d1b7a4910ce8188172bac64f2 Mon Sep 17 00:00:00 2001 From: TheByronHimes Date: Mon, 13 May 2024 13:43:08 +0000 Subject: [PATCH 10/11] Add title-only update test --- tests/test_outbox_subscriber.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_outbox_subscriber.py b/tests/test_outbox_subscriber.py index d1db2bc..cef39bd 100644 --- a/tests/test_outbox_subscriber.py +++ b/tests/test_outbox_subscriber.py @@ -113,8 +113,9 @@ async def test_user_data_upsert( {"email": "different@example.com"}, {"name": "another name", "email": "anders@example.com"}, {}, + {"title": event_schemas.AcademicTitle.PROF}, ], - ids=["name", "email", "both", "neither"], + ids=["name", "email", "both", "neither", "title"], ) async def test_user_reregistration_notifications( joint_fixture: JointFixture, @@ -138,7 +139,7 @@ async def test_user_reregistration_notifications( # Prepare the expected notification. expected_notifications = [] - if changed_details: + if "name" in changed_details or "email" in changed_details: expected_notifications.append( event_schemas.Notification( recipient_email=TEST_USER.email From af5be39cde4e6ad1328d8ba78efd686af16dd80b Mon Sep 17 00:00:00 2001 From: TheByronHimes Date: Mon, 13 May 2024 13:48:25 +0000 Subject: [PATCH 11/11] Update IVA events topic name for consistency --- .devcontainer/.dev_config.yaml | 2 +- README.md | 2 +- config_schema.json | 6 +++--- example_config.yaml | 2 +- src/nos/translators/inbound/event_sub.py | 4 ++-- tests/fixtures/test_config.yaml | 2 +- tests/test_orchestrator.py | 4 ++-- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.devcontainer/.dev_config.yaml b/.devcontainer/.dev_config.yaml index 54c6ec7..4737bcd 100644 --- a/.devcontainer/.dev_config.yaml +++ b/.devcontainer/.dev_config.yaml @@ -11,6 +11,6 @@ notification_event_type: notification notification_event_topic: notification_events file_registered_event_topic: internal_file_registry file_registered_event_type: file_registered -iva_events_topic: ivas +iva_state_changed_event_topic: ivas iva_state_changed_event_type: iva_state_changed user_events_topic: users diff --git a/README.md b/README.md index 8d3e782..1167cad 100644 --- a/README.md +++ b/README.md @@ -153,7 +153,7 @@ The service requires the following configuration parameters: ``` -- **`iva_events_topic`** *(string)*: The name of the topic containing IVA events. +- **`iva_state_changed_event_topic`** *(string)*: The name of the topic containing IVA events. Examples: diff --git a/config_schema.json b/config_schema.json index 07f7622..90d49c2 100644 --- a/config_schema.json +++ b/config_schema.json @@ -90,12 +90,12 @@ "title": "File Registered Event Type", "type": "string" }, - "iva_events_topic": { + "iva_state_changed_event_topic": { "description": "The name of the topic containing IVA events.", "examples": [ "ivas" ], - "title": "Iva Events Topic", + "title": "Iva State Changed Event Topic", "type": "string" }, "iva_state_changed_event_type": { @@ -227,7 +227,7 @@ "access_request_denied_event_type", "file_registered_event_topic", "file_registered_event_type", - "iva_events_topic", + "iva_state_changed_event_topic", "iva_state_changed_event_type", "service_instance_id", "kafka_servers", diff --git a/example_config.yaml b/example_config.yaml index d6346d5..45c2f1d 100644 --- a/example_config.yaml +++ b/example_config.yaml @@ -8,7 +8,7 @@ db_name: users file_registered_event_topic: internal_file_registry file_registered_event_type: file_registered generate_correlation_id: true -iva_events_topic: ivas +iva_state_changed_event_topic: ivas iva_state_changed_event_type: iva_state_changed kafka_security_protocol: PLAINTEXT kafka_servers: diff --git a/src/nos/translators/inbound/event_sub.py b/src/nos/translators/inbound/event_sub.py index 85f67de..822b26c 100644 --- a/src/nos/translators/inbound/event_sub.py +++ b/src/nos/translators/inbound/event_sub.py @@ -59,7 +59,7 @@ class EventSubTranslatorConfig(BaseSettings): description="The type used for events detailing internally file registrations.", examples=["file_registered"], ) - iva_events_topic: str = Field( + iva_state_changed_event_topic: str = Field( default=..., description="The name of the topic containing IVA events.", examples=["ivas"], @@ -80,7 +80,7 @@ def __init__( self.topics_of_interest = [ config.access_request_events_topic, config.file_registered_event_topic, - config.iva_events_topic, + config.iva_state_changed_event_topic, ] self.types_of_interest = [ config.access_request_created_event_type, diff --git a/tests/fixtures/test_config.yaml b/tests/fixtures/test_config.yaml index 54c6ec7..4737bcd 100644 --- a/tests/fixtures/test_config.yaml +++ b/tests/fixtures/test_config.yaml @@ -11,6 +11,6 @@ notification_event_type: notification notification_event_topic: notification_events file_registered_event_topic: internal_file_registry file_registered_event_type: file_registered -iva_events_topic: ivas +iva_state_changed_event_topic: ivas iva_state_changed_event_type: iva_state_changed user_events_topic: users diff --git a/tests/test_orchestrator.py b/tests/test_orchestrator.py index 77966ec..b08a693 100644 --- a/tests/test_orchestrator.py +++ b/tests/test_orchestrator.py @@ -322,7 +322,7 @@ async def test_iva_state_change( await joint_fixture.kafka.publish_event( payload=trigger_event.model_dump(), type_=joint_fixture.config.iva_state_changed_event_type, - topic=joint_fixture.config.iva_events_topic, + topic=joint_fixture.config.iva_state_changed_event_topic, key=TEST_USER.user_id, ) @@ -387,7 +387,7 @@ async def test_all_ivas_reset(joint_fixture: JointFixture): await joint_fixture.kafka.publish_event( payload=trigger_event.model_dump(), type_=joint_fixture.config.iva_state_changed_event_type, - topic=joint_fixture.config.iva_events_topic, + topic=joint_fixture.config.iva_state_changed_event_topic, key=f"all-{TEST_USER.user_id}", )