diff --git a/LICENSE b/LICENSE index 8ea40a3..be3f7b2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,20 +1,7 @@ -Copyright (c) 2014 - 2024 UNICEF. All rights reserved. - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as -published by the Free Software Foundation, either version 3 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License below for more details. - ------------------------------------------------------------------------- - GNU AFFERO GENERAL PUBLIC LICENSE + GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -656,7 +643,7 @@ the "copyright" line and a pointer to where the full notice is found. GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . + along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. @@ -671,4 +658,4 @@ specific requirements. You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see -. \ No newline at end of file +. diff --git a/docker/Dockerfile b/docker/Dockerfile index 756fef4..090f229 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.11-slim-bookworm as base +FROM python:3.12-slim-bookworm as base RUN apt update \ && apt install --no-install-recommends -y \ @@ -13,7 +13,7 @@ RUN apt update \ && chown -R hpg:hpg /code /tmp /data /static ENV PACKAGES_DIR=/packages -ENV PYPACKAGES=$PACKAGES_DIR/__pypackages__/3.11 +ENV PYPACKAGES=$PACKAGES_DIR/__pypackages__/3.12 ENV LIB_DIR=$PYPACKAGES/lib ENV PYTHONPATH=$PYTHONPATH:$LIB_DIR:/code/src ENV PATH=$PATH:$PYPACKAGES/bin diff --git a/pdm.lock b/pdm.lock index 7f2897b..edce424 100644 --- a/pdm.lock +++ b/pdm.lock @@ -5,10 +5,10 @@ groups = ["default", "dev"] strategy = [] lock_version = "4.5.0" -content_hash = "sha256:9a585a952060f78dc07ceb919a0249fe153bf70a2105df1668a3183dbb4e891e" +content_hash = "sha256:a3bd8c3a436595b62d8c44e216b49f6f9a44d7c7f6d7dd7cc70995a57acbe534" [[metadata.targets]] -requires_python = ">=3.11" +requires_python = ">=3.12" [[package]] name = "amqp" @@ -59,19 +59,6 @@ files = [ {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, ] -[[package]] -name = "async-timeout" -version = "4.0.3" -requires_python = ">=3.7" -summary = "Timeout context manager for asyncio programs" -dependencies = [ - "typing-extensions>=3.6.5; python_version < \"3.8\"", -] -files = [ - {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, - {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, -] - [[package]] name = "attrs" version = "24.2.0" @@ -87,7 +74,7 @@ files = [ [[package]] name = "azure-core" -version = "1.30.2" +version = "1.31.0" requires_python = ">=3.8" summary = "Microsoft Azure Core Library for Python" dependencies = [ @@ -96,24 +83,24 @@ dependencies = [ "typing-extensions>=4.6.0", ] files = [ - {file = "azure-core-1.30.2.tar.gz", hash = "sha256:a14dc210efcd608821aa472d9fb8e8d035d29b68993819147bc290a8ac224472"}, - {file = "azure_core-1.30.2-py3-none-any.whl", hash = "sha256:cf019c1ca832e96274ae85abd3d9f752397194d9fea3b41487290562ac8abe4a"}, + {file = "azure_core-1.31.0-py3-none-any.whl", hash = "sha256:22954de3777e0250029360ef31d80448ef1be13b80a459bff80ba7073379e2cd"}, + {file = "azure_core-1.31.0.tar.gz", hash = "sha256:656a0dd61e1869b1506b7c6a3b31d62f15984b1a573d6326f6aa2f3e4123284b"}, ] [[package]] name = "azure-storage-blob" -version = "12.22.0" +version = "12.23.1" requires_python = ">=3.8" summary = "Microsoft Azure Blob Storage Client Library for Python" dependencies = [ - "azure-core>=1.28.0", + "azure-core>=1.30.0", "cryptography>=2.1.4", "isodate>=0.6.1", "typing-extensions>=4.6.0", ] files = [ - {file = "azure-storage-blob-12.22.0.tar.gz", hash = "sha256:b3804bb4fe8ab1c32771fa464053da772a682c2737b19da438a3f4e5e3b3736e"}, - {file = "azure_storage_blob-12.22.0-py3-none-any.whl", hash = "sha256:bb7d2d824ce3f11f14a27ee7d9281289f7e072ac8311c52e3652672455b7d5e8"}, + {file = "azure_storage_blob-12.23.1-py3-none-any.whl", hash = "sha256:1c2238aa841d1545f42714a5017c010366137a44a0605da2d45f770174bfc6b4"}, + {file = "azure_storage_blob-12.23.1.tar.gz", hash = "sha256:a587e54d4e39d2a27bd75109db164ffa2058fe194061e5446c5a89bca918272f"}, ] [[package]] @@ -162,18 +149,18 @@ files = [ [[package]] name = "billiard" -version = "4.2.0" +version = "4.2.1" requires_python = ">=3.7" summary = "Python multiprocessing fork with improvements and bugfixes" files = [ - {file = "billiard-4.2.0-py3-none-any.whl", hash = "sha256:07aa978b308f334ff8282bd4a746e681b3513db5c9a514cbdd810cbbdc19714d"}, - {file = "billiard-4.2.0.tar.gz", hash = "sha256:9a3c3184cb275aa17a732f93f65b20c525d3d9f253722d26a82194803ade5a2c"}, + {file = "billiard-4.2.1-py3-none-any.whl", hash = "sha256:40b59a4ac8806ba2c2369ea98d876bc6108b051c227baffd928c644d15d8f3cb"}, + {file = "billiard-4.2.1.tar.gz", hash = "sha256:12b641b0c539073fc8d3f5b8b7be998956665c4233c7c1fcd66a7e677c4fb36f"}, ] [[package]] name = "black" -version = "24.8.0" -requires_python = ">=3.8" +version = "24.10.0" +requires_python = ">=3.9" summary = "The uncompromising code formatter." dependencies = [ "click>=8.0.0", @@ -185,16 +172,16 @@ dependencies = [ "typing-extensions>=4.0.1; python_version < \"3.11\"", ] files = [ - {file = "black-24.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fb6e2c0b86bbd43dee042e48059c9ad7830abd5c94b0bc518c0eeec57c3eddc1"}, - {file = "black-24.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:837fd281f1908d0076844bc2b801ad2d369c78c45cf800cad7b61686051041af"}, - {file = "black-24.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62e8730977f0b77998029da7971fa896ceefa2c4c4933fcd593fa599ecbf97a4"}, - {file = "black-24.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:72901b4913cbac8972ad911dc4098d5753704d1f3c56e44ae8dce99eecb0e3af"}, - {file = "black-24.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7c046c1d1eeb7aea9335da62472481d3bbf3fd986e093cffd35f4385c94ae368"}, - {file = "black-24.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:649f6d84ccbae73ab767e206772cc2d7a393a001070a4c814a546afd0d423aed"}, - {file = "black-24.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b59b250fdba5f9a9cd9d0ece6e6d993d91ce877d121d161e4698af3eb9c1018"}, - {file = "black-24.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:6e55d30d44bed36593c3163b9bc63bf58b3b30e4611e4d88a0c3c239930ed5b2"}, - {file = "black-24.8.0-py3-none-any.whl", hash = "sha256:972085c618ee94f402da1af548a4f218c754ea7e5dc70acb168bfaca4c2542ed"}, - {file = "black-24.8.0.tar.gz", hash = "sha256:2500945420b6784c38b9ee885af039f5e7471ef284ab03fa35ecdde4688cd83f"}, + {file = "black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3"}, + {file = "black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65"}, + {file = "black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f"}, + {file = "black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8"}, + {file = "black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981"}, + {file = "black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b"}, + {file = "black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2"}, + {file = "black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b"}, + {file = "black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d"}, + {file = "black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875"}, ] [[package]] @@ -237,58 +224,46 @@ files = [ [[package]] name = "certifi" -version = "2024.7.4" +version = "2024.8.30" requires_python = ">=3.6" summary = "Python package for providing Mozilla's CA Bundle." files = [ - {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, - {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, ] [[package]] name = "cffi" -version = "1.17.0" +version = "1.17.1" requires_python = ">=3.8" summary = "Foreign Function Interface for Python calling C code." dependencies = [ "pycparser", ] files = [ - {file = "cffi-1.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720"}, - {file = "cffi-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6"}, - {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91"}, - {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8"}, - {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb"}, - {file = "cffi-1.17.0-cp311-cp311-win32.whl", hash = "sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9"}, - {file = "cffi-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0"}, - {file = "cffi-1.17.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc"}, - {file = "cffi-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150"}, - {file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a"}, - {file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885"}, - {file = "cffi-1.17.0-cp312-cp312-win32.whl", hash = "sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492"}, - {file = "cffi-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2"}, - {file = "cffi-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118"}, - {file = "cffi-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f"}, - {file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0"}, - {file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4"}, - {file = "cffi-1.17.0-cp313-cp313-win32.whl", hash = "sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a"}, - {file = "cffi-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7"}, - {file = "cffi-1.17.0.tar.gz", hash = "sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, ] [[package]] @@ -308,21 +283,6 @@ requires_python = ">=3.7.0" summary = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." files = [ {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, @@ -410,16 +370,6 @@ version = "7.6.1" requires_python = ">=3.8" summary = "Code coverage measurement for Python" files = [ - {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, - {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, - {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, - {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, @@ -464,16 +414,6 @@ dependencies = [ "tomli; python_full_version <= \"3.11.0a6\"", ] files = [ - {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, - {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, - {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, - {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, @@ -509,41 +449,41 @@ files = [ [[package]] name = "cron-descriptor" -version = "1.4.3" +version = "1.4.5" summary = "A Python library that converts cron expressions into human readable strings." files = [ - {file = "cron_descriptor-1.4.3-py3-none-any.whl", hash = "sha256:a67ba21804983b1427ed7f3e1ec27ee77bf24c652b0430239c268c5ddfbf9dc0"}, - {file = "cron_descriptor-1.4.3.tar.gz", hash = "sha256:7b1a00d7d25d6ae6896c0da4457e790b98cba778398a3d48e341e5e0d33f0488"}, + {file = "cron_descriptor-1.4.5-py3-none-any.whl", hash = "sha256:736b3ae9d1a99bc3dbfc5b55b5e6e7c12031e7ba5de716625772f8b02dcd6013"}, + {file = "cron_descriptor-1.4.5.tar.gz", hash = "sha256:f51ce4ffc1d1f2816939add8524f206c376a42c87a5fca3091ce26725b3b1bca"}, ] [[package]] name = "cryptography" -version = "43.0.0" +version = "43.0.1" requires_python = ">=3.7" summary = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." dependencies = [ "cffi>=1.12; platform_python_implementation != \"PyPy\"", ] files = [ - {file = "cryptography-43.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:64c3f16e2a4fc51c0d06af28441881f98c5d91009b8caaff40cf3548089e9c74"}, - {file = "cryptography-43.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3dcdedae5c7710b9f97ac6bba7e1052b95c7083c9d0e9df96e02a1932e777895"}, - {file = "cryptography-43.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d9a1eca329405219b605fac09ecfc09ac09e595d6def650a437523fcd08dd22"}, - {file = "cryptography-43.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ea9e57f8ea880eeea38ab5abf9fbe39f923544d7884228ec67d666abd60f5a47"}, - {file = "cryptography-43.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9a8d6802e0825767476f62aafed40532bd435e8a5f7d23bd8b4f5fd04cc80ecf"}, - {file = "cryptography-43.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cc70b4b581f28d0a254d006f26949245e3657d40d8857066c2ae22a61222ef55"}, - {file = "cryptography-43.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4a997df8c1c2aae1e1e5ac49c2e4f610ad037fc5a3aadc7b64e39dea42249431"}, - {file = "cryptography-43.0.0-cp37-abi3-win32.whl", hash = "sha256:6e2b11c55d260d03a8cf29ac9b5e0608d35f08077d8c087be96287f43af3ccdc"}, - {file = "cryptography-43.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:31e44a986ceccec3d0498e16f3d27b2ee5fdf69ce2ab89b52eaad1d2f33d8778"}, - {file = "cryptography-43.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:7b3f5fe74a5ca32d4d0f302ffe6680fcc5c28f8ef0dc0ae8f40c0f3a1b4fca66"}, - {file = "cryptography-43.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac1955ce000cb29ab40def14fd1bbfa7af2017cca696ee696925615cafd0dce5"}, - {file = "cryptography-43.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:299d3da8e00b7e2b54bb02ef58d73cd5f55fb31f33ebbf33bd00d9aa6807df7e"}, - {file = "cryptography-43.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ee0c405832ade84d4de74b9029bedb7b31200600fa524d218fc29bfa371e97f5"}, - {file = "cryptography-43.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cb013933d4c127349b3948aa8aaf2f12c0353ad0eccd715ca789c8a0f671646f"}, - {file = "cryptography-43.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fdcb265de28585de5b859ae13e3846a8e805268a823a12a4da2597f1f5afc9f0"}, - {file = "cryptography-43.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2905ccf93a8a2a416f3ec01b1a7911c3fe4073ef35640e7ee5296754e30b762b"}, - {file = "cryptography-43.0.0-cp39-abi3-win32.whl", hash = "sha256:47ca71115e545954e6c1d207dd13461ab81f4eccfcb1345eac874828b5e3eaaf"}, - {file = "cryptography-43.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:0663585d02f76929792470451a5ba64424acc3cd5227b03921dab0e2f27b1709"}, - {file = "cryptography-43.0.0.tar.gz", hash = "sha256:b88075ada2d51aa9f18283532c9f60e72170041bba88d7f37e49cbb10275299e"}, + {file = "cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"}, + {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062"}, + {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962"}, + {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277"}, + {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a"}, + {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042"}, + {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494"}, + {file = "cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2"}, + {file = "cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d"}, + {file = "cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d"}, + {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806"}, + {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85"}, + {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c"}, + {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1"}, + {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa"}, + {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4"}, + {file = "cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47"}, + {file = "cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb"}, + {file = "cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d"}, ] [[package]] @@ -598,17 +538,17 @@ files = [ [[package]] name = "django" -version = "5.0.8" +version = "5.1.2" requires_python = ">=3.10" summary = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." dependencies = [ - "asgiref<4,>=3.7.0", + "asgiref<4,>=3.8.1", "sqlparse>=0.3.1", "tzdata; sys_platform == \"win32\"", ] files = [ - {file = "Django-5.0.8-py3-none-any.whl", hash = "sha256:333a7988f7ca4bc14d360d3d8f6b793704517761ae3813b95432043daec22a45"}, - {file = "Django-5.0.8.tar.gz", hash = "sha256:ebe859c9da6fead9c9ee6dbfa4943b04f41342f4cea2c4d8c978ef0d10694f2b"}, + {file = "Django-5.1.2-py3-none-any.whl", hash = "sha256:f11aa87ad8d5617171e3f77e1d5d16f004b79a2cf5d2e1d2b97a6a1f8e9ba5ed"}, + {file = "Django-5.1.2.tar.gz", hash = "sha256:bd7376f90c99f96b643722eee676498706c9fd7dc759f55ebfaf2c08ebcdf4f0"}, ] [[package]] @@ -667,10 +607,11 @@ files = [ [[package]] name = "django-celery-beat" -version = "2.6.0" +version = "2.7.0" +requires_python = ">=3.8" summary = "Database-backed Periodic Tasks." dependencies = [ - "Django<5.1,>=2.2", + "Django<5.2,>=2.2", "backports-zoneinfo; python_version < \"3.9\"", "celery<6.0,>=5.2.3", "cron-descriptor>=1.2.32", @@ -680,7 +621,8 @@ dependencies = [ "tzdata", ] files = [ - {file = "django-celery-beat-2.6.0.tar.gz", hash = "sha256:f75b2d129731f1214be8383e18fae6bfeacdb55dffb2116ce849222c0106f9ad"}, + {file = "django_celery_beat-2.7.0-py3-none-any.whl", hash = "sha256:851c680d8fbf608ca5fecd5836622beea89fa017bc2b3f94a5b8c648c32d84b1"}, + {file = "django_celery_beat-2.7.0.tar.gz", hash = "sha256:8482034925e09b698c05ad61c36ed2a8dbc436724a3fe119215193a4ca6dc967"}, ] [[package]] @@ -698,23 +640,22 @@ files = [ [[package]] name = "django-concurrency" -version = "2.5" -summary = "Optimistic lock implementation for Django. Prevents users from doing concurrent editing." +version = "2.6.0" +requires_python = ">=3.10" +summary = "Optimistic lock implementation for Django. Prevents users from doing concurrent editing" files = [ - {file = "django-concurrency-2.5.tar.gz", hash = "sha256:3eb0f17807ee1b967460d298c515018b30fb573413305dec5bbee775915dc979"}, + {file = "django_concurrency-2.6.0-py3-none-any.whl", hash = "sha256:eed723272c5450f102c0e7d03fbb1ab1253bcf853073d7ba356591eab88ecc9b"}, + {file = "django_concurrency-2.6.0.tar.gz", hash = "sha256:f5c4133d6497da91a8c2640f443e216160a38398b6c8506fe551770691fe2a1d"}, ] [[package]] name = "django-constance" -version = "3.1.0" -requires_python = ">=3.7" +version = "4.1.2" +requires_python = ">=3.8" summary = "Django live settings with pluggable backends, including Redis." -dependencies = [ - "django-picklefield", -] files = [ - {file = "django-constance-3.1.0.tar.gz", hash = "sha256:2b96e51de63751ef63f8f92f74e0f6aea30fb6453f3a736c21e1f8b3f6cf0b4f"}, - {file = "django_constance-3.1.0-py3-none-any.whl", hash = "sha256:6242486a346e396d765a9333d17f3101c8613cabc92e0b98dcb70c2a391bc53b"}, + {file = "django_constance-4.1.2-py3-none-any.whl", hash = "sha256:bd8e847a5a6225cfc69da9d87de909dbb765e4150507eb3f555327ba32ac6fd6"}, + {file = "django_constance-4.1.2.tar.gz", hash = "sha256:52163529d4b1be4404d4f8568c6742f76f4d4fc90dc31355849ea2c1e0c525d7"}, ] [[package]] @@ -836,15 +777,15 @@ files = [ [[package]] name = "django-model-utils" -version = "4.5.1" +version = "5.0.0" requires_python = ">=3.8" summary = "Django model mixins and utilities" dependencies = [ "Django>=3.2", ] files = [ - {file = "django_model_utils-4.5.1-py3-none-any.whl", hash = "sha256:f1141fc71796242edeffed5ad53a8cc57f00d345eb5a3a63e3f69401cd562ee2"}, - {file = "django_model_utils-4.5.1.tar.gz", hash = "sha256:1220f22d9a467d53a1e0f4cda4857df0b2f757edf9a29955c42461988caa648a"}, + {file = "django_model_utils-5.0.0-py3-none-any.whl", hash = "sha256:fec78e6c323d565a221f7c4edc703f4567d7bb1caeafe1acd16a80c5ff82056b"}, + {file = "django_model_utils-5.0.0.tar.gz", hash = "sha256:041cdd6230d2fbf6cd943e1969318bce762272077f4ecd333ab2263924b4e5eb"}, ] [[package]] @@ -873,6 +814,14 @@ files = [ {file = "django_picklefield-3.2-py3-none-any.whl", hash = "sha256:e9a73539d110f69825d9320db18bcb82e5189ff48dbed41821c026a20497764c"}, ] +[[package]] +name = "django-regex" +version = "0.5.0" +summary = "Fields and utilities to work with regular expression in Django" +files = [ + {file = "django-regex-0.5.0.tar.gz", hash = "sha256:6af1add11ae5232f133a42754c9291f9113996b1294b048305d9f1a427bca27c"}, +] + [[package]] name = "django-smart-admin" version = "2.6.0" @@ -888,6 +837,19 @@ files = [ {file = "django-smart-admin-2.6.0.tar.gz", hash = "sha256:9ac878433c57eb285360e0c019258fc7fef9d5557805dafb55d2f965e4fe02e2"}, ] +[[package]] +name = "django-smart-env" +version = "0.1.0" +requires_python = ">=3.12" +summary = "Add your description here" +dependencies = [ + "django-environ>=0.11.2", +] +files = [ + {file = "django_smart_env-0.1.0-py3-none-any.whl", hash = "sha256:ffcbc03ab2b28808d1ac80b5165543549396dde4a24107e969a9635ba9321849"}, + {file = "django_smart_env-0.1.0.tar.gz", hash = "sha256:09ef06a2ae9223c68ba893dae2b6188938f41e464cb38e4714c341950fc1caf3"}, +] + [[package]] name = "django-storages" version = "1.14.4" @@ -959,7 +921,7 @@ files = [ [[package]] name = "django-viewflow" -version = "2.2.6" +version = "2.2.8" requires_python = ">=3.8" summary = "Reusable library to build business applications fast" dependencies = [ @@ -967,20 +929,20 @@ dependencies = [ "django-filter>=2.3.0", ] files = [ - {file = "django_viewflow-2.2.6-py3-none-any.whl", hash = "sha256:f727ee1c689490c546c6787c2c8b527d12b6cd3dea32b25ff57422d21fa52548"}, - {file = "django_viewflow-2.2.6.tar.gz", hash = "sha256:05ae644064c29a7e220871109673b1204dc7809611c254b1c155424a348b1fa4"}, + {file = "django-viewflow-2.2.8.tar.gz", hash = "sha256:f0ee76a760b336cc4e159bba5736352f707f0785922d3397c94ea9f1d8e9ae04"}, + {file = "django_viewflow-2.2.8-py3-none-any.whl", hash = "sha256:129469c449e517da1d2d58289ac38107cf5c062e64e3df5135224b70eca6efcd"}, ] [[package]] name = "django-webtest" -version = "1.9.11" +version = "1.9.12" summary = "Instant integration of Ian Bicking's WebTest (http://docs.pylonsproject.org/projects/webtest/) with Django's testing framework." dependencies = [ "webtest>=1.3.3", ] files = [ - {file = "django-webtest-1.9.11.tar.gz", hash = "sha256:9597d26ced599bc5d4d9366bb451469fc9707b4779f79543cdf401ae6c5aeb35"}, - {file = "django_webtest-1.9.11-py3-none-any.whl", hash = "sha256:e29baf8337e7fe7db41ce63ca6661f7b5c77fe56f506f48b305e09313f5475b4"}, + {file = "django_webtest-1.9.12-py3-none-any.whl", hash = "sha256:de5c988c20eef7abbb3d0508494d9e576af08087d0fb6109b1d54f15ef4d78fa"}, + {file = "django_webtest-1.9.12.tar.gz", hash = "sha256:5012c30665e7a6e585a1544eda75045d07d5b3f5ccccd4d0fe144c4555884095"}, ] [[package]] @@ -1093,62 +1055,49 @@ files = [ [[package]] name = "executing" -version = "2.0.1" -requires_python = ">=3.5" +version = "2.1.0" +requires_python = ">=3.8" summary = "Get the currently executing AST node of a frame, and other information" files = [ - {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, - {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, + {file = "executing-2.1.0-py2.py3-none-any.whl", hash = "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf"}, + {file = "executing-2.1.0.tar.gz", hash = "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab"}, ] [[package]] name = "factory-boy" -version = "3.3.0" -requires_python = ">=3.7" +version = "3.3.1" +requires_python = ">=3.8" summary = "A versatile test fixtures replacement based on thoughtbot's factory_bot for Ruby." dependencies = [ "Faker>=0.7.0", - "importlib-metadata; python_version < \"3.8\"", ] files = [ - {file = "factory_boy-3.3.0-py2.py3-none-any.whl", hash = "sha256:a2cdbdb63228177aa4f1c52f4b6d83fab2b8623bf602c7dedd7eb83c0f69c04c"}, - {file = "factory_boy-3.3.0.tar.gz", hash = "sha256:bc76d97d1a65bbd9842a6d722882098eb549ec8ee1081f9fb2e8ff29f0c300f1"}, + {file = "factory_boy-3.3.1-py2.py3-none-any.whl", hash = "sha256:7b1113c49736e1e9995bc2a18f4dbf2c52cf0f841103517010b1d825712ce3ca"}, + {file = "factory_boy-3.3.1.tar.gz", hash = "sha256:8317aa5289cdfc45f9cae570feb07a6177316c82e34d14df3c2e1f22f26abef0"}, ] [[package]] name = "faker" -version = "27.0.0" +version = "30.3.0" requires_python = ">=3.8" summary = "Faker is a Python package that generates fake data for you." dependencies = [ "python-dateutil>=2.4", + "typing-extensions", ] files = [ - {file = "Faker-27.0.0-py3-none-any.whl", hash = "sha256:55ed0c4ed7bf16800c64823805f6fbbe6d4823db4b7c0903f6f890b8e4d6c34b"}, - {file = "faker-27.0.0.tar.gz", hash = "sha256:32c78b68d2ba97aaad78422e4035785de2b4bb46b81e428190fc11978da9036c"}, -] - -[[package]] -name = "fastdiff" -version = "0.3.0" -summary = "A fast native implementation of diff algorithm with a pure python fallback" -dependencies = [ - "wasmer-compiler-cranelift>=1.0.0", - "wasmer>=1.0.0", -] -files = [ - {file = "fastdiff-0.3.0-py2.py3-none-any.whl", hash = "sha256:ca5f61f6ddf5a1564ddfd98132ad28e7abe4a88a638a8b014a2214f71e5918ec"}, - {file = "fastdiff-0.3.0.tar.gz", hash = "sha256:4dfa09c47832a8c040acda3f1f55fc0ab4d666f0e14e6951e6da78d59acd945a"}, + {file = "Faker-30.3.0-py3-none-any.whl", hash = "sha256:e8a15fd1b0f72992b008f5ea94c70d3baa0cb51b0d5a0e899c17b1d1b23d2771"}, + {file = "faker-30.3.0.tar.gz", hash = "sha256:8760fbb34564fbb2f394345eef24aec5b8f6506b6cfcefe8195ed66dd1032bdb"}, ] [[package]] name = "filelock" -version = "3.15.4" +version = "3.16.1" requires_python = ">=3.8" summary = "A platform independent file lock." files = [ - {file = "filelock-3.15.4-py3-none-any.whl", hash = "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7"}, - {file = "filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb"}, + {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"}, + {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"}, ] [[package]] @@ -1168,7 +1117,7 @@ files = [ [[package]] name = "flake8-bugbear" -version = "24.4.26" +version = "24.8.19" requires_python = ">=3.8.1" summary = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." dependencies = [ @@ -1176,8 +1125,8 @@ dependencies = [ "flake8>=6.0.0", ] files = [ - {file = "flake8_bugbear-24.4.26-py3-none-any.whl", hash = "sha256:cb430dd86bc821d79ccc0b030789a9c87a47a369667f12ba06e80f11305e8258"}, - {file = "flake8_bugbear-24.4.26.tar.gz", hash = "sha256:ff8d4ba5719019ebf98e754624c30c05cef0dadcf18a65d91c7567300e52a130"}, + {file = "flake8_bugbear-24.8.19-py3-none-any.whl", hash = "sha256:25bc3867f7338ee3b3e0916bf8b8a0b743f53a9a5175782ddc4325ed4f386b89"}, + {file = "flake8_bugbear-24.8.19.tar.gz", hash = "sha256:9b77627eceda28c51c27af94560a72b5b2c97c016651bdce45d8f56c180d2d32"}, ] [[package]] @@ -1276,32 +1225,32 @@ files = [ [[package]] name = "humanize" -version = "4.10.0" -requires_python = ">=3.8" +version = "4.11.0" +requires_python = ">=3.9" summary = "Python humanize utilities" files = [ - {file = "humanize-4.10.0-py3-none-any.whl", hash = "sha256:39e7ccb96923e732b5c2e27aeaa3b10a8dfeeba3eb965ba7b74a3eb0e30040a6"}, - {file = "humanize-4.10.0.tar.gz", hash = "sha256:06b6eb0293e4b85e8d385397c5868926820db32b9b654b932f57fa41c23c9978"}, + {file = "humanize-4.11.0-py3-none-any.whl", hash = "sha256:b53caaec8532bcb2fff70c8826f904c35943f8cecaca29d272d9df38092736c0"}, + {file = "humanize-4.11.0.tar.gz", hash = "sha256:e66f36020a2d5a974c504bd2555cf770621dbdbb6d82f94a6857c0b1ea2608be"}, ] [[package]] name = "identify" -version = "2.6.0" +version = "2.6.1" requires_python = ">=3.8" summary = "File identification library for Python" files = [ - {file = "identify-2.6.0-py2.py3-none-any.whl", hash = "sha256:e79ae4406387a9d300332b5fd366d8994f1525e8414984e1a59e058b2eda2dd0"}, - {file = "identify-2.6.0.tar.gz", hash = "sha256:cb171c685bdc31bcc4c1734698736a7d5b6c8bf2e0c15117f4d469c8640ae5cf"}, + {file = "identify-2.6.1-py2.py3-none-any.whl", hash = "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0"}, + {file = "identify-2.6.1.tar.gz", hash = "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98"}, ] [[package]] name = "idna" -version = "3.7" -requires_python = ">=3.5" +version = "3.10" +requires_python = ">=3.6" summary = "Internationalized Domain Names in Applications (IDNA)" files = [ - {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, - {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] [[package]] @@ -1356,7 +1305,7 @@ files = [ [[package]] name = "ipython" -version = "8.26.0" +version = "8.28.0" requires_python = ">=3.10" summary = "IPython: Productive Interactive Computing" dependencies = [ @@ -1373,20 +1322,18 @@ dependencies = [ "typing-extensions>=4.6; python_version < \"3.12\"", ] files = [ - {file = "ipython-8.26.0-py3-none-any.whl", hash = "sha256:e6b347c27bdf9c32ee9d31ae85defc525755a1869f14057e900675b9e8d6e6ff"}, - {file = "ipython-8.26.0.tar.gz", hash = "sha256:1cec0fbba8404af13facebe83d04436a7434c7400e59f47acf467c64abd0956c"}, + {file = "ipython-8.28.0-py3-none-any.whl", hash = "sha256:530ef1e7bb693724d3cdc37287c80b07ad9b25986c007a53aa1857272dac3f35"}, + {file = "ipython-8.28.0.tar.gz", hash = "sha256:0d0d15ca1e01faeb868ef56bc7ee5a0de5bd66885735682e8a322ae289a13d1a"}, ] [[package]] name = "isodate" -version = "0.6.1" +version = "0.7.2" +requires_python = ">=3.7" summary = "An ISO 8601 date/time/duration parser and formatter" -dependencies = [ - "six", -] files = [ - {file = "isodate-0.6.1-py2.py3-none-any.whl", hash = "sha256:0751eece944162659049d35f4f549ed815792b38793f07cf73381c1c87cbed96"}, - {file = "isodate-0.6.1.tar.gz", hash = "sha256:48c5881de7e8b0a0d648cb024c8062dc84e7b840ed81e864c7614fd3c127bde9"}, + {file = "isodate-0.7.2-py3-none-any.whl", hash = "sha256:28009937d8031054830160fce6d409ed342816b543597cece116d966c6d99e15"}, + {file = "isodate-0.7.2.tar.gz", hash = "sha256:4cd1aa0f43ca76f4a6c6c0292a85f40b35ec2e43e315b59f06e6d32171a953e6"}, ] [[package]] @@ -1445,16 +1392,15 @@ files = [ [[package]] name = "jsonschema-specifications" -version = "2023.12.1" -requires_python = ">=3.8" +version = "2024.10.1" +requires_python = ">=3.9" summary = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" dependencies = [ - "importlib-resources>=1.4.0; python_version < \"3.9\"", "referencing>=0.31.0", ] files = [ - {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"}, - {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"}, + {file = "jsonschema_specifications-2024.10.1-py3-none-any.whl", hash = "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf"}, + {file = "jsonschema_specifications-2024.10.1.tar.gz", hash = "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272"}, ] [[package]] @@ -1471,18 +1417,19 @@ files = [ [[package]] name = "kombu" -version = "5.4.0" +version = "5.4.2" requires_python = ">=3.8" summary = "Messaging library for Python." dependencies = [ "amqp<6.0.0,>=5.1.1", "backports-zoneinfo[tzdata]>=0.2.1; python_version < \"3.9\"", "typing-extensions==4.12.2; python_version < \"3.10\"", + "tzdata; python_version >= \"3.9\"", "vine==5.1.0", ] files = [ - {file = "kombu-5.4.0-py3-none-any.whl", hash = "sha256:c8dd99820467610b4febbc7a9e8a0d3d7da2d35116b67184418b51cc520ea6b6"}, - {file = "kombu-5.4.0.tar.gz", hash = "sha256:ad200a8dbdaaa2bbc5f26d2ee7d707d9a1fded353a0f4bd751ce8c7d9f449c60"}, + {file = "kombu-5.4.2-py3-none-any.whl", hash = "sha256:14212f5ccf022fc0a70453bb025a1dcc32782a588c49ea866884047d66e14763"}, + {file = "kombu-5.4.2.tar.gz", hash = "sha256:eef572dd2fd9fc614b37580e3caeafdd5af46c1eff31e7fba89138cdb406f2cf"}, ] [[package]] @@ -1491,23 +1438,6 @@ version = "5.3.0" requires_python = ">=3.6" summary = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." files = [ - {file = "lxml-5.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:74bcb423462233bc5d6066e4e98b0264e7c1bed7541fff2f4e34fe6b21563c8b"}, - {file = "lxml-5.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a3d819eb6f9b8677f57f9664265d0a10dd6551d227afb4af2b9cd7bdc2ccbf18"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b8f5db71b28b8c404956ddf79575ea77aa8b1538e8b2ef9ec877945b3f46442"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3406b63232fc7e9b8783ab0b765d7c59e7c59ff96759d8ef9632fca27c7ee4"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ecdd78ab768f844c7a1d4a03595038c166b609f6395e25af9b0f3f26ae1230f"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:168f2dfcfdedf611eb285efac1516c8454c8c99caf271dccda8943576b67552e"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa617107a410245b8660028a7483b68e7914304a6d4882b5ff3d2d3eb5948d8c"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:69959bd3167b993e6e710b99051265654133a98f20cec1d9b493b931942e9c16"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:bd96517ef76c8654446fc3db9242d019a1bb5fe8b751ba414765d59f99210b79"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:ab6dd83b970dc97c2d10bc71aa925b84788c7c05de30241b9e96f9b6d9ea3080"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:eec1bb8cdbba2925bedc887bc0609a80e599c75b12d87ae42ac23fd199445654"}, - {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a7095eeec6f89111d03dabfe5883a1fd54da319c94e0fb104ee8f23616b572d"}, - {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6f651ebd0b21ec65dfca93aa629610a0dbc13dbc13554f19b0113da2e61a4763"}, - {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:f422a209d2455c56849442ae42f25dbaaba1c6c3f501d58761c619c7836642ec"}, - {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:62f7fdb0d1ed2065451f086519865b4c90aa19aed51081979ecd05a21eb4d1be"}, - {file = "lxml-5.3.0-cp311-cp311-win32.whl", hash = "sha256:c6379f35350b655fd817cd0d6cbeef7f265f3ae5fedb1caae2eb442bbeae9ab9"}, - {file = "lxml-5.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:9c52100e2c2dbb0649b90467935c4b0de5528833c76a35ea1a2691ec9f1ee7a1"}, {file = "lxml-5.3.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e99f5507401436fdcc85036a2e7dc2e28d962550afe1cbfc07c40e454256a859"}, {file = "lxml-5.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:384aacddf2e5813a36495233b64cb96b1949da72bef933918ba5c84e06af8f0e"}, {file = "lxml-5.3.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:874a216bf6afaf97c263b56371434e47e2c652d215788396f60477540298218f"}, @@ -1547,31 +1477,41 @@ files = [ [[package]] name = "markupsafe" -version = "2.1.5" -requires_python = ">=3.7" +version = "3.0.1" +requires_python = ">=3.9" summary = "Safely add untrusted strings to HTML/XML markup." files = [ - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, - {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, + {file = "MarkupSafe-3.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8ae369e84466aa70f3154ee23c1451fda10a8ee1b63923ce76667e3077f2b0c4"}, + {file = "MarkupSafe-3.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40f1e10d51c92859765522cbd79c5c8989f40f0419614bcdc5015e7b6bf97fc5"}, + {file = "MarkupSafe-3.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a4cb365cb49b750bdb60b846b0c0bc49ed62e59a76635095a179d440540c346"}, + {file = "MarkupSafe-3.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee3941769bd2522fe39222206f6dd97ae83c442a94c90f2b7a25d847d40f4729"}, + {file = "MarkupSafe-3.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62fada2c942702ef8952754abfc1a9f7658a4d5460fabe95ac7ec2cbe0d02abc"}, + {file = "MarkupSafe-3.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4c2d64fdba74ad16138300815cfdc6ab2f4647e23ced81f59e940d7d4a1469d9"}, + {file = "MarkupSafe-3.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:fb532dd9900381d2e8f48172ddc5a59db4c445a11b9fab40b3b786da40d3b56b"}, + {file = "MarkupSafe-3.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0f84af7e813784feb4d5e4ff7db633aba6c8ca64a833f61d8e4eade234ef0c38"}, + {file = "MarkupSafe-3.0.1-cp312-cp312-win32.whl", hash = "sha256:cbf445eb5628981a80f54087f9acdbf84f9b7d862756110d172993b9a5ae81aa"}, + {file = "MarkupSafe-3.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:a10860e00ded1dd0a65b83e717af28845bb7bd16d8ace40fe5531491de76b79f"}, + {file = "MarkupSafe-3.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e81c52638315ff4ac1b533d427f50bc0afc746deb949210bc85f05d4f15fd772"}, + {file = "MarkupSafe-3.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:312387403cd40699ab91d50735ea7a507b788091c416dd007eac54434aee51da"}, + {file = "MarkupSafe-3.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ae99f31f47d849758a687102afdd05bd3d3ff7dbab0a8f1587981b58a76152a"}, + {file = "MarkupSafe-3.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c97ff7fedf56d86bae92fa0a646ce1a0ec7509a7578e1ed238731ba13aabcd1c"}, + {file = "MarkupSafe-3.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7420ceda262dbb4b8d839a4ec63d61c261e4e77677ed7c66c99f4e7cb5030dd"}, + {file = "MarkupSafe-3.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45d42d132cff577c92bfba536aefcfea7e26efb975bd455db4e6602f5c9f45e7"}, + {file = "MarkupSafe-3.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4c8817557d0de9349109acb38b9dd570b03cc5014e8aabf1cbddc6e81005becd"}, + {file = "MarkupSafe-3.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6a54c43d3ec4cf2a39f4387ad044221c66a376e58c0d0e971d47c475ba79c6b5"}, + {file = "MarkupSafe-3.0.1-cp313-cp313-win32.whl", hash = "sha256:c91b394f7601438ff79a4b93d16be92f216adb57d813a78be4446fe0f6bc2d8c"}, + {file = "MarkupSafe-3.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:fe32482b37b4b00c7a52a07211b479653b7fe4f22b2e481b9a9b099d8a430f2f"}, + {file = "MarkupSafe-3.0.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:17b2aea42a7280db02ac644db1d634ad47dcc96faf38ab304fe26ba2680d359a"}, + {file = "MarkupSafe-3.0.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:852dc840f6d7c985603e60b5deaae1d89c56cb038b577f6b5b8c808c97580f1d"}, + {file = "MarkupSafe-3.0.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0778de17cff1acaeccc3ff30cd99a3fd5c50fc58ad3d6c0e0c4c58092b859396"}, + {file = "MarkupSafe-3.0.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:800100d45176652ded796134277ecb13640c1a537cad3b8b53da45aa96330453"}, + {file = "MarkupSafe-3.0.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d06b24c686a34c86c8c1fba923181eae6b10565e4d80bdd7bc1c8e2f11247aa4"}, + {file = "MarkupSafe-3.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:33d1c36b90e570ba7785dacd1faaf091203d9942bc036118fab8110a401eb1a8"}, + {file = "MarkupSafe-3.0.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:beeebf760a9c1f4c07ef6a53465e8cfa776ea6a2021eda0d0417ec41043fe984"}, + {file = "MarkupSafe-3.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:bbde71a705f8e9e4c3e9e33db69341d040c827c7afa6789b14c6e16776074f5a"}, + {file = "MarkupSafe-3.0.1-cp313-cp313t-win32.whl", hash = "sha256:82b5dba6eb1bcc29cc305a18a3c5365d2af06ee71b123216416f7e20d2a84e5b"}, + {file = "MarkupSafe-3.0.1-cp313-cp313t-win_amd64.whl", hash = "sha256:730d86af59e0e43ce277bb83970530dd223bf7f2a838e086b50affa6ec5f9295"}, + {file = "markupsafe-3.0.1.tar.gz", hash = "sha256:3e683ee4f5d0fa2dde4db77ed8dd8a876686e3fc417655c2ece9a90576905344"}, ] [[package]] @@ -1599,7 +1539,7 @@ files = [ [[package]] name = "mypy" -version = "1.11.1" +version = "1.11.2" requires_python = ">=3.8" summary = "Optional static typing for Python" dependencies = [ @@ -1608,18 +1548,13 @@ dependencies = [ "typing-extensions>=4.6.0", ] files = [ - {file = "mypy-1.11.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7b6343d338390bb946d449677726edf60102a1c96079b4f002dedff375953fc5"}, - {file = "mypy-1.11.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4fe9f4e5e521b458d8feb52547f4bade7ef8c93238dfb5bbc790d9ff2d770ca"}, - {file = "mypy-1.11.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:886c9dbecc87b9516eff294541bf7f3655722bf22bb898ee06985cd7269898de"}, - {file = "mypy-1.11.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fca4a60e1dd9fd0193ae0067eaeeb962f2d79e0d9f0f66223a0682f26ffcc809"}, - {file = "mypy-1.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:0bd53faf56de9643336aeea1c925012837432b5faf1701ccca7fde70166ccf72"}, - {file = "mypy-1.11.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f39918a50f74dc5969807dcfaecafa804fa7f90c9d60506835036cc1bc891dc8"}, - {file = "mypy-1.11.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0bc71d1fb27a428139dd78621953effe0d208aed9857cb08d002280b0422003a"}, - {file = "mypy-1.11.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b868d3bcff720dd7217c383474008ddabaf048fad8d78ed948bb4b624870a417"}, - {file = "mypy-1.11.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a707ec1527ffcdd1c784d0924bf5cb15cd7f22683b919668a04d2b9c34549d2e"}, - {file = "mypy-1.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:64f4a90e3ea07f590c5bcf9029035cf0efeae5ba8be511a8caada1a4893f5525"}, - {file = "mypy-1.11.1-py3-none-any.whl", hash = "sha256:0624bdb940255d2dd24e829d99a13cfeb72e4e9031f9492148f410ed30bcab54"}, - {file = "mypy-1.11.1.tar.gz", hash = "sha256:f404a0b069709f18bbdb702eb3dcfe51910602995de00bd39cea3050b5772d08"}, + {file = "mypy-1.11.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e8960dbbbf36906c5c0b7f4fbf2f0c7ffb20f4898e6a879fcf56a41a08b0d318"}, + {file = "mypy-1.11.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06d26c277962f3fb50e13044674aa10553981ae514288cb7d0a738f495550b36"}, + {file = "mypy-1.11.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e7184632d89d677973a14d00ae4d03214c8bc301ceefcdaf5c474866814c987"}, + {file = "mypy-1.11.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3a66169b92452f72117e2da3a576087025449018afc2d8e9bfe5ffab865709ca"}, + {file = "mypy-1.11.2-cp312-cp312-win_amd64.whl", hash = "sha256:969ea3ef09617aff826885a22ece0ddef69d95852cdad2f60c8bb06bf1f71f70"}, + {file = "mypy-1.11.2-py3-none-any.whl", hash = "sha256:b499bc07dbdcd3de92b0a8b29fdf592c111276f6a12fe29c30f6c417dd546d12"}, + {file = "mypy-1.11.2.tar.gz", hash = "sha256:7f9993ad3e0ffdc95c2a14b66dee63729f021968bff8ad911867579c65d13a79"}, ] [[package]] @@ -1647,19 +1582,15 @@ files = [ [[package]] name = "newrelic" -version = "9.13.0" -requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +version = "10.0.0" +requires_python = ">=3.7" summary = "New Relic Python Agent" files = [ - {file = "newrelic-9.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbfe4a0f2d34d8d9ef31cee7c73a49d3fe2b9a92129d70819058f1df736cdd38"}, - {file = "newrelic-9.13.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db3cc230970902c2548e5d747ce96d38bc009d087cf49bef4ce8679cdedc57c1"}, - {file = "newrelic-9.13.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d5fe36aae1154610d2d03cd8cdfc52b6ea3f63a0b672b14185e4e1532016f826"}, - {file = "newrelic-9.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f9ab59b30729532bab64497910c1051665269814366be8ee3fde2391032dd9f6"}, - {file = "newrelic-9.13.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa8addb08bf7595eeb65ada2b33d9272541b6e872e519382be28690a920f4785"}, - {file = "newrelic-9.13.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:632435a5f5170dd9a72012b6c21ca62ec2e9e4b24e7d52fc4d895a359dbba652"}, - {file = "newrelic-9.13.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d720f97c844a015cd54d69e052f0956e93e45fcd33b829e8cc20356af6a0b0c4"}, - {file = "newrelic-9.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3c5cc86c88302623375e282ec17a1c55da739f2ab58ca48607f85c48a43cba33"}, - {file = "newrelic-9.13.0.tar.gz", hash = "sha256:7405bfc65d6d983a738e756044956f06c366a234fdde0ccf7cf0d52fedfd72e4"}, + {file = "newrelic-10.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:002e21527c77c0c9640402c152d40a114b4cc821e7de93cf445fffaef160f1aa"}, + {file = "newrelic-10.0.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f4cd5ca11f08badd4b1cdd746053cfb30a09d5d9b9c1f5d911718d2870b4493"}, + {file = "newrelic-10.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:27d2f34bf714ef9d7ff8a68265a2094b87a4bdc7b1bbbd0a1421cf5cf8f33311"}, + {file = "newrelic-10.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f1aac4a5fe1d0cbe2bb9e2c52152604fb872a6bce28e129febd29d1d307df1f4"}, + {file = "newrelic-10.0.0.tar.gz", hash = "sha256:548b538c3e95b589a30565bff668285ca74bb64069eb1d6f643bde9768944f53"}, ] [[package]] @@ -1731,7 +1662,7 @@ files = [ [[package]] name = "paramiko" -version = "3.4.1" +version = "3.5.0" requires_python = ">=3.6" summary = "SSH2 protocol library" dependencies = [ @@ -1740,8 +1671,8 @@ dependencies = [ "pynacl>=1.5", ] files = [ - {file = "paramiko-3.4.1-py3-none-any.whl", hash = "sha256:8e49fd2f82f84acf7ffd57c64311aa2b30e575370dc23bdb375b10262f7eac32"}, - {file = "paramiko-3.4.1.tar.gz", hash = "sha256:8b15302870af7f6652f2e038975c1d2973f06046cb5d7d65355668b3ecbece0c"}, + {file = "paramiko-3.5.0-py3-none-any.whl", hash = "sha256:1fedf06b085359051cd7d0d270cebe19e755a8a921cc2ddbfa647fb0cd7d68f9"}, + {file = "paramiko-3.5.0.tar.gz", hash = "sha256:ad11e540da4f55cedda52931f1a3f812a8238a7af7f62a60de538cd80bb28124"}, ] [[package]] @@ -1787,21 +1718,21 @@ files = [ [[package]] name = "phonenumbers" -version = "8.13.43" +version = "8.13.47" summary = "Python version of Google's common library for parsing, formatting, storing and validating international phone numbers." files = [ - {file = "phonenumbers-8.13.43-py2.py3-none-any.whl", hash = "sha256:339e521403fe4dd9c664dbbeb2fe434f9ea5c81e54c0fdfadbaeb53b26a76c27"}, - {file = "phonenumbers-8.13.43.tar.gz", hash = "sha256:35b904e4a79226eee027fbb467a9aa6f1ab9ffc3c09c91bf14b885c154936726"}, + {file = "phonenumbers-8.13.47-py2.py3-none-any.whl", hash = "sha256:5d3c0142ef7055ca5551884352e3b6b93bfe002a0bc95b8eaba39b0e2184541b"}, + {file = "phonenumbers-8.13.47.tar.gz", hash = "sha256:53c5e7c6d431cafe4efdd44956078404ae9bc8b0eacc47be3105d3ccc88aaffa"}, ] [[package]] name = "platformdirs" -version = "4.2.2" +version = "4.3.6" requires_python = ">=3.8" summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." files = [ - {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, - {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, ] [[package]] @@ -1816,7 +1747,7 @@ files = [ [[package]] name = "pre-commit" -version = "3.8.0" +version = "4.0.1" requires_python = ">=3.9" summary = "A framework for managing and maintaining multi-language pre-commit hooks." dependencies = [ @@ -1827,31 +1758,31 @@ dependencies = [ "virtualenv>=20.10.0", ] files = [ - {file = "pre_commit-3.8.0-py2.py3-none-any.whl", hash = "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f"}, - {file = "pre_commit-3.8.0.tar.gz", hash = "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af"}, + {file = "pre_commit-4.0.1-py2.py3-none-any.whl", hash = "sha256:efde913840816312445dc98787724647c65473daefe420785f885e8ed9a06878"}, + {file = "pre_commit-4.0.1.tar.gz", hash = "sha256:80905ac375958c0444c65e9cebebd948b3cdb518f335a091a670a89d652139d2"}, ] [[package]] name = "prometheus-client" -version = "0.20.0" +version = "0.21.0" requires_python = ">=3.8" summary = "Python client for the Prometheus monitoring system." files = [ - {file = "prometheus_client-0.20.0-py3-none-any.whl", hash = "sha256:cde524a85bce83ca359cc837f28b8c0db5cac7aa653a588fd7e84ba061c329e7"}, - {file = "prometheus_client-0.20.0.tar.gz", hash = "sha256:287629d00b147a32dcb2be0b9df905da599b2d82f80377083ec8463309a4bb89"}, + {file = "prometheus_client-0.21.0-py3-none-any.whl", hash = "sha256:4fa6b4dd0ac16d58bb587c04b1caae65b8c5043e85f778f42f5f632f6af2e166"}, + {file = "prometheus_client-0.21.0.tar.gz", hash = "sha256:96c83c606b71ff2b0a433c98889d275f51ffec6c5e267de37c7a2b5c9aa9233e"}, ] [[package]] name = "prompt-toolkit" -version = "3.0.47" +version = "3.0.48" requires_python = ">=3.7.0" summary = "Library for building powerful interactive command lines in Python" dependencies = [ "wcwidth", ] files = [ - {file = "prompt_toolkit-3.0.47-py3-none-any.whl", hash = "sha256:0d7bfa67001d5e39d02c224b663abc33687405033a8c422d0d675a5a13361d10"}, - {file = "prompt_toolkit-3.0.47.tar.gz", hash = "sha256:1e1b29cb58080b1e69f207c893a1a7bf16d127a5c30c9d17a25a5d77792e5360"}, + {file = "prompt_toolkit-3.0.48-py3-none-any.whl", hash = "sha256:f49a827f90062e411f1ce1f854f2aedb3c23353244f8108b89283587397ac10e"}, + {file = "prompt_toolkit-3.0.48.tar.gz", hash = "sha256:d6623ab0477a80df74e646bdbc93621143f5caf104206aa29294d53de1a03d90"}, ] [[package]] @@ -1872,62 +1803,62 @@ files = [ [[package]] name = "psycopg" -version = "3.2.1" +version = "3.2.3" requires_python = ">=3.8" summary = "PostgreSQL database adapter for Python" dependencies = [ "backports-zoneinfo>=0.2.0; python_version < \"3.9\"", - "typing-extensions>=4.4", + "typing-extensions>=4.6; python_version < \"3.13\"", "tzdata; sys_platform == \"win32\"", ] files = [ - {file = "psycopg-3.2.1-py3-none-any.whl", hash = "sha256:ece385fb413a37db332f97c49208b36cf030ff02b199d7635ed2fbd378724175"}, - {file = "psycopg-3.2.1.tar.gz", hash = "sha256:dc8da6dc8729dacacda3cc2f17d2c9397a70a66cf0d2b69c91065d60d5f00cb7"}, + {file = "psycopg-3.2.3-py3-none-any.whl", hash = "sha256:644d3973fe26908c73d4be746074f6e5224b03c1101d302d9a53bf565ad64907"}, + {file = "psycopg-3.2.3.tar.gz", hash = "sha256:a5764f67c27bec8bfac85764d23c534af2c27b893550377e37ce59c12aac47a2"}, ] [[package]] name = "psycopg-binary" -version = "3.2.1" +version = "3.2.3" requires_python = ">=3.8" summary = "PostgreSQL database adapter for Python -- C optimisation distribution" files = [ - {file = "psycopg_binary-3.2.1-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:62b1b7b07e00ee490afb39c0a47d8282a9c2822c7cfed9553a04b0058adf7e7f"}, - {file = "psycopg_binary-3.2.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:f8afb07114ea9b924a4a0305ceb15354ccf0ef3c0e14d54b8dbeb03e50182dd7"}, - {file = "psycopg_binary-3.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40bb515d042f6a345714ec0403df68ccf13f73b05e567837d80c886c7c9d3805"}, - {file = "psycopg_binary-3.2.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6418712ba63cebb0c88c050b3997185b0ef54173b36568522d5634ac06153040"}, - {file = "psycopg_binary-3.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:101472468d59c74bb8565fab603e032803fd533d16be4b2d13da1bab8deb32a3"}, - {file = "psycopg_binary-3.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa3931f308ab4a479d0ee22dc04bea867a6365cac0172e5ddcba359da043854b"}, - {file = "psycopg_binary-3.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dc314a47d44fe1a8069b075a64abffad347a3a1d8652fed1bab5d3baea37acb2"}, - {file = "psycopg_binary-3.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:cc304a46be1e291031148d9d95c12451ffe783ff0cc72f18e2cc7ec43cdb8c68"}, - {file = "psycopg_binary-3.2.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6f9e13600647087df5928875559f0eb8f496f53e6278b7da9511b4b3d0aff960"}, - {file = "psycopg_binary-3.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b140182830c76c74d17eba27df3755a46442ce8d4fb299e7f1cf2f74a87c877b"}, - {file = "psycopg_binary-3.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:3c838806eeb99af39f934b7999e35f947a8e577997cc892c12b5053a97a9057f"}, - {file = "psycopg_binary-3.2.1-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:7066d3dca196ed0dc6172f9777b2d62e4f138705886be656cccff2d555234d60"}, - {file = "psycopg_binary-3.2.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:28ada5f610468c57d8a4a055a8ea915d0085a43d794266c4f3b9d02f4288f4db"}, - {file = "psycopg_binary-3.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e8213bf50af073b1aa8dc3cff123bfeedac86332a16c1b7274910bc88a847c7"}, - {file = "psycopg_binary-3.2.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74d623261655a169bc84a9669890975c229f2fa6e19a7f2d10a77675dcf1a707"}, - {file = "psycopg_binary-3.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:42781ba94e8842ee98bca5a7d0c44cc9d067500fedca2d6a90fa3609b6d16b42"}, - {file = "psycopg_binary-3.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33e6669091d09f8ba36e10ce678a6d9916e110446236a9b92346464a3565635e"}, - {file = "psycopg_binary-3.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b09e8a576a2ac69d695032ee76f31e03b30781828b5dd6d18c6a009e5a3d1c35"}, - {file = "psycopg_binary-3.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8f28ff0cb9f1defdc4a6f8c958bf6787274247e7dfeca811f6e2f56602695fb1"}, - {file = "psycopg_binary-3.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4c84fcac8a3a3479ac14673095cc4e1fdba2935499f72c436785ac679bec0d1a"}, - {file = "psycopg_binary-3.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:950fd666ec9e9fe6a8eeb2b5a8f17301790e518953730ad44d715b59ffdbc67f"}, - {file = "psycopg_binary-3.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:334046a937bb086c36e2c6889fe327f9f29bfc085d678f70fac0b0618949f674"}, + {file = "psycopg_binary-3.2.3-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:48f8ca6ee8939bab760225b2ab82934d54330eec10afe4394a92d3f2a0c37dd6"}, + {file = "psycopg_binary-3.2.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:5361ea13c241d4f0ec3f95e0bf976c15e2e451e9cc7ef2e5ccfc9d170b197a40"}, + {file = "psycopg_binary-3.2.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb987f14af7da7c24f803111dbc7392f5070fd350146af3345103f76ea82e339"}, + {file = "psycopg_binary-3.2.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0463a11b1cace5a6aeffaf167920707b912b8986a9c7920341c75e3686277920"}, + {file = "psycopg_binary-3.2.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8b7be9a6c06518967b641fb15032b1ed682fd3b0443f64078899c61034a0bca6"}, + {file = "psycopg_binary-3.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64a607e630d9f4b2797f641884e52b9f8e239d35943f51bef817a384ec1678fe"}, + {file = "psycopg_binary-3.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:fa33ead69ed133210d96af0c63448b1385df48b9c0247eda735c5896b9e6dbbf"}, + {file = "psycopg_binary-3.2.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:1f8b0d0e99d8e19923e6e07379fa00570be5182c201a8c0b5aaa9a4d4a4ea20b"}, + {file = "psycopg_binary-3.2.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:709447bd7203b0b2debab1acec23123eb80b386f6c29e7604a5d4326a11e5bd6"}, + {file = "psycopg_binary-3.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5e37d5027e297a627da3551a1e962316d0f88ee4ada74c768f6c9234e26346d9"}, + {file = "psycopg_binary-3.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:261f0031ee6074765096a19b27ed0f75498a8338c3dcd7f4f0d831e38adf12d1"}, + {file = "psycopg_binary-3.2.3-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:41fdec0182efac66b27478ac15ef54c9ebcecf0e26ed467eb7d6f262a913318b"}, + {file = "psycopg_binary-3.2.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:07d019a786eb020c0f984691aa1b994cb79430061065a694cf6f94056c603d26"}, + {file = "psycopg_binary-3.2.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c57615791a337378fe5381143259a6c432cdcbb1d3e6428bfb7ce59fff3fb5c"}, + {file = "psycopg_binary-3.2.3-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8eb9a4e394926b93ad919cad1b0a918e9b4c846609e8c1cfb6b743683f64da0"}, + {file = "psycopg_binary-3.2.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5905729668ef1418bd36fbe876322dcb0f90b46811bba96d505af89e6fbdce2f"}, + {file = "psycopg_binary-3.2.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd65774ed7d65101b314808b6893e1a75b7664f680c3ef18d2e5c84d570fa393"}, + {file = "psycopg_binary-3.2.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:700679c02f9348a0d0a2adcd33a0275717cd0d0aee9d4482b47d935023629505"}, + {file = "psycopg_binary-3.2.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:96334bb64d054e36fed346c50c4190bad9d7c586376204f50bede21a913bf942"}, + {file = "psycopg_binary-3.2.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:9099e443d4cc24ac6872e6a05f93205ba1a231b1a8917317b07c9ef2b955f1f4"}, + {file = "psycopg_binary-3.2.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1985ab05e9abebfbdf3163a16ebb37fbc5d49aff2bf5b3d7375ff0920bbb54cd"}, + {file = "psycopg_binary-3.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:e90352d7b610b4693fad0feea48549d4315d10f1eba5605421c92bb834e90170"}, ] [[package]] name = "psycopg" -version = "3.2.1" +version = "3.2.3" extras = ["binary"] requires_python = ">=3.8" summary = "PostgreSQL database adapter for Python" dependencies = [ - "psycopg-binary==3.2.1; implementation_name != \"pypy\"", - "psycopg==3.2.1", + "psycopg-binary==3.2.3; implementation_name != \"pypy\"", + "psycopg==3.2.3", ] files = [ - {file = "psycopg-3.2.1-py3-none-any.whl", hash = "sha256:ece385fb413a37db332f97c49208b36cf030ff02b199d7635ed2fbd378724175"}, - {file = "psycopg-3.2.1.tar.gz", hash = "sha256:dc8da6dc8729dacacda3cc2f17d2c9397a70a66cf0d2b69c91065d60d5f00cb7"}, + {file = "psycopg-3.2.3-py3-none-any.whl", hash = "sha256:644d3973fe26908c73d4be746074f6e5224b03c1101d302d9a53bf565ad64907"}, + {file = "psycopg-3.2.3.tar.gz", hash = "sha256:a5764f67c27bec8bfac85764d23c534af2c27b893550377e37ce59c12aac47a2"}, ] [[package]] @@ -2035,7 +1966,7 @@ files = [ [[package]] name = "pytest" -version = "8.3.2" +version = "8.3.3" requires_python = ">=3.8" summary = "pytest: simple powerful testing with Python" dependencies = [ @@ -2047,8 +1978,8 @@ dependencies = [ "tomli>=1; python_version < \"3.11\"", ] files = [ - {file = "pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5"}, - {file = "pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"}, + {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, + {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, ] [[package]] @@ -2067,15 +1998,15 @@ files = [ [[package]] name = "pytest-django" -version = "4.8.0" +version = "4.9.0" requires_python = ">=3.8" summary = "A Django plugin for pytest." dependencies = [ "pytest>=7.0.0", ] files = [ - {file = "pytest-django-4.8.0.tar.gz", hash = "sha256:5d054fe011c56f3b10f978f41a8efb2e5adfc7e680ef36fb571ada1f24779d90"}, - {file = "pytest_django-4.8.0-py3-none-any.whl", hash = "sha256:ca1ddd1e0e4c227cf9e3e40a6afc6d106b3e70868fd2ac5798a22501271cd0c7"}, + {file = "pytest_django-4.9.0-py3-none-any.whl", hash = "sha256:1d83692cb39188682dbb419ff0393867e9904094a549a7d38a3154d5731b2b99"}, + {file = "pytest_django-4.9.0.tar.gz", hash = "sha256:8bf7bc358c9ae6f6fc51b6cebb190fe20212196e6807121f11bd6a3b03428314"}, ] [[package]] @@ -2091,6 +2022,23 @@ files = [ {file = "pytest_echo-1.7.3-py2.py3-none-any.whl", hash = "sha256:683f4d2fef8dd701aeaf47db834ccc114d43f580abcfea53f3ce2ffe8166c3c0"}, ] +[[package]] +name = "pytest-factoryboy" +version = "2.7.0" +requires_python = ">=3.8" +summary = "Factory Boy support for pytest." +dependencies = [ + "factory-boy>=2.10.0", + "inflection", + "packaging", + "pytest>=6.2", + "typing-extensions", +] +files = [ + {file = "pytest_factoryboy-2.7.0-py3-none-any.whl", hash = "sha256:bf3222db22d954fbf46f4bff902a0a8d82f3fc3594a47c04bbdc0546ff4c59a6"}, + {file = "pytest_factoryboy-2.7.0.tar.gz", hash = "sha256:67fc54ec8669a3feb8ac60094dd57cd71eb0b20b2c319d2957873674c776a77b"}, +] + [[package]] name = "pytest-xdist" version = "3.6.1" @@ -2157,15 +2105,6 @@ version = "6.0.2" requires_python = ">=3.8" summary = "YAML parser and emitter for Python" files = [ - {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, - {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, - {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, - {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, - {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, - {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, @@ -2189,17 +2128,15 @@ files = [ [[package]] name = "redis" -version = "5.0.8" -requires_python = ">=3.7" +version = "5.1.1" +requires_python = ">=3.8" summary = "Python client for Redis database and key-value store" dependencies = [ "async-timeout>=4.0.3; python_full_version < \"3.11.3\"", - "importlib-metadata>=1.0; python_version < \"3.8\"", - "typing-extensions; python_version < \"3.8\"", ] files = [ - {file = "redis-5.0.8-py3-none-any.whl", hash = "sha256:56134ee08ea909106090934adc36f65c9bcbbaecea5b21ba704ba6fb561f8eb4"}, - {file = "redis-5.0.8.tar.gz", hash = "sha256:0c5b10d387568dfe0698c6fad6615750c24170e548ca2deac10c649d463e9870"}, + {file = "redis-5.1.1-py3-none-any.whl", hash = "sha256:f8ea06b7482a668c6475ae202ed8d9bcaa409f6e87fb77ed1043d912afd62e24"}, + {file = "redis-5.1.1.tar.gz", hash = "sha256:f6c997521fedbae53387307c5d0bf784d9acc28d9f1d058abeac566ec4dbed72"}, ] [[package]] @@ -2305,19 +2242,6 @@ version = "0.20.0" requires_python = ">=3.8" summary = "Python bindings to Rust's persistent data structures (rpds)" files = [ - {file = "rpds_py-0.20.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ac2f4f7a98934c2ed6505aead07b979e6f999389f16b714448fb39bbaa86a489"}, - {file = "rpds_py-0.20.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:220002c1b846db9afd83371d08d239fdc865e8f8c5795bbaec20916a76db3318"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d7919548df3f25374a1f5d01fbcd38dacab338ef5f33e044744b5c36729c8db"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:758406267907b3781beee0f0edfe4a179fbd97c0be2e9b1154d7f0a1279cf8e5"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3d61339e9f84a3f0767b1995adfb171a0d00a1185192718a17af6e124728e0f5"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1259c7b3705ac0a0bd38197565a5d603218591d3f6cee6e614e380b6ba61c6f6"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c1dc0f53856b9cc9a0ccca0a7cc61d3d20a7088201c0937f3f4048c1718a209"}, - {file = "rpds_py-0.20.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7e60cb630f674a31f0368ed32b2a6b4331b8350d67de53c0359992444b116dd3"}, - {file = "rpds_py-0.20.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dbe982f38565bb50cb7fb061ebf762c2f254ca3d8c20d4006878766e84266272"}, - {file = "rpds_py-0.20.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:514b3293b64187172bc77c8fb0cdae26981618021053b30d8371c3a902d4d5ad"}, - {file = "rpds_py-0.20.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d0a26ffe9d4dd35e4dfdd1e71f46401cff0181c75ac174711ccff0459135fa58"}, - {file = "rpds_py-0.20.0-cp311-none-win32.whl", hash = "sha256:89c19a494bf3ad08c1da49445cc5d13d8fefc265f48ee7e7556839acdacf69d0"}, - {file = "rpds_py-0.20.0-cp311-none-win_amd64.whl", hash = "sha256:c638144ce971df84650d3ed0096e2ae7af8e62ecbbb7b201c8935c370df00a2c"}, {file = "rpds_py-0.20.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a84ab91cbe7aab97f7446652d0ed37d35b68a465aeef8fc41932a9d7eee2c1a6"}, {file = "rpds_py-0.20.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:56e27147a5a4c2c21633ff8475d185734c0e4befd1c989b5b95a5d0db699b21b"}, {file = "rpds_py-0.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2580b0c34583b85efec8c5c5ec9edf2dfe817330cc882ee972ae650e7b5ef739"}, @@ -2349,7 +2273,7 @@ files = [ [[package]] name = "sentry-sdk" -version = "2.13.0" +version = "2.16.0" requires_python = ">=3.6" summary = "Python client for Sentry (https://sentry.io)" dependencies = [ @@ -2357,18 +2281,18 @@ dependencies = [ "urllib3>=1.26.11", ] files = [ - {file = "sentry_sdk-2.13.0-py2.py3-none-any.whl", hash = "sha256:6beede8fc2ab4043da7f69d95534e320944690680dd9a963178a49de71d726c6"}, - {file = "sentry_sdk-2.13.0.tar.gz", hash = "sha256:8d4a576f7a98eb2fdb40e13106e41f330e5c79d72a68be1316e7852cf4995260"}, + {file = "sentry_sdk-2.16.0-py2.py3-none-any.whl", hash = "sha256:49139c31ebcd398f4f6396b18910610a0c1602f6e67083240c33019d1f6aa30c"}, + {file = "sentry_sdk-2.16.0.tar.gz", hash = "sha256:90f733b32e15dfc1999e6b7aca67a38688a567329de4d6e184154a73f96c6892"}, ] [[package]] name = "setuptools" -version = "72.2.0" +version = "75.1.0" requires_python = ">=3.8" summary = "Easily download, build, install, upgrade, and uninstall Python packages" files = [ - {file = "setuptools-72.2.0-py3-none-any.whl", hash = "sha256:f11dd94b7bae3a156a95ec151f24e4637fb4fa19c878e4d191bfb8b2d82728c4"}, - {file = "setuptools-72.2.0.tar.gz", hash = "sha256:80aacbf633704e9c8bfa1d99fa5dd4dc59573efcf9e4042c13d3bcef91ac2ef9"}, + {file = "setuptools-75.1.0-py3-none-any.whl", hash = "sha256:35ab7fd3bcd95e6b7fd704e4a1539513edad446c097797f2985e0e4b960772f2"}, + {file = "setuptools-75.1.0.tar.gz", hash = "sha256:d59a21b17a275fb872a9c3dae73963160ae079f1049ed956880cd7c09b120538"}, ] [[package]] @@ -2377,19 +2301,6 @@ version = "3.19.3" requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.5" summary = "Simple, fast, extensible JSON encoder/decoder for Python" files = [ - {file = "simplejson-3.19.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e88abff510dcff903a18d11c2a75f9964e768d99c8d147839913886144b2065e"}, - {file = "simplejson-3.19.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:934a50a614fb831614db5dbfba35127ee277624dda4d15895c957d2f5d48610c"}, - {file = "simplejson-3.19.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:212fce86a22188b0c7f53533b0f693ea9605c1a0f02c84c475a30616f55a744d"}, - {file = "simplejson-3.19.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d9e8f836688a8fabe6a6b41b334aa550a6823f7b4ac3d3712fc0ad8655be9a8"}, - {file = "simplejson-3.19.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23228037dc5d41c36666384062904d74409a62f52283d9858fa12f4c22cffad1"}, - {file = "simplejson-3.19.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0791f64fed7d4abad639491f8a6b1ba56d3c604eb94b50f8697359b92d983f36"}, - {file = "simplejson-3.19.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4f614581b61a26fbbba232a1391f6cee82bc26f2abbb6a0b44a9bba25c56a1c"}, - {file = "simplejson-3.19.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1df0aaf1cb787fdf34484ed4a1f0c545efd8811f6028623290fef1a53694e597"}, - {file = "simplejson-3.19.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:951095be8d4451a7182403354c22ec2de3e513e0cc40408b689af08d02611588"}, - {file = "simplejson-3.19.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:2a954b30810988feeabde843e3263bf187697e0eb5037396276db3612434049b"}, - {file = "simplejson-3.19.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c40df31a75de98db2cdfead6074d4449cd009e79f54c1ebe5e5f1f153c68ad20"}, - {file = "simplejson-3.19.3-cp311-cp311-win32.whl", hash = "sha256:7e2a098c21ad8924076a12b6c178965d88a0ad75d1de67e1afa0a66878f277a5"}, - {file = "simplejson-3.19.3-cp311-cp311-win_amd64.whl", hash = "sha256:c9bedebdc5fdad48af8783022bae307746d54006b783007d1d3c38e10872a2c6"}, {file = "simplejson-3.19.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:66a0399e21c2112acacfebf3d832ebe2884f823b1c7e6d1363f2944f1db31a99"}, {file = "simplejson-3.19.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6ef9383c5e05f445be60f1735c1816163c874c0b1ede8bb4390aff2ced34f333"}, {file = "simplejson-3.19.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:42e5acf80d4d971238d4df97811286a044d720693092b20a56d5e56b7dcc5d09"}, @@ -2430,20 +2341,6 @@ files = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] -[[package]] -name = "snapshottest" -version = "0.6.0" -summary = "Snapshot testing for pytest, unittest, Django, and Nose" -dependencies = [ - "fastdiff<1,>=0.1.4", - "six>=1.10.0", - "termcolor", -] -files = [ - {file = "snapshottest-0.6.0-py2.py3-none-any.whl", hash = "sha256:9b177cffe0870c589df8ddbee0a770149c5474b251955bdbde58b7f32a4ec429"}, - {file = "snapshottest-0.6.0.tar.gz", hash = "sha256:bbcaf81d92d8e330042e5c928e13d9f035e99e91b314fe55fda949c2f17b653c"}, -] - [[package]] name = "social-auth-app-django" version = "5.4.2" @@ -2538,16 +2435,6 @@ files = [ {file = "tablib-3.5.0.tar.gz", hash = "sha256:f6661dfc45e1d4f51fa8a6239f9c8349380859a5bfaa73280645f046d6c96e33"}, ] -[[package]] -name = "termcolor" -version = "2.4.0" -requires_python = ">=3.8" -summary = "ANSI color formatting for output in terminal" -files = [ - {file = "termcolor-2.4.0-py3-none-any.whl", hash = "sha256:9297c0df9c99445c2412e832e882a7884038a25617c60cea2ad69488d4040d63"}, - {file = "termcolor-2.4.0.tar.gz", hash = "sha256:aab9e56047c8ac41ed798fa36d892a37aca6b3e9159f3e0c24bc64a9b3ac7b7a"}, -] - [[package]] name = "tornado" version = "6.4.1" @@ -2615,27 +2502,27 @@ files = [ [[package]] name = "types-python-dateutil" -version = "2.9.0.20240316" +version = "2.9.0.20241003" requires_python = ">=3.8" summary = "Typing stubs for python-dateutil" files = [ - {file = "types-python-dateutil-2.9.0.20240316.tar.gz", hash = "sha256:5d2f2e240b86905e40944dd787db6da9263f0deabef1076ddaed797351ec0202"}, - {file = "types_python_dateutil-2.9.0.20240316-py3-none-any.whl", hash = "sha256:6b8cb66d960771ce5ff974e9dd45e38facb81718cc1e208b10b1baccbfdbee3b"}, + {file = "types-python-dateutil-2.9.0.20241003.tar.gz", hash = "sha256:58cb85449b2a56d6684e41aeefb4c4280631246a0da1a719bdbe6f3fb0317446"}, + {file = "types_python_dateutil-2.9.0.20241003-py3-none-any.whl", hash = "sha256:250e1d8e80e7bbc3a6c99b907762711d1a1cdd00e978ad39cb5940f6f0a87f3d"}, ] [[package]] name = "types-pytz" -version = "2024.1.0.20240417" +version = "2024.2.0.20241003" requires_python = ">=3.8" summary = "Typing stubs for pytz" files = [ - {file = "types-pytz-2024.1.0.20240417.tar.gz", hash = "sha256:6810c8a1f68f21fdf0f4f374a432487c77645a0ac0b31de4bf4690cf21ad3981"}, - {file = "types_pytz-2024.1.0.20240417-py3-none-any.whl", hash = "sha256:8335d443310e2db7b74e007414e74c4f53b67452c0cb0d228ca359ccfba59659"}, + {file = "types-pytz-2024.2.0.20241003.tar.gz", hash = "sha256:575dc38f385a922a212bac00a7d6d2e16e141132a3c955078f4a4fd13ed6cb44"}, + {file = "types_pytz-2024.2.0.20241003-py3-none-any.whl", hash = "sha256:3e22df1336c0c6ad1d29163c8fda82736909eb977281cb823c57f8bae07118b7"}, ] [[package]] name = "types-redis" -version = "4.6.0.20240806" +version = "4.6.0.20241004" requires_python = ">=3.8" summary = "Typing stubs for redis" dependencies = [ @@ -2643,31 +2530,31 @@ dependencies = [ "types-pyOpenSSL", ] files = [ - {file = "types-redis-4.6.0.20240806.tar.gz", hash = "sha256:60dd02c2b91ea2d42ad079ac58dedc31d71d6eedb1c21d3796811b02baac655d"}, - {file = "types_redis-4.6.0.20240806-py3-none-any.whl", hash = "sha256:9d8fbe0ce37e3660c0a06982db7812384295d10a93d637c7f8604a2f3c88b0e6"}, + {file = "types-redis-4.6.0.20241004.tar.gz", hash = "sha256:5f17d2b3f9091ab75384153bfa276619ffa1cf6a38da60e10d5e6749cc5b902e"}, + {file = "types_redis-4.6.0.20241004-py3-none-any.whl", hash = "sha256:ef5da68cb827e5f606c8f9c0b49eeee4c2669d6d97122f301d3a55dc6a63f6ed"}, ] [[package]] name = "types-requests" -version = "2.32.0.20240712" +version = "2.32.0.20240914" requires_python = ">=3.8" summary = "Typing stubs for requests" dependencies = [ "urllib3>=2", ] files = [ - {file = "types-requests-2.32.0.20240712.tar.gz", hash = "sha256:90c079ff05e549f6bf50e02e910210b98b8ff1ebdd18e19c873cd237737c1358"}, - {file = "types_requests-2.32.0.20240712-py3-none-any.whl", hash = "sha256:f754283e152c752e46e70942fa2a146b5bc70393522257bb85bd1ef7e019dcc3"}, + {file = "types-requests-2.32.0.20240914.tar.gz", hash = "sha256:2850e178db3919d9bf809e434eef65ba49d0e7e33ac92d588f4a5e295fffd405"}, + {file = "types_requests-2.32.0.20240914-py3-none-any.whl", hash = "sha256:59c2f673eb55f32a99b2894faf6020e1a9f4a402ad0f192bfee0b64469054310"}, ] [[package]] name = "types-setuptools" -version = "71.1.0.20240813" +version = "75.1.0.20240917" requires_python = ">=3.8" summary = "Typing stubs for setuptools" files = [ - {file = "types-setuptools-71.1.0.20240813.tar.gz", hash = "sha256:94ff4f0af18c7c24ac88932bcb0f5655fb7187a001b7c61e53a1bfdaf9877b54"}, - {file = "types_setuptools-71.1.0.20240813-py3-none-any.whl", hash = "sha256:d9d9ba2936f5d3b47b59ae9bf65942a60063ac1d6bbee180a8a79fbb43f22ce5"}, + {file = "types-setuptools-75.1.0.20240917.tar.gz", hash = "sha256:12f12a165e7ed383f31def705e5c0fa1c26215dd466b0af34bd042f7d5331f55"}, + {file = "types_setuptools-75.1.0.20240917-py3-none-any.whl", hash = "sha256:06f78307e68d1bbde6938072c57b81cf8a99bc84bd6dc7e4c5014730b097dc0c"}, ] [[package]] @@ -2682,12 +2569,12 @@ files = [ [[package]] name = "tzdata" -version = "2024.1" +version = "2024.2" requires_python = ">=2" summary = "Provider of IANA time zone data" files = [ - {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, - {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, + {file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"}, + {file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"}, ] [[package]] @@ -2764,20 +2651,20 @@ files = [ [[package]] name = "urllib3" -version = "2.2.2" +version = "2.2.3" requires_python = ">=3.8" summary = "HTTP library with thread-safe connection pooling, file post, and more." files = [ - {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, - {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, + {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, + {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, ] [[package]] name = "uwsgi" -version = "2.0.26" +version = "2.0.27" summary = "The uWSGI server" files = [ - {file = "uwsgi-2.0.26.tar.gz", hash = "sha256:86e6bfcd4dc20529665f5b7777193cdc48622fb2c59f0a7f1e3dc32b3882e7f9"}, + {file = "uwsgi-2.0.27.tar.gz", hash = "sha256:3ee5bfb7e6e9c93478c22aa8183eef35b95a2d5b14cca16172e67f135565c458"}, ] [[package]] @@ -2792,7 +2679,7 @@ files = [ [[package]] name = "virtualenv" -version = "20.26.3" +version = "20.26.6" requires_python = ">=3.7" summary = "Virtual Python Environment builder" dependencies = [ @@ -2802,8 +2689,8 @@ dependencies = [ "platformdirs<5,>=3.9.1", ] files = [ - {file = "virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589"}, - {file = "virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a"}, + {file = "virtualenv-20.26.6-py3-none-any.whl", hash = "sha256:7345cc5b25405607a624d8418154577459c3e0277f5466dd79c49d5e492995f2"}, + {file = "virtualenv-20.26.6.tar.gz", hash = "sha256:280aede09a2a5c317e409a00102e7077c6432c5a38f0ef938e643805a7ad2c48"}, ] [[package]] @@ -2816,48 +2703,29 @@ files = [ {file = "waitress-3.0.0.tar.gz", hash = "sha256:005da479b04134cdd9dd602d1ee7c49d79de0537610d653674cc6cbde222b8a1"}, ] -[[package]] -name = "wasmer" -version = "1.1.0" -summary = "Python extension to run WebAssembly binaries" -files = [ - {file = "wasmer-1.1.0-py3-none-any.whl", hash = "sha256:2caf8c67feae9cd4246421551036917811c446da4f27ad4c989521ef42751931"}, -] - -[[package]] -name = "wasmer-compiler-cranelift" -version = "1.1.0" -summary = "Python extension to run WebAssembly binaries" -files = [ - {file = "wasmer_compiler_cranelift-1.1.0-py3-none-any.whl", hash = "sha256:200fea80609cfb088457327acf66d5aa61f4c4f66b5a71133ada960b534c7355"}, -] - [[package]] name = "watchdog" -version = "4.0.2" -requires_python = ">=3.8" +version = "5.0.3" +requires_python = ">=3.9" summary = "Filesystem events monitoring" files = [ - {file = "watchdog-4.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7c7d4bf585ad501c5f6c980e7be9c4f15604c7cc150e942d82083b31a7548930"}, - {file = "watchdog-4.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:914285126ad0b6eb2258bbbcb7b288d9dfd655ae88fa28945be05a7b475a800b"}, - {file = "watchdog-4.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:984306dc4720da5498b16fc037b36ac443816125a3705dfde4fd90652d8028ef"}, - {file = "watchdog-4.0.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1cdcfd8142f604630deef34722d695fb455d04ab7cfe9963055df1fc69e6727a"}, - {file = "watchdog-4.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d7ab624ff2f663f98cd03c8b7eedc09375a911794dfea6bf2a359fcc266bff29"}, - {file = "watchdog-4.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:132937547a716027bd5714383dfc40dc66c26769f1ce8a72a859d6a48f371f3a"}, - {file = "watchdog-4.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:cd67c7df93eb58f360c43802acc945fa8da70c675b6fa37a241e17ca698ca49b"}, - {file = "watchdog-4.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bcfd02377be80ef3b6bc4ce481ef3959640458d6feaae0bd43dd90a43da90a7d"}, - {file = "watchdog-4.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:980b71510f59c884d684b3663d46e7a14b457c9611c481e5cef08f4dd022eed7"}, - {file = "watchdog-4.0.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:936acba76d636f70db8f3c66e76aa6cb5136a936fc2a5088b9ce1c7a3508fc83"}, - {file = "watchdog-4.0.2-py3-none-manylinux2014_armv7l.whl", hash = "sha256:e252f8ca942a870f38cf785aef420285431311652d871409a64e2a0a52a2174c"}, - {file = "watchdog-4.0.2-py3-none-manylinux2014_i686.whl", hash = "sha256:0e83619a2d5d436a7e58a1aea957a3c1ccbf9782c43c0b4fed80580e5e4acd1a"}, - {file = "watchdog-4.0.2-py3-none-manylinux2014_ppc64.whl", hash = "sha256:88456d65f207b39f1981bf772e473799fcdc10801062c36fd5ad9f9d1d463a73"}, - {file = "watchdog-4.0.2-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:32be97f3b75693a93c683787a87a0dc8db98bb84701539954eef991fb35f5fbc"}, - {file = "watchdog-4.0.2-py3-none-manylinux2014_s390x.whl", hash = "sha256:c82253cfc9be68e3e49282831afad2c1f6593af80c0daf1287f6a92657986757"}, - {file = "watchdog-4.0.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:c0b14488bd336c5b1845cee83d3e631a1f8b4e9c5091ec539406e4a324f882d8"}, - {file = "watchdog-4.0.2-py3-none-win32.whl", hash = "sha256:0d8a7e523ef03757a5aa29f591437d64d0d894635f8a50f370fe37f913ce4e19"}, - {file = "watchdog-4.0.2-py3-none-win_amd64.whl", hash = "sha256:c344453ef3bf875a535b0488e3ad28e341adbd5a9ffb0f7d62cefacc8824ef2b"}, - {file = "watchdog-4.0.2-py3-none-win_ia64.whl", hash = "sha256:baececaa8edff42cd16558a639a9b0ddf425f93d892e8392a56bf904f5eff22c"}, - {file = "watchdog-4.0.2.tar.gz", hash = "sha256:b4dfbb6c49221be4535623ea4474a4d6ee0a9cef4a80b20c28db4d858b64e270"}, + {file = "watchdog-5.0.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:94d11b07c64f63f49876e0ab8042ae034674c8653bfcdaa8c4b32e71cfff87e8"}, + {file = "watchdog-5.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:349c9488e1d85d0a58e8cb14222d2c51cbc801ce11ac3936ab4c3af986536926"}, + {file = "watchdog-5.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:53a3f10b62c2d569e260f96e8d966463dec1a50fa4f1b22aec69e3f91025060e"}, + {file = "watchdog-5.0.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:950f531ec6e03696a2414b6308f5c6ff9dab7821a768c9d5788b1314e9a46ca7"}, + {file = "watchdog-5.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ae6deb336cba5d71476caa029ceb6e88047fc1dc74b62b7c4012639c0b563906"}, + {file = "watchdog-5.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1021223c08ba8d2d38d71ec1704496471ffd7be42cfb26b87cd5059323a389a1"}, + {file = "watchdog-5.0.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:dd021efa85970bd4824acacbb922066159d0f9e546389a4743d56919b6758b91"}, + {file = "watchdog-5.0.3-py3-none-manylinux2014_armv7l.whl", hash = "sha256:78864cc8f23dbee55be34cc1494632a7ba30263951b5b2e8fc8286b95845f82c"}, + {file = "watchdog-5.0.3-py3-none-manylinux2014_i686.whl", hash = "sha256:1e9679245e3ea6498494b3028b90c7b25dbb2abe65c7d07423ecfc2d6218ff7c"}, + {file = "watchdog-5.0.3-py3-none-manylinux2014_ppc64.whl", hash = "sha256:9413384f26b5d050b6978e6fcd0c1e7f0539be7a4f1a885061473c5deaa57221"}, + {file = "watchdog-5.0.3-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:294b7a598974b8e2c6123d19ef15de9abcd282b0fbbdbc4d23dfa812959a9e05"}, + {file = "watchdog-5.0.3-py3-none-manylinux2014_s390x.whl", hash = "sha256:26dd201857d702bdf9d78c273cafcab5871dd29343748524695cecffa44a8d97"}, + {file = "watchdog-5.0.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:0f9332243355643d567697c3e3fa07330a1d1abf981611654a1f2bf2175612b7"}, + {file = "watchdog-5.0.3-py3-none-win32.whl", hash = "sha256:c66f80ee5b602a9c7ab66e3c9f36026590a0902db3aea414d59a2f55188c1f49"}, + {file = "watchdog-5.0.3-py3-none-win_amd64.whl", hash = "sha256:f00b4cf737f568be9665563347a910f8bdc76f88c2970121c86243c8cfdf90e9"}, + {file = "watchdog-5.0.3-py3-none-win_ia64.whl", hash = "sha256:49f4d36cb315c25ea0d946e018c01bb028048023b9e103d3d3943f58e109dd45"}, + {file = "watchdog-5.0.3.tar.gz", hash = "sha256:108f42a7f0345042a854d4d0ad0834b741d421330d5f575b81cb27b883500176"}, ] [[package]] @@ -2884,8 +2752,8 @@ files = [ [[package]] name = "webtest" -version = "3.0.0" -requires_python = ">=3.6, <4" +version = "3.0.1" +requires_python = ">=3.7" summary = "Helper to test WSGI applications" dependencies = [ "WebOb>=1.2", @@ -2893,8 +2761,8 @@ dependencies = [ "waitress>=0.8.5", ] files = [ - {file = "WebTest-3.0.0-py3-none-any.whl", hash = "sha256:2a001a9efa40d2a7e5d9cd8d1527c75f41814eb6afce2c3d207402547b1e5ead"}, - {file = "WebTest-3.0.0.tar.gz", hash = "sha256:54bd969725838d9861a9fa27f8d971f79d275d94ae255f5c501f53bb6d9929eb"}, + {file = "WebTest-3.0.1-py3-none-any.whl", hash = "sha256:b3bc75d020d0576ee93a5f149666045e58fe2400ea5f0c214d7430d7d213d0d0"}, + {file = "webtest-3.0.1.tar.gz", hash = "sha256:493b5c802f8948a65b5e3a1ad5b2524ee5e1ab60cd713d9a3da3b8da082c06fe"}, ] [[package]] diff --git a/pyproject.toml b/pyproject.toml index bb47575..4d6e9df 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,8 +36,10 @@ includes = [] dev = [ "argh", "black", + "django-regex", "django-webtest", "drf-api-checker", + "factory-boy", "faker", "flake8", "flake8-bugbear", @@ -50,14 +52,15 @@ dev = [ "openpyxl-stubs", "parameterized", "parso", + "pre-commit", "pytest", "pytest-cov", "pytest-django", "pytest-echo", + "pytest-factoryboy", "pytest-xdist", "requests-mock", "responses", - "snapshottest", "types-freezegun", "types-requests", "types-python-dateutil", @@ -71,7 +74,7 @@ authors = [ {name = "ddinicola"}, {name = "Domenico DiNicola", email = "dom.dinicola@gmail.com"}, ] -requires-python = ">=3.11" +requires-python = ">=3.12" dependencies = [ "Django", "celery[redis]", @@ -96,18 +99,18 @@ dependencies = [ "django-model-utils", "django-mptt", "django-smart-admin", + "django-smart-env", "django-storages[azure]", "django-strategy-field", "django-viewflow", "dj-static", "drf-spectacular[sidecar]", - "factory-boy", + "flower", "gunicorn", "newrelic", "natural-keys", "paramiko", "phonenumbers", - "pre-commit", "psycopg[binary]", "sentry-sdk", "social-auth-app-django", @@ -119,7 +122,6 @@ dependencies = [ "wheel", "uwsgi", "zeep", - "flower>=2.0.1", ] name = "hope_payment_gateway" version = "0.1" diff --git a/src/hope_payment_gateway/api/fsp/filters.py b/src/hope_payment_gateway/api/fsp/filters.py index d5f3087..d46bbfd 100644 --- a/src/hope_payment_gateway/api/fsp/filters.py +++ b/src/hope_payment_gateway/api/fsp/filters.py @@ -27,7 +27,7 @@ class Meta: fields = { "remote_id": ["exact"], "name": ["exact"], - "vision_vendor_number": ["exact"], + "vendor_number": ["exact"], } diff --git a/src/hope_payment_gateway/api/fsp/serializers.py b/src/hope_payment_gateway/api/fsp/serializers.py index 87e8c93..f51a0c9 100644 --- a/src/hope_payment_gateway/api/fsp/serializers.py +++ b/src/hope_payment_gateway/api/fsp/serializers.py @@ -46,10 +46,20 @@ class Meta: class FinancialServiceProviderConfigNestedSerializer(serializers.ModelSerializer): delivery_mechanism_name = serializers.CharField(source="delivery_mechanism.name", allow_null=True) + delivery_mechanism_code = serializers.CharField(source="delivery_mechanism.code", allow_null=True) + delivery_mechanism_transfer_type = serializers.CharField(source="delivery_mechanism.transfer_type", allow_null=True) class Meta: model = FinancialServiceProviderConfig - fields = ("id", "key", "label", "delivery_mechanism", "delivery_mechanism_name") + fields = ( + "id", + "key", + "label", + "delivery_mechanism", + "delivery_mechanism_name", + "delivery_mechanism_transfer_type", + "delivery_mechanism_code", + ) class FinancialServiceProviderLightSerializer(PayloadMixin, serializers.ModelSerializer): @@ -58,7 +68,7 @@ class Meta: fields = ( "id", "name", - "vision_vendor_number", + "vendor_number", ) @@ -71,7 +81,7 @@ class Meta: "id", "remote_id", "name", - "vision_vendor_number", + "vendor_number", "configs", ) diff --git a/src/hope_payment_gateway/api/fsp/views.py b/src/hope_payment_gateway/api/fsp/views.py index 85c09e4..4d433cd 100644 --- a/src/hope_payment_gateway/api/fsp/views.py +++ b/src/hope_payment_gateway/api/fsp/views.py @@ -56,7 +56,7 @@ class FinancialServiceProviderViewSet(ProtectedMixin, LoggingAPIViewSet): queryset = FinancialServiceProvider.objects.prefetch_related("configs") filterset_class = FinancialServiceProviderFilter - search_fields = ["name", "vision_vendor_number", "remote_id"] + search_fields = ["name", "vendor_number", "remote_id"] class ConfigurationViewSet(ProtectedMixin, LoggingAPIViewSet): diff --git a/src/hope_payment_gateway/api/urls.py b/src/hope_payment_gateway/api/urls.py index 4aee38a..8d4198b 100644 --- a/src/hope_payment_gateway/api/urls.py +++ b/src/hope_payment_gateway/api/urls.py @@ -17,5 +17,7 @@ router.register(r"wu/corridors", wu_views.CorridorViewSet, basename="wu-corridor") router.register(r"wu/provider_code", wu_views.ServiceProviderCodeViewSet, basename="wu-service-provider-code") +router.register(r"wu/files", wu_views.FileViewset, basename="wu-files") + urlpatterns = router.urls diff --git a/src/hope_payment_gateway/api/western_union/serializers.py b/src/hope_payment_gateway/api/western_union/serializers.py index 6f0dc89..548cfb0 100644 --- a/src/hope_payment_gateway/api/western_union/serializers.py +++ b/src/hope_payment_gateway/api/western_union/serializers.py @@ -1,4 +1,5 @@ from rest_framework import serializers +from rest_framework.serializers import Serializer from hope_payment_gateway.apps.fsp.western_union.models import Corridor, ServiceProviderCode @@ -13,3 +14,15 @@ class ServiceProviderCodeSerializer(serializers.ModelSerializer): class Meta: model = ServiceProviderCode fields = ("description", "code", "country", "currency") + + +class FileSerializer(Serializer): + name = serializers.SerializerMethodField() + url = serializers.SerializerMethodField() + + def get_name(self, obj): + return str(obj) + + def get_url(self, obj): + request = self.context.get("request") + return request.build_absolute_uri(str(obj)) diff --git a/src/hope_payment_gateway/api/western_union/views.py b/src/hope_payment_gateway/api/western_union/views.py index 1b760f8..d862f55 100644 --- a/src/hope_payment_gateway/api/western_union/views.py +++ b/src/hope_payment_gateway/api/western_union/views.py @@ -1,8 +1,16 @@ -from rest_framework.viewsets import ModelViewSet +from django.http import FileResponse + +from rest_framework.response import Response +from rest_framework.viewsets import ModelViewSet, ViewSet from hope_payment_gateway.api.western_union.filters import CorridorFilter, ServiceProviderCodeFilter -from hope_payment_gateway.api.western_union.serializers import CorridorSerializer, ServiceProviderCodeSerializer +from hope_payment_gateway.api.western_union.serializers import ( + CorridorSerializer, + FileSerializer, + ServiceProviderCodeSerializer, +) from hope_payment_gateway.apps.fsp.western_union.models import Corridor, ServiceProviderCode +from hope_payment_gateway.libs.ftp import FTPClient class ProtectedMixin: @@ -24,3 +32,22 @@ class ServiceProviderCodeViewSet(ProtectedMixin, ModelViewSet): filterset_class = ServiceProviderCodeFilter search_fields = ["description", "code"] + + +class FileViewset(ViewSet): + serializer_class = FileSerializer + filter_backends = list() + lookup_field = "filename" + lookup_value_regex = r"[\w.;_@]+" + + def get_queryset(self): + return FTPClient().ls() + + def list(self, request): + serializer = self.serializer_class(instance=FTPClient().ls(), many=True, context={"request": request}) + return Response(serializer.data) + + def retrieve(self, request, filename=None): + response = FileResponse(FTPClient().download(filename)) + response["Content-Disposition"] = 'attachment; filename="%s"' % filename + return response diff --git a/src/hope_payment_gateway/apps/core/admin.py b/src/hope_payment_gateway/apps/core/admin.py index e12fe83..a1f604b 100644 --- a/src/hope_payment_gateway/apps/core/admin.py +++ b/src/hope_payment_gateway/apps/core/admin.py @@ -4,6 +4,8 @@ from hope_payment_gateway.apps.core.models import System, User +admin.site.site_header = "Payment Gateway" + @admin.register(User) class UserAdminPlus(UserAdminPlus): diff --git a/src/hope_payment_gateway/apps/core/models.py b/src/hope_payment_gateway/apps/core/models.py index 0778dbb..3b0e6b6 100644 --- a/src/hope_payment_gateway/apps/core/models.py +++ b/src/hope_payment_gateway/apps/core/models.py @@ -4,6 +4,15 @@ from unicef_security.models import AbstractUser, SecurityMixin +class Singleton(type): + _instances = {} + + def __call__(cls, *args, **kwargs): + if cls not in cls._instances: + cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) + return cls._instances[cls] + + class User(SecurityMixin, AbstractUser): class Meta: app_label = "core" diff --git a/src/hope_payment_gateway/apps/core/storage.py b/src/hope_payment_gateway/apps/core/storage.py deleted file mode 100644 index 3d4a804..0000000 --- a/src/hope_payment_gateway/apps/core/storage.py +++ /dev/null @@ -1,50 +0,0 @@ -import os -from typing import Any - -from django.core.files.storage import FileSystemStorage - -from storages.backends.azure_storage import AzureStorage - - -class DataSetStorage(FileSystemStorage): - def get_available_name(self, name: str, max_length: int | None = None) -> str: - if self.exists(name): - self.delete(name) - return name - - def save(self, name: str, content: Any, max_length: int | None = None) -> None: - raise RuntimeError("This storage cannot save files") - - def delete(self, name: str) -> None: - raise RuntimeError("This storage cannot delete files") - - def open(self, name: str, mode: str = "rb") -> Any: - if "w" in mode: - raise RuntimeError("This storage cannot open files in write mode") - return super().open(name, mode="rb") - - -class SettingsStorage(AzureStorage): - prefix = "" - - def get_default_settings(self): - base = super().get_default_settings() - for k, _ in base.items(): - if value := os.getenv(f"{self.prefix}_AZURE_{k.upper()}", None): - base[k] = value - return base - - -class UniqueStorageMixin: - def get_available_name(self, name: str, max_length: int | None = None) -> str: - if self.exists(name): - self.delete(name) - return name - - -class MediaStorage(UniqueStorageMixin, SettingsStorage): - prefix = "MEDIA" - - -class StaticStorage(UniqueStorageMixin, SettingsStorage): - prefix = "STATIC" diff --git a/src/hope_payment_gateway/apps/core/templates/request.html b/src/hope_payment_gateway/apps/core/templates/request.html new file mode 100644 index 0000000..29d3fb2 --- /dev/null +++ b/src/hope_payment_gateway/apps/core/templates/request.html @@ -0,0 +1,19 @@ +{% extends "admin_extra_buttons/action_page.html" %} +{% load static %} + +{% block content %} + + {% autoescape on %} + {{ msg | linebreaksbr }} + {% endautoescape %} + + +
+        {% if format == "json" %}
+            {{ content | pprint }}
+        {% else %}
+            {{ content }}
+        {% endif %}
+    
+ +{% endblock %} diff --git a/src/hope_payment_gateway/apps/fsp/moneygram/__init__.py b/src/hope_payment_gateway/apps/fsp/moneygram/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/hope_payment_gateway/apps/fsp/moneygram/client.py b/src/hope_payment_gateway/apps/fsp/moneygram/client.py new file mode 100644 index 0000000..b388c23 --- /dev/null +++ b/src/hope_payment_gateway/apps/fsp/moneygram/client.py @@ -0,0 +1,181 @@ +import base64 +import json +import logging + +from django.conf import settings + +import phonenumbers +import requests +from phonenumbers import NumberParseException +from urllib3.connectionpool import HTTPSConnectionPool + +from hope_payment_gateway.apps.core.models import Singleton +from hope_payment_gateway.apps.gateway.flows import PaymentRecordFlow +from hope_payment_gateway.apps.gateway.models import PaymentRecord + +logger = logging.getLogger(__name__) + + +MONEYGRAM_DM_MAPPING = { + "WILL_CALL": "WILL_CALL", + "DIRECT_TO_ACCT": "DIRECT_TO_ACCT", + "BANK_DEPOSIT": "DIRECT_TO_ACCT", +} + + +class PayloadMissingKey(Exception): + pass + + +class MoneyGramClient(metaclass=Singleton): + token = "" + expires_in = None + token_response = None + + def __init__(self): + self.get_token() + + def get_token(self): + url = settings.MONEYGRAM_HOST + "/oauth/accesstoken?grant_type=client_credentials" + credentials = f"{settings.MONEYGRAM_CLIENT_ID}:{settings.MONEYGRAM_CLIENT_SECRET}" + encoded_credentials = base64.b64encode(credentials.encode("utf-8")).decode("utf-8") + headers = {"Content-Type": "application/json", "Authorization": "Basic " + encoded_credentials} + + try: + response = requests.get(url, headers=headers) + except HTTPSConnectionPool: + self.token = None + self.token_response = None + else: + if response.status_code == 200: + parsed_response = json.loads(response.text) + self.token = parsed_response["access_token"] + self.expires_in = parsed_response["expires_in"] + else: + logger.warning("Invalid token") + self.token = None + self.token_response = response + + def prepare_transaction(self, hope_payload): + + raw_phone_no = hope_payload.get("phone_no", "N/A") + try: + phone_no = phonenumbers.parse(raw_phone_no, None) + phone_number = phone_no.national_number + country_code = phone_no.country_code + except NumberParseException: + phone_number = raw_phone_no + country_code = None + + for key in [ + "first_name", + "last_name", + "amount", + "destination_country", + "destination_currency", + "payment_record_code", + ]: + if not (key in hope_payload.keys() and hope_payload[key]): + raise PayloadMissingKey("InvalidPayload: {} is missing in the payload".format(key)) + + return { + "targetAudience": "AGENT_FACING", + "agentPartnerId": settings.MONEYGRAM_PARTNER_ID, + "userLanguage": "en-US", + "destinationCountryCode": hope_payload["destination_country"], + # "destinationCountrySubdivisionCode": "US-NY", + "receiveCurrencyCode": hope_payload["destination_currency"], + "serviceOptionCode": hope_payload.get("delivery_services_code", "WILL_CALL"), + # "serviceOptionRoutingCode": "74261037", # TODO + "autoCommit": "true", + "sendAmount": {"currencyCode": hope_payload["origination_currency"], "value": hope_payload["amount"]}, + "sender": { + "business": { + "businessName": "UNICEF", + "legalEntityName": "UNICEF", + "businessType": "ACCOMMODATION_HOTELS", + "businessRegistrationNumber": settings.MONEYGRAM_REGISTRATION_NUMBER, + "businessIssueDate": "2024-04-29", + "businessCountryOfRegistration": "USA", + "address": { + "line1": "3 United Nations Plaza", + "city": "NEW YORK", + "countrySubdivisionCode": "US-NY", + "countryCode": "USA", + "postalCode": 10017, + }, + "contactDetails": {"phone": {"number": 2123267000, "countryDialCode": 1}}, + } + }, + "beneficiary": { + "consumer": { + "name": { + "firstName": hope_payload["first_name"], + "middleName": hope_payload.get("middle_name", ""), + "lastName": hope_payload["last_name"], + }, + "address": { + "line1": hope_payload.get("address", "Via di Acilia"), + "city": hope_payload.get("city", "Roma"), + "countryCode": hope_payload["destination_country"], + "postalCode": 55442, + }, + "mobilePhone": {"number": phone_number, "countryDialCode": country_code}, + } + }, + } + + def create_transaction(self, hope_payload): + + if self.token: + + url = settings.MONEYGRAM_HOST + "/disbursement/v1/transactions" + payload = self.prepare_transaction(hope_payload) + headers = { + "Content-Type": "application/json", + "X-MG-ClientRequestId": hope_payload["payment_record_code"], + "Authorization": "Bearer " + self.token, + } + + response = self.perform_request(url, headers, payload) + self.transaction_callback(hope_payload, response.json()) + return response + + else: + return self.token_response + + def perform_request(self, url, headers, payload=None): + try: + response = requests.post(url, json=payload, headers=headers) + + if response.status_code == 200: + parsed_response = json.dumps(json.loads(response.text), indent=2) + print(parsed_response) + else: + print("Request failed with status code:", response.status_code) + print(json.dumps(json.loads(response.text), indent=2)) + + except (requests.exceptions.RequestException, requests.exceptions.MissingSchema) as e: + print("An error occurred:", e) + response = dict + + return response + + def transaction_callback(self, hope_payload, response): + record_code = hope_payload["payment_record_code"] + pr = PaymentRecord.objects.get(record_code=record_code) + pr.fsp_code = response["referenceNumber"] + pr.success = True + pr.payout_amount = response["receiveAmount"]["amount"]["value"] + pr.extra_data.update( + { + "fee": response["receiveAmount"]["fees"]["value"], + "fee_currency": response["receiveAmount"]["fees"]["currencyCode"], + "taxes": response["receiveAmount"]["taxes"]["value"], + "taxes_currency": response["receiveAmount"]["taxes"]["currencyCode"], + "expectedPayoutDate": response["expectedPayoutDate"], + "transactionId": response["transactionId"], + } + ) + flow = PaymentRecordFlow(pr) + flow.store() diff --git a/src/hope_payment_gateway/apps/fsp/moneygram/tasks.py b/src/hope_payment_gateway/apps/fsp/moneygram/tasks.py new file mode 100644 index 0000000..22cb24b --- /dev/null +++ b/src/hope_payment_gateway/apps/fsp/moneygram/tasks.py @@ -0,0 +1,50 @@ +import logging +from typing import List + +from constance import config + +from hope_payment_gateway.apps.fsp.moneygram.client import MoneyGramClient +from hope_payment_gateway.apps.gateway.models import ( + FinancialServiceProvider, + PaymentInstruction, + PaymentInstructionState, + PaymentRecord, + PaymentRecordState, +) +from hope_payment_gateway.celery import app + + +@app.task() # queue="executors" +def moneygram_send_task(vendor_number="1900723202", tag=None, threshold=10000): + """Task to trigger MoneyGram payments""" + logging.info("MoneyGram Task started") + fsp = FinancialServiceProvider.objects.get(vision_vendor_number=vendor_number) + threshold = threshold or config.MONEYGRAM_THREASHOLD + + records_count = 0 + + qs = PaymentInstruction.objects.filter(status=PaymentInstructionState.READY, fsp=fsp) + if tag: + qs = qs.filter(tag=tag) + + for pi in qs: + logging.info(f"Processing payment instruction {pi.unicef_id}") + records = pi.paymentrecord_set.filter(status=PaymentRecordState.PENDING, marked_for_payment=False) + records_count += records.count() + if records_count > threshold: + break + + logging.info(f"Sending {records_count} records {pi} to Moneygram") + records_ids = list(records.values_list("id", flat=True)) + moneygram_notify.delay(records_ids) + pi.status = PaymentInstructionState.PROCESSED + pi.save() + + logging.info("MoneyGram Task completed") + + +@app.task +def moneygram_notify(to_process_ids: List[PaymentRecord]) -> None: + PaymentRecord.objects.filter(id__in=to_process_ids).update(marked_for_payment=True) + for record in PaymentRecord.objects.filter(id__in=to_process_ids): + MoneyGramClient().create_transaction(record.get_payload()) diff --git a/src/hope_payment_gateway/apps/fsp/western_union/admin.py b/src/hope_payment_gateway/apps/fsp/western_union/admin.py index 5ef469b..f30d8c0 100644 --- a/src/hope_payment_gateway/apps/fsp/western_union/admin.py +++ b/src/hope_payment_gateway/apps/fsp/western_union/admin.py @@ -38,21 +38,21 @@ class CorridorAdmin(ExtraButtonsMixin, admin.ModelAdmin): def request(self, request) -> TemplateResponse: context = self.get_common_context(request) context.update(requests_request()) - return TemplateResponse(request, "western_union.html", context) + return TemplateResponse(request, "request.html", context) @view() def das_countries_currencies(self, request) -> TemplateResponse: context = self.get_common_context(request) context["msg"] = "Countries with related Currencies (Many to many)" context.update(das_countries_currencies()) - return TemplateResponse(request, "western_union.html", context) + return TemplateResponse(request, "request.html", context) @view() def das_origination_currencies(self, request) -> TemplateResponse: context = self.get_common_context(request) context["msg"] = "Countries with related iso codes" context.update(das_origination_currencies()) - return TemplateResponse(request, "western_union.html", context) + return TemplateResponse(request, "request.html", context) @view() def das_destination_currencies(self, request) -> TemplateResponse: @@ -60,14 +60,14 @@ def das_destination_currencies(self, request) -> TemplateResponse: context = self.get_common_context(request) context["msg"] = f"currencies allowed for in {destination_country} \n " f"PARAM: destination_country" context.update(das_destination_currencies(destination_country)) - return TemplateResponse(request, "western_union.html", context) + return TemplateResponse(request, "request.html", context) @view() def das_destination_countries(self, request) -> TemplateResponse: context = self.get_common_context(request) context["msg"] = "List of destination countries" context.update(das_destination_countries()) - return TemplateResponse(request, "western_union.html", context) + return TemplateResponse(request, "request.html", context) @view() def das_delivery_services(self, request) -> TemplateResponse: @@ -80,7 +80,7 @@ def das_delivery_services(self, request) -> TemplateResponse: f"PARAM: destination_currency" ) context.update(das_delivery_services(destination_country, destination_currency)) - return TemplateResponse(request, "western_union.html", context) + return TemplateResponse(request, "request.html", context) @choice() def western_union(self, button): @@ -105,7 +105,7 @@ def delivery_services(self, request, pk) -> TemplateResponse: f"PARAM: destination_currency" ) context.update(das_delivery_services(destination_country, destination_currency)) - return TemplateResponse(request, "western_union.html", context) + return TemplateResponse(request, "request.html", context) @view() def das_delivery_option_template(self, request) -> TemplateResponse: @@ -120,7 +120,7 @@ def das_delivery_option_template(self, request) -> TemplateResponse: f"PARAM: template_code" ) context.update(das_delivery_option_template(destination_country, destination_currency, template_code)) - return TemplateResponse(request, "western_union.html", context) + return TemplateResponse(request, "request.html", context) @button() def delivery_option_template(self, request, pk) -> TemplateResponse: @@ -137,7 +137,7 @@ def delivery_option_template(self, request, pk) -> TemplateResponse: f"PARAM: template_code" ) context.update(das_delivery_option_template(destination_country, destination_currency, template_code)) - return TemplateResponse(request, "western_union.html", context) + return TemplateResponse(request, "request.html", context) @admin.register(ServiceProviderCode) diff --git a/src/hope_payment_gateway/apps/fsp/western_union/endpoints/client.py b/src/hope_payment_gateway/apps/fsp/western_union/endpoints/client.py index b866e6d..3091f7d 100644 --- a/src/hope_payment_gateway/apps/fsp/western_union/endpoints/client.py +++ b/src/hope_payment_gateway/apps/fsp/western_union/endpoints/client.py @@ -1,4 +1,5 @@ import logging +import xml.dom.minidom from pathlib import Path from requests import Session @@ -62,6 +63,7 @@ def response_context(self, service_name, payload, wsdl_name=None, port=None): code = 400 logger.exception(exc) except Exception as exc: + title = f"{exc.message} [{exc.code}]" code = 400 error = str(exc) logger.exception(exc) @@ -71,4 +73,5 @@ def response_context(self, service_name, payload, wsdl_name=None, port=None): def prepare(self, service_name, payload): node = self.client.create_message(self.client.service, service_name, **payload) data = etree_to_string(node) - return node, data + dom = xml.dom.minidom.parseString(data) + return node, dom.toprettyxml() diff --git a/src/hope_payment_gateway/apps/fsp/western_union/endpoints/config.py b/src/hope_payment_gateway/apps/fsp/western_union/endpoints/config.py index 9f03ae8..8e6d1ed 100644 --- a/src/hope_payment_gateway/apps/fsp/western_union/endpoints/config.py +++ b/src/hope_payment_gateway/apps/fsp/western_union/endpoints/config.py @@ -9,7 +9,7 @@ WIC = "WIC" # system # delivery_services_code -MONEY_IN_TIME = "000" +MONEY_IN_TIME = "000" # Cash over the counter: collect money kiosk WALLET = "800" diff --git a/src/hope_payment_gateway/apps/fsp/western_union/handlers.py b/src/hope_payment_gateway/apps/fsp/western_union/handlers.py index d26f227..d6f016c 100644 --- a/src/hope_payment_gateway/apps/fsp/western_union/handlers.py +++ b/src/hope_payment_gateway/apps/fsp/western_union/handlers.py @@ -5,7 +5,7 @@ class WesternUnionHandler(FSPProcessor): def get_configuration(self, config_key, delivery_mechanism): - wu = FinancialServiceProvider.objects.get(vision_vendor_number="1900723202") + wu = FinancialServiceProvider.objects.get(vendor_number="1900723202") try: config = FinancialServiceProviderConfig.objects.get( key=config_key, fsp=wu, delivery_mechanism__code=delivery_mechanism diff --git a/src/hope_payment_gateway/apps/fsp/western_union/tasks.py b/src/hope_payment_gateway/apps/fsp/western_union/tasks.py index df4d420..9c35f27 100644 --- a/src/hope_payment_gateway/apps/fsp/western_union/tasks.py +++ b/src/hope_payment_gateway/apps/fsp/western_union/tasks.py @@ -20,10 +20,10 @@ @app.task() # queue="executors" -def western_union_send_task(vision_vendor_number="1900723202", tag=None, threshold=10000): +def western_union_send_task(vendor_number="1900723202", tag=None, threshold=10000): """Task to trigger Western Union payments""" logging.info("Western Union Task started") - fsp = FinancialServiceProvider.objects.get(vision_vendor_number=vision_vendor_number) + fsp = FinancialServiceProvider.objects.get(vendor_number=vendor_number) threshold = threshold or config.WESTERN_UNION_THREASHOLD records_count = 0 diff --git a/src/hope_payment_gateway/apps/fsp/western_union/templates/western_union.html b/src/hope_payment_gateway/apps/fsp/western_union/templates/western_union.html deleted file mode 100644 index e804802..0000000 --- a/src/hope_payment_gateway/apps/fsp/western_union/templates/western_union.html +++ /dev/null @@ -1,16 +0,0 @@ -{% extends "admin_extra_buttons/action_page.html" %} -{% load static %} -{% block content %} -{% autoescape on %} - {{ msg | linebreaksbr }} -{% endautoescape %} - - -{% if format == "json" %} -
-{% endif %}
-    {{ content }}
-{% if format == "json" %}
-    
-{% endif %} -{% endblock %} diff --git a/src/hope_payment_gateway/apps/gateway/admin.py b/src/hope_payment_gateway/apps/gateway/admin.py index 4e6bde0..d8e1f4d 100644 --- a/src/hope_payment_gateway/apps/gateway/admin.py +++ b/src/hope_payment_gateway/apps/gateway/admin.py @@ -16,6 +16,7 @@ from adminfilters.autocomplete import AutoCompleteFilter from adminfilters.mixin import AdminFiltersMixin +from hope_payment_gateway.apps.fsp.moneygram.client import MoneyGramClient, PayloadMissingKey from hope_payment_gateway.apps.fsp.western_union.endpoints.cancel import cancel, search_request from hope_payment_gateway.apps.fsp.western_union.endpoints.client import WesternUnionClient from hope_payment_gateway.apps.fsp.western_union.endpoints.send_money import ( @@ -69,19 +70,22 @@ class PaymentRecordAdmin(ExtraButtonsMixin, AdminFiltersMixin, admin.ModelAdmin) actions = [export_as_template] + def get_queryset(self, request): + return super().get_queryset(request).select_related("parent__fsp") + @choice(change_list=False) def western_union(self, button): button.choices = [ - self.prepare_payload, - self.send_money_validation, - self.send_money, - self.search_request, - self.cancel, + self.wu_prepare_payload, + self.wu_send_money_validation, + self.wu_send_money, + self.wu_search_request, + self.wu_cancel, ] return button - @view(html_attrs={"style": "background-color:#88FF88;color:black"}) - def prepare_payload(self, request, pk) -> TemplateResponse: + @view(html_attrs={"style": "background-color:#88FF88;color:black"}, label="Prepare Payload") + def wu_prepare_payload(self, request, pk) -> TemplateResponse: context = self.get_common_context(request, pk) obj = PaymentRecord.objects.get(pk=pk) payload = obj.get_payload() @@ -89,16 +93,16 @@ def prepare_payload(self, request, pk) -> TemplateResponse: payload = create_validation_payload(payload) client = WesternUnionClient("SendMoneyValidation_Service_H2HService.wsdl") _, data = client.prepare("sendmoneyValidation", payload) - context["title"] = "Payload" + context["title"] = "Western Union Payload" context["content"] = data - return TemplateResponse(request, "western_union.html", context) + return TemplateResponse(request, "request.html", context) - except (PayloadException, InvalidCorridor) as e: + except (PayloadException, InvalidCorridor, PayloadMissingKey) as e: messages.add_message(request, messages.ERROR, str(e)) return obj - @view(html_attrs={"style": "background-color:#88FF88;color:black"}) - def send_money_validation(self, request, pk) -> TemplateResponse: + @view(html_attrs={"style": "background-color:#88FF88;color:black"}, label="Send Money Validation") + def wu_send_money_validation(self, request, pk) -> TemplateResponse: context = self.get_common_context(request, pk) obj = PaymentRecord.objects.get(pk=pk) payload = obj.get_payload() @@ -106,13 +110,13 @@ def send_money_validation(self, request, pk) -> TemplateResponse: try: payload = create_validation_payload(payload) context.update(send_money_validation(payload)) - return TemplateResponse(request, "western_union.html", context) + return TemplateResponse(request, "request.html", context) except (PayloadException, InvalidCorridor) as e: messages.add_message(request, messages.ERROR, str(e)) return obj - @view(html_attrs={"style": "background-color:#88FF88;color:black"}) - def send_money(self, request, pk) -> TemplateResponse: + @view(html_attrs={"style": "background-color:#88FF88;color:black"}, label="Send Money") + def wu_send_money(self, request, pk) -> TemplateResponse: obj = PaymentRecord.objects.get(pk=pk) log = send_money(obj.get_payload()) if log is None: @@ -121,19 +125,19 @@ def send_money(self, request, pk) -> TemplateResponse: loglevel = messages.SUCCESS if log.success else messages.ERROR messages.add_message(request, loglevel, log.message) - @view(html_attrs={"style": "background-color:yellow;color:blue"}) - def search_request(self, request, pk) -> TemplateResponse: + @view(html_attrs={"style": "background-color:yellow;color:blue"}, label="Search Request") + def wu_search_request(self, request, pk) -> TemplateResponse: context = self.get_common_context(request, pk) obj = PaymentRecord.objects.get(pk=pk) if mtcn := obj.extra_data.get("mtcn", None): context["msg"] = f"Search request through MTCN \n" f"PARAM: mtcn {mtcn}" frm = obj.extra_data.get("foreign_remote_system", None) context.update(search_request(frm, mtcn)) - return TemplateResponse(request, "western_union.html", context) + return TemplateResponse(request, "request.html", context) messages.warning(request, "Missing MTCN") - @view(html_attrs={"style": "background-color:#88FF88;color:black"}) - def cancel(self, request, pk) -> TemplateResponse: + @view(html_attrs={"style": "background-color:#88FF88;color:black"}, label="Cancel") + def wu_cancel(self, request, pk) -> TemplateResponse: context = self.get_common_context(request, pk) obj = PaymentRecord.objects.get(pk=pk) if mtcn := obj.extra_data.get("mtcn", None): @@ -142,8 +146,57 @@ def cancel(self, request, pk) -> TemplateResponse: loglevel = messages.SUCCESS if log.success else messages.ERROR messages.add_message(request, loglevel, log.message) - def get_queryset(self, request): - return super().get_queryset(request).select_related("parent__fsp") + @view(html_attrs={"style": "background-color:#88FF88;color:black"}, label="Prepare Payload") + def mg_prepare_payload(self, request, pk) -> TemplateResponse: + context = self.get_common_context(request, pk) + obj = PaymentRecord.objects.get(pk=pk) + try: + client = MoneyGramClient() + context["title"] = "Moneygram Payload" + context["content"] = client.prepare_transaction(obj.get_payload()) + return TemplateResponse(request, "request.html", context) + + except (PayloadException, InvalidCorridor, PayloadMissingKey) as e: + messages.add_message(request, messages.ERROR, str(e)) + return obj + + @view(html_attrs={"style": "background-color:#88FF88;color:black"}, label="Create Transaction") + def mg_create_transaction(self, request, pk) -> TemplateResponse: + obj = PaymentRecord.objects.get(pk=pk) + + client = MoneyGramClient() + resp = client.create_transaction(obj.get_payload()) + + data = resp.json() + msgs = [] + if resp.status_code == 200: + loglevel = messages.SUCCESS + elif 400 <= resp.status_code < 500: + loglevel = messages.WARNING + if "errors" in resp.json(): + for error in data["errors"]: + msgs.append(f"{error['message']} ({error['code']})") + elif "error" in resp.json(): + msgs.append(resp.json()["error"]["message"]) + else: + msgs = [ + "Error", + ] + else: + loglevel = messages.ERROR + for error in data["errors"]: + msgs.append(f"{error['message']} ({error['code']})") + + for msg in msgs: + messages.add_message(request, loglevel, msg) + + @choice(change_list=False) + def moneygram(self, button): + button.choices = [ + self.mg_prepare_payload, + self.mg_create_transaction, + ] + return button @link() def instruction(self, button: button) -> Optional[str]: @@ -250,10 +303,10 @@ class FinancialServiceProviderConfigInline(TabularInline): class FinancialServiceProviderAdmin(ExtraButtonsMixin, admin.ModelAdmin): list_display = ( "name", - "vision_vendor_number", + "vendor_number", "remote_id", ) - search_fields = ("remote_id", "name", "vision_vendor_number") + search_fields = ("remote_id", "name", "vendor_number") inlines = (FinancialServiceProviderConfigInline,) diff --git a/src/hope_payment_gateway/apps/gateway/migrations/0024_rename_vision_vendor_number_financialserviceprovider_vendor_number.py b/src/hope_payment_gateway/apps/gateway/migrations/0024_rename_vision_vendor_number_financialserviceprovider_vendor_number.py new file mode 100644 index 0000000..71aaa0b --- /dev/null +++ b/src/hope_payment_gateway/apps/gateway/migrations/0024_rename_vision_vendor_number_financialserviceprovider_vendor_number.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.1 on 2024-10-10 07:24 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("gateway", "0023_rename_type_deliverymechanism_transfer_type_and_more"), + ] + + operations = [ + migrations.RenameField( + model_name="financialserviceprovider", + old_name="vision_vendor_number", + new_name="vendor_number", + ), + ] diff --git a/src/hope_payment_gateway/apps/gateway/models.py b/src/hope_payment_gateway/apps/gateway/models.py index 15d4bdd..d16035d 100644 --- a/src/hope_payment_gateway/apps/gateway/models.py +++ b/src/hope_payment_gateway/apps/gateway/models.py @@ -40,12 +40,12 @@ def __str__(self): class FinancialServiceProvider(TimeStampedModel): remote_id = models.CharField(max_length=255, db_index=True, null=True, blank=True) name = models.CharField(max_length=64, unique=True) - vision_vendor_number = models.CharField(max_length=100, unique=True) + vendor_number = models.CharField(max_length=100, unique=True) strategy = StrategyField(registry=registry) configuration = models.JSONField(default=dict, null=True, blank=True) def __str__(self): - return f"{self.name} [{self.vision_vendor_number}]" + return f"{self.name} [{self.vendor_number}]" class FinancialServiceProviderConfig(models.Model): diff --git a/src/hope_payment_gateway/config/__init__.py b/src/hope_payment_gateway/config/__init__.py index 5618283..488b258 100644 --- a/src/hope_payment_gateway/config/__init__.py +++ b/src/hope_payment_gateway/config/__init__.py @@ -1,4 +1,4 @@ -from environ import Env +from smart_env import SmartEnv MANDATORY = { "DATABASE_URL": (str, "", "Database connetcion url"), @@ -19,27 +19,49 @@ OPTIONAL = { "ADMIN_EMAIL": (str, "", "Admin email"), "ADMIN_PASSWORD": (str, "", "Admin password"), - "ALLOWED_HOSTS": (list, ["127.0.0.1", "localhost"], "Django ALLOWED_HOSTS"), - "AZURE_ACCOUNT_KEY": (str, "", "Azure account Key"), + "ALLOWED_HOSTS": (list, ["127.0.0.1", "localhost"]), + "AZURE_ACCOUNT_KEY": (str, ""), "AZURE_ACCOUNT_NAME": (str, ""), "AZURE_CONTAINER": (str, ""), + "AZURE_CLIENT_KEY": (str, ""), + "AZURE_CLIENT_SECRET": (str, ""), + "AZURE_TENANT_ID": (str, ""), "CELERY_VISIBILITY_TIMEOUT": (int, 1800), "CELERY_TASK_ALWAYS_EAGER": (bool, False), "CELERY_TASK_EAGER_PROPAGATES": (bool, True), + "CORS_ORIGIN_ALLOW_ALL": (bool, False), "CSRF_COOKIE_SECURE": (bool, True), "DEBUG": (bool, False, "Django DEBUG"), + "EMAIL_HOST": (str, ""), "EMAIL_HOST_PASSWORD": (str, ""), "EMAIL_HOST_USER": (str, ""), + "EMAIL_PORT": (int, 587), + "EMAIL_USE_SSL": (bool, False), + "EMAIL_USE_TLS": (bool, True), + "FILE_STORAGE_DEFAULT": (str, "django.core.files.storage.FileSystemStorage"), + "FILE_STORAGE_MEDIA": (str, "django.core.files.storage.FileSystemStorage"), + "FILE_STORAGE_STATIC": (str, "django.contrib.staticfiles.storage.StaticFilesStorage"), + "FTP_WESTERN_UNION_PASSWORD": (str, ""), + "FTP_WESTERN_UNION_PORT": (int, 22), + "FTP_WESTERN_UNION_SERVER": (str, "westu.f.unicef.org"), + "FTP_WESTERN_UNION_USERNAME": (str, ""), + "HOST": (str, "http://localhost:8000"), + "LOGIN_ENABLED": (bool, False), "SECURE_HSTS_SECONDS": (int, 60), "SESSION_COOKIE_HTTPONLY": (bool, True), "SECURE_SSL_REDIRECT": (bool, True), "SECURE_HSTS_PRELOAD": (bool, True), "SIGNING_BACKEND": (str, "django.core.signing.TimestampSigner"), - "STATIC_FILE_STORAGE": (str, "hope_payment_gateway.apps.core.storage.StaticStorage"), "MEDIA_URL": (str, "/media/"), "MEDIA_ROOT": (str, "/tmp/media/"), + "MONEYGRAM_HOST": (str, ""), + "MONEYGRAM_CLIENT_ID": (str, ""), + "MONEYGRAM_CLIENT_SECRET": (str, ""), + "MONEYGRAM_PARTNER_ID": (str, ""), + "MONEYGRAM_REGISTRATION_NUMBER": (str, ""), "SENTRY_DSN": (str, ""), - "SENTRY_URL": (str, "https://excubo.unicef.org/"), + "SENTRY_ENVIRONMENT": (str, ""), + "SENTRY_URL": (str, "https://monitoring.hope.unicef.org/"), "SESSION_COOKIE_DOMAIN": (str, "unicef.org"), "SESSION_COOKIE_NAME": (str, "hpg_session"), "SESSION_COOKIE_PATH": (str, "/"), @@ -47,16 +69,13 @@ "STATIC_URL": (str, "/static/"), "STATIC_ROOT": (str, "/tmp/static/"), "TIME_ZONE": (str, "UTC"), + "WESTERN_UNION_BASE_URL": (str, ""), + "WESTERN_UNION_CERT": (str, ""), + "WESTERN_UNION_KEY": (str, ""), "WP_APPLICATION_SERVER_KEY": (str, ""), "WP_CLAIMS": (str, '{"sub": "mailto: hope@unicef.org","aud": "https://android.googleapis.com"}'), "WP_PRIVATE_KEY": (str, ""), } -class SmartEnv(Env): - def __init__(self, **scheme): # type: ignore[no-untyped-def] - self.raw = scheme - super().__init__(**{k: v[:2] for k, v in scheme.items()}) - - env = SmartEnv(**{**DEVELOPMENT, **MANDATORY, **OPTIONAL}) # type: ignore[no-untyped-call] diff --git a/src/hope_payment_gateway/config/fragments/__init__.py b/src/hope_payment_gateway/config/fragments/__init__.py index 2e82248..56a5a45 100644 --- a/src/hope_payment_gateway/config/fragments/__init__.py +++ b/src/hope_payment_gateway/config/fragments/__init__.py @@ -2,6 +2,7 @@ from .constance import * # noqa from .cors import * # noqa from .debug_toolbar import * # noqa +from .moneygram import * # noqa from .power_query import * # noqa from .rest_framework import * # noqa from .sentry import * # noqa diff --git a/src/hope_payment_gateway/config/fragments/celery.py b/src/hope_payment_gateway/config/fragments/celery.py index 612b88c..58c8e0e 100644 --- a/src/hope_payment_gateway/config/fragments/celery.py +++ b/src/hope_payment_gateway/config/fragments/celery.py @@ -2,12 +2,12 @@ CELERY_ACCEPT_CONTENT = ["pickle", "json", "application/text"] CELERY_BROKER_URL = env("CACHE_URL") -CELERY_BROKER_VISIBILITY_VAR = env("CELERY_VISIBILITY_TIMEOUT", default=1800) # in seconds +CELERY_BROKER_VISIBILITY_VAR = env("CELERY_VISIBILITY_TIMEOUT") # in seconds CELERY_BROKER_TRANSPORT_OPTIONS = {"visibility_timeout": int(CELERY_BROKER_VISIBILITY_VAR)} CELERY_RESULT_BACKEND = "django-db" CELERY_BEAT_SCHEDULER = "django_celery_beat.schedulers.DatabaseScheduler" # Sensible settings for celery -CELERY_TASK_ALWAYS_EAGER = env("CELERY_TASK_ALWAYS_EAGER", default=False) +CELERY_TASK_ALWAYS_EAGER = env("CELERY_TASK_ALWAYS_EAGER") CELERY_TASK_ACKS_LATE = True CELERY_TASK_PUBLISH_RETRY = True CELERY_WORKER_DISABLE_RATE_LIMITS = False diff --git a/src/hope_payment_gateway/config/fragments/constance.py b/src/hope_payment_gateway/config/fragments/constance.py index 3b13fab..c6ff820 100644 --- a/src/hope_payment_gateway/config/fragments/constance.py +++ b/src/hope_payment_gateway/config/fragments/constance.py @@ -1,6 +1,13 @@ from hope_payment_gateway.config.settings import CACHE_URL +CONSTANCE_BACKEND = "constance.backends.database.DatabaseBackend" + CONSTANCE_CONFIG = { + "MONEYGRAM_THREASHOLD": ( + 10000, + "Hourly threshold of calls to be made to MoneyGram API", + int, + ), "WESTERN_UNION_THREASHOLD": ( 10000, "Hourly threshold of calls to be made to Western Union API", diff --git a/src/hope_payment_gateway/config/fragments/cors.py b/src/hope_payment_gateway/config/fragments/cors.py index 8e565cb..e98ee7b 100644 --- a/src/hope_payment_gateway/config/fragments/cors.py +++ b/src/hope_payment_gateway/config/fragments/cors.py @@ -1,4 +1,4 @@ from ..settings import env # django-cors-headers: https://github.com/ottoyiu/django-cors-headers -CORS_ORIGIN_ALLOW_ALL = env("CORS_ORIGIN_ALLOW_ALL", default=False) +CORS_ORIGIN_ALLOW_ALL = env("CORS_ORIGIN_ALLOW_ALL") diff --git a/src/hope_payment_gateway/config/fragments/moneygram.py b/src/hope_payment_gateway/config/fragments/moneygram.py new file mode 100644 index 0000000..2a52edb --- /dev/null +++ b/src/hope_payment_gateway/config/fragments/moneygram.py @@ -0,0 +1,10 @@ +from ..settings import env + +# production: https://api.moneygram.com +# test: https://sandboxapi.moneygram.com + +MONEYGRAM_HOST = env("MONEYGRAM_HOST") +MONEYGRAM_CLIENT_ID = env("MONEYGRAM_CLIENT_ID") +MONEYGRAM_CLIENT_SECRET = env("MONEYGRAM_CLIENT_SECRET") +MONEYGRAM_PARTNER_ID = env("MONEYGRAM_PARTNER_ID") +MONEYGRAM_REGISTRATION_NUMBER = env("MONEYGRAM_REGISTRATION_NUMBER") diff --git a/src/hope_payment_gateway/config/fragments/sentry.py b/src/hope_payment_gateway/config/fragments/sentry.py index b0e5108..21fa4fb 100644 --- a/src/hope_payment_gateway/config/fragments/sentry.py +++ b/src/hope_payment_gateway/config/fragments/sentry.py @@ -5,7 +5,7 @@ from .. import env -SENTRY_DSN = env("SENTRY_DSN", default=None) # noqa: F405 +SENTRY_DSN = env("SENTRY_DSN") if SENTRY_DSN: # pragma: no cover sentry_sdk.init( @@ -14,5 +14,5 @@ send_default_pii=True, enable_tracing=True, integrations=[DjangoIntegration(), CeleryIntegration(), LoggingIntegration()], - environment=env("SENTRY_ENVIRONMENT", default=None), + environment=env("SENTRY_ENVIRONMENT"), ) diff --git a/src/hope_payment_gateway/config/fragments/social_auth.py b/src/hope_payment_gateway/config/fragments/social_auth.py index 6212dd2..b4cc780 100644 --- a/src/hope_payment_gateway/config/fragments/social_auth.py +++ b/src/hope_payment_gateway/config/fragments/social_auth.py @@ -1,8 +1,8 @@ from ..settings import env -SOCIAL_AUTH_SECRET = env.str("AZURE_CLIENT_SECRET", default="") -SOCIAL_AUTH_TENANT_ID = env("AZURE_TENANT_ID", default="") -SOCIAL_AUTH_KEY = env.str("AZURE_CLIENT_KEY", default="") +SOCIAL_AUTH_SECRET = env.str("AZURE_CLIENT_SECRET") +SOCIAL_AUTH_TENANT_ID = env("AZURE_TENANT_ID") +SOCIAL_AUTH_KEY = env.str("AZURE_CLIENT_KEY") SOCIAL_AUTH_URL_NAMESPACE = "social" SOCIAL_AUTH_SANITIZE_REDIRECTS = False diff --git a/src/hope_payment_gateway/config/fragments/western_union.py b/src/hope_payment_gateway/config/fragments/western_union.py index d97f6a8..a2713e2 100644 --- a/src/hope_payment_gateway/config/fragments/western_union.py +++ b/src/hope_payment_gateway/config/fragments/western_union.py @@ -1,10 +1,10 @@ from ..settings import env -WESTERN_UNION_BASE_URL = env("WESTERN_UNION_BASE_URL", default="") -WESTERN_UNION_CERT = env("WESTERN_UNION_CERT", default="") -WESTERN_UNION_KEY = env("WESTERN_UNION_KEY", default="") +WESTERN_UNION_BASE_URL = env("WESTERN_UNION_BASE_URL") +WESTERN_UNION_CERT = env("WESTERN_UNION_CERT") +WESTERN_UNION_KEY = env("WESTERN_UNION_KEY") -FTP_WESTERN_UNION_SERVER = env("FTP_WESTERN_UNION_SERVER", default="westu.f.unicef.org") -FTP_WESTERN_UNION_USERNAME = env("FTP_WESTERN_UNION_USERNAME", default="username") -FTP_WESTERN_UNION_PASSWORD = env("FTP_WESTERN_UNION_PASSWORD", default="password") -FTP_WESTERN_UNION_PORT = env("FTP_WESTERN_UNION_PORT", default=22) +FTP_WESTERN_UNION_SERVER = env("FTP_WESTERN_UNION_SERVER") +FTP_WESTERN_UNION_USERNAME = env("FTP_WESTERN_UNION_USERNAME") +FTP_WESTERN_UNION_PASSWORD = env("FTP_WESTERN_UNION_PASSWORD") +FTP_WESTERN_UNION_PORT = env("FTP_WESTERN_UNION_PORT") diff --git a/src/hope_payment_gateway/config/settings.py b/src/hope_payment_gateway/config/settings.py index 02667b7..8a767d4 100644 --- a/src/hope_payment_gateway/config/settings.py +++ b/src/hope_payment_gateway/config/settings.py @@ -91,8 +91,8 @@ BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) MEDIA_ROOT = env("MEDIA_ROOT") MEDIA_URL = env("MEDIA_URL") -STATIC_ROOT = env("STATIC_ROOT", default=os.path.join(BASE_DIR, "static")) -STATIC_URL = env("STATIC_URL", default="/static/") +STATIC_ROOT = env("STATIC_ROOT") +STATIC_URL = env("STATIC_URL") STATICFILES_DIRS = [] STATICFILES_FINDERS = [ "django.contrib.staticfiles.finders.FileSystemFinder", @@ -100,12 +100,9 @@ ] STORAGES = { - "default": { - "BACKEND": env.str("DEFAULT_FILE_STORAGE", default="hope_payment_gateway.apps.core.storage.MediaStorage"), - }, - "staticfiles": { - "BACKEND": env.str("STATIC_FILE_STORAGE", default="django.contrib.staticfiles.storage.StaticFilesStorage"), - }, + "default": env.storage("FILE_STORAGE_DEFAULT"), + "staticfiles": env.storage("FILE_STORAGE_STATIC"), + "media": env.storage("FILE_STORAGE_MEDIA"), } SECRET_KEY = env("SECRET_KEY") @@ -195,19 +192,21 @@ AUTH_USER_MODEL = "core.User" -HOST = env("HOST", default="http://localhost:8000") +HOST = env("HOST") DEFAULT_FROM_EMAIL = "hope@unicef.org" # EMAIL_BACKEND = "djcelery_email.backends.CeleryEmailBackend" # TODO: when ready, add djcelery_email EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" -EMAIL_HOST = env("EMAIL_HOST", default="") -EMAIL_HOST_USER = env("EMAIL_HOST_USER", default="") -EMAIL_HOST_PASSWORD = env("EMAIL_HOST_PASSWORD", default="") -EMAIL_PORT = env("EMAIL_PORT", default=25) -EMAIL_USE_TLS = env("EMAIL_USE_TLS", default=False) -EMAIL_USE_SSL = env("EMAIL_USE_SSL", default=False) - -LOGIN_ENABLED = env("LOGIN_ENABLED", default=False) +EMAIL_HOST = env( + "EMAIL_HOST", +) +EMAIL_HOST_USER = env("EMAIL_HOST_USER") +EMAIL_HOST_PASSWORD = env("EMAIL_HOST_PASSWORD") +EMAIL_PORT = env("EMAIL_PORT") +EMAIL_USE_TLS = env("EMAIL_USE_TLS") +EMAIL_USE_SSL = env("EMAIL_USE_SSL") + +LOGIN_ENABLED = env("LOGIN_ENABLED") from .fragments import * # noqa diff --git a/src/hope_payment_gateway/libs/ftp.py b/src/hope_payment_gateway/libs/ftp.py index af54cca..93d9cf4 100644 --- a/src/hope_payment_gateway/libs/ftp.py +++ b/src/hope_payment_gateway/libs/ftp.py @@ -1,12 +1,36 @@ -# https://github.com/rajansahu713/Working-with-Python-Libraries/tree/main/SFTP_work +import io +import logging from django.conf import settings import paramiko +logger = logging.getLogger(__name__) -def ls(): - t = paramiko.Transport((settings.FTP_WESTERN_UNION_SERVER, settings.FTP_WESTERN_UNION_PORT)) - t.connect(username=settings.FTP_WESTERN_UNION_USERNAME, password=settings.FTP_WESTERN_UNION_PASSWORD) - sftp = paramiko.SFTPClient.from_transport(t) - return sftp.listdir() + +class FTPClient: + client = None + + def __init__(self): + transport = paramiko.Transport((settings.FTP_WESTERN_UNION_SERVER, settings.FTP_WESTERN_UNION_PORT)) + transport.connect(username=settings.FTP_WESTERN_UNION_USERNAME, password=settings.FTP_WESTERN_UNION_PASSWORD) + self.client = paramiko.SFTPClient.from_transport(transport) + + def disconnect(self): + self.client.close() + + def ls(self): + return self.client.listdir() + + def get(self, filename, local_folder="/"): + local_file_path = f"{local_folder}/{filename}" + try: + self.client.get(filename, local_file_path) + except FileNotFoundError: + logger.info(f"File: {filename} was not found on the source server") + + def download(self, filename): + fl = io.BytesIO() + self.client.getfo(filename, fl) + fl.seek(0) + return fl diff --git a/tests/api/_api_checker/api.test_viewsets/configuration.fixture.json b/tests/api/_api_checker/api.test_viewsets/configuration.fixture.json index 6c24c8b..9be2ec6 100644 --- a/tests/api/_api_checker/api.test_viewsets/configuration.fixture.json +++ b/tests/api/_api_checker/api.test_viewsets/configuration.fixture.json @@ -20,7 +20,7 @@ "modified": "2024-04-30T13:26:18.440Z", "remote_id": "XPdEDeFmdXeT", "name": "dXKJxnrciVEJ", - "vision_vendor_number": "ABudUmYEozKU", + "vendor_number": "ABudUmYEozKU", "strategy": "hope_payment_gateway.apps.gateway.registry.DefaultProcessor", "configuration": {} } diff --git a/tests/api/_api_checker/api.test_viewsets/fsp.fixture.json b/tests/api/_api_checker/api.test_viewsets/fsp.fixture.json index 61dc10a..440b68d 100644 --- a/tests/api/_api_checker/api.test_viewsets/fsp.fixture.json +++ b/tests/api/_api_checker/api.test_viewsets/fsp.fixture.json @@ -8,7 +8,7 @@ "modified": "2024-04-30T13:26:18.440Z", "remote_id": "XPdEDeFmdXeT", "name": "dXKJxnrciVEJ", - "vision_vendor_number": "ABudUmYEozKU", + "vendor_number": "ABudUmYEozKU", "strategy": "hope_payment_gateway.apps.gateway.registry.DefaultProcessor", "configuration": {} } diff --git a/tests/api/_api_checker/api.test_viewsets/p_instruction.fixture.json b/tests/api/_api_checker/api.test_viewsets/p_instruction.fixture.json index 8558f68..3748bb2 100644 --- a/tests/api/_api_checker/api.test_viewsets/p_instruction.fixture.json +++ b/tests/api/_api_checker/api.test_viewsets/p_instruction.fixture.json @@ -25,7 +25,7 @@ "modified": "2024-04-30T13:26:18.440Z", "remote_id": "XPdEDeFmdXeT", "name": "dXKJxnrciVEJ", - "vision_vendor_number": "ABudUmYEozKU", + "vendor_number": "ABudUmYEozKU", "strategy": "hope_payment_gateway.apps.gateway.registry.DefaultProcessor", "configuration": {} } diff --git a/tests/api/_api_checker/api.test_viewsets/p_record.fixture.json b/tests/api/_api_checker/api.test_viewsets/p_record.fixture.json index c792193..49c6a7d 100644 --- a/tests/api/_api_checker/api.test_viewsets/p_record.fixture.json +++ b/tests/api/_api_checker/api.test_viewsets/p_record.fixture.json @@ -44,7 +44,7 @@ "modified": "2024-04-30T13:26:18.440Z", "remote_id": "XPdEDeFmdXeT", "name": "dXKJxnrciVEJ", - "vision_vendor_number": "ABudUmYEozKU", + "vendor_number": "ABudUmYEozKU", "strategy": "hope_payment_gateway.apps.gateway.registry.DefaultProcessor", "configuration": {} } diff --git a/tests/api/_api_checker/api.test_viewsets/test_api_config/_api_rest_config_/get/dc937b59892604f5a86ac96936cd7ff09e25f18ae6b758e8014a24c7fa039e91.response.json b/tests/api/_api_checker/api.test_viewsets/test_api_config/_api_rest_config_/get/dc937b59892604f5a86ac96936cd7ff09e25f18ae6b758e8014a24c7fa039e91.response.json index f79d1fe..df41f18 100644 --- a/tests/api/_api_checker/api.test_viewsets/test_api_config/_api_rest_config_/get/dc937b59892604f5a86ac96936cd7ff09e25f18ae6b758e8014a24c7fa039e91.response.json +++ b/tests/api/_api_checker/api.test_viewsets/test_api_config/_api_rest_config_/get/dc937b59892604f5a86ac96936cd7ff09e25f18ae6b758e8014a24c7fa039e91.response.json @@ -5,7 +5,7 @@ "Vary": "Accept, origin", "Allow": "GET, POST, HEAD, OPTIONS", "X-Frame-Options": "DENY", - "Content-Length": "302", + "Content-Length": "295", "X-Content-Type-Options": "nosniff", "Referrer-Policy": "same-origin", "Cross-Origin-Opener-Policy": "same-origin" @@ -18,7 +18,7 @@ "fsp": { "id": 717, "name": "dXKJxnrciVEJ", - "vision_vendor_number": "ABudUmYEozKU" + "vendor_number": "ABudUmYEozKU" }, "delivery_mechanism": { "id": 1, diff --git a/tests/api/_api_checker/api.test_viewsets/test_api_fsp/_api_rest_fsp_/get/dc937b59892604f5a86ac96936cd7ff09e25f18ae6b758e8014a24c7fa039e91.response.json b/tests/api/_api_checker/api.test_viewsets/test_api_fsp/_api_rest_fsp_/get/dc937b59892604f5a86ac96936cd7ff09e25f18ae6b758e8014a24c7fa039e91.response.json index f9f723b..22eb250 100644 --- a/tests/api/_api_checker/api.test_viewsets/test_api_fsp/_api_rest_fsp_/get/dc937b59892604f5a86ac96936cd7ff09e25f18ae6b758e8014a24c7fa039e91.response.json +++ b/tests/api/_api_checker/api.test_viewsets/test_api_fsp/_api_rest_fsp_/get/dc937b59892604f5a86ac96936cd7ff09e25f18ae6b758e8014a24c7fa039e91.response.json @@ -5,7 +5,7 @@ "Vary": "Accept, origin", "Allow": "GET, POST, HEAD, OPTIONS", "X-Frame-Options": "DENY", - "Content-Length": "112", + "Content-Length": "105", "X-Content-Type-Options": "nosniff", "Referrer-Policy": "same-origin", "Cross-Origin-Opener-Policy": "same-origin" @@ -15,7 +15,7 @@ "id": 717, "remote_id": "XPdEDeFmdXeT", "name": "dXKJxnrciVEJ", - "vision_vendor_number": "ABudUmYEozKU", + "vendor_number": "ABudUmYEozKU", "configs": [] } ], diff --git a/tests/conftest.py b/tests/conftest.py index 875a277..d69822a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -60,7 +60,7 @@ def prl(): @pytest.fixture() def wu(): return FinancialServiceProviderFactory( - name="Western Union", vision_vendor_number="1900723202", strategy=fqn(WesternUnionHandler) + name="Western Union", vendor_number="1900723202", strategy=fqn(WesternUnionHandler) ) diff --git a/tests/core/test_permissions.py b/tests/core/test_permissions.py index 2cca4d1..bc920a4 100644 --- a/tests/core/test_permissions.py +++ b/tests/core/test_permissions.py @@ -21,6 +21,7 @@ def test_get_client_ip_without_x_forwarded_for(request_factory): @pytest.mark.parametrize("ip,expected", [("127.0.0.1", True), ("192.168.1.1", False)]) +@pytest.mark.django_db @override_settings(DEBUG=False, WHITELISTED_IPS="127.0.0.1") def test_whitelist_permission_allowed(request_factory, ip, expected): request = request_factory.get("/admin", HTTP_X_FORWARDED_FOR=ip) @@ -28,6 +29,7 @@ def test_whitelist_permission_allowed(request_factory, ip, expected): assert permission.has_permission(request, None) is expected +@pytest.mark.django_db def test_whitelist_permission_denied(request_factory): request = request_factory.get("/admin", HTTP_X_FORWARDED_FOR="10.0.0.2") permission = WhitelistPermission() diff --git a/tests/core/test_storage.py b/tests/core/test_storage.py deleted file mode 100644 index c876f25..0000000 --- a/tests/core/test_storage.py +++ /dev/null @@ -1,45 +0,0 @@ -from django.core.files.base import ContentFile - -import pytest - -from hope_payment_gateway.apps.core.storage import DataSetStorage, MediaStorage, StaticStorage - - -@pytest.fixture -def data_set_storage(tmp_path): - return DataSetStorage(location=str(tmp_path)) - - -def test_readonly_storage(data_set_storage): - """ - We test to see if a file can be created and deleted - """ - file_name = "filetest.txt" - with pytest.raises(RuntimeError): - data_set_storage.save(file_name, ContentFile("original content")) - - -def test_media_storage_reads_environment_variables(monkeypatch): - """ - We test to see if it can recognize media variable in environment settings - """ - monkeypatch.setenv("MEDIA_AZURE_ACCOUNT_NAME", "media_account") - storage = MediaStorage() - settings = storage.get_default_settings() - - assert ( - settings["account_name"] == "media_account" - ), "MediaStorage should override settings based on environment variables" - - -def test_static_storage_reads_environment_variables(monkeypatch): - """ - We test to see if it can recognize static variable in environment settings - """ - monkeypatch.setenv("STATIC_AZURE_ACCOUNT_KEY", "static_key") - storage = StaticStorage() - settings = storage.get_default_settings() - - assert ( - settings["account_key"] == "static_key" - ), "StaticStorage should override settings based on environment variables" diff --git a/tests/factories.py b/tests/factories.py index ba3b2f6..ec4100a 100644 --- a/tests/factories.py +++ b/tests/factories.py @@ -91,7 +91,7 @@ class Meta: class FinancialServiceProviderFactory(factory.django.DjangoModelFactory): remote_id = fuzzy.FuzzyText() name = fuzzy.FuzzyText() - vision_vendor_number = fuzzy.FuzzyText() + vendor_number = fuzzy.FuzzyText() strategy = fqn(DefaultProcessor) class Meta: diff --git a/tests/gateway/test_models.py b/tests/gateway/test_models.py index 5546d75..5eade67 100644 --- a/tests/gateway/test_models.py +++ b/tests/gateway/test_models.py @@ -13,7 +13,7 @@ @pytest.mark.django_db def test_fsp(): - fsp = FinancialServiceProviderFactory(name="Western Union", vision_vendor_number="007") + fsp = FinancialServiceProviderFactory(name="Western Union", vendor_number="007") assert str(fsp) == "Western Union [007]" diff --git a/tests/moneygram/__init__.py b/tests/moneygram/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/moneygram/responses/token.yaml b/tests/moneygram/responses/token.yaml new file mode 100644 index 0000000..3f5dddd --- /dev/null +++ b/tests/moneygram/responses/token.yaml @@ -0,0 +1,34 @@ +responses: +- response: + auto_calculate_content_length: false + body: "{\n \"refresh_token_expires_in\" : \"0\",\n \"api_product_list\" : \"\ + [DisbursementStatus-Ext, DisbursementRefund-Ext, Disbursement-Ext]\",\n \"\ + api_product_list_json\" : [ \"DisbursementStatus-Ext\", \"DisbursementRefund-Ext\"\ + , \"Disbursement-Ext\" ],\n \"organization_name\" : \"moneygram\",\n \"developer.email\"\ + \ : \"developer@moneygram.com\",\n \"token_type\" : \"BearerToken\",\n \"\ + issued_at\" : \"1723627825298\",\n \"client_id\" : \"MY_IDO\"\ + ,\n \"access_token\" : \"HMfWVGb6AYGmx3B07JSXsfIZQw6Z\",\n \"application_name\"\ + \ : \"APP_NAME\",\n \"scope\" : \"\",\n \"expires_in\"\ + \ : \"3599\",\n \"refresh_count\" : \"0\",\n \"status\" : \"approved\"\n}" + content_type: text/plain + headers: + Access-Control-Allow-Headers: origin, x-requested-with, accept, content-type, + authorization, X-MG-SessionId, X-MG-ClientRequestId + Access-Control-Allow-Methods: GET, POST + Access-Control-Allow-Origin: '*' + Access-Control-Max-Age: '3628800' + Set-Cookie: visid_incap_2947185=MDZB6vzTS92oBVFcWuBZoBV5vGYAAAAAQUIPAAAAAACSnsGlFGNcbS0ZHCTX9iR8; + expires=Wed, 13 Aug 2025 23:07:14 GMT; HttpOnly; path=/; Domain=.moneygram.com, + nlbi_2947185=1FW3N90gbiyeRVn8dIbzIAAAAADOscteGaN9nnA4MVEJDa5N; HttpOnly; path=/; + Domain=.moneygram.com, incap_ses_1575_2947185=4jWdFh9tJCUsKnC8Q4bbFTF5vGYAAAAAlOtxXuEgwgaClJpsmwlVaw==; + path=/; Domain=.moneygram.com + Transfer-Encoding: chunked + X-CDN: Imperva + X-Iinfo: 12-44611785-44611790 NNYY CT(127 261 0) RT(1723627824848 53) q(0 0 + 0 5) r(1 1) U16 + X-MG-ClientRequestId: '' + X-MG-RequestId: rrt-8548968501246811288-c-gce-24097-124013989-1 + X-MG-SessionId: '' + method: GET + status: 200 + url: https://sandboxapi.moneygram.com/oauth/accesstoken?grant_type=client_credentials diff --git a/tests/moneygram/responses/transaction.yaml b/tests/moneygram/responses/transaction.yaml new file mode 100644 index 0000000..e731532 --- /dev/null +++ b/tests/moneygram/responses/transaction.yaml @@ -0,0 +1,24 @@ +responses: +- response: + auto_calculate_content_length: false + body: " \n {\n\"errors\": [{\n \"category\": \"Gateway-50000\",\n\ + \ \"code\": \"G903\",\n \"message\": \"Access_Token_Expired\"\n }]\n} " + content_type: text/plain + headers: + Set-Cookie: visid_incap_2947185=RIa0o6QLRkigrLEMnRWLl1rgvGYAAAAAQUIPAAAAAACCgSRoPoQqUetVQT2Os3XH; + expires=Wed, 13 Aug 2025 22:31:15 GMT; HttpOnly; path=/; Domain=.moneygram.com, + nlbi_2947185=tsfSXOW4BFV8CzQOdIbzIAAAAAC1TX2TY/99Wm14yAmIb+Cg; HttpOnly; path=/; + Domain=.moneygram.com, incap_ses_578_2947185=pFVsX56Mvl2Xdbv9EngFCIvgvGYAAAAA9xiPqZ2FW5ggODsoeGnTWw==; + path=/; Domain=.moneygram.com + Transfer-Encoding: chunked + WWW-Authenticate: 'Bearer realm="null",error="invalid_token",error_description="keymanagement.service.access_token_expired: + Access Token expired"' + X-CDN: Imperva + X-Iinfo: 13-85722317-85722321 NNYY CT(115 232 0) RT(1723654283707 43) q(0 0 + 0 0) r(1 1) U6 + X-MG-ClientRequestId: code-123 + X-MG-RequestId: rrt-9054480439679465427-c-gce-38780-127104294-1 + X-MG-SessionId: '' + method: POST + status: 401 + url: https://sandboxapi.moneygram.com/disbursement/v1/transactions diff --git a/tests/moneygram/test_client.py b/tests/moneygram/test_client.py new file mode 100644 index 0000000..d44d0b9 --- /dev/null +++ b/tests/moneygram/test_client.py @@ -0,0 +1,45 @@ +from django.test import override_settings + +import pytest +import responses + +from hope_payment_gateway.apps.fsp.moneygram.client import MoneyGramClient + +# from responses import _recorder +# @_recorder.record(file_path="tests/moneygram/responses/token.yaml") + + +@responses.activate +@override_settings(MONEYGRAM_HOST="https://sandboxapi.moneygram.com") +def test_get_token(): + # responses.get("https://sandboxapi.moneygram.com/oauth/accesstoken?grant_type=client_credentials") + responses._add_from_file(file_path="tests/moneygram/responses/token.yaml") + client = MoneyGramClient() + + assert client.token == "HMfWVGb6AYGmx3B07JSXsfIZQw6Z" + assert client.expires_in == "3599" + + +# @_recorder.record(file_path="tests/moneygram/responses/transaction.yaml") +@responses.activate +@pytest.mark.django_db +@pytest.mark.skip +@override_settings(MONEYGRAM_HOST="https://sandboxapi.moneygram.com") +def test_create_transaction(): + responses._add_from_file(file_path="tests/moneygram/responses/token.yaml") + responses._add_from_file(file_path="tests/moneygram/responses/transaction.yaml") + client = MoneyGramClient() + + payload = { + "first_name": "Alice", + "last_name": "Foo", + "amount": 1000, + "origination_currency": "IT", + "destination_country": "AF", + "destination_currency": "USD", + "payment_record_code": "code-123", + } + + response = client.create_transaction(payload) + + assert response.status_code == 401