From b05dbd99d682c30cfc52a317d720f50b96961d63 Mon Sep 17 00:00:00 2001 From: Jonathan Sick Date: Wed, 3 Aug 2022 13:03:22 -0400 Subject: [PATCH 01/12] Refresh all dependencies --- requirements/dev.txt | 481 +++-------------------- requirements/main.txt | 884 ++++-------------------------------------- 2 files changed, 137 insertions(+), 1228 deletions(-) diff --git a/requirements/dev.txt b/requirements/dev.txt index 8a6a0247..d634d186 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -2,545 +2,168 @@ # This file is autogenerated by pip-compile with python 3.10 # To update, run: # -# pip-compile --generate-hashes --output-file=requirements/dev.txt requirements/dev.in +# pip-compile --allow-unsafe --output-file=requirements/dev.txt requirements/dev.in # -anyio==3.6.1 \ - --hash=sha256:413adf95f93886e442aea925f3ee43baa5a765a64a0f52c6081894f9992fdd0b \ - --hash=sha256:cb29b9c70620506a9a8f87a309591713446953302d7d995344d0d7c6c0c9a7be +anyio==3.6.1 # via # -c requirements/main.txt # httpcore # watchfiles -asgi-lifespan==1.0.1 \ - --hash=sha256:9a33e7da2073c4764bc79bd6136501d6c42f60e3d2168ba71235e84122eadb7f \ - --hash=sha256:9ea969dc5eb5cf08e52c08dce6f61afcadd28112e72d81c972b1d8eb8691ab53 +asgi-lifespan==1.0.1 # via -r requirements/dev.in -attrs==21.4.0 \ - --hash=sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4 \ - --hash=sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd +attrs==22.1.0 # via # -c requirements/main.txt # pytest -certifi==2022.6.15 \ - --hash=sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d \ - --hash=sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412 +certifi==2022.6.15 # via # -c requirements/main.txt # httpcore # httpx -cfgv==3.3.1 \ - --hash=sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426 \ - --hash=sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736 +cfgv==3.3.1 # via pre-commit -click==8.1.3 \ - --hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \ - --hash=sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48 +click==8.1.3 # via # -c requirements/main.txt # uvicorn -coverage[toml]==6.4.1 \ - --hash=sha256:01c5615d13f3dd3aa8543afc069e5319cfa0c7d712f6e04b920431e5c564a749 \ - --hash=sha256:106c16dfe494de3193ec55cac9640dd039b66e196e4641fa8ac396181578b982 \ - --hash=sha256:129cd05ba6f0d08a766d942a9ed4b29283aff7b2cccf5b7ce279d50796860bb3 \ - --hash=sha256:145f296d00441ca703a659e8f3eb48ae39fb083baba2d7ce4482fb2723e050d9 \ - --hash=sha256:1480ff858b4113db2718848d7b2d1b75bc79895a9c22e76a221b9d8d62496428 \ - --hash=sha256:269eaa2c20a13a5bf17558d4dc91a8d078c4fa1872f25303dddcbba3a813085e \ - --hash=sha256:26dff09fb0d82693ba9e6231248641d60ba606150d02ed45110f9ec26404ed1c \ - --hash=sha256:2bd9a6fc18aab8d2e18f89b7ff91c0f34ff4d5e0ba0b33e989b3cd4194c81fd9 \ - --hash=sha256:309ce4a522ed5fca432af4ebe0f32b21d6d7ccbb0f5fcc99290e71feba67c264 \ - --hash=sha256:3384f2a3652cef289e38100f2d037956194a837221edd520a7ee5b42d00cc605 \ - --hash=sha256:342d4aefd1c3e7f620a13f4fe563154d808b69cccef415415aece4c786665397 \ - --hash=sha256:39ee53946bf009788108b4dd2894bf1349b4e0ca18c2016ffa7d26ce46b8f10d \ - --hash=sha256:4321f075095a096e70aff1d002030ee612b65a205a0a0f5b815280d5dc58100c \ - --hash=sha256:4803e7ccf93230accb928f3a68f00ffa80a88213af98ed338a57ad021ef06815 \ - --hash=sha256:4ce1b258493cbf8aec43e9b50d89982346b98e9ffdfaae8ae5793bc112fb0068 \ - --hash=sha256:664a47ce62fe4bef9e2d2c430306e1428ecea207ffd68649e3b942fa8ea83b0b \ - --hash=sha256:75ab269400706fab15981fd4bd5080c56bd5cc07c3bccb86aab5e1d5a88dc8f4 \ - --hash=sha256:83c4e737f60c6936460c5be330d296dd5b48b3963f48634c53b3f7deb0f34ec4 \ - --hash=sha256:84631e81dd053e8a0d4967cedab6db94345f1c36107c71698f746cb2636c63e3 \ - --hash=sha256:84e65ef149028516c6d64461b95a8dbcfce95cfd5b9eb634320596173332ea84 \ - --hash=sha256:865d69ae811a392f4d06bde506d531f6a28a00af36f5c8649684a9e5e4a85c83 \ - --hash=sha256:87f4f3df85aa39da00fd3ec4b5abeb7407e82b68c7c5ad181308b0e2526da5d4 \ - --hash=sha256:8c08da0bd238f2970230c2a0d28ff0e99961598cb2e810245d7fc5afcf1254e8 \ - --hash=sha256:961e2fb0680b4f5ad63234e0bf55dfb90d302740ae9c7ed0120677a94a1590cb \ - --hash=sha256:9b3e07152b4563722be523e8cd0b209e0d1a373022cfbde395ebb6575bf6790d \ - --hash=sha256:a7f3049243783df2e6cc6deafc49ea123522b59f464831476d3d1448e30d72df \ - --hash=sha256:bf5601c33213d3cb19d17a796f8a14a9eaa5e87629a53979a5981e3e3ae166f6 \ - --hash=sha256:cec3a0f75c8f1031825e19cd86ee787e87cf03e4fd2865c79c057092e69e3a3b \ - --hash=sha256:d42c549a8f41dc103a8004b9f0c433e2086add8a719da00e246e17cbe4056f72 \ - --hash=sha256:d67d44996140af8b84284e5e7d398e589574b376fb4de8ccd28d82ad8e3bea13 \ - --hash=sha256:d9c80df769f5ec05ad21ea34be7458d1dc51ff1fb4b2219e77fe24edf462d6df \ - --hash=sha256:e57816f8ffe46b1df8f12e1b348f06d164fd5219beba7d9433ba79608ef011cc \ - --hash=sha256:ee2ddcac99b2d2aec413e36d7a429ae9ebcadf912946b13ffa88e7d4c9b712d6 \ - --hash=sha256:f02cbbf8119db68455b9d763f2f8737bb7db7e43720afa07d8eb1604e5c5ae28 \ - --hash=sha256:f1d5aa2703e1dab4ae6cf416eb0095304f49d004c39e9db1d86f57924f43006b \ - --hash=sha256:f5b66caa62922531059bc5ac04f836860412f7f88d38a476eda0a6f11d4724f4 \ - --hash=sha256:f69718750eaae75efe506406c490d6fc5a6161d047206cc63ce25527e8a3adad \ - --hash=sha256:fb73e0011b8793c053bfa85e53129ba5f0250fdc0392c1591fd35d915ec75c46 \ - --hash=sha256:fd180ed867e289964404051a958f7cccabdeed423f91a899829264bb7974d3d3 \ - --hash=sha256:fdb6f7bd51c2d1714cea40718f6149ad9be6a2ee7d93b19e9f00934c0f2a74d9 \ - --hash=sha256:ffa9297c3a453fba4717d06df579af42ab9a28022444cae7fa605af4df612d54 +coverage[toml]==6.4.3 # via # -r requirements/dev.in # pytest-cov -distlib==0.3.4 \ - --hash=sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b \ - --hash=sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579 +distlib==0.3.5 # via virtualenv -filelock==3.7.1 \ - --hash=sha256:37def7b658813cda163b56fc564cdc75e86d338246458c4c28ae84cabefa2404 \ - --hash=sha256:3a0fd85166ad9dbab54c9aec96737b744106dc5f15c0b09a6744a445299fcf04 +filelock==3.8.0 # via virtualenv -greenlet==1.1.2 \ - --hash=sha256:0051c6f1f27cb756ffc0ffbac7d2cd48cb0362ac1736871399a739b2885134d3 \ - --hash=sha256:00e44c8afdbe5467e4f7b5851be223be68adb4272f44696ee71fe46b7036a711 \ - --hash=sha256:013d61294b6cd8fe3242932c1c5e36e5d1db2c8afb58606c5a67efce62c1f5fd \ - --hash=sha256:049fe7579230e44daef03a259faa24511d10ebfa44f69411d99e6a184fe68073 \ - --hash=sha256:14d4f3cd4e8b524ae9b8aa567858beed70c392fdec26dbdb0a8a418392e71708 \ - --hash=sha256:166eac03e48784a6a6e0e5f041cfebb1ab400b394db188c48b3a84737f505b67 \ - --hash=sha256:17ff94e7a83aa8671a25bf5b59326ec26da379ace2ebc4411d690d80a7fbcf23 \ - --hash=sha256:1e12bdc622676ce47ae9abbf455c189e442afdde8818d9da983085df6312e7a1 \ - --hash=sha256:21915eb821a6b3d9d8eefdaf57d6c345b970ad722f856cd71739493ce003ad08 \ - --hash=sha256:288c6a76705dc54fba69fbcb59904ae4ad768b4c768839b8ca5fdadec6dd8cfd \ - --hash=sha256:2bde6792f313f4e918caabc46532aa64aa27a0db05d75b20edfc5c6f46479de2 \ - --hash=sha256:32ca72bbc673adbcfecb935bb3fb1b74e663d10a4b241aaa2f5a75fe1d1f90aa \ - --hash=sha256:356b3576ad078c89a6107caa9c50cc14e98e3a6c4874a37c3e0273e4baf33de8 \ - --hash=sha256:40b951f601af999a8bf2ce8c71e8aaa4e8c6f78ff8afae7b808aae2dc50d4c40 \ - --hash=sha256:572e1787d1460da79590bf44304abbc0a2da944ea64ec549188fa84d89bba7ab \ - --hash=sha256:58df5c2a0e293bf665a51f8a100d3e9956febfbf1d9aaf8c0677cf70218910c6 \ - --hash=sha256:64e6175c2e53195278d7388c454e0b30997573f3f4bd63697f88d855f7a6a1fc \ - --hash=sha256:7227b47e73dedaa513cdebb98469705ef0d66eb5a1250144468e9c3097d6b59b \ - --hash=sha256:7418b6bfc7fe3331541b84bb2141c9baf1ec7132a7ecd9f375912eca810e714e \ - --hash=sha256:7cbd7574ce8e138bda9df4efc6bf2ab8572c9aff640d8ecfece1b006b68da963 \ - --hash=sha256:7ff61ff178250f9bb3cd89752df0f1dd0e27316a8bd1465351652b1b4a4cdfd3 \ - --hash=sha256:833e1551925ed51e6b44c800e71e77dacd7e49181fdc9ac9a0bf3714d515785d \ - --hash=sha256:8639cadfda96737427330a094476d4c7a56ac03de7265622fcf4cfe57c8ae18d \ - --hash=sha256:8c5d5b35f789a030ebb95bff352f1d27a93d81069f2adb3182d99882e095cefe \ - --hash=sha256:8c790abda465726cfb8bb08bd4ca9a5d0a7bd77c7ac1ca1b839ad823b948ea28 \ - --hash=sha256:8d2f1fb53a421b410751887eb4ff21386d119ef9cde3797bf5e7ed49fb51a3b3 \ - --hash=sha256:903bbd302a2378f984aef528f76d4c9b1748f318fe1294961c072bdc7f2ffa3e \ - --hash=sha256:93f81b134a165cc17123626ab8da2e30c0455441d4ab5576eed73a64c025b25c \ - --hash=sha256:95e69877983ea39b7303570fa6760f81a3eec23d0e3ab2021b7144b94d06202d \ - --hash=sha256:9633b3034d3d901f0a46b7939f8c4d64427dfba6bbc5a36b1a67364cf148a1b0 \ - --hash=sha256:97e5306482182170ade15c4b0d8386ded995a07d7cc2ca8f27958d34d6736497 \ - --hash=sha256:9f3cba480d3deb69f6ee2c1825060177a22c7826431458c697df88e6aeb3caee \ - --hash=sha256:aa5b467f15e78b82257319aebc78dd2915e4c1436c3c0d1ad6f53e47ba6e2713 \ - --hash=sha256:abb7a75ed8b968f3061327c433a0fbd17b729947b400747c334a9c29a9af6c58 \ - --hash=sha256:aec52725173bd3a7b56fe91bc56eccb26fbdff1386ef123abb63c84c5b43b63a \ - --hash=sha256:b11548073a2213d950c3f671aa88e6f83cda6e2fb97a8b6317b1b5b33d850e06 \ - --hash=sha256:b1692f7d6bc45e3200844be0dba153612103db241691088626a33ff1f24a0d88 \ - --hash=sha256:b336501a05e13b616ef81ce329c0e09ac5ed8c732d9ba7e3e983fcc1a9e86965 \ - --hash=sha256:b8c008de9d0daba7b6666aa5bbfdc23dcd78cafc33997c9b7741ff6353bafb7f \ - --hash=sha256:b92e29e58bef6d9cfd340c72b04d74c4b4e9f70c9fa7c78b674d1fec18896dc4 \ - --hash=sha256:be5f425ff1f5f4b3c1e33ad64ab994eed12fc284a6ea71c5243fd564502ecbe5 \ - --hash=sha256:dd0b1e9e891f69e7675ba5c92e28b90eaa045f6ab134ffe70b52e948aa175b3c \ - --hash=sha256:e30f5ea4ae2346e62cedde8794a56858a67b878dd79f7df76a0767e356b1744a \ - --hash=sha256:e6a36bb9474218c7a5b27ae476035497a6990e21d04c279884eb10d9b290f1b1 \ - --hash=sha256:e859fcb4cbe93504ea18008d1df98dee4f7766db66c435e4882ab35cf70cac43 \ - --hash=sha256:eb6ea6da4c787111adf40f697b4e58732ee0942b5d3bd8f435277643329ba627 \ - --hash=sha256:ec8c433b3ab0419100bd45b47c9c8551248a5aee30ca5e9d399a0b57ac04651b \ - --hash=sha256:eff9d20417ff9dcb0d25e2defc2574d10b491bf2e693b4e491914738b7908168 \ - --hash=sha256:f0214eb2a23b85528310dad848ad2ac58e735612929c8072f6093f3585fd342d \ - --hash=sha256:f276df9830dba7a333544bd41070e8175762a7ac20350786b322b714b0e654f5 \ - --hash=sha256:f3acda1924472472ddd60c29e5b9db0cec629fbe3c5c5accb74d6d6d14773478 \ - --hash=sha256:f70a9e237bb792c7cc7e44c531fd48f5897961701cdaa06cf22fc14965c496cf \ - --hash=sha256:f9d29ca8a77117315101425ec7ec2a47a22ccf59f5593378fc4077ac5b754fce \ - --hash=sha256:fa877ca7f6b48054f847b61d6fa7bed5cebb663ebc55e018fda12db09dcc664c \ - --hash=sha256:fdcec0b8399108577ec290f55551d926d9a1fa6cad45882093a7a07ac5ec147b +greenlet==1.1.2 # via # -c requirements/main.txt # sqlalchemy -h11==0.12.0 \ - --hash=sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6 \ - --hash=sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042 +h11==0.12.0 # via # -c requirements/main.txt # httpcore # uvicorn -holdup==3.0.0 \ - --hash=sha256:4a6a43862d3710a27be563c6c91a733de6e59e7c36e94ca701d077d7cb6afda5 \ - --hash=sha256:64b7ab29078c48d284914bb5b15b0ebdbff64cb272bbc8493ba1b149650cfdc5 +holdup==3.0.0 # via -r requirements/dev.in -httpcore==0.15.0 \ - --hash=sha256:1105b8b73c025f23ff7c36468e4432226cbb959176eab66864b8e31c4ee27fa6 \ - --hash=sha256:18b68ab86a3ccf3e7dc0f43598eaddcf472b602aba29f9aa6ab85fe2ada3980b +httpcore==0.15.0 # via # -c requirements/main.txt # httpx -httptools==0.4.0 \ - --hash=sha256:1a99346ebcb801b213c591540837340bdf6fd060a8687518d01c607d338b7424 \ - --hash=sha256:1ee0b459257e222b878a6c09ccf233957d3a4dcb883b0847640af98d2d9aac23 \ - --hash=sha256:20a45bcf22452a10fa8d58b7dbdb474381f6946bf5b8933e3662d572bc61bae4 \ - --hash=sha256:29bf97a5c532da9c7a04de2c7a9c31d1d54f3abd65a464119b680206bbbb1055 \ - --hash=sha256:2c9a930c378b3d15d6b695fb95ebcff81a7395b4f9775c4f10a076beb0b2c1ff \ - --hash=sha256:2db44a0b294d317199e9f80123e72c6b005c55b625b57fae36de68670090fa48 \ - --hash=sha256:3194f6d6443befa8d4db16c1946b2fc428a3ceb8ab32eb6f09a59f86104dc1a0 \ - --hash=sha256:34d2903dd2a3dd85d33705b6fde40bf91fc44411661283763fd0746723963c83 \ - --hash=sha256:48e48530d9b995a84d1d89ae6b3ec4e59ea7d494b150ac3bbc5e2ac4acce92cd \ - --hash=sha256:54bbd295f031b866b9799dd39cb45deee81aca036c9bff9f58ca06726f6494f1 \ - --hash=sha256:5d1fe6b6661022fd6cac541f54a4237496b246e6f1c0a6b41998ee08a1135afe \ - --hash=sha256:645373c070080e632480a3d251d892cb795be3d3a15f86975d0f1aca56fd230d \ - --hash=sha256:6a1a7dfc1f9c78a833e2c4904757a0f47ce25d08634dd2a52af394eefe5f9777 \ - --hash=sha256:701e66b59dd21a32a274771238025d58db7e2b6ecebbab64ceff51b8e31527ae \ - --hash=sha256:72aa3fbe636b16d22e04b5a9d24711b043495e0ecfe58080addf23a1a37f3409 \ - --hash=sha256:7af6bdbd21a2a25d6784f6d67f44f5df33ef39b6159543b9f9064d365c01f919 \ - --hash=sha256:7ee9f226acab9085037582c059d66769862706e8e8cd2340470ceb8b3850873d \ - --hash=sha256:7f7bfb74718f52d5ed47d608d507bf66d3bc01d4a8b3e6dd7134daaae129357b \ - --hash=sha256:8e2eb957787cbb614a0f006bfc5798ff1d90ac7c4dd24854c84edbdc8c02369e \ - --hash=sha256:903f739c9fb78dab8970b0f3ea51f21955b24b45afa77b22ff0e172fc11ef111 \ - --hash=sha256:98993805f1e3cdb53de4eed02b55dcc953cdf017ba7bbb2fd89226c086a6d855 \ - --hash=sha256:9967d9758df505975913304c434cb9ab21e2c609ad859eb921f2f615a038c8de \ - --hash=sha256:a113789e53ac1fa26edf99856a61e4c493868e125ae0dd6354cf518948fbbd5c \ - --hash=sha256:a522d12e2ddbc2e91842ffb454a1aeb0d47607972c7d8fc88bd0838d97fb8a2a \ - --hash=sha256:abe829275cdd4174b4c4e65ad718715d449e308d59793bf3a931ee1bf7e7b86c \ - --hash=sha256:c286985b5e194ca0ebb2908d71464b9be8f17cc66d6d3e330e8d5407248f56ad \ - --hash=sha256:cd1295f52971097f757edfbfce827b6dbbfb0f7a74901ee7d4933dff5ad4c9af \ - --hash=sha256:ceafd5e960b39c7e0d160a1936b68eb87c5e79b3979d66e774f0c77d4d8faaed \ - --hash=sha256:d1f27bb0f75bef722d6e22dc609612bfa2f994541621cd2163f8c943b6463dfe \ - --hash=sha256:d3a4e165ca6204f34856b765d515d558dc84f1352033b8721e8d06c3e44930c3 \ - --hash=sha256:d9b90bf58f3ba04e60321a23a8723a1ff2a9377502535e70495e5ada8e6e6722 \ - --hash=sha256:f72b5d24d6730035128b238decdc4c0f2104b7056a7ca55cf047c106842ec890 \ - --hash=sha256:fcddfe70553be717d9745990dfdb194e22ee0f60eb8f48c0794e7bfeda30d2d5 \ - --hash=sha256:fdb9f9ed79bc6f46b021b3319184699ba1a22410a82204e6e89c774530069683 +httptools==0.4.0 # via # -c requirements/main.txt # uvicorn -httpx==0.23.0 \ - --hash=sha256:42974f577483e1e932c3cdc3cd2303e883cbfba17fe228b0f63589764d7b9c4b \ - --hash=sha256:f28eac771ec9eb4866d3fb4ab65abd42d38c424739e80c08d8d20570de60b0ef +httpx==0.23.0 # via # -c requirements/main.txt # -r requirements/dev.in # respx -identify==2.5.1 \ - --hash=sha256:0dca2ea3e4381c435ef9c33ba100a78a9b40c0bab11189c7cf121f75815efeaa \ - --hash=sha256:3d11b16f3fe19f52039fb7e39c9c884b21cb1b586988114fbe42671f03de3e82 +identify==2.5.3 # via pre-commit -idna==3.3 \ - --hash=sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff \ - --hash=sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d +idna==3.3 # via # -c requirements/main.txt # anyio # rfc3986 -iniconfig==1.1.1 \ - --hash=sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3 \ - --hash=sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32 +iniconfig==1.1.1 # via pytest -mypy==0.961 \ - --hash=sha256:006be38474216b833eca29ff6b73e143386f352e10e9c2fbe76aa8549e5554f5 \ - --hash=sha256:03c6cc893e7563e7b2949b969e63f02c000b32502a1b4d1314cabe391aa87d66 \ - --hash=sha256:0e9f70df36405c25cc530a86eeda1e0867863d9471fe76d1273c783df3d35c2e \ - --hash=sha256:1ece702f29270ec6af25db8cf6185c04c02311c6bb21a69f423d40e527b75c56 \ - --hash=sha256:3e09f1f983a71d0672bbc97ae33ee3709d10c779beb613febc36805a6e28bb4e \ - --hash=sha256:439c726a3b3da7ca84a0199a8ab444cd8896d95012c4a6c4a0d808e3147abf5d \ - --hash=sha256:5a0b53747f713f490affdceef835d8f0cb7285187a6a44c33821b6d1f46ed813 \ - --hash=sha256:5f1332964963d4832a94bebc10f13d3279be3ce8f6c64da563d6ee6e2eeda932 \ - --hash=sha256:63e85a03770ebf403291ec50097954cc5caf2a9205c888ce3a61bd3f82e17569 \ - --hash=sha256:64759a273d590040a592e0f4186539858c948302c653c2eac840c7a3cd29e51b \ - --hash=sha256:697540876638ce349b01b6786bc6094ccdaba88af446a9abb967293ce6eaa2b0 \ - --hash=sha256:9940e6916ed9371809b35b2154baf1f684acba935cd09928952310fbddaba648 \ - --hash=sha256:9f5f5a74085d9a81a1f9c78081d60a0040c3efb3f28e5c9912b900adf59a16e6 \ - --hash=sha256:a5ea0875a049de1b63b972456542f04643daf320d27dc592d7c3d9cd5d9bf950 \ - --hash=sha256:b117650592e1782819829605a193360a08aa99f1fc23d1d71e1a75a142dc7e15 \ - --hash=sha256:b24be97351084b11582fef18d79004b3e4db572219deee0212078f7cf6352723 \ - --hash=sha256:b88f784e9e35dcaa075519096dc947a388319cb86811b6af621e3523980f1c8a \ - --hash=sha256:bdd5ca340beffb8c44cb9dc26697628d1b88c6bddf5c2f6eb308c46f269bb6f3 \ - --hash=sha256:d5aaf1edaa7692490f72bdb9fbd941fbf2e201713523bdb3f4038be0af8846c6 \ - --hash=sha256:e999229b9f3198c0c880d5e269f9f8129c8862451ce53a011326cad38b9ccd24 \ - --hash=sha256:f4a21d01fc0ba4e31d82f0fff195682e29f9401a8bdb7173891070eb260aeb3b \ - --hash=sha256:f4b794db44168a4fc886e3450201365c9526a522c46ba089b55e1f11c163750d \ - --hash=sha256:f730d56cb924d371c26b8eaddeea3cc07d78ff51c521c6d04899ac6904b75492 +mypy==0.971 # via # -r requirements/dev.in # sqlalchemy -mypy-extensions==0.4.3 \ - --hash=sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d \ - --hash=sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8 +mypy-extensions==0.4.3 # via mypy -nodeenv==1.7.0 \ - --hash=sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e \ - --hash=sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b +nodeenv==1.7.0 # via pre-commit -packaging==21.3 \ - --hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \ - --hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522 +packaging==21.3 # via # -c requirements/main.txt # pytest -platformdirs==2.5.2 \ - --hash=sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788 \ - --hash=sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19 +platformdirs==2.5.2 # via virtualenv -pluggy==1.0.0 \ - --hash=sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159 \ - --hash=sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3 +pluggy==1.0.0 # via pytest -pre-commit==2.19.0 \ - --hash=sha256:10c62741aa5704faea2ad69cb550ca78082efe5697d6f04e5710c3c229afdd10 \ - --hash=sha256:4233a1e38621c87d9dda9808c6606d7e7ba0e087cd56d3fe03202a01d2919615 +pre-commit==2.20.0 # via -r requirements/dev.in -py==1.11.0 \ - --hash=sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719 \ - --hash=sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378 +py==1.11.0 # via pytest -pyparsing==3.0.9 \ - --hash=sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb \ - --hash=sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc +pyparsing==3.0.9 # via # -c requirements/main.txt # packaging -pytest==7.1.2 \ - --hash=sha256:13d0e3ccfc2b6e26be000cb6568c832ba67ba32e719443bfe725814d3c42433c \ - --hash=sha256:a06a0425453864a270bc45e71f783330a7428defb4230fb5e6a731fde06ecd45 +pytest==7.1.2 # via # -r requirements/dev.in # pytest-asyncio # pytest-cov -pytest-asyncio==0.18.3 \ - --hash=sha256:16cf40bdf2b4fb7fc8e4b82bd05ce3fbcd454cbf7b92afc445fe299dabb88213 \ - --hash=sha256:7659bdb0a9eb9c6e3ef992eef11a2b3e69697800ad02fb06374a210d85b29f91 \ - --hash=sha256:8fafa6c52161addfd41ee7ab35f11836c5a16ec208f93ee388f752bea3493a84 +pytest-asyncio==0.19.0 # via -r requirements/dev.in -pytest-cov==3.0.0 \ - --hash=sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6 \ - --hash=sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470 +pytest-cov==3.0.0 # via -r requirements/dev.in -python-dotenv==0.20.0 \ - --hash=sha256:b7e3b04a59693c42c36f9ab1cc2acc46fa5df8c78e178fc33a8d4cd05c8d498f \ - --hash=sha256:d92a187be61fe482e4fd675b6d52200e7be63a12b724abbf931a40ce4fa92938 +python-dotenv==0.20.0 # via # -c requirements/main.txt # uvicorn -pyyaml==6.0 \ - --hash=sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293 \ - --hash=sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b \ - --hash=sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57 \ - --hash=sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b \ - --hash=sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4 \ - --hash=sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07 \ - --hash=sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba \ - --hash=sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9 \ - --hash=sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287 \ - --hash=sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513 \ - --hash=sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0 \ - --hash=sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0 \ - --hash=sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92 \ - --hash=sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f \ - --hash=sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2 \ - --hash=sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc \ - --hash=sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c \ - --hash=sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86 \ - --hash=sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4 \ - --hash=sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c \ - --hash=sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34 \ - --hash=sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b \ - --hash=sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c \ - --hash=sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb \ - --hash=sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737 \ - --hash=sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3 \ - --hash=sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d \ - --hash=sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53 \ - --hash=sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78 \ - --hash=sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803 \ - --hash=sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a \ - --hash=sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174 \ - --hash=sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5 +pyyaml==6.0 # via # -c requirements/main.txt # pre-commit # uvicorn -respx==0.19.2 \ - --hash=sha256:417f986fec599b9cc6531e93e494b7a75d1cb7bccff9dde5b53edc51f7954494 \ - --hash=sha256:f3d210bb4de0ccc4c5afabeb87c3c1b03b3765a9c1a73eb042a07bb18ac33705 +respx==0.19.2 # via -r requirements/dev.in -rfc3986[idna2008]==1.5.0 \ - --hash=sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835 \ - --hash=sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97 +rfc3986[idna2008]==1.5.0 # via # -c requirements/main.txt # httpx -six==1.16.0 \ - --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ - --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 - # via - # -c requirements/main.txt - # virtualenv -sniffio==1.2.0 \ - --hash=sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663 \ - --hash=sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de +sniffio==1.2.0 # via # -c requirements/main.txt # anyio # asgi-lifespan # httpcore # httpx -sqlalchemy[asyncio,mypy]==1.4.39 \ - --hash=sha256:047ef5ccd8860f6147b8ac6c45a4bc573d4e030267b45d9a1c47b55962ff0e6f \ - --hash=sha256:05a05771617bfa723ba4cef58d5b25ac028b0d68f28f403edebed5b8243b3a87 \ - --hash=sha256:0ec54460475f0c42512895c99c63d90dd2d9cbd0c13491a184182e85074b04c5 \ - --hash=sha256:107df519eb33d7f8e0d0d052128af2f25066c1a0f6b648fd1a9612ab66800b86 \ - --hash=sha256:14ea8ff2d33c48f8e6c3c472111d893b9e356284d1482102da9678195e5a8eac \ - --hash=sha256:1745987ada1890b0e7978abdb22c133eca2e89ab98dc17939042240063e1ef21 \ - --hash=sha256:1962dfee37b7fb17d3d4889bf84c4ea08b1c36707194c578f61e6e06d12ab90f \ - --hash=sha256:20bf65bcce65c538e68d5df27402b39341fabeecf01de7e0e72b9d9836c13c52 \ - --hash=sha256:26146c59576dfe9c546c9f45397a7c7c4a90c25679492ff610a7500afc7d03a6 \ - --hash=sha256:365b75938049ae31cf2176efd3d598213ddb9eb883fbc82086efa019a5f649df \ - --hash=sha256:4770eb3ba69ec5fa41c681a75e53e0e342ac24c1f9220d883458b5596888e43a \ - --hash=sha256:50e7569637e2e02253295527ff34666706dbb2bc5f6c61a5a7f44b9610c9bb09 \ - --hash=sha256:5c2d19bfb33262bf987ef0062345efd0f54c4189c2d95159c72995457bf4a359 \ - --hash=sha256:621f050e72cc7dfd9ad4594ff0abeaad954d6e4a2891545e8f1a53dcdfbef445 \ - --hash=sha256:6d81de54e45f1d756785405c9d06cd17918c2eecc2d4262dc2d276ca612c2f61 \ - --hash=sha256:6f95706da857e6e79b54c33c1214f5467aab10600aa508ddd1239d5df271986e \ - --hash=sha256:752ef2e8dbaa3c5d419f322e3632f00ba6b1c3230f65bc97c2ff5c5c6c08f441 \ - --hash=sha256:7b2785dd2a0c044a36836857ac27310dc7a99166253551ee8f5408930958cc60 \ - --hash=sha256:7f13644b15665f7322f9e0635129e0ef2098409484df67fcd225d954c5861559 \ - --hash=sha256:8194896038753b46b08a0b0ae89a5d80c897fb601dd51e243ed5720f1f155d27 \ - --hash=sha256:864d4f89f054819cb95e93100b7d251e4d114d1c60bc7576db07b046432af280 \ - --hash=sha256:8b773c9974c272aae0fa7e95b576d98d17ee65f69d8644f9b6ffc90ee96b4d19 \ - --hash=sha256:8f901be74f00a13bf375241a778455ee864c2c21c79154aad196b7a994e1144f \ - --hash=sha256:91d2b89bb0c302f89e753bea008936acfa4e18c156fb264fe41eb6bbb2bbcdeb \ - --hash=sha256:b0538b66f959771c56ff996d828081908a6a52a47c5548faed4a3d0a027a5368 \ - --hash=sha256:b30e70f1594ee3c8902978fd71900d7312453922827c4ce0012fa6a8278d6df4 \ - --hash=sha256:b71be98ef6e180217d1797185c75507060a57ab9cd835653e0112db16a710f0d \ - --hash=sha256:c6d00cb9da8d0cbfaba18cad046e94b06de6d4d0ffd9d4095a3ad1838af22528 \ - --hash=sha256:d1f665e50592caf4cad3caed3ed86f93227bffe0680218ccbb293bd5a6734ca8 \ - --hash=sha256:e6e2c8581c6620136b9530137954a8376efffd57fe19802182c7561b0ab48b48 \ - --hash=sha256:e7a7667d928ba6ee361a3176e1bef6847c1062b37726b33505cc84136f657e0d \ - --hash=sha256:ec3985c883d6d217cf2013028afc6e3c82b8907192ba6195d6e49885bfc4b19d \ - --hash=sha256:ede13a472caa85a13abe5095e71676af985d7690eaa8461aeac5c74f6600b6c0 \ - --hash=sha256:f24d4d6ec301688c59b0c4bb1c1c94c5d0bff4ecad33bb8f5d9efdfb8d8bc925 \ - --hash=sha256:f2a42acc01568b9701665e85562bbff78ec3e21981c7d51d56717c22e5d3d58b \ - --hash=sha256:fbc076f79d830ae4c9d49926180a1140b49fa675d0f0d555b44c9a15b29f4c80 +sqlalchemy[asyncio,mypy]==1.4.40 # via # -c requirements/main.txt # -r requirements/dev.in -sqlalchemy2-stubs==0.0.2a24 \ - --hash=sha256:e15c45302eafe196ed516f979ef017135fd619d2c62d02de9a5c5f2e59a600c4 \ - --hash=sha256:f2399251d3d8f00a88659d711a449c855a0d4e977c7a9134e414f1459b9acc11 +sqlalchemy2-stubs==0.0.2a25 # via sqlalchemy -toml==0.10.2 \ - --hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b \ - --hash=sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f +toml==0.10.2 # via pre-commit -tomli==2.0.1 \ - --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ - --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f +tomli==2.0.1 # via # -c requirements/main.txt # coverage # mypy # pytest -types-pyyaml==6.0.9 \ - --hash=sha256:33ae75c84b8f61fddf0c63e9c7e557db9db1694ad3c2ee8628ec5efebb5a5e9b \ - --hash=sha256:b738e9ef120da0af8c235ba49d3b72510f56ef9bcc308fc8e7357100ff122284 +types-pyyaml==6.0.11 # via -r requirements/dev.in -typing-extensions==4.2.0 \ - --hash=sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708 \ - --hash=sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376 +typing-extensions==4.3.0 # via # -c requirements/main.txt # mypy # sqlalchemy2-stubs -uvicorn[standard]==0.18.1 \ - --hash=sha256:013c4ea0787cc2dc456ef4368e18c01982e6be57903e4d3183218e543eb889b7 \ - --hash=sha256:35703e6518105cfe53f16a5a9435db3e2e227d0784f1fd8fbc1214b1fdc108df +uvicorn[standard]==0.18.2 # via # -c requirements/main.txt # -r requirements/dev.in -uvloop==0.16.0 \ - --hash=sha256:04ff57aa137230d8cc968f03481176041ae789308b4d5079118331ab01112450 \ - --hash=sha256:089b4834fd299d82d83a25e3335372f12117a7d38525217c2258e9b9f4578897 \ - --hash=sha256:1e5f2e2ff51aefe6c19ee98af12b4ae61f5be456cd24396953244a30880ad861 \ - --hash=sha256:30ba9dcbd0965f5c812b7c2112a1ddf60cf904c1c160f398e7eed3a6b82dcd9c \ - --hash=sha256:3a19828c4f15687675ea912cc28bbcb48e9bb907c801873bd1519b96b04fb805 \ - --hash=sha256:6224f1401025b748ffecb7a6e2652b17768f30b1a6a3f7b44660e5b5b690b12d \ - --hash=sha256:647e481940379eebd314c00440314c81ea547aa636056f554d491e40503c8464 \ - --hash=sha256:6ccd57ae8db17d677e9e06192e9c9ec4bd2066b77790f9aa7dede2cc4008ee8f \ - --hash=sha256:772206116b9b57cd625c8a88f2413df2fcfd0b496eb188b82a43bed7af2c2ec9 \ - --hash=sha256:8e0d26fa5875d43ddbb0d9d79a447d2ace4180d9e3239788208527c4784f7cab \ - --hash=sha256:98d117332cc9e5ea8dfdc2b28b0a23f60370d02e1395f88f40d1effd2cb86c4f \ - --hash=sha256:b572256409f194521a9895aef274cea88731d14732343da3ecdb175228881638 \ - --hash=sha256:bd53f7f5db562f37cd64a3af5012df8cac2c464c97e732ed556800129505bd64 \ - --hash=sha256:bd8f42ea1ea8f4e84d265769089964ddda95eb2bb38b5cbe26712b0616c3edee \ - --hash=sha256:e814ac2c6f9daf4c36eb8e85266859f42174a4ff0d71b99405ed559257750382 \ - --hash=sha256:f74bc20c7b67d1c27c72601c78cf95be99d5c2cdd4514502b4f3eb0933ff1228 +uvloop==0.16.0 # via # -c requirements/main.txt # uvicorn -virtualenv==20.15.0 \ - --hash=sha256:4c44b1d77ca81f8368e2d7414f9b20c428ad16b343ac6d226206c5b84e2b4fcc \ - --hash=sha256:804cce4de5b8a322f099897e308eecc8f6e2951f1a8e7e2b3598dff865f01336 +virtualenv==20.16.3 # via pre-commit -watchfiles==0.15.0 \ - --hash=sha256:56abed43e645d1f2d6def83e35999cc5758b051aff54ca1065cbfcaea15b3389 \ - --hash=sha256:65ca99a94fcab29d00aa406526eb29cf198c0661854d59a315596064fed02141 \ - --hash=sha256:67d4c66e46a564059df4aeedab78f09cba0b697bf36cc77566b0a7015dfb7f5d \ - --hash=sha256:6e0e8829d32b05151e6009570449f44f891e05f518e495d25f960e0d0b2d0064 \ - --hash=sha256:715733c2ac9da67b2790788657ff6f8b3797eb31565bfc592289b523ae907ca2 \ - --hash=sha256:7b81c6e404b2aa62482a719eb778e4a16d01728302dce1f1512c1e5354a73fda \ - --hash=sha256:82238d08d8a49f1a1ba254278cd4329a154f6100b028393059722ebeddd2ff3d \ - --hash=sha256:955e8f840e1996a8a41be57de4c03af7b1515a685b7fb6abe222f859e413a907 \ - --hash=sha256:cab62510f990d195986302aa6a48ed636d685b099927049120d520c96069fa49 \ - --hash=sha256:d1f9de6b776b3aff17898a4cf5ac5a2d0a16212ea7aad2bbe0ef6aa3e79a96af \ - --hash=sha256:d4f45acd1143db6d3ee77a4ff12d3239bc8083108133e6174e9dcce59c1f9902 \ - --hash=sha256:f7f71012e096e11256fae3b37617a9777980f281e18deb2e789e85cd5b113935 +watchfiles==0.16.1 # via # -c requirements/main.txt # uvicorn -websockets==10.3 \ - --hash=sha256:07cdc0a5b2549bcfbadb585ad8471ebdc7bdf91e32e34ae3889001c1c106a6af \ - --hash=sha256:210aad7fdd381c52e58777560860c7e6110b6174488ef1d4b681c08b68bf7f8c \ - --hash=sha256:28dd20b938a57c3124028680dc1600c197294da5db4292c76a0b48efb3ed7f76 \ - --hash=sha256:2f94fa3ae454a63ea3a19f73b95deeebc9f02ba2d5617ca16f0bbdae375cda47 \ - --hash=sha256:31564a67c3e4005f27815634343df688b25705cccb22bc1db621c781ddc64c69 \ - --hash=sha256:347974105bbd4ea068106ec65e8e8ebd86f28c19e529d115d89bd8cc5cda3079 \ - --hash=sha256:379e03422178436af4f3abe0aa8f401aa77ae2487843738542a75faf44a31f0c \ - --hash=sha256:3eda1cb7e9da1b22588cefff09f0951771d6ee9fa8dbe66f5ae04cc5f26b2b55 \ - --hash=sha256:51695d3b199cd03098ae5b42833006a0f43dc5418d3102972addc593a783bc02 \ - --hash=sha256:54c000abeaff6d8771a4e2cef40900919908ea7b6b6a30eae72752607c6db559 \ - --hash=sha256:5b936bf552e4f6357f5727579072ff1e1324717902127ffe60c92d29b67b7be3 \ - --hash=sha256:6075fd24df23133c1b078e08a9b04a3bc40b31a8def4ee0b9f2c8865acce913e \ - --hash=sha256:661f641b44ed315556a2fa630239adfd77bd1b11cb0b9d96ed8ad90b0b1e4978 \ - --hash=sha256:6ea6b300a6bdd782e49922d690e11c3669828fe36fc2471408c58b93b5535a98 \ - --hash=sha256:6ed1d6f791eabfd9808afea1e068f5e59418e55721db8b7f3bfc39dc831c42ae \ - --hash=sha256:7934e055fd5cd9dee60f11d16c8d79c4567315824bacb1246d0208a47eca9755 \ - --hash=sha256:7ab36e17af592eec5747c68ef2722a74c1a4a70f3772bc661079baf4ae30e40d \ - --hash=sha256:7f6d96fdb0975044fdd7953b35d003b03f9e2bcf85f2d2cf86285ece53e9f991 \ - --hash=sha256:83e5ca0d5b743cde3d29fda74ccab37bdd0911f25bd4cdf09ff8b51b7b4f2fa1 \ - --hash=sha256:85506b3328a9e083cc0a0fb3ba27e33c8db78341b3eb12eb72e8afd166c36680 \ - --hash=sha256:8af75085b4bc0b5c40c4a3c0e113fa95e84c60f4ed6786cbb675aeb1ee128247 \ - --hash=sha256:8b1359aba0ff810d5830d5ab8e2c4a02bebf98a60aa0124fb29aa78cfdb8031f \ - --hash=sha256:8fbd7d77f8aba46d43245e86dd91a8970eac4fb74c473f8e30e9c07581f852b2 \ - --hash=sha256:907e8247480f287aa9bbc9391bd6de23c906d48af54c8c421df84655eef66af7 \ - --hash=sha256:93d5ea0b5da8d66d868b32c614d2b52d14304444e39e13a59566d4acb8d6e2e4 \ - --hash=sha256:97bc9d41e69a7521a358f9b8e44871f6cdeb42af31815c17aed36372d4eec667 \ - --hash=sha256:994cdb1942a7a4c2e10098d9162948c9e7b235df755de91ca33f6e0481366fdb \ - --hash=sha256:a141de3d5a92188234afa61653ed0bbd2dde46ad47b15c3042ffb89548e77094 \ - --hash=sha256:a1e15b230c3613e8ea82c9fc6941b2093e8eb939dd794c02754d33980ba81e36 \ - --hash=sha256:aad5e300ab32036eb3fdc350ad30877210e2f51bceaca83fb7fef4d2b6c72b79 \ - --hash=sha256:b529fdfa881b69fe563dbd98acce84f3e5a67df13de415e143ef053ff006d500 \ - --hash=sha256:b9c77f0d1436ea4b4dc089ed8335fa141e6a251a92f75f675056dac4ab47a71e \ - --hash=sha256:bb621ec2dbbbe8df78a27dbd9dd7919f9b7d32a73fafcb4d9252fc4637343582 \ - --hash=sha256:c7250848ce69559756ad0086a37b82c986cd33c2d344ab87fea596c5ac6d9442 \ - --hash=sha256:c8d1d14aa0f600b5be363077b621b1b4d1eb3fbf90af83f9281cda668e6ff7fd \ - --hash=sha256:d1655a6fc7aecd333b079d00fb3c8132d18988e47f19740c69303bf02e9883c6 \ - --hash=sha256:d6353ba89cfc657a3f5beabb3b69be226adbb5c6c7a66398e17809b0ce3c4731 \ - --hash=sha256:da4377904a3379f0c1b75a965fff23b28315bcd516d27f99a803720dfebd94d4 \ - --hash=sha256:e49ea4c1a9543d2bd8a747ff24411509c29e4bdcde05b5b0895e2120cb1a761d \ - --hash=sha256:e4e08305bfd76ba8edab08dcc6496f40674f44eb9d5e23153efa0a35750337e8 \ - --hash=sha256:e6fa05a680e35d0fcc1470cb070b10e6fe247af54768f488ed93542e71339d6f \ - --hash=sha256:e7e6f2d6fd48422071cc8a6f8542016f350b79cc782752de531577d35e9bd677 \ - --hash=sha256:e904c0381c014b914136c492c8fa711ca4cced4e9b3d110e5e7d436d0fc289e8 \ - --hash=sha256:ec2b0ab7edc8cd4b0eb428b38ed89079bdc20c6bdb5f889d353011038caac2f9 \ - --hash=sha256:ef5ce841e102278c1c2e98f043db99d6755b1c58bde475516aef3a008ed7f28e \ - --hash=sha256:f351c7d7d92f67c0609329ab2735eee0426a03022771b00102816a72715bb00b \ - --hash=sha256:fab7c640815812ed5f10fbee7abbf58788d602046b7bb3af9b1ac753a6d5e916 \ - --hash=sha256:fc06cc8073c8e87072138ba1e431300e2d408f054b27047d047b549455066ff4 +websockets==10.3 # via # -c requirements/main.txt # uvicorn -# WARNING: The following packages were not pinned, but pip requires them to be -# pinned when the requirements file includes hashes. Consider using the --allow-unsafe flag. -# setuptools +# The following packages are considered to be unsafe in a requirements file: +setuptools==65.0.0 + # via + # -c requirements/main.txt + # nodeenv diff --git a/requirements/main.txt b/requirements/main.txt index 7894e573..d038bbf4 100644 --- a/requirements/main.txt +++ b/requirements/main.txt @@ -2,950 +2,236 @@ # This file is autogenerated by pip-compile with python 3.10 # To update, run: # -# pip-compile --generate-hashes --output-file=requirements/main.txt requirements/main.in +# pip-compile --allow-unsafe --output-file=requirements/main.txt requirements/main.in # -aioredis==2.0.1 \ - --hash=sha256:9ac0d0b3b485d293b8ca1987e6de8658d7dafcca1cddfcd1d506cae8cdebfdd6 \ - --hash=sha256:eaa51aaf993f2d71f54b70527c440437ba65340588afeb786cd87c55c89cd98e +aioredis==2.0.1 # via -r requirements/main.in -anyio==3.6.1 \ - --hash=sha256:413adf95f93886e442aea925f3ee43baa5a765a64a0f52c6081894f9992fdd0b \ - --hash=sha256:cb29b9c70620506a9a8f87a309591713446953302d7d995344d0d7c6c0c9a7be +anyio==3.6.1 # via # httpcore # starlette # watchfiles -arq==0.23a1 \ - --hash=sha256:7cec3b9584f7ac735f4ee93e88c27a8eb4552d379ea8d76f84b60f52fc404f03 \ - --hash=sha256:b60a347be3865ab058284320c5309a3303f8466d0843de44de9633e74871194f +arq==0.23a1 # via safir -async-timeout==4.0.2 \ - --hash=sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15 \ - --hash=sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c +async-timeout==4.0.2 # via # aioredis # redis -asyncpg==0.25.0 \ - --hash=sha256:0a61fb196ce4dae2f2fa26eb20a778db21bbee484d2e798cb3cc988de13bdd1b \ - --hash=sha256:18d49e2d93a7139a2fdbd113e320cc47075049997268a61bfbe0dde680c55471 \ - --hash=sha256:191fe6341385b7fdea7dbdcf47fd6db3fd198827dcc1f2b228476d13c05a03c6 \ - --hash=sha256:1a70783f6ffa34cc7dd2de20a873181414a34fd35a4a208a1f1a7f9f695e4ec4 \ - --hash=sha256:2633331cbc8429030b4f20f712f8d0fbba57fa8555ee9b2f45f981b81328b256 \ - --hash=sha256:2bc197fc4aca2fd24f60241057998124012469d2e414aed3f992579db0c88e3a \ - --hash=sha256:4327f691b1bdb222df27841938b3e04c14068166b3a97491bec2cb982f49f03e \ - --hash=sha256:43cde84e996a3afe75f325a68300093425c2f47d340c0fc8912765cf24a1c095 \ - --hash=sha256:52fab7f1b2c29e187dd8781fce896249500cf055b63471ad66332e537e9b5f7e \ - --hash=sha256:56d88d7ef4341412cd9c68efba323a4519c916979ba91b95d4c08799d2ff0c09 \ - --hash=sha256:5e4105f57ad1e8fbc8b1e535d8fcefa6ce6c71081228f08680c6dea24384ff0e \ - --hash=sha256:63f8e6a69733b285497c2855464a34de657f2cccd25aeaeeb5071872e9382540 \ - --hash=sha256:649e2966d98cc48d0646d9a4e29abecd8b59d38d55c256d5c857f6b27b7407ac \ - --hash=sha256:6f8f5fc975246eda83da8031a14004b9197f510c41511018e7b1bedde6968e92 \ - --hash=sha256:72a1e12ea0cf7c1e02794b697e3ca967b2360eaa2ce5d4bfdd8604ec2d6b774b \ - --hash=sha256:739bbd7f89a2b2f6bc44cb8bf967dab12c5bc714fcbe96e68d512be45ecdf962 \ - --hash=sha256:863d36eba4a7caa853fd7d83fad5fd5306f050cc2fe6e54fbe10cdb30420e5e9 \ - --hash=sha256:a738f1b2876f30d710d3dc1e7858160a0afe1603ba16bf5f391f5316eb0ed855 \ - --hash=sha256:a84d30e6f850bac0876990bcd207362778e2208df0bee8be8da9f1558255e634 \ - --hash=sha256:acb311722352152936e58a8ee3c5b8e791b24e84cd7d777c414ff05b3530ca68 \ - --hash=sha256:beaecc52ad39614f6ca2e48c3ca15d56e24a2c15cbfdcb764a4320cc45f02fd5 \ - --hash=sha256:bf5e3408a14a17d480f36ebaf0401a12ff6ae5457fdf45e4e2775c51cc9517d3 \ - --hash=sha256:bf6dc9b55b9113f39eaa2057337ce3f9ef7de99a053b8a16360395ce588925cd \ - --hash=sha256:ddb4c3263a8d63dcde3d2c4ac1c25206bfeb31fa83bd70fd539e10f87739dee4 \ - --hash=sha256:f55918ded7b85723a5eaeb34e86e7b9280d4474be67df853ab5a7fa0cc7c6bf2 \ - --hash=sha256:fe471ccd915b739ca65e2e4dbd92a11b44a5b37f2e38f70827a1c147dafe0fa8 +asyncpg==0.26.0 # via safir -attrs==21.4.0 \ - --hash=sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4 \ - --hash=sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd +attrs==22.1.0 # via jsonschema -beautifulsoup4==4.11.1 \ - --hash=sha256:58d5c3d29f5a36ffeb94f02f0d786cd53014cf9b3b3951d42e0080d8a9498d30 \ - --hash=sha256:ad9aa55b65ef2808eb405f46cf74df7fcb7044d5cbc26487f96eb2ef2e436693 +beautifulsoup4==4.11.1 # via nbconvert -bleach==5.0.0 \ - --hash=sha256:08a1fe86d253b5c88c92cc3d810fd8048a16d15762e1e5b74d502256e5926aa1 \ - --hash=sha256:c6d6cc054bdc9c83b48b8083e236e5f00f238428666d2ce2e083eaa5fd568565 +bleach==5.0.1 # via nbconvert -certifi==2022.6.15 \ - --hash=sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d \ - --hash=sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412 +certifi==2022.6.15 # via # httpcore # httpx -cffi==1.15.0 \ - --hash=sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3 \ - --hash=sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2 \ - --hash=sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636 \ - --hash=sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20 \ - --hash=sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728 \ - --hash=sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27 \ - --hash=sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66 \ - --hash=sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443 \ - --hash=sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0 \ - --hash=sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7 \ - --hash=sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39 \ - --hash=sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605 \ - --hash=sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a \ - --hash=sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37 \ - --hash=sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029 \ - --hash=sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139 \ - --hash=sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc \ - --hash=sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df \ - --hash=sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14 \ - --hash=sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880 \ - --hash=sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2 \ - --hash=sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a \ - --hash=sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e \ - --hash=sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474 \ - --hash=sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024 \ - --hash=sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8 \ - --hash=sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0 \ - --hash=sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e \ - --hash=sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a \ - --hash=sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e \ - --hash=sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032 \ - --hash=sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6 \ - --hash=sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e \ - --hash=sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b \ - --hash=sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e \ - --hash=sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954 \ - --hash=sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962 \ - --hash=sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c \ - --hash=sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4 \ - --hash=sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55 \ - --hash=sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962 \ - --hash=sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023 \ - --hash=sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c \ - --hash=sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6 \ - --hash=sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8 \ - --hash=sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382 \ - --hash=sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7 \ - --hash=sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc \ - --hash=sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997 \ - --hash=sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796 +cffi==1.15.1 # via cryptography -click==8.1.3 \ - --hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \ - --hash=sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48 +click==8.1.3 # via # -r requirements/main.in # arq # uvicorn -cryptography==37.0.2 \ - --hash=sha256:093cb351031656d3ee2f4fa1be579a8c69c754cf874206be1d4cf3b542042804 \ - --hash=sha256:0cc20f655157d4cfc7bada909dc5cc228211b075ba8407c46467f63597c78178 \ - --hash=sha256:1b9362d34363f2c71b7853f6251219298124aa4cc2075ae2932e64c91a3e2717 \ - --hash=sha256:1f3bfbd611db5cb58ca82f3deb35e83af34bb8cf06043fa61500157d50a70982 \ - --hash=sha256:2bd1096476aaac820426239ab534b636c77d71af66c547b9ddcd76eb9c79e004 \ - --hash=sha256:31fe38d14d2e5f787e0aecef831457da6cec68e0bb09a35835b0b44ae8b988fe \ - --hash=sha256:3b8398b3d0efc420e777c40c16764d6870bcef2eb383df9c6dbb9ffe12c64452 \ - --hash=sha256:3c81599befb4d4f3d7648ed3217e00d21a9341a9a688ecdd615ff72ffbed7336 \ - --hash=sha256:419c57d7b63f5ec38b1199a9521d77d7d1754eb97827bbb773162073ccd8c8d4 \ - --hash=sha256:46f4c544f6557a2fefa7ac8ac7d1b17bf9b647bd20b16decc8fbcab7117fbc15 \ - --hash=sha256:471e0d70201c069f74c837983189949aa0d24bb2d751b57e26e3761f2f782b8d \ - --hash=sha256:59b281eab51e1b6b6afa525af2bd93c16d49358404f814fe2c2410058623928c \ - --hash=sha256:731c8abd27693323b348518ed0e0705713a36d79fdbd969ad968fbef0979a7e0 \ - --hash=sha256:95e590dd70642eb2079d280420a888190aa040ad20f19ec8c6e097e38aa29e06 \ - --hash=sha256:a68254dd88021f24a68b613d8c51d5c5e74d735878b9e32cc0adf19d1f10aaf9 \ - --hash=sha256:a7d5137e556cc0ea418dca6186deabe9129cee318618eb1ffecbd35bee55ddc1 \ - --hash=sha256:aeaba7b5e756ea52c8861c133c596afe93dd716cbcacae23b80bc238202dc023 \ - --hash=sha256:dc26bb134452081859aa21d4990474ddb7e863aa39e60d1592800a8865a702de \ - --hash=sha256:e53258e69874a306fcecb88b7534d61820db8a98655662a3dd2ec7f1afd9132f \ - --hash=sha256:ef15c2df7656763b4ff20a9bc4381d8352e6640cfeb95c2972c38ef508e75181 \ - --hash=sha256:f224ad253cc9cea7568f49077007d2263efa57396a2f2f78114066fd54b5c68e \ - --hash=sha256:f8ec91983e638a9bcd75b39f1396e5c0dc2330cbd9ce4accefe68717e6779e0a +cryptography==37.0.4 # via pyjwt -defusedxml==0.7.1 \ - --hash=sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69 \ - --hash=sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61 +defusedxml==0.7.1 # via nbconvert -deprecated==1.2.13 \ - --hash=sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d \ - --hash=sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d +deprecated==1.2.13 # via redis -dnspython==2.2.1 \ - --hash=sha256:0f7569a4a6ff151958b64304071d370daa3243d15941a7beedf0c9fe5105603e \ - --hash=sha256:a851e51367fb93e9e1361732c1d60dab63eff98712e503ea7d92e6eccb109b4f +dnspython==2.2.1 # via email-validator -email-validator==1.2.1 \ - --hash=sha256:6757aea012d40516357c0ac2b1a4c31219ab2f899d26831334c5d069e8b6c3d8 \ - --hash=sha256:c8589e691cf73eb99eed8d10ce0e9cbb05a0886ba920c8bcb7c82873f4c5789c +email-validator==1.2.1 # via pydantic -entrypoints==0.4 \ - --hash=sha256:b706eddaa9218a19ebcd67b56818f05bb27589b1ca9e8d797b74affad4ccacd4 \ - --hash=sha256:f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f +entrypoints==0.4 # via # jupyter-client # nbconvert -fastapi==0.78.0 \ - --hash=sha256:15fcabd5c78c266fa7ae7d8de9b384bfc2375ee0503463a6febbe3bab69d6f65 \ - --hash=sha256:3233d4a789ba018578658e2af1a4bb5e38bdd122ff722b313666a9b2c6786a83 +fastapi==0.79.0 # via # -r requirements/main.in # safir -fastjsonschema==2.15.3 \ - --hash=sha256:0a572f0836962d844c1fc435e200b2e4f4677e4e6611a2e3bdd01ba697c275ec \ - --hash=sha256:ddb0b1d8243e6e3abb822bd14e447a89f4ab7439342912d590444831fa00b6a0 +fastjsonschema==2.16.1 # via nbformat -gidgethub==5.2.0 \ - --hash=sha256:390caafb3e9c6125bb9c8c9865a78d09e028f19592352d5b88e0ed881b8dea18 \ - --hash=sha256:c359b769194e72f984d2e328de0ee8eb81b702342b0a44dc5cebac92104ecf4b +gidgethub==5.2.0 # via -r requirements/main.in -greenlet==1.1.2 \ - --hash=sha256:0051c6f1f27cb756ffc0ffbac7d2cd48cb0362ac1736871399a739b2885134d3 \ - --hash=sha256:00e44c8afdbe5467e4f7b5851be223be68adb4272f44696ee71fe46b7036a711 \ - --hash=sha256:013d61294b6cd8fe3242932c1c5e36e5d1db2c8afb58606c5a67efce62c1f5fd \ - --hash=sha256:049fe7579230e44daef03a259faa24511d10ebfa44f69411d99e6a184fe68073 \ - --hash=sha256:14d4f3cd4e8b524ae9b8aa567858beed70c392fdec26dbdb0a8a418392e71708 \ - --hash=sha256:166eac03e48784a6a6e0e5f041cfebb1ab400b394db188c48b3a84737f505b67 \ - --hash=sha256:17ff94e7a83aa8671a25bf5b59326ec26da379ace2ebc4411d690d80a7fbcf23 \ - --hash=sha256:1e12bdc622676ce47ae9abbf455c189e442afdde8818d9da983085df6312e7a1 \ - --hash=sha256:21915eb821a6b3d9d8eefdaf57d6c345b970ad722f856cd71739493ce003ad08 \ - --hash=sha256:288c6a76705dc54fba69fbcb59904ae4ad768b4c768839b8ca5fdadec6dd8cfd \ - --hash=sha256:2bde6792f313f4e918caabc46532aa64aa27a0db05d75b20edfc5c6f46479de2 \ - --hash=sha256:32ca72bbc673adbcfecb935bb3fb1b74e663d10a4b241aaa2f5a75fe1d1f90aa \ - --hash=sha256:356b3576ad078c89a6107caa9c50cc14e98e3a6c4874a37c3e0273e4baf33de8 \ - --hash=sha256:40b951f601af999a8bf2ce8c71e8aaa4e8c6f78ff8afae7b808aae2dc50d4c40 \ - --hash=sha256:572e1787d1460da79590bf44304abbc0a2da944ea64ec549188fa84d89bba7ab \ - --hash=sha256:58df5c2a0e293bf665a51f8a100d3e9956febfbf1d9aaf8c0677cf70218910c6 \ - --hash=sha256:64e6175c2e53195278d7388c454e0b30997573f3f4bd63697f88d855f7a6a1fc \ - --hash=sha256:7227b47e73dedaa513cdebb98469705ef0d66eb5a1250144468e9c3097d6b59b \ - --hash=sha256:7418b6bfc7fe3331541b84bb2141c9baf1ec7132a7ecd9f375912eca810e714e \ - --hash=sha256:7cbd7574ce8e138bda9df4efc6bf2ab8572c9aff640d8ecfece1b006b68da963 \ - --hash=sha256:7ff61ff178250f9bb3cd89752df0f1dd0e27316a8bd1465351652b1b4a4cdfd3 \ - --hash=sha256:833e1551925ed51e6b44c800e71e77dacd7e49181fdc9ac9a0bf3714d515785d \ - --hash=sha256:8639cadfda96737427330a094476d4c7a56ac03de7265622fcf4cfe57c8ae18d \ - --hash=sha256:8c5d5b35f789a030ebb95bff352f1d27a93d81069f2adb3182d99882e095cefe \ - --hash=sha256:8c790abda465726cfb8bb08bd4ca9a5d0a7bd77c7ac1ca1b839ad823b948ea28 \ - --hash=sha256:8d2f1fb53a421b410751887eb4ff21386d119ef9cde3797bf5e7ed49fb51a3b3 \ - --hash=sha256:903bbd302a2378f984aef528f76d4c9b1748f318fe1294961c072bdc7f2ffa3e \ - --hash=sha256:93f81b134a165cc17123626ab8da2e30c0455441d4ab5576eed73a64c025b25c \ - --hash=sha256:95e69877983ea39b7303570fa6760f81a3eec23d0e3ab2021b7144b94d06202d \ - --hash=sha256:9633b3034d3d901f0a46b7939f8c4d64427dfba6bbc5a36b1a67364cf148a1b0 \ - --hash=sha256:97e5306482182170ade15c4b0d8386ded995a07d7cc2ca8f27958d34d6736497 \ - --hash=sha256:9f3cba480d3deb69f6ee2c1825060177a22c7826431458c697df88e6aeb3caee \ - --hash=sha256:aa5b467f15e78b82257319aebc78dd2915e4c1436c3c0d1ad6f53e47ba6e2713 \ - --hash=sha256:abb7a75ed8b968f3061327c433a0fbd17b729947b400747c334a9c29a9af6c58 \ - --hash=sha256:aec52725173bd3a7b56fe91bc56eccb26fbdff1386ef123abb63c84c5b43b63a \ - --hash=sha256:b11548073a2213d950c3f671aa88e6f83cda6e2fb97a8b6317b1b5b33d850e06 \ - --hash=sha256:b1692f7d6bc45e3200844be0dba153612103db241691088626a33ff1f24a0d88 \ - --hash=sha256:b336501a05e13b616ef81ce329c0e09ac5ed8c732d9ba7e3e983fcc1a9e86965 \ - --hash=sha256:b8c008de9d0daba7b6666aa5bbfdc23dcd78cafc33997c9b7741ff6353bafb7f \ - --hash=sha256:b92e29e58bef6d9cfd340c72b04d74c4b4e9f70c9fa7c78b674d1fec18896dc4 \ - --hash=sha256:be5f425ff1f5f4b3c1e33ad64ab994eed12fc284a6ea71c5243fd564502ecbe5 \ - --hash=sha256:dd0b1e9e891f69e7675ba5c92e28b90eaa045f6ab134ffe70b52e948aa175b3c \ - --hash=sha256:e30f5ea4ae2346e62cedde8794a56858a67b878dd79f7df76a0767e356b1744a \ - --hash=sha256:e6a36bb9474218c7a5b27ae476035497a6990e21d04c279884eb10d9b290f1b1 \ - --hash=sha256:e859fcb4cbe93504ea18008d1df98dee4f7766db66c435e4882ab35cf70cac43 \ - --hash=sha256:eb6ea6da4c787111adf40f697b4e58732ee0942b5d3bd8f435277643329ba627 \ - --hash=sha256:ec8c433b3ab0419100bd45b47c9c8551248a5aee30ca5e9d399a0b57ac04651b \ - --hash=sha256:eff9d20417ff9dcb0d25e2defc2574d10b491bf2e693b4e491914738b7908168 \ - --hash=sha256:f0214eb2a23b85528310dad848ad2ac58e735612929c8072f6093f3585fd342d \ - --hash=sha256:f276df9830dba7a333544bd41070e8175762a7ac20350786b322b714b0e654f5 \ - --hash=sha256:f3acda1924472472ddd60c29e5b9db0cec629fbe3c5c5accb74d6d6d14773478 \ - --hash=sha256:f70a9e237bb792c7cc7e44c531fd48f5897961701cdaa06cf22fc14965c496cf \ - --hash=sha256:f9d29ca8a77117315101425ec7ec2a47a22ccf59f5593378fc4077ac5b754fce \ - --hash=sha256:fa877ca7f6b48054f847b61d6fa7bed5cebb663ebc55e018fda12db09dcc664c \ - --hash=sha256:fdcec0b8399108577ec290f55551d926d9a1fa6cad45882093a7a07ac5ec147b +greenlet==1.1.2 # via sqlalchemy -gunicorn==20.1.0 \ - --hash=sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e \ - --hash=sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8 +gunicorn==20.1.0 # via -r requirements/main.in -h11==0.12.0 \ - --hash=sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6 \ - --hash=sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042 +h11==0.12.0 # via # httpcore # uvicorn -httpcore==0.15.0 \ - --hash=sha256:1105b8b73c025f23ff7c36468e4432226cbb959176eab66864b8e31c4ee27fa6 \ - --hash=sha256:18b68ab86a3ccf3e7dc0f43598eaddcf472b602aba29f9aa6ab85fe2ada3980b +httpcore==0.15.0 # via httpx -httptools==0.4.0 \ - --hash=sha256:1a99346ebcb801b213c591540837340bdf6fd060a8687518d01c607d338b7424 \ - --hash=sha256:1ee0b459257e222b878a6c09ccf233957d3a4dcb883b0847640af98d2d9aac23 \ - --hash=sha256:20a45bcf22452a10fa8d58b7dbdb474381f6946bf5b8933e3662d572bc61bae4 \ - --hash=sha256:29bf97a5c532da9c7a04de2c7a9c31d1d54f3abd65a464119b680206bbbb1055 \ - --hash=sha256:2c9a930c378b3d15d6b695fb95ebcff81a7395b4f9775c4f10a076beb0b2c1ff \ - --hash=sha256:2db44a0b294d317199e9f80123e72c6b005c55b625b57fae36de68670090fa48 \ - --hash=sha256:3194f6d6443befa8d4db16c1946b2fc428a3ceb8ab32eb6f09a59f86104dc1a0 \ - --hash=sha256:34d2903dd2a3dd85d33705b6fde40bf91fc44411661283763fd0746723963c83 \ - --hash=sha256:48e48530d9b995a84d1d89ae6b3ec4e59ea7d494b150ac3bbc5e2ac4acce92cd \ - --hash=sha256:54bbd295f031b866b9799dd39cb45deee81aca036c9bff9f58ca06726f6494f1 \ - --hash=sha256:5d1fe6b6661022fd6cac541f54a4237496b246e6f1c0a6b41998ee08a1135afe \ - --hash=sha256:645373c070080e632480a3d251d892cb795be3d3a15f86975d0f1aca56fd230d \ - --hash=sha256:6a1a7dfc1f9c78a833e2c4904757a0f47ce25d08634dd2a52af394eefe5f9777 \ - --hash=sha256:701e66b59dd21a32a274771238025d58db7e2b6ecebbab64ceff51b8e31527ae \ - --hash=sha256:72aa3fbe636b16d22e04b5a9d24711b043495e0ecfe58080addf23a1a37f3409 \ - --hash=sha256:7af6bdbd21a2a25d6784f6d67f44f5df33ef39b6159543b9f9064d365c01f919 \ - --hash=sha256:7ee9f226acab9085037582c059d66769862706e8e8cd2340470ceb8b3850873d \ - --hash=sha256:7f7bfb74718f52d5ed47d608d507bf66d3bc01d4a8b3e6dd7134daaae129357b \ - --hash=sha256:8e2eb957787cbb614a0f006bfc5798ff1d90ac7c4dd24854c84edbdc8c02369e \ - --hash=sha256:903f739c9fb78dab8970b0f3ea51f21955b24b45afa77b22ff0e172fc11ef111 \ - --hash=sha256:98993805f1e3cdb53de4eed02b55dcc953cdf017ba7bbb2fd89226c086a6d855 \ - --hash=sha256:9967d9758df505975913304c434cb9ab21e2c609ad859eb921f2f615a038c8de \ - --hash=sha256:a113789e53ac1fa26edf99856a61e4c493868e125ae0dd6354cf518948fbbd5c \ - --hash=sha256:a522d12e2ddbc2e91842ffb454a1aeb0d47607972c7d8fc88bd0838d97fb8a2a \ - --hash=sha256:abe829275cdd4174b4c4e65ad718715d449e308d59793bf3a931ee1bf7e7b86c \ - --hash=sha256:c286985b5e194ca0ebb2908d71464b9be8f17cc66d6d3e330e8d5407248f56ad \ - --hash=sha256:cd1295f52971097f757edfbfce827b6dbbfb0f7a74901ee7d4933dff5ad4c9af \ - --hash=sha256:ceafd5e960b39c7e0d160a1936b68eb87c5e79b3979d66e774f0c77d4d8faaed \ - --hash=sha256:d1f27bb0f75bef722d6e22dc609612bfa2f994541621cd2163f8c943b6463dfe \ - --hash=sha256:d3a4e165ca6204f34856b765d515d558dc84f1352033b8721e8d06c3e44930c3 \ - --hash=sha256:d9b90bf58f3ba04e60321a23a8723a1ff2a9377502535e70495e5ada8e6e6722 \ - --hash=sha256:f72b5d24d6730035128b238decdc4c0f2104b7056a7ca55cf047c106842ec890 \ - --hash=sha256:fcddfe70553be717d9745990dfdb194e22ee0f60eb8f48c0794e7bfeda30d2d5 \ - --hash=sha256:fdb9f9ed79bc6f46b021b3319184699ba1a22410a82204e6e89c774530069683 +httptools==0.4.0 # via uvicorn -httpx==0.23.0 \ - --hash=sha256:42974f577483e1e932c3cdc3cd2303e883cbfba17fe228b0f63589764d7b9c4b \ - --hash=sha256:f28eac771ec9eb4866d3fb4ab65abd42d38c424739e80c08d8d20570de60b0ef +httpx==0.23.0 # via safir -idna==3.3 \ - --hash=sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff \ - --hash=sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d +idna==3.3 # via # anyio # email-validator # rfc3986 -jinja2==3.1.2 \ - --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \ - --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61 +jinja2==3.1.2 # via # -r requirements/main.in # nbconvert -jsonschema==4.6.0 \ - --hash=sha256:1c92d2db1900b668201f1797887d66453ab1fbfea51df8e4b46236689c427baf \ - --hash=sha256:9d6397ba4a6c0bf0300736057f649e3e12ecbc07d3e81a0dacb72de4e9801957 +jsonschema==4.9.1 # via # -r requirements/main.in # nbformat -jupyter-client==7.3.4 \ - --hash=sha256:17d74b0d0a7b24f1c8c527b24fcf4607c56bee542ffe8e3418e50b21e514b621 \ - --hash=sha256:aa9a6c32054b290374f95f73bb0cae91455c58dfb84f65c8591912b8f65e6d56 +jupyter-client==7.3.4 # via nbclient -jupyter-core==4.10.0 \ - --hash=sha256:a6de44b16b7b31d7271130c71a6792c4040f077011961138afed5e5e73181aec \ - --hash=sha256:e7f5212177af7ab34179690140f188aa9bf3d322d8155ed972cbded19f55b6f3 +jupyter-core==4.11.1 # via # jupyter-client # nbconvert # nbformat -jupyterlab-pygments==0.2.2 \ - --hash=sha256:2405800db07c9f770863bcf8049a529c3dd4d3e28536638bd7c1c01d2748309f \ - --hash=sha256:7405d7fde60819d905a9fa8ce89e4cd830e318cdad22a0030f7a901da705585d +jupyterlab-pygments==0.2.2 # via nbconvert -linkify-it-py==1.0.3 \ - --hash=sha256:11e29f00150cddaa8f434153f103c14716e7e097a8fd372d9eb1ed06ed91524d \ - --hash=sha256:2b3f168d5ce75e3a425e34b341a6b73e116b5d9ed8dbbbf5dc7456843b7ce2ee +linkify-it-py==1.0.3 # via markdown-it-py -markdown-it-py[linkify,plugins]==2.1.0 \ - --hash=sha256:93de681e5c021a432c63147656fe21790bc01231e0cd2da73626f1aa3ac0fe27 \ - --hash=sha256:cf7e59fed14b5ae17c0006eff14a2d9a00ed5f3a846148153899a0224e2c07da +lxml==4.9.1 + # via nbconvert +markdown-it-py[linkify,plugins]==2.1.0 # via # -r requirements/main.in # mdformat # mdformat-gfm # mdit-py-plugins -markupsafe==2.1.1 \ - --hash=sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003 \ - --hash=sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88 \ - --hash=sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5 \ - --hash=sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7 \ - --hash=sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a \ - --hash=sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603 \ - --hash=sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1 \ - --hash=sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135 \ - --hash=sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247 \ - --hash=sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6 \ - --hash=sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601 \ - --hash=sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77 \ - --hash=sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02 \ - --hash=sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e \ - --hash=sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63 \ - --hash=sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f \ - --hash=sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980 \ - --hash=sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b \ - --hash=sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812 \ - --hash=sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff \ - --hash=sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96 \ - --hash=sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1 \ - --hash=sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925 \ - --hash=sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a \ - --hash=sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6 \ - --hash=sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e \ - --hash=sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f \ - --hash=sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4 \ - --hash=sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f \ - --hash=sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3 \ - --hash=sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c \ - --hash=sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a \ - --hash=sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417 \ - --hash=sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a \ - --hash=sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a \ - --hash=sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37 \ - --hash=sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452 \ - --hash=sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933 \ - --hash=sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a \ - --hash=sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7 +markupsafe==2.1.1 # via # jinja2 # nbconvert -mdformat==0.7.14 \ - --hash=sha256:530eabe496726bd5f4dec5635c37c2496f4c8abc4c15fafa606919b48d92a9d9 \ - --hash=sha256:60c457955f795e5a030e24bc96be30a29eee7836ba98b32e02581688da7670c5 +mdformat==0.7.14 # via # -r requirements/main.in # mdformat-gfm # mdformat-tables -mdformat-gfm==0.3.5 \ - --hash=sha256:1e627edc7665b59e008b3b9e5decc18c40cbd625c196d77e5ea3bc624e80ac8a \ - --hash=sha256:5ee5f0de1d3b56d5edfced023bfff0aeed958be328e5460dac3221ac1b61ce7c +mdformat-gfm==0.3.5 # via -r requirements/main.in -mdformat-tables==0.4.1 \ - --hash=sha256:3024e88e9d29d7b8bb07fd6b59c9d5dcf14d2060122be29e30e72d27b65d7da9 \ - --hash=sha256:981f3dc7350027f78e3fd6a5fe8a16e123eec423af2d140e588d855751501019 +mdformat-tables==0.4.1 # via mdformat-gfm -mdit-py-plugins==0.3.0 \ - --hash=sha256:b1279701cee2dbf50e188d3da5f51fee8d78d038cdf99be57c6b9d1aa93b4073 \ - --hash=sha256:ecc24f51eeec6ab7eecc2f9724e8272c2fb191c2e93cf98109120c2cace69750 +mdit-py-plugins==0.3.0 # via # markdown-it-py # mdformat-gfm -mdurl==0.1.1 \ - --hash=sha256:6a8f6804087b7128040b2fb2ebe242bdc2affaeaa034d5fc9feeed30b443651b \ - --hash=sha256:f79c9709944df218a4cdb0fcc0b0c7ead2f44594e3e84dc566606f04ad749c20 +mdurl==0.1.2 # via markdown-it-py -mistune==0.8.4 \ - --hash=sha256:59a3429db53c50b5c6bcc8a07f8848cb00d7dc8bdb431a4ab41920d201d4756e \ - --hash=sha256:88a1051873018da288eee8538d476dffe1262495144b33ecb586c4ab266bb8d4 +mistune==0.8.4 # via nbconvert -nbclient==0.6.4 \ - --hash=sha256:cdef7757cead1735d2c70cc66095b072dced8a1e6d1c7639ef90cd3e04a11f2e \ - --hash=sha256:f251bba200a2b401a061dfd700a7a70b5772f664fb49d4a2d3e5536ec0e98c76 +nbclient==0.6.6 # via nbconvert -nbconvert==6.5.0 \ - --hash=sha256:223e46e27abe8596b8aed54301fadbba433b7ffea8196a68fd7b1ff509eee99d \ - --hash=sha256:c56dd0b8978a1811a5654f74c727ff16ca87dd5a43abd435a1c49b840fcd8360 +nbconvert==6.5.3 # via -r requirements/main.in -nbformat==5.4.0 \ - --hash=sha256:0d6072aaec95dddc39735c144ee8bbc6589c383fb462e4058abc855348152dad \ - --hash=sha256:44ba5ca6acb80c5d5a500f1e5b83ede8cbe364d5a495c4c8cf60aaf1ba656501 +nbformat==5.4.0 # via # -r requirements/main.in # nbclient # nbconvert -nest-asyncio==1.5.5 \ - --hash=sha256:b98e3ec1b246135e4642eceffa5a6c23a3ab12c82ff816a92c612d68205813b2 \ - --hash=sha256:e442291cd942698be619823a17a86a5759eabe1f8613084790de189fe9e16d65 +nest-asyncio==1.5.5 # via # jupyter-client # nbclient -packaging==21.3 \ - --hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \ - --hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522 +packaging==21.3 # via # nbconvert # redis -pandocfilters==1.5.0 \ - --hash=sha256:0b679503337d233b4339a817bfc8c50064e2eff681314376a47cb582305a7a38 \ - --hash=sha256:33aae3f25fd1a026079f5d27bdd52496f0e0803b3469282162bafdcbdf6ef14f +pandocfilters==1.5.0 # via nbconvert -pycparser==2.21 \ - --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ - --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 +pycparser==2.21 # via cffi -pydantic[email]==1.9.1 \ - --hash=sha256:02eefd7087268b711a3ff4db528e9916ac9aa18616da7bca69c1871d0b7a091f \ - --hash=sha256:059b6c1795170809103a1538255883e1983e5b831faea6558ef873d4955b4a74 \ - --hash=sha256:0bf07cab5b279859c253d26a9194a8906e6f4a210063b84b433cf90a569de0c1 \ - --hash=sha256:1542636a39c4892c4f4fa6270696902acb186a9aaeac6f6cf92ce6ae2e88564b \ - --hash=sha256:177071dfc0df6248fd22b43036f936cfe2508077a72af0933d0c1fa269b18537 \ - --hash=sha256:18f3e912f9ad1bdec27fb06b8198a2ccc32f201e24174cec1b3424dda605a310 \ - --hash=sha256:1dd8fecbad028cd89d04a46688d2fcc14423e8a196d5b0a5c65105664901f810 \ - --hash=sha256:1ed987c3ff29fff7fd8c3ea3a3ea877ad310aae2ef9889a119e22d3f2db0691a \ - --hash=sha256:447d5521575f18e18240906beadc58551e97ec98142266e521c34968c76c8761 \ - --hash=sha256:494f7c8537f0c02b740c229af4cb47c0d39840b829ecdcfc93d91dcbb0779892 \ - --hash=sha256:4988c0f13c42bfa9ddd2fe2f569c9d54646ce84adc5de84228cfe83396f3bd58 \ - --hash=sha256:4ce9ae9e91f46c344bec3b03d6ee9612802682c1551aaf627ad24045ce090761 \ - --hash=sha256:5d93d4e95eacd313d2c765ebe40d49ca9dd2ed90e5b37d0d421c597af830c195 \ - --hash=sha256:61b6760b08b7c395975d893e0b814a11cf011ebb24f7d869e7118f5a339a82e1 \ - --hash=sha256:72ccb318bf0c9ab97fc04c10c37683d9eea952ed526707fabf9ac5ae59b701fd \ - --hash=sha256:79b485767c13788ee314669008d01f9ef3bc05db9ea3298f6a50d3ef596a154b \ - --hash=sha256:7eb57ba90929bac0b6cc2af2373893d80ac559adda6933e562dcfb375029acee \ - --hash=sha256:8bc541a405423ce0e51c19f637050acdbdf8feca34150e0d17f675e72d119580 \ - --hash=sha256:969dd06110cb780da01336b281f53e2e7eb3a482831df441fb65dd30403f4608 \ - --hash=sha256:985ceb5d0a86fcaa61e45781e567a59baa0da292d5ed2e490d612d0de5796918 \ - --hash=sha256:9bcf8b6e011be08fb729d110f3e22e654a50f8a826b0575c7196616780683380 \ - --hash=sha256:9ce157d979f742a915b75f792dbd6aa63b8eccaf46a1005ba03aa8a986bde34a \ - --hash=sha256:9f659a5ee95c8baa2436d392267988fd0f43eb774e5eb8739252e5a7e9cf07e0 \ - --hash=sha256:a4a88dcd6ff8fd47c18b3a3709a89adb39a6373f4482e04c1b765045c7e282fd \ - --hash=sha256:a955260d47f03df08acf45689bd163ed9df82c0e0124beb4251b1290fa7ae728 \ - --hash=sha256:a9af62e9b5b9bc67b2a195ebc2c2662fdf498a822d62f902bf27cccb52dbbf49 \ - --hash=sha256:ae72f8098acb368d877b210ebe02ba12585e77bd0db78ac04a1ee9b9f5dd2166 \ - --hash=sha256:b83ba3825bc91dfa989d4eed76865e71aea3a6ca1388b59fc801ee04c4d8d0d6 \ - --hash=sha256:c11951b404e08b01b151222a1cb1a9f0a860a8153ce8334149ab9199cd198131 \ - --hash=sha256:c320c64dd876e45254bdd350f0179da737463eea41c43bacbee9d8c9d1021f11 \ - --hash=sha256:c8098a724c2784bf03e8070993f6d46aa2eeca031f8d8a048dff277703e6e193 \ - --hash=sha256:d12f96b5b64bec3f43c8e82b4aab7599d0157f11c798c9f9c528a72b9e0b339a \ - --hash=sha256:e565a785233c2d03724c4dc55464559639b1ba9ecf091288dd47ad9c629433bd \ - --hash=sha256:f0f047e11febe5c3198ed346b507e1d010330d56ad615a7e0a89fae604065a0e \ - --hash=sha256:fe4670cb32ea98ffbf5a1262f14c3e102cccd92b1869df3bb09538158ba90fe6 +pydantic[email]==1.9.2 # via # -r requirements/main.in # arq # fastapi # safir -pygments==2.12.0 \ - --hash=sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb \ - --hash=sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519 +pygments==2.13.0 # via nbconvert -pyjwt[crypto]==2.4.0 \ - --hash=sha256:72d1d253f32dbd4f5c88eaf1fdc62f3a19f676ccbadb9dbc5d07e951b2b26daf \ - --hash=sha256:d42908208c699b3b973cbeb01a969ba6a96c821eefb1c5bfe4c390c01d67abba +pyjwt[crypto]==2.4.0 # via gidgethub -pyparsing==3.0.9 \ - --hash=sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb \ - --hash=sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc +pyparsing==3.0.9 # via packaging -pyrsistent==0.18.1 \ - --hash=sha256:0e3e1fcc45199df76053026a51cc59ab2ea3fc7c094c6627e93b7b44cdae2c8c \ - --hash=sha256:1b34eedd6812bf4d33814fca1b66005805d3640ce53140ab8bbb1e2651b0d9bc \ - --hash=sha256:4ed6784ceac462a7d6fcb7e9b663e93b9a6fb373b7f43594f9ff68875788e01e \ - --hash=sha256:5d45866ececf4a5fff8742c25722da6d4c9e180daa7b405dc0a2a2790d668c26 \ - --hash=sha256:636ce2dc235046ccd3d8c56a7ad54e99d5c1cd0ef07d9ae847306c91d11b5fec \ - --hash=sha256:6455fc599df93d1f60e1c5c4fe471499f08d190d57eca040c0ea182301321286 \ - --hash=sha256:6bc66318fb7ee012071b2792024564973ecc80e9522842eb4e17743604b5e045 \ - --hash=sha256:7bfe2388663fd18bd8ce7db2c91c7400bf3e1a9e8bd7d63bf7e77d39051b85ec \ - --hash=sha256:7ec335fc998faa4febe75cc5268a9eac0478b3f681602c1f27befaf2a1abe1d8 \ - --hash=sha256:914474c9f1d93080338ace89cb2acee74f4f666fb0424896fcfb8d86058bf17c \ - --hash=sha256:b568f35ad53a7b07ed9b1b2bae09eb15cdd671a5ba5d2c66caee40dbf91c68ca \ - --hash=sha256:cdfd2c361b8a8e5d9499b9082b501c452ade8bbf42aef97ea04854f4a3f43b22 \ - --hash=sha256:d1b96547410f76078eaf66d282ddca2e4baae8964364abb4f4dcdde855cd123a \ - --hash=sha256:d4d61f8b993a7255ba714df3aca52700f8125289f84f704cf80916517c46eb96 \ - --hash=sha256:d7a096646eab884bf8bed965bad63ea327e0d0c38989fc83c5ea7b8a87037bfc \ - --hash=sha256:df46c854f490f81210870e509818b729db4488e1f30f2a1ce1698b2295a878d1 \ - --hash=sha256:e24a828f57e0c337c8d8bb9f6b12f09dfdf0273da25fda9e314f0b684b415a07 \ - --hash=sha256:e4f3149fd5eb9b285d6bfb54d2e5173f6a116fe19172686797c056672689daf6 \ - --hash=sha256:e92a52c166426efbe0d1ec1332ee9119b6d32fc1f0bbfd55d5c1088070e7fc1b \ - --hash=sha256:f87cc2863ef33c709e237d4b5f4502a62a00fab450c9e020892e8e2ede5847f5 \ - --hash=sha256:fd8da6d0124efa2f67d86fa70c851022f87c98e205f0594e1fae044e7119a5a6 +pyrsistent==0.18.1 # via jsonschema -python-dateutil==2.8.2 \ - --hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \ - --hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9 +python-dateutil==2.8.2 # via jupyter-client -python-dotenv==0.20.0 \ - --hash=sha256:b7e3b04a59693c42c36f9ab1cc2acc46fa5df8c78e178fc33a8d4cd05c8d498f \ - --hash=sha256:d92a187be61fe482e4fd675b6d52200e7be63a12b724abbf931a40ce4fa92938 +python-dotenv==0.20.0 # via uvicorn -pyyaml==6.0 \ - --hash=sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293 \ - --hash=sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b \ - --hash=sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57 \ - --hash=sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b \ - --hash=sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4 \ - --hash=sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07 \ - --hash=sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba \ - --hash=sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9 \ - --hash=sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287 \ - --hash=sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513 \ - --hash=sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0 \ - --hash=sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0 \ - --hash=sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92 \ - --hash=sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f \ - --hash=sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2 \ - --hash=sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc \ - --hash=sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c \ - --hash=sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86 \ - --hash=sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4 \ - --hash=sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c \ - --hash=sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34 \ - --hash=sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b \ - --hash=sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c \ - --hash=sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb \ - --hash=sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737 \ - --hash=sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3 \ - --hash=sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d \ - --hash=sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53 \ - --hash=sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78 \ - --hash=sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803 \ - --hash=sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a \ - --hash=sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174 \ - --hash=sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5 +pyyaml==6.0 # via # -r requirements/main.in # uvicorn -pyzmq==23.2.0 \ - --hash=sha256:004a431dfa0459123e6f4660d7e3c4ac19217d134ca38bacfffb2e78716fe944 \ - --hash=sha256:057b154471e096e2dda147f7b057041acc303bb7ca4aa24c3b88c6cecdd78717 \ - --hash=sha256:0e08671dc202a1880fa522f921f35ca5925ba30da8bc96228d74a8f0643ead9c \ - --hash=sha256:1b2a21f595f8cc549abd6c8de1fcd34c83441e35fb24b8a59bf161889c62a486 \ - --hash=sha256:21552624ce69e69f7924f413b802b1fb554f4c0497f837810e429faa1cd4f163 \ - --hash=sha256:22ac0243a41798e3eb5d5714b28c2f28e3d10792dffbc8a5fca092f975fdeceb \ - --hash=sha256:2b054525c9f7e240562185bf21671ca16d56bde92e9bd0f822c07dec7626b704 \ - --hash=sha256:30c365e60c39c53f8eea042b37ea28304ffa6558fb7241cf278745095a5757da \ - --hash=sha256:3a4d87342c2737fbb9eee5c33c792db27b36b04957b4e6b7edd73a5b239a2a13 \ - --hash=sha256:420b9abd1a7330687a095373b8280a20cdee04342fbc8ccb3b56d9ec8efd4e62 \ - --hash=sha256:444f7d615d5f686d0ef508b9edfa8a286e6d89f449a1ba37b60ef69d869220a3 \ - --hash=sha256:558f5f636e3e65f261b64925e8b190e8689e334911595394572cc7523879006d \ - --hash=sha256:5592fb4316f895922b1cacb91b04a0fa09d6f6f19bbab4442b4d0a0825177b93 \ - --hash=sha256:59928dfebe93cf1e203e3cb0fd5d5dd384da56b99c8305f2e1b0a933751710f6 \ - --hash=sha256:5cb642e94337b0c76c9c8cb9bfb0f8a78654575847d080d3e1504f312d691fc3 \ - --hash=sha256:5d57542429df6acff02ff022067aa75b677603cee70e3abb9742787545eec966 \ - --hash=sha256:5d92e7cbeab7f70b08cc0f27255b0bb2500afc30f31075bca0b1cb87735d186c \ - --hash=sha256:602835e5672ca9ca1d78e6c148fb28c4f91b748ebc41fbd2f479d8763d58bc9b \ - --hash=sha256:60746a7e8558655420a69441c0a1d47ed225ed3ac355920b96a96d0554ef7e6b \ - --hash=sha256:61b97f624da42813f74977425a3a6144d604ea21cf065616d36ea3a866d92c1c \ - --hash=sha256:693c96ae4d975eb8efa1639670e9b1fac0c3f98b7845b65c0f369141fb4bb21f \ - --hash=sha256:814e5aaf0c3be9991a59066eafb2d6e117aed6b413e3e7e9be45d4e55f5e2748 \ - --hash=sha256:83005d8928f8a5cebcfb33af3bfb84b1ad65d882b899141a331cc5d07d89f093 \ - --hash=sha256:831da96ba3f36cc892f0afbb4fb89b28b61b387261676e55d55a682addbd29f7 \ - --hash=sha256:8355744fdbdeac5cfadfa4f38b82029b5f2b8cab7472a33453a217a7f3a9dce2 \ - --hash=sha256:8496a2a5efd055c61ac2c6a18116c768a25c644b6747dcfde43e91620ab3453c \ - --hash=sha256:859059caf564f0c9398c9005278055ed3d37af4d73de6b1597821193b04ca09b \ - --hash=sha256:8c0f4d6f8c985bab83792be26ff3233940ba42e22237610ac50cbcfc10a5c235 \ - --hash=sha256:8c2d8b69a2bf239ae3d987537bf3fbc2b044a405394cf4c258fc684971dd48b2 \ - --hash=sha256:984b232802eddf9f0be264a4d57a10b3a1fd7319df14ee6fc7b41c6d155a3e6c \ - --hash=sha256:99cedf38eaddf263cf7e2a50e405f12c02cedf6d9df00a0d9c5d7b9417b57f76 \ - --hash=sha256:a3dc339f7bc185d5fd0fd976242a5baf35de404d467e056484def8a4dd95868b \ - --hash=sha256:a51f12a8719aad9dcfb55d456022f16b90abc8dde7d3ca93ce3120b40e3fa169 \ - --hash=sha256:bbabd1df23bf63ae829e81200034c0e433499275a6ed29ca1a912ea7629426d9 \ - --hash=sha256:bcc6953e47bcfc9028ddf9ab2a321a3c51d7cc969db65edec092019bb837959f \ - --hash=sha256:c0a5f987d73fd9b46c3d180891f829afda714ab6bab30a1218724d4a0a63afd8 \ - --hash=sha256:c223a13555444707a0a7ebc6f9ee63053147c8c082bd1a31fd1207a03e8b0500 \ - --hash=sha256:c616893a577e9d6773a3836732fd7e2a729157a108b8fccd31c87512fa01671a \ - --hash=sha256:c882f1d4f96fbd807e92c334251d8ebd159a1ef89059ccd386ddea83fdb91bd8 \ - --hash=sha256:c8dec8a2f3f0bb462e6439df436cd8c7ec37968e90b4209ac621e7fbc0ed3b00 \ - --hash=sha256:c9638e0057e3f1a8b7c5ce33c7575349d9183a033a19b5676ad55096ae36820b \ - --hash=sha256:ce4f71e17fa849de41a06109030d3f6815fcc33338bf98dd0dde6d456d33c929 \ - --hash=sha256:ced12075cdf3c7332ecc1960f77f7439d5ebb8ea20bbd3c34c8299e694f1b0a1 \ - --hash=sha256:d11628212fd731b8986f1561d9bb3f8c38d9c15b330c3d8a88963519fbcd553b \ - --hash=sha256:d1610260cc672975723fcf7705c69a95f3b88802a594c9867781bedd9b13422c \ - --hash=sha256:d4651de7316ec8560afe430fb042c0782ed8ac54c0be43a515944d7c78fddac8 \ - --hash=sha256:da338e2728410d74ddeb1479ec67cfba73311607037455a40f92b6f5c62bf11d \ - --hash=sha256:de727ea906033b30527b4a99498f19aca3f4d1073230a958679a5b726e2784e0 \ - --hash=sha256:e2e2db5c6ef376e97c912733dfc24406f5949474d03e800d5f07b6aca4d870af \ - --hash=sha256:e669913cb2179507628419ec4f0e453e48ce6f924de5884d396f18c31836089c \ - --hash=sha256:eb4a573a8499685d62545e806d8fd143c84ac8b3439f925cd92c8763f0ed9bd7 \ - --hash=sha256:f146648941cadaaaf01254a75651a23c08159d009d36c5af42a7cc200a5e53ec \ - --hash=sha256:f3ff6abde52e702397949054cb5b06c1c75b5d6542f6a2ce029e46f71ffbbbf2 \ - --hash=sha256:f5aa9da520e4bb8cee8189f2f541701405e7690745094ded7a37b425d60527ea \ - --hash=sha256:f5fdb00d65ec44b10cc6b9b6318ef1363b81647a4aa3270ca39565eadb2d1201 \ - --hash=sha256:f685003d836ad0e5d4f08d1e024ee3ac7816eb2f873b2266306eef858f058133 \ - --hash=sha256:fee86542dc4ee8229e023003e3939b4d58cc2453922cf127778b69505fc9064b +pyzmq==23.2.1 # via jupyter-client -redis==4.3.3 \ - --hash=sha256:2f7a57cf4af15cd543c4394bcbe2b9148db2606a37edba755368836e3a1d053e \ - --hash=sha256:f57f8df5d238a8ecf92f499b6b21467bfee6c13d89953c27edf1e2bc673622e7 +redis==4.3.4 # via arq -rfc3986[idna2008]==1.5.0 \ - --hash=sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835 \ - --hash=sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97 +rfc3986[idna2008]==1.5.0 # via httpx -safir[arq,db]==3.2.0 \ - --hash=sha256:3573c6f24043004591e5c070a7b7f2445fdf575e1114f2cecfb34164dc33e5a0 \ - --hash=sha256:c0b51c0d0a0fd05549329122aa6ebb9affdedc56861691cea1cc98939bfd9621 +safir[arq,db]==3.2.0 # via -r requirements/main.in -six==1.16.0 \ - --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ - --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 +six==1.16.0 # via # bleach # python-dateutil -sniffio==1.2.0 \ - --hash=sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663 \ - --hash=sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de +sniffio==1.2.0 # via # anyio # httpcore # httpx -soupsieve==2.3.2.post1 \ - --hash=sha256:3b2503d3c7084a42b1ebd08116e5f81aadfaea95863628c80a3b774a11b7c759 \ - --hash=sha256:fc53893b3da2c33de295667a0e19f078c14bf86544af307354de5fcf12a3f30d +soupsieve==2.3.2.post1 # via beautifulsoup4 -sqlalchemy[asyncio]==1.4.39 \ - --hash=sha256:047ef5ccd8860f6147b8ac6c45a4bc573d4e030267b45d9a1c47b55962ff0e6f \ - --hash=sha256:05a05771617bfa723ba4cef58d5b25ac028b0d68f28f403edebed5b8243b3a87 \ - --hash=sha256:0ec54460475f0c42512895c99c63d90dd2d9cbd0c13491a184182e85074b04c5 \ - --hash=sha256:107df519eb33d7f8e0d0d052128af2f25066c1a0f6b648fd1a9612ab66800b86 \ - --hash=sha256:14ea8ff2d33c48f8e6c3c472111d893b9e356284d1482102da9678195e5a8eac \ - --hash=sha256:1745987ada1890b0e7978abdb22c133eca2e89ab98dc17939042240063e1ef21 \ - --hash=sha256:1962dfee37b7fb17d3d4889bf84c4ea08b1c36707194c578f61e6e06d12ab90f \ - --hash=sha256:20bf65bcce65c538e68d5df27402b39341fabeecf01de7e0e72b9d9836c13c52 \ - --hash=sha256:26146c59576dfe9c546c9f45397a7c7c4a90c25679492ff610a7500afc7d03a6 \ - --hash=sha256:365b75938049ae31cf2176efd3d598213ddb9eb883fbc82086efa019a5f649df \ - --hash=sha256:4770eb3ba69ec5fa41c681a75e53e0e342ac24c1f9220d883458b5596888e43a \ - --hash=sha256:50e7569637e2e02253295527ff34666706dbb2bc5f6c61a5a7f44b9610c9bb09 \ - --hash=sha256:5c2d19bfb33262bf987ef0062345efd0f54c4189c2d95159c72995457bf4a359 \ - --hash=sha256:621f050e72cc7dfd9ad4594ff0abeaad954d6e4a2891545e8f1a53dcdfbef445 \ - --hash=sha256:6d81de54e45f1d756785405c9d06cd17918c2eecc2d4262dc2d276ca612c2f61 \ - --hash=sha256:6f95706da857e6e79b54c33c1214f5467aab10600aa508ddd1239d5df271986e \ - --hash=sha256:752ef2e8dbaa3c5d419f322e3632f00ba6b1c3230f65bc97c2ff5c5c6c08f441 \ - --hash=sha256:7b2785dd2a0c044a36836857ac27310dc7a99166253551ee8f5408930958cc60 \ - --hash=sha256:7f13644b15665f7322f9e0635129e0ef2098409484df67fcd225d954c5861559 \ - --hash=sha256:8194896038753b46b08a0b0ae89a5d80c897fb601dd51e243ed5720f1f155d27 \ - --hash=sha256:864d4f89f054819cb95e93100b7d251e4d114d1c60bc7576db07b046432af280 \ - --hash=sha256:8b773c9974c272aae0fa7e95b576d98d17ee65f69d8644f9b6ffc90ee96b4d19 \ - --hash=sha256:8f901be74f00a13bf375241a778455ee864c2c21c79154aad196b7a994e1144f \ - --hash=sha256:91d2b89bb0c302f89e753bea008936acfa4e18c156fb264fe41eb6bbb2bbcdeb \ - --hash=sha256:b0538b66f959771c56ff996d828081908a6a52a47c5548faed4a3d0a027a5368 \ - --hash=sha256:b30e70f1594ee3c8902978fd71900d7312453922827c4ce0012fa6a8278d6df4 \ - --hash=sha256:b71be98ef6e180217d1797185c75507060a57ab9cd835653e0112db16a710f0d \ - --hash=sha256:c6d00cb9da8d0cbfaba18cad046e94b06de6d4d0ffd9d4095a3ad1838af22528 \ - --hash=sha256:d1f665e50592caf4cad3caed3ed86f93227bffe0680218ccbb293bd5a6734ca8 \ - --hash=sha256:e6e2c8581c6620136b9530137954a8376efffd57fe19802182c7561b0ab48b48 \ - --hash=sha256:e7a7667d928ba6ee361a3176e1bef6847c1062b37726b33505cc84136f657e0d \ - --hash=sha256:ec3985c883d6d217cf2013028afc6e3c82b8907192ba6195d6e49885bfc4b19d \ - --hash=sha256:ede13a472caa85a13abe5095e71676af985d7690eaa8461aeac5c74f6600b6c0 \ - --hash=sha256:f24d4d6ec301688c59b0c4bb1c1c94c5d0bff4ecad33bb8f5d9efdfb8d8bc925 \ - --hash=sha256:f2a42acc01568b9701665e85562bbff78ec3e21981c7d51d56717c22e5d3d58b \ - --hash=sha256:fbc076f79d830ae4c9d49926180a1140b49fa675d0f0d555b44c9a15b29f4c80 +sqlalchemy[asyncio]==1.4.40 # via safir -starlette==0.19.1 \ - --hash=sha256:5a60c5c2d051f3a8eb546136aa0c9399773a689595e099e0877704d5888279bf \ - --hash=sha256:c6d21096774ecb9639acad41b86b7706e52ba3bf1dc13ea4ed9ad593d47e24c7 +starlette==0.19.1 # via # -r requirements/main.in # fastapi # safir -structlog==21.5.0 \ - --hash=sha256:68c4c29c003714fe86834f347cb107452847ba52414390a7ee583472bde00fc9 \ - --hash=sha256:fd7922e195262b337da85c2a91c84be94ccab1f8fd1957bd6986f6904e3761c8 +structlog==22.1.0 # via safir -tinycss2==1.1.1 \ - --hash=sha256:b2e44dd8883c360c35dd0d1b5aad0b610e5156c2cb3b33434634e539ead9d8bf \ - --hash=sha256:fe794ceaadfe3cf3e686b22155d0da5780dd0e273471a51846d0a02bc204fec8 +tinycss2==1.1.1 # via nbconvert -tomli==2.0.1 \ - --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ - --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f +tomli==2.0.1 # via mdformat -tornado==6.1 \ - --hash=sha256:0a00ff4561e2929a2c37ce706cb8233b7907e0cdc22eab98888aca5dd3775feb \ - --hash=sha256:0d321a39c36e5f2c4ff12b4ed58d41390460f798422c4504e09eb5678e09998c \ - --hash=sha256:1e8225a1070cd8eec59a996c43229fe8f95689cb16e552d130b9793cb570a288 \ - --hash=sha256:20241b3cb4f425e971cb0a8e4ffc9b0a861530ae3c52f2b0434e6c1b57e9fd95 \ - --hash=sha256:25ad220258349a12ae87ede08a7b04aca51237721f63b1808d39bdb4b2164558 \ - --hash=sha256:33892118b165401f291070100d6d09359ca74addda679b60390b09f8ef325ffe \ - --hash=sha256:33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791 \ - --hash=sha256:3447475585bae2e77ecb832fc0300c3695516a47d46cefa0528181a34c5b9d3d \ - --hash=sha256:34ca2dac9e4d7afb0bed4677512e36a52f09caa6fded70b4e3e1c89dbd92c326 \ - --hash=sha256:3e63498f680547ed24d2c71e6497f24bca791aca2fe116dbc2bd0ac7f191691b \ - --hash=sha256:548430be2740e327b3fe0201abe471f314741efcb0067ec4f2d7dcfb4825f3e4 \ - --hash=sha256:6196a5c39286cc37c024cd78834fb9345e464525d8991c21e908cc046d1cc02c \ - --hash=sha256:61b32d06ae8a036a6607805e6720ef00a3c98207038444ba7fd3d169cd998910 \ - --hash=sha256:6286efab1ed6e74b7028327365cf7346b1d777d63ab30e21a0f4d5b275fc17d5 \ - --hash=sha256:65d98939f1a2e74b58839f8c4dab3b6b3c1ce84972ae712be02845e65391ac7c \ - --hash=sha256:66324e4e1beede9ac79e60f88de548da58b1f8ab4b2f1354d8375774f997e6c0 \ - --hash=sha256:6c77c9937962577a6a76917845d06af6ab9197702a42e1346d8ae2e76b5e3675 \ - --hash=sha256:70dec29e8ac485dbf57481baee40781c63e381bebea080991893cd297742b8fd \ - --hash=sha256:7250a3fa399f08ec9cb3f7b1b987955d17e044f1ade821b32e5f435130250d7f \ - --hash=sha256:748290bf9112b581c525e6e6d3820621ff020ed95af6f17fedef416b27ed564c \ - --hash=sha256:7da13da6f985aab7f6f28debab00c67ff9cbacd588e8477034c0652ac141feea \ - --hash=sha256:8f959b26f2634a091bb42241c3ed8d3cedb506e7c27b8dd5c7b9f745318ddbb6 \ - --hash=sha256:9de9e5188a782be6b1ce866e8a51bc76a0fbaa0e16613823fc38e4fc2556ad05 \ - --hash=sha256:a48900ecea1cbb71b8c71c620dee15b62f85f7c14189bdeee54966fbd9a0c5bd \ - --hash=sha256:b87936fd2c317b6ee08a5741ea06b9d11a6074ef4cc42e031bc6403f82a32575 \ - --hash=sha256:c77da1263aa361938476f04c4b6c8916001b90b2c2fdd92d8d535e1af48fba5a \ - --hash=sha256:cb5ec8eead331e3bb4ce8066cf06d2dfef1bfb1b2a73082dfe8a161301b76e37 \ - --hash=sha256:cc0ee35043162abbf717b7df924597ade8e5395e7b66d18270116f8745ceb795 \ - --hash=sha256:d14d30e7f46a0476efb0deb5b61343b1526f73ebb5ed84f23dc794bdb88f9d9f \ - --hash=sha256:d371e811d6b156d82aa5f9a4e08b58debf97c302a35714f6f45e35139c332e32 \ - --hash=sha256:d3d20ea5782ba63ed13bc2b8c291a053c8d807a8fa927d941bd718468f7b950c \ - --hash=sha256:d3f7594930c423fd9f5d1a76bee85a2c36fd8b4b16921cae7e965f22575e9c01 \ - --hash=sha256:dcef026f608f678c118779cd6591c8af6e9b4155c44e0d1bc0c87c036fb8c8c4 \ - --hash=sha256:e0791ac58d91ac58f694d8d2957884df8e4e2f6687cdf367ef7eb7497f79eaa2 \ - --hash=sha256:e385b637ac3acaae8022e7e47dfa7b83d3620e432e3ecb9a3f7f58f150e50921 \ - --hash=sha256:e519d64089b0876c7b467274468709dadf11e41d65f63bba207e04217f47c085 \ - --hash=sha256:e7229e60ac41a1202444497ddde70a48d33909e484f96eb0da9baf8dc68541df \ - --hash=sha256:ed3ad863b1b40cd1d4bd21e7498329ccaece75db5a5bf58cd3c9f130843e7102 \ - --hash=sha256:f0ba29bafd8e7e22920567ce0d232c26d4d47c8b5cf4ed7b562b5db39fa199c5 \ - --hash=sha256:fa2ba70284fa42c2a5ecb35e322e68823288a4251f9ba9cc77be04ae15eada68 \ - --hash=sha256:fba85b6cd9c39be262fcd23865652920832b61583de2a2ca907dbd8e8a8c81e5 +tornado==6.2 # via jupyter-client -traitlets==5.3.0 \ - --hash=sha256:0bb9f1f9f017aa8ec187d8b1b2a7a6626a2a1d877116baba52a129bfa124f8e2 \ - --hash=sha256:65fa18961659635933100db8ca120ef6220555286949774b9cfc106f941d1c7a +traitlets==5.3.0 # via # jupyter-client # jupyter-core # nbclient # nbconvert # nbformat -typing-extensions==4.2.0 \ - --hash=sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708 \ - --hash=sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376 +typing-extensions==4.3.0 # via # aioredis # pydantic -uc-micro-py==1.0.1 \ - --hash=sha256:316cfb8b6862a0f1d03540f0ae6e7b033ff1fa0ddbe60c12cbe0d4cec846a69f \ - --hash=sha256:b7cdf4ea79433043ddfe2c82210208f26f7962c0cfbe3bacb05ee879a7fdb596 +uc-micro-py==1.0.1 # via linkify-it-py -uritemplate==4.1.1 \ - --hash=sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0 \ - --hash=sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e +uritemplate==4.1.1 # via gidgethub -uvicorn[standard]==0.18.1 \ - --hash=sha256:013c4ea0787cc2dc456ef4368e18c01982e6be57903e4d3183218e543eb889b7 \ - --hash=sha256:35703e6518105cfe53f16a5a9435db3e2e227d0784f1fd8fbc1214b1fdc108df +uvicorn[standard]==0.18.2 # via -r requirements/main.in -uvloop==0.16.0 \ - --hash=sha256:04ff57aa137230d8cc968f03481176041ae789308b4d5079118331ab01112450 \ - --hash=sha256:089b4834fd299d82d83a25e3335372f12117a7d38525217c2258e9b9f4578897 \ - --hash=sha256:1e5f2e2ff51aefe6c19ee98af12b4ae61f5be456cd24396953244a30880ad861 \ - --hash=sha256:30ba9dcbd0965f5c812b7c2112a1ddf60cf904c1c160f398e7eed3a6b82dcd9c \ - --hash=sha256:3a19828c4f15687675ea912cc28bbcb48e9bb907c801873bd1519b96b04fb805 \ - --hash=sha256:6224f1401025b748ffecb7a6e2652b17768f30b1a6a3f7b44660e5b5b690b12d \ - --hash=sha256:647e481940379eebd314c00440314c81ea547aa636056f554d491e40503c8464 \ - --hash=sha256:6ccd57ae8db17d677e9e06192e9c9ec4bd2066b77790f9aa7dede2cc4008ee8f \ - --hash=sha256:772206116b9b57cd625c8a88f2413df2fcfd0b496eb188b82a43bed7af2c2ec9 \ - --hash=sha256:8e0d26fa5875d43ddbb0d9d79a447d2ace4180d9e3239788208527c4784f7cab \ - --hash=sha256:98d117332cc9e5ea8dfdc2b28b0a23f60370d02e1395f88f40d1effd2cb86c4f \ - --hash=sha256:b572256409f194521a9895aef274cea88731d14732343da3ecdb175228881638 \ - --hash=sha256:bd53f7f5db562f37cd64a3af5012df8cac2c464c97e732ed556800129505bd64 \ - --hash=sha256:bd8f42ea1ea8f4e84d265769089964ddda95eb2bb38b5cbe26712b0616c3edee \ - --hash=sha256:e814ac2c6f9daf4c36eb8e85266859f42174a4ff0d71b99405ed559257750382 \ - --hash=sha256:f74bc20c7b67d1c27c72601c78cf95be99d5c2cdd4514502b4f3eb0933ff1228 +uvloop==0.16.0 # via uvicorn -watchfiles==0.15.0 \ - --hash=sha256:56abed43e645d1f2d6def83e35999cc5758b051aff54ca1065cbfcaea15b3389 \ - --hash=sha256:65ca99a94fcab29d00aa406526eb29cf198c0661854d59a315596064fed02141 \ - --hash=sha256:67d4c66e46a564059df4aeedab78f09cba0b697bf36cc77566b0a7015dfb7f5d \ - --hash=sha256:6e0e8829d32b05151e6009570449f44f891e05f518e495d25f960e0d0b2d0064 \ - --hash=sha256:715733c2ac9da67b2790788657ff6f8b3797eb31565bfc592289b523ae907ca2 \ - --hash=sha256:7b81c6e404b2aa62482a719eb778e4a16d01728302dce1f1512c1e5354a73fda \ - --hash=sha256:82238d08d8a49f1a1ba254278cd4329a154f6100b028393059722ebeddd2ff3d \ - --hash=sha256:955e8f840e1996a8a41be57de4c03af7b1515a685b7fb6abe222f859e413a907 \ - --hash=sha256:cab62510f990d195986302aa6a48ed636d685b099927049120d520c96069fa49 \ - --hash=sha256:d1f9de6b776b3aff17898a4cf5ac5a2d0a16212ea7aad2bbe0ef6aa3e79a96af \ - --hash=sha256:d4f45acd1143db6d3ee77a4ff12d3239bc8083108133e6174e9dcce59c1f9902 \ - --hash=sha256:f7f71012e096e11256fae3b37617a9777980f281e18deb2e789e85cd5b113935 +watchfiles==0.16.1 # via uvicorn -webencodings==0.5.1 \ - --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ - --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 +webencodings==0.5.1 # via # bleach # tinycss2 -websockets==10.3 \ - --hash=sha256:07cdc0a5b2549bcfbadb585ad8471ebdc7bdf91e32e34ae3889001c1c106a6af \ - --hash=sha256:210aad7fdd381c52e58777560860c7e6110b6174488ef1d4b681c08b68bf7f8c \ - --hash=sha256:28dd20b938a57c3124028680dc1600c197294da5db4292c76a0b48efb3ed7f76 \ - --hash=sha256:2f94fa3ae454a63ea3a19f73b95deeebc9f02ba2d5617ca16f0bbdae375cda47 \ - --hash=sha256:31564a67c3e4005f27815634343df688b25705cccb22bc1db621c781ddc64c69 \ - --hash=sha256:347974105bbd4ea068106ec65e8e8ebd86f28c19e529d115d89bd8cc5cda3079 \ - --hash=sha256:379e03422178436af4f3abe0aa8f401aa77ae2487843738542a75faf44a31f0c \ - --hash=sha256:3eda1cb7e9da1b22588cefff09f0951771d6ee9fa8dbe66f5ae04cc5f26b2b55 \ - --hash=sha256:51695d3b199cd03098ae5b42833006a0f43dc5418d3102972addc593a783bc02 \ - --hash=sha256:54c000abeaff6d8771a4e2cef40900919908ea7b6b6a30eae72752607c6db559 \ - --hash=sha256:5b936bf552e4f6357f5727579072ff1e1324717902127ffe60c92d29b67b7be3 \ - --hash=sha256:6075fd24df23133c1b078e08a9b04a3bc40b31a8def4ee0b9f2c8865acce913e \ - --hash=sha256:661f641b44ed315556a2fa630239adfd77bd1b11cb0b9d96ed8ad90b0b1e4978 \ - --hash=sha256:6ea6b300a6bdd782e49922d690e11c3669828fe36fc2471408c58b93b5535a98 \ - --hash=sha256:6ed1d6f791eabfd9808afea1e068f5e59418e55721db8b7f3bfc39dc831c42ae \ - --hash=sha256:7934e055fd5cd9dee60f11d16c8d79c4567315824bacb1246d0208a47eca9755 \ - --hash=sha256:7ab36e17af592eec5747c68ef2722a74c1a4a70f3772bc661079baf4ae30e40d \ - --hash=sha256:7f6d96fdb0975044fdd7953b35d003b03f9e2bcf85f2d2cf86285ece53e9f991 \ - --hash=sha256:83e5ca0d5b743cde3d29fda74ccab37bdd0911f25bd4cdf09ff8b51b7b4f2fa1 \ - --hash=sha256:85506b3328a9e083cc0a0fb3ba27e33c8db78341b3eb12eb72e8afd166c36680 \ - --hash=sha256:8af75085b4bc0b5c40c4a3c0e113fa95e84c60f4ed6786cbb675aeb1ee128247 \ - --hash=sha256:8b1359aba0ff810d5830d5ab8e2c4a02bebf98a60aa0124fb29aa78cfdb8031f \ - --hash=sha256:8fbd7d77f8aba46d43245e86dd91a8970eac4fb74c473f8e30e9c07581f852b2 \ - --hash=sha256:907e8247480f287aa9bbc9391bd6de23c906d48af54c8c421df84655eef66af7 \ - --hash=sha256:93d5ea0b5da8d66d868b32c614d2b52d14304444e39e13a59566d4acb8d6e2e4 \ - --hash=sha256:97bc9d41e69a7521a358f9b8e44871f6cdeb42af31815c17aed36372d4eec667 \ - --hash=sha256:994cdb1942a7a4c2e10098d9162948c9e7b235df755de91ca33f6e0481366fdb \ - --hash=sha256:a141de3d5a92188234afa61653ed0bbd2dde46ad47b15c3042ffb89548e77094 \ - --hash=sha256:a1e15b230c3613e8ea82c9fc6941b2093e8eb939dd794c02754d33980ba81e36 \ - --hash=sha256:aad5e300ab32036eb3fdc350ad30877210e2f51bceaca83fb7fef4d2b6c72b79 \ - --hash=sha256:b529fdfa881b69fe563dbd98acce84f3e5a67df13de415e143ef053ff006d500 \ - --hash=sha256:b9c77f0d1436ea4b4dc089ed8335fa141e6a251a92f75f675056dac4ab47a71e \ - --hash=sha256:bb621ec2dbbbe8df78a27dbd9dd7919f9b7d32a73fafcb4d9252fc4637343582 \ - --hash=sha256:c7250848ce69559756ad0086a37b82c986cd33c2d344ab87fea596c5ac6d9442 \ - --hash=sha256:c8d1d14aa0f600b5be363077b621b1b4d1eb3fbf90af83f9281cda668e6ff7fd \ - --hash=sha256:d1655a6fc7aecd333b079d00fb3c8132d18988e47f19740c69303bf02e9883c6 \ - --hash=sha256:d6353ba89cfc657a3f5beabb3b69be226adbb5c6c7a66398e17809b0ce3c4731 \ - --hash=sha256:da4377904a3379f0c1b75a965fff23b28315bcd516d27f99a803720dfebd94d4 \ - --hash=sha256:e49ea4c1a9543d2bd8a747ff24411509c29e4bdcde05b5b0895e2120cb1a761d \ - --hash=sha256:e4e08305bfd76ba8edab08dcc6496f40674f44eb9d5e23153efa0a35750337e8 \ - --hash=sha256:e6fa05a680e35d0fcc1470cb070b10e6fe247af54768f488ed93542e71339d6f \ - --hash=sha256:e7e6f2d6fd48422071cc8a6f8542016f350b79cc782752de531577d35e9bd677 \ - --hash=sha256:e904c0381c014b914136c492c8fa711ca4cced4e9b3d110e5e7d436d0fc289e8 \ - --hash=sha256:ec2b0ab7edc8cd4b0eb428b38ed89079bdc20c6bdb5f889d353011038caac2f9 \ - --hash=sha256:ef5ce841e102278c1c2e98f043db99d6755b1c58bde475516aef3a008ed7f28e \ - --hash=sha256:f351c7d7d92f67c0609329ab2735eee0426a03022771b00102816a72715bb00b \ - --hash=sha256:fab7c640815812ed5f10fbee7abbf58788d602046b7bb3af9b1ac753a6d5e916 \ - --hash=sha256:fc06cc8073c8e87072138ba1e431300e2d408f054b27047d047b549455066ff4 +websockets==10.3 # via uvicorn -wrapt==1.14.1 \ - --hash=sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3 \ - --hash=sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b \ - --hash=sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4 \ - --hash=sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2 \ - --hash=sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656 \ - --hash=sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3 \ - --hash=sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff \ - --hash=sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310 \ - --hash=sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a \ - --hash=sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57 \ - --hash=sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069 \ - --hash=sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383 \ - --hash=sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe \ - --hash=sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87 \ - --hash=sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d \ - --hash=sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b \ - --hash=sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907 \ - --hash=sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f \ - --hash=sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0 \ - --hash=sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28 \ - --hash=sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1 \ - --hash=sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853 \ - --hash=sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc \ - --hash=sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3 \ - --hash=sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3 \ - --hash=sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164 \ - --hash=sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1 \ - --hash=sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c \ - --hash=sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1 \ - --hash=sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7 \ - --hash=sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1 \ - --hash=sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320 \ - --hash=sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed \ - --hash=sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1 \ - --hash=sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248 \ - --hash=sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c \ - --hash=sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456 \ - --hash=sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77 \ - --hash=sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef \ - --hash=sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1 \ - --hash=sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7 \ - --hash=sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86 \ - --hash=sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4 \ - --hash=sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d \ - --hash=sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d \ - --hash=sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8 \ - --hash=sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5 \ - --hash=sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471 \ - --hash=sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00 \ - --hash=sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68 \ - --hash=sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3 \ - --hash=sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d \ - --hash=sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735 \ - --hash=sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d \ - --hash=sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569 \ - --hash=sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7 \ - --hash=sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59 \ - --hash=sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5 \ - --hash=sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb \ - --hash=sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b \ - --hash=sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f \ - --hash=sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462 \ - --hash=sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015 \ - --hash=sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af +wrapt==1.14.1 # via deprecated -# WARNING: The following packages were not pinned, but pip requires them to be -# pinned when the requirements file includes hashes. Consider using the --allow-unsafe flag. -# setuptools +# The following packages are considered to be unsafe in a requirements file: +setuptools==65.0.0 + # via gunicorn From 33c72183e83199c47ffe32b2d1d5abc3b917bf43 Mon Sep 17 00:00:00 2001 From: Jonathan Sick Date: Wed, 3 Aug 2022 13:08:12 -0400 Subject: [PATCH 02/12] Update pre-commit config --- .pre-commit-config.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f929a2bd..9297cd26 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.1.0 + rev: v4.3.0 hooks: - id: check-yaml - id: check-toml @@ -13,11 +13,11 @@ repos: - toml - repo: https://github.com/psf/black - rev: 22.3.0 + rev: 22.6.0 hooks: - id: black - - repo: https://gitlab.com/pycqa/flake8 - rev: 4.0.1 + - repo: https://github.com/pycqa/flake8 + rev: 5.0.3 hooks: - id: flake8 From a81e247919c9b635adc2e6caeffb05a315bc4524 Mon Sep 17 00:00:00 2001 From: Jonathan Sick Date: Wed, 3 Aug 2022 15:43:48 -0400 Subject: [PATCH 03/12] Document path parameters with Path The fastapi.Path class lets us properly document the path parameters in the Open API spec. --- src/timessquare/handlers/v1/handlers.py | 47 +++++++++++++++++-------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/src/timessquare/handlers/v1/handlers.py b/src/timessquare/handlers/v1/handlers.py index 050dbabc..ddb2c0e5 100644 --- a/src/timessquare/handlers/v1/handlers.py +++ b/src/timessquare/handlers/v1/handlers.py @@ -2,7 +2,7 @@ from typing import List -from fastapi import APIRouter, Depends, HTTPException, Request +from fastapi import APIRouter, Depends, HTTPException, Path, Request from fastapi.responses import HTMLResponse, PlainTextResponse from safir.metadata import get_metadata @@ -26,6 +26,29 @@ v1_router = APIRouter(tags=["v1"]) """FastAPI router for all external handlers.""" +display_path_parameter = Path( + title="Page display path", + description=( + "A display path is a POSIX-like '/'-separated path consisting " + "of components:\n" + "\n" + "- GitHub owner (organization or username)\n" + "- Github repository\n" + "- Directory name or names (as appropriate)\n" + "- Page filename stem\n" + ), + example="lsst-sqre/times-square-demo/matplotlib/gaussian2d", +) + +page_path_parameter = Path( + title="Page name", + description=( + "An opaque identifier for a page. This is often the 'name' field for " + "a page's resource model." + ), + example="3d5a140634c34e249b7531667469b816", +) + @v1_router.get( "/", @@ -53,7 +76,8 @@ async def get_index( name="get_page", ) async def get_page( - page: str, context: RequestContext = Depends(context_dependency) + page: str = page_path_parameter, + context: RequestContext = Depends(context_dependency), ) -> Page: """Get metadata about a page resource, which models a webpage that is rendered from a parameterized Jupyter Notebook. @@ -186,7 +210,7 @@ async def post_page( name="get_page_source", ) async def get_page_source( - page: str, + page: str = page_path_parameter, context: RequestContext = Depends(context_dependency), ) -> PlainTextResponse: """Get the content of the source ipynb file, which is unexecuted and has @@ -215,7 +239,7 @@ async def get_page_source( name="get_rendered_notebook", ) async def get_rendered_notebook( - page: str, + page: str = page_path_parameter, context: RequestContext = Depends(context_dependency), ) -> PlainTextResponse: """Get a Jupyter Notebook with the parameter values filled in. The @@ -236,7 +260,7 @@ async def get_rendered_notebook( name="get_page_html", ) async def get_page_html( - page: str, + page: str = page_path_parameter, context: RequestContext = Depends(context_dependency), ) -> HTMLResponse: """Get the rendered HTML of a notebook.""" @@ -261,7 +285,7 @@ async def get_page_html( response_model=HtmlStatus, ) async def get_page_html_status( - page: str, + page: str = page_path_parameter, context: RequestContext = Depends(context_dependency), ) -> HtmlStatus: page_service = context.page_service @@ -302,19 +326,14 @@ async def get_github_tree( name="get_github_page", ) async def get_github_page( - display_path: str, context: RequestContext = Depends(context_dependency) + display_path: str = display_path_parameter, + context: RequestContext = Depends(context_dependency), ) -> Page: """Get the metadata for a GitHub-backed page. This endpoint provides the same data as ``GET /v1/pages/:page``, but is queried via the page's GitHub "display path" rather than the opaque - page slug. A display path is a POSIX-like "/"-separated path consisting - of components: - - - GitHub owner (organization or username) - - Github repository - - Directory name or names (as appropriate) - - Page filename stem + page name. """ page_service = context.page_service async with context.session.begin(): From 036a2ad6cf620a73ac62f373ca2f8ba3b316d4d8 Mon Sep 17 00:00:00 2001 From: Jonathan Sick Date: Thu, 4 Aug 2022 12:00:23 -0400 Subject: [PATCH 04/12] Add service and handers for getting PR-based pages This provides access to the pages that are built automatically by the GitHub Check run handlers for a GitHub pull request. - New PageService.get_github_pr_page - New /github-pr/ endpoints, similar to the existing /github/ endpoints, but have the PR's head commit SHA in the path to show pages for a specific PR check run - Revised GitHubTree domain model. The new domain model separates path segments (which are used to add nodes relative to other nodes) from the Squareone URL path. This dramatically simplifies the tree domain construction and makes it possible to use the same domain object for PR preview trees as well. The new GitHubNode is a dataclass; in the REST API we transform that dataclass into a Pydantic model for the response. --- src/timessquare/domain/githubtree.py | 283 +++++++++++++++++------- src/timessquare/handlers/v1/handlers.py | 86 ++++++- src/timessquare/handlers/v1/models.py | 93 +++++++- src/timessquare/services/page.py | 54 +++++ src/timessquare/storage/page.py | 71 +++++- tests/domain/githubtree_test.py | 151 +++++++++++++ 6 files changed, 639 insertions(+), 99 deletions(-) create mode 100644 tests/domain/githubtree_test.py diff --git a/src/timessquare/domain/githubtree.py b/src/timessquare/domain/githubtree.py index 0aa604e9..bc6fefe5 100644 --- a/src/timessquare/domain/githubtree.py +++ b/src/timessquare/domain/githubtree.py @@ -2,11 +2,9 @@ from __future__ import annotations -from dataclasses import dataclass +from dataclasses import dataclass, field from enum import Enum -from typing import List - -from pydantic import BaseModel, Field +from typing import List, Optional class GitHubNodeType(str, Enum): @@ -25,103 +23,222 @@ class GitHubNodeType(str, Enum): """Page inside a GitHub repository.""" -class GitHubNode(BaseModel): +@dataclass +class GitHubNode: """A node in the GitHub contents tree.""" - node_type: GitHubNodeType = Field( - title="Node type", - description=( - "Indicates whether this a GitHub owner (user or organization), " - "repository, directory in a repositiory, or a page itself." - ), - ) - - title: str = Field(title="Display title") - - path: str = Field( - title="Hierarchical path", - description=( - "The page is POSIX-path formatted without a preceeding or " - "trailing slash. The first path element is always the owner, " - "followed by the repository name, directory, and page name as " - "necessary." - ), - example="lsst-sqre/times-square-demo/matplotlib/gaussian2d", - ) - - contents: List[GitHubNode] = Field( - title="Nodes contained within this node.", - description="For 'page' nodes, this is an empty list.", - default_factory=list, - ) + node_type: GitHubNodeType + """The type of path object in the node.""" + + path_segments: List[str] + """The segments in the path (i.e. the name of this page, or + this directory) up to this point. + + Path segments are always ordered: + + 1. owner + 2. repo + 3. directory or directories, as necessary + 4. page file stem (i.e. filename without extension) + """ + + title: str + """Presentational title for this node.""" + + github_commit: Optional[str] = None + """The commit SHA if this tree is for a specific commit (a PR preview) + instead of corresponding to the default branch of the repository. + """ + + contents: List[GitHubNode] = field(default_factory=list) @property - def path_segments(self) -> List[str]: - return self.path.split("/") + def squareone_path(self) -> str: + """Path to the node in Squareone. + + - If `github_commit` is None, the URL path is relative to + ``/times-square/github/`` (not included. + - If the node contains a non-None `github_commit`, + the path is relative to ``/times-square/github-pr/`` (not included). + """ + if self.github_commit is None: + # a path corresponding to the default branch (i.e. the "live view + # github-backed pages) + return "/".join(self.path_segments) + else: + # a path corresponding to the commit view of a repository, + # for PR previews. + # formatted as owner/repo/commit/dirname/filestem + return ( + f"{self.path_segments[0]}/{self.path_segments[1]}/" + f"{self.github_commit}/{'/'.join(self.path_segments[2:])}" + ) + + @classmethod + def create_with_repo_root( + cls, results: List[GitHubTreeQueryResult] + ) -> GitHubNode: + """Create a tree with this root-node being the first repository in + the results. + + This is appropriate for creating trees for GitHub PR previews. + """ + root_path_segment = [results[0].github_owner, results[0].github_repo] + root = cls( + node_type=GitHubNodeType.repo, + path_segments=root_path_segment, + github_commit=results[0].github_commit, + title=results[0].github_repo, + contents=[], + ) + for result in results: + root.insert_node(result) + return root - def insert_input(self, tree_input: GitHubTreeInput) -> None: - n = len(self.path_segments) - if n == len(tree_input.path_segments): - # input is a direct child of this node - self.contents.append(tree_input.to_node()) + @classmethod + def create_with_owner_root( + cls, results: List[GitHubTreeQueryResult] + ) -> GitHubNode: + """Create a tree with the root-node being the first GitHub owner in + the results. + + This is appropriate for creating trees for the default branch views + of GitHub-backed pages. + """ + root_path_segment = [results[0].github_owner] + root = cls( + node_type=GitHubNodeType.owner, + path_segments=root_path_segment, + title=results[0].github_owner, + github_commit=results[0].github_commit, + contents=[], + ) + for result in results: + root.insert_node(result) + return root + + def insert_node(self, result: GitHubTreeQueryResult) -> None: + """Insert an SQL page result as a child (direct, or not) of the + current node. + """ + if self.node_type == GitHubNodeType.owner: + self._insert_node_from_owner(result) + elif self.node_type == GitHubNodeType.repo: + self._insert_node_from_repo(result) + elif self.node_type == GitHubNodeType.directory: + self._insert_node_from_directory(result) + else: + raise ValueError("Cannot insert a node into a page") + + def _insert_node_from_owner(self, result: GitHubTreeQueryResult) -> None: + # Try to insert node into an existing repository node + for repo_node in self.contents: + if repo_node.path_segments[1] == result.github_repo: + repo_node.insert_node(result) + return + + # Create a repo node since one doesn't already exist + repo_node = GitHubNode( + node_type=GitHubNodeType.repo, + path_segments=result.path_segments[:2], + title=result.path_segments[1], + github_commit=result.github_commit, + contents=[], + ) + self.contents.append(repo_node) + repo_node.insert_node(result) + + def _insert_node_from_repo(self, result: GitHubTreeQueryResult) -> None: + if len(result.path_segments) == 3: + # direct child of this node + self.contents.append( + GitHubNode( + node_type=GitHubNodeType.page, + path_segments=result.path_segments, + title=result.title, + github_commit=result.github_commit, + contents=[], + ) + ) + return else: - # find child that contains input - for child in self.contents: - if (len(child.path_segments) >= n + 1) and ( - child.path_segments[n] == tree_input.path_segments[n] + # Find existing directory containing this page + for child_node in self.contents: + n = len(child_node.path_segments) + if ( + child_node.node_type == GitHubNodeType.directory + and child_node.path_segments == result.path_segments[:n] ): - child.insert_input(tree_input) + child_node.insert_node(result) return - # Create a new child node because the necessary one doesn't - # exist - if n == 1: - node_type = GitHubNodeType.repo - else: - node_type = GitHubNodeType.directory - child = GitHubNode( - node_type=node_type, - title=tree_input.path_segments[n], - path="/".join(tree_input.path_segments[: n + 1]), + # Create a directory node + dir_node = GitHubNode( + node_type=GitHubNodeType.directory, + path_segments=result.path_segments[ + : len(self.path_segments) + 1 + ], + title=result.path_segments[len(self.path_segments)], + github_commit=result.github_commit, contents=[], ) - child.insert_input(tree_input) - self.contents.append(child) + self.contents.append(dir_node) + dir_node.insert_node(result) + + def _insert_node_from_directory( + self, result: GitHubTreeQueryResult + ) -> None: + self_segment_count = len(self.path_segments) + input_segment_count = len(result.path_segments) + + if input_segment_count == self_segment_count + 1: + # a direct child of this directory + self.contents.append( + GitHubNode( + node_type=GitHubNodeType.page, + path_segments=result.path_segments, + title=result.title, + github_commit=result.github_commit, + contents=[], + ) + ) + else: + # Create a directory node + dir_node = GitHubNode( + node_type=GitHubNodeType.directory, + path_segments=result.path_segments[: self_segment_count + 1], + title=result.path_segments[self_segment_count], + github_commit=result.github_commit, + contents=[], + ) + self.contents.append(dir_node) + dir_node.insert_node(result) @dataclass -class GitHubTreeInput: +class GitHubTreeQueryResult: """A domain class used to aid construction of the GitHub contents tree from the original SQL storage of pages. - - This class is used by `PageStore.get_github_tree`; `GitHubNode` is the - public product. """ - path_segments: List[str] + # The order of these attributes matches the order of the sql query + # in timessquare.storage.page. + + github_owner: str + + github_repo: str - stem: str + github_commit: Optional[str] + + path_prefix: str title: str - @classmethod - def from_sql_row( - cls, - github_owner: str, - github_repo: str, - path_prefix: str, - title: str, - path_stem: str, - ) -> GitHubTreeInput: - path_segments = [github_owner, github_repo] - if path_prefix: - path_segments.extend(path_prefix.split("/")) - - return cls(path_segments=path_segments, stem=path_stem, title=title) - - def to_node(self) -> GitHubNode: - return GitHubNode( - node_type=GitHubNodeType.page, - title=self.title, - path="/".join(self.path_segments + [self.stem]), - contents=[], - ) + path_stem: str + + @property + def path_segments(self) -> List[str]: + segments: List[str] = [self.github_owner, self.github_repo] + if len(self.path_prefix) > 0: + segments.extend(self.path_prefix.split("/")) + segments.append(self.path_stem) + return segments diff --git a/src/timessquare/handlers/v1/handlers.py b/src/timessquare/handlers/v1/handlers.py index ddb2c0e5..64400a66 100644 --- a/src/timessquare/handlers/v1/handlers.py +++ b/src/timessquare/handlers/v1/handlers.py @@ -13,7 +13,7 @@ ) from .models import ( - GitHubTreeRoot, + GitHubContentsRoot, HtmlStatus, Index, Page, @@ -40,6 +40,14 @@ example="lsst-sqre/times-square-demo/matplotlib/gaussian2d", ) +github_owner_parameter = Path( + title="GitHub owner (organization or username)", example="lsst-sqre" +) + +github_repo_parameter = Path( + title="GitHub repository", example="times-square-demo" +) + page_path_parameter = Path( title="Page name", description=( @@ -49,6 +57,16 @@ example="3d5a140634c34e249b7531667469b816", ) +path_parameter = Path( + title="Notebook path in repository (without extension)", + example="matplotlib/gaussian2d", +) + +pr_commit_parameter = Path( + title="Git commit for pull request check run", + example="878092649b8bc1d8ef1436cc623bcecb923ece39", +) + @v1_router.get( "/", @@ -301,11 +319,11 @@ async def get_page_html_status( "/github", summary="Get a tree of GitHub-backed pages", name="get_github_tree", - response_model=GitHubTreeRoot, + response_model=GitHubContentsRoot, ) async def get_github_tree( context: RequestContext = Depends(context_dependency), -) -> GitHubTreeRoot: +) -> GitHubContentsRoot: """Get the tree of GitHub-backed pages. This endpoint is primarily intended to be used by Squareone to power @@ -316,7 +334,7 @@ async def get_github_tree( page_service = context.page_service async with context.session.begin(): github_tree = await page_service.get_github_tree() - return GitHubTreeRoot.from_tree(tree=github_tree) + return GitHubContentsRoot.from_tree(tree=github_tree) @v1_router.get( @@ -343,3 +361,63 @@ async def get_github_page( "get_page", page=page_domain.name ) return Page.from_domain(page=page_domain, request=context.request) + + +@v1_router.get( + "/github-pr/{owner}/{repo}/{commit}", + summary="Get a tree of GitHub PR preview pages", + name="get_github_pr_tree", + response_model=GitHubContentsRoot, +) +async def get_github_pr_tree( + owner: str = github_owner_parameter, + repo: str = github_repo_parameter, + commit: str = pr_commit_parameter, + context: RequestContext = Depends(context_dependency), +) -> GitHubContentsRoot: + """Get the tree of GitHub-backed pages for a pull request. + + This endpoint is primarily intended to be used by Squareone to power + its navigational view of GitHub pages for a specific pull request + (actually a commit SHA) of a repository. + """ + page_service = context.page_service + async with context.session.begin(): + github_tree = await page_service.get_github_pr_tree( + owner=owner, repo=repo, commit=commit + ) + return GitHubContentsRoot.from_tree( + tree=github_tree, + owner=owner, + repo=repo, + commit=commit, + ) + + +@v1_router.get( + "/github-pr/{owner}/{repo}/{commit}/{path:path}", + response_model=Page, + summary="Metadata for GitHub-backed page", + name="get_github_pr_page", +) +async def get_github_pr_page( + owner: str = github_owner_parameter, + repo: str = github_repo_parameter, + commit: str = pr_commit_parameter, + path: str = path_parameter, + context: RequestContext = Depends(context_dependency), +) -> Page: + """Get the metadata for a pull request preview of a GitHub-backed page.""" + page_service = context.page_service + async with context.session.begin(): + page_domain = await page_service.get_github_pr_page( + owner=owner, + repo=repo, + commit=commit, + path=path, + ) + + context.response.headers["location"] = context.request.url_for( + "get_page", page=page_domain.name + ) + return Page.from_domain(page=page_domain, request=context.request) diff --git a/src/timessquare/handlers/v1/models.py b/src/timessquare/handlers/v1/models.py index cd96b424..92c89a1c 100644 --- a/src/timessquare/handlers/v1/models.py +++ b/src/timessquare/handlers/v1/models.py @@ -11,7 +11,7 @@ from pydantic import AnyHttpUrl, BaseModel, EmailStr, Field from safir.metadata import Metadata as SafirMetadata -from timessquare.domain.githubtree import GitHubNode +from timessquare.domain.githubtree import GitHubNode, GitHubNodeType from timessquare.domain.nbhtml import NbHtmlModel from timessquare.domain.page import PageModel, PageSummaryModel, PersonModel @@ -21,7 +21,7 @@ class Index(BaseModel): metadata: SafirMetadata = Field(..., title="Package metadata") - api_docs: AnyHttpUrl = Field(..., tile="Browsable API documentation") + api_docs: AnyHttpUrl = Field(..., title="Browsable API documentation") page_name_field = Field( @@ -409,11 +409,90 @@ class PostPageRequest(BaseModel): cache_ttl: Optional[int] = page_cache_ttl_field -class GitHubTreeRoot(BaseModel): - """The GitHub-backed pages, organized hierarchically.""" +class GitHubContentsNode(BaseModel): + """Information about a node in a GitHub contents tree.""" - contents: List[GitHubNode] + node_type: GitHubNodeType = Field( + ..., + title="Node type", + description="Type of node in the GitHub contents tree.", + example="page", + ) + + path: str = Field( + ..., + title="Path", + description="Squareone URL path", + example="lsst-sqre/times-square-demo/demo", + ) + + title: str = Field( + ..., + title="Title", + description="Presentation title of the node.", + example="Demo", + ) + + contents: List[GitHubContentsNode] = Field( + ..., title="Contents", description="Children of this node" + ) @classmethod - def from_tree(cls, *, tree: List[GitHubNode]) -> GitHubTreeRoot: - return cls(contents=tree) + def from_domain_model(cls, node: GitHubNode) -> GitHubContentsNode: + return cls( + node_type=node.node_type, + path=node.squareone_path, + title=node.title, + contents=[cls.from_domain_model(n) for n in node.contents], + ) + + +class GitHubContentsRoot(BaseModel): + """The tree of GitHub contents.""" + + contents: List[GitHubContentsNode] = Field( + title="Contents", description="Content nodes" + ) + + owner: Optional[str] = Field( + None, + title="GitHub owner", + description=( + "The GitHub owner for this tree, if this tree applies to a single " + "GitHub owner." + ), + ) + + repo: Optional[str] = Field( + None, + title="GitHub repo", + description=( + "The GitHub repo for this tree, if this tree applies to a single " + "GitHub repo." + ), + ) + + commit: Optional[str] = Field( + None, + title="GitHub commit", + description=( + "The GitHub commit for this tree, if this tree is specific to a " + "commit, such as for a PR preview." + ), + ) + + @classmethod + def from_tree( + cls, + *, + tree: List[GitHubNode], + owner: Optional[str] = None, + repo: Optional[str] = None, + commit: Optional[str] = None, + ) -> GitHubContentsRoot: + return cls( + contents=[GitHubContentsNode.from_domain_model(n) for n in tree], + owner=owner, + repo=repo, + commit=commit, + ) diff --git a/src/timessquare/services/page.py b/src/timessquare/services/page.py index 506442e8..6f95c64a 100644 --- a/src/timessquare/services/page.py +++ b/src/timessquare/services/page.py @@ -130,6 +130,48 @@ async def get_github_backed_page(self, display_path: str) -> PageModel: raise PageNotFoundError(display_path) return page + async def get_github_pr_page( + self, + *, + owner: str, + repo: str, + commit: str, + path: str, + ) -> PageModel: + """Get a page for a specific commit, corresponding to a GitHub PR's + check run. + + Parameters + ---------- + owner : `str` + GitHub repository owner (username or organization). + repo : `str` + GitHub repository name. + commit : `str` + The SHA of the Git commit corresponding to the check run. + path : `str` + The page's path within the repository (without the file extension). + + Returns + ------- + page : `PageModel` + The domain model for a page. For PRs, this page is creating while + processing the GitHub check suite. + + Raises + ------ + PageNotFoundError + Raised if the page is not found in the PageStore. + """ + display_path = f"{owner}/{repo}/{path}" + page = await self._page_store.get_github_backed_page( + display_path, commit=commit + ) + if page is None: + # FIXME add a commit attribute to the exception + raise PageNotFoundError(display_path) + return page + async def get_page_summaries(self) -> List[PageSummaryModel]: """Get page summaries.""" return await self._page_store.list_page_summaries() @@ -146,6 +188,18 @@ async def get_github_tree(self) -> List[GitHubNode]: """Get the tree of GitHub-backed pages.""" return await self._page_store.get_github_tree() + async def get_github_pr_tree( + self, + *, + owner: str, + repo: str, + commit: str, + ) -> List[GitHubNode]: + """Get the tree of GitHub-backed pages for a specific pull request.""" + return await self._page_store.get_github_pr_tree( + owner=owner, repo=repo, commit=commit + ) + async def update_page_in_store(self, page: PageModel) -> None: """Update the page in the database.""" await self._page_store.update_page(page) diff --git a/src/timessquare/storage/page.py b/src/timessquare/storage/page.py index 2124b68c..fbafa830 100644 --- a/src/timessquare/storage/page.py +++ b/src/timessquare/storage/page.py @@ -12,7 +12,7 @@ from timessquare.domain.githubtree import ( GitHubNode, GitHubNodeType, - GitHubTreeInput, + GitHubTreeQueryResult, ) from timessquare.domain.page import ( PageModel, @@ -273,9 +273,10 @@ async def get_github_tree(self) -> List[GitHubNode]: async def _generate_node_for_owner(self, owner_name: str) -> GitHubNode: statement = ( - select( + select( # order matches GitHubTreeQueryResult SqlPage.github_owner, SqlPage.github_repo, + SqlPage.github_commit, SqlPage.repository_display_path_prefix, SqlPage.title, SqlPage.repository_path_stem, @@ -293,16 +294,76 @@ async def _generate_node_for_owner(self, owner_name: str) -> GitHubNode: result = await self._session.execute(statement) tree_inputs = [ - GitHubTreeInput.from_sql_row(*row) for row in result.all() + GitHubTreeQueryResult( + github_owner=row[0], + github_repo=row[1], + github_commit=row[2], + path_prefix=row[3], + title=row[4], + path_stem=row[5], + ) + for row in result.all() ] owner_node = GitHubNode( node_type=GitHubNodeType.owner, title=owner_name, - path=owner_name, + path_segments=[owner_name], + github_commit=None, contents=[], ) for tree_input in tree_inputs: - owner_node.insert_input(tree_input) + owner_node.insert_node(tree_input) return owner_node + + async def get_github_pr_tree( + self, *, owner: str, repo: str, commit: str + ) -> List[GitHubNode]: + """Get the tree of GitHub-backed pages for a pull request commit.""" + statement = ( + select( # order matches GitHubTreeQueryResult + SqlPage.github_owner, + SqlPage.github_repo, + SqlPage.github_commit, + SqlPage.repository_display_path_prefix, + SqlPage.title, + SqlPage.repository_path_stem, + ) + .where(SqlPage.date_deleted == None) # noqa: E711 + .where(SqlPage.github_commit == commit) + .where(SqlPage.github_owner == owner) + .order_by( + SqlPage.repository_display_path_prefix, + SqlPage.title, + ) + ) + result = await self._session.execute(statement) + + tree_inputs = [ + GitHubTreeQueryResult( + github_owner=row[0], + github_repo=row[1], + github_commit=row[2], + path_prefix=row[3], + title=row[4], + path_stem=row[5], + ) + for row in result.all() + ] + if len(tree_inputs) == 0: + return [] + + # Create a root node for the repo to use its insert_input method + # for sorting the tree and creating directories as needed + repo_node = GitHubNode( + node_type=GitHubNodeType.repo, + path_segments=[owner, repo], + github_commit=commit, + title=repo, + contents=[], + ) + for tree_input in tree_inputs: + repo_node.insert_node(tree_input) + + return repo_node.contents diff --git a/tests/domain/githubtree_test.py b/tests/domain/githubtree_test.py new file mode 100644 index 00000000..5117fffd --- /dev/null +++ b/tests/domain/githubtree_test.py @@ -0,0 +1,151 @@ +"""Tests for the githubtree domain models.""" + +from __future__ import annotations + +from timessquare.domain.githubtree import ( + GitHubNode, + GitHubNodeType, + GitHubTreeQueryResult, +) + + +def test_githubtreenode() -> None: + """Test the construction of a GitHubNode from mock GitHubTreeInputs with + a null GitHub commit. + """ + mock_sql_results = [ + [ + "lsst-sqre", + "times-square-demo", + None, + "", + "Alpha", + "alpha", + ], + [ + "lsst-sqre", + "times-square-demo", + None, + "", + "Beta", + "beta", + ], + [ + "lsst-sqre", + "times-square-demo", + None, + "subdir", + "Gamma", + "gamma", + ], + ] + tree_inputs = [ + GitHubTreeQueryResult( + github_owner=str(row[0]), + github_repo=str(row[1]), + github_commit=row[2], + path_prefix=str(row[3]), + title=str(row[4]), + path_stem=str(row[5]), + ) + for row in mock_sql_results + ] + + owner_node = GitHubNode( + node_type=GitHubNodeType.owner, + title="lsst-sqre", + path_segments=["lsst-sqre"], + github_commit=None, + contents=[], + ) + for tree_input in tree_inputs: + owner_node.insert_node(tree_input) + + assert owner_node.title == "lsst-sqre" + assert owner_node.contents[0].title == "times-square-demo" + repo_node = owner_node.contents[0] + assert repo_node.node_type == GitHubNodeType.repo + print(owner_node) + + assert repo_node.contents[0].title == "Alpha" + assert repo_node.contents[0].squareone_path == ( + "lsst-sqre/times-square-demo/alpha" + ) + + assert repo_node.contents[1].title == "Beta" + + assert repo_node.contents[2].title == "subdir" + dir_node = repo_node.contents[2] + assert dir_node.contents[0].title == "Gamma" + assert dir_node.contents[0].squareone_path == ( + "lsst-sqre/times-square-demo/subdir/gamma" + ) + + +def test_githubprtreenode() -> None: + """Test the construction of a GitHubPrNode from mock inputs.""" + mock_sql_results = [ + [ + "lsst-sqre", + "times-square-demo", + "e35e1d5c485531ba9e99081c52dbdc5579e00556", + "", + "Alpha", + "alpha", + ], + [ + "lsst-sqre", + "times-square-demo", + "e35e1d5c485531ba9e99081c52dbdc5579e00556", + "", + "Beta", + "beta", + ], + [ + "lsst-sqre", + "times-square-demo", + "e35e1d5c485531ba9e99081c52dbdc5579e00556", + "subdir", + "Gamma", + "gamma", + ], + ] + tree_inputs = [ + GitHubTreeQueryResult( + github_owner=str(row[0]), + github_repo=str(row[1]), + github_commit=row[2], + path_prefix=str(row[3]), + title=str(row[4]), + path_stem=str(row[5]), + ) + for row in mock_sql_results + ] + + repo_node = GitHubNode( + node_type=GitHubNodeType.repo, + title="times-square-demo", + path_segments=["lsst-sqre", "times-square-demo"], + github_commit="e35e1d5c485531ba9e99081c52dbdc5579e00556", + contents=[], + ) + for tree_input in tree_inputs: + repo_node.insert_node(tree_input) + + assert repo_node.contents[0].title == "Alpha" + assert repo_node.contents[0].squareone_path == ( + "lsst-sqre/times-square-demo/e35e1d5c485531ba9e99081c52dbdc5579e00556" + "/alpha" + ) + assert repo_node.contents[1].title == "Beta" + assert repo_node.contents[1].squareone_path == ( + "lsst-sqre/times-square-demo/e35e1d5c485531ba9e99081c52dbdc5579e00556" + "/beta" + ) + assert repo_node.contents[2].title == "subdir" + dir_node = repo_node.contents[2] + assert dir_node.contents[0].title == "Gamma" + assert dir_node.contents[0].squareone_path == ( + "lsst-sqre/times-square-demo/e35e1d5c485531ba9e99081c52dbdc5579e00556" + "/subdir/gamma" + ) From b73d8011fc9e22a234c8031ef265908b0f828ad0 Mon Sep 17 00:00:00 2001 From: Jonathan Sick Date: Tue, 16 Aug 2022 15:00:28 -0400 Subject: [PATCH 05/12] Create a GitHubRepoService for a given repo Normally we create a GitHubRepoService in webhook handlers where the installation ID is know. This new create_github_repo_service classmethod lets us look-up the installation ID for a specific repository, and then create the service using a GitHub client authenticated for that installation. --- .../dependencies/requestcontext.py | 16 +++++ src/timessquare/services/github/repo.py | 59 +++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/src/timessquare/dependencies/requestcontext.py b/src/timessquare/dependencies/requestcontext.py index c979296b..b06a7c23 100644 --- a/src/timessquare/dependencies/requestcontext.py +++ b/src/timessquare/dependencies/requestcontext.py @@ -14,6 +14,7 @@ from timessquare.config import Config, config from timessquare.dependencies.redis import redis_dependency +from timessquare.services.github.repo import GitHubRepoService from timessquare.services.page import PageService from timessquare.storage.nbhtmlcache import NbHtmlCacheStore from timessquare.storage.noteburstjobstore import NoteburstJobStore @@ -55,6 +56,7 @@ class RequestContext: @property def page_service(self) -> PageService: + """An instance of the page service.""" return PageService( page_store=PageStore(self.session), html_cache=NbHtmlCacheStore(self.redis), @@ -63,6 +65,20 @@ def page_service(self) -> PageService: logger=self.logger, ) + async def create_github_repo_service( + self, owner: str, repo: str + ) -> GitHubRepoService: + """An instance of the GitHub repository service for manging + GitHub-backed pages and accessing GitHub's API. + """ + return await GitHubRepoService.create_for_repo( + owner=owner, + repo=repo, + http_client=self.http_client, + page_service=self.page_service, + logger=self.logger, + ) + def get_request_username(self) -> Optional[str]: """Get the username who made the request diff --git a/src/timessquare/services/github/repo.py b/src/timessquare/services/github/repo.py index 39df2429..4c2bacb7 100644 --- a/src/timessquare/services/github/repo.py +++ b/src/timessquare/services/github/repo.py @@ -41,6 +41,11 @@ from timessquare.domain.page import PageExecutionInfo, PageModel from ..page import PageService +from .client import ( + create_github_client, + create_github_installation_client, + get_app_jwt, +) class GitHubRepoService: @@ -73,6 +78,60 @@ def __init__( self._page_service = page_service self._logger = logger + @classmethod + async def create_for_repo( + cls, + *, + owner: str, + repo: str, + http_client: AsyncClient, + page_service: PageService, + logger: BoundLogger, + ) -> GitHubRepoService: + """Create a github repo service for a specific repository (requires + that the Times Square GitHub App is installed for that repository). + + Parameters + ---------- + owner : `str` + The GitHub repo's owner. + repo : `str` + The GitHub repo's name. + http_client : `AsyncClient` + An httpx client. + github_client : `GitHubAPI` + A GidgetHub API client that is authenticated as a GitHub app + installation. + page_service : `PageService` + The Page service. This GitHubRepoService acts as a layer on top of + the regular page service to handle domain models from the github + domain. + logger : `BoundLogger` + A logger, ideally with request/worker job context already bound. + """ + app_jwt = get_app_jwt() + app_client = create_github_client(http_client=http_client) + installation_data = await app_client.getitem( + "/repos/{owner}/{repo}/installation", + url_vars={"owner": owner, "repo": repo}, + jwt=app_jwt, + ) + installation_id = installation_data["id"] + installation_client = await create_github_installation_client( + http_client=http_client, installation_id=installation_id + ) + return cls( + http_client=http_client, + github_client=installation_client, + page_service=page_service, + logger=logger, + ) + + @property + def page_service(self) -> PageService: + """The page service used by the repo service.""" + return self._page_service + async def sync_from_repo_installation( self, owner: str, From 10c614f78e6d294d220e26f7037967655dff3930 Mon Sep 17 00:00:00 2001 From: Jonathan Sick Date: Tue, 16 Aug 2022 15:02:56 -0400 Subject: [PATCH 06/12] Capture output in a GitHub check run model --- src/timessquare/domain/githubapi.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/timessquare/domain/githubapi.py b/src/timessquare/domain/githubapi.py index e7dd5849..4e5995f5 100644 --- a/src/timessquare/domain/githubapi.py +++ b/src/timessquare/domain/githubapi.py @@ -226,6 +226,18 @@ class GitHubCheckSuiteId(BaseModel): id: str = Field(description="Check suite ID") +class GitHubCheckRunOutput(BaseModel): + """Check run output report.""" + + title: Optional[str] = Field(None, description="Title of the report") + + summary: Optional[str] = Field( + None, description="Summary information (markdown formatted" + ) + + text: Optional[str] = Field(None, description="Extended report (markdown)") + + class GitHubCheckRunModel(BaseModel): """A Pydantic model for the "check_run" field in a check_run webhook payload (`GitHubCheckRunPayloadModel`). @@ -257,3 +269,7 @@ class GitHubCheckRunModel(BaseModel): html_url: HttpUrl = Field(description="URL of the check run webpage.") check_suite: GitHubCheckSuiteId + + output: Optional[GitHubCheckRunOutput] = Field( + None, title="Output", description="Check run output, if available." + ) From f1f253e1041d248d999c50fd6a709341f3727b97 Mon Sep 17 00:00:00 2001 From: Jonathan Sick Date: Tue, 16 Aug 2022 15:03:24 -0400 Subject: [PATCH 07/12] Add GitHubRepoService.get_check_runs Get the check run resources from the GitHub API for a specific commit. --- src/timessquare/services/github/repo.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/timessquare/services/github/repo.py b/src/timessquare/services/github/repo.py index 4c2bacb7..729ce42b 100644 --- a/src/timessquare/services/github/repo.py +++ b/src/timessquare/services/github/repo.py @@ -564,3 +564,19 @@ async def run_notebook_check_run( ) await check.submit_conclusion(github_client=self._github_client) + + async def get_check_runs( + self, owner: str, repo: str, head_sha: str + ) -> List[GitHubCheckRunModel]: + """Get the check runs from GitHub corresponding to a commit. + + https://docs.github.com/en/rest/checks/runs#list-check-runs-for-a-git-reference + """ + check_runs: List[GitHubCheckRunModel] = [] + async for item in self._github_client.getiter( + "/repos/{owner}/{repo}/commits/{ref}/check-runs", + url_vars={"owner": owner, "repo": repo, "ref": head_sha}, + iterable_key="check_runs", + ): + check_runs.append(GitHubCheckRunModel.parse_obj(item)) + return check_runs From 394b4c1c635613b0a709d6b9853aac80489b954c Mon Sep 17 00:00:00 2001 From: Jonathan Sick Date: Tue, 16 Aug 2022 17:38:30 -0400 Subject: [PATCH 08/12] Add GitHubRepoService.get_pulls_for_check_runs This method, along with the required domain models, allow us to get the PR resources related to GitHub check runs for a specific commit. --- src/timessquare/domain/githubapi.py | 53 ++++++++++++++++++++++++- src/timessquare/services/github/repo.py | 24 +++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/src/timessquare/domain/githubapi.py b/src/timessquare/domain/githubapi.py index 4e5995f5..855edd8f 100644 --- a/src/timessquare/domain/githubapi.py +++ b/src/timessquare/domain/githubapi.py @@ -4,7 +4,7 @@ from base64 import b64decode from enum import Enum -from typing import Optional +from typing import List, Optional from pydantic import BaseModel, Field, HttpUrl @@ -20,6 +20,23 @@ class GitHubRepoOwnerModel(BaseModel): ) +class GitHubUserModel(BaseModel): + """A Pydantic model for the "user" field found in GitHub API resources. + + This contains brief (public) info about a user. + """ + + login: str = Field(title="Login name", description="GitHub username") + + html_url: HttpUrl = Field(description="Homepage for the user on GitHub") + + url: HttpUrl = Field( + description="URL for the user's resource in the GitHub API" + ) + + avatar_url: HttpUrl = Field(description="URL to the user's avatar") + + class GitHubRepositoryModel(BaseModel): """A Pydantic model for the "repository" field, often found in webhook payloads. @@ -77,6 +94,16 @@ class GitHubRepositoryModel(BaseModel): ) +class GitHubPullState(str, Enum): + """The state of a GitHub PR. + + https://docs.github.com/en/rest/pulls/pulls#get-a-pull-request + """ + + open = "open" + closed = "closed" + + class GitHubPullRequestModel(BaseModel): """A Pydantic model for a GitHub Pull Request. @@ -92,7 +119,15 @@ class GitHubPullRequestModel(BaseModel): title: str = Field(title="Title") - # TODO a lot more data is available. Expand this model as needed. + state: GitHubPullState = Field( + description="Whether the PR is opened or closed" + ) + + draft: bool = Field(description="True if the PR is a draft") + + merged: bool = Field(description="True if the PR is merged") + + user: GitHubUserModel = Field(description="The user that opened the PR") class GitHubBranchCommitModel(BaseModel): @@ -238,6 +273,16 @@ class GitHubCheckRunOutput(BaseModel): text: Optional[str] = Field(None, description="Extended report (markdown)") +class GitHubCheckRunPrInfoModel(BaseModel): + """A Pydantic model of the "pull_requsts[]" items in a check run + GitHub API model. + + https://docs.github.com/en/rest/checks/runs#get-a-check-run + """ + + url: HttpUrl = Field(description="GitHub API URL for this pull request") + + class GitHubCheckRunModel(BaseModel): """A Pydantic model for the "check_run" field in a check_run webhook payload (`GitHubCheckRunPayloadModel`). @@ -273,3 +318,7 @@ class GitHubCheckRunModel(BaseModel): output: Optional[GitHubCheckRunOutput] = Field( None, title="Output", description="Check run output, if available." ) + + pull_requests: List[GitHubCheckRunPrInfoModel] = Field( + default_factory=list + ) diff --git a/src/timessquare/services/github/repo.py b/src/timessquare/services/github/repo.py index 729ce42b..6c4ba923 100644 --- a/src/timessquare/services/github/repo.py +++ b/src/timessquare/services/github/repo.py @@ -580,3 +580,27 @@ async def get_check_runs( ): check_runs.append(GitHubCheckRunModel.parse_obj(item)) return check_runs + + async def get_pulls_for_check_runs( + self, check_runs: List[GitHubCheckRunModel] + ) -> List[GitHubPullRequestModel]: + """Get the pull requests from GitHub covered by the provided check + runs. + + Normally we'll look up the check runs first with `get_check_runs` + and then use this method to get information about the corresponding + pull requests. + """ + # reduce the unique pull request urls + pr_urls: List[str] = [] + for check_run in check_runs: + for pr in check_run.pull_requests: + pr_urls.append(pr.url) + pr_urls = sorted(list(set(pr_urls))) + + pull_requests: List[GitHubPullRequestModel] = [] + for pr_url in pr_urls: + data = await self._github_client.getitem(pr_url) + pull_requests.append(GitHubPullRequestModel.parse_obj(data)) + + return pull_requests From c6f9061fe7bfefa6157ee032c06086b008db1956 Mon Sep 17 00:00:00 2001 From: Jonathan Sick Date: Tue, 16 Aug 2022 17:39:43 -0400 Subject: [PATCH 09/12] Include GitHub context with PR contents The contents for a GitHub pull request now include info about pull requests and the status of check runs. --- src/timessquare/handlers/v1/handlers.py | 28 +++- src/timessquare/handlers/v1/models.py | 206 ++++++++++++++++++++++-- 2 files changed, 219 insertions(+), 15 deletions(-) diff --git a/src/timessquare/handlers/v1/handlers.py b/src/timessquare/handlers/v1/handlers.py index 64400a66..8dd547c9 100644 --- a/src/timessquare/handlers/v1/handlers.py +++ b/src/timessquare/handlers/v1/handlers.py @@ -14,6 +14,7 @@ from .models import ( GitHubContentsRoot, + GitHubPrContents, HtmlStatus, Index, Page, @@ -367,30 +368,49 @@ async def get_github_page( "/github-pr/{owner}/{repo}/{commit}", summary="Get a tree of GitHub PR preview pages", name="get_github_pr_tree", - response_model=GitHubContentsRoot, + response_model=GitHubPrContents, ) async def get_github_pr_tree( owner: str = github_owner_parameter, repo: str = github_repo_parameter, commit: str = pr_commit_parameter, context: RequestContext = Depends(context_dependency), -) -> GitHubContentsRoot: +) -> GitHubPrContents: """Get the tree of GitHub-backed pages for a pull request. This endpoint is primarily intended to be used by Squareone to power its navigational view of GitHub pages for a specific pull request (actually a commit SHA) of a repository. """ - page_service = context.page_service + repo_service = await context.create_github_repo_service( + owner=owner, repo=repo + ) # TODO handle response where the app is not installed + page_service = repo_service.page_service + async with context.session.begin(): github_tree = await page_service.get_github_pr_tree( owner=owner, repo=repo, commit=commit ) - return GitHubContentsRoot.from_tree( + + check_runs = await repo_service.get_check_runs( + owner=owner, repo=repo, head_sha=commit + ) + context.logger.debug( + "Check runs", check_runs=[run.dict() for run in check_runs] + ) + + pull_requests = await repo_service.get_pulls_for_check_runs(check_runs) + context.logger.debug( + "Pull requests", prs=[pr.dict() for pr in pull_requests] + ) + + return GitHubPrContents.create( tree=github_tree, owner=owner, repo=repo, commit=commit, + check_runs=check_runs, + pull_requests=pull_requests, ) diff --git a/src/timessquare/handlers/v1/models.py b/src/timessquare/handlers/v1/models.py index 92c89a1c..1fcdf9e6 100644 --- a/src/timessquare/handlers/v1/models.py +++ b/src/timessquare/handlers/v1/models.py @@ -3,14 +3,22 @@ from __future__ import annotations from datetime import datetime +from enum import Enum from typing import Any, Dict, List, Optional from urllib.parse import urlencode from fastapi import Request from markdown_it import MarkdownIt -from pydantic import AnyHttpUrl, BaseModel, EmailStr, Field +from pydantic import AnyHttpUrl, BaseModel, EmailStr, Field, HttpUrl from safir.metadata import Metadata as SafirMetadata +from timessquare.domain.githubapi import ( + GitHubCheckRunConclusion, + GitHubCheckRunModel, + GitHubCheckRunStatus, + GitHubPullRequestModel, + GitHubPullState, +) from timessquare.domain.githubtree import GitHubNode, GitHubNodeType from timessquare.domain.nbhtml import NbHtmlModel from timessquare.domain.page import PageModel, PageSummaryModel, PersonModel @@ -454,8 +462,158 @@ class GitHubContentsRoot(BaseModel): title="Contents", description="Content nodes" ) - owner: Optional[str] = Field( + @classmethod + def from_tree( + cls, + *, + tree: List[GitHubNode], + ) -> GitHubContentsRoot: + return cls( + contents=[GitHubContentsNode.from_domain_model(n) for n in tree], + ) + + +class GitHubContributor(BaseModel): + """A GitHub contributor.""" + + username: str = Field(..., title="Username", description="GitHub username") + + html_url: HttpUrl = Field( + ..., title="HTML URL", description="The user's homepage on GitHub." + ) + + avatar_url: HttpUrl = Field(..., title="Avatar image URL") + + +class GitHubPrState(str, Enum): + """The state of a GitHub PR.""" + + draft = "draft" + open = "open" + merged = "merged" + closed = "closed" + + +class GitHubPr(BaseModel): + """Information about a pull request.""" + + number: int = Field( + title="PR number", description="The pull request number." + ) + + title: str = Field(title="Title of the pull request") + + conversation_url: HttpUrl = Field( + title="URL for the PR's conversation page on GitHub." + ) + + contributor: GitHubContributor + + state: GitHubPrState + + @classmethod + def from_github_pr(cls, pull_request: GitHubPullRequestModel) -> GitHubPr: + # Consolidate github state information + if pull_request.merged: + state = GitHubPrState.merged + elif pull_request.draft: + state = GitHubPrState.draft + elif pull_request.state == GitHubPullState.closed: + state = GitHubPrState.closed + else: + state = GitHubPrState.open + + return cls( + number=pull_request.number, + title=pull_request.title, + conversation_url=pull_request.html_url, + state=state, + contributor=GitHubContributor( + username=pull_request.user.login, + html_url=pull_request.user.html_url, + avatar_url=pull_request.user.avatar_url, + ), + ) + + +class GitHubCheckRunSummary(BaseModel): + """Summary info about a check run.""" + + status: GitHubCheckRunStatus + + conclusion: Optional[GitHubCheckRunConclusion] + + external_id: Optional[str] = Field( + description="Identifier set by the check runner." + ) + + head_sha: str = Field( + title="Head sha", + description="The SHA of the most recent commit for this check suite.", + ) + + name: str = Field(description="Name of the check run.") + + html_url: HttpUrl = Field( + description="URL of the check run webpage on GitHub." + ) + + report_title: Optional[str] = Field( None, + title="Report title", + ) + + report_summary: Optional[FormattedText] = Field( + None, + title="Report summary", + ) + + report_text: Optional[FormattedText] = Field( + None, + title="Report body text", + ) + + @classmethod + def from_checkrun( + cls, check_run: GitHubCheckRunModel + ) -> GitHubCheckRunSummary: + """Create a check run summary API model from the GitHub API + model. + """ + report_title: Optional[str] = None + report_summary: Optional[FormattedText] = None + report_text: Optional[FormattedText] = None + + if check_run.output: + output = check_run.output + if output.title: + report_title = output.title + if output.summary: + report_summary = FormattedText.from_gfm(output.summary) + if output.text: + report_text = FormattedText.from_gfm(output.text) + + instance = cls( + status=check_run.status, + conclusion=check_run.conclusion, + external_id=check_run.external_id, + head_sha=check_run.head_sha, + name=check_run.name, + html_url=check_run.html_url, + report_title=report_title, + report_summary=report_summary, + report_text=report_text, + ) + return instance + + +class GitHubPrContents(GitHubContentsRoot): + """The contents of a GitHub pull request, along with information + about the check run and pull request. + """ + + owner: str = Field( + ..., title="GitHub owner", description=( "The GitHub owner for this tree, if this tree applies to a single " @@ -463,8 +621,8 @@ class GitHubContentsRoot(BaseModel): ), ) - repo: Optional[str] = Field( - None, + repo: str = Field( + ..., title="GitHub repo", description=( "The GitHub repo for this tree, if this tree applies to a single " @@ -472,8 +630,8 @@ class GitHubContentsRoot(BaseModel): ), ) - commit: Optional[str] = Field( - None, + commit: str = Field( + ..., title="GitHub commit", description=( "The GitHub commit for this tree, if this tree is specific to a " @@ -481,18 +639,44 @@ class GitHubContentsRoot(BaseModel): ), ) + yaml_check: Optional[GitHubCheckRunSummary] = Field( + ..., description="Summary of notebook execution check run." + ) + + nbexec_check: Optional[GitHubCheckRunSummary] = Field( + ..., description="Summary of notebook execution check run." + ) + + pull_requests: List[GitHubPr] = Field( + ..., + title="Pull Requests", + ) + @classmethod - def from_tree( + def create( cls, *, tree: List[GitHubNode], - owner: Optional[str] = None, - repo: Optional[str] = None, - commit: Optional[str] = None, - ) -> GitHubContentsRoot: + owner: str, + repo: str, + commit: str, + check_runs: List[GitHubCheckRunModel], + pull_requests: List[GitHubPullRequestModel], + ) -> GitHubPrContents: + yaml_check: Optional[GitHubCheckRunSummary] = None + nbexec_check: Optional[GitHubCheckRunSummary] = None + for check_run in check_runs: + if check_run.external_id == "times-square/nbexec": + nbexec_check = GitHubCheckRunSummary.from_checkrun(check_run) + elif check_run.external_id == "times-square/yaml-check": + yaml_check = GitHubCheckRunSummary.from_checkrun(check_run) + return cls( contents=[GitHubContentsNode.from_domain_model(n) for n in tree], owner=owner, repo=repo, commit=commit, + yaml_check=yaml_check, + nbexec_check=nbexec_check, + pull_requests=[GitHubPr.from_github_pr(p) for p in pull_requests], ) From 6e70ced4d3b49c6986f7879f6dc6f9cbfcf140ac Mon Sep 17 00:00:00 2001 From: Jonathan Sick Date: Thu, 18 Aug 2022 14:36:21 -0400 Subject: [PATCH 10/12] Add details_url for check run results This sets the "details_url" field for check runs to the Squareone landing page for the check run, /times-square/github-pr/:owner/:repo/:commit --- src/timessquare/domain/githubcheckrun.py | 37 ++++++++++++++++++++---- src/timessquare/services/github/repo.py | 2 +- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/timessquare/domain/githubcheckrun.py b/src/timessquare/domain/githubcheckrun.py index 903e9310..aa51b4f0 100644 --- a/src/timessquare/domain/githubcheckrun.py +++ b/src/timessquare/domain/githubcheckrun.py @@ -9,6 +9,8 @@ from gidgethub.httpx import GitHubAPI from pydantic import ValidationError +from timessquare.config import config + from .githubapi import ( GitHubBlobModel, GitHubCheckRunAnnotationLevel, @@ -99,8 +101,11 @@ class GitHubCheck(metaclass=ABCMeta): share the same external ID. """ - def __init__(self, check_run: GitHubCheckRunModel) -> None: + def __init__( + self, *, check_run: GitHubCheckRunModel, repo: GitHubRepositoryModel + ) -> None: self.check_run = check_run + self.repo = repo self.annotations: List[Annotation] = [] @property @@ -125,6 +130,21 @@ def text(self) -> str: """The text body of the check's message.""" raise NotImplementedError + @property + def squareone_pr_url_root(self) -> str: + """Root URL for this check run in Squareone. + + Formatted as ``{host}/times-square/github-pr/{owner}/{repo}/{commit}`` + """ + if config.environment_url.endswith("/"): + squareone_url = str(config.environment_url) + else: + squareone_url = f"{str(config.environment_url)}/" + return ( + f"{squareone_url}/times-square/github-pr/{self.repo.owner.login}" + f"/{self.repo.name}/{self.check_run.head_sha}" + ) + def export_truncated_annotations(self) -> List[Dict[str, Any]]: """Export the first 50 annotations to objects serializable to GitHub. @@ -155,6 +175,7 @@ async def submit_conclusion( data={ "status": GitHubCheckRunStatus.completed, "conclusion": self.conclusion, + "details_url": self.squareone_pr_url_root, "output": { "title": self.title, "summary": self.summary, @@ -175,14 +196,16 @@ class GitHubConfigsCheck(GitHubCheck): share the same external ID. """ - def __init__(self, check_run: GitHubCheckRunModel) -> None: + def __init__( + self, check_run: GitHubCheckRunModel, repo: GitHubRepositoryModel + ) -> None: self.sidecar_files_checked: List[str] = [] # Optional caching for data reuse self.checkout: Optional[GitHubRepositoryCheckout] = None self.tree: Optional[RecursiveGitTreeModel] = None - super().__init__(check_run=check_run) + super().__init__(check_run=check_run, repo=repo) @classmethod async def create_check_run_and_validate( @@ -225,7 +248,7 @@ async def validate_repo( repository containing Times Square notebooks given a check run already registered with GitHub. """ - check = cls(check_run) + check = cls(check_run, repo) await check.submit_in_progress(github_client) try: @@ -365,9 +388,11 @@ class NotebookExecutionsCheck(GitHubCheck): share the same external ID. """ - def __init__(self, check_run: GitHubCheckRunModel) -> None: + def __init__( + self, check_run: GitHubCheckRunModel, repo: GitHubRepositoryModel + ) -> None: self.notebook_paths_checked: List[str] = [] - super().__init__(check_run=check_run) + super().__init__(check_run=check_run, repo=repo) def report_noteburst_failure( self, page_execution: PageExecutionInfo diff --git a/src/timessquare/services/github/repo.py b/src/timessquare/services/github/repo.py index 6c4ba923..835b6fa1 100644 --- a/src/timessquare/services/github/repo.py +++ b/src/timessquare/services/github/repo.py @@ -442,7 +442,7 @@ async def run_notebook_check_run( This check actually creates/updates Page resources, hence it is run at the service layer, rather than in a domain model. """ - check = NotebookExecutionsCheck(check_run) + check = NotebookExecutionsCheck(check_run, repo) await check.submit_in_progress(self._github_client) self._logger.debug("Notebook executions check in progress") From f55e9975cae9097efa7eecf30df27ba794b2a247 Mon Sep 17 00:00:00 2001 From: Jonathan Sick Date: Thu, 18 Aug 2022 14:51:24 -0400 Subject: [PATCH 11/12] Link to notebook previews in Squareone --- src/timessquare/domain/githubcheckrun.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/timessquare/domain/githubcheckrun.py b/src/timessquare/domain/githubcheckrun.py index aa51b4f0..82327eb1 100644 --- a/src/timessquare/domain/githubcheckrun.py +++ b/src/timessquare/domain/githubcheckrun.py @@ -2,6 +2,7 @@ from __future__ import annotations +import os.path from abc import ABCMeta, abstractproperty from dataclasses import dataclass from typing import Any, Dict, List, Optional, Sequence, Union @@ -145,6 +146,10 @@ def squareone_pr_url_root(self) -> str: f"/{self.repo.name}/{self.check_run.head_sha}" ) + def get_preview_url(self, notebook_path: str) -> str: + display_path = os.path.splitext(notebook_path)[0] + return f"{self.squareone_pr_url_root}/{display_path}" + def export_truncated_annotations(self) -> List[Dict[str, Any]]: """Export the first 50 annotations to objects serializable to GitHub. @@ -457,10 +462,12 @@ def text(self) -> str: notebook_paths = list(set(self.notebook_paths_checked)) notebook_paths.sort() for notebook_path in notebook_paths: + preview_url = self.get_preview_url(notebook_path) + linked_notebook = f"[{notebook_path}]({preview_url})" if self._is_file_ok(notebook_path): - text = f"{text}| {notebook_path} | ✅ |\n" + text = f"{text}| {linked_notebook} | ✅ |\n" else: - text = f"{text}| {notebook_path} | ❌ |\n" + text = f"{text}| {linked_notebook} | ❌ |\n" return text From 122598af83a339c18b58ce017ca9c53b47ba2653 Mon Sep 17 00:00:00 2001 From: Jonathan Sick Date: Mon, 15 Aug 2022 14:11:50 -0400 Subject: [PATCH 12/12] Update change log for 0.6.0 --- CHANGELOG.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 510054a9..131338ee 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,16 @@ Change log ========== +0.6.0 (2022-08-18) +------------------ + +Times Square now exposes information about pages created during GitHub PR check runs: + +- ``GET /times-square/api/v1/github-pr/:org/:repo/:sha`` provides metadata for a repository's check run in general, such as the contents in the check run and the GitHub pull request or check run. +- ``GET /times-square/api/v1/github-pr/:org/:repo/:sha/:path`` provides metadata about a specific notebook. + +Times Square check runs also link to the pull request preview pages published through Times Square's interface in Squareone. + 0.5.0 (2022-07-04) ------------------