From 929c66930f44146d01c211e4b31ae617bd71b910 Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Wed, 21 Aug 2024 20:44:25 +0100 Subject: [PATCH 01/20] Add DRF csv renderer --- Pipfile | 1 + Pipfile.lock | 872 +++++++++++++++++++++++++++------------------------ 2 files changed, 455 insertions(+), 418 deletions(-) diff --git a/Pipfile b/Pipfile index 65e0bd6e7..e412a9c1f 100644 --- a/Pipfile +++ b/Pipfile @@ -76,6 +76,7 @@ psycopg = "~=3.1.18" django-log-formatter-asim = "~=0.0.5" dbt-copilot-python = "~=0.2.1" dj-database-url = "~=2.2.0" +djangorestframework-csv = "~=3.0.2" [requires] python_version = "3.9" diff --git a/Pipfile.lock b/Pipfile.lock index 51e17732a..e9a919fec 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "7d90ec10377b963c00f65731b10d47d9a279d41d157509323d138fdcf307b99d" + "sha256": "7807d0e7e445d981669421aab87a389ee7ca862f4b0d3268d27d94735b4646f8" }, "pipfile-spec": 6, "requires": { @@ -124,61 +124,76 @@ }, "cffi": { "hashes": [ - "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc", - "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a", - "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417", - "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab", - "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520", - "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36", - "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743", - "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8", - "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed", - "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684", - "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56", - "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324", - "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d", - "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235", - "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e", - "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088", - "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000", - "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7", - "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e", - "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673", - "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c", - "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe", - "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2", - "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098", - "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8", - "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a", - "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0", - "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b", - "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896", - "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e", - "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9", - "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2", - "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b", - "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6", - "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404", - "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f", - "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0", - "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4", - "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc", - "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936", - "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba", - "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872", - "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb", - "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614", - "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1", - "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d", - "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969", - "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b", - "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4", - "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627", - "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956", - "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357" + "sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f", + "sha256:0a048d4f6630113e54bb4b77e315e1ba32a5a31512c31a273807d0027a7e69ab", + "sha256:0bb15e7acf8ab35ca8b24b90af52c8b391690ef5c4aec3d31f38f0d37d2cc499", + "sha256:0d46ee4764b88b91f16661a8befc6bfb24806d885e27436fdc292ed7e6f6d058", + "sha256:0e60821d312f99d3e1569202518dddf10ae547e799d75aef3bca3a2d9e8ee693", + "sha256:0fdacad9e0d9fc23e519efd5ea24a70348305e8d7d85ecbb1a5fa66dc834e7fb", + "sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377", + "sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885", + "sha256:1a2ddbac59dc3716bc79f27906c010406155031a1c801410f1bafff17ea304d2", + "sha256:2404f3de742f47cb62d023f0ba7c5a916c9c653d5b368cc966382ae4e57da401", + "sha256:24658baf6224d8f280e827f0a50c46ad819ec8ba380a42448e24459daf809cf4", + "sha256:24aa705a5f5bd3a8bcfa4d123f03413de5d86e497435693b638cbffb7d5d8a1b", + "sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59", + "sha256:331ad15c39c9fe9186ceaf87203a9ecf5ae0ba2538c9e898e3a6967e8ad3db6f", + "sha256:3aa9d43b02a0c681f0bfbc12d476d47b2b2b6a3f9287f11ee42989a268a1833c", + "sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555", + "sha256:4304d4416ff032ed50ad6bb87416d802e67139e31c0bde4628f36a47a3164bfa", + "sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424", + "sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb", + "sha256:48b389b1fd5144603d61d752afd7167dfd205973a43151ae5045b35793232aa2", + "sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8", + "sha256:516a405f174fd3b88829eabfe4bb296ac602d6a0f68e0d64d5ac9456194a5b7e", + "sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9", + "sha256:5bdc0f1f610d067c70aa3737ed06e2726fd9d6f7bfee4a351f4c40b6831f4e82", + "sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828", + "sha256:6327b572f5770293fc062a7ec04160e89741e8552bf1c358d1a23eba68166759", + "sha256:669b29a9eca6146465cc574659058ed949748f0809a2582d1f1a324eb91054dc", + "sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118", + "sha256:6d872186c1617d143969defeadac5a904e6e374183e07977eedef9c07c8953bf", + "sha256:6f76a90c345796c01d85e6332e81cab6d70de83b829cf1d9762d0a3da59c7932", + "sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a", + "sha256:7cbc78dc018596315d4e7841c8c3a7ae31cc4d638c9b627f87d52e8abaaf2d29", + "sha256:856bf0924d24e7f93b8aee12a3a1095c34085600aa805693fb7f5d1962393206", + "sha256:8a98748ed1a1df4ee1d6f927e151ed6c1a09d5ec21684de879c7ea6aa96f58f2", + "sha256:93a7350f6706b31f457c1457d3a3259ff9071a66f312ae64dc024f049055f72c", + "sha256:964823b2fc77b55355999ade496c54dde161c621cb1f6eac61dc30ed1b63cd4c", + "sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0", + "sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a", + "sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195", + "sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6", + "sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9", + "sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc", + "sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb", + "sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0", + "sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7", + "sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb", + "sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a", + "sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492", + "sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720", + "sha256:c815270206f983309915a6844fe994b2fa47e5d05c4c4cef267c3b30e34dbe42", + "sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7", + "sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d", + "sha256:d6bdcd415ba87846fd317bee0774e412e8792832e7805938987e4ede1d13046d", + "sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb", + "sha256:dbc183e7bef690c9abe5ea67b7b60fdbca81aa8da43468287dae7b5c046107d4", + "sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2", + "sha256:dec6b307ce928e8e112a6bb9921a1cb00a0e14979bf28b98e084a4b8a742bd9b", + "sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8", + "sha256:e4094c7b464cf0a858e75cd14b03509e84789abf7b79f8537e6a72152109c76e", + "sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204", + "sha256:eb09b82377233b902d4c3fbeeb7ad731cdab579c6c6fda1f763cd779139e47c3", + "sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150", + "sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4", + "sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76", + "sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e", + "sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb", + "sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91" ], "markers": "python_version >= '3.8'", - "version": "==1.16.0" + "version": "==1.17.0" }, "cfgv": { "hashes": [ @@ -558,20 +573,20 @@ }, "django-queryable-properties": { "hashes": [ - "sha256:68f3ed8cd6f03fb2993eabe1c3235091781f01266397b75319e1e20556991d7f", - "sha256:f272d5b68be3bd3a57004dcbe1f849ba5080a97069ff0f0f858c364a9eafedb6" + "sha256:9a2d35ea6cd33f80ac666f62009006a2373bcfbfc720981a60a9a428585659d1", + "sha256:aaec7d3ea9dc3be44e6114ca1ca705ac0e23b00c5209832aeb1c6ab5c4e9c345" ], "index": "pypi", - "version": "==1.9.2" + "version": "==1.9.3" }, "django-reversion": { "hashes": [ - "sha256:5884e9f77f55c341b3f0a8d3b0af000f060530653776997267c8b1e5349d8fee", - "sha256:c047cc99a9f1ba4aae6db89c3ac243478d6de98ec8a60c7073fcc875d89c5cdb" + "sha256:084d4f117d9e2b4e8dfdfaad83ebb34410a03eed6071c96089e6811fdea82ad3", + "sha256:3309821e5b6fceedcce6b6975f1a9c7fab6ae7c7d0e1276a90e345946fa0dcb8" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==5.0.12" + "markers": "python_version >= '3.8'", + "version": "==5.1.0" }, "django-silk": { "hashes": [ @@ -616,6 +631,14 @@ "markers": "python_version >= '3.8'", "version": "==3.15.2" }, + "djangorestframework-csv": { + "hashes": [ + "sha256:b269b692feda1971e1342f395a21d339c6a16d2961ff64357a9a6188f27af10f", + "sha256:d1bcfbaaeaa5145af6bb0985a36a5bbf2f853d9961c722f69c7b0c9c3bcc269a" + ], + "index": "pypi", + "version": "==3.0.2" + }, "docopt": { "hashes": [ "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491" @@ -766,11 +789,11 @@ }, "googleapis-common-protos": { "hashes": [ - "sha256:0e1c2cdfcbc354b76e4a211a35ea35d6926a835cba1377073c4861db904a1877", - "sha256:c6442f7a0a6b2a80369457d79e6672bb7dcbaab88e0848302497e3ec80780a6a" + "sha256:27a2499c7e8aff199665b22741997e485eccc8645aa9176c7c988e6fae507945", + "sha256:27c5abdffc4911f28101e635de1533fb4cfd2c37fbaa9174587c799fac90aa87" ], "markers": "python_version >= '3.7'", - "version": "==1.63.1" + "version": "==1.63.2" }, "gprof2dot": { "hashes": [ @@ -846,55 +869,55 @@ }, "grpcio": { "hashes": [ - "sha256:03b43d0ccf99c557ec671c7dede64f023c7da9bb632ac65dbc57f166e4970040", - "sha256:0a12ddb1678ebc6a84ec6b0487feac020ee2b1659cbe69b80f06dbffdb249122", - "sha256:0a2813093ddb27418a4c99f9b1c223fab0b053157176a64cc9db0f4557b69bd9", - "sha256:0cc79c982ccb2feec8aad0e8fb0d168bcbca85bc77b080d0d3c5f2f15c24ea8f", - "sha256:1257b76748612aca0f89beec7fa0615727fd6f2a1ad580a9638816a4b2eb18fd", - "sha256:1262402af5a511c245c3ae918167eca57342c72320dffae5d9b51840c4b2f86d", - "sha256:19264fc964576ddb065368cae953f8d0514ecc6cb3da8903766d9fb9d4554c33", - "sha256:198908f9b22e2672a998870355e226a725aeab327ac4e6ff3a1399792ece4762", - "sha256:1de403fc1305fd96cfa75e83be3dee8538f2413a6b1685b8452301c7ba33c294", - "sha256:20405cb8b13fd779135df23fabadc53b86522d0f1cba8cca0e87968587f50650", - "sha256:2981c7365a9353f9b5c864595c510c983251b1ab403e05b1ccc70a3d9541a73b", - "sha256:2c3c1b90ab93fed424e454e93c0ed0b9d552bdf1b0929712b094f5ecfe7a23ad", - "sha256:39b9d0acaa8d835a6566c640f48b50054f422d03e77e49716d4c4e8e279665a1", - "sha256:3b64ae304c175671efdaa7ec9ae2cc36996b681eb63ca39c464958396697daff", - "sha256:4657d24c8063e6095f850b68f2d1ba3b39f2b287a38242dcabc166453e950c59", - "sha256:4d6dab6124225496010bd22690f2d9bd35c7cbb267b3f14e7a3eb05c911325d4", - "sha256:55260032b95c49bee69a423c2f5365baa9369d2f7d233e933564d8a47b893027", - "sha256:55697ecec192bc3f2f3cc13a295ab670f51de29884ca9ae6cd6247df55df2502", - "sha256:5841dd1f284bd1b3d8a6eca3a7f062b06f1eec09b184397e1d1d43447e89a7ae", - "sha256:58b1041e7c870bb30ee41d3090cbd6f0851f30ae4eb68228955d973d3efa2e61", - "sha256:5e42634a989c3aa6049f132266faf6b949ec2a6f7d302dbb5c15395b77d757eb", - "sha256:5e56462b05a6f860b72f0fa50dca06d5b26543a4e88d0396259a07dc30f4e5aa", - "sha256:5f8b75f64d5d324c565b263c67dbe4f0af595635bbdd93bb1a88189fc62ed2e5", - "sha256:62b4e6eb7bf901719fce0ca83e3ed474ae5022bb3827b0a501e056458c51c0a1", - "sha256:6503b64c8b2dfad299749cad1b595c650c91e5b2c8a1b775380fcf8d2cbba1e9", - "sha256:6c024ffc22d6dc59000faf8ad781696d81e8e38f4078cb0f2630b4a3cf231a90", - "sha256:73819689c169417a4f978e562d24f2def2be75739c4bed1992435d007819da1b", - "sha256:75dbbf415026d2862192fe1b28d71f209e2fd87079d98470db90bebe57b33179", - "sha256:8caee47e970b92b3dd948371230fcceb80d3f2277b3bf7fbd7c0564e7d39068e", - "sha256:8d51dd1c59d5fa0f34266b80a3805ec29a1f26425c2a54736133f6d87fc4968a", - "sha256:940e3ec884520155f68a3b712d045e077d61c520a195d1a5932c531f11883489", - "sha256:a011ac6c03cfe162ff2b727bcb530567826cec85eb8d4ad2bfb4bd023287a52d", - "sha256:a3a035c37ce7565b8f4f35ff683a4db34d24e53dc487e47438e434eb3f701b2a", - "sha256:a5e771d0252e871ce194d0fdcafd13971f1aae0ddacc5f25615030d5df55c3a2", - "sha256:ac15b6c2c80a4d1338b04d42a02d376a53395ddf0ec9ab157cbaf44191f3ffdd", - "sha256:b1a82e0b9b3022799c336e1fc0f6210adc019ae84efb7321d668129d28ee1efb", - "sha256:bac71b4b28bc9af61efcdc7630b166440bbfbaa80940c9a697271b5e1dabbc61", - "sha256:bbc5b1d78a7822b0a84c6f8917faa986c1a744e65d762ef6d8be9d75677af2ca", - "sha256:c1a786ac592b47573a5bb7e35665c08064a5d77ab88a076eec11f8ae86b3e3f6", - "sha256:c84ad903d0d94311a2b7eea608da163dace97c5fe9412ea311e72c3684925602", - "sha256:d4d29cc612e1332237877dfa7fe687157973aab1d63bd0f84cf06692f04c0367", - "sha256:e3d9f8d1221baa0ced7ec7322a981e28deb23749c76eeeb3d33e18b72935ab62", - "sha256:e7cd5c1325f6808b8ae31657d281aadb2a51ac11ab081ae335f4f7fc44c1721d", - "sha256:ed6091fa0adcc7e4ff944090cf203a52da35c37a130efa564ded02b7aff63bcd", - "sha256:ee73a2f5ca4ba44fa33b4d7d2c71e2c8a9e9f78d53f6507ad68e7d2ad5f64a22", - "sha256:f10193c69fc9d3d726e83bbf0f3d316f1847c3071c8c93d8090cf5f326b14309" - ], - "markers": "python_version >= '3.8'", - "version": "==1.64.1" + "sha256:05f02d68fc720e085f061b704ee653b181e6d5abfe315daef085719728d3d1fd", + "sha256:078038e150a897e5e402ed3d57f1d31ebf604cbed80f595bd281b5da40762a92", + "sha256:0b2944390a496567de9e70418f3742b477d85d8ca065afa90432edc91b4bb8ad", + "sha256:11f8b16121768c1cb99d7dcb84e01510e60e6a206bf9123e134118802486f035", + "sha256:1c4caafe71aef4dabf53274bbf4affd6df651e9f80beedd6b8e08ff438ed3260", + "sha256:1cbc208edb9acf1cc339396a1a36b83796939be52f34e591c90292045b579fbf", + "sha256:238a625f391a1b9f5f069bdc5930f4fd71b74426bea52196fc7b83f51fa97d34", + "sha256:2a6d8169812932feac514b420daffae8ab8e36f90f3122b94ae767e633296b17", + "sha256:2b91ce647b6307f25650872454a4d02a2801f26a475f90d0b91ed8110baae589", + "sha256:3207ae60d07e5282c134b6e02f9271a2cb523c6d7a346c6315211fe2bf8d61ed", + "sha256:32d60e18ff7c34fe3f6db3d35ad5c6dc99f5b43ff3982cb26fad4174462d10b1", + "sha256:33158e56c6378063923c417e9fbdb28660b6e0e2835af42e67f5a7793f587af7", + "sha256:47d0aaaab82823f0aa6adea5184350b46e2252e13a42a942db84da5b733f2e05", + "sha256:55714ea852396ec9568f45f487639945ab674de83c12bea19d5ddbc3ae41ada3", + "sha256:6c4e62bcf297a1568f627f39576dbfc27f1e5338a691c6dd5dd6b3979da51d1c", + "sha256:76991b7a6fb98630a3328839755181ce7c1aa2b1842aa085fd4198f0e5198960", + "sha256:770bd4bd721961f6dd8049bc27338564ba8739913f77c0f381a9815e465ff965", + "sha256:7a412959aa5f08c5ac04aa7b7c3c041f5e4298cadd4fcc2acff195b56d185ebc", + "sha256:84c901cdec16a092099f251ef3360d15e29ef59772150fa261d94573612539b5", + "sha256:85ae8f8517d5bcc21fb07dbf791e94ed84cc28f84c903cdc2bd7eaeb437c8f45", + "sha256:89c00a18801b1ed9cc441e29b521c354725d4af38c127981f2c950c796a09b6e", + "sha256:8da58ff80bc4556cf29bc03f5fff1f03b8387d6aaa7b852af9eb65b2cf833be4", + "sha256:8e5c4c15ac3fe1eb68e46bc51e66ad29be887479f231f8237cf8416058bf0cc1", + "sha256:a101696f9ece90a0829988ff72f1b1ea2358f3df035bdf6d675dd8b60c2c0894", + "sha256:a2f80510f99f82d4eb825849c486df703f50652cea21c189eacc2b84f2bde764", + "sha256:a70a20eed87bba647a38bedd93b3ce7db64b3f0e8e0952315237f7f5ca97b02d", + "sha256:a80e9a5e3f93c54f5eb82a3825ea1fc4965b2fa0026db2abfecb139a5c4ecdf1", + "sha256:ab5ec837d8cee8dbce9ef6386125f119b231e4333cc6b6d57b6c5c7c82a72331", + "sha256:b67d450f1e008fedcd81e097a3a400a711d8be1a8b20f852a7b8a73fead50fe3", + "sha256:b7ca419f1462390851eec395b2089aad1e49546b52d4e2c972ceb76da69b10f8", + "sha256:b8270b15b99781461b244f5c81d5c2bc9696ab9189fb5ff86c841417fb3b39fe", + "sha256:bc74f3f745c37e2c5685c9d2a2d5a94de00f286963f5213f763ae137bf4f2358", + "sha256:c3655139d7be213c32c79ef6fb2367cae28e56ef68e39b1961c43214b457f257", + "sha256:c97962720489ef31b5ad8a916e22bc31bba3664e063fb9f6702dce056d4aa61b", + "sha256:cabd706183ee08d8026a015af5819a0b3a8959bdc9d1f6fdacd1810f09200f2a", + "sha256:d3a9e35bcb045e39d7cac30464c285389b9a816ac2067e4884ad2c02e709ef8e", + "sha256:d750e9330eb14236ca11b78d0c494eed13d6a95eb55472298f0e547c165ee324", + "sha256:d7df567b67d16d4177835a68d3f767bbcbad04da9dfb52cbd19171f430c898bd", + "sha256:ec6f219fb5d677a522b0deaf43cea6697b16f338cb68d009e30930c4aa0d2209", + "sha256:ec71fc5b39821ad7d80db7473c8f8c2910f3382f0ddadfbcfc2c6c437107eb67", + "sha256:ee6ed64a27588a2c94e8fa84fe8f3b5c89427d4d69c37690903d428ec61ca7e4", + "sha256:f17f9fa2d947dbfaca01b3ab2c62eefa8240131fdc67b924eb42ce6032e3e5c1", + "sha256:f5b5970341359341d0e4c789da7568264b2a89cd976c05ea476036852b5950cd", + "sha256:f79c87c114bf37adf408026b9e2e333fe9ff31dfc9648f6f80776c513145c813", + "sha256:fa36dd8496d3af0d40165252a669fa4f6fd2db4b4026b9a9411cbf060b9d6a15", + "sha256:fe6505376f5b00bb008e4e1418152e3ad3d954b629da286c7913ff3cfc0ff740" + ], + "markers": "python_version >= '3.8'", + "version": "==1.65.5" }, "gunicorn": { "hashes": [ @@ -915,11 +938,11 @@ }, "identify": { "hashes": [ - "sha256:37d93f380f4de590500d9dba7db359d0d3da95ffe7f9de1753faa159e71e7dfa", - "sha256:e5e00f54165f9047fbebeb4a560f9acfb8af4c88232be60a488e9b68d122745d" + "sha256:cb171c685bdc31bcc4c1734698736a7d5b6c8bf2e0c15117f4d469c8640ae5cf", + "sha256:e79ae4406387a9d300332b5fd366d8994f1525e8414984e1a59e058b2eda2dd0" ], "markers": "python_version >= '3.8'", - "version": "==2.5.36" + "version": "==2.6.0" }, "idna": { "hashes": [ @@ -971,11 +994,11 @@ }, "kombu": { "hashes": [ - "sha256:011c4cd9a355c14a1de8d35d257314a1d2456d52b7140388561acac3cf1a97bf", - "sha256:5634c511926309c7f9789f1433e9ed402616b56836ef9878f01bd59267b4c7a9" + "sha256:ad200a8dbdaaa2bbc5f26d2ee7d707d9a1fded353a0f4bd751ce8c7d9f449c60", + "sha256:c8dd99820467610b4febbc7a9e8a0d3d7da2d35116b67184418b51cc520ea6b6" ], "markers": "python_version >= '3.8'", - "version": "==5.3.7" + "version": "==5.4.0" }, "kubi-ecs-logger": { "hashes": [ @@ -1123,11 +1146,11 @@ }, "opentelemetry-propagator-aws-xray": { "hashes": [ - "sha256:49267a1d72b3f04880ac75e24f9ef38fe323e2f3156c4531e0e00c71c0829c0f", - "sha256:6e8be667bbcf17c3d81d70b2a7cdec0b11257ff64d3829ffe75b810ba1b49f86" + "sha256:1c99181ee228e99bddb638a0c911a297fa21f1c3a0af951f841e79919b5f1934", + "sha256:6b2cee5479d2ef0172307b66ed2ed151f598a0fd29b3c01133ac87ca06326260" ], - "markers": "python_version >= '3.6'", - "version": "==1.0.1" + "markers": "python_version >= '3.8'", + "version": "==1.0.2" }, "opentelemetry-proto": { "hashes": [ @@ -1147,11 +1170,11 @@ }, "opentelemetry-sdk-extension-aws": { "hashes": [ - "sha256:dd7cf6fc0e7c8070dbe179348f2f194ca4555601b60efb7264d82fc8df53f4ba", - "sha256:f964b0598793ded268d3329c33829fad33f63a8d9299fe51bf3a743e81fd7c67" + "sha256:4c6e4b9fec01a4a9cfeac5272ce5aae6bc80e080a6bae1e52098746f53a7b32d", + "sha256:9faa9bdf480d1c5c53151dabee75735c94dbde09e4762c68ff5c7bd4aa3408f3" ], - "markers": "python_version >= '3.6'", - "version": "==2.0.1" + "markers": "python_version >= '3.8'", + "version": "==2.0.2" }, "opentelemetry-semantic-conventions": { "hashes": [ @@ -1195,11 +1218,11 @@ }, "phonenumbers": { "hashes": [ - "sha256:3ad2d086fa71e7eef409001b9195ac54bebb0c6e3e752209b558ca192c9229a0", - "sha256:db7ca4970d206b2056231105300753b1a5b229f43416f8c2b3010e63fbb68d77" + "sha256:339e521403fe4dd9c664dbbeb2fe434f9ea5c81e54c0fdfadbaeb53b26a76c27", + "sha256:35b904e4a79226eee027fbb467a9aa6f1ab9ffc3c09c91bf14b885c154936726" ], "index": "pypi", - "version": "==8.13.39" + "version": "==8.13.43" }, "pickleshare": { "hashes": [ @@ -1293,11 +1316,11 @@ }, "pre-commit": { "hashes": [ - "sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a", - "sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5" + "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af", + "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f" ], "markers": "python_version >= '3.9'", - "version": "==3.7.1" + "version": "==3.8.0" }, "prompt-toolkit": { "hashes": [ @@ -1309,29 +1332,29 @@ }, "protobuf": { "hashes": [ - "sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4", - "sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8", - "sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c", - "sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d", - "sha256:c053062984e61144385022e53678fbded7aea14ebb3e0305ae3592fb219ccfa4", - "sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa", - "sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c", - "sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019", - "sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9", - "sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c", - "sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2" + "sha256:051e97ce9fa6067a4546e75cb14f90cf0232dcb3e3d508c448b8d0e4265b61c1", + "sha256:0dc4a62cc4052a036ee2204d26fe4d835c62827c855c8a03f29fe6da146b380d", + "sha256:3319e073562e2515c6ddc643eb92ce20809f5d8f10fead3332f71c63be6a7040", + "sha256:4c8a70fdcb995dcf6c8966cfa3a29101916f7225e9afe3ced4395359955d3835", + "sha256:7e372cbbda66a63ebca18f8ffaa6948455dfecc4e9c1029312f6c2edcd86c4e1", + "sha256:90bf6fd378494eb698805bbbe7afe6c5d12c8e17fca817a646cd6a1818c696ca", + "sha256:ac79a48d6b99dfed2729ccccee547b34a1d3d63289c71cef056653a846a2240f", + "sha256:ba3d8504116a921af46499471c63a85260c1a5fc23333154a427a310e015d26d", + "sha256:bfbebc1c8e4793cfd58589acfb8a1026be0003e852b9da7db5a4285bde996978", + "sha256:db9fd45183e1a67722cafa5c1da3e85c6492a5383f127c86c4c4aa4845867dc4", + "sha256:eecd41bfc0e4b1bd3fa7909ed93dd14dd5567b98c941d6c1ad08fdcab3d6884b" ], "markers": "python_version >= '3.8'", - "version": "==4.25.3" + "version": "==4.25.4" }, "psycopg": { "hashes": [ - "sha256:92d7b78ad82426cdcf1a0440678209faa890c6e1721361c2f8901f0dccd62961", - "sha256:dca5e5521c859f6606686432ae1c94e8766d29cc91f2ee595378c510cc5b0731" + "sha256:32f5862ab79f238496236f97fe374a7ab55b4b4bb839a74802026544735f9a07", + "sha256:898a29f49ac9c903d554f5a6cdc44a8fc564325557c18f82e51f39c1f4fc2aeb" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==3.1.19" + "version": "==3.1.20" }, "ptyprocess": { "hashes": [ @@ -1342,11 +1365,11 @@ }, "pycodestyle": { "hashes": [ - "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c", - "sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4" + "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3", + "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521" ], "markers": "python_version >= '3.8'", - "version": "==2.12.0" + "version": "==2.12.1" }, "pycparser": { "hashes": [ @@ -1366,11 +1389,11 @@ }, "pyjwt": { "hashes": [ - "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de", - "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320" + "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850", + "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c" ], - "markers": "python_version >= '3.7'", - "version": "==2.8.0" + "markers": "python_version >= '3.8'", + "version": "==2.9.0" }, "pypdf2": { "hashes": [ @@ -1383,11 +1406,11 @@ }, "pyphen": { "hashes": [ - "sha256:999b430916ab42ae9912537cd95c074e0c6691e89a9d05999f9b610a68f34858", - "sha256:a430623decac53dc3691241253263cba36b9dd7a44ffd2680b706af368cda2f2" + "sha256:2c006b3ddf072c9571ab97606d9ab3c26a92eaced4c0d59fd1d26988f308f413", + "sha256:b4a4c6d7d5654b698b5fc68123148bb799b3debe0175d1d5dc3edfe93066fc4c" ], "markers": "python_version >= '3.8'", - "version": "==0.15.0" + "version": "==0.16.0" }, "python-dateutil": { "hashes": [ @@ -1397,69 +1420,64 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.9.0.post0" }, - "pytz": { - "hashes": [ - "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812", - "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319" - ], - "version": "==2024.1" - }, "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" ], - "markers": "python_version >= '3.6'", - "version": "==6.0.1" + "markers": "python_version >= '3.8'", + "version": "==6.0.2" }, "redis": { "hashes": [ @@ -1514,11 +1532,11 @@ }, "setuptools": { "hashes": [ - "sha256:01a1e793faa5bd89abc851fa15d0a0db26f160890c7102cd8dce643e886b47f5", - "sha256:d9b8b771455a97c8a9f3ab3448ebe0b29b5e105f1228bba41028be116985a267" + "sha256:b208925fcb9f7af924ed2dc04708ea89791e24bde0d3020b27df0e116088b34e", + "sha256:d59a3e788ab7e012ab2c4baed1b376da6366883ee20d7a5fc426816e3d7b1193" ], "markers": "python_version >= '3.8'", - "version": "==70.1.0" + "version": "==73.0.1" }, "six": { "hashes": [ @@ -1744,11 +1762,11 @@ }, "zipp": { "hashes": [ - "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19", - "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c" + "sha256:0145e43d89664cfe1a2e533adc75adafed82fe2da404b4bbb6b026c0157bdb31", + "sha256:58da6168be89f0be59beb194da1250516fdaa062ccebd30127ac65d30045e10d" ], "markers": "python_version >= '3.8'", - "version": "==3.19.2" + "version": "==3.20.0" }, "zope.event": { "hashes": [ @@ -1760,45 +1778,43 @@ }, "zope.interface": { "hashes": [ - "sha256:00b5c3e9744dcdc9e84c24ed6646d5cf0cf66551347b310b3ffd70f056535854", - "sha256:0e4fa5d34d7973e6b0efa46fe4405090f3b406f64b6290facbb19dcbf642ad6b", - "sha256:136cacdde1a2c5e5bc3d0b2a1beed733f97e2dad8c2ad3c2e17116f6590a3827", - "sha256:1730c93a38b5a18d24549bc81613223962a19d457cfda9bdc66e542f475a36f4", - "sha256:1a62fd6cd518693568e23e02f41816adedfca637f26716837681c90b36af3671", - "sha256:1c207e6f6dfd5749a26f5a5fd966602d6b824ec00d2df84a7e9a924e8933654e", - "sha256:2eccd5bef45883802848f821d940367c1d0ad588de71e5cabe3813175444202c", - "sha256:33ee982237cffaf946db365c3a6ebaa37855d8e3ca5800f6f48890209c1cfefc", - "sha256:3d136e5b8821073e1a09dde3eb076ea9988e7010c54ffe4d39701adf0c303438", - "sha256:47654177e675bafdf4e4738ce58cdc5c6d6ee2157ac0a78a3fa460942b9d64a8", - "sha256:47937cf2e7ed4e0e37f7851c76edeb8543ec9b0eae149b36ecd26176ff1ca874", - "sha256:4ac46298e0143d91e4644a27a769d1388d5d89e82ee0cf37bf2b0b001b9712a4", - "sha256:4c0b208a5d6c81434bdfa0f06d9b667e5de15af84d8cae5723c3a33ba6611b82", - "sha256:551db2fe892fcbefb38f6f81ffa62de11090c8119fd4e66a60f3adff70751ec7", - "sha256:599f3b07bde2627e163ce484d5497a54a0a8437779362395c6b25e68c6590ede", - "sha256:5ef8356f16b1a83609f7a992a6e33d792bb5eff2370712c9eaae0d02e1924341", - "sha256:5fe919027f29b12f7a2562ba0daf3e045cb388f844e022552a5674fcdf5d21f1", - "sha256:6f0a6be264afb094975b5ef55c911379d6989caa87c4e558814ec4f5125cfa2e", - "sha256:706efc19f9679a1b425d6fa2b4bc770d976d0984335eaea0869bd32f627591d2", - "sha256:73f9752cf3596771c7726f7eea5b9e634ad47c6d863043589a1c3bb31325c7eb", - "sha256:762e616199f6319bb98e7f4f27d254c84c5fb1c25c908c2a9d0f92b92fb27530", - "sha256:866a0f583be79f0def667a5d2c60b7b4cc68f0c0a470f227e1122691b443c934", - "sha256:86a94af4a88110ed4bb8961f5ac72edf782958e665d5bfceaab6bf388420a78b", - "sha256:8e0343a6e06d94f6b6ac52fbc75269b41dd3c57066541a6c76517f69fe67cb43", - "sha256:97e615eab34bd8477c3f34197a17ce08c648d38467489359cb9eb7394f1083f7", - "sha256:a96e6d4074db29b152222c34d7eec2e2db2f92638d2b2b2c704f9e8db3ae0edc", - "sha256:b912750b13d76af8aac45ddf4679535def304b2a48a07989ec736508d0bbfbde", - "sha256:bc2676312cc3468a25aac001ec727168994ea3b69b48914944a44c6a0b251e79", - "sha256:cebff2fe5dc82cb22122e4e1225e00a4a506b1a16fafa911142ee124febf2c9e", - "sha256:d22fce0b0f5715cdac082e35a9e735a1752dc8585f005d045abb1a7c20e197f9", - "sha256:d3f7e001328bd6466b3414215f66dde3c7c13d8025a9c160a75d7b2687090d15", - "sha256:d3fe667935e9562407c2511570dca14604a654988a13d8725667e95161d92e9b", - "sha256:dabb70a6e3d9c22df50e08dc55b14ca2a99da95a2d941954255ac76fd6982bc5", - "sha256:e2fb8e8158306567a3a9a41670c1ff99d0567d7fc96fa93b7abf8b519a46b250", - "sha256:e96ac6b3169940a8cd57b4f2b8edcad8f5213b60efcd197d59fbe52f0accd66e", - "sha256:fbf649bc77510ef2521cf797700b96167bb77838c40780da7ea3edd8b78044d1" + "sha256:03bd5c0db82237bbc47833a8b25f1cc090646e212f86b601903d79d7e6b37031", + "sha256:03f1452d5d1f279184d5bdb663a3dc39902d9320eceb63276240791e849054b6", + "sha256:10ebac566dd0cec66f942dc759d46a994a2b3ba7179420f0e2130f88f8a5f400", + "sha256:192b7a792e3145ed880ff6b1a206fdb783697cfdb4915083bfca7065ec845e60", + "sha256:19c829d52e921b9fe0b2c0c6a8f9a2508c49678ee1be598f87d143335b6a35dc", + "sha256:3f3495462bc0438b76536a0e10d765b168ae636092082531b88340dc40dcd118", + "sha256:3f52050c6a10d4a039ec6f2c58e5b3ade5cc570d16cf9d102711e6b8413c90e6", + "sha256:400d06c9ec8dbcc96f56e79376297e7be07a315605c9a2208720da263d44d76f", + "sha256:4ec212037becf6d2f705b7ed4538d56980b1e7bba237df0d8995cbbed29961dc", + "sha256:51d5713e8e38f2d3ec26e0dfdca398ed0c20abda2eb49ffc15a15a23eb8e5f6d", + "sha256:52f5253cca1b35eaeefa51abd366b87f48f8714097c99b131ba61f3fdbbb58e7", + "sha256:5566fd9271c89ad03d81b0831c37d46ae5e2ed211122c998637130159a120cf1", + "sha256:55bbcc74dc0c7ab489c315c28b61d7a1d03cf938cc99cc58092eb065f120c3a5", + "sha256:696c2a381fc7876b3056711717dba5eddd07c2c9e5ccd50da54029a1293b6e43", + "sha256:6ba4b3638d014918b918aa90a9c8370bd74a03abf8fcf9deb353b3a461a59a84", + "sha256:7039e624bcb820f77cc2ff3d1adcce531932990eee16121077eb51d9c76b6c14", + "sha256:88d108d004e0df25224de77ce349a7e73494ea2cb194031f7c9687e68a88ec9b", + "sha256:8c1dff87b30fd150c61367d0e2cdc49bb55f8b9fd2a303560bbc24b951573ae1", + "sha256:9a8195b99e650e6f329ce4e5eb22d448bdfef0406404080812bc96e2a05674cb", + "sha256:af0b33f04677b57843d529b9257a475d2865403300b48c67654c40abac2f9f24", + "sha256:b419f2144e1762ab845f20316f1df36b15431f2622ebae8a6d5f7e8e712b413c", + "sha256:b59deb0ddc7b431e41d720c00f99d68b52cb9bd1d5605a085dc18f502fe9c47f", + "sha256:bc0615351221926a36a0fbcb2520fb52e0b23e8c22a43754d9cb8f21358c33c0", + "sha256:c203d82069ba31e1f3bc7ba530b2461ec86366cd4bfc9b95ec6ce58b1b559c34", + "sha256:ce6cbb852fb8f2f9bb7b9cdca44e2e37bce783b5f4c167ff82cb5f5128163c8f", + "sha256:d33cb526efdc235a2531433fc1287fcb80d807d5b401f9b801b78bf22df560dd", + "sha256:da0cef4d7e3f19c3bd1d71658d6900321af0492fee36ec01b550a10924cffb9c", + "sha256:da21e7eec49252df34d426c2ee9cf0361c923026d37c24728b0fa4cc0599fd03", + "sha256:ea8d51e5eb29e57d34744369cd08267637aa5a0fefc9b5d33775ab7ff2ebf2e3", + "sha256:ec4e87e6fdc511a535254daa122c20e11959ce043b4e3425494b237692a34f1c", + "sha256:f0f5fda7cbf890371a59ab1d06512da4f2c89a6ea194e595808123c863c38eff", + "sha256:f32ca483e6ade23c7caaee9d5ee5d550cf4146e9b68d2fb6c68bac183aa41c37", + "sha256:f749ca804648d00eda62fe1098f229b082dfca930d8bad8386e572a6eafa7525", + "sha256:f89a420cf5a6f2aa7849dd59e1ff0e477f562d97cf8d6a1ee03461e1eec39887" ], - "markers": "python_version >= '3.7'", - "version": "==6.4.post2" + "markers": "python_version >= '3.8'", + "version": "==7.0.1" } }, "develop": { @@ -1873,69 +1889,84 @@ }, "certifi": { "hashes": [ - "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516", - "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56" + "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b", + "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90" ], "markers": "python_version >= '3.6'", - "version": "==2024.6.2" + "version": "==2024.7.4" }, "cffi": { "hashes": [ - "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc", - "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a", - "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417", - "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab", - "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520", - "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36", - "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743", - "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8", - "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed", - "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684", - "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56", - "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324", - "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d", - "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235", - "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e", - "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088", - "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000", - "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7", - "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e", - "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673", - "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c", - "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe", - "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2", - "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098", - "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8", - "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a", - "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0", - "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b", - "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896", - "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e", - "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9", - "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2", - "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b", - "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6", - "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404", - "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f", - "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0", - "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4", - "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc", - "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936", - "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba", - "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872", - "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb", - "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614", - "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1", - "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d", - "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969", - "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b", - "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4", - "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627", - "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956", - "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357" + "sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f", + "sha256:0a048d4f6630113e54bb4b77e315e1ba32a5a31512c31a273807d0027a7e69ab", + "sha256:0bb15e7acf8ab35ca8b24b90af52c8b391690ef5c4aec3d31f38f0d37d2cc499", + "sha256:0d46ee4764b88b91f16661a8befc6bfb24806d885e27436fdc292ed7e6f6d058", + "sha256:0e60821d312f99d3e1569202518dddf10ae547e799d75aef3bca3a2d9e8ee693", + "sha256:0fdacad9e0d9fc23e519efd5ea24a70348305e8d7d85ecbb1a5fa66dc834e7fb", + "sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377", + "sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885", + "sha256:1a2ddbac59dc3716bc79f27906c010406155031a1c801410f1bafff17ea304d2", + "sha256:2404f3de742f47cb62d023f0ba7c5a916c9c653d5b368cc966382ae4e57da401", + "sha256:24658baf6224d8f280e827f0a50c46ad819ec8ba380a42448e24459daf809cf4", + "sha256:24aa705a5f5bd3a8bcfa4d123f03413de5d86e497435693b638cbffb7d5d8a1b", + "sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59", + "sha256:331ad15c39c9fe9186ceaf87203a9ecf5ae0ba2538c9e898e3a6967e8ad3db6f", + "sha256:3aa9d43b02a0c681f0bfbc12d476d47b2b2b6a3f9287f11ee42989a268a1833c", + "sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555", + "sha256:4304d4416ff032ed50ad6bb87416d802e67139e31c0bde4628f36a47a3164bfa", + "sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424", + "sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb", + "sha256:48b389b1fd5144603d61d752afd7167dfd205973a43151ae5045b35793232aa2", + "sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8", + "sha256:516a405f174fd3b88829eabfe4bb296ac602d6a0f68e0d64d5ac9456194a5b7e", + "sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9", + "sha256:5bdc0f1f610d067c70aa3737ed06e2726fd9d6f7bfee4a351f4c40b6831f4e82", + "sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828", + "sha256:6327b572f5770293fc062a7ec04160e89741e8552bf1c358d1a23eba68166759", + "sha256:669b29a9eca6146465cc574659058ed949748f0809a2582d1f1a324eb91054dc", + "sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118", + "sha256:6d872186c1617d143969defeadac5a904e6e374183e07977eedef9c07c8953bf", + "sha256:6f76a90c345796c01d85e6332e81cab6d70de83b829cf1d9762d0a3da59c7932", + "sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a", + "sha256:7cbc78dc018596315d4e7841c8c3a7ae31cc4d638c9b627f87d52e8abaaf2d29", + "sha256:856bf0924d24e7f93b8aee12a3a1095c34085600aa805693fb7f5d1962393206", + "sha256:8a98748ed1a1df4ee1d6f927e151ed6c1a09d5ec21684de879c7ea6aa96f58f2", + "sha256:93a7350f6706b31f457c1457d3a3259ff9071a66f312ae64dc024f049055f72c", + "sha256:964823b2fc77b55355999ade496c54dde161c621cb1f6eac61dc30ed1b63cd4c", + "sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0", + "sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a", + "sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195", + "sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6", + "sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9", + "sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc", + "sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb", + "sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0", + "sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7", + "sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb", + "sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a", + "sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492", + "sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720", + "sha256:c815270206f983309915a6844fe994b2fa47e5d05c4c4cef267c3b30e34dbe42", + "sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7", + "sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d", + "sha256:d6bdcd415ba87846fd317bee0774e412e8792832e7805938987e4ede1d13046d", + "sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb", + "sha256:dbc183e7bef690c9abe5ea67b7b60fdbca81aa8da43468287dae7b5c046107d4", + "sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2", + "sha256:dec6b307ce928e8e112a6bb9921a1cb00a0e14979bf28b98e084a4b8a742bd9b", + "sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8", + "sha256:e4094c7b464cf0a858e75cd14b03509e84789abf7b79f8537e6a72152109c76e", + "sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204", + "sha256:eb09b82377233b902d4c3fbeeb7ad731cdab579c6c6fda1f763cd779139e47c3", + "sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150", + "sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4", + "sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76", + "sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e", + "sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb", + "sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91" ], "markers": "python_version >= '3.8'", - "version": "==1.16.0" + "version": "==1.17.0" }, "charset-normalizer": { "hashes": [ @@ -2172,11 +2203,11 @@ }, "exceptiongroup": { "hashes": [ - "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad", - "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16" + "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", + "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" ], "markers": "python_version < '3.11'", - "version": "==1.2.1" + "version": "==1.2.2" }, "freezegun": { "hashes": [ @@ -2529,11 +2560,11 @@ }, "pycodestyle": { "hashes": [ - "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c", - "sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4" + "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3", + "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521" ], "markers": "python_version >= '3.8'", - "version": "==2.12.0" + "version": "==2.12.1" }, "pycparser": { "hashes": [ @@ -2604,12 +2635,12 @@ }, "pytest": { "hashes": [ - "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343", - "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977" + "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5", + "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==8.2.2" + "version": "==8.3.2" }, "pytest-bdd": { "hashes": [ @@ -2656,60 +2687,62 @@ }, "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" ], - "markers": "python_version >= '3.6'", - "version": "==6.0.1" + "markers": "python_version >= '3.8'", + "version": "==6.0.2" }, "requests": { "hashes": [ @@ -2770,11 +2803,11 @@ }, "setuptools": { "hashes": [ - "sha256:01a1e793faa5bd89abc851fa15d0a0db26f160890c7102cd8dce643e886b47f5", - "sha256:d9b8b771455a97c8a9f3ab3448ebe0b29b5e105f1228bba41028be116985a267" + "sha256:b208925fcb9f7af924ed2dc04708ea89791e24bde0d3020b27df0e116088b34e", + "sha256:d59a3e788ab7e012ab2c4baed1b376da6366883ee20d7a5fc426816e3d7b1193" ], "markers": "python_version >= '3.8'", - "version": "==70.1.0" + "version": "==73.0.1" }, "six": { "hashes": [ @@ -2852,41 +2885,44 @@ "watchmedo" ], "hashes": [ - "sha256:0144c0ea9997b92615af1d94afc0c217e07ce2c14912c7b1a5731776329fcfc7", - "sha256:03e70d2df2258fb6cb0e95bbdbe06c16e608af94a3ffbd2b90c3f1e83eb10767", - "sha256:093b23e6906a8b97051191a4a0c73a77ecc958121d42346274c6af6520dec175", - "sha256:123587af84260c991dc5f62a6e7ef3d1c57dfddc99faacee508c71d287248459", - "sha256:17e32f147d8bf9657e0922c0940bcde863b894cd871dbb694beb6704cfbd2fb5", - "sha256:206afc3d964f9a233e6ad34618ec60b9837d0582b500b63687e34011e15bb429", - "sha256:4107ac5ab936a63952dea2a46a734a23230aa2f6f9db1291bf171dac3ebd53c6", - "sha256:4513ec234c68b14d4161440e07f995f231be21a09329051e67a2118a7a612d2d", - "sha256:611be3904f9843f0529c35a3ff3fd617449463cb4b73b1633950b3d97fa4bfb7", - "sha256:62c613ad689ddcb11707f030e722fa929f322ef7e4f18f5335d2b73c61a85c28", - "sha256:667f3c579e813fcbad1b784db7a1aaa96524bed53437e119f6a2f5de4db04235", - "sha256:6e8c70d2cd745daec2a08734d9f63092b793ad97612470a0ee4cbb8f5f705c57", - "sha256:7577b3c43e5909623149f76b099ac49a1a01ca4e167d1785c76eb52fa585745a", - "sha256:998d2be6976a0ee3a81fb8e2777900c28641fb5bfbd0c84717d89bca0addcdc5", - "sha256:a3c2c317a8fb53e5b3d25790553796105501a235343f5d2bf23bb8649c2c8709", - "sha256:ab998f567ebdf6b1da7dc1e5accfaa7c6992244629c0fdaef062f43249bd8dee", - "sha256:ac7041b385f04c047fcc2951dc001671dee1b7e0615cde772e84b01fbf68ee84", - "sha256:bca36be5707e81b9e6ce3208d92d95540d4ca244c006b61511753583c81c70dd", - "sha256:c9904904b6564d4ee8a1ed820db76185a3c96e05560c776c79a6ce5ab71888ba", - "sha256:cad0bbd66cd59fc474b4a4376bc5ac3fc698723510cbb64091c2a793b18654db", - "sha256:d10a681c9a1d5a77e75c48a3b8e1a9f2ae2928eda463e8d33660437705659682", - "sha256:d4925e4bf7b9bddd1c3de13c9b8a2cdb89a468f640e66fbfabaf735bd85b3e35", - "sha256:d7b9f5f3299e8dd230880b6c55504a1f69cf1e4316275d1b215ebdd8187ec88d", - "sha256:da2dfdaa8006eb6a71051795856bedd97e5b03e57da96f98e375682c48850645", - "sha256:dddba7ca1c807045323b6af4ff80f5ddc4d654c8bce8317dde1bd96b128ed253", - "sha256:e7921319fe4430b11278d924ef66d4daa469fafb1da679a2e48c935fa27af193", - "sha256:e93f451f2dfa433d97765ca2634628b789b49ba8b504fdde5837cdcf25fdb53b", - "sha256:eebaacf674fa25511e8867028d281e602ee6500045b57f43b08778082f7f8b44", - "sha256:ef0107bbb6a55f5be727cfc2ef945d5676b97bffb8425650dadbb184be9f9a2b", - "sha256:f0de0f284248ab40188f23380b03b59126d1479cd59940f2a34f8852db710625", - "sha256:f27279d060e2ab24c0aa98363ff906d2386aa6c4dc2f1a374655d4e02a6c5e5e", - "sha256:f8affdf3c0f0466e69f5b3917cdd042f89c8c63aebdb9f7c078996f607cdb0f5" - ], - "markers": "python_version >= '3.8'", - "version": "==4.0.1" + "sha256:0b4359067d30d5b864e09c8597b112fe0a0a59321a0f331498b013fb097406b4", + "sha256:0d8a7e523ef03757a5aa29f591437d64d0d894635f8a50f370fe37f913ce4e19", + "sha256:0e83619a2d5d436a7e58a1aea957a3c1ccbf9782c43c0b4fed80580e5e4acd1a", + "sha256:10b6683df70d340ac3279eff0b2766813f00f35a1d37515d2c99959ada8f05fa", + "sha256:132937547a716027bd5714383dfc40dc66c26769f1ce8a72a859d6a48f371f3a", + "sha256:1cdcfd8142f604630deef34722d695fb455d04ab7cfe9963055df1fc69e6727a", + "sha256:2d468028a77b42cc685ed694a7a550a8d1771bb05193ba7b24006b8241a571a1", + "sha256:32be97f3b75693a93c683787a87a0dc8db98bb84701539954eef991fb35f5fbc", + "sha256:770eef5372f146997638d737c9a3c597a3b41037cfbc5c41538fc27c09c3a3f9", + "sha256:7c7d4bf585ad501c5f6c980e7be9c4f15604c7cc150e942d82083b31a7548930", + "sha256:88456d65f207b39f1981bf772e473799fcdc10801062c36fd5ad9f9d1d463a73", + "sha256:914285126ad0b6eb2258bbbcb7b288d9dfd655ae88fa28945be05a7b475a800b", + "sha256:936acba76d636f70db8f3c66e76aa6cb5136a936fc2a5088b9ce1c7a3508fc83", + "sha256:980b71510f59c884d684b3663d46e7a14b457c9611c481e5cef08f4dd022eed7", + "sha256:984306dc4720da5498b16fc037b36ac443816125a3705dfde4fd90652d8028ef", + "sha256:a2cffa171445b0efa0726c561eca9a27d00a1f2b83846dbd5a4f639c4f8ca8e1", + "sha256:aa160781cafff2719b663c8a506156e9289d111d80f3387cf3af49cedee1f040", + "sha256:b2c45f6e1e57ebb4687690c05bc3a2c1fb6ab260550c4290b8abb1335e0fd08b", + "sha256:b4dfbb6c49221be4535623ea4474a4d6ee0a9cef4a80b20c28db4d858b64e270", + "sha256:baececaa8edff42cd16558a639a9b0ddf425f93d892e8392a56bf904f5eff22c", + "sha256:bcfd02377be80ef3b6bc4ce481ef3959640458d6feaae0bd43dd90a43da90a7d", + "sha256:c0b14488bd336c5b1845cee83d3e631a1f8b4e9c5091ec539406e4a324f882d8", + "sha256:c100d09ac72a8a08ddbf0629ddfa0b8ee41740f9051429baa8e31bb903ad7508", + "sha256:c344453ef3bf875a535b0488e3ad28e341adbd5a9ffb0f7d62cefacc8824ef2b", + "sha256:c50f148b31b03fbadd6d0b5980e38b558046b127dc483e5e4505fcef250f9503", + "sha256:c82253cfc9be68e3e49282831afad2c1f6593af80c0daf1287f6a92657986757", + "sha256:cd67c7df93eb58f360c43802acc945fa8da70c675b6fa37a241e17ca698ca49b", + "sha256:d7ab624ff2f663f98cd03c8b7eedc09375a911794dfea6bf2a359fcc266bff29", + "sha256:e252f8ca942a870f38cf785aef420285431311652d871409a64e2a0a52a2174c", + "sha256:ede7f010f2239b97cc79e6cb3c249e72962404ae3865860855d5cbe708b0fd22", + "sha256:eeea812f38536a0aa859972d50c76e37f4456474b02bd93674d1947cf1e39578", + "sha256:f15edcae3830ff20e55d1f4e743e92970c847bcddc8b7509bcd172aa04de506e", + "sha256:f5315a8c8dd6dd9425b974515081fc0aadca1d1d61e078d2246509fd756141ee", + "sha256:f6ee8dedd255087bc7fe82adf046f0b75479b989185fb0bdf9a98b612170eac7", + "sha256:f7c739888c20f99824f7aa9d31ac8a97353e22d0c0e54703a547a218f6637eb3" + ], + "markers": "python_version >= '3.8'", + "version": "==4.0.2" }, "wcwidth": { "hashes": [ From 03a3d50d17e3541f46d37d82dc73fac42e693778 Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Tue, 20 Aug 2024 14:18:10 +0100 Subject: [PATCH 02/20] Add endpoint for licence statuses --- api/data_workspace/urls.py | 2 + api/data_workspace/v2/__init__.py | 0 api/data_workspace/v2/serializers.py | 5 ++ api/data_workspace/v2/tests/__init__.py | 0 api/data_workspace/v2/tests/bdd/__init__.py | 0 .../bdd/scenarios/licence_statuses.feature | 13 ++++ .../v2/tests/bdd/test_licence_statuses.py | 65 +++++++++++++++++++ api/data_workspace/v2/urls.py | 11 ++++ api/data_workspace/v2/views.py | 20 ++++++ api/licences/enums.py | 4 ++ 10 files changed, 120 insertions(+) create mode 100644 api/data_workspace/v2/__init__.py create mode 100644 api/data_workspace/v2/serializers.py create mode 100644 api/data_workspace/v2/tests/__init__.py create mode 100644 api/data_workspace/v2/tests/bdd/__init__.py create mode 100644 api/data_workspace/v2/tests/bdd/scenarios/licence_statuses.feature create mode 100644 api/data_workspace/v2/tests/bdd/test_licence_statuses.py create mode 100644 api/data_workspace/v2/urls.py create mode 100644 api/data_workspace/v2/views.py diff --git a/api/data_workspace/urls.py b/api/data_workspace/urls.py index 58bbcadd8..ac0046971 100644 --- a/api/data_workspace/urls.py +++ b/api/data_workspace/urls.py @@ -5,6 +5,7 @@ from api.data_workspace.v0.urls import router_v0 from api.data_workspace.v1.urls import router_v1 +from api.data_workspace.v2.urls import router_v2 app_name = "data_workspace" @@ -12,4 +13,5 @@ urlpatterns = [ path("v0/", include((router_v0.urls, "data_workspace_v0"), namespace="v0")), path("v1/", include((router_v1.urls, "data_workspace_v1"), namespace="v1")), + path("v2/", include((router_v2.urls, "data_workspace_v2"), namespace="v2")), ] diff --git a/api/data_workspace/v2/__init__.py b/api/data_workspace/v2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py new file mode 100644 index 000000000..db93b0882 --- /dev/null +++ b/api/data_workspace/v2/serializers.py @@ -0,0 +1,5 @@ +from rest_framework import serializers + + +class LicenceStatusSerializer(serializers.Serializer): + name = serializers.CharField(source="*") diff --git a/api/data_workspace/v2/tests/__init__.py b/api/data_workspace/v2/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/api/data_workspace/v2/tests/bdd/__init__.py b/api/data_workspace/v2/tests/bdd/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/api/data_workspace/v2/tests/bdd/scenarios/licence_statuses.feature b/api/data_workspace/v2/tests/bdd/scenarios/licence_statuses.feature new file mode 100644 index 000000000..182c80135 --- /dev/null +++ b/api/data_workspace/v2/tests/bdd/scenarios/licence_statuses.feature @@ -0,0 +1,13 @@ +Scenario: Licence statuses + Given the following licence statuses: + | name | + | cancelled | + | draft | + | exhausted | + | expired | + | issued | + | reinstated | + | revoked | + | surrendered | + | suspended | + Then there are no other licence statuses diff --git a/api/data_workspace/v2/tests/bdd/test_licence_statuses.py b/api/data_workspace/v2/tests/bdd/test_licence_statuses.py new file mode 100644 index 000000000..b6d593874 --- /dev/null +++ b/api/data_workspace/v2/tests/bdd/test_licence_statuses.py @@ -0,0 +1,65 @@ +import pytest + +from django.urls import reverse +from pytest_bdd import ( + given, + parsers, + then, + scenarios, +) +from rest_framework import status + + +scenarios("./scenarios/licence_statuses.feature") + + +def create_table(data_table): + lines = data_table.strip().split("\n") + + keys = [key.strip() for key in lines[0].split("|") if key] + + parsed_data_table = [] + for line in lines[1:]: + values = [value.strip() for value in line.split("|") if value] + entry = dict(zip(keys, values)) + parsed_data_table.append(entry) + + return parsed_data_table + + +@pytest.fixture() +def unpage_data(client): + def _unpage_data(url): + unpaged_results = [] + while True: + response = client.get(url) + assert response.status_code == status.HTTP_200_OK + unpaged_results += response.data["results"] + if not response.data["next"]: + break + url = response.data["next"] + + return unpaged_results + + return _unpage_data + + +@pytest.fixture() +def licence_status_list_url(): + return reverse("data_workspace:v2:dw-licence-statuses-list") + + +@given( + parsers.parse("the following licence statuses:\n{licence_statuses}"), target_fixture="found_licence_status_names" +) +def the_following_licence_statuses(licence_statuses): + licence_statuses = create_table(licence_statuses) + return [licence_status["name"] for licence_status in licence_statuses] + + +@then("there are no other licence statuses") +def no_other_licence_statuses(found_licence_status_names, unpage_data, licence_status_list_url): + licence_status_data = unpage_data(licence_status_list_url) + assert sorted(found_licence_status_names) == sorted( + [licence_status["name"] for licence_status in licence_status_data] + ) diff --git a/api/data_workspace/v2/urls.py b/api/data_workspace/v2/urls.py new file mode 100644 index 000000000..052933284 --- /dev/null +++ b/api/data_workspace/v2/urls.py @@ -0,0 +1,11 @@ +from rest_framework.routers import DefaultRouter + +from api.data_workspace.v2 import views + + +router_v2 = DefaultRouter() +router_v2.register( + "licence-statuses", + views.LicenceStatusesListView, + basename="dw-licence-statuses", +) diff --git a/api/data_workspace/v2/views.py b/api/data_workspace/v2/views.py new file mode 100644 index 000000000..13a738612 --- /dev/null +++ b/api/data_workspace/v2/views.py @@ -0,0 +1,20 @@ +from rest_framework import viewsets +from rest_framework.generics import ListAPIView +from rest_framework.pagination import LimitOffsetPagination +from rest_framework.settings import api_settings + +from rest_framework_csv.renderers import PaginatedCSVRenderer + +from api.core.authentication import DataWorkspaceOnlyAuthentication +from api.data_workspace.v2.serializers import LicenceStatusSerializer +from api.licences.enums import LicenceStatus + + +class LicenceStatusesListView(viewsets.GenericViewSet, ListAPIView): + authentication_classes = (DataWorkspaceOnlyAuthentication,) + pagination_class = LimitOffsetPagination + renderer_classes = tuple(api_settings.DEFAULT_RENDERER_CLASSES) + (PaginatedCSVRenderer,) + serializer_class = LicenceStatusSerializer + + def get_queryset(self): + return LicenceStatus.all() diff --git a/api/licences/enums.py b/api/licences/enums.py index 3aa338ea7..d090cd7aa 100644 --- a/api/licences/enums.py +++ b/api/licences/enums.py @@ -45,6 +45,10 @@ def to_str(cls, status): def can_edit_status(cls, status): return status in cls._can_edit_status + @classmethod + def all(cls): + return [getattr(cls, param) for param in dir(cls) if param.isupper()] + hmrc_integration_action_to_licence_status = { HMRCIntegrationActionEnum.SURRENDER: LicenceStatus.SURRENDERED, From dabc052e3e10b7f40c65ed4ce4e2f5185eee9517 Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Tue, 20 Aug 2024 14:36:12 +0100 Subject: [PATCH 03/20] Add endpoint for licence decision types --- api/data_workspace/v2/serializers.py | 4 ++ api/data_workspace/v2/tests/bdd/conftest.py | 38 +++++++++++++++++++ .../scenarios/licence_decision_types.feature | 9 +++++ .../tests/bdd/test_licence_decision_types.py | 34 +++++++++++++++++ .../v2/tests/bdd/test_licence_statuses.py | 34 +---------------- api/data_workspace/v2/urls.py | 5 +++ api/data_workspace/v2/views.py | 20 +++++++++- api/licences/enums.py | 12 ++++++ 8 files changed, 121 insertions(+), 35 deletions(-) create mode 100644 api/data_workspace/v2/tests/bdd/conftest.py create mode 100644 api/data_workspace/v2/tests/bdd/scenarios/licence_decision_types.feature create mode 100644 api/data_workspace/v2/tests/bdd/test_licence_decision_types.py diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index db93b0882..3211c4174 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -3,3 +3,7 @@ class LicenceStatusSerializer(serializers.Serializer): name = serializers.CharField(source="*") + + +class LicenceDecisionTypeSerializer(serializers.Serializer): + name = serializers.CharField(source="*") diff --git a/api/data_workspace/v2/tests/bdd/conftest.py b/api/data_workspace/v2/tests/bdd/conftest.py new file mode 100644 index 000000000..ccabecb89 --- /dev/null +++ b/api/data_workspace/v2/tests/bdd/conftest.py @@ -0,0 +1,38 @@ +import pytest + +from rest_framework import status + + +@pytest.fixture +def create_table(): + def _create_table(data_table): + lines = data_table.strip().split("\n") + + keys = [key.strip() for key in lines[0].split("|") if key] + + parsed_data_table = [] + for line in lines[1:]: + values = [value.strip() for value in line.split("|") if value] + entry = dict(zip(keys, values)) + parsed_data_table.append(entry) + + return parsed_data_table + + return _create_table + + +@pytest.fixture() +def unpage_data(client): + def _unpage_data(url): + unpaged_results = [] + while True: + response = client.get(url) + assert response.status_code == status.HTTP_200_OK + unpaged_results += response.data["results"] + if not response.data["next"]: + break + url = response.data["next"] + + return unpaged_results + + return _unpage_data diff --git a/api/data_workspace/v2/tests/bdd/scenarios/licence_decision_types.feature b/api/data_workspace/v2/tests/bdd/scenarios/licence_decision_types.feature new file mode 100644 index 000000000..6ee8186b4 --- /dev/null +++ b/api/data_workspace/v2/tests/bdd/scenarios/licence_decision_types.feature @@ -0,0 +1,9 @@ +Scenario: Licence decision types + Given the following licence decision types: + | name | + | issued | + | refused | + | rejected | + | nlr | + | withdrawn | + Then there are no other licence decision types diff --git a/api/data_workspace/v2/tests/bdd/test_licence_decision_types.py b/api/data_workspace/v2/tests/bdd/test_licence_decision_types.py new file mode 100644 index 000000000..1d1f43f91 --- /dev/null +++ b/api/data_workspace/v2/tests/bdd/test_licence_decision_types.py @@ -0,0 +1,34 @@ +import pytest + +from django.urls import reverse +from pytest_bdd import ( + given, + parsers, + then, + scenarios, +) + + +scenarios("./scenarios/licence_decision_types.feature") + + +@pytest.fixture() +def licence_decision_type_list_url(): + return reverse("data_workspace:v2:dw-licence-decision-types-list") + + +@given( + parsers.parse("the following licence decision types:\n{licence_decision_types}"), + target_fixture="found_licence_decision_type_names", +) +def the_following_licence_decision_types(create_table, licence_decision_types): + licence_decision_types = create_table(licence_decision_types) + return [licence_decision_type["name"] for licence_decision_type in licence_decision_types] + + +@then("there are no other licence decision types") +def no_other_licence_decision_types(found_licence_decision_type_names, unpage_data, licence_decision_type_list_url): + licence_decision_type_data = unpage_data(licence_decision_type_list_url) + assert sorted(found_licence_decision_type_names) == sorted( + [licence_decision_type["name"] for licence_decision_type in licence_decision_type_data] + ) diff --git a/api/data_workspace/v2/tests/bdd/test_licence_statuses.py b/api/data_workspace/v2/tests/bdd/test_licence_statuses.py index b6d593874..d9409dbb2 100644 --- a/api/data_workspace/v2/tests/bdd/test_licence_statuses.py +++ b/api/data_workspace/v2/tests/bdd/test_licence_statuses.py @@ -7,43 +7,11 @@ then, scenarios, ) -from rest_framework import status scenarios("./scenarios/licence_statuses.feature") -def create_table(data_table): - lines = data_table.strip().split("\n") - - keys = [key.strip() for key in lines[0].split("|") if key] - - parsed_data_table = [] - for line in lines[1:]: - values = [value.strip() for value in line.split("|") if value] - entry = dict(zip(keys, values)) - parsed_data_table.append(entry) - - return parsed_data_table - - -@pytest.fixture() -def unpage_data(client): - def _unpage_data(url): - unpaged_results = [] - while True: - response = client.get(url) - assert response.status_code == status.HTTP_200_OK - unpaged_results += response.data["results"] - if not response.data["next"]: - break - url = response.data["next"] - - return unpaged_results - - return _unpage_data - - @pytest.fixture() def licence_status_list_url(): return reverse("data_workspace:v2:dw-licence-statuses-list") @@ -52,7 +20,7 @@ def licence_status_list_url(): @given( parsers.parse("the following licence statuses:\n{licence_statuses}"), target_fixture="found_licence_status_names" ) -def the_following_licence_statuses(licence_statuses): +def the_following_licence_statuses(create_table, licence_statuses): licence_statuses = create_table(licence_statuses) return [licence_status["name"] for licence_status in licence_statuses] diff --git a/api/data_workspace/v2/urls.py b/api/data_workspace/v2/urls.py index 052933284..fe2ec60ea 100644 --- a/api/data_workspace/v2/urls.py +++ b/api/data_workspace/v2/urls.py @@ -9,3 +9,8 @@ views.LicenceStatusesListView, basename="dw-licence-statuses", ) +router_v2.register( + "licence-decision-types", + views.LicenceDecisionTypesListView, + basename="dw-licence-decision-types", +) diff --git a/api/data_workspace/v2/views.py b/api/data_workspace/v2/views.py index 13a738612..310c690d9 100644 --- a/api/data_workspace/v2/views.py +++ b/api/data_workspace/v2/views.py @@ -6,8 +6,14 @@ from rest_framework_csv.renderers import PaginatedCSVRenderer from api.core.authentication import DataWorkspaceOnlyAuthentication -from api.data_workspace.v2.serializers import LicenceStatusSerializer -from api.licences.enums import LicenceStatus +from api.data_workspace.v2.serializers import ( + LicenceDecisionTypeSerializer, + LicenceStatusSerializer, +) +from api.licences.enums import ( + LicenceDecisionType, + LicenceStatus, +) class LicenceStatusesListView(viewsets.GenericViewSet, ListAPIView): @@ -18,3 +24,13 @@ class LicenceStatusesListView(viewsets.GenericViewSet, ListAPIView): def get_queryset(self): return LicenceStatus.all() + + +class LicenceDecisionTypesListView(viewsets.GenericViewSet, ListAPIView): + authentication_classes = (DataWorkspaceOnlyAuthentication,) + pagination_class = LimitOffsetPagination + renderer_classes = tuple(api_settings.DEFAULT_RENDERER_CLASSES) + (PaginatedCSVRenderer,) + serializer_class = LicenceDecisionTypeSerializer + + def get_queryset(self): + return LicenceDecisionType.all() diff --git a/api/licences/enums.py b/api/licences/enums.py index d090cd7aa..6444326a3 100644 --- a/api/licences/enums.py +++ b/api/licences/enums.py @@ -50,6 +50,18 @@ def all(cls): return [getattr(cls, param) for param in dir(cls) if param.isupper()] +class LicenceDecisionType: + ISSUED = "issued" + REFUSED = "refused" + REJECTED = "rejected" + NLR = "nlr" + WITHDRAWN = "withdrawn" + + @classmethod + def all(cls): + return [getattr(cls, param) for param in dir(cls) if param.isupper()] + + hmrc_integration_action_to_licence_status = { HMRCIntegrationActionEnum.SURRENDER: LicenceStatus.SURRENDERED, HMRCIntegrationActionEnum.CANCEL: LicenceStatus.CANCELLED, From 1f13a946c47b1954970044e6c79b034241eb4dac Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Tue, 20 Aug 2024 16:02:40 +0100 Subject: [PATCH 04/20] Add applications endpoint --- api/applications/tests/factories.py | 5 +- api/data_workspace/v2/serializers.py | 20 ++++++ api/data_workspace/v2/tests/bdd/conftest.py | 9 +++ .../bdd/scenarios/siel_applications.feature | 21 ++++++ .../v2/tests/bdd/test_siel_applications.py | 70 +++++++++++++++++++ api/data_workspace/v2/urls.py | 5 ++ api/data_workspace/v2/views.py | 10 +++ 7 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 api/data_workspace/v2/tests/bdd/scenarios/siel_applications.feature create mode 100644 api/data_workspace/v2/tests/bdd/test_siel_applications.py diff --git a/api/applications/tests/factories.py b/api/applications/tests/factories.py index 90463f10e..2d183a712 100644 --- a/api/applications/tests/factories.py +++ b/api/applications/tests/factories.py @@ -1,3 +1,4 @@ +import datetime import factory from faker import Faker @@ -60,9 +61,11 @@ class Meta: @classmethod def _create(cls, model_class, *args, **kwargs): obj = model_class(*args, **kwargs) - obj.status = get_case_status_by_status(CaseStatusEnum.SUBMITTED) if "status" in kwargs and isinstance(kwargs["status"], CaseStatus): obj.status = kwargs["status"] + else: + obj.status = get_case_status_by_status(CaseStatusEnum.SUBMITTED) + obj.submitted_at = datetime.datetime.now() obj.save() return obj diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index 3211c4174..b4bb46d8b 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -1,5 +1,13 @@ from rest_framework import serializers +from api.applications.models import StandardApplication + + +def get_original_application(obj): + if not obj.amendment_of: + return obj + return get_original_application(obj.amendment_of) + class LicenceStatusSerializer(serializers.Serializer): name = serializers.CharField(source="*") @@ -7,3 +15,15 @@ class LicenceStatusSerializer(serializers.Serializer): class LicenceDecisionTypeSerializer(serializers.Serializer): name = serializers.CharField(source="*") + + +class SIELApplicationSerializer(serializers.ModelSerializer): + id = serializers.SerializerMethodField(required=False) + + class Meta: + model = StandardApplication + fields = ("id", "status") + + def get_id(self, application): + application = get_original_application(application) + return application.pk diff --git a/api/data_workspace/v2/tests/bdd/conftest.py b/api/data_workspace/v2/tests/bdd/conftest.py index ccabecb89..e6db05c38 100644 --- a/api/data_workspace/v2/tests/bdd/conftest.py +++ b/api/data_workspace/v2/tests/bdd/conftest.py @@ -3,6 +3,15 @@ from rest_framework import status +def pytest_bdd_apply_tag(tag, function): + if tag == "db": + marker = pytest.mark.django_db() + marker(function) + return True + + return None + + @pytest.fixture def create_table(): def _create_table(data_table): diff --git a/api/data_workspace/v2/tests/bdd/scenarios/siel_applications.feature b/api/data_workspace/v2/tests/bdd/scenarios/siel_applications.feature new file mode 100644 index 000000000..a99fa07d6 --- /dev/null +++ b/api/data_workspace/v2/tests/bdd/scenarios/siel_applications.feature @@ -0,0 +1,21 @@ +@db +Feature: SIEL Applications + +Scenario: Draft SIEL application + Given a draft SIEL application + Then it is not presented + +Scenario: Submitted SIEL application without an amendment + Given a submitted SIEL application without an amendment + Then it is presented as a single SIEL application + And the SIEL application has the id of itself + +Scenario: SIEL application with a single amendment + Given a submitted SIEL application that has been amended + Then it is presented as a single SIEL application + And the SIEL application has the id of the first SIEL application in the amendment chain + +Scenario: SIEL application with multiple amendments + Given a submitted SIEL application with multiple amendments + Then it is presented as a single SIEL application + And the SIEL application has the id of the first SIEL application in the amendment chain diff --git a/api/data_workspace/v2/tests/bdd/test_siel_applications.py b/api/data_workspace/v2/tests/bdd/test_siel_applications.py new file mode 100644 index 000000000..26f8e784c --- /dev/null +++ b/api/data_workspace/v2/tests/bdd/test_siel_applications.py @@ -0,0 +1,70 @@ +import pytest + +from django.urls import reverse +from pytest_bdd import ( + given, + scenarios, + then, +) + +from api.applications.tests.factories import ( + DraftStandardApplicationFactory, + StandardApplicationFactory, +) + + +scenarios("./scenarios/siel_applications.feature") + + +@pytest.fixture() +def siel_applications_list_url(): + return reverse("data_workspace:v2:dw-siel-applications-list") + + +@given("a draft SIEL application", target_fixture="draft_siel_application") +def draft_siel_application(): + return DraftStandardApplicationFactory() + + +@then("it is not presented") +def draft_application_not_presented(unpage_data, siel_applications_list_url): + siel_application_data = unpage_data(siel_applications_list_url) + assert siel_application_data == [] + + +@given("a submitted SIEL application without an amendment", target_fixture="siel_application") +def siel_application_without_an_amendment(): + return StandardApplicationFactory() + + +@then("it is presented as a single SIEL application", target_fixture="siel_application_data") +def presented_as_a_single_siel_application(client, siel_applications_list_url, unpage_data): + siel_application_data = unpage_data(siel_applications_list_url) + assert len(siel_application_data) == 1 + return siel_application_data + + +@then("the SIEL application has the id of itself") +def siel_application_id_of_itself(siel_application, siel_application_data): + assert siel_application.pk == siel_application_data[0]["id"] + + +@given("a submitted SIEL application that has been amended", target_fixture="original_siel_application") +def siel_application_with_an_amendment(): + original_siel_application = StandardApplicationFactory() + StandardApplicationFactory(amendment_of=original_siel_application) + return original_siel_application + + +@then("the SIEL application has the id of the first SIEL application in the amendment chain") +def siel_application_has_first_id_in_amendment_chain(original_siel_application, siel_application_data): + assert original_siel_application.pk == siel_application_data[0]["id"] + + +@given("a submitted SIEL application with multiple amendments", target_fixture="original_siel_application") +def siel_application_with_multiple_amendments(): + original_siel_application = StandardApplicationFactory() + next_siel_application = StandardApplicationFactory(amendment_of=original_siel_application) + another_siel_application = StandardApplicationFactory(amendment_of=next_siel_application) + StandardApplicationFactory(amendment_of=another_siel_application) + return original_siel_application diff --git a/api/data_workspace/v2/urls.py b/api/data_workspace/v2/urls.py index fe2ec60ea..b2499035d 100644 --- a/api/data_workspace/v2/urls.py +++ b/api/data_workspace/v2/urls.py @@ -14,3 +14,8 @@ views.LicenceDecisionTypesListView, basename="dw-licence-decision-types", ) +router_v2.register( + "siel-applications", + views.SIELApplicationsListView, + basename="dw-siel-applications", +) diff --git a/api/data_workspace/v2/views.py b/api/data_workspace/v2/views.py index 310c690d9..b7c5f2e55 100644 --- a/api/data_workspace/v2/views.py +++ b/api/data_workspace/v2/views.py @@ -5,10 +5,12 @@ from rest_framework_csv.renderers import PaginatedCSVRenderer +from api.applications.models import StandardApplication from api.core.authentication import DataWorkspaceOnlyAuthentication from api.data_workspace.v2.serializers import ( LicenceDecisionTypeSerializer, LicenceStatusSerializer, + SIELApplicationSerializer, ) from api.licences.enums import ( LicenceDecisionType, @@ -34,3 +36,11 @@ class LicenceDecisionTypesListView(viewsets.GenericViewSet, ListAPIView): def get_queryset(self): return LicenceDecisionType.all() + + +class SIELApplicationsListView(viewsets.ReadOnlyModelViewSet): + authentication_classes = (DataWorkspaceOnlyAuthentication,) + pagination_class = LimitOffsetPagination + queryset = StandardApplication.objects.filter(amendment__isnull=True).exclude(submitted_at__isnull=True) + renderer_classes = tuple(api_settings.DEFAULT_RENDERER_CLASSES) + (PaginatedCSVRenderer,) + serializer_class = SIELApplicationSerializer From f673f94d93130fd67f7ade1229c00ac781209681 Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Tue, 20 Aug 2024 19:51:59 +0100 Subject: [PATCH 05/20] Add a licence decision endpoint --- api/data_workspace/v2/serializers.py | 48 ++++++++++--- api/data_workspace/v2/tests/bdd/conftest.py | 48 +++++++++++-- .../bdd/scenarios/licence_decisions.feature | 6 ++ .../v2/tests/bdd/test_licence_decisions.py | 67 +++++++++++++++++++ .../v2/tests/test_serializers/__init__.py | 0 .../test_licence_decision_serializer.py | 23 +++++++ api/data_workspace/v2/urls.py | 5 ++ api/data_workspace/v2/views.py | 17 +++++ 8 files changed, 199 insertions(+), 15 deletions(-) create mode 100644 api/data_workspace/v2/tests/bdd/scenarios/licence_decisions.feature create mode 100644 api/data_workspace/v2/tests/bdd/test_licence_decisions.py create mode 100644 api/data_workspace/v2/tests/test_serializers/__init__.py create mode 100644 api/data_workspace/v2/tests/test_serializers/test_licence_decision_serializer.py diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index b4bb46d8b..2360da3ae 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -1,12 +1,18 @@ +from django.contrib.contenttypes.models import ContentType from rest_framework import serializers from api.applications.models import StandardApplication +from api.audit_trail.enums import AuditType +from api.audit_trail.models import Audit +from api.cases.models import Case +from api.licences.enums import LicenceDecisionType +from api.staticdata.statuses.enums import CaseStatusEnum -def get_original_application(obj): - if not obj.amendment_of: - return obj - return get_original_application(obj.amendment_of) +# def get_original_application(obj): +# if not obj.amendment_of: +# return obj +# return get_original_application(obj.amendment_of) class LicenceStatusSerializer(serializers.Serializer): @@ -18,12 +24,36 @@ class LicenceDecisionTypeSerializer(serializers.Serializer): class SIELApplicationSerializer(serializers.ModelSerializer): - id = serializers.SerializerMethodField(required=False) - class Meta: model = StandardApplication fields = ("id", "status") - def get_id(self, application): - application = get_original_application(application) - return application.pk + +class LicenceDecisionSerializer(serializers.ModelSerializer): + application_id = serializers.UUIDField(source="id") + decision = serializers.SerializerMethodField() + decision_made_at = serializers.SerializerMethodField() + + class Meta: + model = StandardApplication + fields = ( + "application_id", + "decision", + "decision_made_at", + ) + + def get_decision(self, application): + if application.status.status == CaseStatusEnum.WITHDRAWN: + return LicenceDecisionType.WITHDRAWN + + def get_decision_made_at(self, application): + if application.status.status == CaseStatusEnum.WITHDRAWN: + target_content_type = ContentType.objects.get_for_model(Case) + withdrawn_audit_logs = Audit.objects.filter( + payload__status__new__in=["withdrawn", "Withdrawn"], + target_content_type=target_content_type, + target_object_id=application.get_case().pk, + verb=AuditType.UPDATED_STATUS, + ) + audit = withdrawn_audit_logs.latest("created_at") + return audit.created_at diff --git a/api/data_workspace/v2/tests/bdd/conftest.py b/api/data_workspace/v2/tests/bdd/conftest.py index e6db05c38..a8e6d1ecd 100644 --- a/api/data_workspace/v2/tests/bdd/conftest.py +++ b/api/data_workspace/v2/tests/bdd/conftest.py @@ -1,15 +1,21 @@ import pytest from rest_framework import status +from rest_framework.test import APIClient +from api.organisations.tests.factories import OrganisationFactory +from api.users.enums import SystemUser +from api.users.libraries.user_to_token import user_to_token +from api.users.tests.factories import ( + BaseUserFactory, + ExporterUserFactory, + UserOrganisationRelationshipFactory, +) -def pytest_bdd_apply_tag(tag, function): - if tag == "db": - marker = pytest.mark.django_db() - marker(function) - return True - return None +@pytest.fixture(autouse=True) +def system_user(db): + return BaseUserFactory(id=SystemUser.id) @pytest.fixture @@ -45,3 +51,33 @@ def _unpage_data(url): return unpaged_results return _unpage_data + + +@pytest.fixture() +def api_client(): + return APIClient() + + +@pytest.fixture() +def exporter_user(): + return ExporterUserFactory() + + +@pytest.fixture() +def organisation(exporter_user): + organisation = OrganisationFactory() + + UserOrganisationRelationshipFactory( + organisation=organisation, + user=exporter_user, + ) + + return organisation + + +@pytest.fixture() +def exporter_headers(exporter_user, organisation): + return { + "HTTP_EXPORTER_USER_TOKEN": user_to_token(exporter_user.baseuser_ptr), + "HTTP_ORGANISATION_ID": str(organisation.id), + } diff --git a/api/data_workspace/v2/tests/bdd/scenarios/licence_decisions.feature b/api/data_workspace/v2/tests/bdd/scenarios/licence_decisions.feature new file mode 100644 index 000000000..7e0d1d961 --- /dev/null +++ b/api/data_workspace/v2/tests/bdd/scenarios/licence_decisions.feature @@ -0,0 +1,6 @@ +Feature: Licence decisions + +Scenario: Withdrawn application + Given a SIEL application that has been withdrawn by the exporter + Then there will be a licence decision of "withdrawn" for that application + And it will have the time of when the decision was made diff --git a/api/data_workspace/v2/tests/bdd/test_licence_decisions.py b/api/data_workspace/v2/tests/bdd/test_licence_decisions.py new file mode 100644 index 000000000..ac70aa7aa --- /dev/null +++ b/api/data_workspace/v2/tests/bdd/test_licence_decisions.py @@ -0,0 +1,67 @@ +import pytest + +from django.utils import timezone +from django.urls import reverse +from freezegun import freeze_time +from pytest_bdd import ( + given, + parsers, + then, + scenarios, +) +from rest_framework import status + +from api.applications.tests.factories import StandardApplicationFactory +from api.staticdata.statuses.enums import CaseStatusEnum + + +scenarios("./scenarios/licence_decisions.feature") + + +@pytest.fixture() +def licence_decisions_list_url(): + return reverse("data_workspace:v2:dw-licence-decisions-list") + + +@pytest.fixture() +def withdrawn_time(): + with freeze_time("2024-01-01 12:00:01") as frozen_time: + yield timezone.make_aware(frozen_time()) + + +@given("a SIEL application that has been withdrawn by the exporter", target_fixture="application") +def withdrawn_siel_application(api_client, exporter_headers, organisation, withdrawn_time): + submitted_application = StandardApplicationFactory(organisation=organisation) + change_status_url = reverse( + "exporter_applications:change_status", + kwargs={ + "pk": str(submitted_application.pk), + }, + ) + response = api_client.post( + change_status_url, + **exporter_headers, + data={"status": CaseStatusEnum.WITHDRAWN}, + ) + assert response.status_code == status.HTTP_200_OK + + return submitted_application + + +@then( + parsers.parse('there will be a licence decision of "{licence_decision_type}" for that application'), + target_fixture="licence_decisions_data", +) +def licence_decision(licence_decision_type, unpage_data, licence_decisions_list_url, application): + licence_decisions_data = unpage_data(licence_decisions_list_url) + assert len(licence_decisions_data) == 1 + licence_decision = licence_decisions_data[0] + assert licence_decision["application_id"] == str(application.pk) + assert licence_decision["decision"] == licence_decision_type + return licence_decisions_data + + +@then("it will have the time of when the decision was made") +def licence_decision_time(licence_decisions_data, withdrawn_time): + licence_decision = licence_decisions_data[0] + assert licence_decision["decision_made_at"] == withdrawn_time diff --git a/api/data_workspace/v2/tests/test_serializers/__init__.py b/api/data_workspace/v2/tests/test_serializers/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/api/data_workspace/v2/tests/test_serializers/test_licence_decision_serializer.py b/api/data_workspace/v2/tests/test_serializers/test_licence_decision_serializer.py new file mode 100644 index 000000000..6fe863a47 --- /dev/null +++ b/api/data_workspace/v2/tests/test_serializers/test_licence_decision_serializer.py @@ -0,0 +1,23 @@ +from django.test import TestCase +from parameterized import parameterized + +from api.audit_trail.enums import AuditType +from api.audit_trail.tests.factories import AuditFactory +from api.applications.tests.factories import StandardApplicationFactory +from api.data_workspace.v2.serializers import LicenceDecisionSerializer +from api.staticdata.statuses.enums import CaseStatusEnum +from api.staticdata.statuses.libraries.get_case_status import get_case_status_by_status + + +class LicenceDecisionSerializerTests(TestCase): + + @parameterized.expand(["withdrawn", "Withdrawn"]) + def test_decision_made_at_with_withdrawn_status(self, status_name): + application = StandardApplicationFactory(status=get_case_status_by_status(CaseStatusEnum.WITHDRAWN)) + audit = AuditFactory( + payload={"status": {"new": status_name}}, + target=application.get_case(), + verb=AuditType.UPDATED_STATUS, + ) + serializer = LicenceDecisionSerializer(instance=application) + assert serializer.data["decision_made_at"] == audit.created_at diff --git a/api/data_workspace/v2/urls.py b/api/data_workspace/v2/urls.py index b2499035d..071340f19 100644 --- a/api/data_workspace/v2/urls.py +++ b/api/data_workspace/v2/urls.py @@ -19,3 +19,8 @@ views.SIELApplicationsListView, basename="dw-siel-applications", ) +router_v2.register( + "licence-decisions", + views.LicenceDecisionsListView, + basename="dw-licence-decisions", +) diff --git a/api/data_workspace/v2/views.py b/api/data_workspace/v2/views.py index b7c5f2e55..967cf420a 100644 --- a/api/data_workspace/v2/views.py +++ b/api/data_workspace/v2/views.py @@ -8,6 +8,7 @@ from api.applications.models import StandardApplication from api.core.authentication import DataWorkspaceOnlyAuthentication from api.data_workspace.v2.serializers import ( + LicenceDecisionSerializer, LicenceDecisionTypeSerializer, LicenceStatusSerializer, SIELApplicationSerializer, @@ -16,6 +17,8 @@ LicenceDecisionType, LicenceStatus, ) +from api.staticdata.statuses.enums import CaseStatusEnum +from api.staticdata.statuses.libraries.get_case_status import get_case_status_by_status class LicenceStatusesListView(viewsets.GenericViewSet, ListAPIView): @@ -44,3 +47,17 @@ class SIELApplicationsListView(viewsets.ReadOnlyModelViewSet): queryset = StandardApplication.objects.filter(amendment__isnull=True).exclude(submitted_at__isnull=True) renderer_classes = tuple(api_settings.DEFAULT_RENDERER_CLASSES) + (PaginatedCSVRenderer,) serializer_class = SIELApplicationSerializer + + +class LicenceDecisionsListView(viewsets.ReadOnlyModelViewSet): + authentication_classes = (DataWorkspaceOnlyAuthentication,) + pagination_class = LimitOffsetPagination + renderer_classes = tuple(api_settings.DEFAULT_RENDERER_CLASSES) + (PaginatedCSVRenderer,) + serializer_class = LicenceDecisionSerializer + + def get_queryset(self): + withdrawn_status = get_case_status_by_status(CaseStatusEnum.WITHDRAWN) + return StandardApplication.objects.filter( + amendment__isnull=True, + status=withdrawn_status, + ).exclude(submitted_at__isnull=True) From d16560409d93e8982f1cf4d9cccc5e853f2626da Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Wed, 21 Aug 2024 11:17:31 +0100 Subject: [PATCH 06/20] Add logic for issued licence applications --- api/data_workspace/v2/serializers.py | 22 +++++-- api/data_workspace/v2/tests/bdd/conftest.py | 28 +++++++++ .../bdd/scenarios/licence_decisions.feature | 7 ++- .../v2/tests/bdd/test_licence_decisions.py | 57 ++++++++++++++++++- api/data_workspace/v2/views.py | 7 ++- api/users/tests/factories.py | 11 +++- 6 files changed, 121 insertions(+), 11 deletions(-) diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index 2360da3ae..c5382510d 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -46,14 +46,28 @@ def get_decision(self, application): if application.status.status == CaseStatusEnum.WITHDRAWN: return LicenceDecisionType.WITHDRAWN + if application.status.status == CaseStatusEnum.FINALISED: + return LicenceDecisionType.ISSUED + def get_decision_made_at(self, application): + target_content_type = ContentType.objects.get_for_model(Case) + case_audit_logs = Audit.objects.filter( + target_content_type=target_content_type, + target_object_id=application.get_case().pk, + ) + if application.status.status == CaseStatusEnum.WITHDRAWN: - target_content_type = ContentType.objects.get_for_model(Case) - withdrawn_audit_logs = Audit.objects.filter( + withdrawn_audit_logs = case_audit_logs.filter( payload__status__new__in=["withdrawn", "Withdrawn"], - target_content_type=target_content_type, - target_object_id=application.get_case().pk, verb=AuditType.UPDATED_STATUS, ) audit = withdrawn_audit_logs.latest("created_at") return audit.created_at + + if application.status.status == CaseStatusEnum.FINALISED: + issued_audit_logs = case_audit_logs.filter( + payload__status="issued", + verb=AuditType.LICENCE_UPDATED_STATUS, + ) + audit = issued_audit_logs.latest("created_at") + return audit.created_at diff --git a/api/data_workspace/v2/tests/bdd/conftest.py b/api/data_workspace/v2/tests/bdd/conftest.py index a8e6d1ecd..fe9792348 100644 --- a/api/data_workspace/v2/tests/bdd/conftest.py +++ b/api/data_workspace/v2/tests/bdd/conftest.py @@ -3,12 +3,19 @@ from rest_framework import status from rest_framework.test import APIClient +from api.core.constants import ( + GovPermissions, + Roles, +) from api.organisations.tests.factories import OrganisationFactory from api.users.enums import SystemUser from api.users.libraries.user_to_token import user_to_token from api.users.tests.factories import ( BaseUserFactory, ExporterUserFactory, + GovUserFactory, + PermissionFactory, + RoleFactory, UserOrganisationRelationshipFactory, ) @@ -81,3 +88,24 @@ def exporter_headers(exporter_user, organisation): "HTTP_EXPORTER_USER_TOKEN": user_to_token(exporter_user.baseuser_ptr), "HTTP_ORGANISATION_ID": str(organisation.id), } + + +@pytest.fixture(autouse=True) +def internal_default_role_id(db): + role = RoleFactory( + pk=Roles.INTERNAL_DEFAULT_ROLE_ID, + permissions=[ + PermissionFactory(pk=GovPermissions.MANAGE_LICENCE_FINAL_ADVICE.name), + ], + ) + return role + + +@pytest.fixture() +def gov_user(): + return GovUserFactory() + + +@pytest.fixture() +def gov_headers(gov_user): + return {"HTTP_GOV_USER_TOKEN": user_to_token(gov_user.baseuser_ptr)} diff --git a/api/data_workspace/v2/tests/bdd/scenarios/licence_decisions.feature b/api/data_workspace/v2/tests/bdd/scenarios/licence_decisions.feature index 7e0d1d961..6748584c7 100644 --- a/api/data_workspace/v2/tests/bdd/scenarios/licence_decisions.feature +++ b/api/data_workspace/v2/tests/bdd/scenarios/licence_decisions.feature @@ -3,4 +3,9 @@ Feature: Licence decisions Scenario: Withdrawn application Given a SIEL application that has been withdrawn by the exporter Then there will be a licence decision of "withdrawn" for that application - And it will have the time of when the decision was made + And the licence decision time will be the time of when the application was withdrawn + +Scenario: Issued licence application + Given a SIEL application that has a licence issued + Then there will be a licence decision of "issued" for that application + And the licence decision time will be the time of when the licence was issued diff --git a/api/data_workspace/v2/tests/bdd/test_licence_decisions.py b/api/data_workspace/v2/tests/bdd/test_licence_decisions.py index ac70aa7aa..a967aaa1e 100644 --- a/api/data_workspace/v2/tests/bdd/test_licence_decisions.py +++ b/api/data_workspace/v2/tests/bdd/test_licence_decisions.py @@ -12,6 +12,7 @@ from rest_framework import status from api.applications.tests.factories import StandardApplicationFactory +from api.cases.enums import AdviceType from api.staticdata.statuses.enums import CaseStatusEnum @@ -44,7 +45,8 @@ def withdrawn_siel_application(api_client, exporter_headers, organisation, withd data={"status": CaseStatusEnum.WITHDRAWN}, ) assert response.status_code == status.HTTP_200_OK - + submitted_application.refresh_from_db() + assert submitted_application.status.status == CaseStatusEnum.WITHDRAWN return submitted_application @@ -61,7 +63,58 @@ def licence_decision(licence_decision_type, unpage_data, licence_decisions_list_ return licence_decisions_data -@then("it will have the time of when the decision was made") +@then("the licence decision time will be the time of when the application was withdrawn") def licence_decision_time(licence_decisions_data, withdrawn_time): licence_decision = licence_decisions_data[0] assert licence_decision["decision_made_at"] == withdrawn_time + + +@given("a SIEL application that has a licence issued", target_fixture="application") +def application_with_licence_issued(organisation, api_client, gov_headers, issued_time): + submitted_application = StandardApplicationFactory(organisation=organisation) + finalise_application_url = reverse( + "applications:finalise", + kwargs={ + "pk": str(submitted_application.pk), + }, + ) + post_date = timezone.now() + response = api_client.put( + finalise_application_url, + data={ + "action": AdviceType.APPROVE, + "year": post_date.year, + "month": post_date.month, + "day": post_date.day, + }, + **gov_headers, + ) + assert response.status_code == status.HTTP_200_OK, f"Error {response.json()['errors']} raised instead of 200" + + finalise_case_url = reverse( + "cases:finalise", + kwargs={ + "pk": str(submitted_application.pk), + }, + ) + response = api_client.put( + finalise_case_url, + data={}, + **gov_headers, + ) + assert response.status_code == status.HTTP_201_CREATED + submitted_application.refresh_from_db() + assert submitted_application.status.status == CaseStatusEnum.FINALISED + return submitted_application + + +@pytest.fixture() +def issued_time(): + with freeze_time("2024-01-01 12:00:01") as frozen_time: + yield timezone.make_aware(frozen_time()) + + +@then("the licence decision time will be the time of when the licence was issued") +def application_with_licence_issued(licence_decisions_data, issued_time): + licence_decision = licence_decisions_data[0] + assert licence_decision["decision_made_at"] == issued_time diff --git a/api/data_workspace/v2/views.py b/api/data_workspace/v2/views.py index 967cf420a..240737007 100644 --- a/api/data_workspace/v2/views.py +++ b/api/data_workspace/v2/views.py @@ -18,7 +18,6 @@ LicenceStatus, ) from api.staticdata.statuses.enums import CaseStatusEnum -from api.staticdata.statuses.libraries.get_case_status import get_case_status_by_status class LicenceStatusesListView(viewsets.GenericViewSet, ListAPIView): @@ -56,8 +55,10 @@ class LicenceDecisionsListView(viewsets.ReadOnlyModelViewSet): serializer_class = LicenceDecisionSerializer def get_queryset(self): - withdrawn_status = get_case_status_by_status(CaseStatusEnum.WITHDRAWN) return StandardApplication.objects.filter( amendment__isnull=True, - status=withdrawn_status, + status__status__in=[ + CaseStatusEnum.FINALISED, + CaseStatusEnum.WITHDRAWN, + ], ).exclude(submitted_at__isnull=True) diff --git a/api/users/tests/factories.py b/api/users/tests/factories.py index 6702897aa..188f3011e 100644 --- a/api/users/tests/factories.py +++ b/api/users/tests/factories.py @@ -6,7 +6,11 @@ from api.organisations.tests.factories import OrganisationFactory from api.users import models from api.users.enums import UserType, UserStatuses -from api.users.models import Role, UserOrganisationRelationship +from api.users.models import ( + Permission, + Role, + UserOrganisationRelationship, +) from api.teams.tests.factories import TeamFactory faker = Faker() @@ -36,6 +40,11 @@ class Meta: model = models.ExporterUser +class PermissionFactory(factory.django.DjangoModelFactory): + class Meta: + model = Permission + + class RoleFactory(factory.django.DjangoModelFactory): name = "fake_role" type = UserType.EXPORTER From a123235f952e3483d81d1ca410c2ca3fffcccda6 Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Wed, 21 Aug 2024 16:57:57 +0100 Subject: [PATCH 07/20] Add logic for refused licences --- api/data_workspace/v2/serializers.py | 32 ++++- .../bdd/scenarios/licence_decisions.feature | 5 + .../v2/tests/bdd/test_licence_decisions.py | 110 +++++++++++++++++- api/letter_templates/tests/factories.py | 11 ++ .../letter_layouts/tests/__init__.py | 0 .../letter_layouts/tests/factories.py | 8 ++ 6 files changed, 159 insertions(+), 7 deletions(-) create mode 100644 api/letter_templates/tests/factories.py create mode 100644 api/staticdata/letter_layouts/tests/__init__.py create mode 100644 api/staticdata/letter_layouts/tests/factories.py diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index c5382510d..e6f626872 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -6,7 +6,10 @@ from api.audit_trail.models import Audit from api.cases.models import Case from api.licences.enums import LicenceDecisionType -from api.staticdata.statuses.enums import CaseStatusEnum +from api.staticdata.statuses.enums import ( + CaseStatusEnum, + CaseSubStatusIdEnum, +) # def get_original_application(obj): @@ -46,9 +49,18 @@ def get_decision(self, application): if application.status.status == CaseStatusEnum.WITHDRAWN: return LicenceDecisionType.WITHDRAWN - if application.status.status == CaseStatusEnum.FINALISED: + if ( + application.status.status == CaseStatusEnum.FINALISED + and str(application.sub_status.pk) == CaseSubStatusIdEnum.FINALISED__APPROVED + ): return LicenceDecisionType.ISSUED + if ( + application.status.status == CaseStatusEnum.FINALISED + and str(application.sub_status.pk) == CaseSubStatusIdEnum.FINALISED__REFUSED + ): + return LicenceDecisionType.REFUSED + def get_decision_made_at(self, application): target_content_type = ContentType.objects.get_for_model(Case) case_audit_logs = Audit.objects.filter( @@ -64,10 +76,24 @@ def get_decision_made_at(self, application): audit = withdrawn_audit_logs.latest("created_at") return audit.created_at - if application.status.status == CaseStatusEnum.FINALISED: + if ( + application.status.status == CaseStatusEnum.FINALISED + and str(application.sub_status.pk) == CaseSubStatusIdEnum.FINALISED__APPROVED + ): issued_audit_logs = case_audit_logs.filter( payload__status="issued", verb=AuditType.LICENCE_UPDATED_STATUS, ) audit = issued_audit_logs.latest("created_at") return audit.created_at + + if ( + application.status.status == CaseStatusEnum.FINALISED + and str(application.sub_status.pk) == CaseSubStatusIdEnum.FINALISED__REFUSED + ): + issued_audit_logs = case_audit_logs.filter( + payload__decision="refuse", + verb=AuditType.CREATED_FINAL_RECOMMENDATION, + ) + audit = issued_audit_logs.latest("created_at") + return audit.created_at diff --git a/api/data_workspace/v2/tests/bdd/scenarios/licence_decisions.feature b/api/data_workspace/v2/tests/bdd/scenarios/licence_decisions.feature index 6748584c7..ad5fbf127 100644 --- a/api/data_workspace/v2/tests/bdd/scenarios/licence_decisions.feature +++ b/api/data_workspace/v2/tests/bdd/scenarios/licence_decisions.feature @@ -9,3 +9,8 @@ Scenario: Issued licence application Given a SIEL application that has a licence issued Then there will be a licence decision of "issued" for that application And the licence decision time will be the time of when the licence was issued + +Scenario: Refused licence application + Given a SIEL application that has a licence refused + Then there will be a licence decision of "refused" for that application + And the licence decision time will be the time of when the licence was refused diff --git a/api/data_workspace/v2/tests/bdd/test_licence_decisions.py b/api/data_workspace/v2/tests/bdd/test_licence_decisions.py index a967aaa1e..feab00dfc 100644 --- a/api/data_workspace/v2/tests/bdd/test_licence_decisions.py +++ b/api/data_workspace/v2/tests/bdd/test_licence_decisions.py @@ -1,4 +1,5 @@ import pytest +import uuid from django.utils import timezone from django.urls import reverse @@ -12,8 +13,19 @@ from rest_framework import status from api.applications.tests.factories import StandardApplicationFactory -from api.cases.enums import AdviceType -from api.staticdata.statuses.enums import CaseStatusEnum +from api.cases.enums import ( + AdviceType, + CaseTypeEnum, +) +from api.cases.tests.factories import FinalAdviceFactory +from api.cases.generated_documents.tests.factories import GeneratedCaseDocumentFactory +from api.letter_templates.tests.factories import LetterTemplateFactory +from api.staticdata.decisions.models import Decision +from api.staticdata.letter_layouts.tests.factories import LetterLayoutFactory +from api.staticdata.statuses.enums import ( + CaseStatusEnum, + CaseSubStatusIdEnum, +) scenarios("./scenarios/licence_decisions.feature") @@ -70,7 +82,7 @@ def licence_decision_time(licence_decisions_data, withdrawn_time): @given("a SIEL application that has a licence issued", target_fixture="application") -def application_with_licence_issued(organisation, api_client, gov_headers, issued_time): +def application_with_licence_issued(organisation, api_client, gov_headers, gov_user, issued_time): submitted_application = StandardApplicationFactory(organisation=organisation) finalise_application_url = reverse( "applications:finalise", @@ -91,6 +103,26 @@ def application_with_licence_issued(organisation, api_client, gov_headers, issue ) assert response.status_code == status.HTTP_200_OK, f"Error {response.json()['errors']} raised instead of 200" + licence = submitted_application.licences.get() + + FinalAdviceFactory( + case=submitted_application, + user=gov_user, + type=AdviceType.APPROVE, + ) + letter_layout = LetterLayoutFactory(id=uuid.UUID(int=1)) + template = LetterTemplateFactory( + layout=letter_layout, + ) + template.case_types.set([CaseTypeEnum.SIEL.id]) + template.decisions.set([Decision.objects.get(name=AdviceType.APPROVE)]) + GeneratedCaseDocumentFactory( + advice_type=AdviceType.APPROVE, + case=submitted_application.get_case(), + licence=licence, + template=template, + ) + finalise_case_url = reverse( "cases:finalise", kwargs={ @@ -102,9 +134,10 @@ def application_with_licence_issued(organisation, api_client, gov_headers, issue data={}, **gov_headers, ) - assert response.status_code == status.HTTP_201_CREATED + assert response.status_code == status.HTTP_201_CREATED, f"Error {response.json()['errors']} raised instead of 201" submitted_application.refresh_from_db() assert submitted_application.status.status == CaseStatusEnum.FINALISED + assert str(submitted_application.sub_status.pk) == CaseSubStatusIdEnum.FINALISED__APPROVED return submitted_application @@ -118,3 +151,72 @@ def issued_time(): def application_with_licence_issued(licence_decisions_data, issued_time): licence_decision = licence_decisions_data[0] assert licence_decision["decision_made_at"] == issued_time + + +@pytest.fixture() +def refused_time(): + with freeze_time("2024-01-01 12:00:01") as frozen_time: + yield timezone.make_aware(frozen_time()) + + +@given("a SIEL application that has a licence refused", target_fixture="application") +def application_with_licence_refused(organisation, api_client, gov_headers, gov_user, refused_time): + submitted_application = StandardApplicationFactory(organisation=organisation) + finalise_application_url = reverse( + "applications:finalise", + kwargs={ + "pk": str(submitted_application.pk), + }, + ) + post_date = timezone.now() + response = api_client.put( + finalise_application_url, + data={ + "action": AdviceType.REFUSE, + "year": post_date.year, + "month": post_date.month, + "day": post_date.day, + }, + **gov_headers, + ) + assert response.status_code == status.HTTP_200_OK, f"Error {response.json()['errors']} raised instead of 200" + + FinalAdviceFactory( + case=submitted_application, + user=gov_user, + type=AdviceType.REFUSE, + ) + letter_layout = LetterLayoutFactory(id=uuid.UUID(int=1)) + template = LetterTemplateFactory( + layout=letter_layout, + ) + template.case_types.set([CaseTypeEnum.SIEL.id]) + template.decisions.set([Decision.objects.get(name=AdviceType.REFUSE)]) + GeneratedCaseDocumentFactory( + advice_type=AdviceType.REFUSE, + case=submitted_application.get_case(), + template=template, + ) + + finalise_case_url = reverse( + "cases:finalise", + kwargs={ + "pk": str(submitted_application.pk), + }, + ) + response = api_client.put( + finalise_case_url, + data={}, + **gov_headers, + ) + assert response.status_code == status.HTTP_201_CREATED + submitted_application.refresh_from_db() + assert submitted_application.status.status == CaseStatusEnum.FINALISED + assert str(submitted_application.sub_status.pk) == CaseSubStatusIdEnum.FINALISED__REFUSED + return submitted_application + + +@then("the licence decision time will be the time of when the licence was refused") +def application_with_licence_issued(licence_decisions_data, refused_time): + licence_decision = licence_decisions_data[0] + assert licence_decision["decision_made_at"] == refused_time diff --git a/api/letter_templates/tests/factories.py b/api/letter_templates/tests/factories.py new file mode 100644 index 000000000..13f850314 --- /dev/null +++ b/api/letter_templates/tests/factories.py @@ -0,0 +1,11 @@ +import factory + +from api.letter_templates.models import LetterTemplate + + +class LetterTemplateFactory(factory.django.DjangoModelFactory): + include_digital_signature = False + visible_to_exporter = True + + class Meta: + model = LetterTemplate diff --git a/api/staticdata/letter_layouts/tests/__init__.py b/api/staticdata/letter_layouts/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/api/staticdata/letter_layouts/tests/factories.py b/api/staticdata/letter_layouts/tests/factories.py new file mode 100644 index 000000000..1581a041d --- /dev/null +++ b/api/staticdata/letter_layouts/tests/factories.py @@ -0,0 +1,8 @@ +import factory + +from api.staticdata.letter_layouts.models import LetterLayout + + +class LetterLayoutFactory(factory.django.DjangoModelFactory): + class Meta: + model = LetterLayout From 582dd99e535c76229f03990606ec05ab8131d97e Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Wed, 21 Aug 2024 21:24:27 +0100 Subject: [PATCH 08/20] Add NLR decision to endpoint --- api/data_workspace/v2/serializers.py | 30 ++++++++++++- .../bdd/scenarios/licence_decisions.feature | 5 +++ .../v2/tests/bdd/test_licence_decisions.py | 44 +++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index e6f626872..452bbb88b 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -4,6 +4,7 @@ from api.applications.models import StandardApplication from api.audit_trail.enums import AuditType from api.audit_trail.models import Audit +from api.cases.enums import AdviceType from api.cases.models import Case from api.licences.enums import LicenceDecisionType from api.staticdata.statuses.enums import ( @@ -49,6 +50,19 @@ def get_decision(self, application): if application.status.status == CaseStatusEnum.WITHDRAWN: return LicenceDecisionType.WITHDRAWN + if application.status.status == CaseStatusEnum.FINALISED and application.sub_status is None: + target_content_type = ContentType.objects.get_for_model(Case) + case_audit_logs = Audit.objects.filter( + target_content_type=target_content_type, + target_object_id=application.get_case().pk, + ) + final_recommendation_audit_logs = case_audit_logs.filter( + payload__decision=AdviceType.NO_LICENCE_REQUIRED, + verb=AuditType.CREATED_FINAL_RECOMMENDATION, + ) + if final_recommendation_audit_logs.exists(): + return LicenceDecisionType.NLR + if ( application.status.status == CaseStatusEnum.FINALISED and str(application.sub_status.pk) == CaseSubStatusIdEnum.FINALISED__APPROVED @@ -76,6 +90,20 @@ def get_decision_made_at(self, application): audit = withdrawn_audit_logs.latest("created_at") return audit.created_at + if application.status.status == CaseStatusEnum.FINALISED and application.sub_status is None: + target_content_type = ContentType.objects.get_for_model(Case) + case_audit_logs = Audit.objects.filter( + target_content_type=target_content_type, + target_object_id=application.get_case().pk, + ) + final_recommendation_audit_logs = case_audit_logs.filter( + payload__decision=AdviceType.NO_LICENCE_REQUIRED, + verb=AuditType.CREATED_FINAL_RECOMMENDATION, + ) + if final_recommendation_audit_logs.exists(): + audit = final_recommendation_audit_logs.latest("created_at") + return audit.created_at + if ( application.status.status == CaseStatusEnum.FINALISED and str(application.sub_status.pk) == CaseSubStatusIdEnum.FINALISED__APPROVED @@ -92,7 +120,7 @@ def get_decision_made_at(self, application): and str(application.sub_status.pk) == CaseSubStatusIdEnum.FINALISED__REFUSED ): issued_audit_logs = case_audit_logs.filter( - payload__decision="refuse", + payload__decision=AdviceType.REFUSE, verb=AuditType.CREATED_FINAL_RECOMMENDATION, ) audit = issued_audit_logs.latest("created_at") diff --git a/api/data_workspace/v2/tests/bdd/scenarios/licence_decisions.feature b/api/data_workspace/v2/tests/bdd/scenarios/licence_decisions.feature index ad5fbf127..f1065c238 100644 --- a/api/data_workspace/v2/tests/bdd/scenarios/licence_decisions.feature +++ b/api/data_workspace/v2/tests/bdd/scenarios/licence_decisions.feature @@ -14,3 +14,8 @@ Scenario: Refused licence application Given a SIEL application that has a licence refused Then there will be a licence decision of "refused" for that application And the licence decision time will be the time of when the licence was refused + +Scenario: NLR licence application + Given a SIEL application that is NLR + Then there will be a licence decision of "nlr" for that application + And the licence decision time will be the time of when a decision of no licence needed was made diff --git a/api/data_workspace/v2/tests/bdd/test_licence_decisions.py b/api/data_workspace/v2/tests/bdd/test_licence_decisions.py index feab00dfc..098969c19 100644 --- a/api/data_workspace/v2/tests/bdd/test_licence_decisions.py +++ b/api/data_workspace/v2/tests/bdd/test_licence_decisions.py @@ -220,3 +220,47 @@ def application_with_licence_refused(organisation, api_client, gov_headers, gov_ def application_with_licence_issued(licence_decisions_data, refused_time): licence_decision = licence_decisions_data[0] assert licence_decision["decision_made_at"] == refused_time + + +@pytest.fixture() +def nlr_time(): + with freeze_time("2024-01-01 12:00:01") as frozen_time: + yield timezone.make_aware(frozen_time()) + + +@given("a SIEL application that is NLR", target_fixture="application") +def nlr_siel_application(gov_user, organisation, api_client, gov_headers, nlr_time): + submitted_application = StandardApplicationFactory(organisation=organisation) + FinalAdviceFactory(user=gov_user, case=submitted_application, type=AdviceType.NO_LICENCE_REQUIRED) + letter_layout = LetterLayoutFactory(id=uuid.UUID(int=1)) + template = LetterTemplateFactory( + layout=letter_layout, + ) + template.case_types.set([CaseTypeEnum.SIEL.id]) + template.decisions.set([Decision.objects.get(name=AdviceType.NO_LICENCE_REQUIRED)]) + GeneratedCaseDocumentFactory( + advice_type=AdviceType.NO_LICENCE_REQUIRED, + case=submitted_application.get_case(), + template=template, + ) + + finalise_case_url = reverse( + "cases:finalise", + kwargs={ + "pk": str(submitted_application.pk), + }, + ) + response = api_client.put( + finalise_case_url, + data={}, + **gov_headers, + ) + assert response.status_code == status.HTTP_201_CREATED + + return submitted_application + + +@then("the licence decision time will be the time of when a decision of no licence needed was made") +def nlr_licence_decision_time(licence_decisions_data, nlr_time): + licence_decision = licence_decisions_data[0] + assert licence_decision["decision_made_at"] == nlr_time From c97847d196503d650b0b6cca4a3f4d0e7b7a395c Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Thu, 22 Aug 2024 12:07:06 +0100 Subject: [PATCH 09/20] Handle finalised without a sub status --- api/data_workspace/v2/serializers.py | 194 +++++++++++------- .../test_licence_decision_serializer.py | 18 ++ 2 files changed, 133 insertions(+), 79 deletions(-) diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index 452bbb88b..a1d877bb3 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -33,8 +33,115 @@ class Meta: fields = ("id", "status") +def withdrawn_check(application, case_audit_logs): + if application.status.status != CaseStatusEnum.WITHDRAWN: + return + + withdrawn_audit_logs = case_audit_logs.filter( + payload__status__new__in=["withdrawn", "Withdrawn"], + verb=AuditType.UPDATED_STATUS, + ) + audit = withdrawn_audit_logs.latest("created_at") + + return LicenceDecisionType.WITHDRAWN, audit.created_at + + +def nlr_check(application, case_audit_logs): + if application.status.status != CaseStatusEnum.FINALISED: + return + + if application.sub_status is not None: + return + + final_recommendation_audit_logs = case_audit_logs.filter( + payload__decision=AdviceType.NO_LICENCE_REQUIRED, + verb=AuditType.CREATED_FINAL_RECOMMENDATION, + ) + if not final_recommendation_audit_logs.exists(): + return + + audit = final_recommendation_audit_logs.latest("created_at") + + return LicenceDecisionType.NLR, audit.created_at + + +def issued_check(application, case_audit_logs): + if application.status.status != CaseStatusEnum.FINALISED: + return + + if application.sub_status is None: + application_granted_audit_logs = case_audit_logs.filter( + verb=AuditType.GRANTED_APPLICATION, + ) + if not application_granted_audit_logs.exists(): + return + + audit = application_granted_audit_logs.latest("created_at") + return LicenceDecisionType.ISSUED, audit.created_at + + if str(application.sub_status.pk) != CaseSubStatusIdEnum.FINALISED__APPROVED: + return + + issued_audit_logs = case_audit_logs.filter( + payload__status="issued", + verb=AuditType.LICENCE_UPDATED_STATUS, + ) + audit = issued_audit_logs.latest("created_at") + return LicenceDecisionType.ISSUED, audit.created_at + + +def refused_check(application, case_audit_logs): + if application.status.status != CaseStatusEnum.FINALISED: + return + + if application.sub_status is None: + return + + if str(application.sub_status.pk) != CaseSubStatusIdEnum.FINALISED__REFUSED: + return + + final_recommendation_audit_logs = case_audit_logs.filter( + payload__decision=AdviceType.REFUSE, + verb=AuditType.CREATED_FINAL_RECOMMENDATION, + ) + audit = final_recommendation_audit_logs.latest("created_at") + + return LicenceDecisionType.REFUSED, audit.created_at + + +class LicenceDecision: + decision_checks = [ + withdrawn_check, + nlr_check, + issued_check, + refused_check, + ] + + def __init__(self, application): + self.application_id = application.pk + self.setup(application) + + def get_case_audit_logs(self, application): + target_content_type = ContentType.objects.get_for_model(Case) + return Audit.objects.filter( + target_content_type=target_content_type, + target_object_id=application.get_case().pk, + ) + + def setup(self, application): + case_audit_logs = self.get_case_audit_logs(application) + + for decision_check in self.decision_checks: + decision = decision_check(application, case_audit_logs) + if decision: + self.type, self.decision_made_at = decision + break + + return + + class LicenceDecisionSerializer(serializers.ModelSerializer): - application_id = serializers.UUIDField(source="id") + application_id = serializers.UUIDField() decision = serializers.SerializerMethodField() decision_made_at = serializers.SerializerMethodField() @@ -46,82 +153,11 @@ class Meta: "decision_made_at", ) - def get_decision(self, application): - if application.status.status == CaseStatusEnum.WITHDRAWN: - return LicenceDecisionType.WITHDRAWN - - if application.status.status == CaseStatusEnum.FINALISED and application.sub_status is None: - target_content_type = ContentType.objects.get_for_model(Case) - case_audit_logs = Audit.objects.filter( - target_content_type=target_content_type, - target_object_id=application.get_case().pk, - ) - final_recommendation_audit_logs = case_audit_logs.filter( - payload__decision=AdviceType.NO_LICENCE_REQUIRED, - verb=AuditType.CREATED_FINAL_RECOMMENDATION, - ) - if final_recommendation_audit_logs.exists(): - return LicenceDecisionType.NLR - - if ( - application.status.status == CaseStatusEnum.FINALISED - and str(application.sub_status.pk) == CaseSubStatusIdEnum.FINALISED__APPROVED - ): - return LicenceDecisionType.ISSUED - - if ( - application.status.status == CaseStatusEnum.FINALISED - and str(application.sub_status.pk) == CaseSubStatusIdEnum.FINALISED__REFUSED - ): - return LicenceDecisionType.REFUSED - - def get_decision_made_at(self, application): - target_content_type = ContentType.objects.get_for_model(Case) - case_audit_logs = Audit.objects.filter( - target_content_type=target_content_type, - target_object_id=application.get_case().pk, - ) + def to_representation(self, instance): + return super().to_representation(LicenceDecision(instance)) + + def get_decision(self, licence_decision): + return licence_decision.type - if application.status.status == CaseStatusEnum.WITHDRAWN: - withdrawn_audit_logs = case_audit_logs.filter( - payload__status__new__in=["withdrawn", "Withdrawn"], - verb=AuditType.UPDATED_STATUS, - ) - audit = withdrawn_audit_logs.latest("created_at") - return audit.created_at - - if application.status.status == CaseStatusEnum.FINALISED and application.sub_status is None: - target_content_type = ContentType.objects.get_for_model(Case) - case_audit_logs = Audit.objects.filter( - target_content_type=target_content_type, - target_object_id=application.get_case().pk, - ) - final_recommendation_audit_logs = case_audit_logs.filter( - payload__decision=AdviceType.NO_LICENCE_REQUIRED, - verb=AuditType.CREATED_FINAL_RECOMMENDATION, - ) - if final_recommendation_audit_logs.exists(): - audit = final_recommendation_audit_logs.latest("created_at") - return audit.created_at - - if ( - application.status.status == CaseStatusEnum.FINALISED - and str(application.sub_status.pk) == CaseSubStatusIdEnum.FINALISED__APPROVED - ): - issued_audit_logs = case_audit_logs.filter( - payload__status="issued", - verb=AuditType.LICENCE_UPDATED_STATUS, - ) - audit = issued_audit_logs.latest("created_at") - return audit.created_at - - if ( - application.status.status == CaseStatusEnum.FINALISED - and str(application.sub_status.pk) == CaseSubStatusIdEnum.FINALISED__REFUSED - ): - issued_audit_logs = case_audit_logs.filter( - payload__decision=AdviceType.REFUSE, - verb=AuditType.CREATED_FINAL_RECOMMENDATION, - ) - audit = issued_audit_logs.latest("created_at") - return audit.created_at + def get_decision_made_at(self, licence_decision): + return licence_decision.decision_made_at diff --git a/api/data_workspace/v2/tests/test_serializers/test_licence_decision_serializer.py b/api/data_workspace/v2/tests/test_serializers/test_licence_decision_serializer.py index 6fe863a47..73ddff86f 100644 --- a/api/data_workspace/v2/tests/test_serializers/test_licence_decision_serializer.py +++ b/api/data_workspace/v2/tests/test_serializers/test_licence_decision_serializer.py @@ -1,3 +1,5 @@ +import datetime + from django.test import TestCase from parameterized import parameterized @@ -5,6 +7,7 @@ from api.audit_trail.tests.factories import AuditFactory from api.applications.tests.factories import StandardApplicationFactory from api.data_workspace.v2.serializers import LicenceDecisionSerializer +from api.licences.enums import LicenceDecisionType from api.staticdata.statuses.enums import CaseStatusEnum from api.staticdata.statuses.libraries.get_case_status import get_case_status_by_status @@ -21,3 +24,18 @@ def test_decision_made_at_with_withdrawn_status(self, status_name): ) serializer = LicenceDecisionSerializer(instance=application) assert serializer.data["decision_made_at"] == audit.created_at + + def test_finalised_without_sub_status(self): + application = StandardApplicationFactory(status=get_case_status_by_status(CaseStatusEnum.FINALISED)) + assert application.sub_status is None + audit = AuditFactory( + payload={ + "start_date": datetime.date.today().isoformat(), + "licence_duration": "12", + }, + target=application.get_case(), + verb=AuditType.GRANTED_APPLICATION, + ) + serializer = LicenceDecisionSerializer(instance=application) + assert serializer.data["decision"] == LicenceDecisionType.ISSUED + assert serializer.data["decision_made_at"] == audit.created_at From a6aa8ebb772eafd7def9505bb8b0dfcda07519c2 Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Thu, 22 Aug 2024 12:40:32 +0100 Subject: [PATCH 10/20] Add refusal letter check for refused licence --- api/data_workspace/v2/serializers.py | 17 ++++++++++++----- .../test_licence_decision_serializer.py | 17 ++++++++++++++++- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index a1d877bb3..f491e788d 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -95,7 +95,14 @@ def refused_check(application, case_audit_logs): return if application.sub_status is None: - return + refusal_letter_generated_audit_logs = case_audit_logs.filter( + payload__template="Refusal letter template", + verb=AuditType.GENERATE_CASE_DOCUMENT, + ) + if not refusal_letter_generated_audit_logs.exists(): + return + audit = refusal_letter_generated_audit_logs.latest("created_at") + return LicenceDecisionType.REFUSED, audit.created_at if str(application.sub_status.pk) != CaseSubStatusIdEnum.FINALISED__REFUSED: return @@ -136,8 +143,8 @@ def setup(self, application): if decision: self.type, self.decision_made_at = decision break - - return + else: + raise ValueError(f"Cannot determine type of licence decision for application {application.reference_code}") class LicenceDecisionSerializer(serializers.ModelSerializer): @@ -153,8 +160,8 @@ class Meta: "decision_made_at", ) - def to_representation(self, instance): - return super().to_representation(LicenceDecision(instance)) + def to_representation(self, application): + return super().to_representation(LicenceDecision(application)) def get_decision(self, licence_decision): return licence_decision.type diff --git a/api/data_workspace/v2/tests/test_serializers/test_licence_decision_serializer.py b/api/data_workspace/v2/tests/test_serializers/test_licence_decision_serializer.py index 73ddff86f..64797384a 100644 --- a/api/data_workspace/v2/tests/test_serializers/test_licence_decision_serializer.py +++ b/api/data_workspace/v2/tests/test_serializers/test_licence_decision_serializer.py @@ -25,7 +25,7 @@ def test_decision_made_at_with_withdrawn_status(self, status_name): serializer = LicenceDecisionSerializer(instance=application) assert serializer.data["decision_made_at"] == audit.created_at - def test_finalised_without_sub_status(self): + def test_finalised_and_issued_without_sub_status_with_granted_application_audit(self): application = StandardApplicationFactory(status=get_case_status_by_status(CaseStatusEnum.FINALISED)) assert application.sub_status is None audit = AuditFactory( @@ -39,3 +39,18 @@ def test_finalised_without_sub_status(self): serializer = LicenceDecisionSerializer(instance=application) assert serializer.data["decision"] == LicenceDecisionType.ISSUED assert serializer.data["decision_made_at"] == audit.created_at + + def test_finalised_and_refused_without_sub_status_with_refusal_letter_generated_audit(self): + application = StandardApplicationFactory(status=get_case_status_by_status(CaseStatusEnum.FINALISED)) + assert application.sub_status is None + audit = AuditFactory( + payload={ + "file_name": "madeupfile.doc", + "template": "Refusal letter template", + }, + target=application.get_case(), + verb=AuditType.GENERATE_CASE_DOCUMENT, + ) + serializer = LicenceDecisionSerializer(instance=application) + assert serializer.data["decision"] == LicenceDecisionType.REFUSED + assert serializer.data["decision_made_at"] == audit.created_at From 57bd453968224e7888080f5b475c183a06d62a62 Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Thu, 22 Aug 2024 13:06:09 +0100 Subject: [PATCH 11/20] Add NLR letter generation logic --- api/data_workspace/v2/serializers.py | 15 ++++++++++----- .../test_licence_decision_serializer.py | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index f491e788d..0c4d46077 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -57,12 +57,17 @@ def nlr_check(application, case_audit_logs): payload__decision=AdviceType.NO_LICENCE_REQUIRED, verb=AuditType.CREATED_FINAL_RECOMMENDATION, ) - if not final_recommendation_audit_logs.exists(): - return - - audit = final_recommendation_audit_logs.latest("created_at") + if final_recommendation_audit_logs.exists(): + audit = final_recommendation_audit_logs.latest("created_at") + return LicenceDecisionType.NLR, audit.created_at - return LicenceDecisionType.NLR, audit.created_at + nlr_letter_audit_logs = case_audit_logs.filter( + payload__template="No licence required letter template", + verb=AuditType.GENERATE_CASE_DOCUMENT, + ) + if nlr_letter_audit_logs.exists(): + audit = nlr_letter_audit_logs.latest("created_at") + return LicenceDecisionType.NLR, audit.created_at def issued_check(application, case_audit_logs): diff --git a/api/data_workspace/v2/tests/test_serializers/test_licence_decision_serializer.py b/api/data_workspace/v2/tests/test_serializers/test_licence_decision_serializer.py index 64797384a..fedcb5dfc 100644 --- a/api/data_workspace/v2/tests/test_serializers/test_licence_decision_serializer.py +++ b/api/data_workspace/v2/tests/test_serializers/test_licence_decision_serializer.py @@ -54,3 +54,18 @@ def test_finalised_and_refused_without_sub_status_with_refusal_letter_generated_ serializer = LicenceDecisionSerializer(instance=application) assert serializer.data["decision"] == LicenceDecisionType.REFUSED assert serializer.data["decision_made_at"] == audit.created_at + + def test_finalised_and_nlr_without_sub_status_with_nlr_letter_generated_audit(self): + application = StandardApplicationFactory(status=get_case_status_by_status(CaseStatusEnum.FINALISED)) + assert application.sub_status is None + audit = AuditFactory( + payload={ + "file_name": "madeupfile.doc", + "template": "No licence required letter template", + }, + target=application.get_case(), + verb=AuditType.GENERATE_CASE_DOCUMENT, + ) + serializer = LicenceDecisionSerializer(instance=application) + assert serializer.data["decision"] == LicenceDecisionType.NLR + assert serializer.data["decision_made_at"] == audit.created_at From 16eb872cc95c9f1efe6ab67eea5c4369050ba077 Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Thu, 22 Aug 2024 13:35:22 +0100 Subject: [PATCH 12/20] Extract out a decorator for checking licence types --- api/data_workspace/v2/serializers.py | 34 ++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index 0c4d46077..efa60f7ba 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -1,3 +1,5 @@ +from functools import wraps + from django.contrib.contenttypes.models import ContentType from rest_framework import serializers @@ -33,6 +35,21 @@ class Meta: fields = ("id", "status") +def decision_type_checker(decision_type): + def _decision_type_check(func): + @wraps(func) + def wrapper(application, case_audit_logs): + decision_made_at = func(application, case_audit_logs) + if not decision_made_at: + return None + return decision_type, decision_made_at + + return wrapper + + return _decision_type_check + + +@decision_type_checker(LicenceDecisionType.WITHDRAWN) def withdrawn_check(application, case_audit_logs): if application.status.status != CaseStatusEnum.WITHDRAWN: return @@ -43,9 +60,10 @@ def withdrawn_check(application, case_audit_logs): ) audit = withdrawn_audit_logs.latest("created_at") - return LicenceDecisionType.WITHDRAWN, audit.created_at + return audit.created_at +@decision_type_checker(LicenceDecisionType.NLR) def nlr_check(application, case_audit_logs): if application.status.status != CaseStatusEnum.FINALISED: return @@ -59,7 +77,7 @@ def nlr_check(application, case_audit_logs): ) if final_recommendation_audit_logs.exists(): audit = final_recommendation_audit_logs.latest("created_at") - return LicenceDecisionType.NLR, audit.created_at + return audit.created_at nlr_letter_audit_logs = case_audit_logs.filter( payload__template="No licence required letter template", @@ -67,9 +85,10 @@ def nlr_check(application, case_audit_logs): ) if nlr_letter_audit_logs.exists(): audit = nlr_letter_audit_logs.latest("created_at") - return LicenceDecisionType.NLR, audit.created_at + return audit.created_at +@decision_type_checker(LicenceDecisionType.ISSUED) def issued_check(application, case_audit_logs): if application.status.status != CaseStatusEnum.FINALISED: return @@ -82,7 +101,7 @@ def issued_check(application, case_audit_logs): return audit = application_granted_audit_logs.latest("created_at") - return LicenceDecisionType.ISSUED, audit.created_at + return audit.created_at if str(application.sub_status.pk) != CaseSubStatusIdEnum.FINALISED__APPROVED: return @@ -92,9 +111,10 @@ def issued_check(application, case_audit_logs): verb=AuditType.LICENCE_UPDATED_STATUS, ) audit = issued_audit_logs.latest("created_at") - return LicenceDecisionType.ISSUED, audit.created_at + return audit.created_at +@decision_type_checker(LicenceDecisionType.REFUSED) def refused_check(application, case_audit_logs): if application.status.status != CaseStatusEnum.FINALISED: return @@ -107,7 +127,7 @@ def refused_check(application, case_audit_logs): if not refusal_letter_generated_audit_logs.exists(): return audit = refusal_letter_generated_audit_logs.latest("created_at") - return LicenceDecisionType.REFUSED, audit.created_at + return audit.created_at if str(application.sub_status.pk) != CaseSubStatusIdEnum.FINALISED__REFUSED: return @@ -118,7 +138,7 @@ def refused_check(application, case_audit_logs): ) audit = final_recommendation_audit_logs.latest("created_at") - return LicenceDecisionType.REFUSED, audit.created_at + return audit.created_at class LicenceDecision: From 7716e82e0fc42e4cbeed77acb1e16563e7d0216e Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Thu, 22 Aug 2024 14:14:42 +0100 Subject: [PATCH 13/20] Add logic for missing sub status on issued licence --- api/data_workspace/v2/serializers.py | 16 +++++++++++---- .../test_licence_decision_serializer.py | 20 ++++++++++++++++++- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index efa60f7ba..08553da64 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -94,14 +94,22 @@ def issued_check(application, case_audit_logs): return if application.sub_status is None: + issued_audit_logs = case_audit_logs.filter( + payload__status="issued", + verb=AuditType.LICENCE_UPDATED_STATUS, + ) + if issued_audit_logs.exists(): + audit = issued_audit_logs.latest("created_at") + return audit.created_at + application_granted_audit_logs = case_audit_logs.filter( verb=AuditType.GRANTED_APPLICATION, ) - if not application_granted_audit_logs.exists(): - return + if application_granted_audit_logs.exists(): + audit = application_granted_audit_logs.latest("created_at") + return audit.created_at - audit = application_granted_audit_logs.latest("created_at") - return audit.created_at + return if str(application.sub_status.pk) != CaseSubStatusIdEnum.FINALISED__APPROVED: return diff --git a/api/data_workspace/v2/tests/test_serializers/test_licence_decision_serializer.py b/api/data_workspace/v2/tests/test_serializers/test_licence_decision_serializer.py index fedcb5dfc..91523d78d 100644 --- a/api/data_workspace/v2/tests/test_serializers/test_licence_decision_serializer.py +++ b/api/data_workspace/v2/tests/test_serializers/test_licence_decision_serializer.py @@ -7,7 +7,10 @@ from api.audit_trail.tests.factories import AuditFactory from api.applications.tests.factories import StandardApplicationFactory from api.data_workspace.v2.serializers import LicenceDecisionSerializer -from api.licences.enums import LicenceDecisionType +from api.licences.enums import ( + LicenceDecisionType, + LicenceStatus, +) from api.staticdata.statuses.enums import CaseStatusEnum from api.staticdata.statuses.libraries.get_case_status import get_case_status_by_status @@ -69,3 +72,18 @@ def test_finalised_and_nlr_without_sub_status_with_nlr_letter_generated_audit(se serializer = LicenceDecisionSerializer(instance=application) assert serializer.data["decision"] == LicenceDecisionType.NLR assert serializer.data["decision_made_at"] == audit.created_at + + def test_finalised_and_issued_without_sub_status_with_issued_updated_status(self): + application = StandardApplicationFactory(status=get_case_status_by_status(CaseStatusEnum.FINALISED)) + assert application.sub_status is None + audit = AuditFactory( + payload={ + "licence": application.reference_code, + "status": LicenceStatus.ISSUED, + }, + target=application.get_case(), + verb=AuditType.LICENCE_UPDATED_STATUS, + ) + serializer = LicenceDecisionSerializer(instance=application) + assert serializer.data["decision"] == LicenceDecisionType.ISSUED + assert serializer.data["decision_made_at"] == audit.created_at From 85191dadb837da87006f142b6d9c64bfe39dc58f Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Thu, 22 Aug 2024 14:25:51 +0100 Subject: [PATCH 14/20] Add logic for refused licences without sub-status --- api/data_workspace/v2/serializers.py | 17 +++++++++++++---- .../test_licence_decision_serializer.py | 16 ++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index 08553da64..8d9587708 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -128,14 +128,23 @@ def refused_check(application, case_audit_logs): return if application.sub_status is None: + final_recommendation_audit_logs = case_audit_logs.filter( + payload__decision=AdviceType.REFUSE, + verb=AuditType.CREATED_FINAL_RECOMMENDATION, + ) + if final_recommendation_audit_logs.exists(): + audit = final_recommendation_audit_logs.latest("created_at") + return audit.created_at + refusal_letter_generated_audit_logs = case_audit_logs.filter( payload__template="Refusal letter template", verb=AuditType.GENERATE_CASE_DOCUMENT, ) - if not refusal_letter_generated_audit_logs.exists(): - return - audit = refusal_letter_generated_audit_logs.latest("created_at") - return audit.created_at + if refusal_letter_generated_audit_logs.exists(): + audit = refusal_letter_generated_audit_logs.latest("created_at") + return audit.created_at + + return if str(application.sub_status.pk) != CaseSubStatusIdEnum.FINALISED__REFUSED: return diff --git a/api/data_workspace/v2/tests/test_serializers/test_licence_decision_serializer.py b/api/data_workspace/v2/tests/test_serializers/test_licence_decision_serializer.py index 91523d78d..40d8d9e5a 100644 --- a/api/data_workspace/v2/tests/test_serializers/test_licence_decision_serializer.py +++ b/api/data_workspace/v2/tests/test_serializers/test_licence_decision_serializer.py @@ -87,3 +87,19 @@ def test_finalised_and_issued_without_sub_status_with_issued_updated_status(self serializer = LicenceDecisionSerializer(instance=application) assert serializer.data["decision"] == LicenceDecisionType.ISSUED assert serializer.data["decision_made_at"] == audit.created_at + + def test_finalised_and_refused_without_status_with_licence_refused_decision(self): + application = StandardApplicationFactory(status=get_case_status_by_status(CaseStatusEnum.FINALISED)) + assert application.sub_status is None + audit = AuditFactory( + payload={ + "case_reference": application.reference_code, + "decision": "refuse", + "licence_reference": "", + }, + target=application.get_case(), + verb=AuditType.CREATED_FINAL_RECOMMENDATION, + ) + serializer = LicenceDecisionSerializer(instance=application) + assert serializer.data["decision"] == LicenceDecisionType.REFUSED + assert serializer.data["decision_made_at"] == audit.created_at From 0794d1cb42b8305da3d44f8de2a346f76a2c6cfb Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Tue, 27 Aug 2024 13:05:22 +0100 Subject: [PATCH 15/20] Separate out data BDD tests into separate job --- .circleci/config.yml | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8a29ab99d..8b7a5af7c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -134,7 +134,7 @@ jobs: - run: name: Run tests command: | - pipenv run pytest --circleci-parallelize --cov=. --cov-report xml --cov-config=.coveragerc --ignore lite_routing --ignore api/anonymised_db_dumps -k "not seeding and not elasticsearch and not performance and not migration and not db_anonymiser" + pipenv run pytest --circleci-parallelize --cov=. --cov-report xml --cov-config=.coveragerc --ignore lite_routing --ignore api/anonymised_db_dumps --ignore api/data_workspace/v2/tests/bdd -k "not seeding and not elasticsearch and not performance and not migration and not db_anonymiser" - upload_code_coverage: alias: tests @@ -154,7 +154,7 @@ jobs: - run: name: Run tests on Postgres 13 command: | - pipenv run pytest --circleci-parallelize --cov=. --cov-report xml --cov-config=.coveragerc --ignore lite_routing --ignore api/anonymised_db_dumps -k "not seeding and not elasticsearch and not performance and not migration and not db_anonymiser" + pipenv run pytest --circleci-parallelize --cov=. --cov-report xml --cov-config=.coveragerc --ignore lite_routing --ignore api/anonymised_db_dumps --ignore api/data_workspace/v2/tests/bdd -k "not seeding and not elasticsearch and not performance and not migration and not db_anonymiser" - upload_code_coverage: alias: tests_dbt_platform @@ -370,6 +370,36 @@ jobs: - store_artifacts: path: cucumber_html + lite_data_bdd_tests: + docker: + - <<: *image_python_node + - <<: *image_postgres13 + - <<: *image_opensearch + - <<: *image_redis + working_directory: ~/lite-api + environment: + <<: *common_env_vars + LITE_API_ENABLE_ES: True + parallelism: 5 + steps: + - setup + - run: + name: Install cucumber reporter package + command: npm install multiple-cucumber-html-reporter + - run: + name: Create report directories + command: | + mkdir cucumber_results + - run: + name: Run lite_routing tests + command: pipenv run pytest --circleci-parallelize --gherkin-terminal-reporter -vv api/data_workspace/v2/tests/bdd --cucumberjson=cucumber_results/cuc.json + - run: + name: Generate html cucumber report + command: node generate_cucumber_report.js + when: always + - store_artifacts: + path: cucumber_html + open_search_tests: docker: - <<: *image_python @@ -600,6 +630,7 @@ workflows: - lite_routing_tests_dbt_platform - lite_routing_bdd_tests - lite_routing_bdd_tests_dbt_platform + - lite_data_bdd_tests - open_search_tests_dbt_platform - open_search_tests - migration_tests @@ -613,6 +644,7 @@ workflows: - open_search_tests - migration_tests - lite_routing_tests + - lite_data_bdd_tests - check-lite-routing-sha - e2e_tests - anonymised_db_dump_tests From 51709915af628b343c788a9a1ee7cfb6dd40b795 Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Wed, 28 Aug 2024 13:56:49 +0100 Subject: [PATCH 16/20] Add back finding original id of application from amendments chain --- api/data_workspace/v2/serializers.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/api/data_workspace/v2/serializers.py b/api/data_workspace/v2/serializers.py index 8d9587708..29bad536b 100644 --- a/api/data_workspace/v2/serializers.py +++ b/api/data_workspace/v2/serializers.py @@ -15,10 +15,10 @@ ) -# def get_original_application(obj): -# if not obj.amendment_of: -# return obj -# return get_original_application(obj.amendment_of) +def get_original_application(obj): + if not obj.amendment_of: + return obj + return get_original_application(obj.amendment_of) class LicenceStatusSerializer(serializers.Serializer): @@ -30,10 +30,15 @@ class LicenceDecisionTypeSerializer(serializers.Serializer): class SIELApplicationSerializer(serializers.ModelSerializer): + id = serializers.SerializerMethodField() + class Meta: model = StandardApplication fields = ("id", "status") + def get_id(self, application): + return get_original_application(application).pk + def decision_type_checker(decision_type): def _decision_type_check(func): From bba298c635b13ff7346301d02b4fac07d06fcd23 Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Wed, 28 Aug 2024 14:09:40 +0100 Subject: [PATCH 17/20] Move submitted_at as an optional factory attribute to set --- api/applications/tests/factories.py | 7 ++--- .../v2/tests/bdd/test_licence_decisions.py | 21 ++++++++++--- .../v2/tests/bdd/test_siel_applications.py | 30 ++++++++++++++----- 3 files changed, 43 insertions(+), 15 deletions(-) diff --git a/api/applications/tests/factories.py b/api/applications/tests/factories.py index 2d183a712..13bafaa60 100644 --- a/api/applications/tests/factories.py +++ b/api/applications/tests/factories.py @@ -1,4 +1,3 @@ -import datetime import factory from faker import Faker @@ -61,11 +60,11 @@ class Meta: @classmethod def _create(cls, model_class, *args, **kwargs): obj = model_class(*args, **kwargs) + obj.status = get_case_status_by_status(CaseStatusEnum.SUBMITTED) if "status" in kwargs and isinstance(kwargs["status"], CaseStatus): obj.status = kwargs["status"] - else: - obj.status = get_case_status_by_status(CaseStatusEnum.SUBMITTED) - obj.submitted_at = datetime.datetime.now() + if "submitted_at" in kwargs: + obj.submitted_at = kwargs["submitted_at"] obj.save() return obj diff --git a/api/data_workspace/v2/tests/bdd/test_licence_decisions.py b/api/data_workspace/v2/tests/bdd/test_licence_decisions.py index 098969c19..1505afd69 100644 --- a/api/data_workspace/v2/tests/bdd/test_licence_decisions.py +++ b/api/data_workspace/v2/tests/bdd/test_licence_decisions.py @@ -1,3 +1,4 @@ +import datetime import pytest import uuid @@ -44,7 +45,10 @@ def withdrawn_time(): @given("a SIEL application that has been withdrawn by the exporter", target_fixture="application") def withdrawn_siel_application(api_client, exporter_headers, organisation, withdrawn_time): - submitted_application = StandardApplicationFactory(organisation=organisation) + submitted_application = StandardApplicationFactory( + organisation=organisation, + submitted_at=datetime.datetime.now(), + ) change_status_url = reverse( "exporter_applications:change_status", kwargs={ @@ -83,7 +87,10 @@ def licence_decision_time(licence_decisions_data, withdrawn_time): @given("a SIEL application that has a licence issued", target_fixture="application") def application_with_licence_issued(organisation, api_client, gov_headers, gov_user, issued_time): - submitted_application = StandardApplicationFactory(organisation=organisation) + submitted_application = StandardApplicationFactory( + organisation=organisation, + submitted_at=datetime.datetime.now(), + ) finalise_application_url = reverse( "applications:finalise", kwargs={ @@ -161,7 +168,10 @@ def refused_time(): @given("a SIEL application that has a licence refused", target_fixture="application") def application_with_licence_refused(organisation, api_client, gov_headers, gov_user, refused_time): - submitted_application = StandardApplicationFactory(organisation=organisation) + submitted_application = StandardApplicationFactory( + organisation=organisation, + submitted_at=datetime.datetime.now(), + ) finalise_application_url = reverse( "applications:finalise", kwargs={ @@ -230,7 +240,10 @@ def nlr_time(): @given("a SIEL application that is NLR", target_fixture="application") def nlr_siel_application(gov_user, organisation, api_client, gov_headers, nlr_time): - submitted_application = StandardApplicationFactory(organisation=organisation) + submitted_application = StandardApplicationFactory( + organisation=organisation, + submitted_at=datetime.datetime.now(), + ) FinalAdviceFactory(user=gov_user, case=submitted_application, type=AdviceType.NO_LICENCE_REQUIRED) letter_layout = LetterLayoutFactory(id=uuid.UUID(int=1)) template = LetterTemplateFactory( diff --git a/api/data_workspace/v2/tests/bdd/test_siel_applications.py b/api/data_workspace/v2/tests/bdd/test_siel_applications.py index 26f8e784c..812a99e72 100644 --- a/api/data_workspace/v2/tests/bdd/test_siel_applications.py +++ b/api/data_workspace/v2/tests/bdd/test_siel_applications.py @@ -1,3 +1,4 @@ +import datetime import pytest from django.urls import reverse @@ -34,7 +35,9 @@ def draft_application_not_presented(unpage_data, siel_applications_list_url): @given("a submitted SIEL application without an amendment", target_fixture="siel_application") def siel_application_without_an_amendment(): - return StandardApplicationFactory() + return StandardApplicationFactory( + submitted_at=datetime.datetime.now(), + ) @then("it is presented as a single SIEL application", target_fixture="siel_application_data") @@ -51,8 +54,13 @@ def siel_application_id_of_itself(siel_application, siel_application_data): @given("a submitted SIEL application that has been amended", target_fixture="original_siel_application") def siel_application_with_an_amendment(): - original_siel_application = StandardApplicationFactory() - StandardApplicationFactory(amendment_of=original_siel_application) + original_siel_application = StandardApplicationFactory( + submitted_at=datetime.datetime.now(), + ) + StandardApplicationFactory( + amendment_of=original_siel_application, + submitted_at=datetime.datetime.now(), + ) return original_siel_application @@ -63,8 +71,16 @@ def siel_application_has_first_id_in_amendment_chain(original_siel_application, @given("a submitted SIEL application with multiple amendments", target_fixture="original_siel_application") def siel_application_with_multiple_amendments(): - original_siel_application = StandardApplicationFactory() - next_siel_application = StandardApplicationFactory(amendment_of=original_siel_application) - another_siel_application = StandardApplicationFactory(amendment_of=next_siel_application) - StandardApplicationFactory(amendment_of=another_siel_application) + original_siel_application = StandardApplicationFactory( + submitted_at=datetime.datetime.now(), + ) + next_siel_application = StandardApplicationFactory( + amendment_of=original_siel_application, + submitted_at=datetime.datetime.now(), + ) + another_siel_application = StandardApplicationFactory( + amendment_of=next_siel_application, + submitted_at=datetime.datetime.now(), + ) + StandardApplicationFactory(amendment_of=another_siel_application, submitted_at=datetime.datetime.now()) return original_siel_application From 68bfec7de45f27cbdc84234a0bbf99ee68eba7f2 Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Wed, 28 Aug 2024 15:11:01 +0100 Subject: [PATCH 18/20] Update Python lockfile --- Pipfile.lock | 311 +++++++++++++++++++++++++-------------------------- 1 file changed, 153 insertions(+), 158 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index e9a919fec..9a535e119 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -789,11 +789,11 @@ }, "googleapis-common-protos": { "hashes": [ - "sha256:27a2499c7e8aff199665b22741997e485eccc8645aa9176c7c988e6fae507945", - "sha256:27c5abdffc4911f28101e635de1533fb4cfd2c37fbaa9174587c799fac90aa87" + "sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63", + "sha256:334a29d07cddc3aa01dee4988f9afd9b2916ee2ff49d6b757155dc0d197852c0" ], "markers": "python_version >= '3.7'", - "version": "==1.63.2" + "version": "==1.65.0" }, "gprof2dot": { "hashes": [ @@ -869,55 +869,55 @@ }, "grpcio": { "hashes": [ - "sha256:05f02d68fc720e085f061b704ee653b181e6d5abfe315daef085719728d3d1fd", - "sha256:078038e150a897e5e402ed3d57f1d31ebf604cbed80f595bd281b5da40762a92", - "sha256:0b2944390a496567de9e70418f3742b477d85d8ca065afa90432edc91b4bb8ad", - "sha256:11f8b16121768c1cb99d7dcb84e01510e60e6a206bf9123e134118802486f035", - "sha256:1c4caafe71aef4dabf53274bbf4affd6df651e9f80beedd6b8e08ff438ed3260", - "sha256:1cbc208edb9acf1cc339396a1a36b83796939be52f34e591c90292045b579fbf", - "sha256:238a625f391a1b9f5f069bdc5930f4fd71b74426bea52196fc7b83f51fa97d34", - "sha256:2a6d8169812932feac514b420daffae8ab8e36f90f3122b94ae767e633296b17", - "sha256:2b91ce647b6307f25650872454a4d02a2801f26a475f90d0b91ed8110baae589", - "sha256:3207ae60d07e5282c134b6e02f9271a2cb523c6d7a346c6315211fe2bf8d61ed", - "sha256:32d60e18ff7c34fe3f6db3d35ad5c6dc99f5b43ff3982cb26fad4174462d10b1", - "sha256:33158e56c6378063923c417e9fbdb28660b6e0e2835af42e67f5a7793f587af7", - "sha256:47d0aaaab82823f0aa6adea5184350b46e2252e13a42a942db84da5b733f2e05", - "sha256:55714ea852396ec9568f45f487639945ab674de83c12bea19d5ddbc3ae41ada3", - "sha256:6c4e62bcf297a1568f627f39576dbfc27f1e5338a691c6dd5dd6b3979da51d1c", - "sha256:76991b7a6fb98630a3328839755181ce7c1aa2b1842aa085fd4198f0e5198960", - "sha256:770bd4bd721961f6dd8049bc27338564ba8739913f77c0f381a9815e465ff965", - "sha256:7a412959aa5f08c5ac04aa7b7c3c041f5e4298cadd4fcc2acff195b56d185ebc", - "sha256:84c901cdec16a092099f251ef3360d15e29ef59772150fa261d94573612539b5", - "sha256:85ae8f8517d5bcc21fb07dbf791e94ed84cc28f84c903cdc2bd7eaeb437c8f45", - "sha256:89c00a18801b1ed9cc441e29b521c354725d4af38c127981f2c950c796a09b6e", - "sha256:8da58ff80bc4556cf29bc03f5fff1f03b8387d6aaa7b852af9eb65b2cf833be4", - "sha256:8e5c4c15ac3fe1eb68e46bc51e66ad29be887479f231f8237cf8416058bf0cc1", - "sha256:a101696f9ece90a0829988ff72f1b1ea2358f3df035bdf6d675dd8b60c2c0894", - "sha256:a2f80510f99f82d4eb825849c486df703f50652cea21c189eacc2b84f2bde764", - "sha256:a70a20eed87bba647a38bedd93b3ce7db64b3f0e8e0952315237f7f5ca97b02d", - "sha256:a80e9a5e3f93c54f5eb82a3825ea1fc4965b2fa0026db2abfecb139a5c4ecdf1", - "sha256:ab5ec837d8cee8dbce9ef6386125f119b231e4333cc6b6d57b6c5c7c82a72331", - "sha256:b67d450f1e008fedcd81e097a3a400a711d8be1a8b20f852a7b8a73fead50fe3", - "sha256:b7ca419f1462390851eec395b2089aad1e49546b52d4e2c972ceb76da69b10f8", - "sha256:b8270b15b99781461b244f5c81d5c2bc9696ab9189fb5ff86c841417fb3b39fe", - "sha256:bc74f3f745c37e2c5685c9d2a2d5a94de00f286963f5213f763ae137bf4f2358", - "sha256:c3655139d7be213c32c79ef6fb2367cae28e56ef68e39b1961c43214b457f257", - "sha256:c97962720489ef31b5ad8a916e22bc31bba3664e063fb9f6702dce056d4aa61b", - "sha256:cabd706183ee08d8026a015af5819a0b3a8959bdc9d1f6fdacd1810f09200f2a", - "sha256:d3a9e35bcb045e39d7cac30464c285389b9a816ac2067e4884ad2c02e709ef8e", - "sha256:d750e9330eb14236ca11b78d0c494eed13d6a95eb55472298f0e547c165ee324", - "sha256:d7df567b67d16d4177835a68d3f767bbcbad04da9dfb52cbd19171f430c898bd", - "sha256:ec6f219fb5d677a522b0deaf43cea6697b16f338cb68d009e30930c4aa0d2209", - "sha256:ec71fc5b39821ad7d80db7473c8f8c2910f3382f0ddadfbcfc2c6c437107eb67", - "sha256:ee6ed64a27588a2c94e8fa84fe8f3b5c89427d4d69c37690903d428ec61ca7e4", - "sha256:f17f9fa2d947dbfaca01b3ab2c62eefa8240131fdc67b924eb42ce6032e3e5c1", - "sha256:f5b5970341359341d0e4c789da7568264b2a89cd976c05ea476036852b5950cd", - "sha256:f79c87c114bf37adf408026b9e2e333fe9ff31dfc9648f6f80776c513145c813", - "sha256:fa36dd8496d3af0d40165252a669fa4f6fd2db4b4026b9a9411cbf060b9d6a15", - "sha256:fe6505376f5b00bb008e4e1418152e3ad3d954b629da286c7913ff3cfc0ff740" - ], - "markers": "python_version >= '3.8'", - "version": "==1.65.5" + "sha256:0f3010bf46b2a01c9e40644cb9ed91b4b8435e5c500a275da5f9f62580e31e80", + "sha256:1c5466222470cb7fbc9cc898af1d48eefd297cb2e2f59af6d4a851c862fa90ac", + "sha256:1eb03524d0f55b965d6c86aa44e5db9e5eaa15f9ed3b164621e652e5b927f4b8", + "sha256:230cdd696751e7eb1395718cd308234749daa217bb8d128f00357dc4df102558", + "sha256:245b08f9b3c645a6a623f3ed4fa43dcfcd6ad701eb9c32511c1bb7380e8c3d23", + "sha256:296a45ea835e12a1cc35ab0c57e455346c272af7b0d178e29c67742167262b4c", + "sha256:37514b68a42e9cf24536345d3cf9e580ffd29117c158b4eeea34625200256067", + "sha256:375b58892301a5fc6ca7d7ff689c9dc9d00895f5d560604ace9f4f0573013c63", + "sha256:423ae18637cd99ddcf2e5a6851c61828c49e9b9d022d0442d979b4f230109787", + "sha256:49234580a073ce7ac490112f6c67c874cbcb27804c4525978cdb21ba7f3f193c", + "sha256:508411df1f2b7cfa05d4d7dbf3d576fe4f949cd61c03f3a6f0378c84e3d7b963", + "sha256:50cea8ce2552865b87e3dffbb85eb21e6b98d928621600c0feda2f02449cd837", + "sha256:516fdbc8e156db71a004bc431a6303bca24cfde186babe96dde7bd01e8f0cc70", + "sha256:526d4f6ca19f31b25606d5c470ecba55c0b22707b524e4de8987919e8920437d", + "sha256:53d4c6706b49e358a2a33345dbe9b6b3bb047cecd7e8c07ba383bd09349bfef8", + "sha256:5b15ef1b296c4e78f15f64fc65bf8081f8774480ffcac45642f69d9d753d9c6b", + "sha256:5e8140b39f10d7be2263afa2838112de29374c5c740eb0afd99146cb5bdbd990", + "sha256:5ea27f4ce8c0daccfdd2c7961e6ba404b6599f47c948415c4cca5728739107a3", + "sha256:5f4b3357e59dfba9140a51597287297bc638710d6a163f99ee14efc19967a821", + "sha256:5f93fc84b72bbc7b84a42f3ca9dc055fa00d2303d9803be011ebf7a10a4eb833", + "sha256:643d8d9632a688ae69661e924b862e23c83a3575b24e52917ec5bcc59543d212", + "sha256:684a4c07883cbd4ac864f0d08d927267404f5f0c76f31c85f9bbe05f2daae2f2", + "sha256:6d586a95c05c82a5354be48bb4537e1accaf2472d8eb7e9086d844cbff934482", + "sha256:6ed35bf7da3fb3b1949e32bdf47a8b5ffe0aed11722d948933bd068531cd4682", + "sha256:748452dbd5a047475d5413bdef08b0b9ceb2c0c0e249d4ee905a5fb82c6328dc", + "sha256:7bc9d823e05d63a87511fb456dcc48dc0fced86c282bf60229675e7ee7aac1a1", + "sha256:8096a922eb91bc97c839f675c3efa1257c6ef181ae1b25d3fb97f2cae4c57c01", + "sha256:832945e64176520520317b50d64ec7d79924429528d5747669b52d0bf2c7bd78", + "sha256:8fc5c710ddd51b5a0dc36ef1b6663430aa620e0ce029b87b150dafd313b978c3", + "sha256:921b8f7f25d5300d7c6837a1e0639ef145fbdbfb728e0a5db2dbccc9fc0fd891", + "sha256:9d5251578767fe44602688c851c2373b5513048ac84c21a0fe946590a8e7933d", + "sha256:a639d3866bfb5a678b5c0b92cd7ab543033ed8988854290fd86145e71731fd4c", + "sha256:aaf30c75cbaf30e561ca45f21eb1f729f0fab3f15c592c1074795ed43e3ff96f", + "sha256:ad7256f224437b2c29c2bef98ddd3130454c5b1ab1f0471fc11794cefd4dbd3d", + "sha256:ba18cfdc09312eb2eea6fa0ce5d2eec3cf345ea78f6528b2eaed6432105e0bd0", + "sha256:ba60ae3b465b3e85080ae3bfbc36fd0305ae495ab16fcf8022fc7d7a23aac846", + "sha256:bc008c6afa1e7c8df99bd9154abc4f0470d26b7730ca2521122e99e771baa8c7", + "sha256:c072f90a1f0409f827ae86266984cba65e89c5831a0726b9fc7f4b5fb940b853", + "sha256:c1ea4c528e7db6660718e4165fd1b5ac24b79a70c870a7bc0b7bdb9babab7c1e", + "sha256:c3084e590e857ba7585ae91078e4c9b6ef55aaf1dc343ce26400ba59a146eada", + "sha256:c3f6feb0dc8456d025e566709f7dd02885add99bedaac50229013069242a1bfd", + "sha256:d0439a970d65327de21c299ea0e0c2ad0987cdaf18ba5066621dea5f427f922b", + "sha256:dd614370e939f9fceeeb2915111a0795271b4c11dfb5fc0f58449bee40c726a5", + "sha256:de9e20a0acb709dcfa15a622c91f584f12c9739a79c47999f73435d2b3cc8a3b", + "sha256:e36fa838ac1d6c87198ca149cbfcc92e1af06bb8c8cd852622f8e58f33ea3324", + "sha256:e8d20308eeae15b3e182f47876f05acbdec1eebd9473a9814a44e46ec4a84c04" + ], + "markers": "python_version >= '3.8'", + "version": "==1.66.0" }, "gunicorn": { "hashes": [ @@ -946,11 +946,11 @@ }, "idna": { "hashes": [ - "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", - "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" + "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac", + "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603" ], - "markers": "python_version >= '3.5'", - "version": "==3.7" + "markers": "python_version >= '3.6'", + "version": "==3.8" }, "importlib-metadata": { "hashes": [ @@ -1218,11 +1218,11 @@ }, "phonenumbers": { "hashes": [ - "sha256:339e521403fe4dd9c664dbbeb2fe434f9ea5c81e54c0fdfadbaeb53b26a76c27", - "sha256:35b904e4a79226eee027fbb467a9aa6f1ab9ffc3c09c91bf14b885c154936726" + "sha256:2175021e84ee4e41b43c890f2d0af51f18c6ca9ad525886d6d6e4ea882e46fac", + "sha256:52cd02865dab1428ca9e89d442629b61d407c7dc687cfb80a3e8d068a584513c" ], "index": "pypi", - "version": "==8.13.43" + "version": "==8.13.44" }, "pickleshare": { "hashes": [ @@ -1532,11 +1532,11 @@ }, "setuptools": { "hashes": [ - "sha256:b208925fcb9f7af924ed2dc04708ea89791e24bde0d3020b27df0e116088b34e", - "sha256:d59a3e788ab7e012ab2c4baed1b376da6366883ee20d7a5fc426816e3d7b1193" + "sha256:0274581a0037b638b9fc1c6883cc71c0210865aaa76073f7882376b641b84e8f", + "sha256:a85e96b8be2b906f3e3e789adec6a9323abf79758ecfa3065bd740d81158b11e" ], "markers": "python_version >= '3.8'", - "version": "==73.0.1" + "version": "==74.0.0" }, "six": { "hashes": [ @@ -1762,11 +1762,11 @@ }, "zipp": { "hashes": [ - "sha256:0145e43d89664cfe1a2e533adc75adafed82fe2da404b4bbb6b026c0157bdb31", - "sha256:58da6168be89f0be59beb194da1250516fdaa062ccebd30127ac65d30045e10d" + "sha256:9960cd8967c8f85a56f920d5d507274e74f9ff813a0ab8889a5b5be2daf44064", + "sha256:c22b14cc4763c5a5b04134207736c107db42e9d3ef2d9779d465f5f1bcba572b" ], "markers": "python_version >= '3.8'", - "version": "==3.20.0" + "version": "==3.20.1" }, "zope.event": { "hashes": [ @@ -1778,43 +1778,43 @@ }, "zope.interface": { "hashes": [ - "sha256:03bd5c0db82237bbc47833a8b25f1cc090646e212f86b601903d79d7e6b37031", - "sha256:03f1452d5d1f279184d5bdb663a3dc39902d9320eceb63276240791e849054b6", - "sha256:10ebac566dd0cec66f942dc759d46a994a2b3ba7179420f0e2130f88f8a5f400", - "sha256:192b7a792e3145ed880ff6b1a206fdb783697cfdb4915083bfca7065ec845e60", - "sha256:19c829d52e921b9fe0b2c0c6a8f9a2508c49678ee1be598f87d143335b6a35dc", - "sha256:3f3495462bc0438b76536a0e10d765b168ae636092082531b88340dc40dcd118", - "sha256:3f52050c6a10d4a039ec6f2c58e5b3ade5cc570d16cf9d102711e6b8413c90e6", - "sha256:400d06c9ec8dbcc96f56e79376297e7be07a315605c9a2208720da263d44d76f", - "sha256:4ec212037becf6d2f705b7ed4538d56980b1e7bba237df0d8995cbbed29961dc", - "sha256:51d5713e8e38f2d3ec26e0dfdca398ed0c20abda2eb49ffc15a15a23eb8e5f6d", - "sha256:52f5253cca1b35eaeefa51abd366b87f48f8714097c99b131ba61f3fdbbb58e7", - "sha256:5566fd9271c89ad03d81b0831c37d46ae5e2ed211122c998637130159a120cf1", - "sha256:55bbcc74dc0c7ab489c315c28b61d7a1d03cf938cc99cc58092eb065f120c3a5", - "sha256:696c2a381fc7876b3056711717dba5eddd07c2c9e5ccd50da54029a1293b6e43", - "sha256:6ba4b3638d014918b918aa90a9c8370bd74a03abf8fcf9deb353b3a461a59a84", - "sha256:7039e624bcb820f77cc2ff3d1adcce531932990eee16121077eb51d9c76b6c14", - "sha256:88d108d004e0df25224de77ce349a7e73494ea2cb194031f7c9687e68a88ec9b", - "sha256:8c1dff87b30fd150c61367d0e2cdc49bb55f8b9fd2a303560bbc24b951573ae1", - "sha256:9a8195b99e650e6f329ce4e5eb22d448bdfef0406404080812bc96e2a05674cb", - "sha256:af0b33f04677b57843d529b9257a475d2865403300b48c67654c40abac2f9f24", - "sha256:b419f2144e1762ab845f20316f1df36b15431f2622ebae8a6d5f7e8e712b413c", - "sha256:b59deb0ddc7b431e41d720c00f99d68b52cb9bd1d5605a085dc18f502fe9c47f", - "sha256:bc0615351221926a36a0fbcb2520fb52e0b23e8c22a43754d9cb8f21358c33c0", - "sha256:c203d82069ba31e1f3bc7ba530b2461ec86366cd4bfc9b95ec6ce58b1b559c34", - "sha256:ce6cbb852fb8f2f9bb7b9cdca44e2e37bce783b5f4c167ff82cb5f5128163c8f", - "sha256:d33cb526efdc235a2531433fc1287fcb80d807d5b401f9b801b78bf22df560dd", - "sha256:da0cef4d7e3f19c3bd1d71658d6900321af0492fee36ec01b550a10924cffb9c", - "sha256:da21e7eec49252df34d426c2ee9cf0361c923026d37c24728b0fa4cc0599fd03", - "sha256:ea8d51e5eb29e57d34744369cd08267637aa5a0fefc9b5d33775ab7ff2ebf2e3", - "sha256:ec4e87e6fdc511a535254daa122c20e11959ce043b4e3425494b237692a34f1c", - "sha256:f0f5fda7cbf890371a59ab1d06512da4f2c89a6ea194e595808123c863c38eff", - "sha256:f32ca483e6ade23c7caaee9d5ee5d550cf4146e9b68d2fb6c68bac183aa41c37", - "sha256:f749ca804648d00eda62fe1098f229b082dfca930d8bad8386e572a6eafa7525", - "sha256:f89a420cf5a6f2aa7849dd59e1ff0e477f562d97cf8d6a1ee03461e1eec39887" - ], - "markers": "python_version >= '3.8'", - "version": "==7.0.1" + "sha256:01e6e58078ad2799130c14a1d34ec89044ada0e1495329d72ee0407b9ae5100d", + "sha256:064ade95cb54c840647205987c7b557f75d2b2f7d1a84bfab4cf81822ef6e7d1", + "sha256:11fa1382c3efb34abf16becff8cb214b0b2e3144057c90611621f2d186b7e1b7", + "sha256:1bee1b722077d08721005e8da493ef3adf0b7908e0cd85cc7dc836ac117d6f32", + "sha256:1eeeb92cb7d95c45e726e3c1afe7707919370addae7ed14f614e22217a536958", + "sha256:21a207c6b2c58def5011768140861a73f5240f4f39800625072ba84e76c9da0b", + "sha256:2545d6d7aac425d528cd9bf0d9e55fcd47ab7fd15f41a64b1c4bf4c6b24946dc", + "sha256:2c4316a30e216f51acbd9fb318aa5af2e362b716596d82cbb92f9101c8f8d2e7", + "sha256:35062d93bc49bd9b191331c897a96155ffdad10744ab812485b6bad5b588d7e4", + "sha256:382d31d1e68877061daaa6499468e9eb38eb7625d4369b1615ac08d3860fe896", + "sha256:3aa8fcbb0d3c2be1bfd013a0f0acd636f6ed570c287743ae2bbd467ee967154d", + "sha256:3d4b91821305c8d8f6e6207639abcbdaf186db682e521af7855d0bea3047c8ca", + "sha256:3de1d553ce72868b77a7e9d598c9bff6d3816ad2b4cc81c04f9d8914603814f3", + "sha256:3fcdc76d0cde1c09c37b7c6b0f8beba2d857d8417b055d4f47df9c34ec518bdd", + "sha256:5112c530fa8aa2108a3196b9c2f078f5738c1c37cfc716970edc0df0414acda8", + "sha256:53d678bb1c3b784edbfb0adeebfeea6bf479f54da082854406a8f295d36f8386", + "sha256:6195c3c03fef9f87c0dbee0b3b6451df6e056322463cf35bca9a088e564a3c58", + "sha256:6d04b11ea47c9c369d66340dbe51e9031df2a0de97d68f442305ed7625ad6493", + "sha256:6dd647fcd765030638577fe6984284e0ebba1a1008244c8a38824be096e37fe3", + "sha256:799ef7a444aebbad5a145c3b34bff012b54453cddbde3332d47ca07225792ea4", + "sha256:7d92920416f31786bc1b2f34cc4fc4263a35a407425319572cbf96b51e835cd3", + "sha256:7e0c151a6c204f3830237c59ee4770cc346868a7a1af6925e5e38650141a7f05", + "sha256:84f8794bd59ca7d09d8fce43ae1b571be22f52748169d01a13d3ece8394d8b5b", + "sha256:95e5913ec718010dc0e7c215d79a9683b4990e7026828eedfda5268e74e73e11", + "sha256:9b9369671a20b8d039b8e5a1a33abd12e089e319a3383b4cc0bf5c67bd05fe7b", + "sha256:ab985c566a99cc5f73bc2741d93f1ed24a2cc9da3890144d37b9582965aff996", + "sha256:af94e429f9d57b36e71ef4e6865182090648aada0cb2d397ae2b3f7fc478493a", + "sha256:c96b3e6b0d4f6ddfec4e947130ec30bd2c7b19db6aa633777e46c8eecf1d6afd", + "sha256:cd2690d4b08ec9eaf47a85914fe513062b20da78d10d6d789a792c0b20307fb1", + "sha256:d3b7ce6d46fb0e60897d62d1ff370790ce50a57d40a651db91a3dde74f73b738", + "sha256:d976fa7b5faf5396eb18ce6c132c98e05504b52b60784e3401f4ef0b2e66709b", + "sha256:db6237e8fa91ea4f34d7e2d16d74741187e9105a63bbb5686c61fea04cdbacca", + "sha256:ecd32f30f40bfd8511b17666895831a51b532e93fc106bfa97f366589d3e4e0e", + "sha256:f418c88f09c3ba159b95a9d1cfcdbe58f208443abb1f3109f4b9b12fd60b187c" + ], + "markers": "python_version >= '3.8'", + "version": "==7.0.3" } }, "develop": { @@ -2236,11 +2236,11 @@ }, "idna": { "hashes": [ - "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", - "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" + "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac", + "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603" ], - "markers": "python_version >= '3.5'", - "version": "==3.7" + "markers": "python_version >= '3.6'", + "version": "==3.8" }, "iniconfig": { "hashes": [ @@ -2461,11 +2461,11 @@ }, "parse-type": { "hashes": [ - "sha256:06d39a8b70fde873eb2a131141a0e79bb34a432941fb3d66fad247abafc9766c", - "sha256:79b1f2497060d0928bc46016793f1fca1057c4aacdf15ef876aa48d75a73a355" + "sha256:8d94a52e0197fbad63fee8f70df16e6ed689e5e4f105b705c9afa7a30397a5aa", + "sha256:8e99d2f52fab2f0f1f3d68ba9d026060140bf0e53680aada0111fb27b2f0e93a" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.6.2" + "version": "==0.6.3" }, "parso": { "hashes": [ @@ -2485,11 +2485,11 @@ }, "pbr": { "hashes": [ - "sha256:4a7317d5e3b17a3dccb6a8cfe67dab65b20551404c52c8ed41279fa4f0cb4cda", - "sha256:d1377122a5a00e2f940ee482999518efe16d745d423a670c27773dfbc3c9a7d9" + "sha256:788183e382e3d1d7707db08978239965e8b9e4e5ed42669bf4758186734d5f24", + "sha256:a776ae228892d8013649c0aeccbb3d5f99ee15e005a4cbb7e61d55a067b28a2a" ], "markers": "python_version >= '2.6'", - "version": "==6.0.0" + "version": "==6.1.0" }, "pep8-naming": { "hashes": [ @@ -2803,11 +2803,11 @@ }, "setuptools": { "hashes": [ - "sha256:b208925fcb9f7af924ed2dc04708ea89791e24bde0d3020b27df0e116088b34e", - "sha256:d59a3e788ab7e012ab2c4baed1b376da6366883ee20d7a5fc426816e3d7b1193" + "sha256:0274581a0037b638b9fc1c6883cc71c0210865aaa76073f7882376b641b84e8f", + "sha256:a85e96b8be2b906f3e3e789adec6a9323abf79758ecfa3065bd740d81158b11e" ], "markers": "python_version >= '3.8'", - "version": "==73.0.1" + "version": "==74.0.0" }, "six": { "hashes": [ @@ -2834,11 +2834,11 @@ }, "stevedore": { "hashes": [ - "sha256:1c15d95766ca0569cad14cb6272d4d31dae66b011a929d7c18219c176ea1b5c9", - "sha256:46b93ca40e1114cea93d738a6c1e365396981bb6bb78c27045b7587c9473544d" + "sha256:1efd34ca08f474dad08d9b19e934a22c68bb6fe416926479ba29e5013bcc8f78", + "sha256:9a64265f4060312828151c204efbe9b7a9852a0d9228756344dbc7e4023e375a" ], "markers": "python_version >= '3.8'", - "version": "==5.2.0" + "version": "==5.3.0" }, "toml": { "hashes": [ @@ -2885,44 +2885,39 @@ "watchmedo" ], "hashes": [ - "sha256:0b4359067d30d5b864e09c8597b112fe0a0a59321a0f331498b013fb097406b4", - "sha256:0d8a7e523ef03757a5aa29f591437d64d0d894635f8a50f370fe37f913ce4e19", - "sha256:0e83619a2d5d436a7e58a1aea957a3c1ccbf9782c43c0b4fed80580e5e4acd1a", - "sha256:10b6683df70d340ac3279eff0b2766813f00f35a1d37515d2c99959ada8f05fa", - "sha256:132937547a716027bd5714383dfc40dc66c26769f1ce8a72a859d6a48f371f3a", - "sha256:1cdcfd8142f604630deef34722d695fb455d04ab7cfe9963055df1fc69e6727a", - "sha256:2d468028a77b42cc685ed694a7a550a8d1771bb05193ba7b24006b8241a571a1", - "sha256:32be97f3b75693a93c683787a87a0dc8db98bb84701539954eef991fb35f5fbc", - "sha256:770eef5372f146997638d737c9a3c597a3b41037cfbc5c41538fc27c09c3a3f9", - "sha256:7c7d4bf585ad501c5f6c980e7be9c4f15604c7cc150e942d82083b31a7548930", - "sha256:88456d65f207b39f1981bf772e473799fcdc10801062c36fd5ad9f9d1d463a73", - "sha256:914285126ad0b6eb2258bbbcb7b288d9dfd655ae88fa28945be05a7b475a800b", - "sha256:936acba76d636f70db8f3c66e76aa6cb5136a936fc2a5088b9ce1c7a3508fc83", - "sha256:980b71510f59c884d684b3663d46e7a14b457c9611c481e5cef08f4dd022eed7", - "sha256:984306dc4720da5498b16fc037b36ac443816125a3705dfde4fd90652d8028ef", - "sha256:a2cffa171445b0efa0726c561eca9a27d00a1f2b83846dbd5a4f639c4f8ca8e1", - "sha256:aa160781cafff2719b663c8a506156e9289d111d80f3387cf3af49cedee1f040", - "sha256:b2c45f6e1e57ebb4687690c05bc3a2c1fb6ab260550c4290b8abb1335e0fd08b", - "sha256:b4dfbb6c49221be4535623ea4474a4d6ee0a9cef4a80b20c28db4d858b64e270", - "sha256:baececaa8edff42cd16558a639a9b0ddf425f93d892e8392a56bf904f5eff22c", - "sha256:bcfd02377be80ef3b6bc4ce481ef3959640458d6feaae0bd43dd90a43da90a7d", - "sha256:c0b14488bd336c5b1845cee83d3e631a1f8b4e9c5091ec539406e4a324f882d8", - "sha256:c100d09ac72a8a08ddbf0629ddfa0b8ee41740f9051429baa8e31bb903ad7508", - "sha256:c344453ef3bf875a535b0488e3ad28e341adbd5a9ffb0f7d62cefacc8824ef2b", - "sha256:c50f148b31b03fbadd6d0b5980e38b558046b127dc483e5e4505fcef250f9503", - "sha256:c82253cfc9be68e3e49282831afad2c1f6593af80c0daf1287f6a92657986757", - "sha256:cd67c7df93eb58f360c43802acc945fa8da70c675b6fa37a241e17ca698ca49b", - "sha256:d7ab624ff2f663f98cd03c8b7eedc09375a911794dfea6bf2a359fcc266bff29", - "sha256:e252f8ca942a870f38cf785aef420285431311652d871409a64e2a0a52a2174c", - "sha256:ede7f010f2239b97cc79e6cb3c249e72962404ae3865860855d5cbe708b0fd22", - "sha256:eeea812f38536a0aa859972d50c76e37f4456474b02bd93674d1947cf1e39578", - "sha256:f15edcae3830ff20e55d1f4e743e92970c847bcddc8b7509bcd172aa04de506e", - "sha256:f5315a8c8dd6dd9425b974515081fc0aadca1d1d61e078d2246509fd756141ee", - "sha256:f6ee8dedd255087bc7fe82adf046f0b75479b989185fb0bdf9a98b612170eac7", - "sha256:f7c739888c20f99824f7aa9d31ac8a97353e22d0c0e54703a547a218f6637eb3" + "sha256:0120b2fa65732797ffa65fa8ee5540c288aa861d91447df298626d6385a24658", + "sha256:01ab36cddc836a0f202c66267daaef92ba5c17c7d6436deff0587bb61234c5c9", + "sha256:0710e9502727f688a7e06d48078545c54485b3d6eb53b171810879d8223c362a", + "sha256:0834c21efa3e767849b09e667274604c7cdfe30b49eb95d794565c53f4db3c1e", + "sha256:109daafc5b0f2a98d1fa9475ff9737eb3559d57b18129a36495e20c71de0b44f", + "sha256:1228cb097e855d1798b550be8f0e9f0cfbac4384f9a3e91f66d250d03e11294e", + "sha256:16c1aa3377bb1f82c5e24277fcbf4e2cac3c4ce46aaaf7212d53caa9076eb7b7", + "sha256:1d17ec7e022c34fa7ddc72aa41bf28c9d1207ffb193df18ba4f6fde453725b3c", + "sha256:1e26f570dd7f5178656affb24d6f0e22ce66c8daf88d4061a27bfb9ac866b40d", + "sha256:22fcad6168fc43cf0e709bd854be5b8edbb0b260f0a6f28f1ea9baa53c6907f7", + "sha256:2aa59fab7ff75281778c649557275ca3085eccbdf825a0e2a5ca3810e977afe5", + "sha256:3c177085c3d210d1c73cb4569442bdaef706ebebc423bd7aed9e90fc12b2e553", + "sha256:3c2d50fdb86aa6df3973313272f5a17eb26eab29ff5a0bf54b6d34597b4dc4e4", + "sha256:4fe6780915000743074236b21b6c37419aea71112af62237881bc265589fe463", + "sha256:663b096368ed7831ac42259919fdb9e0a1f0a8994d972675dfbcca0225e74de1", + "sha256:685931412978d00a91a193d9018fc9e394e565e8e7a0c275512a80e59c6e85f8", + "sha256:6c96b1706430839872a3e33b9370ee3f7a0079f6b828129d88498ad1f96a0f45", + "sha256:6e58eafe9cc5ceebe1562cdb89bacdcd0ef470896e8b0139fe677a5abec243da", + "sha256:78db0fe0336958fc0e1269545c980b6f33d04d184ba191b2800a8b71d3e971a9", + "sha256:7e6b0e9b8a9dc3865d65888b5f5222da4ba9c4e09eab13cff5e305e7b7e7248f", + "sha256:990aedb9e2f336b45a70aed9c014450e7c4a70fd99c5f5b1834d57e1453a177e", + "sha256:b8d747bf6d8fe5ce89cb1a36c3724d1599bd4cde3f90fcba518e6260c7058a52", + "sha256:bc16d448a74a929b896ed9578c25756b2125400b19b3258be8d9a681c7ae8e71", + "sha256:bf3216ec994eabb2212df9861f19056ca0d4cd3516d56cb95801933876519bfe", + "sha256:c2b4d90962639ae7cee371ea3a8da506831945d4418eee090c53bc38e6648dc6", + "sha256:cb59ad83a1700304fc1ac7bc53ae9e5cbe9d60a52ed9bba8e2e2d782a201bb2b", + "sha256:d146331e6b206baa9f6dd40f72b5783ad2302c240df68e7fce196d30588ccf7b", + "sha256:d1acef802916083f2ad7988efc7decf07e46e266916c0a09d8fb9d387288ea12", + "sha256:d76efab5248aafbf8a2c2a63cd7b9545e6b346ad1397af8b862a3bb3140787d8", + "sha256:ff4e957c45c446de34c513eadce01d0b65da7eee47c01dce472dd136124552c9" ], - "markers": "python_version >= '3.8'", - "version": "==4.0.2" + "markers": "python_version >= '3.9'", + "version": "==5.0.0" }, "wcwidth": { "hashes": [ @@ -2933,11 +2928,11 @@ }, "werkzeug": { "hashes": [ - "sha256:097e5bfda9f0aba8da6b8545146def481d06aa7d3266e7448e2cccf67dd8bd18", - "sha256:fc9645dc43e03e4d630d23143a04a7f947a9a3b5727cd535fdfe155a17cc48c8" + "sha256:02c9eb92b7d6c06f31a782811505d2157837cea66aaede3e217c7c27c039476c", + "sha256:34f2371506b250df4d4f84bfe7b0921e4762525762bbd936614909fe25cd7306" ], "markers": "python_version >= '3.8'", - "version": "==3.0.3" + "version": "==3.0.4" }, "wrapt": { "hashes": [ From ffc0f590c29399e8153efffa593c90f726e0c7e9 Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Thu, 29 Aug 2024 10:14:46 +0100 Subject: [PATCH 19/20] Add pytz as an explicit package It looks like this was a sub-dependency of another package so we were only implicitly pulling this library in, however it's actually a required explicit dependency --- Pipfile | 1 + Pipfile.lock | 104 +++++++++++++++++++++++++++------------------------ 2 files changed, 57 insertions(+), 48 deletions(-) diff --git a/Pipfile b/Pipfile index e412a9c1f..f7ce1bed0 100644 --- a/Pipfile +++ b/Pipfile @@ -77,6 +77,7 @@ django-log-formatter-asim = "~=0.0.5" dbt-copilot-python = "~=0.2.1" dj-database-url = "~=2.2.0" djangorestframework-csv = "~=3.0.2" +pytz = "~=2024.1" [requires] python_version = "3.9" diff --git a/Pipfile.lock b/Pipfile.lock index 9a535e119..463ee033d 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "7807d0e7e445d981669421aab87a389ee7ca862f4b0d3268d27d94735b4646f8" + "sha256": "75c3d2c602164557d38f1068b634a5cbfc8fa118674ee296ee22a7e8fea2a483" }, "pipfile-spec": 6, "requires": { @@ -869,55 +869,55 @@ }, "grpcio": { "hashes": [ - "sha256:0f3010bf46b2a01c9e40644cb9ed91b4b8435e5c500a275da5f9f62580e31e80", - "sha256:1c5466222470cb7fbc9cc898af1d48eefd297cb2e2f59af6d4a851c862fa90ac", - "sha256:1eb03524d0f55b965d6c86aa44e5db9e5eaa15f9ed3b164621e652e5b927f4b8", - "sha256:230cdd696751e7eb1395718cd308234749daa217bb8d128f00357dc4df102558", - "sha256:245b08f9b3c645a6a623f3ed4fa43dcfcd6ad701eb9c32511c1bb7380e8c3d23", - "sha256:296a45ea835e12a1cc35ab0c57e455346c272af7b0d178e29c67742167262b4c", - "sha256:37514b68a42e9cf24536345d3cf9e580ffd29117c158b4eeea34625200256067", - "sha256:375b58892301a5fc6ca7d7ff689c9dc9d00895f5d560604ace9f4f0573013c63", - "sha256:423ae18637cd99ddcf2e5a6851c61828c49e9b9d022d0442d979b4f230109787", - "sha256:49234580a073ce7ac490112f6c67c874cbcb27804c4525978cdb21ba7f3f193c", - "sha256:508411df1f2b7cfa05d4d7dbf3d576fe4f949cd61c03f3a6f0378c84e3d7b963", - "sha256:50cea8ce2552865b87e3dffbb85eb21e6b98d928621600c0feda2f02449cd837", - "sha256:516fdbc8e156db71a004bc431a6303bca24cfde186babe96dde7bd01e8f0cc70", - "sha256:526d4f6ca19f31b25606d5c470ecba55c0b22707b524e4de8987919e8920437d", - "sha256:53d4c6706b49e358a2a33345dbe9b6b3bb047cecd7e8c07ba383bd09349bfef8", - "sha256:5b15ef1b296c4e78f15f64fc65bf8081f8774480ffcac45642f69d9d753d9c6b", - "sha256:5e8140b39f10d7be2263afa2838112de29374c5c740eb0afd99146cb5bdbd990", - "sha256:5ea27f4ce8c0daccfdd2c7961e6ba404b6599f47c948415c4cca5728739107a3", - "sha256:5f4b3357e59dfba9140a51597287297bc638710d6a163f99ee14efc19967a821", - "sha256:5f93fc84b72bbc7b84a42f3ca9dc055fa00d2303d9803be011ebf7a10a4eb833", - "sha256:643d8d9632a688ae69661e924b862e23c83a3575b24e52917ec5bcc59543d212", - "sha256:684a4c07883cbd4ac864f0d08d927267404f5f0c76f31c85f9bbe05f2daae2f2", - "sha256:6d586a95c05c82a5354be48bb4537e1accaf2472d8eb7e9086d844cbff934482", - "sha256:6ed35bf7da3fb3b1949e32bdf47a8b5ffe0aed11722d948933bd068531cd4682", - "sha256:748452dbd5a047475d5413bdef08b0b9ceb2c0c0e249d4ee905a5fb82c6328dc", - "sha256:7bc9d823e05d63a87511fb456dcc48dc0fced86c282bf60229675e7ee7aac1a1", - "sha256:8096a922eb91bc97c839f675c3efa1257c6ef181ae1b25d3fb97f2cae4c57c01", - "sha256:832945e64176520520317b50d64ec7d79924429528d5747669b52d0bf2c7bd78", - "sha256:8fc5c710ddd51b5a0dc36ef1b6663430aa620e0ce029b87b150dafd313b978c3", - "sha256:921b8f7f25d5300d7c6837a1e0639ef145fbdbfb728e0a5db2dbccc9fc0fd891", - "sha256:9d5251578767fe44602688c851c2373b5513048ac84c21a0fe946590a8e7933d", - "sha256:a639d3866bfb5a678b5c0b92cd7ab543033ed8988854290fd86145e71731fd4c", - "sha256:aaf30c75cbaf30e561ca45f21eb1f729f0fab3f15c592c1074795ed43e3ff96f", - "sha256:ad7256f224437b2c29c2bef98ddd3130454c5b1ab1f0471fc11794cefd4dbd3d", - "sha256:ba18cfdc09312eb2eea6fa0ce5d2eec3cf345ea78f6528b2eaed6432105e0bd0", - "sha256:ba60ae3b465b3e85080ae3bfbc36fd0305ae495ab16fcf8022fc7d7a23aac846", - "sha256:bc008c6afa1e7c8df99bd9154abc4f0470d26b7730ca2521122e99e771baa8c7", - "sha256:c072f90a1f0409f827ae86266984cba65e89c5831a0726b9fc7f4b5fb940b853", - "sha256:c1ea4c528e7db6660718e4165fd1b5ac24b79a70c870a7bc0b7bdb9babab7c1e", - "sha256:c3084e590e857ba7585ae91078e4c9b6ef55aaf1dc343ce26400ba59a146eada", - "sha256:c3f6feb0dc8456d025e566709f7dd02885add99bedaac50229013069242a1bfd", - "sha256:d0439a970d65327de21c299ea0e0c2ad0987cdaf18ba5066621dea5f427f922b", - "sha256:dd614370e939f9fceeeb2915111a0795271b4c11dfb5fc0f58449bee40c726a5", - "sha256:de9e20a0acb709dcfa15a622c91f584f12c9739a79c47999f73435d2b3cc8a3b", - "sha256:e36fa838ac1d6c87198ca149cbfcc92e1af06bb8c8cd852622f8e58f33ea3324", - "sha256:e8d20308eeae15b3e182f47876f05acbdec1eebd9473a9814a44e46ec4a84c04" + "sha256:0e6c9b42ded5d02b6b1fea3a25f036a2236eeb75d0579bfd43c0018c88bf0a3e", + "sha256:161d5c535c2bdf61b95080e7f0f017a1dfcb812bf54093e71e5562b16225b4ce", + "sha256:17663598aadbedc3cacd7bbde432f541c8e07d2496564e22b214b22c7523dac8", + "sha256:1c17ebcec157cfb8dd445890a03e20caf6209a5bd4ac5b040ae9dbc59eef091d", + "sha256:292a846b92cdcd40ecca46e694997dd6b9be6c4c01a94a0dfb3fcb75d20da858", + "sha256:2ca2559692d8e7e245d456877a85ee41525f3ed425aa97eb7a70fc9a79df91a0", + "sha256:307b1d538140f19ccbd3aed7a93d8f71103c5d525f3c96f8616111614b14bf2a", + "sha256:30a1c2cf9390c894c90bbc70147f2372130ad189cffef161f0432d0157973f45", + "sha256:31a049daa428f928f21090403e5d18ea02670e3d5d172581670be006100db9ef", + "sha256:35334f9c9745add3e357e3372756fd32d925bd52c41da97f4dfdafbde0bf0ee2", + "sha256:3750c5a00bd644c75f4507f77a804d0189d97a107eb1481945a0cf3af3e7a5ac", + "sha256:3885f037eb11f1cacc41f207b705f38a44b69478086f40608959bf5ad85826dd", + "sha256:4573608e23f7e091acfbe3e84ac2045680b69751d8d67685ffa193a4429fedb1", + "sha256:4825a3aa5648010842e1c9d35a082187746aa0cdbf1b7a2a930595a94fb10fce", + "sha256:4877ba180591acdf127afe21ec1c7ff8a5ecf0fe2600f0d3c50e8c4a1cbc6492", + "sha256:48b0d92d45ce3be2084b92fb5bae2f64c208fea8ceed7fccf6a7b524d3c4942e", + "sha256:4d813316d1a752be6f5c4360c49f55b06d4fe212d7df03253dfdae90c8a402bb", + "sha256:5dd67ed9da78e5121efc5c510f0122a972216808d6de70953a740560c572eb44", + "sha256:6f914386e52cbdeb5d2a7ce3bf1fdfacbe9d818dd81b6099a05b741aaf3848bb", + "sha256:7101db1bd4cd9b880294dec41a93fcdce465bdbb602cd8dc5bd2d6362b618759", + "sha256:7e06aa1f764ec8265b19d8f00140b8c4b6ca179a6dc67aa9413867c47e1fb04e", + "sha256:84ca1be089fb4446490dd1135828bd42a7c7f8421e74fa581611f7afdf7ab761", + "sha256:8a1e224ce6f740dbb6b24c58f885422deebd7eb724aff0671a847f8951857c26", + "sha256:97ae7edd3f3f91480e48ede5d3e7d431ad6005bfdbd65c1b56913799ec79e791", + "sha256:9c9bebc6627873ec27a70fc800f6083a13c70b23a5564788754b9ee52c5aef6c", + "sha256:a013c5fbb12bfb5f927444b477a26f1080755a931d5d362e6a9a720ca7dbae60", + "sha256:a66fe4dc35d2330c185cfbb42959f57ad36f257e0cc4557d11d9f0a3f14311df", + "sha256:a92c4f58c01c77205df6ff999faa008540475c39b835277fb8883b11cada127a", + "sha256:aa8ba945c96e73de29d25331b26f3e416e0c0f621e984a3ebdb2d0d0b596a3b3", + "sha256:b0aa03d240b5539648d996cc60438f128c7f46050989e35b25f5c18286c86734", + "sha256:b1b24c23d51a1e8790b25514157d43f0a4dce1ac12b3f0b8e9f66a5e2c4c132f", + "sha256:b7ffb8ea674d68de4cac6f57d2498fef477cef582f1fa849e9f844863af50083", + "sha256:b9feb4e5ec8dc2d15709f4d5fc367794d69277f5d680baf1910fc9915c633524", + "sha256:bff2096bdba686019fb32d2dde45b95981f0d1490e054400f70fc9a8af34b49d", + "sha256:c30aeceeaff11cd5ddbc348f37c58bcb96da8d5aa93fed78ab329de5f37a0d7a", + "sha256:c9f80f9fad93a8cf71c7f161778ba47fd730d13a343a46258065c4deb4b550c0", + "sha256:cfd349de4158d797db2bd82d2020554a121674e98fbe6b15328456b3bf2495bb", + "sha256:d0cd7050397b3609ea51727b1811e663ffda8bda39c6a5bb69525ef12414b503", + "sha256:d639c939ad7c440c7b2819a28d559179a4508783f7e5b991166f8d7a34b52815", + "sha256:e3ba04659e4fce609de2658fe4dbf7d6ed21987a94460f5f92df7579fd5d0e22", + "sha256:ecfe735e7a59e5a98208447293ff8580e9db1e890e232b8b292dc8bd15afc0d2", + "sha256:ef82d361ed5849d34cf09105d00b94b6728d289d6b9235513cb2fcc79f7c432c", + "sha256:f03a5884c56256e08fd9e262e11b5cfacf1af96e2ce78dc095d2c41ccae2c80d", + "sha256:f1fe60d0772831d96d263b53d83fb9a3d050a94b0e94b6d004a5ad111faa5b5b", + "sha256:f517fd7259fe823ef3bd21e508b653d5492e706e9f0ef82c16ce3347a8a5620c", + "sha256:fdb14bad0835914f325349ed34a51940bc2ad965142eb3090081593c6e347be9" ], "markers": "python_version >= '3.8'", - "version": "==1.66.0" + "version": "==1.66.1" }, "gunicorn": { "hashes": [ @@ -1420,6 +1420,14 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.9.0.post0" }, + "pytz": { + "hashes": [ + "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812", + "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319" + ], + "index": "pypi", + "version": "==2024.1" + }, "pyyaml": { "hashes": [ "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", From c2ab619feae4733812b2fe2eb62f579132012370 Mon Sep 17 00:00:00 2001 From: Kevin Carrogan Date: Thu, 29 Aug 2024 12:08:44 +0100 Subject: [PATCH 20/20] Add code coverage output for lite data bdd tests --- .circleci/config.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8b7a5af7c..ab399adcf 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -391,8 +391,10 @@ jobs: command: | mkdir cucumber_results - run: - name: Run lite_routing tests - command: pipenv run pytest --circleci-parallelize --gherkin-terminal-reporter -vv api/data_workspace/v2/tests/bdd --cucumberjson=cucumber_results/cuc.json + name: Run lite_data_bdd tests + command: pipenv run pytest --cov=. --cov-report xml --cov-config=.coveragerc --circleci-parallelize --gherkin-terminal-reporter -vv api/data_workspace/v2/tests/bdd --cucumberjson=cucumber_results/cuc.json + - upload_code_coverage: + alias: lite_data_bdd_tests - run: name: Generate html cucumber report command: node generate_cucumber_report.js