diff --git a/Pipfile b/Pipfile index 3bcbe159..27115972 100644 --- a/Pipfile +++ b/Pipfile @@ -10,8 +10,8 @@ requests = "*" cerberus = "*" defusedxml = "*" xmltodict = "*" -jinja2 = "*" python-dotenv = "*" +pydantic = "*" [dev-packages] pytest = "*" @@ -19,11 +19,11 @@ mypy = "*" pylint = "*" flake8 = "*" black = {extras = ["d"], version = "*"} -var-dump = "*" types-pyyaml = "*" types-requests = "*" pytest-cov = "*" coveralls = "*" +icecream = "*" [requires] python_version = "3.11" diff --git a/Pipfile.lock b/Pipfile.lock index bfb14a80..86fe17ae 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "87e664a0e25e7b0a590fdf2ef6c7be3266ff1e1081d362423814e68f053cb8d8" + "sha256": "392659112522bebd6fdaf2d24c384cc546c19f65e7c2b260538daf8cd70f43b3" }, "pipfile-spec": 6, "requires": { @@ -16,6 +16,14 @@ ] }, "default": { + "annotated-types": { + "hashes": [ + "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", + "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" + ], + "markers": "python_version >= '3.8'", + "version": "==0.7.0" + }, "cerberus": { "hashes": [ "sha256:7649a5815024d18eb7c6aa5e7a95355c649a53aacfc9b050e9d0bf6bfa2af372", @@ -26,11 +34,11 @@ }, "certifi": { "hashes": [ - "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", - "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" + "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", + "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9" ], "markers": "python_version >= '3.6'", - "version": "==2024.2.2" + "version": "==2024.8.30" }, "charset-normalizer": { "hashes": [ @@ -148,86 +156,115 @@ }, "idna": { "hashes": [ - "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", - "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" + "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", + "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" ], - "markers": "python_version >= '3.5'", - "version": "==3.7" + "markers": "python_version >= '3.6'", + "version": "==3.10" }, - "jinja2": { + "pydantic": { "hashes": [ - "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", - "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d" + "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f", + "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==3.1.4" + "markers": "python_version >= '3.8'", + "version": "==2.9.2" }, - "markupsafe": { + "pydantic-core": { "hashes": [ - "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf", - "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff", - "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f", - "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3", - "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532", - "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f", - "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617", - "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df", - "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4", - "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906", - "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f", - "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4", - "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8", - "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371", - "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2", - "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465", - "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52", - "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6", - "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", - "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad", - "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2", - "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0", - "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029", - "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f", - "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a", - "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced", - "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5", - "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c", - "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf", - "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9", - "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", - "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", - "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3", - "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1", - "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46", - "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc", - "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a", - "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee", - "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900", - "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5", - "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea", - "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f", - "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5", - "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e", - "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a", - "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f", - "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50", - "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a", - "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", - "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4", - "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff", - "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2", - "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46", - "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b", - "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf", - "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5", - "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5", - "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab", - "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd", - "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68" + "sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36", + "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05", + "sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071", + "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327", + "sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c", + "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36", + "sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29", + "sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744", + "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d", + "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec", + "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e", + "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e", + "sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577", + "sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232", + "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863", + "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6", + "sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368", + "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480", + "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2", + "sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2", + "sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6", + "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769", + "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d", + "sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2", + "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84", + "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166", + "sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271", + "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5", + "sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb", + "sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13", + "sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323", + "sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556", + "sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665", + "sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef", + "sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb", + "sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119", + "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126", + "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510", + "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b", + "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87", + "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f", + "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc", + "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8", + "sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21", + "sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f", + "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6", + "sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658", + "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b", + "sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3", + "sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb", + "sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59", + "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24", + "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9", + "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3", + "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd", + "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753", + "sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55", + "sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad", + "sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a", + "sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605", + "sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e", + "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b", + "sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433", + "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8", + "sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07", + "sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728", + "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0", + "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327", + "sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555", + "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64", + "sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6", + "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea", + "sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b", + "sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df", + "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e", + "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd", + "sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068", + "sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3", + "sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040", + "sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12", + "sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916", + "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f", + "sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f", + "sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801", + "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231", + "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5", + "sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8", + "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee", + "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607" ], - "markers": "python_version >= '3.7'", - "version": "==2.1.5" + "markers": "python_version >= '3.8'", + "version": "==2.23.4" }, "python-dotenv": { "hashes": [ @@ -240,61 +277,63 @@ }, "pyyaml": { "hashes": [ - "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5", - "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc", - "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", - "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741", - "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206", - "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27", - "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595", - "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62", - "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98", - "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696", - "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290", - "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9", - "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d", - "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6", - "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867", - "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47", - "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486", - "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6", - "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3", - "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007", - "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938", - "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0", - "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c", - "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735", - "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d", - "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28", - "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", - "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", - "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", - "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef", - "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", - "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd", - "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3", - "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0", - "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515", - "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c", - "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c", - "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924", - "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34", - "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43", - "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859", - "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673", - "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54", - "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a", - "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b", - "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab", - "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa", - "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c", - "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585", - "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d", - "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f" + "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", + "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", + "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", + "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", + "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", + "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", + "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", + "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", + "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", + "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", + "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", + "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", + "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", + "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", + "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", + "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", + "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", + "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", + "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", + "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", + "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", + "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", + "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", + "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", + "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", + "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", + "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", + "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", + "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", + "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", + "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", + "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", + "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", + "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", + "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", + "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", + "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", + "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", + "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", + "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", + "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", + "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", + "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", + "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", + "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", + "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", + "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", + "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", + "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", + "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", + "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", + "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", + "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" ], "index": "pypi", - "markers": "python_version >= '3.6'", - "version": "==6.0.1" + "markers": "python_version >= '3.8'", + "version": "==6.0.2" }, "requests": { "hashes": [ @@ -305,13 +344,21 @@ "markers": "python_version >= '3.8'", "version": "==2.32.3" }, + "typing-extensions": { + "hashes": [ + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" + ], + "markers": "python_version < '3.13'", + "version": "==4.12.2" + }, "urllib3": { "hashes": [ - "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", - "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19" + "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", + "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9" ], "markers": "python_version >= '3.8'", - "version": "==2.2.1" + "version": "==2.2.3" }, "xmltodict": { "hashes": [ @@ -324,86 +371,109 @@ } }, "develop": { + "aiohappyeyeballs": { + "hashes": [ + "sha256:75cf88a15106a5002a8eb1dab212525c00d1f4c0fa96e551c9fbe6f09a621586", + "sha256:8a7a83727b2756f394ab2895ea0765a0a8c475e3c71e98d43d76f22b4b435572" + ], + "markers": "python_version >= '3.8'", + "version": "==2.4.3" + }, "aiohttp": { "hashes": [ - "sha256:0605cc2c0088fcaae79f01c913a38611ad09ba68ff482402d3410bf59039bfb8", - "sha256:0a158704edf0abcac8ac371fbb54044f3270bdbc93e254a82b6c82be1ef08f3c", - "sha256:0cbf56238f4bbf49dab8c2dc2e6b1b68502b1e88d335bea59b3f5b9f4c001475", - "sha256:1732102949ff6087589408d76cd6dea656b93c896b011ecafff418c9661dc4ed", - "sha256:18f634d540dd099c262e9f887c8bbacc959847cfe5da7a0e2e1cf3f14dbf2daf", - "sha256:239f975589a944eeb1bad26b8b140a59a3a320067fb3cd10b75c3092405a1372", - "sha256:2faa61a904b83142747fc6a6d7ad8fccff898c849123030f8e75d5d967fd4a81", - "sha256:320e8618eda64e19d11bdb3bd04ccc0a816c17eaecb7e4945d01deee2a22f95f", - "sha256:38d80498e2e169bc61418ff36170e0aad0cd268da8b38a17c4cf29d254a8b3f1", - "sha256:3916c8692dbd9d55c523374a3b8213e628424d19116ac4308e434dbf6d95bbdd", - "sha256:393c7aba2b55559ef7ab791c94b44f7482a07bf7640d17b341b79081f5e5cd1a", - "sha256:3b7b30258348082826d274504fbc7c849959f1989d86c29bc355107accec6cfb", - "sha256:3fcb4046d2904378e3aeea1df51f697b0467f2aac55d232c87ba162709478c46", - "sha256:4109adee842b90671f1b689901b948f347325045c15f46b39797ae1bf17019de", - "sha256:4558e5012ee03d2638c681e156461d37b7a113fe13970d438d95d10173d25f78", - "sha256:45731330e754f5811c314901cebdf19dd776a44b31927fa4b4dbecab9e457b0c", - "sha256:4715a9b778f4293b9f8ae7a0a7cef9829f02ff8d6277a39d7f40565c737d3771", - "sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb", - "sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430", - "sha256:4ff550491f5492ab5ed3533e76b8567f4b37bd2995e780a1f46bca2024223233", - "sha256:52c27110f3862a1afbcb2af4281fc9fdc40327fa286c4625dfee247c3ba90156", - "sha256:55b39c8684a46e56ef8c8d24faf02de4a2b2ac60d26cee93bc595651ff545de9", - "sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59", - "sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888", - "sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c", - "sha256:60cdbd56f4cad9f69c35eaac0fbbdf1f77b0ff9456cebd4902f3dd1cf096464c", - "sha256:6380c039ec52866c06d69b5c7aad5478b24ed11696f0e72f6b807cfb261453da", - "sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424", - "sha256:66331d00fb28dc90aa606d9a54304af76b335ae204d1836f65797d6fe27f1ca2", - "sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb", - "sha256:694d828b5c41255e54bc2dddb51a9f5150b4eefa9886e38b52605a05d96566e8", - "sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a", - "sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10", - "sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0", - "sha256:7b179eea70833c8dee51ec42f3b4097bd6370892fa93f510f76762105568cf09", - "sha256:7f64cbd44443e80094309875d4f9c71d0401e966d191c3d469cde4642bc2e031", - "sha256:82a6a97d9771cb48ae16979c3a3a9a18b600a8505b1115cfe354dfb2054468b4", - "sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3", - "sha256:8676e8fd73141ded15ea586de0b7cda1542960a7b9ad89b2b06428e97125d4fa", - "sha256:88e311d98cc0bf45b62fc46c66753a83445f5ab20038bcc1b8a1cc05666f428a", - "sha256:8b4f72fbb66279624bfe83fd5eb6aea0022dad8eec62b71e7bf63ee1caadeafe", - "sha256:8c64a6dc3fe5db7b1b4d2b5cb84c4f677768bdc340611eca673afb7cf416ef5a", - "sha256:8cf142aa6c1a751fcb364158fd710b8a9be874b81889c2bd13aa8893197455e2", - "sha256:8d1964eb7617907c792ca00b341b5ec3e01ae8c280825deadbbd678447b127e1", - "sha256:93e22add827447d2e26d67c9ac0161756007f152fdc5210277d00a85f6c92323", - "sha256:9c69e77370cce2d6df5d12b4e12bdcca60c47ba13d1cbbc8645dd005a20b738b", - "sha256:9dbc053ac75ccc63dc3a3cc547b98c7258ec35a215a92bd9f983e0aac95d3d5b", - "sha256:9e3a1ae66e3d0c17cf65c08968a5ee3180c5a95920ec2731f53343fac9bad106", - "sha256:a6ea1a5b409a85477fd8e5ee6ad8f0e40bf2844c270955e09360418cfd09abac", - "sha256:a81b1143d42b66ffc40a441379387076243ef7b51019204fd3ec36b9f69e77d6", - "sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832", - "sha256:afc52b8d969eff14e069a710057d15ab9ac17cd4b6753042c407dcea0e40bf75", - "sha256:b3df71da99c98534be076196791adca8819761f0bf6e08e07fd7da25127150d6", - "sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d", - "sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72", - "sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db", - "sha256:c6021d296318cb6f9414b48e6a439a7f5d1f665464da507e8ff640848ee2a58a", - "sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da", - "sha256:c7a4b7a6cf5b6eb11e109a9755fd4fda7d57395f8c575e166d363b9fc3ec4678", - "sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b", - "sha256:cd2adf5c87ff6d8b277814a28a535b59e20bfea40a101db6b3bdca7e9926bc24", - "sha256:d1469f228cd9ffddd396d9948b8c9cd8022b6d1bf1e40c6f25b0fb90b4f893ed", - "sha256:d153f652a687a8e95ad367a86a61e8d53d528b0530ef382ec5aaf533140ed00f", - "sha256:d5ab8e1f6bee051a4bf6195e38a5c13e5e161cb7bad83d8854524798bd9fcd6e", - "sha256:da00da442a0e31f1c69d26d224e1efd3a1ca5bcbf210978a2ca7426dfcae9f58", - "sha256:da22dab31d7180f8c3ac7c7635f3bcd53808f374f6aa333fe0b0b9e14b01f91a", - "sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342", - "sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558", - "sha256:e9a3d838441bebcf5cf442700e3963f58b5c33f015341f9ea86dcd7d503c07e2", - "sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551", - "sha256:f22eb3a6c1080d862befa0a89c380b4dafce29dc6cd56083f630073d102eb595", - "sha256:f26383adb94da5e7fb388d441bf09c61e5e35f455a3217bfd790c6b6bc64b2ee", - "sha256:f3c2890ca8c59ee683fd09adf32321a40fe1cf164e3387799efb2acebf090c11", - "sha256:f64fd07515dad67f24b6ea4a66ae2876c01031de91c93075b8093f07c0a2d93d", - "sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7", - "sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f" + "sha256:10c7932337285a6bfa3a5fe1fd4da90b66ebfd9d0cbd1544402e1202eb9a8c3e", + "sha256:177126e971782769b34933e94fddd1089cef0fe6b82fee8a885e539f5b0f0c6a", + "sha256:1ce46dfb49cfbf9e92818be4b761d4042230b1f0e05ffec0aad15b3eb162b905", + "sha256:1e7a6af57091056a79a35104d6ec29d98ec7f1fb7270ad9c6fff871b678d1ff8", + "sha256:21a72f4a9c69a8567a0aca12042f12bba25d3139fd5dd8eeb9931f4d9e8599cd", + "sha256:21c1925541ca84f7b5e0df361c0a813a7d6a56d3b0030ebd4b220b8d232015f9", + "sha256:21f8225f7dc187018e8433c9326be01477fb2810721e048b33ac49091b19fb4a", + "sha256:22cdeb684d8552490dd2697a5138c4ecb46f844892df437aaf94f7eea99af879", + "sha256:270e653b5a4b557476a1ed40e6b6ce82f331aab669620d7c95c658ef976c9c5e", + "sha256:2df786c96c57cd6b87156ba4c5f166af7b88f3fc05f9d592252fdc83d8615a3c", + "sha256:32710d6b3b6c09c60c794d84ca887a3a2890131c0b02b3cefdcc6709a2260a7c", + "sha256:33a68011a38020ed4ff41ae0dbf4a96a202562ecf2024bdd8f65385f1d07f6ef", + "sha256:365783e1b7c40b59ed4ce2b5a7491bae48f41cd2c30d52647a5b1ee8604c68ad", + "sha256:3a95d2686bc4794d66bd8de654e41b5339fab542b2bca9238aa63ed5f4f2ce82", + "sha256:3b2036479b6b94afaaca7d07b8a68dc0e67b0caf5f6293bb6a5a1825f5923000", + "sha256:3c7f270f4ca92760f98a42c45a58674fff488e23b144ec80b1cc6fa2effed377", + "sha256:3f6d47e392c27206701565c8df4cac6ebed28fdf6dcaea5b1eea7a4631d8e6db", + "sha256:40d2d719c3c36a7a65ed26400e2b45b2d9ed7edf498f4df38b2ae130f25a0d01", + "sha256:4618f0d2bf523043866a9ff8458900d8eb0a6d4018f251dae98e5f1fb699f3a8", + "sha256:471a8c47344b9cc309558b3fcc469bd2c12b49322b4b31eb386c4a2b2d44e44a", + "sha256:4954e6b06dd0be97e1a5751fc606be1f9edbdc553c5d9b57d72406a8fbd17f9d", + "sha256:497a7d20caea8855c5429db3cdb829385467217d7feb86952a6107e033e031b9", + "sha256:4b91f4f62ad39a8a42d511d66269b46cb2fb7dea9564c21ab6c56a642d28bff5", + "sha256:4dbf252ac19860e0ab56cd480d2805498f47c5a2d04f5995d8d8a6effd04b48c", + "sha256:4e10b04542d27e21538e670156e88766543692a0a883f243ba8fad9ddea82e53", + "sha256:5284997e3d88d0dfb874c43e51ae8f4a6f4ca5b90dcf22995035187253d430db", + "sha256:57359785f27394a8bcab0da6dcd46706d087dfebf59a8d0ad2e64a4bc2f6f94f", + "sha256:597128cb7bc5f068181b49a732961f46cb89f85686206289d6ccb5e27cb5fbe2", + "sha256:5aa1a073514cf59c81ad49a4ed9b5d72b2433638cd53160fd2f3a9cfa94718db", + "sha256:680dbcff5adc7f696ccf8bf671d38366a1f620b5616a1d333d0cb33956065395", + "sha256:6984dda9d79064361ab58d03f6c1e793ea845c6cfa89ffe1a7b9bb400dfd56bd", + "sha256:69de056022e7abf69cb9fec795515973cc3eeaff51e3ea8d72a77aa933a91c52", + "sha256:6c7efa6616a95e3bd73b8a69691012d2ef1f95f9ea0189e42f338fae080c2fc6", + "sha256:6d1ad868624f6cea77341ef2877ad4e71f7116834a6cd7ec36ec5c32f94ee6ae", + "sha256:713dff3f87ceec3bde4f3f484861464e722cf7533f9fa6b824ec82bb5a9010a7", + "sha256:71462f8eeca477cbc0c9700a9464e3f75f59068aed5e9d4a521a103692da72dc", + "sha256:7c38cfd355fd86c39b2d54651bd6ed7d63d4fe3b5553f364bae3306e2445f847", + "sha256:8296edd99d0dd9d0eb8b9e25b3b3506eef55c1854e9cc230f0b3f885f680410b", + "sha256:85431c9131a9a0f65260dc7a65c800ca5eae78c4c9931618f18c8e0933a0e0c1", + "sha256:85e4d7bd05d18e4b348441e7584c681eff646e3bf38f68b2626807f3add21aa2", + "sha256:8885ca09d3a9317219c0831276bfe26984b17b2c37b7bf70dd478d17092a4772", + "sha256:8960fabc20bfe4fafb941067cda8e23c8c17c98c121aa31c7bf0cdab11b07842", + "sha256:9443d9ebc5167ce1fbb552faf2d666fb22ef5716a8750be67efd140a7733738c", + "sha256:9721554bfa9e15f6e462da304374c2f1baede3cb06008c36c47fa37ea32f1dc4", + "sha256:98a4eb60e27033dee9593814ca320ee8c199489fbc6b2699d0f710584db7feb7", + "sha256:98fae99d5c2146f254b7806001498e6f9ffb0e330de55a35e72feb7cb2fa399b", + "sha256:9a281cba03bdaa341c70b7551b2256a88d45eead149f48b75a96d41128c240b3", + "sha256:a087c84b4992160ffef7afd98ef24177c8bd4ad61c53607145a8377457385100", + "sha256:a1ba7bc139592339ddeb62c06486d0fa0f4ca61216e14137a40d626c81faf10c", + "sha256:a3081246bab4d419697ee45e555cef5cd1def7ac193dff6f50be761d2e44f194", + "sha256:a72f89aea712c619b2ca32c6f4335c77125ede27530ad9705f4f349357833695", + "sha256:a78ba86d5a08207d1d1ad10b97aed6ea48b374b3f6831d02d0b06545ac0f181e", + "sha256:a961ee6f2cdd1a2be4735333ab284691180d40bad48f97bb598841bfcbfb94ec", + "sha256:ab1546fc8e00676febc81c548a876c7bde32f881b8334b77f84719ab2c7d28dc", + "sha256:ab2d6523575fc98896c80f49ac99e849c0b0e69cc80bf864eed6af2ae728a52b", + "sha256:aff048793d05e1ce05b62e49dccf81fe52719a13f4861530706619506224992b", + "sha256:b1a012677b8e0a39e181e218de47d6741c5922202e3b0b65e412e2ce47c39337", + "sha256:b667e2a03407d79a76c618dc30cedebd48f082d85880d0c9c4ec2faa3e10f43e", + "sha256:b91557ee0893da52794b25660d4f57bb519bcad8b7df301acd3898f7197c5d81", + "sha256:badb51d851358cd7535b647bb67af4854b64f3c85f0d089c737f75504d5910ec", + "sha256:c36074b26f3263879ba8e4dbd33db2b79874a3392f403a70b772701363148b9f", + "sha256:c4916070e12ae140110aa598031876c1bf8676a36a750716ea0aa5bd694aa2e7", + "sha256:c6769d71bfb1ed60321363a9bc05e94dcf05e38295ef41d46ac08919e5b00d19", + "sha256:c887019dbcb4af58a091a45ccf376fffe800b5531b45c1efccda4bedf87747ea", + "sha256:cd9716ef0224fe0d0336997eb242f40619f9f8c5c57e66b525a1ebf9f1d8cebe", + "sha256:ceacea31f8a55cdba02bc72c93eb2e1b77160e91f8abd605969c168502fd71eb", + "sha256:d088ca05381fd409793571d8e34eca06daf41c8c50a05aeed358d2d340c7af81", + "sha256:d3a79200a9d5e621c4623081ddb25380b713c8cf5233cd11c1aabad990bb9381", + "sha256:d82404a0e7b10e0d7f022cf44031b78af8a4f99bd01561ac68f7c24772fed021", + "sha256:d95ae4420669c871667aad92ba8cce6251d61d79c1a38504621094143f94a8b4", + "sha256:da57af0c54a302b7c655fa1ccd5b1817a53739afa39924ef1816e7b7c8a07ccb", + "sha256:ddb9b9764cfb4459acf01c02d2a59d3e5066b06a846a364fd1749aa168efa2be", + "sha256:de23085cf90911600ace512e909114385026b16324fa203cc74c81f21fd3276a", + "sha256:e1f0f7b27171b2956a27bd8f899751d0866ddabdd05cbddf3520f945130a908c", + "sha256:e32148b4a745e70a255a1d44b5664de1f2e24fcefb98a75b60c83b9e260ddb5b", + "sha256:e45fdfcb2d5bcad83373e4808825b7512953146d147488114575780640665027", + "sha256:e56bb7e31c4bc79956b866163170bc89fd619e0581ce813330d4ea46921a4881", + "sha256:e860985f30f3a015979e63e7ba1a391526cdac1b22b7b332579df7867848e255", + "sha256:ee3587506898d4a404b33bd19689286ccf226c3d44d7a73670c8498cd688e42c", + "sha256:ee97c4e54f457c366e1f76fbbf3e8effee9de57dae671084a161c00f481106ce", + "sha256:ef9b484604af05ca745b6108ca1aaa22ae1919037ae4f93aaf9a37ba42e0b835", + "sha256:f21e8f2abed9a44afc3d15bba22e0dfc71e5fa859bea916e42354c16102b036f", + "sha256:f23a6c1d09de5de89a33c9e9b229106cb70dcfdd55e81a3a3580eaadaa32bc92", + "sha256:f5d5d5401744dda50b943d8764508d0e60cc2d3305ac1e6420935861a9d544bc", + "sha256:f78e2a78432c537ae876a93013b7bc0027ba5b93ad7b3463624c4b6906489332", + "sha256:f8179855a4e4f3b931cb1764ec87673d3fbdcca2af496c8d30567d7b034a13db", + "sha256:fc0e7f91705445d79beafba9bb3057dd50830e40fe5417017a76a214af54e122", + "sha256:fe285a697c851734285369614443451462ce78aac2b77db23567507484b1dc6f", + "sha256:fe3d79d6af839ffa46fdc5d2cf34295390894471e9875050eafa584cb781508d", + "sha256:fecd55e7418fabd297fd836e65cbd6371aa4035a264998a091bbf13f94d9c44d", + "sha256:ffef3d763e4c8fc97e740da5b4d0f080b78630a3914f4e772a122bbfa608c1db" ], - "version": "==3.9.5" + "version": "==3.10.8" }, "aiosignal": { "hashes": [ @@ -415,58 +485,65 @@ }, "astroid": { "hashes": [ - "sha256:8ead48e31b92b2e217b6c9733a21afafe479d52d6e164dd25fb1a770c7c3cf94", - "sha256:e8a0083b4bb28fcffb6207a3bfc9e5d0a68be951dd7e336d5dcf639c682388c0" + "sha256:5eba185467253501b62a9f113c263524b4f5d55e1b30456370eed4cdbd6438fd", + "sha256:e73d0b62dd680a7c07cb2cd0ce3c22570b044dd01bd994bc3a2dd16c6cbba162" ], - "markers": "python_full_version >= '3.8.0'", - "version": "==3.2.2" + "markers": "python_full_version >= '3.9.0'", + "version": "==3.3.4" + }, + "asttokens": { + "hashes": [ + "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24", + "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0" + ], + "version": "==2.4.1" }, "attrs": { "hashes": [ - "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", - "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" + "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", + "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2" ], "markers": "python_version >= '3.7'", - "version": "==23.2.0" + "version": "==24.2.0" }, "black": { "extras": [ "d" ], "hashes": [ - "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474", - "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1", - "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0", - "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8", - "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96", - "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1", - "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04", - "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021", - "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94", - "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d", - "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c", - "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7", - "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c", - "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc", - "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7", - "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d", - "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c", - "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741", - "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce", - "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb", - "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063", - "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e" + "sha256:09cdeb74d494ec023ded657f7092ba518e8cf78fa8386155e4a03fdcc44679e6", + "sha256:1f13f7f386f86f8121d76599114bb8c17b69d962137fc70efe56137727c7047e", + "sha256:2500945420b6784c38b9ee885af039f5e7471ef284ab03fa35ecdde4688cd83f", + "sha256:2b59b250fdba5f9a9cd9d0ece6e6d993d91ce877d121d161e4698af3eb9c1018", + "sha256:3c4285573d4897a7610054af5a890bde7c65cb466040c5f0c8b732812d7f0e5e", + "sha256:505289f17ceda596658ae81b61ebbe2d9b25aa78067035184ed0a9d855d18afd", + "sha256:62e8730977f0b77998029da7971fa896ceefa2c4c4933fcd593fa599ecbf97a4", + "sha256:649f6d84ccbae73ab767e206772cc2d7a393a001070a4c814a546afd0d423aed", + "sha256:6e55d30d44bed36593c3163b9bc63bf58b3b30e4611e4d88a0c3c239930ed5b2", + "sha256:707a1ca89221bc8a1a64fb5e15ef39cd755633daa672a9db7498d1c19de66a42", + "sha256:72901b4913cbac8972ad911dc4098d5753704d1f3c56e44ae8dce99eecb0e3af", + "sha256:73bbf84ed136e45d451a260c6b73ed674652f90a2b3211d6a35e78054563a9bb", + "sha256:7c046c1d1eeb7aea9335da62472481d3bbf3fd986e093cffd35f4385c94ae368", + "sha256:81c6742da39f33b08e791da38410f32e27d632260e599df7245cccee2064afeb", + "sha256:837fd281f1908d0076844bc2b801ad2d369c78c45cf800cad7b61686051041af", + "sha256:972085c618ee94f402da1af548a4f218c754ea7e5dc70acb168bfaca4c2542ed", + "sha256:9e84e33b37be070ba135176c123ae52a51f82306def9f7d063ee302ecab2cf47", + "sha256:b19c9ad992c7883ad84c9b22aaa73562a16b819c1d8db7a1a1a49fb7ec13c7d2", + "sha256:d6417535d99c37cee4091a2f24eb2b6d5ec42b144d50f1f2e436d9fe1916fe1a", + "sha256:eab4dd44ce80dea27dc69db40dab62d4ca96112f87996bca68cd75639aeb2e4c", + "sha256:f490dbd59680d809ca31efdae20e634f3fae27fba3ce0ba3208333b713bc3920", + "sha256:fb6e2c0b86bbd43dee042e48059c9ad7830abd5c94b0bc518c0eeec57c3eddc1" ], "markers": "python_version >= '3.8'", - "version": "==24.4.2" + "version": "==24.8.0" }, "certifi": { "hashes": [ - "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", - "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" + "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", + "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9" ], "markers": "python_version >= '3.6'", - "version": "==2024.2.2" + "version": "==2024.8.30" }, "charset-normalizer": { "hashes": [ @@ -573,66 +650,94 @@ "markers": "python_version >= '3.7'", "version": "==8.1.7" }, + "colorama": { + "hashes": [ + "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", + "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'", + "version": "==0.4.6" + }, "coverage": { "extras": [ "toml" ], "hashes": [ - "sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523", - "sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f", - "sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d", - "sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb", - "sha256:1d2a830ade66d3563bb61d1e3c77c8def97b30ed91e166c67d0632c018f380f0", - "sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c", - "sha256:244f509f126dc71369393ce5fea17c0592c40ee44e607b6d855e9c4ac57aac98", - "sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83", - "sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8", - "sha256:2e079c9ec772fedbade9d7ebc36202a1d9ef7291bc9b3a024ca395c4d52853d7", - "sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac", - "sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84", - "sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb", - "sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3", - "sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884", - "sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614", - "sha256:3d5a67f0da401e105753d474369ab034c7bae51a4c31c77d94030d59e41df5bd", - "sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807", - "sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd", - "sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8", - "sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc", - "sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db", - "sha256:75e3f4e86804023e991096b29e147e635f5e2568f77883a1e6eed74512659ab0", - "sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08", - "sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232", - "sha256:8383a6c8cefba1b7cecc0149415046b6fc38836295bc4c84e820872eb5478b3d", - "sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a", - "sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1", - "sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286", - "sha256:990fb20b32990b2ce2c5f974c3e738c9358b2735bc05075d50a6f36721b8f303", - "sha256:9aad68c3f2566dfae84bf46295a79e79d904e1c21ccfc66de88cd446f8686341", - "sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84", - "sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45", - "sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc", - "sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec", - "sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd", - "sha256:b368e1aee1b9b75757942d44d7598dcd22a9dbb126affcbba82d15917f0cc155", - "sha256:bde997cac85fcac227b27d4fb2c7608a2c5f6558469b0eb704c5726ae49e1c52", - "sha256:c4c2872b3c91f9baa836147ca33650dc5c172e9273c808c3c3199c75490e709d", - "sha256:c59d2ad092dc0551d9f79d9d44d005c945ba95832a6798f98f9216ede3d5f485", - "sha256:d1da0a2e3b37b745a2b2a678a4c796462cf753aebf94edcc87dcc6b8641eae31", - "sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d", - "sha256:dd4b3355b01273a56b20c219e74e7549e14370b31a4ffe42706a8cda91f19f6d", - "sha256:e08c470c2eb01977d221fd87495b44867a56d4d594f43739a8028f8646a51e0d", - "sha256:f5102a92855d518b0996eb197772f5ac2a527c0ec617124ad5242a3af5e25f85", - "sha256:f542287b1489c7a860d43a7d8883e27ca62ab84ca53c965d11dac1d3a1fab7ce", - "sha256:f78300789a708ac1f17e134593f577407d52d0417305435b134805c4fb135adb", - "sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974", - "sha256:f836c174c3a7f639bded48ec913f348c4761cbf49de4a20a956d3431a7c9cb24", - "sha256:fa21a04112c59ad54f69d80e376f7f9d0f5f9123ab87ecd18fbb9ec3a2beed56", - "sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9", - "sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35" + "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca", + "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d", + "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6", + "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989", + "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c", + "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b", + "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223", + "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f", + "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56", + "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3", + "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8", + "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb", + "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388", + "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0", + "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a", + "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8", + "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f", + "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a", + "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962", + "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8", + "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391", + "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc", + "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2", + "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155", + "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb", + "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0", + "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c", + "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a", + "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004", + "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060", + "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232", + "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93", + "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129", + "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163", + "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de", + "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6", + "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23", + "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569", + "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d", + "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778", + "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d", + "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36", + "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a", + "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6", + "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34", + "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704", + "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106", + "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9", + "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862", + "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b", + "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255", + "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16", + "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3", + "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133", + "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb", + "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657", + "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d", + "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca", + "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36", + "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c", + "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e", + "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff", + "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7", + "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5", + "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02", + "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c", + "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df", + "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3", + "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a", + "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959", + "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234", + "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc" ], "markers": "python_version >= '3.8'", - "version": "==7.5.3" + "version": "==7.6.1" }, "coveralls": { "hashes": [ @@ -645,11 +750,11 @@ }, "dill": { "hashes": [ - "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca", - "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7" + "sha256:468dff3b89520b474c0397703366b7b95eebe6303f108adf9b19da1f702be87a", + "sha256:81aa267dddf68cbfe8029c42ca9ec6a4ab3b22371d1c450abc54422577b4512c" ], "markers": "python_version >= '3.11'", - "version": "==0.3.8" + "version": "==0.3.9" }, "docopt": { "hashes": [ @@ -657,14 +762,22 @@ ], "version": "==0.6.2" }, + "executing": { + "hashes": [ + "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf", + "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab" + ], + "markers": "python_version >= '3.8'", + "version": "==2.1.0" + }, "flake8": { "hashes": [ - "sha256:33f96621059e65eec474169085dc92bf26e7b2d47366b70be2f67ab80dc25132", - "sha256:a6dfbb75e03252917f2473ea9653f7cd799c3064e54d4c8140044c5c065f53c3" + "sha256:049d058491e228e03e67b390f311bbf88fce2dbaa8fa673e7aea87b7198b8d38", + "sha256:597477df7860daa5aa0fdd84bf5208a043ab96b8e96ab708770ae0364dd03213" ], "index": "pypi", "markers": "python_full_version >= '3.8.1'", - "version": "==7.0.0" + "version": "==7.1.1" }, "frozenlist": { "hashes": [ @@ -749,13 +862,21 @@ "markers": "python_version >= '3.8'", "version": "==1.4.1" }, + "icecream": { + "hashes": [ + "sha256:0aa4a7c3374ec36153a1d08f81e3080e83d8ac1eefd97d2f4fe9544e8f9b49de", + "sha256:757aec31ad4488b949bc4f499d18e6e5973c40cc4d4fc607229e78cfaec94c34" + ], + "index": "pypi", + "version": "==2.1.3" + }, "idna": { "hashes": [ - "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", - "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" + "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", + "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" ], - "markers": "python_version >= '3.5'", - "version": "==3.7" + "markers": "python_version >= '3.6'", + "version": "==3.10" }, "iniconfig": { "hashes": [ @@ -783,133 +904,135 @@ }, "multidict": { "hashes": [ - "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556", - "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c", - "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29", - "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b", - "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8", - "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7", - "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd", - "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40", - "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6", - "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3", - "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c", - "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9", - "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5", - "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae", - "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442", - "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9", - "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc", - "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c", - "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea", - "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5", - "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50", - "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182", - "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453", - "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e", - "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600", - "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733", - "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda", - "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241", - "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461", - "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e", - "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e", - "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b", - "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e", - "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7", - "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386", - "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd", - "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9", - "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf", - "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee", - "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5", - "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a", - "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271", - "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54", - "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4", - "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496", - "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb", - "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319", - "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3", - "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f", - "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527", - "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed", - "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604", - "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef", - "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8", - "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5", - "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5", - "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626", - "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c", - "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d", - "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c", - "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc", - "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc", - "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b", - "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38", - "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450", - "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1", - "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f", - "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3", - "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755", - "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226", - "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a", - "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046", - "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf", - "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479", - "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e", - "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1", - "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a", - "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83", - "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929", - "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93", - "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a", - "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c", - "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44", - "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89", - "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba", - "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e", - "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da", - "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24", - "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423", - "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef" + "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f", + "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056", + "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761", + "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3", + "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b", + "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6", + "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748", + "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966", + "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f", + "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1", + "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6", + "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada", + "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305", + "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2", + "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d", + "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a", + "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef", + "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c", + "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb", + "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60", + "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6", + "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4", + "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478", + "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81", + "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7", + "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56", + "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3", + "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6", + "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30", + "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb", + "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", + "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0", + "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925", + "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c", + "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6", + "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e", + "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95", + "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2", + "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133", + "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2", + "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa", + "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3", + "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3", + "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436", + "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657", + "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581", + "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492", + "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43", + "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2", + "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2", + "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926", + "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057", + "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc", + "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80", + "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255", + "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1", + "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972", + "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53", + "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1", + "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423", + "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a", + "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160", + "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c", + "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd", + "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa", + "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5", + "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b", + "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa", + "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef", + "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44", + "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4", + "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156", + "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753", + "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28", + "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d", + "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a", + "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304", + "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008", + "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429", + "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72", + "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399", + "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3", + "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392", + "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167", + "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c", + "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774", + "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351", + "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76", + "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875", + "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd", + "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28", + "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db" ], - "markers": "python_version >= '3.7'", - "version": "==6.0.5" + "markers": "python_version >= '3.8'", + "version": "==6.1.0" }, "mypy": { "hashes": [ - "sha256:075cbf81f3e134eadaf247de187bd604748171d6b79736fa9b6c9685b4083061", - "sha256:12b6bfc1b1a66095ab413160a6e520e1dc076a28f3e22f7fb25ba3b000b4ef99", - "sha256:1ec404a7cbe9fc0e92cb0e67f55ce0c025014e26d33e54d9e506a0f2d07fe5de", - "sha256:28d0e038361b45f099cc086d9dd99c15ff14d0188f44ac883010e172ce86c38a", - "sha256:2b0695d605ddcd3eb2f736cd8b4e388288c21e7de85001e9f85df9187f2b50f9", - "sha256:3236a4c8f535a0631f85f5fcdffba71c7feeef76a6002fcba7c1a8e57c8be1ec", - "sha256:3be66771aa5c97602f382230165b856c231d1277c511c9a8dd058be4784472e1", - "sha256:3d087fcbec056c4ee34974da493a826ce316947485cef3901f511848e687c131", - "sha256:3f298531bca95ff615b6e9f2fc0333aae27fa48052903a0ac90215021cdcfa4f", - "sha256:4a2b5cdbb5dd35aa08ea9114436e0d79aceb2f38e32c21684dcf8e24e1e92821", - "sha256:4cf18f9d0efa1b16478c4c129eabec36148032575391095f73cae2e722fcf9d5", - "sha256:8b2cbaca148d0754a54d44121b5825ae71868c7592a53b7292eeb0f3fdae95ee", - "sha256:8f55583b12156c399dce2df7d16f8a5095291354f1e839c252ec6c0611e86e2e", - "sha256:92f93b21c0fe73dc00abf91022234c79d793318b8a96faac147cd579c1671746", - "sha256:9e36fb078cce9904c7989b9693e41cb9711e0600139ce3970c6ef814b6ebc2b2", - "sha256:9fd50226364cd2737351c79807775136b0abe084433b55b2e29181a4c3c878c0", - "sha256:a781f6ad4bab20eef8b65174a57e5203f4be627b46291f4589879bf4e257b97b", - "sha256:a87dbfa85971e8d59c9cc1fcf534efe664d8949e4c0b6b44e8ca548e746a8d53", - "sha256:b808e12113505b97d9023b0b5e0c0705a90571c6feefc6f215c1df9381256e30", - "sha256:bc6ac273b23c6b82da3bb25f4136c4fd42665f17f2cd850771cb600bdd2ebeda", - "sha256:cd777b780312ddb135bceb9bc8722a73ec95e042f911cc279e2ec3c667076051", - "sha256:da1cbf08fb3b851ab3b9523a884c232774008267b1f83371ace57f412fe308c2", - "sha256:e22e1527dc3d4aa94311d246b59e47f6455b8729f4968765ac1eacf9a4760bc7", - "sha256:f8c083976eb530019175aabadb60921e73b4f45736760826aa1689dda8208aee", - "sha256:f90cff89eea89273727d8783fef5d4a934be2fdca11b47def50cf5d311aff727", - "sha256:fa7ef5244615a2523b56c034becde4e9e3f9b034854c93639adb667ec9ec2976", - "sha256:fcfc70599efde5c67862a07a1aaf50e55bce629ace26bb19dc17cece5dd31ca4" + "sha256:06d26c277962f3fb50e13044674aa10553981ae514288cb7d0a738f495550b36", + "sha256:2ff93107f01968ed834f4256bc1fc4475e2fecf6c661260066a985b52741ddce", + "sha256:36383a4fcbad95f2657642a07ba22ff797de26277158f1cc7bd234821468b1b6", + "sha256:37c7fa6121c1cdfcaac97ce3d3b5588e847aa79b580c1e922bb5d5d2902df19b", + "sha256:3a66169b92452f72117e2da3a576087025449018afc2d8e9bfe5ffab865709ca", + "sha256:3f14cd3d386ac4d05c5a39a51b84387403dadbd936e17cb35882134d4f8f0d24", + "sha256:41ea707d036a5307ac674ea172875f40c9d55c5394f888b168033177fce47383", + "sha256:478db5f5036817fe45adb7332d927daa62417159d49783041338921dcf646fc7", + "sha256:4a8a53bc3ffbd161b5b2a4fff2f0f1e23a33b0168f1c0778ec70e1a3d66deb86", + "sha256:539c570477a96a4e6fb718b8d5c3e0c0eba1f485df13f86d2970c91f0673148d", + "sha256:57555a7715c0a34421013144a33d280e73c08df70f3a18a552938587ce9274f4", + "sha256:6e658bd2d20565ea86da7d91331b0eed6d2eee22dc031579e6297f3e12c758c8", + "sha256:6e7184632d89d677973a14d00ae4d03214c8bc301ceefcdaf5c474866814c987", + "sha256:75746e06d5fa1e91bfd5432448d00d34593b52e7e91a187d981d08d1f33d4385", + "sha256:7f9993ad3e0ffdc95c2a14b66dee63729f021968bff8ad911867579c65d13a79", + "sha256:801780c56d1cdb896eacd5619a83e427ce436d86a3bdf9112527f24a66618fef", + "sha256:801ca29f43d5acce85f8e999b1e431fb479cb02d0e11deb7d2abb56bdaf24fd6", + "sha256:969ea3ef09617aff826885a22ece0ddef69d95852cdad2f60c8bb06bf1f71f70", + "sha256:a976775ab2256aadc6add633d44f100a2517d2388906ec4f13231fafbb0eccca", + "sha256:af8d155170fcf87a2afb55b35dc1a0ac21df4431e7d96717621962e4b9192e70", + "sha256:b499bc07dbdcd3de92b0a8b29fdf592c111276f6a12fe29c30f6c417dd546d12", + "sha256:cd953f221ac1379050a8a646585a29574488974f79d8082cedef62744f0a0104", + "sha256:d42a6dd818ffce7be66cce644f1dff482f1d97c53ca70908dff0b9ddc120b77a", + "sha256:e8960dbbbf36906c5c0b7f4fbf2f0c7ffb20f4898e6a879fcf56a41a08b0d318", + "sha256:edb91dded4df17eae4537668b23f0ff6baf3707683734b6a818d5b9d0c0c31a1", + "sha256:ee23de8530d99b6db0573c4ef4bd8f39a2a6f9b60655bf7a1357e585a3486f2b", + "sha256:f7821776e5c4286b6a13138cc935e2e9b6fde05e081bdebf5cdb2bb97c9df81d" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.10.0" + "version": "==1.11.2" }, "mypy-extensions": { "hashes": [ @@ -921,11 +1044,11 @@ }, "packaging": { "hashes": [ - "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", - "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9" + "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", + "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" ], - "markers": "python_version >= '3.7'", - "version": "==24.0" + "markers": "python_version >= '3.8'", + "version": "==24.1" }, "pathspec": { "hashes": [ @@ -937,11 +1060,11 @@ }, "platformdirs": { "hashes": [ - "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee", - "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3" + "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", + "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb" ], "markers": "python_version >= '3.8'", - "version": "==4.2.2" + "version": "==4.3.6" }, "pluggy": { "hashes": [ @@ -953,11 +1076,11 @@ }, "pycodestyle": { "hashes": [ - "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f", - "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67" + "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3", + "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521" ], "markers": "python_version >= '3.8'", - "version": "==2.11.1" + "version": "==2.12.1" }, "pyflakes": { "hashes": [ @@ -967,23 +1090,31 @@ "markers": "python_version >= '3.8'", "version": "==3.2.0" }, + "pygments": { + "hashes": [ + "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", + "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a" + ], + "markers": "python_version >= '3.8'", + "version": "==2.18.0" + }, "pylint": { "hashes": [ - "sha256:3f8788ab20bb8383e06dd2233e50f8e08949cfd9574804564803441a4946eab4", - "sha256:d068ca1dfd735fb92a07d33cb8f288adc0f6bc1287a139ca2425366f7cbe38f8" + "sha256:2f846a466dd023513240bc140ad2dd73bfc080a5d85a710afdb728c420a5a2b9", + "sha256:9f3dcc87b1203e612b78d91a896407787e708b3f189b5fa0b307712d49ff0c6e" ], "index": "pypi", - "markers": "python_full_version >= '3.8.0'", - "version": "==3.2.2" + "markers": "python_full_version >= '3.9.0'", + "version": "==3.3.1" }, "pytest": { "hashes": [ - "sha256:5046e5b46d8e4cac199c373041f26be56fdb81eb4e67dc11d4e10811fc3408fd", - "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1" + "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", + "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==8.2.1" + "version": "==8.3.3" }, "pytest-cov": { "hashes": [ @@ -1003,150 +1134,153 @@ "markers": "python_version >= '3.8'", "version": "==2.32.3" }, + "six": { + "hashes": [ + "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", + "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.16.0" + }, "tomlkit": { "hashes": [ - "sha256:af914f5a9c59ed9d0762c7b64d3b5d5df007448eb9cd2edc8a46b1eafead172f", - "sha256:eef34fba39834d4d6b73c9ba7f3e4d1c417a4e56f89a7e96e090dd0d24b8fb3c" + "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde", + "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79" ], - "markers": "python_version >= '3.7'", - "version": "==0.12.5" + "markers": "python_version >= '3.8'", + "version": "==0.13.2" }, "types-pyyaml": { "hashes": [ - "sha256:a9e0f0f88dc835739b0c1ca51ee90d04ca2a897a71af79de9aec5f38cb0a5342", - "sha256:b845b06a1c7e54b8e5b4c683043de0d9caf205e7434b3edc678ff2411979b8f6" + "sha256:392b267f1c0fe6022952462bf5d6523f31e37f6cea49b14cee7ad634b6301570", + "sha256:d1405a86f9576682234ef83bcb4e6fff7c9305c8b1fbad5e0bcd4f7dbdc9c587" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==6.0.12.20240311" + "version": "==6.0.12.20240917" }, "types-requests": { "hashes": [ - "sha256:26b8a6de32d9f561192b9942b41c0ab2d8010df5677ca8aa146289d11d505f57", - "sha256:f19ed0e2daa74302069bbbbf9e82902854ffa780bc790742a810a9aaa52f65ec" + "sha256:2850e178db3919d9bf809e434eef65ba49d0e7e33ac92d588f4a5e295fffd405", + "sha256:59c2f673eb55f32a99b2894faf6020e1a9f4a402ad0f192bfee0b64469054310" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==2.32.0.20240523" + "version": "==2.32.0.20240914" }, "typing-extensions": { "hashes": [ - "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8", - "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594" + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], - "markers": "python_version >= '3.8'", - "version": "==4.12.0" + "markers": "python_version < '3.13'", + "version": "==4.12.2" }, "urllib3": { "hashes": [ - "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", - "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19" + "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", + "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9" ], "markers": "python_version >= '3.8'", - "version": "==2.2.1" - }, - "var-dump": { - "hashes": [ - "sha256:9031944c174f8ce971b71a047fc56a81dfa1ce05d354fff3a16d781391d020ae" - ], - "index": "pypi", - "version": "==1.2" + "version": "==2.2.3" }, "yarl": { "hashes": [ - "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51", - "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce", - "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559", - "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0", - "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81", - "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc", - "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4", - "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c", - "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130", - "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136", - "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e", - "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec", - "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7", - "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1", - "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455", - "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099", - "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129", - "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10", - "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142", - "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98", - "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa", - "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7", - "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525", - "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c", - "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9", - "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c", - "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8", - "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b", - "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf", - "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23", - "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd", - "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27", - "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f", - "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece", - "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434", - "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec", - "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff", - "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78", - "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d", - "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863", - "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53", - "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31", - "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15", - "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5", - "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b", - "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57", - "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3", - "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1", - "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f", - "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad", - "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c", - "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7", - "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2", - "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b", - "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2", - "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b", - "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9", - "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be", - "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e", - "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984", - "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4", - "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074", - "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2", - "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392", - "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91", - "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541", - "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf", - "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572", - "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66", - "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575", - "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14", - "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5", - "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1", - "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e", - "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551", - "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17", - "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead", - "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0", - "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe", - "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234", - "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0", - "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7", - "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34", - "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42", - "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385", - "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78", - "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be", - "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958", - "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749", - "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec" + "sha256:08d7148ff11cb8e886d86dadbfd2e466a76d5dd38c7ea8ebd9b0e07946e76e4b", + "sha256:098b870c18f1341786f290b4d699504e18f1cd050ed179af8123fd8232513424", + "sha256:11b3ca8b42a024513adce810385fcabdd682772411d95bbbda3b9ed1a4257644", + "sha256:1891d69a6ba16e89473909665cd355d783a8a31bc84720902c5911dbb6373465", + "sha256:1bbb418f46c7f7355084833051701b2301092e4611d9e392360c3ba2e3e69f88", + "sha256:1d0828e17fa701b557c6eaed5edbd9098eb62d8838344486248489ff233998b8", + "sha256:1d8e3ca29f643dd121f264a7c89f329f0fcb2e4461833f02de6e39fef80f89da", + "sha256:1fa56f34b2236f5192cb5fceba7bbb09620e5337e0b6dfe2ea0ddbd19dd5b154", + "sha256:216a6785f296169ed52cd7dcdc2612f82c20f8c9634bf7446327f50398732a51", + "sha256:22b739f99c7e4787922903f27a892744189482125cc7b95b747f04dd5c83aa9f", + "sha256:2430cf996113abe5aee387d39ee19529327205cda975d2b82c0e7e96e5fdabdc", + "sha256:269c201bbc01d2cbba5b86997a1e0f73ba5e2f471cfa6e226bcaa7fd664b598d", + "sha256:298c1eecfd3257aa16c0cb0bdffb54411e3e831351cd69e6b0739be16b1bdaa8", + "sha256:2a93a4557f7fc74a38ca5a404abb443a242217b91cd0c4840b1ebedaad8919d4", + "sha256:2b2442a415a5f4c55ced0fade7b72123210d579f7d950e0b5527fc598866e62c", + "sha256:2db874dd1d22d4c2c657807562411ffdfabec38ce4c5ce48b4c654be552759dc", + "sha256:309c104ecf67626c033845b860d31594a41343766a46fa58c3309c538a1e22b2", + "sha256:31497aefd68036d8e31bfbacef915826ca2e741dbb97a8d6c7eac66deda3b606", + "sha256:373f16f38721c680316a6a00ae21cc178e3a8ef43c0227f88356a24c5193abd6", + "sha256:396e59b8de7e4d59ff5507fb4322d2329865b909f29a7ed7ca37e63ade7f835c", + "sha256:3bb83a0f12701c0b91112a11148b5217617982e1e466069d0555be9b372f2734", + "sha256:3de86547c820e4f4da4606d1c8ab5765dd633189791f15247706a2eeabc783ae", + "sha256:3fdbf0418489525231723cdb6c79e7738b3cbacbaed2b750cb033e4ea208f220", + "sha256:40c6e73c03a6befb85b72da213638b8aaa80fe4136ec8691560cf98b11b8ae6e", + "sha256:44a4c40a6f84e4d5955b63462a0e2a988f8982fba245cf885ce3be7618f6aa7d", + "sha256:44b07e1690f010c3c01d353b5790ec73b2f59b4eae5b0000593199766b3f7a5c", + "sha256:45d23c4668d4925688e2ea251b53f36a498e9ea860913ce43b52d9605d3d8177", + "sha256:45f209fb4bbfe8630e3d2e2052535ca5b53d4ce2d2026bed4d0637b0416830da", + "sha256:4afdf84610ca44dcffe8b6c22c68f309aff96be55f5ea2fa31c0c225d6b83e23", + "sha256:4feaaa4742517eaceafcbe74595ed335a494c84634d33961214b278126ec1485", + "sha256:576365c9f7469e1f6124d67b001639b77113cfd05e85ce0310f5f318fd02fe85", + "sha256:5820bd4178e6a639b3ef1db8b18500a82ceab6d8b89309e121a6859f56585b05", + "sha256:5989a38ba1281e43e4663931a53fbf356f78a0325251fd6af09dd03b1d676a09", + "sha256:5a9bacedbb99685a75ad033fd4de37129449e69808e50e08034034c0bf063f99", + "sha256:5b66c87da3c6da8f8e8b648878903ca54589038a0b1e08dde2c86d9cd92d4ac9", + "sha256:5c5e32fef09ce101fe14acd0f498232b5710effe13abac14cd95de9c274e689e", + "sha256:658e8449b84b92a4373f99305de042b6bd0d19bf2080c093881e0516557474a5", + "sha256:6a2acde25be0cf9be23a8f6cbd31734536a264723fca860af3ae5e89d771cd71", + "sha256:6a5185ad722ab4dd52d5fb1f30dcc73282eb1ed494906a92d1a228d3f89607b0", + "sha256:6b7f6e699304717fdc265a7e1922561b02a93ceffdaefdc877acaf9b9f3080b8", + "sha256:703b0f584fcf157ef87816a3c0ff868e8c9f3c370009a8b23b56255885528f10", + "sha256:7055bbade838d68af73aea13f8c86588e4bcc00c2235b4b6d6edb0dbd174e246", + "sha256:78f271722423b2d4851cf1f4fa1a1c4833a128d020062721ba35e1a87154a049", + "sha256:7addd26594e588503bdef03908fc207206adac5bd90b6d4bc3e3cf33a829f57d", + "sha256:81bad32c8f8b5897c909bf3468bf601f1b855d12f53b6af0271963ee67fff0d2", + "sha256:82e692fb325013a18a5b73a4fed5a1edaa7c58144dc67ad9ef3d604eccd451ad", + "sha256:84bbcdcf393139f0abc9f642bf03f00cac31010f3034faa03224a9ef0bb74323", + "sha256:86c438ce920e089c8c2388c7dcc8ab30dfe13c09b8af3d306bcabb46a053d6f7", + "sha256:8be8cdfe20787e6a5fcbd010f8066227e2bb9058331a4eccddec6c0db2bb85b2", + "sha256:8c723c91c94a3bc8033dd2696a0f53e5d5f8496186013167bddc3fb5d9df46a3", + "sha256:8ca53632007c69ddcdefe1e8cbc3920dd88825e618153795b57e6ebcc92e752a", + "sha256:8f722f30366474a99745533cc4015b1781ee54b08de73260b2bbe13316079851", + "sha256:942c80a832a79c3707cca46bd12ab8aa58fddb34b1626d42b05aa8f0bcefc206", + "sha256:94a993f976cdcb2dc1b855d8b89b792893220db8862d1a619efa7451817c836b", + "sha256:95c6737f28069153c399d875317f226bbdea939fd48a6349a3b03da6829fb550", + "sha256:9915300fe5a0aa663c01363db37e4ae8e7c15996ebe2c6cce995e7033ff6457f", + "sha256:9a18595e6a2ee0826bf7dfdee823b6ab55c9b70e8f80f8b77c37e694288f5de1", + "sha256:9c8854b9f80693d20cec797d8e48a848c2fb273eb6f2587b57763ccba3f3bd4b", + "sha256:9cec42a20eae8bebf81e9ce23fb0d0c729fc54cf00643eb251ce7c0215ad49fe", + "sha256:9d2e1626be8712333a9f71270366f4a132f476ffbe83b689dd6dc0d114796c74", + "sha256:9d74f3c335cfe9c21ea78988e67f18eb9822f5d31f88b41aec3a1ec5ecd32da5", + "sha256:9fb4134cc6e005b99fa29dbc86f1ea0a298440ab6b07c6b3ee09232a3b48f495", + "sha256:a0ae6637b173d0c40b9c1462e12a7a2000a71a3258fa88756a34c7d38926911c", + "sha256:a31d21089894942f7d9a8df166b495101b7258ff11ae0abec58e32daf8088813", + "sha256:a3442c31c11088e462d44a644a454d48110f0588de830921fd201060ff19612a", + "sha256:ab9524e45ee809a083338a749af3b53cc7efec458c3ad084361c1dbf7aaf82a2", + "sha256:b1481c048fe787f65e34cb06f7d6824376d5d99f1231eae4778bbe5c3831076d", + "sha256:b8c837ab90c455f3ea8e68bee143472ee87828bff19ba19776e16ff961425b57", + "sha256:bbf2c3f04ff50f16404ce70f822cdc59760e5e2d7965905f0e700270feb2bbfc", + "sha256:bbf9c2a589be7414ac4a534d54e4517d03f1cbb142c0041191b729c2fa23f320", + "sha256:bcd5bf4132e6a8d3eb54b8d56885f3d3a38ecd7ecae8426ecf7d9673b270de43", + "sha256:c14c16831b565707149c742d87a6203eb5597f4329278446d5c0ae7a1a43928e", + "sha256:c49f3e379177f4477f929097f7ed4b0622a586b0aa40c07ac8c0f8e40659a1ac", + "sha256:c92b89bffc660f1274779cb6fbb290ec1f90d6dfe14492523a0667f10170de26", + "sha256:cd66152561632ed4b2a9192e7f8e5a1d41e28f58120b4761622e0355f0fe034c", + "sha256:cf1ad338620249f8dd6d4b6a91a69d1f265387df3697ad5dc996305cf6c26fb2", + "sha256:d07b52c8c450f9366c34aa205754355e933922c79135125541daae6cbf31c799", + "sha256:d0d12fe78dcf60efa205e9a63f395b5d343e801cf31e5e1dda0d2c1fb618073d", + "sha256:d4ee1d240b84e2f213565f0ec08caef27a0e657d4c42859809155cf3a29d1735", + "sha256:d959fe96e5c2712c1876d69af0507d98f0b0e8d81bee14cfb3f6737470205419", + "sha256:dcaef817e13eafa547cdfdc5284fe77970b891f731266545aae08d6cce52161e", + "sha256:df4e82e68f43a07735ae70a2d84c0353e58e20add20ec0af611f32cd5ba43fb4", + "sha256:ec8cfe2295f3e5e44c51f57272afbd69414ae629ec7c6b27f5a410efc78b70a0", + "sha256:ec9dd328016d8d25702a24ee274932aebf6be9787ed1c28d021945d264235b3c", + "sha256:ef9b85fa1bc91c4db24407e7c4da93a5822a73dd4513d67b454ca7064e8dc6a3", + "sha256:f3bf60444269345d712838bb11cc4eadaf51ff1a364ae39ce87a5ca8ad3bb2c8", + "sha256:f452cc1436151387d3d50533523291d5f77c6bc7913c116eb985304abdbd9ec9", + "sha256:f7917697bcaa3bc3e83db91aa3a0e448bf5cde43c84b7fc1ae2427d2417c0224", + "sha256:f90575e9fe3aae2c1e686393a9689c724cd00045275407f71771ae5d690ccf38", + "sha256:fb382fd7b4377363cc9f13ba7c819c3c78ed97c36a82f16f3f92f108c787cbbf", + "sha256:fb9f59f3848edf186a76446eb8bcf4c900fe147cb756fbbd730ef43b2e67c6a7", + "sha256:fc2931ac9ce9c61c9968989ec831d3a5e6fcaaff9474e7cfa8de80b7aff5a093" ], - "markers": "python_version >= '3.7'", - "version": "==1.9.4" + "markers": "python_version >= '3.8'", + "version": "==1.13.1" } } } diff --git a/chk/console/main.py b/chk/console/main.py index c1e8e41a..54ca93a5 100644 --- a/chk/console/main.py +++ b/chk/console/main.py @@ -1,10 +1,8 @@ """Commands""" import typing -from os import environ import click -from dotenv import load_dotenv import chk.modules.fetch as fetch_executor import chk.modules.validate as validate_executor @@ -30,12 +28,10 @@ def combine_initial_variables(external_vars: str, **kwargs: typing.Any) -> dict: """Reads a json string and converts to dict, and combines with env and dotenv variables""" - load_dotenv() + return load_variables_as_dict(external_vars, **kwargs) - return load_variables_as_dict(external_vars, **kwargs) | {"_ENV": dict(environ)} - -def after_hook(resp: object) -> None: +def after_hook(resp: dict) -> None: """Saves custom data from commands to global context bus Args: diff --git a/chk/infrastructure/document.py b/chk/infrastructure/document.py index 672ee153..2f592564 100644 --- a/chk/infrastructure/document.py +++ b/chk/infrastructure/document.py @@ -1,9 +1,11 @@ """ Base document and utility """ + import dataclasses import cerberus +from pydantic import BaseModel, Field from chk.infrastructure.file_loader import FileContext @@ -18,11 +20,22 @@ class VersionedDocument: version: str = dataclasses.field(default_factory=str) +class VersionedDocumentV2(BaseModel): + """ + versioned document entity + """ + + context: tuple = Field(default_factory=tuple) + version: str = Field(default_factory=str) + + class VersionedDocumentSupport: """DocumentVersionSupport""" @staticmethod - def validate_with_schema(schema: dict, doc: VersionedDocument) -> bool: + def validate_with_schema( + schema: dict, doc: VersionedDocument | VersionedDocumentV2 + ) -> bool: """Validate a document with given schema Args: diff --git a/chk/infrastructure/file_loader.py b/chk/infrastructure/file_loader.py index e1189a58..7c7ccb38 100644 --- a/chk/infrastructure/file_loader.py +++ b/chk/infrastructure/file_loader.py @@ -1,11 +1,14 @@ """ File loader utility """ + +from __future__ import annotations + import hashlib -from typing import NamedTuple +import json from pathlib import Path +from typing import NamedTuple -import json import yaml from chk.infrastructure.typing_extras import JsonDecodingError @@ -81,7 +84,7 @@ class FileContext(NamedTuple): filepath_hash: str = "" @staticmethod - def from_file(file: str, **kwarg: dict) -> "FileContext": + def from_file(file: str, **kwarg: dict) -> FileContext: FileLoader.is_file_ok(file) absolute_path = str(Path(file).absolute()) fpath_hash = hashlib.sha256(absolute_path.encode("utf-8")).hexdigest() @@ -95,31 +98,48 @@ def from_file(file: str, **kwarg: dict) -> "FileContext": arguments=kwarg["arguments"] if "arguments" in kwarg else {}, ) + @property + def filepath_as_path(self) -> Path: + """Get filepath as Path""" -class PathFrom: - """Utility to expand to full path""" + return Path(self.filepath) - def __init__(self, base: Path): - self.base = base.absolute().parent + @property + def filepath_base_as_path(self) -> Path: + """Get filepath parent or base as Path""" - def absolute(self, target: str) -> str: - """Find absolute in comparison to base URL""" + return Path(self.filepath).absolute().parent - if target.startswith("./") or target.startswith("../"): - if self.base.exists(): - to_path = self.base - target_path_sp = target.split("/") - for part in target_path_sp: - if part == "..": - to_path = to_path.parent - else: - to_path = Path(str(to_path) + "/" + part) +def generate_abs_path(base_: str, target_: str) -> str: + """Generate absolute path in comparison to base path + Args: + base_: str, base path to calculate from + target_: str, file path that need absolute path - return str(to_path) - raise ValueError("Invalid base path.") + Returns: + Absolute path for given filepath + """ + + base = Path(base_) + base_abs = base.absolute().parent if base.is_file() else base.absolute() + + if not base_abs.exists(): + raise ValueError("Invalid base path.") + if not (target_.startswith("./") or target_.startswith("../")): raise ValueError("Invalid target path.") + to_path = base_abs + target_path_sp = target_.split("/") + + for part in target_path_sp: + if part == "..": + to_path = to_path.parent + else: + to_path = to_path / part + + return str(to_path) + class ExecuteContext(NamedTuple): """Information storage for execution context""" diff --git a/chk/infrastructure/helper.py b/chk/infrastructure/helper.py index d2cfd6ec..d2475ad8 100644 --- a/chk/infrastructure/helper.py +++ b/chk/infrastructure/helper.py @@ -1,7 +1,9 @@ """ Helper functions module """ + import ast +import re from collections.abc import Callable from typing import Any @@ -157,6 +159,16 @@ def to_auto(var: str) -> Any: return var + @staticmethod + def try_dict(to_dict: Any, say_exception: bool = False) -> dict | Any: + try: + return dict(to_dict) + except ValueError as ex: + if say_exception: + raise ex + else: + return to_dict + def formatter(message: object, cb: Callable = str, dump: bool = True) -> str: """Format message with given callback @@ -175,3 +187,16 @@ def formatter(message: object, cb: Callable = str, dump: bool = True) -> str: click.echo(printable) return printable + + +def slugify(string: str) -> str: + """Make slug out of string""" + + if not isinstance(string, str): + raise TypeError("slugify: only string value supported.") + + string = string.lower().strip() + string = re.sub(r"[^\w\s-]", "", string) + string = re.sub(r"[\s_-]+", "-", string) + string = re.sub(r"-{2,}", "", string) + return string diff --git a/chk/infrastructure/symbol_table.py b/chk/infrastructure/symbol_table.py index 40bd999a..f1054dfe 100644 --- a/chk/infrastructure/symbol_table.py +++ b/chk/infrastructure/symbol_table.py @@ -1,12 +1,19 @@ """ Symbol and variable management """ + +import copy import enum +import os +import typing from collections import UserDict from collections.abc import Callable -from chk.infrastructure.document import VersionedDocument -from chk.infrastructure.file_loader import FileContext, ExecuteContext +from dotenv import load_dotenv +from pydantic import BaseModel, ConfigDict, Field + +from chk.infrastructure.document import VersionedDocument, VersionedDocumentV2 +from chk.infrastructure.file_loader import ExecuteContext, FileContext from chk.infrastructure.helper import data_get from chk.infrastructure.templating import StrTemplate @@ -55,8 +62,27 @@ class Variables(UserDict): """Holds data for a variable""" -class ExposableVariables(UserDict): - """Holds data for a expose data""" +class ExecResponse(BaseModel): + """ExecResponse""" + + model_config = ConfigDict(arbitrary_types_allowed=True) + + file_ctx: FileContext + exec_ctx: ExecuteContext + variables: Variables + variables_exec: Variables + extra: object = Field(default=None) + exception: Exception | None = Field(default=None) + exposed: list | dict = Field(default_factory=list) + report: dict = Field(default_factory=dict) + + +@typing.overload +def replace_value(doc: dict, var_s: dict) -> dict: ... + + +@typing.overload +def replace_value(doc: list, var_s: dict) -> list: ... def replace_value(doc: dict | list, var_s: dict) -> dict | list: @@ -79,9 +105,12 @@ def replace_value(doc: dict | list, var_s: dict) -> dict | list: class VariableTableManager: """VariableTableManager""" - @staticmethod + @classmethod def handle( - variable_doc: Variables, document: VersionedDocument, exec_ctx: ExecuteContext + cls, + variable_doc: Variables, + document: VersionedDocument | VersionedDocumentV2, + exec_ctx: ExecuteContext, ) -> None: """Handles variable handling @@ -90,20 +119,22 @@ def handle( document: VersionedDocument of document data exec_ctx: ExecuteContext; passed ExecuteContext """ + # load environment variables + cls.handle_environment(variable_doc) - # make file contexts out od tuple + # make file contexts out of tuple file_ctx = FileContext(*document.context) if variables := data_get(file_ctx.document, VariableConfigNode.VARIABLES): - VariableTableManager.handle_absolute(variable_doc, variables) + cls.handle_absolute(variable_doc, variables) - VariableTableManager.handle_execute_context(variable_doc, exec_ctx) + cls.handle_execute_context(variable_doc, exec_ctx) if variables: - VariableTableManager.handle_composite(variable_doc, variables) + cls.handle_composite(variable_doc, variables) - @staticmethod - def handle_absolute(variable_doc: Variables, document: dict) -> None: + @classmethod + def handle_absolute(cls, variable_doc: Variables, document: dict) -> None: """Handles absolute variables and values from document Args: @@ -117,8 +148,9 @@ def handle_absolute(variable_doc: Variables, document: dict) -> None: variable_doc[key] = val - @staticmethod + @classmethod def handle_composite( + cls, variable_doc: Variables, document: dict, replace_callback: Callable = replace_value, @@ -143,9 +175,9 @@ def handle_composite( for key, val in replaced_values.items(): variable_doc[key] = val - @staticmethod + @classmethod def handle_execute_context( - variable_doc: Variables, exec_ctx: ExecuteContext + cls, variable_doc: Variables, exec_ctx: ExecuteContext ) -> None: """Handle variables passed from external context @@ -159,6 +191,16 @@ def handle_execute_context( for key, val in ext_vars.items(): variable_doc[key] = val + @classmethod + def handle_environment(cls, variable_doc: Variables) -> None: + """Handle variables passed from external context + + Args: + variable_doc: Variables; Variable store + """ + load_dotenv() + variable_doc["_ENV"] = dict(os.environ) + class ExposeManager: """ExposeManager handles all expose related functionality""" @@ -196,7 +238,9 @@ def replace_values( return replace_callback(expose_doc, values) @staticmethod - def get_exposed_replaced_data(document: VersionedDocument, store: dict) -> list: + def get_exposed_replaced_data( + document: VersionedDocument | VersionedDocumentV2, store: dict + ) -> list: """Get expose doc from a `VersionedDocument`, and prepare it from the value of `Variables`, and `store`, and return @@ -214,3 +258,34 @@ def get_exposed_replaced_data(document: VersionedDocument, store: dict) -> list: return ExposeManager.replace_values(expose_doc, store) return [] + + @staticmethod + def get_exposed_replaced_data_v2( + document: VersionedDocumentV2, store: dict + ) -> dict: + """ + Get expose doc from a `VersionedDocument`, and prepare it from the + value of `Variables`, and `store`, and return + + Args: + document: VersionedDocument to get expose definition from it + store: dict to use as value store + + Returns: + dict: list of expose data + """ + + file_ctx = FileContext(*document.context) + + if expose_doc := ExposeManager.get_expose_doc(file_ctx.document): + + exposed_doc_t = copy.copy(expose_doc) + exposed_doc_t = [ + str(key).replace("%>", "").replace("<%", "").strip() + for key in exposed_doc_t + ] + + expose_val = ExposeManager.replace_values(expose_doc, store) + return dict(zip(exposed_doc_t, expose_val)) + + return {} diff --git a/chk/infrastructure/third_party/http_fetcher.py b/chk/infrastructure/third_party/http_fetcher.py index 629d15f5..7763ec8b 100644 --- a/chk/infrastructure/third_party/http_fetcher.py +++ b/chk/infrastructure/third_party/http_fetcher.py @@ -1,7 +1,7 @@ """ Driver to handle requests library (https://pypi.org/project/requests/) """ - +from __future__ import annotations from collections import UserDict import requests @@ -37,7 +37,7 @@ def as_fmt_str(self) -> str: return presentation @staticmethod - def from_response(response: requests.Response) -> "ApiResponse": + def from_response(response: requests.Response) -> ApiResponse: """Create a ApiResponse object from requests.Response object Args: diff --git a/chk/infrastructure/version.py b/chk/infrastructure/version.py index 449ad70f..c8d52f03 100644 --- a/chk/infrastructure/version.py +++ b/chk/infrastructure/version.py @@ -14,12 +14,18 @@ VERSION_STORE = { "http": [ "0.7.2", + "0.8.0", ], "testcase": [ "0.7.2", + "0.8.0", ], "validation": [ "0.7.2", + "0.8.0", + ], + "workflow": [ + "0.8.0", ], } @@ -108,6 +114,11 @@ def verify_doc_type_ver(self) -> bool: return True + def __str__(self) -> str: + """str dunder""" + + return self.original_version_str + class DocumentVersionMaker: """Create document version object""" diff --git a/chk/infrastructure/view.py b/chk/infrastructure/view.py new file mode 100644 index 00000000..fd181949 --- /dev/null +++ b/chk/infrastructure/view.py @@ -0,0 +1,24 @@ +"""View related utility mod""" + +import abc +import typing + +from pydantic import BaseModel + + +class PresentationBuilder(BaseModel, abc.ABC): + """Presentable signature""" + + data: typing.Any + + @abc.abstractmethod + def dump_fmt(self) -> str: + """Signature to dump formatted string""" + + raise NotImplementedError("Signature to dump formatted string") + + @abc.abstractmethod + def dump_json(self) -> str: + """Signature to dump json""" + + raise NotImplementedError("Signature to dump json") diff --git a/chk/modules/fetch.py b/chk/modules/fetch.py index a5717c6f..52619e0b 100644 --- a/chk/modules/fetch.py +++ b/chk/modules/fetch.py @@ -1,36 +1,39 @@ """ Fetch module """ -import dataclasses + +from __future__ import annotations + import enum import json import pathlib - from collections import UserDict, abc from urllib.parse import unquote, urlparse -from requests.auth import HTTPBasicAuth - -from defusedxml.minidom import parseString import xmltodict +from defusedxml.minidom import parseString +from pydantic import BaseModel, Field +from requests.auth import HTTPBasicAuth -from chk.infrastructure.document import VersionedDocument, VersionedDocumentSupport +from chk.infrastructure.document import ( + VersionedDocumentSupport, + VersionedDocumentV2, +) from chk.infrastructure.file_loader import ExecuteContext, FileContext from chk.infrastructure.helper import data_get, formatter from chk.infrastructure.symbol_table import ( + EXPOSE_SCHEMA as EXP_SCHEMA, + ExecResponse, + ExposeManager, + VARIABLE_SCHEMA as VAR_SCHEMA, VariableTableManager, Variables, replace_value, - VARIABLE_SCHEMA as VAR_SCHEMA, - EXPOSE_SCHEMA as EXP_SCHEMA, - ExposeManager, - ExposableVariables, ) - from chk.infrastructure.third_party.http_fetcher import ( ApiResponse, - fetch, BearerAuthentication, + fetch, ) from chk.infrastructure.version import DocumentVersionMaker, SCHEMA as VER_SCHEMA @@ -201,6 +204,16 @@ def allowed_url(value: str) -> bool: return True +class FetchTask(BaseModel): + """Parsed FetchTask""" + + name: str + uses: str + file: str + variables: dict = Field(default_factory=dict) + arguments: dict = Field(default_factory=dict) + + class HttpRequestArgCompiler: """HttpRequestArgCompiler""" @@ -308,16 +321,15 @@ def add_generic_args(request_data: dict, request_arg: dict) -> None: HttpRequestArgCompiler.add_body(request_data, request_arg) -@dataclasses.dataclass(slots=True) -class HttpDocument(VersionedDocument): +class HttpDocument(VersionedDocumentV2, BaseModel): """ Http document entity """ - request: dict = dataclasses.field(default_factory=dict) + request: dict = Field(default_factory=dict) @staticmethod - def from_file_context(ctx: FileContext) -> "HttpDocument": + def from_file_context(ctx: FileContext) -> HttpDocument: """Create a HttpDocument from FileContext :param ctx: FileContext to create the HttpDocument from """ @@ -328,18 +340,14 @@ def from_file_context(ctx: FileContext) -> "HttpDocument": if not (request_dct := data_get(ctx.document, "request")): raise RuntimeError("`request:` not found.") + # @TODO keep `context`, `version` as object + # @TODO implement __repr__ for WorkflowDocument return HttpDocument( context=tuple(ctx), version=version_str, request=request_dct, ) - @property - def as_dict(self) -> dict: - """Return a dict of the data""" - - return dataclasses.asdict(self) - class ApiResponseDict(UserDict): """Represents a API response with body in dict representation""" @@ -348,7 +356,7 @@ class ApiResponseDict(UserDict): body_as_dict: dict @staticmethod - def from_api_response(resp: ApiResponse) -> "ApiResponseDict": + def from_api_response(resp: ApiResponse) -> ApiResponseDict: """Create JsonApiResponse from ApiResponse Args: @@ -484,14 +492,16 @@ def display(expose_list: list, exec_ctx: ExecuteContext) -> None: if exec_ctx.options["format"]: formatter( - "\n---\n".join( - [ - item if isinstance(item, str) else str(item) - for item in display_item_list - ] - ) - if len(display_item_list) > 1 - else display_item_list.pop(), + ( + "\n---\n".join( + [ + item if isinstance(item, str) else str(item) + for item in display_item_list + ] + ) + if len(display_item_list) > 1 + else display_item_list.pop() + ), dump=exec_ctx.options["dump"], ) else: @@ -508,21 +518,15 @@ def display(expose_list: list, exec_ctx: ExecuteContext) -> None: formatter(_to_display, dump=exec_ctx.options["dump"]) -def execute( - ctx: FileContext, exec_ctx: ExecuteContext, cb: abc.Callable = lambda *args: ... -) -> None: - """Run a http document +def call(file_ctx: FileContext, exec_ctx: ExecuteContext) -> ExecResponse: + """Call a http document""" - Args: - ctx: FileContext object to handle - exec_ctx: ExecuteContext - cb: Callable - """ + r_exception: Exception | None = None - http_doc = HttpDocument.from_file_context(ctx) + http_doc = HttpDocument.from_file_context(file_ctx) DocumentVersionMaker.verify_if_allowed( - DocumentVersionMaker.from_dict(http_doc.as_dict), VERSION_SCOPE + DocumentVersionMaker.from_dict(http_doc.model_dump()), VERSION_SCOPE ) VersionedDocumentSupport.validate_with_schema( @@ -533,12 +537,70 @@ def execute( VariableTableManager.handle(variable_doc, http_doc, exec_ctx) HttpDocumentSupport.process_request_template(http_doc, variable_doc) - response = HttpDocumentSupport.execute_request(http_doc) - output_data = ExposableVariables({"_response": response.data}) + response = ApiResponse() + + try: + response = HttpDocumentSupport.execute_request(http_doc) + except Exception as ex: + r_exception = ex + + output_data = Variables({"_response": response.data}) - exposed_data = ExposeManager.get_exposed_replaced_data( - http_doc, {**variable_doc.data, **output_data.data} + exposed_data = ExposeManager.get_exposed_replaced_data_v2( + http_doc, + {**variable_doc.data, **output_data.data}, ) - cb({ctx.filepath_hash: output_data.data}) - HttpDocumentSupport.display(exposed_data, exec_ctx) + # TODO: instead if sending specific report items, and making presentable in other + # module, we should prepare and long and short form of presentable that can be + # loaded via other module + + return ExecResponse( + file_ctx=file_ctx, + exec_ctx=exec_ctx, + variables_exec=output_data, + variables=variable_doc, + exception=r_exception, + exposed=exposed_data, + report={ + "is_success": r_exception is None, + "request_method": file_ctx.document["request"]["method"], + "request_url": file_ctx.document["request"]["url"], + }, + ) + + +def execute( + ctx: FileContext, exec_ctx: ExecuteContext, cb: abc.Callable = lambda *args: ... +) -> None: + """Call with a http document + + Args: + ctx: FileContext object to handle + exec_ctx: ExecuteContext + cb: Callable + """ + + exr = call(file_ctx=ctx, exec_ctx=exec_ctx) + if exr.exception is not None: + raise exr.exception + + cb({ctx.filepath_hash: exr.variables_exec.data}) + HttpDocumentSupport.display(exr.exposed, exec_ctx) + + +def task_fetch(**kwargs: dict) -> ExecResponse: + """Task impl""" + + if not (doc := kwargs.get("task", {})): + raise ValueError("Wrong task format given.") + + _task = FetchTask(**doc) + + return call( + FileContext.from_file(_task.file), + ExecuteContext( + options={"dump": True, "format": True}, + arguments=_task.arguments | {"variables": _task.variables}, + ), + ) diff --git a/chk/modules/validate/__init__.py b/chk/modules/validate/__init__.py index d63206ed..28394365 100644 --- a/chk/modules/validate/__init__.py +++ b/chk/modules/validate/__init__.py @@ -2,37 +2,41 @@ Validate module """ -import dataclasses +from __future__ import annotations + import enum import json -import operator from collections import abc import cerberus +from pydantic import BaseModel, Field -from chk.infrastructure.document import VersionedDocument, VersionedDocumentSupport -from chk.infrastructure.file_loader import FileContext, ExecuteContext +from chk.infrastructure.document import ( + VersionedDocumentSupport, + VersionedDocumentV2, +) +from chk.infrastructure.file_loader import ExecuteContext, FileContext from chk.infrastructure.helper import data_get, formatter -from chk.infrastructure.version import DocumentVersionMaker, SCHEMA as VER_SCHEMA - from chk.infrastructure.symbol_table import ( - VARIABLE_SCHEMA as VAR_SCHEMA, EXPOSE_SCHEMA as EXP_SCHEMA, - Variables, + ExecResponse, + ExposeManager, + VARIABLE_SCHEMA as VAR_SCHEMA, VariableTableManager, + Variables, replace_value, - ExposeManager, - ExposableVariables, ) +from chk.infrastructure.version import DocumentVersionMaker, SCHEMA as VER_SCHEMA from chk.modules.validate.assertion_services import ( + AllTestRunResult, AssertionEntry, AssertionEntryListRunner, - AllTestRunResult, MAP_TYPE_TO_FN, + ValidationTask, ) from chk.modules.validate.assertion_validation import ( - get_schema_map, AssertionEntityProperty, + get_schema_map, ) VERSION_SCOPE = ["validation"] @@ -65,17 +69,16 @@ class ValidationConfigNode(enum.StrEnum): } -@dataclasses.dataclass(slots=True) -class ValidationDocument(VersionedDocument): +class ValidationDocument(VersionedDocumentV2, BaseModel): """ Http document entity """ - data: dict = dataclasses.field(default_factory=dict) - asserts: list = dataclasses.field(default_factory=list) + data: dict = Field(default_factory=dict) + asserts: list = Field(default_factory=list) @staticmethod - def from_file_context(ctx: FileContext) -> "ValidationDocument": + def from_file_context(ctx: FileContext) -> ValidationDocument: """Create a ValidationDocument from FileContext :param ctx: FileContext to create the ValidationDocument from """ @@ -88,6 +91,8 @@ def from_file_context(ctx: FileContext) -> "ValidationDocument": _data = data_get(ctx.document, ValidationConfigNode.DATA, {}) + # @TODO keep `context`, `version` as object + # @TODO implement __repr__ for WorkflowDocument return ValidationDocument( context=tuple(ctx), version=_version, @@ -95,12 +100,6 @@ def from_file_context(ctx: FileContext) -> "ValidationDocument": data=_data, ) - @property - def as_dict(self) -> dict: - """Return a dict of the data""" - - return dataclasses.asdict(self) - class ValidationDocumentSupport: """Service class for ValidationDocument""" @@ -130,19 +129,23 @@ def set_data_template( """sets data or template""" data = data_get(exec_ctx.arguments, "data", {}) - variables[ValidationConfigNode.VAR_NODE] = data if data else validate_doc.data + variables[ValidationConfigNode.VAR_NODE.value] = ( + data if data else validate_doc.data + ) @staticmethod def process_data_template(variables: Variables) -> None: """process data or template before assertion""" - data = variables[ValidationConfigNode.VAR_NODE] + data = variables[ValidationConfigNode.VAR_NODE.value] tmp_variables = { key: val for key, val in variables.data.items() - if key != ValidationConfigNode.VAR_NODE + if key != ValidationConfigNode.VAR_NODE.value } - variables[ValidationConfigNode.VAR_NODE] = replace_value(data, tmp_variables) + variables[ValidationConfigNode.VAR_NODE.value] = replace_value( + data, tmp_variables + ) @staticmethod def make_assertion_entry_list(assert_lst: list[dict]) -> list[AssertionEntry]: @@ -221,35 +224,31 @@ def display(expose_list: list, exec_ctx: ExecuteContext) -> None: if exec_ctx.options["format"]: formatter( - "\n---\n".join([str(item) for item in display_item_list]) - if len(display_item_list) > 1 - else display_item_list.pop(), + ( + "\n---\n".join([str(item) for item in display_item_list]) + if len(display_item_list) > 1 + else display_item_list.pop() + ), dump=exec_ctx.options["dump"], ) else: formatter( - json.dumps(display_item_list) - if len(display_item_list) > 1 - else json.dumps(display_item_list.pop()), + ( + json.dumps(display_item_list) + if len(display_item_list) > 1 + else json.dumps(display_item_list.pop()) + ), dump=exec_ctx.options["dump"], ) -def execute( - ctx: FileContext, exec_ctx: ExecuteContext, cb: abc.Callable = lambda *args: ... -) -> None: - """Run a validation document - - Args: - ctx: FileContext object to handle - exec_ctx: ExecuteContext - cb: Callable - """ +def call(file_ctx: FileContext, exec_ctx: ExecuteContext) -> ExecResponse: + """Call a validation document""" - validate_doc = ValidationDocument.from_file_context(ctx) + validate_doc = ValidationDocument.from_file_context(file_ctx) DocumentVersionMaker.verify_if_allowed( - DocumentVersionMaker.from_dict(validate_doc.as_dict), VERSION_SCOPE + DocumentVersionMaker.from_dict(validate_doc.model_dump()), VERSION_SCOPE ) VersionedDocumentSupport.validate_with_schema( @@ -268,20 +267,65 @@ def execute( ) test_run_result = AssertionEntryListRunner.test_run(assert_list, variable_doc.data) + output_data = Variables( + { + "_asserts_response": test_run_result.as_dict, + "_data": variable_doc["_data"], + } + ) - exposed_data = ExposeManager.get_exposed_replaced_data( + exposed_data = ExposeManager.get_exposed_replaced_data_v2( validate_doc, - {**variable_doc.data, **{"_asserts_response": test_run_result}}, + { + **variable_doc.data, + **{"_asserts_response": test_run_result.as_dict}, + }, ) - ValidationDocumentSupport.display(exposed_data, exec_ctx) - cb( - { - ctx.filepath_hash: ExposableVariables( - { - "_asserts_response": test_run_result.as_dict, - "_data": variable_doc["_data"], - } - ).data - } + return ExecResponse( + file_ctx=file_ctx, + exec_ctx=exec_ctx, + variables_exec=output_data, + variables=variable_doc, + extra=test_run_result, + exposed=exposed_data, + report={ + "is_success": test_run_result["count_fail"] == 0, + "count_all": test_run_result["count_all"], + "count_fail": test_run_result["count_fail"], + }, + ) + + +def execute( + ctx: FileContext, exec_ctx: ExecuteContext, cb: abc.Callable = lambda *args: ... +) -> None: + """Run a validation document + + Args: + ctx: FileContext object to handle + exec_ctx: ExecuteContext + cb: Callable + """ + + exec_response = call(file_ctx=ctx, exec_ctx=exec_ctx) + + cb({ctx.filepath_hash: exec_response.variables_exec.data}) + ValidationDocumentSupport.display(exec_response.exposed, exec_ctx) + + +def task_validation(**kwargs: dict) -> ExecResponse: + """Task impl""" + + if not (doc := kwargs.get("task", {})): + raise ValueError("Wrong task format given.") + + _task = ValidationTask(**doc) + + return call( + FileContext.from_file(_task.file), + ExecuteContext( + options={"dump": True, "format": True}, + arguments=_task.arguments | {"variables": _task.variables}, + ), ) diff --git a/chk/modules/validate/assertion_services.py b/chk/modules/validate/assertion_services.py index 89e4ce2f..90e5a732 100644 --- a/chk/modules/validate/assertion_services.py +++ b/chk/modules/validate/assertion_services.py @@ -9,6 +9,8 @@ from collections.abc import Callable from datetime import datetime +from pydantic import BaseModel, Field + import chk.modules.validate.assertion_function as asrt_f from chk.infrastructure.helper import Cast from chk.infrastructure.templating import StrTemplate @@ -63,7 +65,9 @@ @dataclasses.dataclass class AssertionEntry: - """AssertionEntry holds one assertion operation""" + """AssertionEntry holds one assertion operation + TODO: implement __iter__ for this class + """ assert_type: str actual: typing.Any @@ -121,6 +125,7 @@ def as_fmt_str(self) -> str: class AllTestRunResult(UserDict): """Result of a test run + TODO: implement __iter__ for this class keys: id, time_start, time_end, count_all, results, count_fail """ @@ -327,3 +332,13 @@ def test_run( test_run_result["results"] = results return test_run_result + + +class ValidationTask(BaseModel): + """Parsed FetchTask""" + + name: str + uses: str + file: str + variables: dict = Field(default_factory=dict) + arguments: dict = Field(default_factory=dict) \ No newline at end of file diff --git a/chk/modules/workflow/__init__.py b/chk/modules/workflow/__init__.py index 9f09a92e..464747f4 100644 --- a/chk/modules/workflow/__init__.py +++ b/chk/modules/workflow/__init__.py @@ -1,3 +1,231 @@ """ Workflow module """ + +from __future__ import annotations + +import json +import pathlib +from collections import abc +from collections.abc import Callable + +from pydantic import BaseModel, ConfigDict, Field + +from chk.console.main import combine_initial_variables +from chk.infrastructure.document import ( + VersionedDocumentV2, +) +from chk.infrastructure.file_loader import ExecuteContext, FileContext +from chk.infrastructure.helper import data_get, formatter, slugify +from chk.infrastructure.symbol_table import ( + ExecResponse, + ExposeManager, + VariableTableManager, + Variables, + replace_value, +) +from chk.infrastructure.version import DocumentVersionMaker +from chk.infrastructure.view import PresentationBuilder +from chk.modules.fetch import task_fetch +from chk.modules.validate import task_validation +from chk.modules.workflow.entities import ( + ChkwareTask, + ChkwareValidateTask, + StepResult, + TaskExecParam, + WorkflowConfigNode, + WorkflowUses, +) +from chk.modules.workflow.services import ChkwareTaskSupport, WorkflowPresenter + +VERSION_SCOPE = ["workflow"] + + +class WorkflowDocument(VersionedDocumentV2, BaseModel): + """WorkflowDocument""" + + model_config = ConfigDict(extra="forbid") + + name: str = Field(default_factory=str) + id: str = Field(default_factory=str) + tasks: list[dict] = Field(default="") + + @staticmethod + def from_file_context(ctx: FileContext) -> WorkflowDocument: + """Create a WorkflowDocument from FileContext""" + + # version + doc_ver = DocumentVersionMaker.from_dict(ctx.document) + DocumentVersionMaker.verify_if_allowed(doc_ver, VERSION_SCOPE) + + # id, name + # @TODO Name and ID processing should have separate func + if name_str := data_get(ctx.document, "name"): + name_str = str(name_str).strip() + + if id_str := data_get(ctx.document, "id"): + id_str = slugify(str(id_str).strip()) + else: + id_str = ( + slugify(name_str) + if name_str and len(name_str) > 0 + else pathlib.Path(ctx.filepath).stem + ) + + if not name_str: + name_str = id_str + + # tasks + if not (tasks_lst := data_get(ctx.document, "tasks")): + raise RuntimeError("`tasks:` not found.") + + if not isinstance(tasks_lst, list): + raise RuntimeError("`tasks:` is not list.") + + # @TODO keep `context`, `version` as object + # @TODO implement __repr__ for WorkflowDocument + return WorkflowDocument( + context=tuple(ctx), + version=str(doc_ver), + name=name_str, + id=id_str, + tasks=tasks_lst, + ) + + +class WorkflowDocumentSupport: + """Workflow document support""" + + @classmethod + def _prepare_validate_task_argument_data_(cls, task: ChkwareTask) -> dict: + """Prepare data for ChkwareValidateTask.arguments.data""" + + if isinstance(task, ChkwareValidateTask) and task.arguments: + return task.arguments.data + + return {} + + @classmethod + def set_step_template(cls, variables: Variables) -> None: + """sets data or template""" + + # @TODO implement data set functionality with validation for variables + variables[WorkflowConfigNode.NODE.value] = [] + + @classmethod + def process_task_template( + cls, document: WorkflowDocument, variables: Variables + ) -> list: + """Process task block of document""" + + base_fpath: str = FileContext(*document.context).filepath + exec_report: list[StepResult] = [] + + for task in document.tasks: + if not isinstance(task, dict): + raise RuntimeError("`tasks.*.item` should be map.") + + # replace values in tasks + task_d_: dict = replace_value(task, variables.data) + task_o_ = ChkwareTaskSupport.make_task( + task_d_, **dict(base_file_path=base_fpath) + ) + + execution_ctx = ExecuteContext( + {"dump": True, "format": True}, + {"variables": combine_initial_variables(json.dumps(task_o_.variables))}, + ) + + task_fn = None + + match task_o_.uses: + case WorkflowUses.fetch.value: + task_fn = task_fetch + case WorkflowUses.validate.value: + task_fn = task_validation + + if task_fn: + te_param = TaskExecParam(task=task_o_, exec_ctx=execution_ctx) + task_resp: ExecResponse = cls.execute_task(task_fn, te_param, variables) + + exec_report.append( + StepResult( + task=task_o_, + is_success=task_resp.report.pop("is_success"), + others=task_resp.report, + exposed=task_resp.exposed, + ) + ) + + return exec_report + + @classmethod + def execute_task( + cls, task_fn: Callable, task_params: TaskExecParam, variables: Variables + ) -> ExecResponse: + """execute_task""" + + _task_res: ExecResponse = task_fn(**task_params.as_dict()) + variables[WorkflowConfigNode.NODE.value].append(_task_res.exposed) + + return _task_res + + @classmethod + def display( + cls, + ex_resp: ExecResponse, + exec_ctx: ExecuteContext, + presenter: type[PresentationBuilder], + ) -> None: + wfp = presenter(data=ex_resp) + if exec_ctx.options["format"]: + formatter(wfp.dump_fmt(), dump=exec_ctx.options["dump"]) + else: + formatter(wfp.dump_json(), dump=exec_ctx.options["dump"]) + + +def call(file_ctx: FileContext, exec_ctx: ExecuteContext) -> ExecResponse: + """Call a workflow document""" + + wflow_doc = WorkflowDocument.from_file_context(file_ctx) + + variable_doc = Variables() + VariableTableManager.handle(variable_doc, wflow_doc, exec_ctx) + + service = WorkflowDocumentSupport() + # @TODO make sure the document do not call self making it repeating + service.set_step_template(variable_doc) + exec_report = service.process_task_template(wflow_doc, variable_doc) + + output_data = Variables({"_steps": variable_doc[WorkflowConfigNode.NODE.value]}) + + exposed_data: dict = ExposeManager.get_exposed_replaced_data_v2( + wflow_doc, variable_doc.data + ) + + # TODO also send failed_details (fail code, message, stacktrace, etc) + return ExecResponse( + file_ctx=file_ctx, + exec_ctx=exec_ctx, + variables=variable_doc, + variables_exec=output_data, + extra=exec_report, + exposed=exposed_data, + ) + + +def execute( + ctx: FileContext, exec_ctx: ExecuteContext, cb: abc.Callable = lambda *args: ... +) -> None: + """Run a workflow document + + Args: + ctx: FileContext object to handle + exec_ctx: ExecuteContext + cb: Callable + """ + + exr = call(file_ctx=ctx, exec_ctx=exec_ctx) + + cb({ctx.filepath_hash: exr.variables_exec.data}) + WorkflowDocumentSupport.display(exr, exec_ctx, WorkflowPresenter) diff --git a/chk/modules/workflow/entities.py b/chk/modules/workflow/entities.py new file mode 100644 index 00000000..7ea556fb --- /dev/null +++ b/chk/modules/workflow/entities.py @@ -0,0 +1,89 @@ +""" +Entities for workflow +""" + +from __future__ import annotations + +import enum +from typing import NamedTuple + +from pydantic import BaseModel, ConfigDict, Field + +from chk.infrastructure.file_loader import ExecuteContext, generate_abs_path + + +class WorkflowConfigNode(enum.StrEnum): + """WorkflowConfigNode""" + + NODE = "_steps" + + +class TaskExecParam(NamedTuple): + """TaskExecParams""" + + task: ChkwareTask + exec_ctx: ExecuteContext + + def as_dict(self) -> dict: + """Convert to dict""" + + return {"task": self.task.model_dump(), "execution_context": self.exec_ctx} + + +class WorkflowUses(enum.StrEnum): + """Types of Workflow Uses""" + + fetch = enum.auto() + validate = enum.auto() + + +class ChkwareTask(BaseModel): + """Chkware task""" + + model_config = ConfigDict(extra="forbid") + + name: str + uses: str + file: str + variables: dict = Field(default_factory=dict) + + def __init__(self, basepath: str, /, **kwargs: dict) -> None: + """Constructor""" + + if ( + "file" in kwargs + and isinstance(kwargs["file"], str) + and len(kwargs["file"]) != 0 + ): + kwargs["file"] = generate_abs_path(basepath, kwargs["file"]) + + super().__init__(**kwargs) + + +class ChkwareValidateTask(ChkwareTask): + """Chkware validation task""" + + class ChkwareTaskDataArgument(BaseModel): + """Chkware task data argument""" + + model_config = ConfigDict(extra="forbid") + + data: dict = Field(default_factory=dict) + + model_config = ConfigDict(extra="forbid") + + arguments: ChkwareTaskDataArgument = Field(default_factory=ChkwareTaskDataArgument) + + def __init__(self, basepath: str, /, **kwargs: dict) -> None: + """Constructor""" + + super().__init__(basepath, **kwargs) + + +class StepResult(BaseModel): + """StepResult""" + + task: ChkwareTask | ChkwareValidateTask + is_success: bool + others: dict = Field(default_factory=dict) + exposed: list | dict = Field(default_factory=list) diff --git a/chk/modules/workflow/services.py b/chk/modules/workflow/services.py new file mode 100644 index 00000000..6185fdba --- /dev/null +++ b/chk/modules/workflow/services.py @@ -0,0 +1,152 @@ +""" +Workflow services module +""" + +from __future__ import annotations + +import json + +from chk.infrastructure.helper import Cast +from chk.infrastructure.view import PresentationBuilder +from chk.modules.workflow import ( + ChkwareTask, + ChkwareValidateTask, + StepResult, + WorkflowConfigNode, + WorkflowUses, +) + + +class ChkwareTaskSupport: + """ChkwareTaskSupport""" + + @classmethod + def make_task(cls, task_d_: dict, /, **kwargs: dict) -> ChkwareTask: + """validate task data""" + + if "base_file_path" not in kwargs: + raise ValueError("`base_file_path` not passed.") + + if "uses" not in task_d_: + raise RuntimeError("Malformed task item found.") + + if task_d_["uses"] not in ( + WorkflowUses.fetch.value, + WorkflowUses.validate.value, + ): + raise RuntimeError("task.uses unsupported.") + + base_file_path = str(kwargs["base_file_path"]) + + return ( + ChkwareTask(base_file_path, **task_d_) + if task_d_["uses"] == "fetch" + else ChkwareValidateTask(base_file_path, **task_d_) + ) + + +class WorkflowPresenter(PresentationBuilder): + """WorkflowPresenter""" + + def _prepare_dump_data(self) -> dict: + """prepare dump data""" + + exec_report = self.data.extra + _document = self.data.file_ctx.document + + r_dump = {} + + if _document and "name" in _document: + r_dump["name"] = _document["name"] + + if exec_report: + r_dump["step_count"] = len(exec_report) + r_dump["step_failed"] = len( + [item for item in exec_report if not item.is_success] + ) + + r_dump["tasks"] = [] + + for item in exec_report: + item: StepResult # type: ignore + + response_task_dump = { + "name": item.task.name, + "uses": item.task.uses, + "is_success": item.is_success, + "fetch_request_method": ( + item.others["request_method"] + if "request_method" in item.others + else "" + ), + "fetch_request_url": ( + item.others["request_url"] if "request_url" in item.others else "" + ), + "validate_asserts_count_all": ( + item.others["count_all"] if "count_all" in item.others else "" + ), + "validate_asserts_count_fail": ( + item.others["count_fail"] if "count_fail" in item.others else "" + ), + } + + r_dump["tasks"].append(response_task_dump) + return r_dump + + def dump_fmt(self) -> str: + """return formatted string representation""" + + exposed_fmt_str = [] + for key, value in self.data.exposed.items(): + node = str(WorkflowConfigNode.NODE) + + if node in key and len(key) == len(node): + to_append = self._prepare_dump_str_for_steps() + else: + to_append = json.dumps(value) + + exposed_fmt_str.append(to_append) + + return "\n======\n".join(exposed_fmt_str) + + def _prepare_dump_str_for_steps(self) -> str: + """prepare dump str for steps""" + + dump_dct: dict = self._prepare_dump_data() + + _computed_str = f"\n\nWorkflow: {dump_dct.get('name', '')}" + _computed_str += f"\nSteps total: {dump_dct.get('step_count', '')}, " + _computed_str += f"failed: {dump_dct.get('step_failed', '')}" + + tasks = dump_dct.get("tasks", []) + + for one_task in tasks: + _computed_str += "\n------\n" + _computed_str += "+ " if one_task["is_success"] else "- " + _computed_str += f"Task: {one_task['name']}\n" + if one_task["uses"] == "fetch": + _computed_str += f">> {one_task['fetch_request_method']} {one_task['fetch_request_url']}" + elif one_task["uses"] == "validate": + _computed_str += ( + f">> Total tests: {one_task['validate_asserts_count_all']}, " + ) + _computed_str += f"Failed: {one_task['validate_asserts_count_fail']}" + + return _computed_str + + def dump_json(self) -> str: + """return json representation""" + exposed_fmt_str = [] + + for key, value in self.data.exposed.items(): + node = str(WorkflowConfigNode.NODE) + _to_append = {} + + if node in key and len(key) == len(node): + _to_append = self._prepare_dump_data() + else: + _to_append = value + + exposed_fmt_str.append(_to_append) + + return json.dumps(exposed_fmt_str) diff --git a/requirements-dev.txt b/requirements-dev.txt index dafb652a..512672a0 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,46 +1,53 @@ -i https://pypi.org/simple -aiohttp==3.9.5 +aiohappyeyeballs==2.4.3; python_version >= '3.8' +aiohttp==3.10.8 aiosignal==1.3.1; python_version >= '3.7' -astroid==3.2.2; python_full_version >= '3.8.0' -attrs==23.2.0; python_version >= '3.7' -black[d]==24.4.2; python_version >= '3.8' -certifi==2024.2.2; python_version >= '3.6' +astroid==3.3.4; python_full_version >= '3.9.0' +asttokens==2.4.1 +attrs==24.2.0; python_version >= '3.7' +black[d]==24.8.0; python_version >= '3.8' +certifi==2024.8.30; python_version >= '3.6' charset-normalizer==3.3.2; python_full_version >= '3.7.0' click==8.1.7; python_version >= '3.7' -coverage[toml]==7.5.3; python_version >= '3.8' +colorama==0.4.6; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6' +coverage[toml]==7.6.1; python_version >= '3.8' coveralls==4.0.1; python_version < '3.13' and python_version >= '3.8' -dill==0.3.8; python_version >= '3.11' +dill==0.3.9; python_version >= '3.11' docopt==0.6.2 -flake8==7.0.0; python_full_version >= '3.8.1' +executing==2.1.0; python_version >= '3.8' +flake8==7.1.1; python_full_version >= '3.8.1' frozenlist==1.4.1; python_version >= '3.8' -idna==3.7; python_version >= '3.5' +icecream==2.1.3 +idna==3.10; python_version >= '3.6' iniconfig==2.0.0; python_version >= '3.7' isort==5.13.2; python_full_version >= '3.8.0' mccabe==0.7.0; python_version >= '3.6' -multidict==6.0.5; python_version >= '3.7' -mypy==1.10.0; python_version >= '3.8' +multidict==6.1.0; python_version >= '3.8' +mypy==1.11.2; python_version >= '3.8' mypy-extensions==1.0.0; python_version >= '3.5' -packaging==24.0; python_version >= '3.7' +packaging==24.1; python_version >= '3.8' pathspec==0.12.1; python_version >= '3.8' -platformdirs==4.2.2; python_version >= '3.8' +platformdirs==4.3.6; python_version >= '3.8' pluggy==1.5.0; python_version >= '3.8' -pycodestyle==2.11.1; python_version >= '3.8' +pycodestyle==2.12.1; python_version >= '3.8' pyflakes==3.2.0; python_version >= '3.8' -pylint==3.2.2; python_full_version >= '3.8.0' -pytest==8.2.1; python_version >= '3.8' +pygments==2.18.0; python_version >= '3.8' +pylint==3.3.1; python_full_version >= '3.9.0' +pytest==8.3.3; python_version >= '3.8' pytest-cov==5.0.0; python_version >= '3.8' requests==2.32.3; python_version >= '3.8' -tomlkit==0.12.5; python_version >= '3.7' -types-pyyaml==6.0.12.20240311; python_version >= '3.8' -types-requests==2.32.0.20240523; python_version >= '3.8' -typing-extensions==4.12.0; python_version >= '3.8' -urllib3==2.2.1; python_version >= '3.8' -var-dump==1.2 -yarl==1.9.4; python_version >= '3.7' +six==1.16.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +tomlkit==0.13.2; python_version >= '3.8' +types-pyyaml==6.0.12.20240917; python_version >= '3.8' +types-requests==2.32.0.20240914; python_version >= '3.8' +typing-extensions==4.12.2; python_version < '3.13' +urllib3==2.2.3; python_version >= '3.8' +yarl==1.13.1; python_version >= '3.8' +annotated-types==0.7.0; python_version >= '3.8' cerberus==1.3.5 defusedxml==0.7.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' -jinja2==3.1.4; python_version >= '3.7' -markupsafe==2.1.5; python_version >= '3.7' +pydantic==2.9.2; python_version >= '3.8' +pydantic-core==2.23.4; python_version >= '3.8' python-dotenv==1.0.1; python_version >= '3.8' -pyyaml==6.0.1; python_version >= '3.6' +pyyaml==6.0.2; python_version >= '3.8' xmltodict==0.13.0; python_version >= '3.4' diff --git a/requirements.txt b/requirements.txt index cd0dba0a..d2fb427b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,13 +1,15 @@ +annotated-types==0.7.0; python_version >= '3.8' cerberus==1.3.5 -certifi==2024.2.2; python_version >= '3.6' +certifi==2024.8.30; python_version >= '3.6' charset-normalizer==3.3.2; python_full_version >= '3.7.0' click==8.1.7; python_version >= '3.7' defusedxml==0.7.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' -idna==3.7; python_version >= '3.5' -jinja2==3.1.4; python_version >= '3.7' -markupsafe==2.1.5; python_version >= '3.7' +idna==3.10; python_version >= '3.6' +pydantic==2.9.2; python_version >= '3.8' +pydantic-core==2.23.4; python_version >= '3.8' python-dotenv==1.0.1; python_version >= '3.8' -pyyaml==6.0.1; python_version >= '3.6' +pyyaml==6.0.2; python_version >= '3.8' requests==2.32.3; python_version >= '3.8' -urllib3==2.2.1; python_version >= '3.8' +typing-extensions==4.12.2; python_version < '3.13' +urllib3==2.2.3; python_version >= '3.8' xmltodict==0.13.0; python_version >= '3.4' diff --git a/tests/__init__.py b/tests/__init__.py index 22dfd953..2bea4955 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,5 +1,42 @@ +# type: ignore """ common config """ +import pytest -RES_DIR = './tests/resources/storage/sample_config/' +from chk.infrastructure.file_loader import FileLoader, FileContext, ExecuteContext + +RES_DIR = "./tests/resources/storage/sample_config/" +SPEC_DIR = "./tests/resources/storage/spec_docs/" + + +@pytest.fixture +def load_chk_file(): + def wrapper(file_path): + if FileLoader.is_file_ok(file_path): + return FileLoader.load_yaml(file_path) + + raise RuntimeError("Issue with file loading.") + + return wrapper + + +@pytest.fixture +def load_file_ctx_for_file(load_chk_file): + def wrapper(filepath): + return FileContext(document=load_chk_file(filepath), filepath=filepath) + + return wrapper + + +@pytest.fixture +def get_exec_ctx(): + def wrapper(format=True): + return ExecuteContext( + options={ + "dump": True, + "format": format, + } + ) + + return wrapper diff --git a/tests/console/main_test.py b/tests/console/main_test.py index 47c3c344..9605b6d6 100644 --- a/tests/console/main_test.py +++ b/tests/console/main_test.py @@ -34,7 +34,6 @@ def test_pass(): dct = combine_initial_variables(external_vars) assert isinstance(dct, dict) - assert "_ENV" in dct @staticmethod def test_fail_for_invalid_json(): diff --git a/tests/infrastructure/file_loader_test.py b/tests/infrastructure/file_loader_test.py index e8ce8f15..ef9c56a6 100644 --- a/tests/infrastructure/file_loader_test.py +++ b/tests/infrastructure/file_loader_test.py @@ -9,16 +9,51 @@ from chk.infrastructure.file_loader import ( FileContext, - PathFrom, FileLoader, + generate_abs_path, ) from chk.infrastructure.typing_extras import JsonDecodingError +@pytest.fixture +def file_n(): + return "bitcoin-usd.chk" + + +@pytest.fixture +def options_n(): + return {"result": False} + + +@pytest.fixture +def arguments_n(): + return {"variables": {"var": 1}} + + +@pytest.fixture +def get_FileContext_v1(file_n): + file_path = tests.RES_DIR + file_n + return FileContext.from_file(file_path), file_path + + +@pytest.fixture +def get_FileContext_v2(file_n, options_n): + file_path = tests.RES_DIR + file_n + return FileContext.from_file(file_path, options=options_n), file_path + + +@pytest.fixture +def get_FileContext_v3(file_n, options_n, arguments_n): + file_path = tests.RES_DIR + file_n + return ( + FileContext.from_file(file_path, options=options_n, arguments=arguments_n), + file_path, + ) + + class TestFileContext: - def test_from_file_pass(self): - file_path = tests.RES_DIR + "bitcoin-usd.chk" - ctx = FileContext.from_file(file_path) + def test_from_file_pass(self, get_FileContext_v1): + (ctx, file_path) = get_FileContext_v1 if sys.platform.startswith("win"): file_path = file_path.replace("/", "\\") @@ -32,9 +67,8 @@ def test_from_file_pass(self): assert len(ctx.arguments) == 0 assert isinstance(ctx.arguments, dict) - def test_from_file_pass_with_opt_set(self): - file_path = tests.RES_DIR + "bitcoin-usd.chk" - ctx = FileContext.from_file(file_path, options={"result": False}) + def test_from_file_pass_with_opt_set(self, get_FileContext_v2): + ctx, file_path = get_FileContext_v2 if sys.platform.startswith("win"): file_path = file_path.replace("/", "\\") @@ -48,11 +82,8 @@ def test_from_file_pass_with_opt_set(self): assert len(ctx.arguments) == 0 assert isinstance(ctx.arguments, dict) - def test_from_file_pass_with_opt_arg_set(self): - file_path = tests.RES_DIR + "bitcoin-usd.chk" - ctx = FileContext.from_file( - file_path, options={"result": False}, arguments={"variables": {"var": 1}} - ) + def test_from_file_pass_with_opt_arg_set(self, get_FileContext_v3): + ctx, file_path = get_FileContext_v3 if sys.platform.startswith("win"): file_path = file_path.replace("/", "\\") @@ -67,11 +98,8 @@ def test_from_file_pass_with_opt_arg_set(self): assert isinstance(ctx.arguments["variables"], dict) assert ctx.arguments["variables"]["var"] == 1 - def test_from_file_pass_with_doc(self): - file_path = tests.RES_DIR + "bitcoin-usd.chk" - ctx = FileContext.from_file( - file_path, options={"result": False}, arguments={"variables": {"var": 1}} - ) + def test_from_file_pass_with_doc(self, get_FileContext_v3): + ctx, file_path = get_FileContext_v3 if sys.platform.startswith("win"): file_path = file_path.replace("/", "\\") @@ -80,14 +108,24 @@ def test_from_file_pass_with_doc(self): assert ctx.document == FileLoader.load_yaml(file_path) + def test_property_filepath_as_path_pass(self, get_FileContext_v3): + ctx, _ = get_FileContext_v3 + + assert isinstance(ctx.filepath_as_path, Path) + + def test_property_filepath_base_as_path_pass(self, get_FileContext_v3): + ctx, _ = get_FileContext_v3 + + assert isinstance(ctx.filepath_base_as_path, Path) + -class TestPathFrom: +class TestGenerateAbsPath: """Test PathResolver""" @staticmethod - def test_absolute_pass(): + def test_generate_abs_path_pass(): ctx = FileContext.from_file(tests.RES_DIR + "bitcoin-usd.chk") - p = PathFrom(Path(ctx.filepath)) + p_base = ctx.filepath path_1 = "tests/resources/storage/sample_config/bitcoin-usd-testcase-data.chk" path_2 = "tests/resources/storage/sample_config/some-folder/bitcoin-usd-testcase-data.chk" @@ -100,13 +138,23 @@ def test_absolute_pass(): path_3 = path_3.replace("/", "\\") path_4 = path_4.replace("/", "\\") - assert path_1 in p.absolute("./bitcoin-usd-testcase-data.chk") - assert path_2 in p.absolute("./some-folder/bitcoin-usd-testcase-data.chk") - assert path_3 in p.absolute("./../bitcoin-usd-testcase-data.chk") - assert path_1 in p.absolute("./some-folder/../bitcoin-usd-testcase-data.chk") - assert path_3 in p.absolute("../some-folder/../bitcoin-usd-testcase-data.chk") - assert path_4 in p.absolute("../some-folder/./bitcoin-usd-testcase-data.chk") - assert path_2 in p.absolute("./some-folder////bitcoin-usd-testcase-data.chk") + assert path_1 in generate_abs_path(p_base, "./bitcoin-usd-testcase-data.chk") + assert path_2 in generate_abs_path( + p_base, "./some-folder/bitcoin-usd-testcase-data.chk" + ) + assert path_3 in generate_abs_path(p_base, "./../bitcoin-usd-testcase-data.chk") + assert path_1 in generate_abs_path( + p_base, "./some-folder/../bitcoin-usd-testcase-data.chk" + ) + assert path_3 in generate_abs_path( + p_base, "../some-folder/../bitcoin-usd-testcase-data.chk" + ) + assert path_4 in generate_abs_path( + p_base, "../some-folder/./bitcoin-usd-testcase-data.chk" + ) + assert path_2 in generate_abs_path( + p_base, "./some-folder////bitcoin-usd-testcase-data.chk" + ) FILE_PATH = "tests/resources/storage/sample_config/" diff --git a/tests/infrastructure/helper_test.py b/tests/infrastructure/helper_test.py index ced73b1c..c9ab8658 100644 --- a/tests/infrastructure/helper_test.py +++ b/tests/infrastructure/helper_test.py @@ -14,6 +14,7 @@ is_scalar, Cast, formatter, + slugify, ) @@ -276,3 +277,30 @@ def fmt(val): # assert assert out == "Hello, I am Some One. I am 43 years old.\n" + + +class TestSlugify: + @staticmethod + def test_slugify_pass(): + a = "Some one goes here" + assert slugify(a) == "some-one-goes-here" + + a = "Some ONE GOES HERE" + assert slugify(a) == "some-one-goes-here" + + a = "So'me ONE GO_ES HERE" + assert slugify(a) == "some-one-go-es-here" + + @staticmethod + def test_slugify_fail(): + a = {} + with pytest.raises(TypeError): + slugify(a) + + a = [] + with pytest.raises(TypeError): + slugify(a) + + a = 1 + with pytest.raises(TypeError): + slugify(a) diff --git a/tests/modules/fetch/fetch_module_test.py b/tests/modules/fetch/fetch_module_test.py new file mode 100644 index 00000000..3bd16c24 --- /dev/null +++ b/tests/modules/fetch/fetch_module_test.py @@ -0,0 +1,31 @@ +# type: ignore + +""" +Fetch module tests +""" +from chk.infrastructure.file_loader import FileContext, ExecuteContext +from chk.modules.fetch import call + + +class TestFetchCall: + @staticmethod + def test_call_pass(): + file_ctx = FileContext( + document={ + "version": "default:http:0.7.2", + "request": { + "url": "https://jsonplaceholder.typicode.com/albums/1", + "method": "GET", + }, + } + ) + + exec_ctx = ExecuteContext( + options={ + "dump": True, + "format": False, + } + ) + + er = call(file_ctx, exec_ctx) + assert "_response" in er.variables_exec diff --git a/tests/modules/validate/validate_entity_test.py b/tests/modules/validate/validate_entity_test.py index 021758b4..2e706a22 100644 --- a/tests/modules/validate/validate_entity_test.py +++ b/tests/modules/validate/validate_entity_test.py @@ -117,8 +117,8 @@ def test_as_dict_pass(): doc = ValidationDocument.from_file_context(ctx) - assert isinstance(doc.as_dict, dict) - assert len(doc.as_dict) == 4 + assert isinstance(doc.model_dump(), dict) + assert len(doc.model_dump()) == 4 class TestValidationDocumentSupport: @@ -156,7 +156,7 @@ def test_set_data_template_pass_when_set_from_exec_ctx(self): variables = Variables() ValidationDocumentSupport.set_data_template(doc, variables, exec_ctx) - assert bool(variables[ValidationConfigNode.VAR_NODE]) + assert bool(variables[ValidationConfigNode.VAR_NODE.value]) def test_set_data_template_pass_when_set_from_doc(self): ctx = FileContext( @@ -185,7 +185,7 @@ def test_set_data_template_pass_when_set_from_doc(self): variables = Variables() ValidationDocumentSupport.set_data_template(doc, variables, exec_ctx) - assert bool(variables[ValidationConfigNode.VAR_NODE]) + assert bool(variables[ValidationConfigNode.VAR_NODE.value]) def test_set_data_template_pass_exec_ctx_prioritise(self): ctx = FileContext( @@ -215,8 +215,11 @@ def test_set_data_template_pass_exec_ctx_prioritise(self): variables = Variables() ValidationDocumentSupport.set_data_template(doc, variables, exec_ctx) - assert bool(variables[ValidationConfigNode.VAR_NODE]) - assert variables[ValidationConfigNode.VAR_NODE].get("name") == "Some Name Two" + assert bool(variables[ValidationConfigNode.VAR_NODE.value]) + assert ( + variables[ValidationConfigNode.VAR_NODE.value].get("name") + == "Some Name Two" + ) @staticmethod def test_process_data_template_pass(): @@ -251,8 +254,11 @@ def test_process_data_template_pass(): ValidationDocumentSupport.set_data_template(doc, variables, exec_ctx) ValidationDocumentSupport.process_data_template(variables) - assert bool(variables[ValidationConfigNode.VAR_NODE]) - assert variables[ValidationConfigNode.VAR_NODE].get("greet") == "Hello Somebody" + assert bool(variables[ValidationConfigNode.VAR_NODE.value]) + assert ( + variables[ValidationConfigNode.VAR_NODE.value].get("greet") + == "Hello Somebody" + ) @staticmethod def test_make_assertion_entry_list_pass(): diff --git a/tests/modules/workflow/wf_domain_test.py b/tests/modules/workflow/wf_domain_test.py new file mode 100644 index 00000000..2f20eada --- /dev/null +++ b/tests/modules/workflow/wf_domain_test.py @@ -0,0 +1,62 @@ +# type: ignore +""" +Domain test code +""" +from pydantic import BaseModel, Field + +from chk.infrastructure.symbol_table import Variables +from chk.modules.workflow import WorkflowDocument, WorkflowDocumentSupport +from chk.modules.workflow.entities import ChkwareTask, WorkflowUses +from tests import SPEC_DIR, load_chk_file, load_file_ctx_for_file + + +class TestWorkflowDocument: + @staticmethod + def test_from_file_context_pass(load_chk_file, load_file_ctx_for_file): + + class TaskDict(BaseModel): + file: str = Field(default=str) + name: str = Field(default=str) + uses: WorkflowUses + + filepath = f"{SPEC_DIR}workflow/simple-btc-wf.chk" + file_ctx = load_file_ctx_for_file(filepath) + + wfdoc = WorkflowDocument.from_file_context(file_ctx) + assert wfdoc.id == "simple-btc-workflow-1" + + assert isinstance(wfdoc.tasks, list) + assert all(TaskDict(**i) for i in wfdoc.tasks) + + @staticmethod + def test_from_file_context_pass_noid(load_chk_file, load_file_ctx_for_file): + + class TaskDict(BaseModel): + file: str = Field(default=str) + name: str = Field(default=str) + uses: WorkflowUses + + filepath = f"{SPEC_DIR}workflow/simple-btc-wf.chk" + file_ctx = load_file_ctx_for_file(filepath) + + del file_ctx.document["id"] # remove document id + wfdoc = WorkflowDocument.from_file_context(file_ctx) + + # check if document id defaults to file name + assert wfdoc.id == "simple-btc-workflow" + + assert isinstance(wfdoc.tasks, list) + assert all(TaskDict(**i) for i in wfdoc.tasks) + + +class TestWorkflowDocumentSupport: + @staticmethod + def test_process_task_template_pass(load_chk_file, load_file_ctx_for_file): + # filepath = f"{SPEC_DIR}workflow/simple-btc-wf.chk" + filepath = f"{SPEC_DIR}workflow_cases/simple/coinstats-usd-workflow.chk" + file_ctx = load_file_ctx_for_file(filepath) + + wfdoc = WorkflowDocument.from_file_context(file_ctx) + + rpt = WorkflowDocumentSupport.process_task_template(wfdoc, Variables({"_steps": []})) + assert isinstance(rpt, list) diff --git a/tests/modules/workflow/wf_entities_test.py b/tests/modules/workflow/wf_entities_test.py new file mode 100644 index 00000000..99080add --- /dev/null +++ b/tests/modules/workflow/wf_entities_test.py @@ -0,0 +1,96 @@ +# type: ignore +""" +Testing Entities for workflow +""" +from pathlib import Path + +import pytest +from pydantic import ValidationError + +from chk.modules.workflow.entities import ChkwareTask, ChkwareValidateTask + +fp_p = ( + Path.cwd() + / "tests" + / "resources" + / "storage" + / "spec_docs" + / "workflow_cases" + / "simple" +) + +fp = str(fp_p) + + +class TestChkwareTask: + @staticmethod + def test_from_dict_pass(): + + task = ChkwareTask( + fp, + **{ + "name": "Sample fetch", + "uses": "fetch", + "file": "./coinstats-usd-validate.chk", + }, + ) + + assert task.uses == "fetch" + assert task.file == str(fp_p / "coinstats-usd-validate.chk") + + +class TestChkwareValidateTask: + @staticmethod + def test_from_dict_pass(): + task = ChkwareValidateTask( + fp, + **{ + "name": "Sample validate", + "uses": "validate", + "file": "./coinstats-usd-validate.chk", + }, + ) + + assert task.uses == "validate" + assert task.file == str(fp_p / "coinstats-usd-validate.chk") + assert isinstance(task.arguments, ChkwareValidateTask.ChkwareTaskDataArgument) + + task = ChkwareValidateTask( + fp, + **{ + "name": "Sample validate - 2", + "uses": "validate", + "file": "./coinstats-usd-validate.chk", + "arguments": {"data": {"some": 12, "data": [1, "a"]}}, + }, + ) + + assert task.arguments and "data" in task.arguments.model_dump() + + @staticmethod + def test_from_dict_fail(): + with pytest.raises(ValidationError): + ChkwareValidateTask( + fp, + **{ + "name": "Sample validate - 3", + "uses": "validate", + "file": "./coinstats-usd-validate.chk", + "arguments": { + "data": {"some": 12, "data": [1, "a"]}, + "other_data": 1, + }, + }, + ) + + with pytest.raises(ValidationError): + ChkwareValidateTask( + fp, + **{ + "name": "Sample validate - 4", + "uses": "validate", + "file": "./coinstats-usd-validate.chk", + "other_data": 1, + "arguments": {"data": {"some": 12, "data": [1, "a"]}}, + }, + ) diff --git a/tests/modules/workflow/wf_module_test.py b/tests/modules/workflow/wf_module_test.py new file mode 100644 index 00000000..6fdd2e8d --- /dev/null +++ b/tests/modules/workflow/wf_module_test.py @@ -0,0 +1,33 @@ +# type: ignore +""" +Workflow module test +""" +from chk.infrastructure.symbol_table import ExecResponse +from chk.modules.workflow import call, execute +from tests import SPEC_DIR, get_exec_ctx, load_chk_file, load_file_ctx_for_file + + +class TestWorkflowExecute: + @staticmethod + def test_execute(load_chk_file, load_file_ctx_for_file, get_exec_ctx, capsys): + """test_execute""" + + filepath = f"{SPEC_DIR}workflow_cases/get-req-vars/coinstats-usd-workflow.chk" + file_ctx = load_file_ctx_for_file(filepath) + execution_ctx = get_exec_ctx(True) + + execute(file_ctx, execution_ctx) + + captured = capsys.readouterr() + assert "======" in captured.out + + @staticmethod + def test_call(load_chk_file, load_file_ctx_for_file, get_exec_ctx): + """test_call""" + + filepath = f"{SPEC_DIR}workflow_cases/get-req-vars/coinstats-usd-workflow.chk" + file_ctx = load_file_ctx_for_file(filepath) + execution_ctx = get_exec_ctx(True) + + er = call(file_ctx, execution_ctx) + assert isinstance(er, ExecResponse) diff --git a/tests/resources/storage/spec_docs/fetch/bitcoin-usd.chk b/tests/resources/storage/spec_docs/fetch/bitcoin-usd.chk index 28f0e9ac..1973269f 100644 --- a/tests/resources/storage/spec_docs/fetch/bitcoin-usd.chk +++ b/tests/resources/storage/spec_docs/fetch/bitcoin-usd.chk @@ -2,8 +2,10 @@ version: default:http:0.7.2 request: - url: https://api.coinstats.app/public/v1/coins/bitcoin?currency=USD + url: https://openapiv1.coinstats.app/coins/bitcoin?currency=USD method: GET + headers: + "X-API-KEY": <% _ENV.COINSTATS_API_KEY %> expose: - <% _response %> diff --git a/tests/resources/storage/spec_docs/validate/btc-usd-validate.chk b/tests/resources/storage/spec_docs/validate/btc-usd-validate.chk index cc651594..6b4f6729 100644 --- a/tests/resources/storage/spec_docs/validate/btc-usd-validate.chk +++ b/tests/resources/storage/spec_docs/validate/btc-usd-validate.chk @@ -3,16 +3,13 @@ version: default:validation:0.7.2 asserts: - { type: Equal, actual: <% _data.code %>, expected: 200, msg_pass: 'Response was successful with code `{type_actual}({value_actual})`' } - - { type: List, actual: <% _data.headers %>, msg_pass: 'Header is a list', msg_fail: 'Header is not a list' } + - { type: Map, actual: <% _data.headers %>, msg_pass: 'Header is a list', msg_fail: 'Header is not a list' } - { type: Str, actual: <% _data.code %>, msg_pass: 'Code `{type_actual}({value_actual})` is a string', msg_fail: 'Code `{type_actual}({value_actual})` is not a string', cast_actual_to: int } - { type: StrHave, actual: <% _data.info %>, other: "200 OK" } - - { type: Map, actual: <% _data.body.coin %> } - - { type: Map, actual: <% _data.body.coin %> } - - { type: List, actual: <% _data.body.coin.exp %> } - - { type: List, actual: <% _data.body.coin.exp %> } - - { type: Float, actual: <% _data.body.coin.price %> } - - { type: Float, actual: <% _data.body.coin.price %> } - - { type: MapHasKeys, actual: <% _data.body.coin %>, expected: [ "price", "priceBtc", "priceChange1d", "priceChange1h", "priceChange1w" ] } + - { type: Map, actual: <% _data.body %> } + - { type: List, actual: <% _data.body.explorers %> } + - { type: Float, actual: <% _data.body.price %> } + - { type: MapHasKeys, actual: <% _data.body %>, expected: [ "price", "priceBtc", "priceChange1d", "priceChange1h", "priceChange1w" ] } expose: - <% _asserts_response %> diff --git a/tests/resources/storage/spec_docs/validate/simple-external-data-test.chk b/tests/resources/storage/spec_docs/validate/simple-external-data-test.chk new file mode 100644 index 00000000..f53372f8 --- /dev/null +++ b/tests/resources/storage/spec_docs/validate/simple-external-data-test.chk @@ -0,0 +1,10 @@ +--- +version: default:validation:0.7.2 + +asserts: + - { type: Equal, actual: <% _data.code %>, expected: 200 } + - { type: IntegerGreaterOrEqual, actual: <% _data.age %>, other: 18 } + +expose: + - <% _asserts_response %> + - <% _data %> diff --git a/tests/resources/storage/spec_docs/workflow/simple-btc-wf.chk b/tests/resources/storage/spec_docs/workflow/simple-btc-wf.chk new file mode 100644 index 00000000..47af6d4b --- /dev/null +++ b/tests/resources/storage/spec_docs/workflow/simple-btc-wf.chk @@ -0,0 +1,17 @@ +version: default:workflow:0.8.0 + +name: simple Btc workflow +id: simple Btc workflow 1 + +tasks: + - name: Fetch some content from URL + uses: fetch + file: ../fetch/bitcoin-usd.chk +# variables: { "var": 2 } + + - name: Validate the content is okay + uses: validate + file: ../validate/btc-usd-validate.chk +# variables: { "var": 2 } +# arguments: +# data: <% _tasks.0._expose.0 %> diff --git a/tests/resources/storage/spec_docs/workflow_cases/get-req-vars/coinstats-usd-request.chk b/tests/resources/storage/spec_docs/workflow_cases/get-req-vars/coinstats-usd-request.chk new file mode 100644 index 00000000..f368902c --- /dev/null +++ b/tests/resources/storage/spec_docs/workflow_cases/get-req-vars/coinstats-usd-request.chk @@ -0,0 +1,16 @@ +--- +version: default:http:0.7.2 + +variables: + convertCurrency: USD + +request: + url: "https://openapiv1.coinstats.app/coins/bitcoin" + url_params: + currency: <% convertCurrency %> + method: GET + headers: + "X-API-KEY": <% _ENV.COINSTATS_API_KEY %> + +expose: + - <% _response %> diff --git a/tests/resources/storage/spec_docs/workflow_cases/get-req-vars/coinstats-usd-validate.chk b/tests/resources/storage/spec_docs/workflow_cases/get-req-vars/coinstats-usd-validate.chk new file mode 100644 index 00000000..db55b61e --- /dev/null +++ b/tests/resources/storage/spec_docs/workflow_cases/get-req-vars/coinstats-usd-validate.chk @@ -0,0 +1,23 @@ +--- +version: default:validation:0.7.2 + +variables: + vdata: ~ + +asserts: + - { type: Equal, actual: <% vdata.code %>, expected: 200, msg_pass: 'Response was successful with code `{type_actual}({value_actual})`', cast_actual_to: int } + - { type: Map, actual: <% vdata.headers %>, msg_pass: 'Header is a list', msg_fail: 'Header is not a list' } + - { type: Str, actual: <% vdata.code %>, msg_pass: 'Code `{type_actual}({value_actual})` is a string', msg_fail: 'Code `{type_actual}({value_actual})` is not a string', cast_actual_to: int } + - { type: StrHave, actual: <% vdata.info %>, other: "200 OK" } + - { type: Map, actual: <% vdata.body %> } + - { type: List, actual: <% vdata.body.explorers %> } + - { type: Float, actual: <% vdata.body.price %> } + - { type: MapHasKeys, actual: <% vdata.body %>, expected: [ "price", "priceBtc", "priceChange1d", "priceChange1h", "priceChange1w" ] } + +expose: + - <% _asserts_response %> + - <% vdata %> + +# --- shell command --- +# pipenv run python -m chk validate -nf tests/resources/storage/spec_docs/validate/btc-usd-validate.chk -D "$(pipenv run python -m chk fetch -nf tests/resources/storage/spec_docs/fetch/bitcoin-usd.chk)" +# --- diff --git a/tests/resources/storage/spec_docs/workflow_cases/get-req-vars/coinstats-usd-workflow.chk b/tests/resources/storage/spec_docs/workflow_cases/get-req-vars/coinstats-usd-workflow.chk new file mode 100644 index 00000000..c091d7a3 --- /dev/null +++ b/tests/resources/storage/spec_docs/workflow_cases/get-req-vars/coinstats-usd-workflow.chk @@ -0,0 +1,25 @@ +version: default:workflow:0.8.0 + +name: simple Btc workflow +id: BtcWF1 + +variables: + group: coinstats + currency: GBP + +tasks: + - name: Fetch some content from URL + uses: fetch + file: "./<% group %>-usd-request.chk" + variables: + convertCurrency: <% currency %> + + - name: Validate the content is okay + uses: validate + file: "./<% group %>-usd-validate.chk" + variables: + vdata: <% _steps.0._response %> + +expose: + - <% _steps %> + - <% _steps.1.vdata.body %> diff --git a/tests/resources/storage/spec_docs/workflow_cases/simple/coinstats-usd-request.chk b/tests/resources/storage/spec_docs/workflow_cases/simple/coinstats-usd-request.chk new file mode 100644 index 00000000..1973269f --- /dev/null +++ b/tests/resources/storage/spec_docs/workflow_cases/simple/coinstats-usd-request.chk @@ -0,0 +1,11 @@ +--- +version: default:http:0.7.2 + +request: + url: https://openapiv1.coinstats.app/coins/bitcoin?currency=USD + method: GET + headers: + "X-API-KEY": <% _ENV.COINSTATS_API_KEY %> + +expose: + - <% _response %> diff --git a/tests/resources/storage/spec_docs/workflow_cases/simple/coinstats-usd-validate.chk b/tests/resources/storage/spec_docs/workflow_cases/simple/coinstats-usd-validate.chk new file mode 100644 index 00000000..6b4f6729 --- /dev/null +++ b/tests/resources/storage/spec_docs/workflow_cases/simple/coinstats-usd-validate.chk @@ -0,0 +1,20 @@ +--- +version: default:validation:0.7.2 + +asserts: + - { type: Equal, actual: <% _data.code %>, expected: 200, msg_pass: 'Response was successful with code `{type_actual}({value_actual})`' } + - { type: Map, actual: <% _data.headers %>, msg_pass: 'Header is a list', msg_fail: 'Header is not a list' } + - { type: Str, actual: <% _data.code %>, msg_pass: 'Code `{type_actual}({value_actual})` is a string', msg_fail: 'Code `{type_actual}({value_actual})` is not a string', cast_actual_to: int } + - { type: StrHave, actual: <% _data.info %>, other: "200 OK" } + - { type: Map, actual: <% _data.body %> } + - { type: List, actual: <% _data.body.explorers %> } + - { type: Float, actual: <% _data.body.price %> } + - { type: MapHasKeys, actual: <% _data.body %>, expected: [ "price", "priceBtc", "priceChange1d", "priceChange1h", "priceChange1w" ] } + +expose: + - <% _asserts_response %> + - <% _data %> + +# --- shell command --- +# pipenv run python -m chk validate -nf tests/resources/storage/spec_docs/validate/btc-usd-validate.chk -D "$(pipenv run python -m chk fetch -nf tests/resources/storage/spec_docs/fetch/bitcoin-usd.chk)" +# --- diff --git a/tests/resources/storage/spec_docs/workflow_cases/simple/coinstats-usd-workflow.chk b/tests/resources/storage/spec_docs/workflow_cases/simple/coinstats-usd-workflow.chk new file mode 100644 index 00000000..82455d15 --- /dev/null +++ b/tests/resources/storage/spec_docs/workflow_cases/simple/coinstats-usd-workflow.chk @@ -0,0 +1,13 @@ +version: default:workflow:0.8.0 + +name: simple Btc workflow +id: simple Btc workflow 1 + +tasks: + - name: Fetch some content from URL + uses: fetch + file: ./coinstats-usd-request.chk + + - name: Validate the content is okay + uses: validate + file: ./coinstats-usd-validate.chk