diff --git a/Pipfile.lock b/Pipfile.lock index a4ead8f7..8c37c378 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -44,12 +44,12 @@ }, "faker": { "hashes": [ - "sha256:34b947581c2bced340c39b35f89dbfac4f356932cfff8fe893bde854903f0e6e", - "sha256:adb98e771073a06bdc5d2d6710d8af07ac5da64c8dc2ae3b17bb32319e66fd82" + "sha256:6737cc6d591cd83421fdc5e494f6e2c1a6e32266214f158b745aa9fa15687c98", + "sha256:c153505618801f1704807b258a6010ea8cabf91f66f4788939bfdba83b887e76" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==24.11.0" + "version": "==25.0.1" }, "markdown": { "hashes": [ @@ -268,14 +268,6 @@ "markers": "python_version >= '3.7'", "version": "==2.14.0" }, - "backports.tarfile": { - "hashes": [ - "sha256:91d59138ea401ee2a95e8b839c1e2f51f3e9ca76bdba8b6a29f8d773564686a8", - "sha256:b2f4df351db942d094db94588bbf2c6938697a5f190f44c934acc697da56008b" - ], - "markers": "python_version < '3.12'", - "version": "==1.1.0" - }, "beautifulsoup4": { "hashes": [ "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051", @@ -517,11 +509,11 @@ }, "docutils": { "hashes": [ - "sha256:14c8d34a55b46c88f9f714adb29cefbdd69fb82f3fef825e59c5faab935390d8", - "sha256:65249d8a5345bc95e0f40f280ba63c98eb24de35c6c8f5b662e3e8948adea83f" + "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", + "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2" ], "markers": "python_version >= '3.9'", - "version": "==0.21.1" + "version": "==0.21.2" }, "executing": { "hashes": [ @@ -603,11 +595,11 @@ }, "ipython": { "hashes": [ - "sha256:07232af52a5ba146dc3372c7bf52a0f890a23edf38d77caef8d53f9cdc2584c1", - "sha256:7468edaf4f6de3e1b912e57f66c241e6fd3c7099f2ec2136e239e142e800274d" + "sha256:010db3f8a728a578bb641fdd06c063b9fb8e96a9464c63aec6310fbcb5e80501", + "sha256:d7bf2f6c4314984e3e02393213bab8703cf163ede39672ce5918c51fe253a2a3" ], "markers": "python_version >= '3.10'", - "version": "==8.23.0" + "version": "==8.24.0" }, "isoduration": { "hashes": [ @@ -634,11 +626,11 @@ }, "jaraco.functools": { "hashes": [ - "sha256:c279cb24c93d694ef7270f970d499cab4d3813f4e08273f95398651a634f0925", - "sha256:daf276ddf234bea897ef14f43c4e1bf9eefeac7b7a82a4dd69228ac20acff68d" + "sha256:3b24ccb921d6b593bdceb56ce14799204f473976e2a9d4b15b04d0f2c2326664", + "sha256:d33fa765374c0611b52f8b3a795f8900869aa88c84769d4d1746cd68fb28c3e8" ], "markers": "python_version >= '3.8'", - "version": "==4.0.0" + "version": "==4.0.1" }, "jedi": { "hashes": [ @@ -676,11 +668,11 @@ "format-nongpl" ], "hashes": [ - "sha256:7996507afae316306f9e2290407761157c6f78002dcf7419acb99822143d1c6f", - "sha256:85727c00279f5fa6bedbe6238d2aa6403bedd8b4864ab11207d07df3cc1b2ee5" + "sha256:5b22d434a45935119af990552c862e5d6d564e8f6601206b305a61fdf661a2b7", + "sha256:ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802" ], "markers": "python_version >= '3.8'", - "version": "==4.21.1" + "version": "==4.22.0" }, "jsonschema-specifications": { "hashes": [ @@ -740,12 +732,12 @@ }, "jupyterlab": { "hashes": [ - "sha256:7935f36ba26eb615183a4f5c2bbca5791b5108ce2a00b5505f8cfd100d53648e", - "sha256:cf3e862bc10dbf4331e4eb37438634f813c238cfc62c71c640b3b3b2caa089a8" + "sha256:3384aded8680e7ce504fd63b8bb89a39df21c9c7694d9e7dc4a68742cdb30f9b", + "sha256:c3baf3a2f91f89d110ed5786cd18672b9a357129d4e389d2a0dead15e11a4d2c" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.1.6" + "version": "==4.1.8" }, "jupyterlab-pygments": { "hashes": [ @@ -757,19 +749,19 @@ }, "jupyterlab-server": { "hashes": [ - "sha256:54622cbd330526a385ee0c1fdccdff3a1e7219bf3e864a335284a1270a1973df", - "sha256:9b3ba91cf2837f7f124fca36d63f3ca80ace2bed4898a63dd47e6598c1ab006f" + "sha256:097b5ac709b676c7284ac9c5e373f11930a561f52cd5a86e4fc7e5a9c8a8631d", + "sha256:f5e26156e5258b24d532c84e7c74cc212e203bff93eb856f81c24c16daeecc75" ], "markers": "python_version >= '3.8'", - "version": "==2.26.0" + "version": "==2.27.1" }, "keyring": { "hashes": [ - "sha256:26fc12e6a329d61d24aa47b22a7c5c3f35753df7d8f2860973cf94f4e1fb3427", - "sha256:7230ea690525133f6ad536a9b5def74a4bd52642abe594761028fc044d7c7893" + "sha256:19f17d40335444aab84b19a0d16a77ec0758a9c384e3446ae2ed8bd6d53b67a5", + "sha256:7045f367268ce42dba44745050164b431e46f6e92f99ef2937dfadaef368d8cf" ], "markers": "python_version >= '3.8'", - "version": "==25.1.0" + "version": "==25.2.0" }, "markdown-it-py": { "hashes": [ @@ -887,11 +879,11 @@ }, "nbconvert": { "hashes": [ - "sha256:a6733b78ce3d47c3f85e504998495b07e6ea9cf9bf6ec1c98dda63ec6ad19142", - "sha256:ddeff14beeeedf3dd0bc506623e41e4507e551736de59df69a91f86700292b3b" + "sha256:05873c620fe520b6322bf8a5ad562692343fe3452abda5765c7a34b7d1aa3eb3", + "sha256:86ca91ba266b0a448dc96fa6c5b9d98affabde2867b363258703536807f9f7f4" ], "markers": "python_version >= '3.8'", - "version": "==7.16.3" + "version": "==7.16.4" }, "nbformat": { "hashes": [ @@ -977,7 +969,7 @@ "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3", "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f" ], - "markers": "python_version == '3.11'", + "markers": "python_version >= '3.12'", "version": "==1.26.4" }, "overrides": { @@ -1081,11 +1073,11 @@ }, "platformdirs": { "hashes": [ - "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068", - "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768" + "sha256:031cd18d4ec63ec53e82dceaac0417d218a6863f7745dfcc9efe7793b7039bdf", + "sha256:17d5a1161b3fd67b390023cb2d3b026bbd40abde6fdb052dfbd3a29c3ba22ee1" ], "markers": "python_version >= '3.8'", - "version": "==4.2.0" + "version": "==4.2.1" }, "prometheus-client": { "hashes": [ @@ -1238,97 +1230,97 @@ }, "pyzmq": { "hashes": [ - "sha256:02773b96ef6a17a57680c3609645785c390198be31a4505c01ce0c846f9e7d0e", - "sha256:0397c7431f3fc2bac497992d7447b036bc0d8bb3e15b158b2013201857ff2354", - "sha256:06525d996afdb0da3e8b7df0b654261455f6e86c2c3574c3f00d2bd335be78eb", - "sha256:07fdeac8612a9dca6fcad6cb43c7efb75f53ba75da981fbafa949ddcde1d5662", - "sha256:08db8071020181173c70cf2dad239e5e21e5b2e95f95b0ece0da39a70f5a483c", - "sha256:0ec5147095d6065b0e3a38a1a34f7859ab46496f3d5ce71134165893e9f83674", - "sha256:10ff405db5cee3bbd7aa143d78b25d90356097aed7864e50f0ae644e08759fe9", - "sha256:120887d773e878136e9b33bbba656df0d4c6e2861694d07d058ec60ce1108b24", - "sha256:12ca1afb065e5b21a32b1e35bfcbc8762efc0f7555c166acaec36c93b52d7ccf", - "sha256:1d64889bfe4109f4a59a72b1d21416550465020642d6f556efd044951386bd38", - "sha256:1da5e11862a994360319df4f425e89662563683334e1079684eb77b9a6478ae2", - "sha256:1df2b992eabc59f078ca916e9ac8b5bd463536bf7828c13940b35b8555ed7861", - "sha256:1e87178437460b6df18e761650ef080d3ad5a41813cc3df7f9fd78714fca04c0", - "sha256:2397364289334840c81ff1ef95a5a5ee326de01c1437cc38f7e16785a7b653d9", - "sha256:271c9178a94b009651f8ad3ff9bb9ca45778aaf66c9e325a44d81a7498fcaa59", - "sha256:2806942185b40a3477d9b300c6f71354dd2be37e3f61a43193c96caa51e284d1", - "sha256:321a6872a9371709a62b3a4a14c1e9b5b47549371197c0c2164d2288510cd6d6", - "sha256:36a85da0eab4c5337d0de7f975cca011208a59e9d0637e0c1b571764f1dd4a8f", - "sha256:36d0f2fcbdba1fda8ff213bd17db7ddcba848aa70480ade3fe70401dce606511", - "sha256:39b8ed8d2e5da8b8351c6aa627601b3b52e8eb5e25cf6bcd26b6f012dec7870b", - "sha256:40af30c4cd0a046029d7b5272d02a649f9b1f89fb1361bbc90ba08d55ac88273", - "sha256:4216eee101d104a017042f0e4af0a45875400ff3794f1a59476e210b1a9760e2", - "sha256:44271793067025a07d38ad4be11f08187cce850fafd1890b42046abbcdca2fc0", - "sha256:469f4febd63c26b20132e54cc40048d5698123794b103758ccd21b8a45890dc3", - "sha256:49efc420e36d2e8adc5dae41c2c1e8bb37a069e40a880cbe414a032136b194b0", - "sha256:544a7ee271fac41ddc0ba11f4b128ddd5f2bf0a3186d25be331ed8bfbb253536", - "sha256:55f390adb763196d75a2e8c18277b4344f8a7f94f223b5d096324c5b47c2471e", - "sha256:5736c9a54c27319a65ffc72dbf684538f2773237e94ba50b7f1f74f4e3cb9115", - "sha256:580dd4b1c2edd51f284df0209bf439899f425ed00cb803a85ddc6cf10c866688", - "sha256:58176e2437462568b5099acf17401be64205e175e72767a8250eef84ee9ec4f5", - "sha256:5b48b7e417c56486932fb0c01fecd24916fe6bc359c03a654aa8c63fa33e3d76", - "sha256:5d7fcc648445dbfd6ce9973ec7b4a33ee9307b7e88cf4816f4403ccbaf8de9ca", - "sha256:60f91afc76a3fc5d65dfba4f6b6020c462674b5eab6cbf00dec133d79656072d", - "sha256:694625c2c22be57149e9439757ee02ee4fb6432f7054dc5008bbbc33ef388d1c", - "sha256:6d3d7ef786e778351e6c51b45906e16506ad98bb78b99304032cb1876dfc81d2", - "sha256:6e0e94ca9a8f23000d54e11ecd727b69fb1994baf3b6b1eedb881cdd3196ecec", - "sha256:7129efc54dc48f566eed5422bc555ba4e472e40a1f9de328577c90ade47ccf5d", - "sha256:71a8f010e23dfd61c531084a2b72a81885017da28352540f0b7799ca8423c044", - "sha256:72340614ea23904cff824109eb025648bdf32775d87f5814d3ba6f2335a853f3", - "sha256:72ae3078b1c47552e0e39fd81fc0472e880316897a733dbb3570819be19da48a", - "sha256:7353d231686bbc96c458b934f134ff9165a1e9dd0a2ea8f724469e44bcc2c07a", - "sha256:7a1cc0445038a394479ad36b7e3cf55a19ee40099c031f65de872b8ee7025e79", - "sha256:80fdea3e9e34c480bfccbb910f75380196ae9d1c12880c21743c845ebe6b13aa", - "sha256:814245422f1c7707634397621dbcbeea7671fdc5c43d1ae592f4e0e45179e7fb", - "sha256:8783857a8c8df648a70c81ea3ff53ee71e5bf18468ca5ac3414f419fe8f3bd93", - "sha256:8a5b4dc4d7a3f859026083906724ad1ae743261548b61d0d5abcf2d994122c2b", - "sha256:903b77dd2f17286496fa3ec902bc523f4502b0c64a2892df4b021222a2ba95fe", - "sha256:90ba8f7c6f34c2c11179b293050417c14661035969ef3f8867200ea6901f9000", - "sha256:952e85c5e86f9ba100b78b60719b76e1ff3e13bb403cb6de687bb92e7b2179e7", - "sha256:9691a6ab55d011e83d7438f6711b93b7f8aa21ee8cf3e7ad6d6d9ea26a8f3a1f", - "sha256:9982799d7d7807beb1b26f1aa9a192baccb1a14c5d00eca881a42a0ae562671b", - "sha256:9ce158ab54994c60fdde83300dc1e447446baacbe4ec9e4e80096f9b9a125c13", - "sha256:9d68284ce48617c97e675ed8a89db12a098eaa871a026999c9a10351f547f1fe", - "sha256:a0562054930471b386a44b0887504687c4e7adf4ba89bddc2e5959d16c371764", - "sha256:a2b13008a693c0ffccaeeebcc5ab5f2398cced3b5bf482ba89a38fe56b00eb10", - "sha256:a5207bc2a923118e9afb57fee679be016ea138c27d1be5747118966e2d5d9450", - "sha256:a824b3301ddd003cdceb9b537804e751ac5922a845b19d4e50b4789d1cd28b24", - "sha256:a86409f3f8eae7af5a47babd831a119bdf552e831f04d2225a313305e8e35e7c", - "sha256:aa7431d12ebb5433a92e99dc326d45eaf52a90046032bac4c558b4bdeee5dc7a", - "sha256:ab2e55046263c8b24e64116e80b63cf701df747b44aadcf317aa47c8af2dfe67", - "sha256:abc08b2e688714216870a6ab974733d4a1fcf0437d250ac8feed59c4c5c3f395", - "sha256:ac6f54c399638858e0b2a3153f23934604f3a8c9bb5a9cf865060cc658b1e096", - "sha256:af9f5b1b76753584c871c1c96db8a18650886b3adf9fc8c7d4019343eb329c28", - "sha256:b377b520e618c30c827966c274dd62ce7e15c72ce8767fae6193b6bdd1deb502", - "sha256:bd3537f049dc0488adb3df29a77635eaff2a8d1d3d29a09714db6e2d10caba1a", - "sha256:c2e36399f0433b14a91f956bd7ecf94799c57a6f992889d45440cb05b3de8025", - "sha256:c919895132cae5a458d5a17047fd33c9eb271f15bb3485add34429cfd7b76a71", - "sha256:c952cf06edbbd2d67f627037e2c8e3187ca834d6b9a222e3a3037f80d393a345", - "sha256:ca4ebbef3f5fbd271eafc7c22ebbb88b74232f08b0e51759113f30a8d01f6843", - "sha256:cac954dc83c84e9d9d65f2359d402d7e79ae094d7808d578c9e9cc2c350c5a64", - "sha256:cc98fbd4ce4ef8a0fbe97ab6d495aaa7764461e5a45f24c04f1d234e7bb80293", - "sha256:cd62830100b9b1adb51da4094142bd680d51daf9a0f6f3f39e1f80474eddc011", - "sha256:ce2c53f4963a358ba91b58ccecb84fab6d5f0622230d105c2589f7556ec53cc9", - "sha256:d36a46975925b8bf14b69fe6d4097bc96c91f94ceb954d56853a2211a5cc3433", - "sha256:d492921b398d640a1f796306531bc6911a94ce5528b798ed14e0620abd9b948d", - "sha256:dc7badded4b025dbc25f34b95503b71c952235e6e40de40995c0c120efb4ff6d", - "sha256:dcac700269d081ded42ed3833f9d0effe734148376204af9c0ef0fd25a3fea55", - "sha256:dd13a30454adcf2f361155ea563ec99036678131a17c6b1a3f74426212c14ddc", - "sha256:dd87df01bc8eca392f0d505924087ccafdc4885a498e68df9f09eca9fdc736f1", - "sha256:e0c08a6070358a2984900a4518e2dacbfaf24aac018ab086d7ac2f6069b13340", - "sha256:e495ff09514fc657c5fb2cba0aac082ce0494c6217230783297da9008333a8db", - "sha256:eae3dcc185c405cf645480745c45346a1f42afce240f69a589095e41bd2b9e3d", - "sha256:ed127aff75a3df142ae7a883c49a85b0b2f863b59fa1b8e4280335f5ebab5fd0", - "sha256:f66c925f62ce28946525c32a094e346dd8da6c828d568d7ecda97f5ae36089c3", - "sha256:f6f618d7d7c9c37053a36e6dc5435c53e9e0c7a67e6fd00b69c209d07a8db4dc", - "sha256:f85bb2c47b5fd70e3cbb280e380ab97bdf9f02e1a363cb472fe0a297ac24029d", - "sha256:f971e77358384b8bcf3e9a7577cf84f97adbd6359f943e30cbff66087afcb279", - "sha256:fc907b26d287e6981d1e531c8fc21a0f94fe46a17493a8322eb3c75f8b561334" + "sha256:01fbfbeb8249a68d257f601deb50c70c929dc2dfe683b754659569e502fbd3aa", + "sha256:0270b49b6847f0d106d64b5086e9ad5dc8a902413b5dbbb15d12b60f9c1747a4", + "sha256:03c0ae165e700364b266876d712acb1ac02693acd920afa67da2ebb91a0b3c09", + "sha256:068ca17214038ae986d68f4a7021f97e187ed278ab6dccb79f837d765a54d753", + "sha256:082a2988364b60bb5de809373098361cf1dbb239623e39e46cb18bc035ed9c0c", + "sha256:0aaf982e68a7ac284377d051c742610220fd06d330dcd4c4dbb4cdd77c22a537", + "sha256:0c0991f5a96a8e620f7691e61178cd8f457b49e17b7d9cfa2067e2a0a89fc1d5", + "sha256:115f8359402fa527cf47708d6f8a0f8234f0e9ca0cab7c18c9c189c194dbf620", + "sha256:15c59e780be8f30a60816a9adab900c12a58d79c1ac742b4a8df044ab2a6d920", + "sha256:1b7d0e124948daa4d9686d421ef5087c0516bc6179fdcf8828b8444f8e461a77", + "sha256:1c8eb19abe87029c18f226d42b8a2c9efdd139d08f8bf6e085dd9075446db450", + "sha256:204e0f176fd1d067671157d049466869b3ae1fc51e354708b0dc41cf94e23a3a", + "sha256:2136f64fbb86451dbbf70223635a468272dd20075f988a102bf8a3f194a411dc", + "sha256:2b291d1230845871c00c8462c50565a9cd6026fe1228e77ca934470bb7d70ea0", + "sha256:2c18645ef6294d99b256806e34653e86236eb266278c8ec8112622b61db255de", + "sha256:2cc4e280098c1b192c42a849de8de2c8e0f3a84086a76ec5b07bfee29bda7d18", + "sha256:2ed8357f4c6e0daa4f3baf31832df8a33334e0fe5b020a61bc8b345a3db7a606", + "sha256:3191d312c73e3cfd0f0afdf51df8405aafeb0bad71e7ed8f68b24b63c4f36500", + "sha256:3401613148d93ef0fd9aabdbddb212de3db7a4475367f49f590c837355343972", + "sha256:34106f68e20e6ff253c9f596ea50397dbd8699828d55e8fa18bd4323d8d966e6", + "sha256:3516119f4f9b8671083a70b6afaa0a070f5683e431ab3dc26e9215620d7ca1ad", + "sha256:38ece17ec5f20d7d9b442e5174ae9f020365d01ba7c112205a4d59cf19dc38ee", + "sha256:3b4032a96410bdc760061b14ed6a33613ffb7f702181ba999df5d16fb96ba16a", + "sha256:3bf8b000a4e2967e6dfdd8656cd0757d18c7e5ce3d16339e550bd462f4857e59", + "sha256:3e3070e680f79887d60feeda051a58d0ac36622e1759f305a41059eff62c6da7", + "sha256:4496b1282c70c442809fc1b151977c3d967bfb33e4e17cedbf226d97de18f709", + "sha256:44dd6fc3034f1eaa72ece33588867df9e006a7303725a12d64c3dff92330f625", + "sha256:4adfbb5451196842a88fda3612e2c0414134874bffb1c2ce83ab4242ec9e027d", + "sha256:4b7c0c0b3244bb2275abe255d4a30c050d541c6cb18b870975553f1fb6f37527", + "sha256:4c82a6d952a1d555bf4be42b6532927d2a5686dd3c3e280e5f63225ab47ac1f5", + "sha256:5344b896e79800af86ad643408ca9aa303a017f6ebff8cee5a3163c1e9aec987", + "sha256:5bde86a2ed3ce587fa2b207424ce15b9a83a9fa14422dcc1c5356a13aed3df9d", + "sha256:5bf6c237f8c681dfb91b17f8435b2735951f0d1fad10cc5dfd96db110243370b", + "sha256:5dbb9c997932473a27afa93954bb77a9f9b786b4ccf718d903f35da3232317de", + "sha256:69ea9d6d9baa25a4dc9cef5e2b77b8537827b122214f210dd925132e34ae9b12", + "sha256:6b3146f9ae6af82c47a5282ac8803523d381b3b21caeae0327ed2f7ecb718798", + "sha256:6bcb34f869d431799c3ee7d516554797f7760cb2198ecaa89c3f176f72d062be", + "sha256:6ca08b840fe95d1c2bd9ab92dac5685f949fc6f9ae820ec16193e5ddf603c3b2", + "sha256:6ca7a9a06b52d0e38ccf6bca1aeff7be178917893f3883f37b75589d42c4ac20", + "sha256:703c60b9910488d3d0954ca585c34f541e506a091a41930e663a098d3b794c67", + "sha256:715bdf952b9533ba13dfcf1f431a8f49e63cecc31d91d007bc1deb914f47d0e4", + "sha256:72b67f966b57dbd18dcc7efbc1c7fc9f5f983e572db1877081f075004614fcdd", + "sha256:74423631b6be371edfbf7eabb02ab995c2563fee60a80a30829176842e71722a", + "sha256:77a85dca4c2430ac04dc2a2185c2deb3858a34fe7f403d0a946fa56970cf60a1", + "sha256:7821d44fe07335bea256b9f1f41474a642ca55fa671dfd9f00af8d68a920c2d4", + "sha256:788f15721c64109cf720791714dc14afd0f449d63f3a5487724f024345067381", + "sha256:7ca684ee649b55fd8f378127ac8462fb6c85f251c2fb027eb3c887e8ee347bcd", + "sha256:7daa3e1369355766dea11f1d8ef829905c3b9da886ea3152788dc25ee6079e02", + "sha256:7e6bc96ebe49604df3ec2c6389cc3876cabe475e6bfc84ced1bf4e630662cb35", + "sha256:80b12f25d805a919d53efc0a5ad7c0c0326f13b4eae981a5d7b7cc343318ebb7", + "sha256:871587bdadd1075b112e697173e946a07d722459d20716ceb3d1bd6c64bd08ce", + "sha256:88b88282e55fa39dd556d7fc04160bcf39dea015f78e0cecec8ff4f06c1fc2b5", + "sha256:8d7a498671ca87e32b54cb47c82a92b40130a26c5197d392720a1bce1b3c77cf", + "sha256:926838a535c2c1ea21c903f909a9a54e675c2126728c21381a94ddf37c3cbddf", + "sha256:971e8990c5cc4ddcff26e149398fc7b0f6a042306e82500f5e8db3b10ce69f84", + "sha256:9b273ecfbc590a1b98f014ae41e5cf723932f3b53ba9367cfb676f838038b32c", + "sha256:a42db008d58530efa3b881eeee4991146de0b790e095f7ae43ba5cc612decbc5", + "sha256:a72a84570f84c374b4c287183debc776dc319d3e8ce6b6a0041ce2e400de3f32", + "sha256:ac97a21de3712afe6a6c071abfad40a6224fd14fa6ff0ff8d0c6e6cd4e2f807a", + "sha256:acb704195a71ac5ea5ecf2811c9ee19ecdc62b91878528302dd0be1b9451cc90", + "sha256:b32bff85fb02a75ea0b68f21e2412255b5731f3f389ed9aecc13a6752f58ac97", + "sha256:b3cd31f859b662ac5d7f4226ec7d8bd60384fa037fc02aee6ff0b53ba29a3ba8", + "sha256:b63731993cdddcc8e087c64e9cf003f909262b359110070183d7f3025d1c56b5", + "sha256:b6907da3017ef55139cf0e417c5123a84c7332520e73a6902ff1f79046cd3b94", + "sha256:ba6e5e6588e49139a0979d03a7deb9c734bde647b9a8808f26acf9c547cab1bf", + "sha256:c1c8f2a2ca45292084c75bb6d3a25545cff0ed931ed228d3a1810ae3758f975f", + "sha256:ce828058d482ef860746bf532822842e0ff484e27f540ef5c813d516dd8896d2", + "sha256:d0a2d1bd63a4ad79483049b26514e70fa618ce6115220da9efdff63688808b17", + "sha256:d0cdde3c78d8ab5b46595054e5def32a755fc028685add5ddc7403e9f6de9879", + "sha256:d57dfbf9737763b3a60d26e6800e02e04284926329aee8fb01049635e957fe81", + "sha256:d8416c23161abd94cc7da80c734ad7c9f5dbebdadfdaa77dad78244457448223", + "sha256:dba7d9f2e047dfa2bca3b01f4f84aa5246725203d6284e3790f2ca15fba6b40a", + "sha256:dbf012d8fcb9f2cf0643b65df3b355fdd74fc0035d70bb5c845e9e30a3a4654b", + "sha256:e1258c639e00bf5e8a522fec6c3eaa3e30cf1c23a2f21a586be7e04d50c9acab", + "sha256:e222562dc0f38571c8b1ffdae9d7adb866363134299264a1958d077800b193b7", + "sha256:e4946d6bdb7ba972dfda282f9127e5756d4f299028b1566d1245fa0d438847e6", + "sha256:e746524418b70f38550f2190eeee834db8850088c834d4c8406fbb9bc1ae10b2", + "sha256:e76654e9dbfb835b3518f9938e565c7806976c07b37c33526b574cc1a1050480", + "sha256:e8918973fbd34e7814f59143c5f600ecd38b8038161239fd1a3d33d5817a38b8", + "sha256:e891ce81edd463b3b4c3b885c5603c00141151dd9c6936d98a680c8c72fe5c67", + "sha256:ebbbd0e728af5db9b04e56389e2299a57ea8b9dd15c9759153ee2455b32be6ad", + "sha256:eeb438a26d87c123bb318e5f2b3d86a36060b01f22fbdffd8cf247d52f7c9a2b", + "sha256:eed56b6a39216d31ff8cd2f1d048b5bf1700e4b32a01b14379c3b6dde9ce3aa3", + "sha256:f17cde1db0754c35a91ac00b22b25c11da6eec5746431d6e5092f0cd31a3fea9", + "sha256:f1a9b7d00fdf60b4039f4455afd031fe85ee8305b019334b72dcf73c567edc47", + "sha256:f4b6cecbbf3b7380f3b61de3a7b93cb721125dc125c854c14ddc91225ba52f83", + "sha256:f6b1d1c631e5940cac5a0b22c5379c86e8df6a4ec277c7a856b714021ab6cfad", + "sha256:f6c21c00478a7bea93caaaef9e7629145d4153b15a8653e8bb4609d4bc70dbfc" ], "markers": "python_version >= '3.7'", - "version": "==26.0.0" + "version": "==26.0.3" }, "readme-renderer": { "hashes": [ @@ -1340,11 +1332,11 @@ }, "referencing": { "hashes": [ - "sha256:5773bd84ef41799a5a8ca72dc34590c041eb01bf9aa02632b4a973fb0181a844", - "sha256:d53ae300ceddd3169f1ffa9caf2cb7b769e92657e4fafb23d34b93679116dfd4" + "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c", + "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de" ], "markers": "python_version >= '3.8'", - "version": "==0.34.0" + "version": "==0.35.1" }, "requests": { "hashes": [ @@ -1540,12 +1532,12 @@ }, "sphinx": { "hashes": [ - "sha256:d6c09acd42094fcd96a9299c1b32b2dafe82d667fdd6e532e5978443ad074c2a", - "sha256:fc9f3d13fed5c9a0e677d368090e209899ce5d0081eb552b657e2923e57517f0" + "sha256:413f75440be4cacf328f580b4274ada4565fb2187d696a84970c23f77b64d8c3", + "sha256:a4a7db75ed37531c05002d56ed6948d4c42f473a36f46e1382b0bd76ca9627bc" ], "index": "pypi", "markers": "python_version >= '3.9'", - "version": "==7.3.6" + "version": "==7.3.7" }, "sphinxcontrib-applehelp": { "hashes": [ @@ -1612,11 +1604,11 @@ }, "tinycss2": { "hashes": [ - "sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847", - "sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627" + "sha256:152f9acabd296a8375fbca5b84c961ff95971fcfc32e79550c8df8e29118c54d", + "sha256:54a8dbdffb334d536851be0226030e9505965bb2f30f21a4a82c55fb2a80fae7" ], - "markers": "python_version >= '3.7'", - "version": "==1.2.1" + "markers": "python_version >= '3.8'", + "version": "==1.3.0" }, "tornado": { "hashes": [ @@ -1637,11 +1629,11 @@ }, "traitlets": { "hashes": [ - "sha256:8cdd83c040dab7d1dee822678e5f5d100b514f7b72b01615b26fc5718916fdf9", - "sha256:fcdf85684a772ddeba87db2f398ce00b40ff550d1528c03c14dbf6a02003cd80" + "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", + "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f" ], "markers": "python_version >= '3.8'", - "version": "==5.14.2" + "version": "==5.14.3" }, "twine": { "hashes": [ @@ -1660,14 +1652,6 @@ "markers": "python_version >= '3.8'", "version": "==2.9.0.20240316" }, - "typing-extensions": { - "hashes": [ - "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0", - "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a" - ], - "markers": "python_version < '3.12'", - "version": "==4.11.0" - }, "tzdata": { "hashes": [ "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd", @@ -1714,11 +1698,11 @@ }, "websocket-client": { "hashes": [ - "sha256:10e511ea3a8c744631d3bd77e61eb17ed09304c413ad42cf6ddfa4c7787e8fe6", - "sha256:f4c3d22fec12a2461427a29957ff07d35098ee2d976d3ba244e688b8b4057588" + "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", + "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da" ], "markers": "python_version >= '3.8'", - "version": "==1.7.0" + "version": "==1.8.0" }, "zipp": { "hashes": [ diff --git a/django_ledger/__init__.py b/django_ledger/__init__.py index 5a85cb7d..22206e05 100644 --- a/django_ledger/__init__.py +++ b/django_ledger/__init__.py @@ -9,7 +9,7 @@ default_app_config = 'django_ledger.apps.DjangoLedgerConfig' """Django Ledger""" -__version__ = '0.6.0.2' +__version__ = '0.6.1' __license__ = 'GPLv3 License' __author__ = 'Miguel Sanda' diff --git a/django_ledger/io/__init__.py b/django_ledger/io/__init__.py index 4c21a497..41d4e43a 100644 --- a/django_ledger/io/__init__.py +++ b/django_ledger/io/__init__.py @@ -6,9 +6,7 @@ Miguel Sanda """ -from django_ledger.io.io_digest import * +from django_ledger.io.io_context import * from django_ledger.io.io_middleware import * from django_ledger.io.ratios import * from django_ledger.io.roles import * -# due to circular import -# from django_ledger.io.io_library import IOLibrary diff --git a/django_ledger/io/io_digest.py b/django_ledger/io/io_context.py similarity index 96% rename from django_ledger/io/io_digest.py rename to django_ledger/io/io_context.py index faa0adb2..5e484ee6 100644 --- a/django_ledger/io/io_digest.py +++ b/django_ledger/io/io_context.py @@ -38,6 +38,10 @@ def get_io_txs_queryset(self): def get_strftime_format(self): return self.STRFTIME_FORMAT + @property + def from_datetime(self): + return self.get_from_datetime() + def get_from_datetime(self, as_str: bool = False, fmt=None) -> Optional[datetime]: from_date = self.IO_DATA['from_date'] if from_date: @@ -47,6 +51,10 @@ def get_from_datetime(self, as_str: bool = False, fmt=None) -> Optional[datetime return from_date.strftime(fmt) return from_date + @property + def to_datetime(self): + return self.get_to_datetime() + def get_to_datetime(self, as_str: bool = False, fmt=None) -> datetime: if as_str: if not fmt: diff --git a/django_ledger/io/io_core.py b/django_ledger/io/io_core.py index afb073ee..62fe131f 100644 --- a/django_ledger/io/io_core.py +++ b/django_ledger/io/io_core.py @@ -36,7 +36,7 @@ from django_ledger import settings from django_ledger.exceptions import InvalidDateInputError, TransactionNotInBalanceError from django_ledger.io import roles as roles_module -from django_ledger.io.io_digest import IODigestContextManager +from django_ledger.io.io_context import IODigestContextManager from django_ledger.io.io_middleware import ( AccountRoleIOMiddleware, AccountGroupIOMiddleware, diff --git a/django_ledger/models/entity.py b/django_ledger/models/entity.py index 9eafe848..d4691904 100644 --- a/django_ledger/models/entity.py +++ b/django_ledger/models/entity.py @@ -116,7 +116,7 @@ def get_queryset(self): qs = EntityModelQuerySet(self.model, using=self._db).order_by('path') return qs.order_by('path').select_related('admin', 'default_coa') - def for_user(self, user_model): + def for_user(self, user_model, authorized_superuser: bool = False): """ This QuerySet guarantees that Users do not access or operate on EntityModels that don't have access to. This is the recommended initial QuerySet. @@ -125,6 +125,8 @@ def for_user(self, user_model): ---------- user_model The Django User Model making the request. + authorized_superuser + Allows any superuser to access the EntityModel. Default is False. Returns ------- @@ -134,7 +136,7 @@ def for_user(self, user_model): 2. Is a manager. """ qs = self.get_queryset() - if user_model.is_superuser: + if user_model.is_superuser and authorized_superuser: return qs return qs.filter( Q(admin=user_model) | diff --git a/django_ledger/models/items.py b/django_ledger/models/items.py index 9c1f0eb1..d2d55cec 100644 --- a/django_ledger/models/items.py +++ b/django_ledger/models/items.py @@ -881,8 +881,6 @@ class ItemTransactionModelManager(models.Manager): def for_user(self, user_model): qs = self.get_queryset() - if user_model.is_superuser: - return qs return qs.filter( Q(item_model__entity__admin=user_model) | Q(item_model__entity__managers__in=[user_model]) @@ -891,7 +889,7 @@ def for_user(self, user_model): def for_entity(self, user_model, entity_slug): qs = self.for_user(user_model) if isinstance(entity_slug, lazy_loader.get_entity_model()): - qs.filter( + return qs.filter( Q(item_model__entity=entity_slug) ) return qs.filter( diff --git a/django_ledger/models/ledger.py b/django_ledger/models/ledger.py index 1e564a84..bba1f4a6 100644 --- a/django_ledger/models/ledger.py +++ b/django_ledger/models/ledger.py @@ -226,7 +226,6 @@ def __str__(self): ledger_str = f'LedgerModel: {self.uuid}' return f'{ledger_str} | Posted: {self.posted} | Locked: {self.locked}' - def has_wrapped_model_info(self): if self.additional_info is not None: return self._WRAPPED_MODEL_KEY in self.additional_info @@ -523,7 +522,7 @@ def lock_journal_entries(self, commit: bool = True, **kwargs): je_model_qs.bulk_update(objs=je_model_qs, fields=['locked', 'updated']) return je_model_qs - def unlock(self, commit: bool = False, **kwargs): + def unlock(self, commit: bool = False, raise_exception: bool = True, **kwargs): """ Un-locks the LedgerModel. @@ -532,13 +531,19 @@ def unlock(self, commit: bool = False, **kwargs): commit: bool If True, saves the LedgerModel instance instantly. Defaults to False. """ - if self.can_unlock(): - self.locked = False - if commit: - self.save(update_fields=[ - 'locked', - 'updated' - ]) + if not self.can_unlock(): + if raise_exception: + raise LedgerModelValidationError( + message=_(f'Ledger {self.name} cannot be un-locked. UUID: {self.uuid}') + ) + return + + self.locked = False + if commit: + self.save(update_fields=[ + 'locked', + 'updated' + ]) def hide(self, commit: bool = False, raise_exception: bool = True, **kwargs): if not self.can_hide(): diff --git a/django_ledger/models/mixins.py b/django_ledger/models/mixins.py index e7b66caa..5c5a5946 100644 --- a/django_ledger/models/mixins.py +++ b/django_ledger/models/mixins.py @@ -487,7 +487,8 @@ def lock_ledger(self, commit: bool = False, raise_exception: bool = True, **kwar if ledger_model.locked: if raise_exception: raise ValidationError(f'Bill ledger {ledger_model.name} is already locked...') - ledger_model.lock(commit) + return + ledger_model.lock(commit, raise_exception=raise_exception) def unlock_ledger(self, commit: bool = False, raise_exception: bool = True, **kwargs): """ @@ -501,10 +502,11 @@ def unlock_ledger(self, commit: bool = False, raise_exception: bool = True, **kw If True, raises ValidationError if LedgerModel already locked. """ ledger_model = self.ledger - if not ledger_model.locked: + if not ledger_model.is_locked(): if raise_exception: raise ValidationError(f'Bill ledger {ledger_model.name} is already unlocked...') - ledger_model.unlock(commit) + return + ledger_model.unlock(commit, raise_exception=raise_exception) # POST/UNPOST Ledger... def post_ledger(self, commit: bool = False, raise_exception: bool = True, **kwargs): @@ -522,7 +524,8 @@ def post_ledger(self, commit: bool = False, raise_exception: bool = True, **kwar if ledger_model.posted: if raise_exception: raise ValidationError(f'Bill ledger {ledger_model.name} is already posted...') - ledger_model.post(commit) + return + ledger_model.post(commit, raise_exception=raise_exception) def unpost_ledger(self, commit: bool = False, raise_exception: bool = True, **kwargs): """ @@ -536,13 +539,14 @@ def unpost_ledger(self, commit: bool = False, raise_exception: bool = True, **kw If True, raises ValidationError if LedgerModel already locked. """ ledger_model = self.ledger - if not ledger_model.posted: + if not ledger_model.is_posted(): if raise_exception: raise ValidationError(f'Bill ledger {ledger_model.name} is not posted...') - ledger_model.post(commit) + return + ledger_model.post(commit, raise_exception=raise_exception) def migrate_state(self, - # todo: remove usermodel param... + # todo: remove usermodel param...? user_model, entity_slug: str, itemtxs_qs: Optional[QuerySet] = None, diff --git a/django_ledger/models/transactions.py b/django_ledger/models/transactions.py index b0205934..ff0b9f61 100644 --- a/django_ledger/models/transactions.py +++ b/django_ledger/models/transactions.py @@ -49,35 +49,6 @@ class TransactionModelQuerySet(QuerySet): """ A custom QuerySet class for TransactionModels implementing methods to effectively and safely read TransactionModels from the database. - - Methods - ------- - posted() -> TransactionModelQuerySet: - Fetches a QuerySet of posted transactions only. - - for_accounts(account_list: List[str or AccountModel]) -> TransactionModelQuerySet: - Fetches a QuerySet of TransactionModels which AccountModel has a specific role. - - for_roles(role_list: Union[str, List[str]]) -> TransactionModelQuerySet: - Fetches a QuerySet of TransactionModels which AccountModel has a specific role. - - for_unit(unit_slug: Union[str, EntityUnitModel]) -> TransactionModelQuerySet: - Fetches a QuerySet of TransactionModels associated with a specific EntityUnitModel. - - for_activity(activity_list: Union[str, List[str]]) -> TransactionModelQuerySet: - Fetches a QuerySet of TransactionModels associated with a specific activity or list of activities. - - to_date(to_date: Union[str, date, datetime]) -> TransactionModelQuerySet: - Fetches a QuerySet of TransactionModels associated with a maximum date or timestamp filter. - - from_date(from_date: Union[str, date, datetime]) -> TransactionModelQuerySet: - Fetches a QuerySet of TransactionModels associated with a minimum date or timestamp filter. - - not_closing_entry() -> TransactionModelQuerySet: - Fetches a QuerySet of TransactionModels that are not part of a closing entry. - - is_closing_entry() -> TransactionModelQuerySet: - Fetches a QuerySet of TransactionModels that are part of a closing entry. """ def posted(self) -> QuerySet: @@ -111,7 +82,7 @@ def for_accounts(self, account_list: List[str or AccountModel]): TransactionModelQuerySet Returns a TransactionModelQuerySet with applied filters. """ - if len(account_list) > 0 and isinstance(account_list[0], str): + if isinstance(account_list, list) > 0 and isinstance(account_list[0], str): return self.filter(account__code__in=account_list) return self.filter(account__in=account_list) @@ -276,8 +247,6 @@ def for_user(self, user_model) -> TransactionModelQuerySet: ledger or the user is one of the managers of the entity associated with the transaction's ledger. """ qs = self.get_queryset() - if user_model.is_superuser: - return qs return qs.filter( Q(journal_entry__ledger__entity__admin=user_model) | Q(journal_entry__ledger__entity__managers__in=[user_model]) diff --git a/django_ledger/views/mixins.py b/django_ledger/views/mixins.py index ce23c90d..f1928383 100644 --- a/django_ledger/views/mixins.py +++ b/django_ledger/views/mixins.py @@ -311,25 +311,20 @@ def get_entity_slug_kwarg(self): ) return self.ENTITY_SLUG_URL_KWARG + def get_superuser_authorization(self): + return self.AUTHORIZE_SUPERUSER + def has_permission(self): + has_perm = super().has_permission() + if not has_perm: + return False + entity_slug_kwarg = self.get_entity_slug_kwarg() - if self.request.user.is_superuser: - if not self.AUTHORIZE_SUPERUSER: - return False - if entity_slug_kwarg in self.kwargs: - try: - entity_model_qs = self.get_authorized_entity_queryset() - self.AUTHORIZED_ENTITY_MODEL = entity_model_qs.get(slug__exact=self.kwargs[entity_slug_kwarg]) - except ObjectDoesNotExist: - return False - return True - elif self.request.user.is_authenticated: - has_perm = super().has_permission() - if not has_perm: - return False + entity_model_qs = self.get_authorized_entity_queryset() + + if self.request.user.is_authenticated: if entity_slug_kwarg in self.kwargs: try: - entity_model_qs = self.get_authorized_entity_queryset() self.AUTHORIZED_ENTITY_MODEL = entity_model_qs.get(slug__exact=self.kwargs[entity_slug_kwarg]) except ObjectDoesNotExist: return False @@ -338,7 +333,9 @@ def has_permission(self): def get_authorized_entity_queryset(self): return EntityModel.objects.for_user( - user_model=self.request.user).only( + user_model=self.request.user, + authorized_superuser=self.get_superuser_authorization(), + ).only( 'uuid', 'slug', 'name', 'default_coa', 'admin') def get_authorized_entity_instance(self) -> Optional[EntityModel]: @@ -372,8 +369,26 @@ def get_context_data(self, **kwargs): class DigestContextMixIn: - IO_DIGEST = False - IO_DIGEST_EQUITY = False + IO_DIGEST_UNBOUNDED = False + IO_DIGEST_BOUNDED = False + + IO_DIGEST_UNBOUNDED_CONTEXT_NAME = 'tx_digest' + IO_MANAGER_UNBOUNDED_CONTEXT_NAME = 'tx_digest_context' + + IO_DIGEST_BOUNDED_CONTEXT_NAME = 'equity_digest' + IO_MANAGER_BOUNDED_CONTEXT_NAME = 'equity_digest_context' + + def get_io_digest_unbounded_context_name(self): + return self.IO_DIGEST_UNBOUNDED_CONTEXT_NAME + + def get_io_manager_unbounded_context_name(self): + return self.IO_MANAGER_UNBOUNDED_CONTEXT_NAME + + def get_io_digest_bounded_context_name(self): + return self.IO_DIGEST_BOUNDED_CONTEXT_NAME + + def get_io_manager_bounded_context_name(self): + return self.IO_MANAGER_BOUNDED_CONTEXT_NAME def get_context_data(self, **kwargs): context = super(DigestContextMixIn, self).get_context_data(**kwargs) @@ -385,8 +400,8 @@ def get_io_digest(self, to_date=None, **kwargs): - if any([self.IO_DIGEST, - self.IO_DIGEST_EQUITY]): + if any([self.IO_DIGEST_UNBOUNDED, + self.IO_DIGEST_BOUNDED]): by_period = self.request.GET.get('by_period') entity_model: EntityModel = self.object @@ -401,7 +416,7 @@ def get_io_digest(self, else: unit_slug = None - if self.IO_DIGEST: + if self.IO_DIGEST_UNBOUNDED: io_digest = entity_model.digest(user_model=self.request.user, to_date=to_date, unit_slug=unit_slug, @@ -410,10 +425,10 @@ def get_io_digest(self, process_roles=True, process_groups=True) - context['tx_digest_context'] = io_digest - context['tx_digest'] = io_digest.get_io_data() + context[self.get_io_manager_unbounded_context_name()] = io_digest + context[self.get_io_digest_unbounded_context_name()] = io_digest.get_io_data() - if self.IO_DIGEST_EQUITY: + if self.IO_DIGEST_BOUNDED: io_digest_equity = entity_model.digest(user_model=self.request.user, equity_only=True, to_date=to_date, @@ -424,8 +439,8 @@ def get_io_digest(self, process_roles=False, process_groups=True) - context['equity_digest_context'] = io_digest_equity - context['equity_digest'] = io_digest_equity.get_io_data() + context[self.get_io_manager_bounded_context_name()] = io_digest_equity + context[self.get_io_digest_bounded_context_name()] = io_digest_equity.get_io_data() # todo: how is this used??.... context['date_filter'] = to_date diff --git a/pyproject.toml b/pyproject.toml index 6a8d4a5f..c9ebaef6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "django-ledger" -version = "0.6.0.2" +version = "0.6.1" readme = "README.md" requires-python = ">=3.10" description = "Double entry accounting system built on the Django Web Framework."