From 9126a9fb5e8b61901383a95e7648ba21ecbe7719 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Thu, 17 Oct 2024 10:25:28 +0200 Subject: [PATCH 01/41] Need to merge develop back in --- poetry.lock | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 46 +++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 poetry.lock create mode 100644 pyproject.toml diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 00000000..829e57b1 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,80 @@ +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. + +[[package]] +name = "asgiref" +version = "3.8.1" +description = "ASGI specs, helper code, and adapters" +optional = false +python-versions = ">=3.8" +files = [ + {file = "asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47"}, + {file = "asgiref-3.8.1.tar.gz", hash = "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""} + +[package.extras] +tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] + +[[package]] +name = "django" +version = "4.2.15" +description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." +optional = false +python-versions = ">=3.8" +files = [ + {file = "Django-4.2.15-py3-none-any.whl", hash = "sha256:61ee4a130efb8c451ef3467c67ca99fdce400fedd768634efc86a68c18d80d30"}, + {file = "Django-4.2.15.tar.gz", hash = "sha256:c77f926b81129493961e19c0e02188f8d07c112a1162df69bfab178ae447f94a"}, +] + +[package.dependencies] +asgiref = ">=3.6.0,<4" +sqlparse = ">=0.3.1" +tzdata = {version = "*", markers = "sys_platform == \"win32\""} + +[package.extras] +argon2 = ["argon2-cffi (>=19.1.0)"] +bcrypt = ["bcrypt"] + +[[package]] +name = "sqlparse" +version = "0.5.1" +description = "A non-validating SQL parser." +optional = false +python-versions = ">=3.8" +files = [ + {file = "sqlparse-0.5.1-py3-none-any.whl", hash = "sha256:773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4"}, + {file = "sqlparse-0.5.1.tar.gz", hash = "sha256:bb6b4df465655ef332548e24f08e205afc81b9ab86cb1c45657a7ff173a3a00e"}, +] + +[package.extras] +dev = ["build", "hatch"] +doc = ["sphinx"] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + +[[package]] +name = "tzdata" +version = "2024.2" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +files = [ + {file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"}, + {file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"}, +] + +[metadata] +lock-version = "2.0" +python-versions = "^3.9" +content-hash = "4c4538d91778157bbe1714de368213dc86323cbd6271742ae9aef6bd7b204a0c" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..a4063c63 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,46 @@ +[tool.poetry] +name = "ndoh-hub" +version = "0.10.25" +description = "NDOH Registration and Change service for MomConnect and NurseConnect" +authors = ["Fritz Brand "] +repository = "https://github.com/praekeltfoundation/ndoh-hub" +license = "BSD" +readme = "README.md" + +packages = [ + { include = "aaq" }, + { include = "ada" }, + { include = "changes" }, + { include = "eventstore" }, + { include = "mqr" }, + { include = "ndoh-hub" }, + { include = "registrations" }, +] + +[tool.poetry.dependencies] +python = "^3.9" +Django = "4.2.15" +djangorestframework = "3.15.2" +coreapi = "2.3.3" +Markdown = "3.1.1" +dj-database-url = "1.2.0" +django-environ = "0.10.0" +psycopg2-binary = "2.8.6" +raven = "6.9.0" +django-filter = "2.4.0" +celery = "5.2.3" +six = "1.11.0" +requests = "2.32.0" +demands = "3.0.0" +structlog = "18.2.0" +phonenumberslite = "8.9.15" +django-simple-history = "3.3.0" +openpyxl = "2.5.9" +iso-639 = "0.4.5" +django-prometheus = "2.2.0" +rapidpro-python = "2.6.1" +pycountry = "19.8.18" + + + + From 6f9842a047898195710d14771dafdcf5618ccec1 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Thu, 17 Oct 2024 10:55:41 +0200 Subject: [PATCH 02/41] Added direct git install for iso639 --- poetry.lock | 1638 +++++++++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 73 ++- 2 files changed, 1694 insertions(+), 17 deletions(-) diff --git a/poetry.lock b/poetry.lock index 829e57b1..b87b3fef 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,5 +1,19 @@ # This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +[[package]] +name = "amqp" +version = "5.2.0" +description = "Low-level AMQP client for Python (fork of amqplib)." +optional = false +python-versions = ">=3.6" +files = [ + {file = "amqp-5.2.0-py3-none-any.whl", hash = "sha256:827cb12fb0baa892aad844fd95258143bce4027fdac4fccddbc43330fd281637"}, + {file = "amqp-5.2.0.tar.gz", hash = "sha256:a1ecff425ad063ad42a486c902807d1482311481c8ad95a72694b2975e75f7fd"}, +] + +[package.dependencies] +vine = ">=5.0.0,<6.0.0" + [[package]] name = "asgiref" version = "3.8.1" @@ -7,35 +21,1518 @@ description = "ASGI specs, helper code, and adapters" optional = false python-versions = ">=3.8" files = [ - {file = "asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47"}, - {file = "asgiref-3.8.1.tar.gz", hash = "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590"}, + {file = "asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47"}, + {file = "asgiref-3.8.1.tar.gz", hash = "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""} + +[package.extras] +tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] + +[[package]] +name = "async-timeout" +version = "4.0.3" +description = "Timeout context manager for asyncio programs" +optional = false +python-versions = ">=3.7" +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" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, + {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, +] + +[package.extras] +benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] + +[[package]] +name = "billiard" +version = "3.6.4.0" +description = "Python multiprocessing fork with improvements and bugfixes" +optional = false +python-versions = "*" +files = [ + {file = "billiard-3.6.4.0-py3-none-any.whl", hash = "sha256:87103ea78fa6ab4d5c751c4909bcff74617d985de7fa8b672cf8618afd5a875b"}, + {file = "billiard-3.6.4.0.tar.gz", hash = "sha256:299de5a8da28a783d51b197d496bef4f1595dd023a93a4f59dde1886ae905547"}, +] + +[[package]] +name = "black" +version = "24.3.0" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.8" +files = [ + {file = "black-24.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7d5e026f8da0322b5662fa7a8e752b3fa2dac1c1cbc213c3d7ff9bdd0ab12395"}, + {file = "black-24.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9f50ea1132e2189d8dff0115ab75b65590a3e97de1e143795adb4ce317934995"}, + {file = "black-24.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2af80566f43c85f5797365077fb64a393861a3730bd110971ab7a0c94e873e7"}, + {file = "black-24.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:4be5bb28e090456adfc1255e03967fb67ca846a03be7aadf6249096100ee32d0"}, + {file = "black-24.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4f1373a7808a8f135b774039f61d59e4be7eb56b2513d3d2f02a8b9365b8a8a9"}, + {file = "black-24.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aadf7a02d947936ee418777e0247ea114f78aff0d0959461057cae8a04f20597"}, + {file = "black-24.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c02e4ea2ae09d16314d30912a58ada9a5c4fdfedf9512d23326128ac08ac3d"}, + {file = "black-24.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:bf21b7b230718a5f08bd32d5e4f1db7fc8788345c8aea1d155fc17852b3410f5"}, + {file = "black-24.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:2818cf72dfd5d289e48f37ccfa08b460bf469e67fb7c4abb07edc2e9f16fb63f"}, + {file = "black-24.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4acf672def7eb1725f41f38bf6bf425c8237248bb0804faa3965c036f7672d11"}, + {file = "black-24.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7ed6668cbbfcd231fa0dc1b137d3e40c04c7f786e626b405c62bcd5db5857e4"}, + {file = "black-24.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:56f52cfbd3dabe2798d76dbdd299faa046a901041faf2cf33288bc4e6dae57b5"}, + {file = "black-24.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:79dcf34b33e38ed1b17434693763301d7ccbd1c5860674a8f871bd15139e7837"}, + {file = "black-24.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e19cb1c6365fd6dc38a6eae2dcb691d7d83935c10215aef8e6c38edee3f77abd"}, + {file = "black-24.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65b76c275e4c1c5ce6e9870911384bff5ca31ab63d19c76811cb1fb162678213"}, + {file = "black-24.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:b5991d523eee14756f3c8d5df5231550ae8993e2286b8014e2fdea7156ed0959"}, + {file = "black-24.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c45f8dff244b3c431b36e3224b6be4a127c6aca780853574c00faf99258041eb"}, + {file = "black-24.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6905238a754ceb7788a73f02b45637d820b2f5478b20fec82ea865e4f5d4d9f7"}, + {file = "black-24.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7de8d330763c66663661a1ffd432274a2f92f07feeddd89ffd085b5744f85e7"}, + {file = "black-24.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:7bb041dca0d784697af4646d3b62ba4a6b028276ae878e53f6b4f74ddd6db99f"}, + {file = "black-24.3.0-py3-none-any.whl", hash = "sha256:41622020d7120e01d377f74249e677039d20e6344ff5851de8a10f11f513bf93"}, + {file = "black-24.3.0.tar.gz", hash = "sha256:a0c9c4a0771afc6919578cec71ce82a3e31e054904e7197deacbc9382671c41f"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "celery" +version = "5.2.3" +description = "Distributed Task Queue." +optional = false +python-versions = ">=3.7," +files = [ + {file = "celery-5.2.3-py3-none-any.whl", hash = "sha256:8aacd02fc23a02760686d63dde1eb0daa9f594e735e73ea8fb15c2ff15cb608c"}, + {file = "celery-5.2.3.tar.gz", hash = "sha256:e2cd41667ad97d4f6a2f4672d1c6a6ebada194c619253058b5f23704aaadaa82"}, +] + +[package.dependencies] +billiard = ">=3.6.4.0,<4.0" +click = ">=8.0.3,<9.0" +click-didyoumean = ">=0.0.3" +click-plugins = ">=1.1.1" +click-repl = ">=0.2.0" +kombu = ">=5.2.3,<6.0" +pytz = ">=2021.3" +setuptools = ">=59.1.1,<59.7.0" +vine = ">=5.0.0,<6.0" + +[package.extras] +arangodb = ["pyArango (>=1.3.2)"] +auth = ["cryptography"] +azureblockblob = ["azure-storage-blob (==12.9.0)"] +brotli = ["brotli (>=1.0.0)", "brotlipy (>=0.7.0)"] +cassandra = ["cassandra-driver (<3.21.0)"] +consul = ["python-consul2"] +cosmosdbsql = ["pydocumentdb (==2.3.2)"] +couchbase = ["couchbase (>=3.0.0)"] +couchdb = ["pycouchdb"] +django = ["Django (>=1.11)"] +dynamodb = ["boto3 (>=1.9.178)"] +elasticsearch = ["elasticsearch"] +eventlet = ["eventlet (>=0.32.0)"] +gevent = ["gevent (>=1.5.0)"] +librabbitmq = ["librabbitmq (>=1.5.0)"] +memcache = ["pylibmc"] +mongodb = ["pymongo[srv] (>=3.11.1)"] +msgpack = ["msgpack"] +pymemcache = ["python-memcached"] +pyro = ["pyro4"] +pytest = ["pytest-celery"] +redis = ["redis (>=3.4.1,!=4.0.0,!=4.0.1)"] +s3 = ["boto3 (>=1.9.125)"] +slmq = ["softlayer-messaging (>=1.0.3)"] +solar = ["ephem"] +sqlalchemy = ["sqlalchemy"] +sqs = ["kombu[sqs]"] +tblib = ["tblib (>=1.3.0)", "tblib (>=1.5.0)"] +yaml = ["PyYAML (>=3.10)"] +zookeeper = ["kazoo (>=1.3.1)"] +zstd = ["zstandard"] + +[[package]] +name = "celery-batches" +version = "0.7" +description = "Experimental task class that buffers messages and processes them as a list." +optional = false +python-versions = ">=3.7" +files = [ + {file = "celery-batches-0.7.tar.gz", hash = "sha256:0a0f99073514e0fff3876b6da4ff0d784a91799367e54c5a4a49a75aaf056133"}, + {file = "celery_batches-0.7-py3-none-any.whl", hash = "sha256:3dfb40af6be51da418a86346fa5ed6dfcdf5b095e2f4f6a28467ae1c9c96c11b"}, +] + +[package.dependencies] +celery = ">=4.4,<5.3" + +[[package]] +name = "certifi" +version = "2024.8.30" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, +] + +[[package]] +name = "cfgv" +version = "3.4.0" +description = "Validate configuration and produce human readable error messages." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, + {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.0" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, + {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, + {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, +] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "click-didyoumean" +version = "0.3.1" +description = "Enables git-like *did-you-mean* feature in click" +optional = false +python-versions = ">=3.6.2" +files = [ + {file = "click_didyoumean-0.3.1-py3-none-any.whl", hash = "sha256:5c4bb6007cfea5f2fd6583a2fb6701a22a41eb98957e63d0fac41c10e7c3117c"}, + {file = "click_didyoumean-0.3.1.tar.gz", hash = "sha256:4f82fdff0dbe64ef8ab2279bd6aa3f6a99c3b28c05aa09cbfc07c9d7fbb5a463"}, +] + +[package.dependencies] +click = ">=7" + +[[package]] +name = "click-plugins" +version = "1.1.1" +description = "An extension module for click to enable registering CLI commands via setuptools entry-points." +optional = false +python-versions = "*" +files = [ + {file = "click-plugins-1.1.1.tar.gz", hash = "sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b"}, + {file = "click_plugins-1.1.1-py2.py3-none-any.whl", hash = "sha256:5d262006d3222f5057fd81e1623d4443e41dcda5dc815c06b442aa3c02889fc8"}, +] + +[package.dependencies] +click = ">=4.0" + +[package.extras] +dev = ["coveralls", "pytest (>=3.6)", "pytest-cov", "wheel"] + +[[package]] +name = "click-repl" +version = "0.3.0" +description = "REPL plugin for Click" +optional = false +python-versions = ">=3.6" +files = [ + {file = "click-repl-0.3.0.tar.gz", hash = "sha256:17849c23dba3d667247dc4defe1757fff98694e90fe37474f3feebb69ced26a9"}, + {file = "click_repl-0.3.0-py3-none-any.whl", hash = "sha256:fb7e06deb8da8de86180a33a9da97ac316751c094c6899382da7feeeeb51b812"}, +] + +[package.dependencies] +click = ">=7.0" +prompt-toolkit = ">=3.0.36" + +[package.extras] +testing = ["pytest (>=7.2.1)", "pytest-cov (>=4.0.0)", "tox (>=4.4.3)"] + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "coreapi" +version = "2.3.3" +description = "Python client library for Core API." +optional = false +python-versions = "*" +files = [ + {file = "coreapi-2.3.3-py2.py3-none-any.whl", hash = "sha256:bf39d118d6d3e171f10df9ede5666f63ad80bba9a29a8ec17726a66cf52ee6f3"}, + {file = "coreapi-2.3.3.tar.gz", hash = "sha256:46145fcc1f7017c076a2ef684969b641d18a2991051fddec9458ad3f78ffc1cb"}, +] + +[package.dependencies] +coreschema = "*" +itypes = "*" +requests = "*" +uritemplate = "*" + +[[package]] +name = "coreschema" +version = "0.0.4" +description = "Core Schema." +optional = false +python-versions = "*" +files = [ + {file = "coreschema-0.0.4-py2-none-any.whl", hash = "sha256:5e6ef7bf38c1525d5e55a895934ab4273548629f16aed5c0a6caa74ebf45551f"}, + {file = "coreschema-0.0.4.tar.gz", hash = "sha256:9503506007d482ab0867ba14724b93c18a33b22b6d19fb419ef2d239dd4a1607"}, +] + +[package.dependencies] +jinja2 = "*" + +[[package]] +name = "coverage" +version = "7.6.3" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "coverage-7.6.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6da42bbcec130b188169107ecb6ee7bd7b4c849d24c9370a0c884cf728d8e976"}, + {file = "coverage-7.6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c222958f59b0ae091f4535851cbb24eb57fc0baea07ba675af718fb5302dddb2"}, + {file = "coverage-7.6.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab84a8b698ad5a6c365b08061920138e7a7dd9a04b6feb09ba1bfae68346ce6d"}, + {file = "coverage-7.6.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70a6756ce66cd6fe8486c775b30889f0dc4cb20c157aa8c35b45fd7868255c5c"}, + {file = "coverage-7.6.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c2e6fa98032fec8282f6b27e3f3986c6e05702828380618776ad794e938f53a"}, + {file = "coverage-7.6.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:921fbe13492caf6a69528f09d5d7c7d518c8d0e7b9f6701b7719715f29a71e6e"}, + {file = "coverage-7.6.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6d99198203f0b9cb0b5d1c0393859555bc26b548223a769baf7e321a627ed4fc"}, + {file = "coverage-7.6.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:87cd2e29067ea397a47e352efb13f976eb1b03e18c999270bb50589323294c6e"}, + {file = "coverage-7.6.3-cp310-cp310-win32.whl", hash = "sha256:a3328c3e64ea4ab12b85999eb0779e6139295bbf5485f69d42cf794309e3d007"}, + {file = "coverage-7.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:bca4c8abc50d38f9773c1ec80d43f3768df2e8576807d1656016b9d3eeaa96fd"}, + {file = "coverage-7.6.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c51ef82302386d686feea1c44dbeef744585da16fcf97deea2a8d6c1556f519b"}, + {file = "coverage-7.6.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0ca37993206402c6c35dc717f90d4c8f53568a8b80f0bf1a1b2b334f4d488fba"}, + {file = "coverage-7.6.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c77326300b839c44c3e5a8fe26c15b7e87b2f32dfd2fc9fee1d13604347c9b38"}, + {file = "coverage-7.6.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e484e479860e00da1f005cd19d1c5d4a813324e5951319ac3f3eefb497cc549"}, + {file = "coverage-7.6.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c6c0f4d53ef603397fc894a895b960ecd7d44c727df42a8d500031716d4e8d2"}, + {file = "coverage-7.6.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:37be7b5ea3ff5b7c4a9db16074dc94523b5f10dd1f3b362a827af66a55198175"}, + {file = "coverage-7.6.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:43b32a06c47539fe275106b376658638b418c7cfdfff0e0259fbf877e845f14b"}, + {file = "coverage-7.6.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ee77c7bef0724165e795b6b7bf9c4c22a9b8468a6bdb9c6b4281293c6b22a90f"}, + {file = "coverage-7.6.3-cp311-cp311-win32.whl", hash = "sha256:43517e1f6b19f610a93d8227e47790722c8bf7422e46b365e0469fc3d3563d97"}, + {file = "coverage-7.6.3-cp311-cp311-win_amd64.whl", hash = "sha256:04f2189716e85ec9192df307f7c255f90e78b6e9863a03223c3b998d24a3c6c6"}, + {file = "coverage-7.6.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27bd5f18d8f2879e45724b0ce74f61811639a846ff0e5c0395b7818fae87aec6"}, + {file = "coverage-7.6.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d546cfa78844b8b9c1c0533de1851569a13f87449897bbc95d698d1d3cb2a30f"}, + {file = "coverage-7.6.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9975442f2e7a5cfcf87299c26b5a45266ab0696348420049b9b94b2ad3d40234"}, + {file = "coverage-7.6.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:583049c63106c0555e3ae3931edab5669668bbef84c15861421b94e121878d3f"}, + {file = "coverage-7.6.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2341a78ae3a5ed454d524206a3fcb3cec408c2a0c7c2752cd78b606a2ff15af4"}, + {file = "coverage-7.6.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a4fb91d5f72b7e06a14ff4ae5be625a81cd7e5f869d7a54578fc271d08d58ae3"}, + {file = "coverage-7.6.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e279f3db904e3b55f520f11f983cc8dc8a4ce9b65f11692d4718ed021ec58b83"}, + {file = "coverage-7.6.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aa23ce39661a3e90eea5f99ec59b763b7d655c2cada10729ed920a38bfc2b167"}, + {file = "coverage-7.6.3-cp312-cp312-win32.whl", hash = "sha256:52ac29cc72ee7e25ace7807249638f94c9b6a862c56b1df015d2b2e388e51dbd"}, + {file = "coverage-7.6.3-cp312-cp312-win_amd64.whl", hash = "sha256:40e8b1983080439d4802d80b951f4a93d991ef3261f69e81095a66f86cf3c3c6"}, + {file = "coverage-7.6.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9134032f5aa445ae591c2ba6991d10136a1f533b1d2fa8f8c21126468c5025c6"}, + {file = "coverage-7.6.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:99670790f21a96665a35849990b1df447993880bb6463a0a1d757897f30da929"}, + {file = "coverage-7.6.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dc7d6b380ca76f5e817ac9eef0c3686e7834c8346bef30b041a4ad286449990"}, + {file = "coverage-7.6.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f7b26757b22faf88fcf232f5f0e62f6e0fd9e22a8a5d0d5016888cdfe1f6c1c4"}, + {file = "coverage-7.6.3-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c59d6a4a4633fad297f943c03d0d2569867bd5372eb5684befdff8df8522e39"}, + {file = "coverage-7.6.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f263b18692f8ed52c8de7f40a0751e79015983dbd77b16906e5b310a39d3ca21"}, + {file = "coverage-7.6.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:79644f68a6ff23b251cae1c82b01a0b51bc40c8468ca9585c6c4b1aeee570e0b"}, + {file = "coverage-7.6.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:71967c35828c9ff94e8c7d405469a1fb68257f686bca7c1ed85ed34e7c2529c4"}, + {file = "coverage-7.6.3-cp313-cp313-win32.whl", hash = "sha256:e266af4da2c1a4cbc6135a570c64577fd3e6eb204607eaff99d8e9b710003c6f"}, + {file = "coverage-7.6.3-cp313-cp313-win_amd64.whl", hash = "sha256:ea52bd218d4ba260399a8ae4bb6b577d82adfc4518b93566ce1fddd4a49d1dce"}, + {file = "coverage-7.6.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8d4c6ea0f498c7c79111033a290d060c517853a7bcb2f46516f591dab628ddd3"}, + {file = "coverage-7.6.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:331b200ad03dbaa44151d74daeb7da2cf382db424ab923574f6ecca7d3b30de3"}, + {file = "coverage-7.6.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54356a76b67cf8a3085818026bb556545ebb8353951923b88292556dfa9f812d"}, + {file = "coverage-7.6.3-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ebec65f5068e7df2d49466aab9128510c4867e532e07cb6960075b27658dca38"}, + {file = "coverage-7.6.3-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d33a785ea8354c480515e781554d3be582a86297e41ccbea627a5c632647f2cd"}, + {file = "coverage-7.6.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f7ddb920106bbbbcaf2a274d56f46956bf56ecbde210d88061824a95bdd94e92"}, + {file = "coverage-7.6.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:70d24936ca6c15a3bbc91ee9c7fc661132c6f4c9d42a23b31b6686c05073bde5"}, + {file = "coverage-7.6.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c30e42ea11badb147f0d2e387115b15e2bd8205a5ad70d6ad79cf37f6ac08c91"}, + {file = "coverage-7.6.3-cp313-cp313t-win32.whl", hash = "sha256:365defc257c687ce3e7d275f39738dcd230777424117a6c76043459db131dd43"}, + {file = "coverage-7.6.3-cp313-cp313t-win_amd64.whl", hash = "sha256:23bb63ae3f4c645d2d82fa22697364b0046fbafb6261b258a58587441c5f7bd0"}, + {file = "coverage-7.6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:da29ceabe3025a1e5a5aeeb331c5b1af686daab4ff0fb4f83df18b1180ea83e2"}, + {file = "coverage-7.6.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:df8c05a0f574d480947cba11b947dc41b1265d721c3777881da2fb8d3a1ddfba"}, + {file = "coverage-7.6.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec1e3b40b82236d100d259854840555469fad4db64f669ab817279eb95cd535c"}, + {file = "coverage-7.6.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4adeb878a374126f1e5cf03b87f66279f479e01af0e9a654cf6d1509af46c40"}, + {file = "coverage-7.6.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43d6a66e33b1455b98fc7312b124296dad97a2e191c80320587234a77b1b736e"}, + {file = "coverage-7.6.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1990b1f4e2c402beb317840030bb9f1b6a363f86e14e21b4212e618acdfce7f6"}, + {file = "coverage-7.6.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:12f9515d875859faedb4144fd38694a761cd2a61ef9603bf887b13956d0bbfbb"}, + {file = "coverage-7.6.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:99ded130555c021d99729fabd4ddb91a6f4cc0707df4b1daf912c7850c373b13"}, + {file = "coverage-7.6.3-cp39-cp39-win32.whl", hash = "sha256:c3a79f56dee9136084cf84a6c7c4341427ef36e05ae6415bf7d787c96ff5eaa3"}, + {file = "coverage-7.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:aac7501ae73d4a02f4b7ac8fcb9dc55342ca98ffb9ed9f2dfb8a25d53eda0e4d"}, + {file = "coverage-7.6.3-pp39.pp310-none-any.whl", hash = "sha256:b9853509b4bf57ba7b1f99b9d866c422c9c5248799ab20e652bbb8a184a38181"}, + {file = "coverage-7.6.3.tar.gz", hash = "sha256:bb7d5fe92bd0dc235f63ebe9f8c6e0884f7360f88f3411bfed1350c872ef2054"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli"] + +[[package]] +name = "demands" +version = "3.0.0" +description = "Base HTTP service client" +optional = false +python-versions = "*" +files = [ + {file = "demands-3.0.0.tar.gz", hash = "sha256:796bad2385ce1f26b21abafa49c8e66738c37417d4229a5e89506a6f19355163"}, +] + +[package.dependencies] +requests = ">=2.4.2,<3.0.0" +six = "*" + +[[package]] +name = "distlib" +version = "0.3.9" +description = "Distribution utilities" +optional = false +python-versions = "*" +files = [ + {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, + {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, +] + +[[package]] +name = "dj-database-url" +version = "1.2.0" +description = "Use Database URLs in your Django Application." +optional = false +python-versions = "*" +files = [ + {file = "dj-database-url-1.2.0.tar.gz", hash = "sha256:b23b15046cb38180e0c95207bcc90fe5e9dbde8eef16065907dd85cf4ca7036c"}, + {file = "dj_database_url-1.2.0-py3-none-any.whl", hash = "sha256:5c2993b91801c0f78a8b19e642b497b90831124cbade0c265900d4c1037b4730"}, +] + +[package.dependencies] +Django = ">=3.2" + +[[package]] +name = "django" +version = "4.2.15" +description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." +optional = false +python-versions = ">=3.8" +files = [ + {file = "Django-4.2.15-py3-none-any.whl", hash = "sha256:61ee4a130efb8c451ef3467c67ca99fdce400fedd768634efc86a68c18d80d30"}, + {file = "Django-4.2.15.tar.gz", hash = "sha256:c77f926b81129493961e19c0e02188f8d07c112a1162df69bfab178ae447f94a"}, +] + +[package.dependencies] +asgiref = ">=3.6.0,<4" +sqlparse = ">=0.3.1" +tzdata = {version = "*", markers = "sys_platform == \"win32\""} + +[package.extras] +argon2 = ["argon2-cffi (>=19.1.0)"] +bcrypt = ["bcrypt"] + +[[package]] +name = "django-environ" +version = "0.10.0" +description = "A package that allows you to utilize 12factor inspired environment variables to configure your Django application." +optional = false +python-versions = ">=3.5,<4" +files = [ + {file = "django-environ-0.10.0.tar.gz", hash = "sha256:b3559a91439c9d774a9e0c1ced872364772c612cdf6dc919506a2b13f7a77225"}, + {file = "django_environ-0.10.0-py2.py3-none-any.whl", hash = "sha256:510f8c9c1d0a38b0815f91504270c29440a0cf44fab07f55942fa8d31bbb9be6"}, +] + +[package.extras] +develop = ["coverage[toml] (>=5.0a4)", "furo (>=2021.8.17b43,<2021.9.dev0)", "pytest (>=4.6.11)", "sphinx (>=3.5.0)", "sphinx-notfound-page"] +docs = ["furo (>=2021.8.17b43,<2021.9.dev0)", "sphinx (>=3.5.0)", "sphinx-notfound-page"] +testing = ["coverage[toml] (>=5.0a4)", "pytest (>=4.6.11)"] + +[[package]] +name = "django-filter" +version = "2.4.0" +description = "Django-filter is a reusable Django application for allowing users to filter querysets dynamically." +optional = false +python-versions = ">=3.5" +files = [ + {file = "django-filter-2.4.0.tar.gz", hash = "sha256:84e9d5bb93f237e451db814ed422a3a625751cbc9968b484ecc74964a8696b06"}, + {file = "django_filter-2.4.0-py3-none-any.whl", hash = "sha256:e00d32cebdb3d54273c48f4f878f898dced8d5dfaad009438fe61ebdf535ace1"}, +] + +[package.dependencies] +Django = ">=2.2" + +[[package]] +name = "django-prometheus" +version = "2.2.0" +description = "Django middlewares to monitor your application with Prometheus.io." +optional = false +python-versions = "*" +files = [ + {file = "django-prometheus-2.2.0.tar.gz", hash = "sha256:240378a1307c408bd5fc85614a3a57f1ce633d4a222c9e291e2bbf325173b801"}, + {file = "django_prometheus-2.2.0-py2.py3-none-any.whl", hash = "sha256:e6616770d8820b8834762764bf1b76ec08e1b98e72a6f359d488a2e15fe3537c"}, +] + +[package.dependencies] +prometheus-client = ">=0.7" + +[[package]] +name = "django-redis" +version = "5.2.0" +description = "Full featured redis cache backend for Django." +optional = false +python-versions = ">=3.6" +files = [ + {file = "django-redis-5.2.0.tar.gz", hash = "sha256:8a99e5582c79f894168f5865c52bd921213253b7fd64d16733ae4591564465de"}, + {file = "django_redis-5.2.0-py3-none-any.whl", hash = "sha256:1d037dc02b11ad7aa11f655d26dac3fb1af32630f61ef4428860a2e29ff92026"}, +] + +[package.dependencies] +Django = ">=2.2" +redis = ">=3,<4.0.0 || >4.0.0,<4.0.1 || >4.0.1" + +[package.extras] +hiredis = ["redis[hiredis] (>=3,!=4.0.0,!=4.0.1)"] + +[[package]] +name = "django-simple-history" +version = "3.3.0" +description = "Store model history and view/revert changes from admin site." +optional = false +python-versions = ">=3.7" +files = [ + {file = "django-simple-history-3.3.0.tar.gz", hash = "sha256:2313d2d346f15a1e7a92adb3b6696b226f1cd0c1d920869ec40c4c4076614c41"}, + {file = "django_simple_history-3.3.0-py3-none-any.whl", hash = "sha256:dc1f98e558a0a1e0b6371c3b8efb85f86e02a6db56e83d0ec198343b7408d00a"}, +] + +[[package]] +name = "djangorestframework" +version = "3.15.2" +description = "Web APIs for Django, made easy." +optional = false +python-versions = ">=3.8" +files = [ + {file = "djangorestframework-3.15.2-py3-none-any.whl", hash = "sha256:2b8871b062ba1aefc2de01f773875441a961fefbf79f5eed1e32b2f096944b20"}, + {file = "djangorestframework-3.15.2.tar.gz", hash = "sha256:36fe88cd2d6c6bec23dca9804bab2ba5517a8bb9d8f47ebc68981b56840107ad"}, +] + +[package.dependencies] +django = ">=4.2" + +[[package]] +name = "et-xmlfile" +version = "1.1.0" +description = "An implementation of lxml.xmlfile for the standard library" +optional = false +python-versions = ">=3.6" +files = [ + {file = "et_xmlfile-1.1.0-py3-none-any.whl", hash = "sha256:a2ba85d1d6a74ef63837eed693bcb89c3f752169b0e3e7ae5b16ca5e1b3deada"}, + {file = "et_xmlfile-1.1.0.tar.gz", hash = "sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.2.2" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "filelock" +version = "3.16.1" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.8" +files = [ + {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"}, + {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"}, +] + +[package.extras] +docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4.1)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"] +typing = ["typing-extensions (>=4.12.2)"] + +[[package]] +name = "flake8" +version = "6.0.0" +description = "the modular source code checker: pep8 pyflakes and co" +optional = false +python-versions = ">=3.8.1" +files = [ + {file = "flake8-6.0.0-py2.py3-none-any.whl", hash = "sha256:3833794e27ff64ea4e9cf5d410082a8b97ff1a06c16aa3d2027339cd0f1195c7"}, + {file = "flake8-6.0.0.tar.gz", hash = "sha256:c61007e76655af75e6785a931f452915b371dc48f56efd765247c8fe68f2b181"}, +] + +[package.dependencies] +mccabe = ">=0.7.0,<0.8.0" +pycodestyle = ">=2.10.0,<2.11.0" +pyflakes = ">=3.0.0,<3.1.0" + +[[package]] +name = "freezegun" +version = "1.2.2" +description = "Let your Python tests travel through time" +optional = false +python-versions = ">=3.6" +files = [ + {file = "freezegun-1.2.2-py3-none-any.whl", hash = "sha256:ea1b963b993cb9ea195adbd893a48d573fda951b0da64f60883d7e988b606c9f"}, + {file = "freezegun-1.2.2.tar.gz", hash = "sha256:cd22d1ba06941384410cd967d8a99d5ae2442f57dfafeff2fda5de8dc5c05446"}, +] + +[package.dependencies] +python-dateutil = ">=2.7" + +[[package]] +name = "identify" +version = "2.6.1" +description = "File identification library for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "identify-2.6.1-py2.py3-none-any.whl", hash = "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0"}, + {file = "identify-2.6.1.tar.gz", hash = "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98"}, +] + +[package.extras] +license = ["ukkonen"] + +[[package]] +name = "idna" +version = "3.10" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.6" +files = [ + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, +] + +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "iso-639" +version = "0.4.5" +description = "Python library for ISO 639 standard" +optional = false +python-versions = "*" +files = [] +develop = false + +[package.source] +type = "git" +url = "https://github.com/noumar/iso639.git" +reference = "0.4.5" +resolved_reference = "2175cf04b8b8cec79d99a6c4ad31295d67c22cd6" + +[[package]] +name = "iso6709" +version = "0.1.5" +description = "A library for parsing ISO6709 format Degree Minute Second style coordinates." +optional = false +python-versions = "*" +files = [ + {file = "iso6709-0.1.5-py2.py3-none-any.whl", hash = "sha256:f05621ad20571ffc9d47c3498c8dceb3473ab1fb540192ecd282b9ec760e66af"}, + {file = "iso6709-0.1.5.tar.gz", hash = "sha256:ae482a0ad700ae1496eb9f86b4e23b203b9b947513877938bbe26581c6864aa3"}, +] + +[[package]] +name = "iso8601" +version = "2.1.0" +description = "Simple module to parse ISO 8601 dates" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "iso8601-2.1.0-py3-none-any.whl", hash = "sha256:aac4145c4dcb66ad8b648a02830f5e2ff6c24af20f4f482689be402db2429242"}, + {file = "iso8601-2.1.0.tar.gz", hash = "sha256:6b1d3829ee8921c4301998c909f7829fa9ed3cbdac0d3b16af2d743aed1ba8df"}, +] + +[[package]] +name = "isort" +version = "5.12.0" +description = "A Python utility / library to sort Python imports." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, + {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, +] + +[package.extras] +colors = ["colorama (>=0.4.3)"] +pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] +plugins = ["setuptools"] +requirements-deprecated-finder = ["pip-api", "pipreqs"] + +[[package]] +name = "itypes" +version = "1.2.0" +description = "Simple immutable types for python." +optional = false +python-versions = "*" +files = [ + {file = "itypes-1.2.0-py2.py3-none-any.whl", hash = "sha256:03da6872ca89d29aef62773672b2d408f490f80db48b23079a4b194c86dd04c6"}, + {file = "itypes-1.2.0.tar.gz", hash = "sha256:af886f129dea4a2a1e3d36595a2d139589e4dd287f5cab0b40e799ee81570ff1"}, +] + +[[package]] +name = "jdcal" +version = "1.4.1" +description = "Julian dates from proleptic Gregorian and Julian calendars." +optional = false +python-versions = "*" +files = [ + {file = "jdcal-1.4.1-py2.py3-none-any.whl", hash = "sha256:1abf1305fce18b4e8aa248cf8fe0c56ce2032392bc64bbd61b5dff2a19ec8bba"}, + {file = "jdcal-1.4.1.tar.gz", hash = "sha256:472872e096eb8df219c23f2689fc336668bdb43d194094b5cc1707e1640acfc8"}, +] + +[[package]] +name = "jinja2" +version = "3.1.4" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "kombu" +version = "5.4.2" +description = "Messaging library for Python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "kombu-5.4.2-py3-none-any.whl", hash = "sha256:14212f5ccf022fc0a70453bb025a1dcc32782a588c49ea866884047d66e14763"}, + {file = "kombu-5.4.2.tar.gz", hash = "sha256:eef572dd2fd9fc614b37580e3caeafdd5af46c1eff31e7fba89138cdb406f2cf"}, +] + +[package.dependencies] +amqp = ">=5.1.1,<6.0.0" +typing-extensions = {version = "4.12.2", markers = "python_version < \"3.10\""} +tzdata = {version = "*", markers = "python_version >= \"3.9\""} +vine = "5.1.0" + +[package.extras] +azureservicebus = ["azure-servicebus (>=7.10.0)"] +azurestoragequeues = ["azure-identity (>=1.12.0)", "azure-storage-queue (>=12.6.0)"] +confluentkafka = ["confluent-kafka (>=2.2.0)"] +consul = ["python-consul2 (==0.1.5)"] +librabbitmq = ["librabbitmq (>=2.0.0)"] +mongodb = ["pymongo (>=4.1.1)"] +msgpack = ["msgpack (==1.1.0)"] +pyro = ["pyro4 (==4.82)"] +qpid = ["qpid-python (>=0.26)", "qpid-tools (>=0.26)"] +redis = ["redis (>=4.5.2,!=4.5.5,!=5.0.2)"] +slmq = ["softlayer-messaging (>=1.0.3)"] +sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"] +sqs = ["boto3 (>=1.26.143)", "pycurl (>=7.43.0.5)", "urllib3 (>=1.26.16)"] +yaml = ["PyYAML (>=3.10)"] +zookeeper = ["kazoo (>=2.8.0)"] + +[[package]] +name = "markdown" +version = "3.1.1" +description = "Python implementation of Markdown." +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" +files = [ + {file = "Markdown-3.1.1-py2.py3-none-any.whl", hash = "sha256:56a46ac655704b91e5b7e6326ce43d5ef72411376588afa1dd90e881b83c7e8c"}, + {file = "Markdown-3.1.1.tar.gz", hash = "sha256:2e50876bcdd74517e7b71f3e7a76102050edec255b3983403f1a63e7c8a41e7a"}, +] + +[package.dependencies] +setuptools = ">=36" + +[package.extras] +testing = ["coverage", "pyyaml"] + +[[package]] +name = "markupsafe" +version = "3.0.1" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.9" +files = [ + {file = "MarkupSafe-3.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:db842712984e91707437461930e6011e60b39136c7331e971952bb30465bc1a1"}, + {file = "MarkupSafe-3.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3ffb4a8e7d46ed96ae48805746755fadd0909fea2306f93d5d8233ba23dda12a"}, + {file = "MarkupSafe-3.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67c519635a4f64e495c50e3107d9b4075aec33634272b5db1cde839e07367589"}, + {file = "MarkupSafe-3.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48488d999ed50ba8d38c581d67e496f955821dc183883550a6fbc7f1aefdc170"}, + {file = "MarkupSafe-3.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f31ae06f1328595d762c9a2bf29dafd8621c7d3adc130cbb46278079758779ca"}, + {file = "MarkupSafe-3.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80fcbf3add8790caddfab6764bde258b5d09aefbe9169c183f88a7410f0f6dea"}, + {file = "MarkupSafe-3.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3341c043c37d78cc5ae6e3e305e988532b072329639007fd408a476642a89fd6"}, + {file = "MarkupSafe-3.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cb53e2a99df28eee3b5f4fea166020d3ef9116fdc5764bc5117486e6d1211b25"}, + {file = "MarkupSafe-3.0.1-cp310-cp310-win32.whl", hash = "sha256:db15ce28e1e127a0013dfb8ac243a8e392db8c61eae113337536edb28bdc1f97"}, + {file = "MarkupSafe-3.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:4ffaaac913c3f7345579db4f33b0020db693f302ca5137f106060316761beea9"}, + {file = "MarkupSafe-3.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:26627785a54a947f6d7336ce5963569b5d75614619e75193bdb4e06e21d447ad"}, + {file = "MarkupSafe-3.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b954093679d5750495725ea6f88409946d69cfb25ea7b4c846eef5044194f583"}, + {file = "MarkupSafe-3.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:973a371a55ce9ed333a3a0f8e0bcfae9e0d637711534bcb11e130af2ab9334e7"}, + {file = "MarkupSafe-3.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:244dbe463d5fb6d7ce161301a03a6fe744dac9072328ba9fc82289238582697b"}, + {file = "MarkupSafe-3.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d98e66a24497637dd31ccab090b34392dddb1f2f811c4b4cd80c230205c074a3"}, + {file = "MarkupSafe-3.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ad91738f14eb8da0ff82f2acd0098b6257621410dcbd4df20aaa5b4233d75a50"}, + {file = "MarkupSafe-3.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7044312a928a66a4c2a22644147bc61a199c1709712069a344a3fb5cfcf16915"}, + {file = "MarkupSafe-3.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a4792d3b3a6dfafefdf8e937f14906a51bd27025a36f4b188728a73382231d91"}, + {file = "MarkupSafe-3.0.1-cp311-cp311-win32.whl", hash = "sha256:fa7d686ed9883f3d664d39d5a8e74d3c5f63e603c2e3ff0abcba23eac6542635"}, + {file = "MarkupSafe-3.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:9ba25a71ebf05b9bb0e2ae99f8bc08a07ee8e98c612175087112656ca0f5c8bf"}, + {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-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4935dd7883f1d50e2ffecca0aa33dc1946a94c8f3fdafb8df5c330e48f71b132"}, + {file = "MarkupSafe-3.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e9393357f19954248b00bed7c56f29a25c930593a77630c719653d51e7669c2a"}, + {file = "MarkupSafe-3.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40621d60d0e58aa573b68ac5e2d6b20d44392878e0bfc159012a5787c4e35bc8"}, + {file = "MarkupSafe-3.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f94190df587738280d544971500b9cafc9b950d32efcb1fba9ac10d84e6aa4e6"}, + {file = "MarkupSafe-3.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6a387d61fe41cdf7ea95b38e9af11cfb1a63499af2759444b99185c4ab33f5b"}, + {file = "MarkupSafe-3.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8ad4ad1429cd4f315f32ef263c1342166695fad76c100c5d979c45d5570ed58b"}, + {file = "MarkupSafe-3.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e24bfe89c6ac4c31792793ad9f861b8f6dc4546ac6dc8f1c9083c7c4f2b335cd"}, + {file = "MarkupSafe-3.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2a4b34a8d14649315c4bc26bbfa352663eb51d146e35eef231dd739d54a5430a"}, + {file = "MarkupSafe-3.0.1-cp39-cp39-win32.whl", hash = "sha256:242d6860f1fd9191aef5fae22b51c5c19767f93fb9ead4d21924e0bcb17619d8"}, + {file = "MarkupSafe-3.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:93e8248d650e7e9d49e8251f883eed60ecbc0e8ffd6349e18550925e31bd029b"}, + {file = "markupsafe-3.0.1.tar.gz", hash = "sha256:3e683ee4f5d0fa2dde4db77ed8dd8a876686e3fc417655c2ece9a90576905344"}, +] + +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +optional = false +python-versions = ">=3.6" +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + +[[package]] +name = "mypy" +version = "1.1.1" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mypy-1.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39c7119335be05630611ee798cc982623b9e8f0cff04a0b48dfc26100e0b97af"}, + {file = "mypy-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:61bf08362e93b6b12fad3eab68c4ea903a077b87c90ac06c11e3d7a09b56b9c1"}, + {file = "mypy-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbb19c9f662e41e474e0cff502b7064a7edc6764f5262b6cd91d698163196799"}, + {file = "mypy-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:315ac73cc1cce4771c27d426b7ea558fb4e2836f89cb0296cbe056894e3a1f78"}, + {file = "mypy-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:5cb14ff9919b7df3538590fc4d4c49a0f84392237cbf5f7a816b4161c061829e"}, + {file = "mypy-1.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:26cdd6a22b9b40b2fd71881a8a4f34b4d7914c679f154f43385ca878a8297389"}, + {file = "mypy-1.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5b5f81b40d94c785f288948c16e1f2da37203c6006546c5d947aab6f90aefef2"}, + {file = "mypy-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21b437be1c02712a605591e1ed1d858aba681757a1e55fe678a15c2244cd68a5"}, + {file = "mypy-1.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d809f88734f44a0d44959d795b1e6f64b2bbe0ea4d9cc4776aa588bb4229fc1c"}, + {file = "mypy-1.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:a380c041db500e1410bb5b16b3c1c35e61e773a5c3517926b81dfdab7582be54"}, + {file = "mypy-1.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b7c7b708fe9a871a96626d61912e3f4ddd365bf7f39128362bc50cbd74a634d5"}, + {file = "mypy-1.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1c10fa12df1232c936830839e2e935d090fc9ee315744ac33b8a32216b93707"}, + {file = "mypy-1.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0a28a76785bf57655a8ea5eb0540a15b0e781c807b5aa798bd463779988fa1d5"}, + {file = "mypy-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ef6a01e563ec6a4940784c574d33f6ac1943864634517984471642908b30b6f7"}, + {file = "mypy-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d64c28e03ce40d5303450f547e07418c64c241669ab20610f273c9e6290b4b0b"}, + {file = "mypy-1.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:64cc3afb3e9e71a79d06e3ed24bb508a6d66f782aff7e56f628bf35ba2e0ba51"}, + {file = "mypy-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce61663faf7a8e5ec6f456857bfbcec2901fbdb3ad958b778403f63b9e606a1b"}, + {file = "mypy-1.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2b0c373d071593deefbcdd87ec8db91ea13bd8f1328d44947e88beae21e8d5e9"}, + {file = "mypy-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:2888ce4fe5aae5a673386fa232473014056967f3904f5abfcf6367b5af1f612a"}, + {file = "mypy-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:19ba15f9627a5723e522d007fe708007bae52b93faab00f95d72f03e1afa9598"}, + {file = "mypy-1.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:59bbd71e5c58eed2e992ce6523180e03c221dcd92b52f0e792f291d67b15a71c"}, + {file = "mypy-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9401e33814cec6aec8c03a9548e9385e0e228fc1b8b0a37b9ea21038e64cdd8a"}, + {file = "mypy-1.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4b398d8b1f4fba0e3c6463e02f8ad3346f71956b92287af22c9b12c3ec965a9f"}, + {file = "mypy-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:69b35d1dcb5707382810765ed34da9db47e7f95b3528334a3c999b0c90fe523f"}, + {file = "mypy-1.1.1-py3-none-any.whl", hash = "sha256:4e4e8b362cdf99ba00c2b218036002bdcdf1e0de085cdb296a49df03fb31dfc4"}, + {file = "mypy-1.1.1.tar.gz", hash = "sha256:ae9ceae0f5b9059f33dbc62dea087e942c0ccab4b7a003719cb70f9b8abfa32f"}, +] + +[package.dependencies] +mypy-extensions = ">=1.0.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = ">=3.10" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +install-types = ["pip"] +python2 = ["typed-ast (>=1.4.0,<2)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "nodeenv" +version = "1.9.1" +description = "Node.js virtual environment builder" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, + {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, +] + +[[package]] +name = "openpyxl" +version = "2.5.9" +description = "A Python library to read/write Excel 2010 xlsx/xlsm files" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "openpyxl-2.5.9.tar.gz", hash = "sha256:022c0f3fa1e873cc0ba20651c54dd5e6276fc4ff150b4060723add4fc448645e"}, +] + +[package.dependencies] +et_xmlfile = "*" +jdcal = "*" + +[[package]] +name = "packaging" +version = "24.1" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "phonenumberslite" +version = "8.9.15" +description = "Python version of Google's common library for parsing, formatting, storing and validating international phone numbers." +optional = false +python-versions = "*" +files = [ + {file = "phonenumberslite-8.9.15-py2.py3-none-any.whl", hash = "sha256:570ec0853a2b501bc5e383c935311932d3a3f39bfb7c544dfcc0d0070032ff42"}, + {file = "phonenumberslite-8.9.15.tar.gz", hash = "sha256:c78b269aff4dd731cd8c99960bc67dcd2ac830e23354c5f6d27b0512b8a129be"}, +] + +[[package]] +name = "platformdirs" +version = "4.3.6" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, +] + +[package.extras] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] + +[[package]] +name = "pluggy" +version = "1.5.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pre-commit" +version = "3.2.0" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pre_commit-3.2.0-py2.py3-none-any.whl", hash = "sha256:f712d3688102e13c8e66b7d7dbd8934a6dda157e58635d89f7d6fecdca39ce8a"}, + {file = "pre_commit-3.2.0.tar.gz", hash = "sha256:818f0d998059934d0f81bb3667e3ccdc32da6ed7ccaac33e43dc231561ddaaa9"}, ] [package.dependencies] -typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""} +cfgv = ">=2.0.0" +identify = ">=1.0.0" +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +virtualenv = ">=20.10.0" + +[[package]] +name = "prometheus-client" +version = "0.21.0" +description = "Python client for the Prometheus monitoring system." +optional = false +python-versions = ">=3.8" +files = [ + {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.extras] -tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] +twisted = ["twisted"] [[package]] -name = "django" -version = "4.2.15" -description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." +name = "prompt-toolkit" +version = "3.0.48" +description = "Library for building powerful interactive command lines in Python" +optional = false +python-versions = ">=3.7.0" +files = [ + {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.dependencies] +wcwidth = "*" + +[[package]] +name = "psycopg2-binary" +version = "2.8.6" +description = "psycopg2 - Python-PostgreSQL Database Adapter" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" +files = [ + {file = "psycopg2-binary-2.8.6.tar.gz", hash = "sha256:11b9c0ebce097180129e422379b824ae21c8f2a6596b159c7659e2e5a00e1aa0"}, + {file = "psycopg2_binary-2.8.6-cp27-cp27m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:d14b140a4439d816e3b1229a4a525df917d6ea22a0771a2a78332273fd9528a4"}, + {file = "psycopg2_binary-2.8.6-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:1fabed9ea2acc4efe4671b92c669a213db744d2af8a9fc5d69a8e9bc14b7a9db"}, + {file = "psycopg2_binary-2.8.6-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:f5ab93a2cb2d8338b1674be43b442a7f544a0971da062a5da774ed40587f18f5"}, + {file = "psycopg2_binary-2.8.6-cp27-cp27m-win32.whl", hash = "sha256:b4afc542c0ac0db720cf516dd20c0846f71c248d2b3d21013aa0d4ef9c71ca25"}, + {file = "psycopg2_binary-2.8.6-cp27-cp27m-win_amd64.whl", hash = "sha256:e74a55f6bad0e7d3968399deb50f61f4db1926acf4a6d83beaaa7df986f48b1c"}, + {file = "psycopg2_binary-2.8.6-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:0deac2af1a587ae12836aa07970f5cb91964f05a7c6cdb69d8425ff4c15d4e2c"}, + {file = "psycopg2_binary-2.8.6-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ad20d2eb875aaa1ea6d0f2916949f5c08a19c74d05b16ce6ebf6d24f2c9f75d1"}, + {file = "psycopg2_binary-2.8.6-cp34-cp34m-win32.whl", hash = "sha256:950bc22bb56ee6ff142a2cb9ee980b571dd0912b0334aa3fe0fe3788d860bea2"}, + {file = "psycopg2_binary-2.8.6-cp34-cp34m-win_amd64.whl", hash = "sha256:b8a3715b3c4e604bcc94c90a825cd7f5635417453b253499664f784fc4da0152"}, + {file = "psycopg2_binary-2.8.6-cp35-cp35m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:d1b4ab59e02d9008efe10ceabd0b31e79519da6fb67f7d8e8977118832d0f449"}, + {file = "psycopg2_binary-2.8.6-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:ac0c682111fbf404525dfc0f18a8b5f11be52657d4f96e9fcb75daf4f3984859"}, + {file = "psycopg2_binary-2.8.6-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7d92a09b788cbb1aec325af5fcba9fed7203897bbd9269d5691bb1e3bce29550"}, + {file = "psycopg2_binary-2.8.6-cp35-cp35m-win32.whl", hash = "sha256:aaa4213c862f0ef00022751161df35804127b78adf4a2755b9f991a507e425fd"}, + {file = "psycopg2_binary-2.8.6-cp35-cp35m-win_amd64.whl", hash = "sha256:c2507d796fca339c8fb03216364cca68d87e037c1f774977c8fc377627d01c71"}, + {file = "psycopg2_binary-2.8.6-cp36-cp36m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:ee69dad2c7155756ad114c02db06002f4cded41132cc51378e57aad79cc8e4f4"}, + {file = "psycopg2_binary-2.8.6-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:e82aba2188b9ba309fd8e271702bd0d0fc9148ae3150532bbb474f4590039ffb"}, + {file = "psycopg2_binary-2.8.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d5227b229005a696cc67676e24c214740efd90b148de5733419ac9aaba3773da"}, + {file = "psycopg2_binary-2.8.6-cp36-cp36m-win32.whl", hash = "sha256:a0eb43a07386c3f1f1ebb4dc7aafb13f67188eab896e7397aa1ee95a9c884eb2"}, + {file = "psycopg2_binary-2.8.6-cp36-cp36m-win_amd64.whl", hash = "sha256:e1f57aa70d3f7cc6947fd88636a481638263ba04a742b4a37dd25c373e41491a"}, + {file = "psycopg2_binary-2.8.6-cp37-cp37m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:833709a5c66ca52f1d21d41865a637223b368c0ee76ea54ca5bad6f2526c7679"}, + {file = "psycopg2_binary-2.8.6-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:ba28584e6bca48c59eecbf7efb1576ca214b47f05194646b081717fa628dfddf"}, + {file = "psycopg2_binary-2.8.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:6a32f3a4cb2f6e1a0b15215f448e8ce2da192fd4ff35084d80d5e39da683e79b"}, + {file = "psycopg2_binary-2.8.6-cp37-cp37m-win32.whl", hash = "sha256:0e4dc3d5996760104746e6cfcdb519d9d2cd27c738296525d5867ea695774e67"}, + {file = "psycopg2_binary-2.8.6-cp37-cp37m-win_amd64.whl", hash = "sha256:cec7e622ebc545dbb4564e483dd20e4e404da17ae07e06f3e780b2dacd5cee66"}, + {file = "psycopg2_binary-2.8.6-cp38-cp38-macosx_10_9_x86_64.macosx_10_9_intel.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:ba381aec3a5dc29634f20692349d73f2d21f17653bda1decf0b52b11d694541f"}, + {file = "psycopg2_binary-2.8.6-cp38-cp38-manylinux1_i686.whl", hash = "sha256:a0c50db33c32594305b0ef9abc0cb7db13de7621d2cadf8392a1d9b3c437ef77"}, + {file = "psycopg2_binary-2.8.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2dac98e85565d5688e8ab7bdea5446674a83a3945a8f416ad0110018d1501b94"}, + {file = "psycopg2_binary-2.8.6-cp38-cp38-win32.whl", hash = "sha256:bd1be66dde2b82f80afb9459fc618216753f67109b859a361cf7def5c7968729"}, + {file = "psycopg2_binary-2.8.6-cp38-cp38-win_amd64.whl", hash = "sha256:8cd0fb36c7412996859cb4606a35969dd01f4ea34d9812a141cd920c3b18be77"}, + {file = "psycopg2_binary-2.8.6-cp39-cp39-macosx_10_9_x86_64.macosx_10_9_intel.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:89705f45ce07b2dfa806ee84439ec67c5d9a0ef20154e0e475e2b2ed392a5b83"}, + {file = "psycopg2_binary-2.8.6-cp39-cp39-manylinux1_i686.whl", hash = "sha256:42ec1035841b389e8cc3692277a0bd81cdfe0b65d575a2c8862cec7a80e62e52"}, + {file = "psycopg2_binary-2.8.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7312e931b90fe14f925729cde58022f5d034241918a5c4f9797cac62f6b3a9dd"}, + {file = "psycopg2_binary-2.8.6-cp39-cp39-win32.whl", hash = "sha256:6422f2ff0919fd720195f64ffd8f924c1395d30f9a495f31e2392c2efafb5056"}, + {file = "psycopg2_binary-2.8.6-cp39-cp39-win_amd64.whl", hash = "sha256:15978a1fbd225583dd8cdaf37e67ccc278b5abecb4caf6b2d6b8e2b948e953f6"}, +] + +[[package]] +name = "pycodestyle" +version = "2.10.0" +description = "Python style guide checker" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pycodestyle-2.10.0-py2.py3-none-any.whl", hash = "sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610"}, + {file = "pycodestyle-2.10.0.tar.gz", hash = "sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053"}, +] + +[[package]] +name = "pycountry" +version = "19.8.18" +description = "ISO country, subdivision, language, currency and script definitions and their translations" +optional = false +python-versions = "*" +files = [ + {file = "pycountry-19.8.18.tar.gz", hash = "sha256:3c57aa40adcf293d59bebaffbe60d8c39976fba78d846a018dc0c2ec9c6cb3cb"}, +] + +[[package]] +name = "pyflakes" +version = "3.0.1" +description = "passive checker of Python programs" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pyflakes-3.0.1-py2.py3-none-any.whl", hash = "sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf"}, + {file = "pyflakes-3.0.1.tar.gz", hash = "sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd"}, +] + +[[package]] +name = "pytest" +version = "7.2.1" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.2.1-py3-none-any.whl", hash = "sha256:c7c6ca206e93355074ae32f7403e8ea12163b1163c976fee7d4d84027c162be5"}, + {file = "pytest-7.2.1.tar.gz", hash = "sha256:d45e0952f3727241918b8fd0f376f5ff6b301cc0777c6f9a556935c92d8a7d42"}, +] + +[package.dependencies] +attrs = ">=19.2.0" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] + +[[package]] +name = "pytest-asyncio" +version = "0.21.0" +description = "Pytest support for asyncio" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-asyncio-0.21.0.tar.gz", hash = "sha256:2b38a496aef56f56b0e87557ec313e11e1ab9276fc3863f6a7be0f1d0e415e1b"}, + {file = "pytest_asyncio-0.21.0-py3-none-any.whl", hash = "sha256:f2b3366b7cd501a4056858bd39349d5af19742aed2d81660b7998b6341c7eb9c"}, +] + +[package.dependencies] +pytest = ">=7.0.0" + +[package.extras] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] +testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] + +[[package]] +name = "pytest-cov" +version = "4.0.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.6" +files = [ + {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, + {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, +] + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] + +[[package]] +name = "pytest-django" +version = "4.5.2" +description = "A Django plugin for pytest." +optional = false +python-versions = ">=3.5" +files = [ + {file = "pytest-django-4.5.2.tar.gz", hash = "sha256:d9076f759bb7c36939dbdd5ae6633c18edfc2902d1a69fdbefd2426b970ce6c2"}, + {file = "pytest_django-4.5.2-py3-none-any.whl", hash = "sha256:c60834861933773109334fe5a53e83d1ef4828f2203a1d6a0fa9972f4f75ab3e"}, +] + +[package.dependencies] +pytest = ">=5.4.0" + +[package.extras] +docs = ["sphinx", "sphinx-rtd-theme"] +testing = ["Django", "django-configurations (>=2.0)"] + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pytz" +version = "2024.2" +description = "World timezone definitions, modern and historical" +optional = false +python-versions = "*" +files = [ + {file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"}, + {file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.8" files = [ - {file = "Django-4.2.15-py3-none-any.whl", hash = "sha256:61ee4a130efb8c451ef3467c67ca99fdce400fedd768634efc86a68c18d80d30"}, - {file = "Django-4.2.15.tar.gz", hash = "sha256:c77f926b81129493961e19c0e02188f8d07c112a1162df69bfab178ae447f94a"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {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"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, +] + +[[package]] +name = "rapidpro-python" +version = "2.6.1" +description = "Python client library for the RapidPro" +optional = false +python-versions = "*" +files = [ + {file = "rapidpro-python-2.6.1.tar.gz", hash = "sha256:9dfa15fe9345553433f8a9f8ed9c0c53fdd60382b08a780cf95a317525f0be6f"}, + {file = "rapidpro_python-2.6.1-py2.py3-none-any.whl", hash = "sha256:5ca7174d68faa569f50c0d98858d31af4496cf413c146cd6c8b0f190e9f333d0"}, ] [package.dependencies] -asgiref = ">=3.6.0,<4" -sqlparse = ">=0.3.1" -tzdata = {version = "*", markers = "sys_platform == \"win32\""} +iso8601 = "*" +pytz = "*" +requests = "*" + +[[package]] +name = "raven" +version = "6.9.0" +description = "Raven is a client for Sentry (https://getsentry.com)" +optional = false +python-versions = "*" +files = [ + {file = "raven-6.9.0-py2.py3-none-any.whl", hash = "sha256:95f44f3ea2c1b176d5450df4becdb96c15bf2632888f9ab193e9dd22300ce46a"}, + {file = "raven-6.9.0.tar.gz", hash = "sha256:3fd787d19ebb49919268f06f19310e8112d619ef364f7989246fc8753d469888"}, +] [package.extras] -argon2 = ["argon2-cffi (>=19.1.0)"] -bcrypt = ["bcrypt"] +flask = ["Flask (>=0.8)", "blinker (>=1.1)"] +tests = ["Flask (>=0.8)", "Flask-Login (>=0.2.0)", "ZConfig", "anyjson", "blinker (>=1.1)", "bottle", "celery (>=2.5)", "coverage (<4)", "exam (>=0.5.2)", "flake8 (==3.5.0)", "logbook", "mock", "nose", "paste", "pytest (>=3.2.0,<3.3.0)", "pytest-cov (==2.5.1)", "pytest-flake8 (==1.0.0)", "pytest-pythonpath (==0.7.2)", "pytest-timeout (==1.2.1)", "pytest-xdist (==1.18.2)", "pytz", "requests", "tornado (>=4.1,<5.0)", "tox", "unittest2", "web.py", "webob", "webtest", "wheel"] + +[[package]] +name = "redis" +version = "4.5.4" +description = "Python client for Redis database and key-value store" +optional = false +python-versions = ">=3.7" +files = [ + {file = "redis-4.5.4-py3-none-any.whl", hash = "sha256:2c19e6767c474f2e85167909061d525ed65bea9301c0770bb151e041b7ac89a2"}, + {file = "redis-4.5.4.tar.gz", hash = "sha256:73ec35da4da267d6847e47f68730fdd5f62e2ca69e3ef5885c6a78a9374c3893"}, +] + +[package.dependencies] +async-timeout = {version = ">=4.0.2", markers = "python_version <= \"3.11.2\""} + +[package.extras] +hiredis = ["hiredis (>=1.0.0)"] +ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"] + +[[package]] +name = "requests" +version = "2.32.0" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.8" +files = [ + {file = "requests-2.32.0-py3-none-any.whl", hash = "sha256:f2c3881dddb70d056c5bd7600a4fae312b2a300e39be6a118d30b90bd27262b5"}, + {file = "requests-2.32.0.tar.gz", hash = "sha256:fa5490319474c82ef1d2c9bc459d3652e3ae4ef4c4ebdd18a21145a47ca4b6b8"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "responses" +version = "0.23.1" +description = "A utility library for mocking out the `requests` Python library." +optional = false +python-versions = ">=3.7" +files = [ + {file = "responses-0.23.1-py3-none-any.whl", hash = "sha256:8a3a5915713483bf353b6f4079ba8b2a29029d1d1090a503c70b0dc5d9d0c7bd"}, + {file = "responses-0.23.1.tar.gz", hash = "sha256:c4d9aa9fc888188f0c673eff79a8dadbe2e75b7fe879dc80a221a06e0a68138f"}, +] + +[package.dependencies] +pyyaml = "*" +requests = ">=2.22.0,<3.0" +types-PyYAML = "*" +urllib3 = ">=1.25.10" + +[package.extras] +tests = ["coverage (>=6.0.0)", "flake8", "mypy", "pytest (>=7.0.0)", "pytest-asyncio", "pytest-cov", "pytest-httpserver", "tomli", "tomli-w", "types-requests"] + +[[package]] +name = "setuptools" +version = "59.6.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.6" +files = [ + {file = "setuptools-59.6.0-py3-none-any.whl", hash = "sha256:4ce92f1e1f8f01233ee9952c04f6b81d1e02939d6e1b488428154974a4d0783e"}, + {file = "setuptools-59.6.0.tar.gz", hash = "sha256:22c7348c6d2976a52632c67f7ab0cdf40147db7789f9aed18734643fe9cf3373"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=8.2)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx", "sphinx-inline-tabs", "sphinxcontrib-towncrier"] +testing = ["flake8-2020", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mock", "paver", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-flake8", "pytest-mypy", "pytest-virtualenv (>=1.2.7)", "pytest-xdist", "sphinx", "virtualenv (>=13.0.0)", "wheel"] + +[[package]] +name = "six" +version = "1.11.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = "*" +files = [ + {file = "six-1.11.0-py2.py3-none-any.whl", hash = "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"}, + {file = "six-1.11.0.tar.gz", hash = "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9"}, +] [[package]] name = "sqlparse" @@ -52,6 +1549,47 @@ files = [ dev = ["build", "hatch"] doc = ["sphinx"] +[[package]] +name = "structlog" +version = "18.2.0" +description = "Structured Logging for Python" +optional = false +python-versions = "*" +files = [ + {file = "structlog-18.2.0-py2.py3-none-any.whl", hash = "sha256:e912c03a3cf6876803c3f1b1e4b09dd4b9e4bcd0977586cb59cf538351ba6b1b"}, + {file = "structlog-18.2.0.tar.gz", hash = "sha256:e361edb3b9aeaa85cd38a1bc9ddbb60cda8a991fc29de9db26832f6300e81eb4"}, +] + +[package.dependencies] +six = "*" + +[package.extras] +dev = ["colorama"] +docs = ["sphinx", "twisted"] +tests = ["coverage", "freezegun (>=0.2.8)", "pretend", "pytest (>=3.3.0)", "python-rapidjson", "simplejson"] + +[[package]] +name = "tomli" +version = "2.0.2" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38"}, + {file = "tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"}, +] + +[[package]] +name = "types-pyyaml" +version = "6.0.12.20240917" +description = "Typing stubs for PyYAML" +optional = false +python-versions = ">=3.8" +files = [ + {file = "types-PyYAML-6.0.12.20240917.tar.gz", hash = "sha256:d1405a86f9576682234ef83bcb4e6fff7c9305c8b1fbad5e0bcd4f7dbdc9c587"}, + {file = "types_PyYAML-6.0.12.20240917-py3-none-any.whl", hash = "sha256:392b267f1c0fe6022952462bf5d6523f31e37f6cea49b14cee7ad634b6301570"}, +] + [[package]] name = "typing-extensions" version = "4.12.2" @@ -74,7 +1612,77 @@ files = [ {file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"}, ] +[[package]] +name = "uritemplate" +version = "4.1.1" +description = "Implementation of RFC 6570 URI Templates" +optional = false +python-versions = ">=3.6" +files = [ + {file = "uritemplate-4.1.1-py2.py3-none-any.whl", hash = "sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e"}, + {file = "uritemplate-4.1.1.tar.gz", hash = "sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0"}, +] + +[[package]] +name = "urllib3" +version = "2.2.3" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.8" +files = [ + {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, + {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "vine" +version = "5.1.0" +description = "Python promises." +optional = false +python-versions = ">=3.6" +files = [ + {file = "vine-5.1.0-py3-none-any.whl", hash = "sha256:40fdf3c48b2cfe1c38a49e9ae2da6fda88e4794c810050a728bd7413811fb1dc"}, + {file = "vine-5.1.0.tar.gz", hash = "sha256:8b62e981d35c41049211cf62a0a1242d8c1ee9bd15bb196ce38aefd6799e61e0"}, +] + +[[package]] +name = "virtualenv" +version = "20.26.6" +description = "Virtual Python Environment builder" +optional = false +python-versions = ">=3.7" +files = [ + {file = "virtualenv-20.26.6-py3-none-any.whl", hash = "sha256:7345cc5b25405607a624d8418154577459c3e0277f5466dd79c49d5e492995f2"}, + {file = "virtualenv-20.26.6.tar.gz", hash = "sha256:280aede09a2a5c317e409a00102e7077c6432c5a38f0ef938e643805a7ad2c48"}, +] + +[package.dependencies] +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +platformdirs = ">=3.9.1,<5" + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] + +[[package]] +name = "wcwidth" +version = "0.2.13" +description = "Measures the displayed width of unicode strings in a terminal" +optional = false +python-versions = "*" +files = [ + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, +] + [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "4c4538d91778157bbe1714de368213dc86323cbd6271742ae9aef6bd7b204a0c" +content-hash = "675edc2b0ab5e0616744c6ea997420cad87f65dcb22da67ceffad4c169a9d1fd" diff --git a/pyproject.toml b/pyproject.toml index a4063c63..64b998fc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,6 @@ readme = "README.md" packages = [ { include = "aaq" }, - { include = "ada" }, { include = "changes" }, { include = "eventstore" }, { include = "mqr" }, @@ -36,11 +35,81 @@ structlog = "18.2.0" phonenumberslite = "8.9.15" django-simple-history = "3.3.0" openpyxl = "2.5.9" -iso-639 = "0.4.5" +iso-639 = {git = "https://github.com/noumar/iso639.git", tag = "0.4.5"} django-prometheus = "2.2.0" rapidpro-python = "2.6.1" pycountry = "19.8.18" +attrs = "*" +iso6709 = "0.1.5" +redis = "4.5.4" +django-redis = "5.2.0" +celery_batches = "0.7" +python-dateutil = "2.8.2" +[tool.poetry.group.dev.dependencies] +pytest = "7.2.1" +pytest-cov = "4.0.0" +pytest-django = "4.5.2" +pytest-asyncio = "0.21.0" +flake8 = "6.0.0" +responses = "0.23.1" +mypy = "1.1.1" +black = "24.3.0" +isort = "5.12.0" +pre-commit = "3.2.0" +freezegun = "1.2.2" +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" +[tool.ruff] +extend-exclude = [ + "*/migrations/*.py", + "docs/conf.py", +] + +[tool.ruff.lint] +select = [ + "E", "F", "W", # pycodestyle + pyflakes == flake8 - mccabe + "I", # isort + "UP", # pyupgrade + "S", # flake8-bandit + "B", # flake8-bugbear + "C4", # flake8-comprehensions + # "DJ", # flake8-django + "PIE", # flake8-pie + # "PT", # flake8-pytest-style + "SIM", # flake8-simplify + "PTH", # flake8-use-pathlib + # "RUF", # ruff-specific rules +] + +ignore = [ + "E501", # TODO: Something about these long lines. + "S113", # TODO: Add request timeouts. + "PTH118", # TODO: Switch to pathlib + "PTH100", # TODO: `os.path.abspath()` should be replaced by `Path.resolve()` maybe use pathlib? + "PTH120", # TODO: `os.path.dirname()` should be replaced by `Path.parent` maybe use pathlib? + +] + +[tool.ruff.lint.per-file-ignores] +"**/tests/**" = [ + "S101", # It's okay to use `assert` in tests. + "S106", # TODO: Possible hardcoded password assigned to argument: "TURN_AUTH_TOKEN" +] + +# TODO: Move this somewhere sensible? +"**/tests.py" = [ + "S101", # It's okay to use `assert` in tests. + "S106", # TODO: Possible hardcoded password assigned to argument: "TURN_AUTH_TOKEN" +] + +"**/config/settings/{test,dev}.py" = [ + "S104", # It's okay to bind to all interfaces in tests + "F405", # Its okay to import * in settings + "S105", # Its okay to have hardcoded secrets in test config + +] \ No newline at end of file From 9996a04dc170a4e069dc187b39e4242cd6ecfe70 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Thu, 17 Oct 2024 11:46:07 +0200 Subject: [PATCH 03/41] Perparing to remove pip --- poetry.lock | 209 +++++++------------------------------------------ pyproject.toml | 7 +- 2 files changed, 29 insertions(+), 187 deletions(-) diff --git a/poetry.lock b/poetry.lock index b87b3fef..d4841c24 100644 --- a/poetry.lock +++ b/poetry.lock @@ -72,52 +72,6 @@ files = [ {file = "billiard-3.6.4.0.tar.gz", hash = "sha256:299de5a8da28a783d51b197d496bef4f1595dd023a93a4f59dde1886ae905547"}, ] -[[package]] -name = "black" -version = "24.3.0" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.8" -files = [ - {file = "black-24.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7d5e026f8da0322b5662fa7a8e752b3fa2dac1c1cbc213c3d7ff9bdd0ab12395"}, - {file = "black-24.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9f50ea1132e2189d8dff0115ab75b65590a3e97de1e143795adb4ce317934995"}, - {file = "black-24.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2af80566f43c85f5797365077fb64a393861a3730bd110971ab7a0c94e873e7"}, - {file = "black-24.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:4be5bb28e090456adfc1255e03967fb67ca846a03be7aadf6249096100ee32d0"}, - {file = "black-24.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4f1373a7808a8f135b774039f61d59e4be7eb56b2513d3d2f02a8b9365b8a8a9"}, - {file = "black-24.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aadf7a02d947936ee418777e0247ea114f78aff0d0959461057cae8a04f20597"}, - {file = "black-24.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c02e4ea2ae09d16314d30912a58ada9a5c4fdfedf9512d23326128ac08ac3d"}, - {file = "black-24.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:bf21b7b230718a5f08bd32d5e4f1db7fc8788345c8aea1d155fc17852b3410f5"}, - {file = "black-24.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:2818cf72dfd5d289e48f37ccfa08b460bf469e67fb7c4abb07edc2e9f16fb63f"}, - {file = "black-24.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4acf672def7eb1725f41f38bf6bf425c8237248bb0804faa3965c036f7672d11"}, - {file = "black-24.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7ed6668cbbfcd231fa0dc1b137d3e40c04c7f786e626b405c62bcd5db5857e4"}, - {file = "black-24.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:56f52cfbd3dabe2798d76dbdd299faa046a901041faf2cf33288bc4e6dae57b5"}, - {file = "black-24.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:79dcf34b33e38ed1b17434693763301d7ccbd1c5860674a8f871bd15139e7837"}, - {file = "black-24.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e19cb1c6365fd6dc38a6eae2dcb691d7d83935c10215aef8e6c38edee3f77abd"}, - {file = "black-24.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65b76c275e4c1c5ce6e9870911384bff5ca31ab63d19c76811cb1fb162678213"}, - {file = "black-24.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:b5991d523eee14756f3c8d5df5231550ae8993e2286b8014e2fdea7156ed0959"}, - {file = "black-24.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c45f8dff244b3c431b36e3224b6be4a127c6aca780853574c00faf99258041eb"}, - {file = "black-24.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6905238a754ceb7788a73f02b45637d820b2f5478b20fec82ea865e4f5d4d9f7"}, - {file = "black-24.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7de8d330763c66663661a1ffd432274a2f92f07feeddd89ffd085b5744f85e7"}, - {file = "black-24.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:7bb041dca0d784697af4646d3b62ba4a6b028276ae878e53f6b4f74ddd6db99f"}, - {file = "black-24.3.0-py3-none-any.whl", hash = "sha256:41622020d7120e01d377f74249e677039d20e6344ff5851de8a10f11f513bf93"}, - {file = "black-24.3.0.tar.gz", hash = "sha256:a0c9c4a0771afc6919578cec71ce82a3e31e054904e7197deacbc9382671c41f"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - [[package]] name = "celery" version = "5.2.3" @@ -692,22 +646,6 @@ docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2. testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"] typing = ["typing-extensions (>=4.12.2)"] -[[package]] -name = "flake8" -version = "6.0.0" -description = "the modular source code checker: pep8 pyflakes and co" -optional = false -python-versions = ">=3.8.1" -files = [ - {file = "flake8-6.0.0-py2.py3-none-any.whl", hash = "sha256:3833794e27ff64ea4e9cf5d410082a8b97ff1a06c16aa3d2027339cd0f1195c7"}, - {file = "flake8-6.0.0.tar.gz", hash = "sha256:c61007e76655af75e6785a931f452915b371dc48f56efd765247c8fe68f2b181"}, -] - -[package.dependencies] -mccabe = ">=0.7.0,<0.8.0" -pycodestyle = ">=2.10.0,<2.11.0" -pyflakes = ">=3.0.0,<3.1.0" - [[package]] name = "freezegun" version = "1.2.2" @@ -798,23 +736,6 @@ files = [ {file = "iso8601-2.1.0.tar.gz", hash = "sha256:6b1d3829ee8921c4301998c909f7829fa9ed3cbdac0d3b16af2d743aed1ba8df"}, ] -[[package]] -name = "isort" -version = "5.12.0" -description = "A Python utility / library to sort Python imports." -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, - {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, -] - -[package.extras] -colors = ["colorama (>=0.4.3)"] -pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] -plugins = ["setuptools"] -requirements-deprecated-finder = ["pip-api", "pipreqs"] - [[package]] name = "itypes" version = "1.2.0" @@ -975,74 +896,6 @@ files = [ {file = "markupsafe-3.0.1.tar.gz", hash = "sha256:3e683ee4f5d0fa2dde4db77ed8dd8a876686e3fc417655c2ece9a90576905344"}, ] -[[package]] -name = "mccabe" -version = "0.7.0" -description = "McCabe checker, plugin for flake8" -optional = false -python-versions = ">=3.6" -files = [ - {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, - {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, -] - -[[package]] -name = "mypy" -version = "1.1.1" -description = "Optional static typing for Python" -optional = false -python-versions = ">=3.7" -files = [ - {file = "mypy-1.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39c7119335be05630611ee798cc982623b9e8f0cff04a0b48dfc26100e0b97af"}, - {file = "mypy-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:61bf08362e93b6b12fad3eab68c4ea903a077b87c90ac06c11e3d7a09b56b9c1"}, - {file = "mypy-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbb19c9f662e41e474e0cff502b7064a7edc6764f5262b6cd91d698163196799"}, - {file = "mypy-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:315ac73cc1cce4771c27d426b7ea558fb4e2836f89cb0296cbe056894e3a1f78"}, - {file = "mypy-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:5cb14ff9919b7df3538590fc4d4c49a0f84392237cbf5f7a816b4161c061829e"}, - {file = "mypy-1.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:26cdd6a22b9b40b2fd71881a8a4f34b4d7914c679f154f43385ca878a8297389"}, - {file = "mypy-1.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5b5f81b40d94c785f288948c16e1f2da37203c6006546c5d947aab6f90aefef2"}, - {file = "mypy-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21b437be1c02712a605591e1ed1d858aba681757a1e55fe678a15c2244cd68a5"}, - {file = "mypy-1.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d809f88734f44a0d44959d795b1e6f64b2bbe0ea4d9cc4776aa588bb4229fc1c"}, - {file = "mypy-1.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:a380c041db500e1410bb5b16b3c1c35e61e773a5c3517926b81dfdab7582be54"}, - {file = "mypy-1.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b7c7b708fe9a871a96626d61912e3f4ddd365bf7f39128362bc50cbd74a634d5"}, - {file = "mypy-1.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1c10fa12df1232c936830839e2e935d090fc9ee315744ac33b8a32216b93707"}, - {file = "mypy-1.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0a28a76785bf57655a8ea5eb0540a15b0e781c807b5aa798bd463779988fa1d5"}, - {file = "mypy-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ef6a01e563ec6a4940784c574d33f6ac1943864634517984471642908b30b6f7"}, - {file = "mypy-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d64c28e03ce40d5303450f547e07418c64c241669ab20610f273c9e6290b4b0b"}, - {file = "mypy-1.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:64cc3afb3e9e71a79d06e3ed24bb508a6d66f782aff7e56f628bf35ba2e0ba51"}, - {file = "mypy-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce61663faf7a8e5ec6f456857bfbcec2901fbdb3ad958b778403f63b9e606a1b"}, - {file = "mypy-1.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2b0c373d071593deefbcdd87ec8db91ea13bd8f1328d44947e88beae21e8d5e9"}, - {file = "mypy-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:2888ce4fe5aae5a673386fa232473014056967f3904f5abfcf6367b5af1f612a"}, - {file = "mypy-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:19ba15f9627a5723e522d007fe708007bae52b93faab00f95d72f03e1afa9598"}, - {file = "mypy-1.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:59bbd71e5c58eed2e992ce6523180e03c221dcd92b52f0e792f291d67b15a71c"}, - {file = "mypy-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9401e33814cec6aec8c03a9548e9385e0e228fc1b8b0a37b9ea21038e64cdd8a"}, - {file = "mypy-1.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4b398d8b1f4fba0e3c6463e02f8ad3346f71956b92287af22c9b12c3ec965a9f"}, - {file = "mypy-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:69b35d1dcb5707382810765ed34da9db47e7f95b3528334a3c999b0c90fe523f"}, - {file = "mypy-1.1.1-py3-none-any.whl", hash = "sha256:4e4e8b362cdf99ba00c2b218036002bdcdf1e0de085cdb296a49df03fb31dfc4"}, - {file = "mypy-1.1.1.tar.gz", hash = "sha256:ae9ceae0f5b9059f33dbc62dea087e942c0ccab4b7a003719cb70f9b8abfa32f"}, -] - -[package.dependencies] -mypy-extensions = ">=1.0.0" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = ">=3.10" - -[package.extras] -dmypy = ["psutil (>=4.0)"] -install-types = ["pip"] -python2 = ["typed-ast (>=1.4.0,<2)"] -reports = ["lxml"] - -[[package]] -name = "mypy-extensions" -version = "1.0.0" -description = "Type system extensions for programs checked with the mypy type checker." -optional = false -python-versions = ">=3.5" -files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, -] - [[package]] name = "nodeenv" version = "1.9.1" @@ -1079,17 +932,6 @@ files = [ {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] -[[package]] -name = "pathspec" -version = "0.12.1" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, - {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, -] - [[package]] name = "phonenumberslite" version = "8.9.15" @@ -1222,17 +1064,6 @@ files = [ {file = "psycopg2_binary-2.8.6-cp39-cp39-win_amd64.whl", hash = "sha256:15978a1fbd225583dd8cdaf37e67ccc278b5abecb4caf6b2d6b8e2b948e953f6"}, ] -[[package]] -name = "pycodestyle" -version = "2.10.0" -description = "Python style guide checker" -optional = false -python-versions = ">=3.6" -files = [ - {file = "pycodestyle-2.10.0-py2.py3-none-any.whl", hash = "sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610"}, - {file = "pycodestyle-2.10.0.tar.gz", hash = "sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053"}, -] - [[package]] name = "pycountry" version = "19.8.18" @@ -1243,17 +1074,6 @@ files = [ {file = "pycountry-19.8.18.tar.gz", hash = "sha256:3c57aa40adcf293d59bebaffbe60d8c39976fba78d846a018dc0c2ec9c6cb3cb"}, ] -[[package]] -name = "pyflakes" -version = "3.0.1" -description = "passive checker of Python programs" -optional = false -python-versions = ">=3.6" -files = [ - {file = "pyflakes-3.0.1-py2.py3-none-any.whl", hash = "sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf"}, - {file = "pyflakes-3.0.1.tar.gz", hash = "sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd"}, -] - [[package]] name = "pytest" version = "7.2.1" @@ -1508,6 +1328,33 @@ urllib3 = ">=1.25.10" [package.extras] tests = ["coverage (>=6.0.0)", "flake8", "mypy", "pytest (>=7.0.0)", "pytest-asyncio", "pytest-cov", "pytest-httpserver", "tomli", "tomli-w", "types-requests"] +[[package]] +name = "ruff" +version = "0.6.9" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.6.9-py3-none-linux_armv6l.whl", hash = "sha256:064df58d84ccc0ac0fcd63bc3090b251d90e2a372558c0f057c3f75ed73e1ccd"}, + {file = "ruff-0.6.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:140d4b5c9f5fc7a7b074908a78ab8d384dd7f6510402267bc76c37195c02a7ec"}, + {file = "ruff-0.6.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53fd8ca5e82bdee8da7f506d7b03a261f24cd43d090ea9db9a1dc59d9313914c"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645d7d8761f915e48a00d4ecc3686969761df69fb561dd914a773c1a8266e14e"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eae02b700763e3847595b9d2891488989cac00214da7f845f4bcf2989007d577"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d5ccc9e58112441de8ad4b29dcb7a86dc25c5f770e3c06a9d57e0e5eba48829"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:417b81aa1c9b60b2f8edc463c58363075412866ae4e2b9ab0f690dc1e87ac1b5"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c866b631f5fbce896a74a6e4383407ba7507b815ccc52bcedabb6810fdb3ef7"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b118afbb3202f5911486ad52da86d1d52305b59e7ef2031cea3425142b97d6f"}, + {file = "ruff-0.6.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a67267654edc23c97335586774790cde402fb6bbdb3c2314f1fc087dee320bfa"}, + {file = "ruff-0.6.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3ef0cc774b00fec123f635ce5c547dac263f6ee9fb9cc83437c5904183b55ceb"}, + {file = "ruff-0.6.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:12edd2af0c60fa61ff31cefb90aef4288ac4d372b4962c2864aeea3a1a2460c0"}, + {file = "ruff-0.6.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:55bb01caeaf3a60b2b2bba07308a02fca6ab56233302406ed5245180a05c5625"}, + {file = "ruff-0.6.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:925d26471fa24b0ce5a6cdfab1bb526fb4159952385f386bdcc643813d472039"}, + {file = "ruff-0.6.9-py3-none-win32.whl", hash = "sha256:eb61ec9bdb2506cffd492e05ac40e5bc6284873aceb605503d8494180d6fc84d"}, + {file = "ruff-0.6.9-py3-none-win_amd64.whl", hash = "sha256:785d31851c1ae91f45b3d8fe23b8ae4b5170089021fbb42402d811135f0b7117"}, + {file = "ruff-0.6.9-py3-none-win_arm64.whl", hash = "sha256:a9641e31476d601f83cd602608739a0840e348bda93fec9f1ee816f8b6798b93"}, + {file = "ruff-0.6.9.tar.gz", hash = "sha256:b076ef717a8e5bc819514ee1d602bbdca5b4420ae13a9cf61a0c0a4f53a2baa2"}, +] + [[package]] name = "setuptools" version = "59.6.0" @@ -1685,4 +1532,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "675edc2b0ab5e0616744c6ea997420cad87f65dcb22da67ceffad4c169a9d1fd" +content-hash = "6d0afc0c6e8a5683f6a70c5c7be3a2ef9c8282dd26712c8276c42777d78d58b4" diff --git a/pyproject.toml b/pyproject.toml index 64b998fc..8e1ac16f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,8 +11,6 @@ packages = [ { include = "aaq" }, { include = "changes" }, { include = "eventstore" }, - { include = "mqr" }, - { include = "ndoh-hub" }, { include = "registrations" }, ] @@ -47,15 +45,12 @@ celery_batches = "0.7" python-dateutil = "2.8.2" [tool.poetry.group.dev.dependencies] +ruff = "^0.6.9" pytest = "7.2.1" pytest-cov = "4.0.0" pytest-django = "4.5.2" pytest-asyncio = "0.21.0" -flake8 = "6.0.0" responses = "0.23.1" -mypy = "1.1.1" -black = "24.3.0" -isort = "5.12.0" pre-commit = "3.2.0" freezegun = "1.2.2" From a45b7774d8c692d0c13dbbcd00031eebc7a59247 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Thu, 17 Oct 2024 12:15:00 +0200 Subject: [PATCH 04/41] Unpinned versions --- poetry.lock | 372 ++++++++++++++++++++++++------------------- pyproject.toml | 65 ++++---- requirements-dev.txt | 11 -- requirements.txt | 2 - setup.py | 49 ------ 5 files changed, 241 insertions(+), 258 deletions(-) delete mode 100644 requirements-dev.txt delete mode 100644 requirements.txt delete mode 100644 setup.py diff --git a/poetry.lock b/poetry.lock index d4841c24..b33e4d3d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -74,13 +74,13 @@ files = [ [[package]] name = "celery" -version = "5.2.3" +version = "5.2.7" description = "Distributed Task Queue." optional = false -python-versions = ">=3.7," +python-versions = ">=3.7" files = [ - {file = "celery-5.2.3-py3-none-any.whl", hash = "sha256:8aacd02fc23a02760686d63dde1eb0daa9f594e735e73ea8fb15c2ff15cb608c"}, - {file = "celery-5.2.3.tar.gz", hash = "sha256:e2cd41667ad97d4f6a2f4672d1c6a6ebada194c619253058b5f23704aaadaa82"}, + {file = "celery-5.2.7-py3-none-any.whl", hash = "sha256:138420c020cd58d6707e6257b6beda91fd39af7afde5d36c6334d175302c0e14"}, + {file = "celery-5.2.7.tar.gz", hash = "sha256:fafbd82934d30f8a004f81e8f7a062e31413a23d444be8ee3326553915958c6d"}, ] [package.dependencies] @@ -91,7 +91,6 @@ click-plugins = ">=1.1.1" click-repl = ">=0.2.0" kombu = ">=5.2.3,<6.0" pytz = ">=2021.3" -setuptools = ">=59.1.1,<59.7.0" vine = ">=5.0.0,<6.0" [package.extras] @@ -486,27 +485,28 @@ files = [ [[package]] name = "dj-database-url" -version = "1.2.0" +version = "1.3.0" description = "Use Database URLs in your Django Application." optional = false python-versions = "*" files = [ - {file = "dj-database-url-1.2.0.tar.gz", hash = "sha256:b23b15046cb38180e0c95207bcc90fe5e9dbde8eef16065907dd85cf4ca7036c"}, - {file = "dj_database_url-1.2.0-py3-none-any.whl", hash = "sha256:5c2993b91801c0f78a8b19e642b497b90831124cbade0c265900d4c1037b4730"}, + {file = "dj-database-url-1.3.0.tar.gz", hash = "sha256:87be5f7c4c83d9b3d8ce94b834f96cea14b3986f3629aac097afdd9318d7b098"}, + {file = "dj_database_url-1.3.0-py3-none-any.whl", hash = "sha256:80a115bd7675c9fe14a900b2f8b5c8b1822b5a279b333bf9b2804de681656c7c"}, ] [package.dependencies] Django = ">=3.2" +typing-extensions = ">=3.10.0.0" [[package]] name = "django" -version = "4.2.15" +version = "4.2.16" description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." optional = false python-versions = ">=3.8" files = [ - {file = "Django-4.2.15-py3-none-any.whl", hash = "sha256:61ee4a130efb8c451ef3467c67ca99fdce400fedd768634efc86a68c18d80d30"}, - {file = "Django-4.2.15.tar.gz", hash = "sha256:c77f926b81129493961e19c0e02188f8d07c112a1162df69bfab178ae447f94a"}, + {file = "Django-4.2.16-py3-none-any.whl", hash = "sha256:1ddc333a16fc139fd253035a1606bb24261951bbc3a6ca256717fa06cc41a898"}, + {file = "Django-4.2.16.tar.gz", hash = "sha256:6f1616c2786c408ce86ab7e10f792b8f15742f7b7b7460243929cb371e7f1dad"}, ] [package.dependencies] @@ -550,13 +550,13 @@ Django = ">=2.2" [[package]] name = "django-prometheus" -version = "2.2.0" +version = "2.3.1" description = "Django middlewares to monitor your application with Prometheus.io." optional = false python-versions = "*" files = [ - {file = "django-prometheus-2.2.0.tar.gz", hash = "sha256:240378a1307c408bd5fc85614a3a57f1ce633d4a222c9e291e2bbf325173b801"}, - {file = "django_prometheus-2.2.0-py2.py3-none-any.whl", hash = "sha256:e6616770d8820b8834762764bf1b76ec08e1b98e72a6f359d488a2e15fe3537c"}, + {file = "django-prometheus-2.3.1.tar.gz", hash = "sha256:f9c8b6c780c9419ea01043c63a437d79db2c33353451347894408184ad9c3e1e"}, + {file = "django_prometheus-2.3.1-py2.py3-none-any.whl", hash = "sha256:cf9b26f7ba2e4568f08f8f91480a2882023f5908579681bcf06a4d2465f12168"}, ] [package.dependencies] @@ -564,17 +564,17 @@ prometheus-client = ">=0.7" [[package]] name = "django-redis" -version = "5.2.0" +version = "5.4.0" description = "Full featured redis cache backend for Django." optional = false python-versions = ">=3.6" files = [ - {file = "django-redis-5.2.0.tar.gz", hash = "sha256:8a99e5582c79f894168f5865c52bd921213253b7fd64d16733ae4591564465de"}, - {file = "django_redis-5.2.0-py3-none-any.whl", hash = "sha256:1d037dc02b11ad7aa11f655d26dac3fb1af32630f61ef4428860a2e29ff92026"}, + {file = "django-redis-5.4.0.tar.gz", hash = "sha256:6a02abaa34b0fea8bf9b707d2c363ab6adc7409950b2db93602e6cb292818c42"}, + {file = "django_redis-5.4.0-py3-none-any.whl", hash = "sha256:ebc88df7da810732e2af9987f7f426c96204bf89319df4c6da6ca9a2942edd5b"}, ] [package.dependencies] -Django = ">=2.2" +Django = ">=3.2" redis = ">=3,<4.0.0 || >4.0.0,<4.0.1 || >4.0.1" [package.extras] @@ -582,15 +582,18 @@ hiredis = ["redis[hiredis] (>=3,!=4.0.0,!=4.0.1)"] [[package]] name = "django-simple-history" -version = "3.3.0" +version = "3.7.0" description = "Store model history and view/revert changes from admin site." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "django-simple-history-3.3.0.tar.gz", hash = "sha256:2313d2d346f15a1e7a92adb3b6696b226f1cd0c1d920869ec40c4c4076614c41"}, - {file = "django_simple_history-3.3.0-py3-none-any.whl", hash = "sha256:dc1f98e558a0a1e0b6371c3b8efb85f86e02a6db56e83d0ec198343b7408d00a"}, + {file = "django_simple_history-3.7.0-py3-none-any.whl", hash = "sha256:282cb2c4aa63f51547f17da7f2130abaa81ba01694676d19b88d52c94a57a52c"}, + {file = "django_simple_history-3.7.0.tar.gz", hash = "sha256:ac3b7ca8b0d33f7ea6be8fe7fc98cf43415efa500ff5dfe736fbd1ebc0cf39f9"}, ] +[package.dependencies] +django = ">=4.2" + [[package]] name = "djangorestframework" version = "3.15.2" @@ -648,13 +651,13 @@ typing = ["typing-extensions (>=4.12.2)"] [[package]] name = "freezegun" -version = "1.2.2" +version = "1.5.1" description = "Let your Python tests travel through time" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "freezegun-1.2.2-py3-none-any.whl", hash = "sha256:ea1b963b993cb9ea195adbd893a48d573fda951b0da64f60883d7e988b606c9f"}, - {file = "freezegun-1.2.2.tar.gz", hash = "sha256:cd22d1ba06941384410cd967d8a99d5ae2442f57dfafeff2fda5de8dc5c05446"}, + {file = "freezegun-1.5.1-py3-none-any.whl", hash = "sha256:bf111d7138a8abe55ab48a71755673dbaa4ab87f4cff5634a4442dfec34c15f1"}, + {file = "freezegun-1.5.1.tar.gz", hash = "sha256:b29dedfcda6d5e8e083ce71b2b542753ad48cfec44037b3fc79702e2980a89e9"}, ] [package.dependencies] @@ -688,6 +691,29 @@ files = [ [package.extras] all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] +[[package]] +name = "importlib-metadata" +version = "8.5.0" +description = "Read metadata from Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"}, + {file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"}, +] + +[package.dependencies] +zipp = ">=3.20" + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +perf = ["ipython"] +test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +type = ["pytest-mypy"] + [[package]] name = "iniconfig" version = "2.0.0" @@ -699,21 +725,6 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] -[[package]] -name = "iso-639" -version = "0.4.5" -description = "Python library for ISO 639 standard" -optional = false -python-versions = "*" -files = [] -develop = false - -[package.source] -type = "git" -url = "https://github.com/noumar/iso639.git" -reference = "0.4.5" -resolved_reference = "2175cf04b8b8cec79d99a6c4ad31295d67c22cd6" - [[package]] name = "iso6709" version = "0.1.5" @@ -727,13 +738,13 @@ files = [ [[package]] name = "iso8601" -version = "2.1.0" +version = "0.1.16" description = "Simple module to parse ISO 8601 dates" optional = false -python-versions = ">=3.7,<4.0" +python-versions = "*" files = [ - {file = "iso8601-2.1.0-py3-none-any.whl", hash = "sha256:aac4145c4dcb66ad8b648a02830f5e2ff6c24af20f4f482689be402db2429242"}, - {file = "iso8601-2.1.0.tar.gz", hash = "sha256:6b1d3829ee8921c4301998c909f7829fa9ed3cbdac0d3b16af2d743aed1ba8df"}, + {file = "iso8601-0.1.16-py2.py3-none-any.whl", hash = "sha256:906714829fedbc89955d52806c903f2332e3948ed94e31e85037f9e0226b8376"}, + {file = "iso8601-0.1.16.tar.gz", hash = "sha256:36532f77cc800594e8f16641edae7f1baf7932f05d8e508545b95fc53c6dc85b"}, ] [[package]] @@ -811,19 +822,20 @@ zookeeper = ["kazoo (>=2.8.0)"] [[package]] name = "markdown" -version = "3.1.1" -description = "Python implementation of Markdown." +version = "3.7" +description = "Python implementation of John Gruber's Markdown." optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" +python-versions = ">=3.8" files = [ - {file = "Markdown-3.1.1-py2.py3-none-any.whl", hash = "sha256:56a46ac655704b91e5b7e6326ce43d5ef72411376588afa1dd90e881b83c7e8c"}, - {file = "Markdown-3.1.1.tar.gz", hash = "sha256:2e50876bcdd74517e7b71f3e7a76102050edec255b3983403f1a63e7c8a41e7a"}, + {file = "Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803"}, + {file = "markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2"}, ] [package.dependencies] -setuptools = ">=36" +importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} [package.extras] +docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.5)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"] testing = ["coverage", "pyyaml"] [[package]] @@ -909,12 +921,12 @@ files = [ [[package]] name = "openpyxl" -version = "2.5.9" +version = "2.6.4" description = "A Python library to read/write Excel 2010 xlsx/xlsm files" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ - {file = "openpyxl-2.5.9.tar.gz", hash = "sha256:022c0f3fa1e873cc0ba20651c54dd5e6276fc4ff150b4060723add4fc448645e"}, + {file = "openpyxl-2.6.4.tar.gz", hash = "sha256:1d53801678e18d7fe38c116f1ad0c2383a654670c4c8806105b611c92d92f2e3"}, ] [package.dependencies] @@ -934,13 +946,13 @@ files = [ [[package]] name = "phonenumberslite" -version = "8.9.15" +version = "8.13.47" description = "Python version of Google's common library for parsing, formatting, storing and validating international phone numbers." optional = false python-versions = "*" files = [ - {file = "phonenumberslite-8.9.15-py2.py3-none-any.whl", hash = "sha256:570ec0853a2b501bc5e383c935311932d3a3f39bfb7c544dfcc0d0070032ff42"}, - {file = "phonenumberslite-8.9.15.tar.gz", hash = "sha256:c78b269aff4dd731cd8c99960bc67dcd2ac830e23354c5f6d27b0512b8a129be"}, + {file = "phonenumberslite-8.13.47-py2.py3-none-any.whl", hash = "sha256:baf770804c056a122c76f0d29d3a85bd3111c511c5350548e1c3355449b824e9"}, + {file = "phonenumberslite-8.13.47.tar.gz", hash = "sha256:9a4d040f4ef9ea5cbbd907f6fe9a52313d46191051e3a9994102c05082a9db67"}, ] [[package]] @@ -976,13 +988,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "3.2.0" +version = "3.8.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pre_commit-3.2.0-py2.py3-none-any.whl", hash = "sha256:f712d3688102e13c8e66b7d7dbd8934a6dda157e58635d89f7d6fecdca39ce8a"}, - {file = "pre_commit-3.2.0.tar.gz", hash = "sha256:818f0d998059934d0f81bb3667e3ccdc32da6ed7ccaac33e43dc231561ddaaa9"}, + {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"}, ] [package.dependencies] @@ -1022,46 +1034,78 @@ wcwidth = "*" [[package]] name = "psycopg2-binary" -version = "2.8.6" +version = "2.9.10" description = "psycopg2 - Python-PostgreSQL Database Adapter" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" -files = [ - {file = "psycopg2-binary-2.8.6.tar.gz", hash = "sha256:11b9c0ebce097180129e422379b824ae21c8f2a6596b159c7659e2e5a00e1aa0"}, - {file = "psycopg2_binary-2.8.6-cp27-cp27m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:d14b140a4439d816e3b1229a4a525df917d6ea22a0771a2a78332273fd9528a4"}, - {file = "psycopg2_binary-2.8.6-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:1fabed9ea2acc4efe4671b92c669a213db744d2af8a9fc5d69a8e9bc14b7a9db"}, - {file = "psycopg2_binary-2.8.6-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:f5ab93a2cb2d8338b1674be43b442a7f544a0971da062a5da774ed40587f18f5"}, - {file = "psycopg2_binary-2.8.6-cp27-cp27m-win32.whl", hash = "sha256:b4afc542c0ac0db720cf516dd20c0846f71c248d2b3d21013aa0d4ef9c71ca25"}, - {file = "psycopg2_binary-2.8.6-cp27-cp27m-win_amd64.whl", hash = "sha256:e74a55f6bad0e7d3968399deb50f61f4db1926acf4a6d83beaaa7df986f48b1c"}, - {file = "psycopg2_binary-2.8.6-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:0deac2af1a587ae12836aa07970f5cb91964f05a7c6cdb69d8425ff4c15d4e2c"}, - {file = "psycopg2_binary-2.8.6-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ad20d2eb875aaa1ea6d0f2916949f5c08a19c74d05b16ce6ebf6d24f2c9f75d1"}, - {file = "psycopg2_binary-2.8.6-cp34-cp34m-win32.whl", hash = "sha256:950bc22bb56ee6ff142a2cb9ee980b571dd0912b0334aa3fe0fe3788d860bea2"}, - {file = "psycopg2_binary-2.8.6-cp34-cp34m-win_amd64.whl", hash = "sha256:b8a3715b3c4e604bcc94c90a825cd7f5635417453b253499664f784fc4da0152"}, - {file = "psycopg2_binary-2.8.6-cp35-cp35m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:d1b4ab59e02d9008efe10ceabd0b31e79519da6fb67f7d8e8977118832d0f449"}, - {file = "psycopg2_binary-2.8.6-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:ac0c682111fbf404525dfc0f18a8b5f11be52657d4f96e9fcb75daf4f3984859"}, - {file = "psycopg2_binary-2.8.6-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7d92a09b788cbb1aec325af5fcba9fed7203897bbd9269d5691bb1e3bce29550"}, - {file = "psycopg2_binary-2.8.6-cp35-cp35m-win32.whl", hash = "sha256:aaa4213c862f0ef00022751161df35804127b78adf4a2755b9f991a507e425fd"}, - {file = "psycopg2_binary-2.8.6-cp35-cp35m-win_amd64.whl", hash = "sha256:c2507d796fca339c8fb03216364cca68d87e037c1f774977c8fc377627d01c71"}, - {file = "psycopg2_binary-2.8.6-cp36-cp36m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:ee69dad2c7155756ad114c02db06002f4cded41132cc51378e57aad79cc8e4f4"}, - {file = "psycopg2_binary-2.8.6-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:e82aba2188b9ba309fd8e271702bd0d0fc9148ae3150532bbb474f4590039ffb"}, - {file = "psycopg2_binary-2.8.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d5227b229005a696cc67676e24c214740efd90b148de5733419ac9aaba3773da"}, - {file = "psycopg2_binary-2.8.6-cp36-cp36m-win32.whl", hash = "sha256:a0eb43a07386c3f1f1ebb4dc7aafb13f67188eab896e7397aa1ee95a9c884eb2"}, - {file = "psycopg2_binary-2.8.6-cp36-cp36m-win_amd64.whl", hash = "sha256:e1f57aa70d3f7cc6947fd88636a481638263ba04a742b4a37dd25c373e41491a"}, - {file = "psycopg2_binary-2.8.6-cp37-cp37m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:833709a5c66ca52f1d21d41865a637223b368c0ee76ea54ca5bad6f2526c7679"}, - {file = "psycopg2_binary-2.8.6-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:ba28584e6bca48c59eecbf7efb1576ca214b47f05194646b081717fa628dfddf"}, - {file = "psycopg2_binary-2.8.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:6a32f3a4cb2f6e1a0b15215f448e8ce2da192fd4ff35084d80d5e39da683e79b"}, - {file = "psycopg2_binary-2.8.6-cp37-cp37m-win32.whl", hash = "sha256:0e4dc3d5996760104746e6cfcdb519d9d2cd27c738296525d5867ea695774e67"}, - {file = "psycopg2_binary-2.8.6-cp37-cp37m-win_amd64.whl", hash = "sha256:cec7e622ebc545dbb4564e483dd20e4e404da17ae07e06f3e780b2dacd5cee66"}, - {file = "psycopg2_binary-2.8.6-cp38-cp38-macosx_10_9_x86_64.macosx_10_9_intel.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:ba381aec3a5dc29634f20692349d73f2d21f17653bda1decf0b52b11d694541f"}, - {file = "psycopg2_binary-2.8.6-cp38-cp38-manylinux1_i686.whl", hash = "sha256:a0c50db33c32594305b0ef9abc0cb7db13de7621d2cadf8392a1d9b3c437ef77"}, - {file = "psycopg2_binary-2.8.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2dac98e85565d5688e8ab7bdea5446674a83a3945a8f416ad0110018d1501b94"}, - {file = "psycopg2_binary-2.8.6-cp38-cp38-win32.whl", hash = "sha256:bd1be66dde2b82f80afb9459fc618216753f67109b859a361cf7def5c7968729"}, - {file = "psycopg2_binary-2.8.6-cp38-cp38-win_amd64.whl", hash = "sha256:8cd0fb36c7412996859cb4606a35969dd01f4ea34d9812a141cd920c3b18be77"}, - {file = "psycopg2_binary-2.8.6-cp39-cp39-macosx_10_9_x86_64.macosx_10_9_intel.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:89705f45ce07b2dfa806ee84439ec67c5d9a0ef20154e0e475e2b2ed392a5b83"}, - {file = "psycopg2_binary-2.8.6-cp39-cp39-manylinux1_i686.whl", hash = "sha256:42ec1035841b389e8cc3692277a0bd81cdfe0b65d575a2c8862cec7a80e62e52"}, - {file = "psycopg2_binary-2.8.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7312e931b90fe14f925729cde58022f5d034241918a5c4f9797cac62f6b3a9dd"}, - {file = "psycopg2_binary-2.8.6-cp39-cp39-win32.whl", hash = "sha256:6422f2ff0919fd720195f64ffd8f924c1395d30f9a495f31e2392c2efafb5056"}, - {file = "psycopg2_binary-2.8.6-cp39-cp39-win_amd64.whl", hash = "sha256:15978a1fbd225583dd8cdaf37e67ccc278b5abecb4caf6b2d6b8e2b948e953f6"}, +python-versions = ">=3.8" +files = [ + {file = "psycopg2-binary-2.9.10.tar.gz", hash = "sha256:4b3df0e6990aa98acda57d983942eff13d824135fe2250e6522edaa782a06de2"}, + {file = "psycopg2_binary-2.9.10-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:0ea8e3d0ae83564f2fc554955d327fa081d065c8ca5cc6d2abb643e2c9c1200f"}, + {file = "psycopg2_binary-2.9.10-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:3e9c76f0ac6f92ecfc79516a8034a544926430f7b080ec5a0537bca389ee0906"}, + {file = "psycopg2_binary-2.9.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ad26b467a405c798aaa1458ba09d7e2b6e5f96b1ce0ac15d82fd9f95dc38a92"}, + {file = "psycopg2_binary-2.9.10-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:270934a475a0e4b6925b5f804e3809dd5f90f8613621d062848dd82f9cd62007"}, + {file = "psycopg2_binary-2.9.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:48b338f08d93e7be4ab2b5f1dbe69dc5e9ef07170fe1f86514422076d9c010d0"}, + {file = "psycopg2_binary-2.9.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f4152f8f76d2023aac16285576a9ecd2b11a9895373a1f10fd9db54b3ff06b4"}, + {file = "psycopg2_binary-2.9.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:32581b3020c72d7a421009ee1c6bf4a131ef5f0a968fab2e2de0c9d2bb4577f1"}, + {file = "psycopg2_binary-2.9.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:2ce3e21dc3437b1d960521eca599d57408a695a0d3c26797ea0f72e834c7ffe5"}, + {file = "psycopg2_binary-2.9.10-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e984839e75e0b60cfe75e351db53d6db750b00de45644c5d1f7ee5d1f34a1ce5"}, + {file = "psycopg2_binary-2.9.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c4745a90b78e51d9ba06e2088a2fe0c693ae19cc8cb051ccda44e8df8a6eb53"}, + {file = "psycopg2_binary-2.9.10-cp310-cp310-win32.whl", hash = "sha256:e5720a5d25e3b99cd0dc5c8a440570469ff82659bb09431c1439b92caf184d3b"}, + {file = "psycopg2_binary-2.9.10-cp310-cp310-win_amd64.whl", hash = "sha256:3c18f74eb4386bf35e92ab2354a12c17e5eb4d9798e4c0ad3a00783eae7cd9f1"}, + {file = "psycopg2_binary-2.9.10-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:04392983d0bb89a8717772a193cfaac58871321e3ec69514e1c4e0d4957b5aff"}, + {file = "psycopg2_binary-2.9.10-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:1a6784f0ce3fec4edc64e985865c17778514325074adf5ad8f80636cd029ef7c"}, + {file = "psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5f86c56eeb91dc3135b3fd8a95dc7ae14c538a2f3ad77a19645cf55bab1799c"}, + {file = "psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b3d2491d4d78b6b14f76881905c7a8a8abcf974aad4a8a0b065273a0ed7a2cb"}, + {file = "psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2286791ececda3a723d1910441c793be44625d86d1a4e79942751197f4d30341"}, + {file = "psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:512d29bb12608891e349af6a0cccedce51677725a921c07dba6342beaf576f9a"}, + {file = "psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5a507320c58903967ef7384355a4da7ff3f28132d679aeb23572753cbf2ec10b"}, + {file = "psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6d4fa1079cab9018f4d0bd2db307beaa612b0d13ba73b5c6304b9fe2fb441ff7"}, + {file = "psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:851485a42dbb0bdc1edcdabdb8557c09c9655dfa2ca0460ff210522e073e319e"}, + {file = "psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:35958ec9e46432d9076286dda67942ed6d968b9c3a6a2fd62b48939d1d78bf68"}, + {file = "psycopg2_binary-2.9.10-cp311-cp311-win32.whl", hash = "sha256:ecced182e935529727401b24d76634a357c71c9275b356efafd8a2a91ec07392"}, + {file = "psycopg2_binary-2.9.10-cp311-cp311-win_amd64.whl", hash = "sha256:ee0e8c683a7ff25d23b55b11161c2663d4b099770f6085ff0a20d4505778d6b4"}, + {file = "psycopg2_binary-2.9.10-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:880845dfe1f85d9d5f7c412efea7a08946a46894537e4e5d091732eb1d34d9a0"}, + {file = "psycopg2_binary-2.9.10-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9440fa522a79356aaa482aa4ba500b65f28e5d0e63b801abf6aa152a29bd842a"}, + {file = "psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3923c1d9870c49a2d44f795df0c889a22380d36ef92440ff618ec315757e539"}, + {file = "psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b2c956c028ea5de47ff3a8d6b3cc3330ab45cf0b7c3da35a2d6ff8420896526"}, + {file = "psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f758ed67cab30b9a8d2833609513ce4d3bd027641673d4ebc9c067e4d208eec1"}, + {file = "psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cd9b4f2cfab88ed4a9106192de509464b75a906462fb846b936eabe45c2063e"}, + {file = "psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dc08420625b5a20b53551c50deae6e231e6371194fa0651dbe0fb206452ae1f"}, + {file = "psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d7cd730dfa7c36dbe8724426bf5612798734bff2d3c3857f36f2733f5bfc7c00"}, + {file = "psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:155e69561d54d02b3c3209545fb08938e27889ff5a10c19de8d23eb5a41be8a5"}, + {file = "psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3cc28a6fd5a4a26224007712e79b81dbaee2ffb90ff406256158ec4d7b52b47"}, + {file = "psycopg2_binary-2.9.10-cp312-cp312-win32.whl", hash = "sha256:ec8a77f521a17506a24a5f626cb2aee7850f9b69a0afe704586f63a464f3cd64"}, + {file = "psycopg2_binary-2.9.10-cp312-cp312-win_amd64.whl", hash = "sha256:18c5ee682b9c6dd3696dad6e54cc7ff3a1a9020df6a5c0f861ef8bfd338c3ca0"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:26540d4a9a4e2b096f1ff9cce51253d0504dca5a85872c7f7be23be5a53eb18d"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e217ce4d37667df0bc1c397fdcd8de5e81018ef305aed9415c3b093faaeb10fb"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:245159e7ab20a71d989da00f280ca57da7641fa2cdcf71749c193cea540a74f7"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c4ded1a24b20021ebe677b7b08ad10bf09aac197d6943bfe6fec70ac4e4690d"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3abb691ff9e57d4a93355f60d4f4c1dd2d68326c968e7db17ea96df3c023ef73"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8608c078134f0b3cbd9f89b34bd60a943b23fd33cc5f065e8d5f840061bd0673"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:230eeae2d71594103cd5b93fd29d1ace6420d0b86f4778739cb1a5a32f607d1f"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bb89f0a835bcfc1d42ccd5f41f04870c1b936d8507c6df12b7737febc40f0909"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f0c2d907a1e102526dd2986df638343388b94c33860ff3bbe1384130828714b1"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8157bed2f51db683f31306aa497311b560f2265998122abe1dce6428bd86567"}, + {file = "psycopg2_binary-2.9.10-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:eb09aa7f9cecb45027683bb55aebaaf45a0df8bf6de68801a6afdc7947bb09d4"}, + {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b73d6d7f0ccdad7bc43e6d34273f70d587ef62f824d7261c4ae9b8b1b6af90e8"}, + {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce5ab4bf46a211a8e924d307c1b1fcda82368586a19d0a24f8ae166f5c784864"}, + {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:056470c3dc57904bbf63d6f534988bafc4e970ffd50f6271fc4ee7daad9498a5"}, + {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73aa0e31fa4bb82578f3a6c74a73c273367727de397a7a0f07bd83cbea696baa"}, + {file = "psycopg2_binary-2.9.10-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8de718c0e1c4b982a54b41779667242bc630b2197948405b7bd8ce16bcecac92"}, + {file = "psycopg2_binary-2.9.10-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:5c370b1e4975df846b0277b4deba86419ca77dbc25047f535b0bb03d1a544d44"}, + {file = "psycopg2_binary-2.9.10-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:ffe8ed017e4ed70f68b7b371d84b7d4a790368db9203dfc2d222febd3a9c8863"}, + {file = "psycopg2_binary-2.9.10-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:8aecc5e80c63f7459a1a2ab2c64df952051df196294d9f739933a9f6687e86b3"}, + {file = "psycopg2_binary-2.9.10-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:7a813c8bdbaaaab1f078014b9b0b13f5de757e2b5d9be6403639b298a04d218b"}, + {file = "psycopg2_binary-2.9.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d00924255d7fc916ef66e4bf22f354a940c67179ad3fd7067d7a0a9c84d2fbfc"}, + {file = "psycopg2_binary-2.9.10-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7559bce4b505762d737172556a4e6ea8a9998ecac1e39b5233465093e8cee697"}, + {file = "psycopg2_binary-2.9.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8b58f0a96e7a1e341fc894f62c1177a7c83febebb5ff9123b579418fdc8a481"}, + {file = "psycopg2_binary-2.9.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b269105e59ac96aba877c1707c600ae55711d9dcd3fc4b5012e4af68e30c648"}, + {file = "psycopg2_binary-2.9.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:79625966e176dc97ddabc142351e0409e28acf4660b88d1cf6adb876d20c490d"}, + {file = "psycopg2_binary-2.9.10-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:8aabf1c1a04584c168984ac678a668094d831f152859d06e055288fa515e4d30"}, + {file = "psycopg2_binary-2.9.10-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:19721ac03892001ee8fdd11507e6a2e01f4e37014def96379411ca99d78aeb2c"}, + {file = "psycopg2_binary-2.9.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7f5d859928e635fa3ce3477704acee0f667b3a3d3e4bb109f2b18d4005f38287"}, + {file = "psycopg2_binary-2.9.10-cp39-cp39-win32.whl", hash = "sha256:3216ccf953b3f267691c90c6fe742e45d890d8272326b4a8b20850a03d05b7b8"}, + {file = "psycopg2_binary-2.9.10-cp39-cp39-win_amd64.whl", hash = "sha256:30e34c4e97964805f715206c7b789d54a78b70f3ff19fbe590104b71c45600e5"}, ] [[package]] @@ -1076,17 +1120,16 @@ files = [ [[package]] name = "pytest" -version = "7.2.1" +version = "7.4.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.2.1-py3-none-any.whl", hash = "sha256:c7c6ca206e93355074ae32f7403e8ea12163b1163c976fee7d4d84027c162be5"}, - {file = "pytest-7.2.1.tar.gz", hash = "sha256:d45e0952f3727241918b8fd0f376f5ff6b301cc0777c6f9a556935c92d8a7d42"}, + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, ] [package.dependencies] -attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" @@ -1095,17 +1138,17 @@ pluggy = ">=0.12,<2.0" tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-asyncio" -version = "0.21.0" +version = "0.21.2" description = "Pytest support for asyncio" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-asyncio-0.21.0.tar.gz", hash = "sha256:2b38a496aef56f56b0e87557ec313e11e1ab9276fc3863f6a7be0f1d0e415e1b"}, - {file = "pytest_asyncio-0.21.0-py3-none-any.whl", hash = "sha256:f2b3366b7cd501a4056858bd39349d5af19742aed2d81660b7998b6341c7eb9c"}, + {file = "pytest_asyncio-0.21.2-py3-none-any.whl", hash = "sha256:ab664c88bb7998f711d8039cacd4884da6430886ae8bbd4eded552ed2004f16b"}, + {file = "pytest_asyncio-0.21.2.tar.gz", hash = "sha256:d67738fc232b94b326b9d060750beb16e0074210b98dd8b58a5239fa2a154f45"}, ] [package.dependencies] @@ -1117,13 +1160,13 @@ testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy [[package]] name = "pytest-cov" -version = "4.0.0" +version = "4.1.0" description = "Pytest plugin for measuring coverage." optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, - {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, + {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, + {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, ] [package.dependencies] @@ -1135,17 +1178,17 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale [[package]] name = "pytest-django" -version = "4.5.2" +version = "4.9.0" description = "A Django plugin for pytest." optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" files = [ - {file = "pytest-django-4.5.2.tar.gz", hash = "sha256:d9076f759bb7c36939dbdd5ae6633c18edfc2902d1a69fdbefd2426b970ce6c2"}, - {file = "pytest_django-4.5.2-py3-none-any.whl", hash = "sha256:c60834861933773109334fe5a53e83d1ef4828f2203a1d6a0fa9972f4f75ab3e"}, + {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.dependencies] -pytest = ">=5.4.0" +pytest = ">=7.0.0" [package.extras] docs = ["sphinx", "sphinx-rtd-theme"] @@ -1153,13 +1196,13 @@ testing = ["Django", "django-configurations (>=2.0)"] [[package]] name = "python-dateutil" -version = "2.8.2" +version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, ] [package.dependencies] @@ -1240,48 +1283,47 @@ files = [ [[package]] name = "rapidpro-python" -version = "2.6.1" -description = "Python client library for the RapidPro" +version = "2.15.0" +description = "Python client library for the RapidPro API" optional = false -python-versions = "*" +python-versions = "<4.0,>=3.9" files = [ - {file = "rapidpro-python-2.6.1.tar.gz", hash = "sha256:9dfa15fe9345553433f8a9f8ed9c0c53fdd60382b08a780cf95a317525f0be6f"}, - {file = "rapidpro_python-2.6.1-py2.py3-none-any.whl", hash = "sha256:5ca7174d68faa569f50c0d98858d31af4496cf413c146cd6c8b0f190e9f333d0"}, + {file = "rapidpro_python-2.15.0-py3-none-any.whl", hash = "sha256:3bdd1d0777d18c18a7851d8837a8c62ef844bc443a6d41ab3eb89f485afdb918"}, + {file = "rapidpro_python-2.15.0.tar.gz", hash = "sha256:4bd6298d24c929b37ae1f51632beaf028c4d566f803848c57e28a54cf20cbbb4"}, ] [package.dependencies] -iso8601 = "*" -pytz = "*" -requests = "*" +iso8601 = ">=0.1.13,<0.2.0" +requests = ">=2.25.0,<3.0.0" [[package]] name = "raven" -version = "6.9.0" +version = "6.10.0" description = "Raven is a client for Sentry (https://getsentry.com)" optional = false python-versions = "*" files = [ - {file = "raven-6.9.0-py2.py3-none-any.whl", hash = "sha256:95f44f3ea2c1b176d5450df4becdb96c15bf2632888f9ab193e9dd22300ce46a"}, - {file = "raven-6.9.0.tar.gz", hash = "sha256:3fd787d19ebb49919268f06f19310e8112d619ef364f7989246fc8753d469888"}, + {file = "raven-6.10.0-py2.py3-none-any.whl", hash = "sha256:44a13f87670836e153951af9a3c80405d36b43097db869a36e92809673692ce4"}, + {file = "raven-6.10.0.tar.gz", hash = "sha256:3fa6de6efa2493a7c827472e984ce9b020797d0da16f1db67197bcc23c8fae54"}, ] [package.extras] flask = ["Flask (>=0.8)", "blinker (>=1.1)"] -tests = ["Flask (>=0.8)", "Flask-Login (>=0.2.0)", "ZConfig", "anyjson", "blinker (>=1.1)", "bottle", "celery (>=2.5)", "coverage (<4)", "exam (>=0.5.2)", "flake8 (==3.5.0)", "logbook", "mock", "nose", "paste", "pytest (>=3.2.0,<3.3.0)", "pytest-cov (==2.5.1)", "pytest-flake8 (==1.0.0)", "pytest-pythonpath (==0.7.2)", "pytest-timeout (==1.2.1)", "pytest-xdist (==1.18.2)", "pytz", "requests", "tornado (>=4.1,<5.0)", "tox", "unittest2", "web.py", "webob", "webtest", "wheel"] +tests = ["Flask (>=0.8)", "Flask-Login (>=0.2.0)", "ZConfig", "aiohttp", "anyjson", "blinker (>=1.1)", "blinker (>=1.1)", "bottle", "celery (>=2.5)", "coverage (<4)", "exam (>=0.5.2)", "flake8 (==3.5.0)", "logbook", "mock", "nose", "pytest (>=3.2.0,<3.3.0)", "pytest-cov (==2.5.1)", "pytest-flake8 (==1.0.0)", "pytest-pythonpath (==0.7.2)", "pytest-timeout (==1.2.1)", "pytest-xdist (==1.18.2)", "pytz", "requests", "sanic (>=0.7.0)", "tornado (>=4.1,<5.0)", "tox", "webob", "webtest", "wheel"] [[package]] name = "redis" -version = "4.5.4" +version = "4.6.0" description = "Python client for Redis database and key-value store" optional = false python-versions = ">=3.7" files = [ - {file = "redis-4.5.4-py3-none-any.whl", hash = "sha256:2c19e6767c474f2e85167909061d525ed65bea9301c0770bb151e041b7ac89a2"}, - {file = "redis-4.5.4.tar.gz", hash = "sha256:73ec35da4da267d6847e47f68730fdd5f62e2ca69e3ef5885c6a78a9374c3893"}, + {file = "redis-4.6.0-py3-none-any.whl", hash = "sha256:e2b03db868160ee4591de3cb90d40ebb50a90dd302138775937f6a42b7ed183c"}, + {file = "redis-4.6.0.tar.gz", hash = "sha256:585dc516b9eb042a619ef0a39c3d7d55fe81bdb4df09a52c9cdde0d07bf1aa7d"}, ] [package.dependencies] -async-timeout = {version = ">=4.0.2", markers = "python_version <= \"3.11.2\""} +async-timeout = {version = ">=4.0.2", markers = "python_full_version <= \"3.11.2\""} [package.extras] hiredis = ["hiredis (>=1.0.0)"] @@ -1289,13 +1331,13 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)" [[package]] name = "requests" -version = "2.32.0" +version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" files = [ - {file = "requests-2.32.0-py3-none-any.whl", hash = "sha256:f2c3881dddb70d056c5bd7600a4fae312b2a300e39be6a118d30b90bd27262b5"}, - {file = "requests-2.32.0.tar.gz", hash = "sha256:fa5490319474c82ef1d2c9bc459d3652e3ae4ef4c4ebdd18a21145a47ca4b6b8"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -1310,20 +1352,20 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "responses" -version = "0.23.1" +version = "0.23.3" description = "A utility library for mocking out the `requests` Python library." optional = false python-versions = ">=3.7" files = [ - {file = "responses-0.23.1-py3-none-any.whl", hash = "sha256:8a3a5915713483bf353b6f4079ba8b2a29029d1d1090a503c70b0dc5d9d0c7bd"}, - {file = "responses-0.23.1.tar.gz", hash = "sha256:c4d9aa9fc888188f0c673eff79a8dadbe2e75b7fe879dc80a221a06e0a68138f"}, + {file = "responses-0.23.3-py3-none-any.whl", hash = "sha256:e6fbcf5d82172fecc0aa1860fd91e58cbfd96cee5e96da5b63fa6eb3caa10dd3"}, + {file = "responses-0.23.3.tar.gz", hash = "sha256:205029e1cb334c21cb4ec64fc7599be48b859a0fd381a42443cdd600bfe8b16a"}, ] [package.dependencies] pyyaml = "*" -requests = ">=2.22.0,<3.0" +requests = ">=2.30.0,<3.0" types-PyYAML = "*" -urllib3 = ">=1.25.10" +urllib3 = ">=1.25.10,<3.0" [package.extras] tests = ["coverage (>=6.0.0)", "flake8", "mypy", "pytest (>=7.0.0)", "pytest-asyncio", "pytest-cov", "pytest-httpserver", "tomli", "tomli-w", "types-requests"] @@ -1355,30 +1397,15 @@ files = [ {file = "ruff-0.6.9.tar.gz", hash = "sha256:b076ef717a8e5bc819514ee1d602bbdca5b4420ae13a9cf61a0c0a4f53a2baa2"}, ] -[[package]] -name = "setuptools" -version = "59.6.0" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -optional = false -python-versions = ">=3.6" -files = [ - {file = "setuptools-59.6.0-py3-none-any.whl", hash = "sha256:4ce92f1e1f8f01233ee9952c04f6b81d1e02939d6e1b488428154974a4d0783e"}, - {file = "setuptools-59.6.0.tar.gz", hash = "sha256:22c7348c6d2976a52632c67f7ab0cdf40147db7789f9aed18734643fe9cf3373"}, -] - -[package.extras] -docs = ["furo", "jaraco.packaging (>=8.2)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx", "sphinx-inline-tabs", "sphinxcontrib-towncrier"] -testing = ["flake8-2020", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mock", "paver", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-flake8", "pytest-mypy", "pytest-virtualenv (>=1.2.7)", "pytest-xdist", "sphinx", "virtualenv (>=13.0.0)", "wheel"] - [[package]] name = "six" -version = "1.11.0" +version = "1.16.0" description = "Python 2 and 3 compatibility utilities" optional = false -python-versions = "*" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ - {file = "six-1.11.0-py2.py3-none-any.whl", hash = "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"}, - {file = "six-1.11.0.tar.gz", hash = "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9"}, + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] [[package]] @@ -1529,7 +1556,26 @@ files = [ {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, ] +[[package]] +name = "zipp" +version = "3.20.2" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.8" +files = [ + {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"}, + {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"}, +] + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +type = ["pytest-mypy"] + [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "6d0afc0c6e8a5683f6a70c5c7be3a2ef9c8282dd26712c8276c42777d78d58b4" +content-hash = "02a19101de08b0b2182dedb222de9f3ffc23622fc7fea9b78b01d7fdee5b50e1" diff --git a/pyproject.toml b/pyproject.toml index 8e1ac16f..2468eaa2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,43 +16,42 @@ packages = [ [tool.poetry.dependencies] python = "^3.9" -Django = "4.2.15" -djangorestframework = "3.15.2" -coreapi = "2.3.3" -Markdown = "3.1.1" -dj-database-url = "1.2.0" -django-environ = "0.10.0" -psycopg2-binary = "2.8.6" -raven = "6.9.0" -django-filter = "2.4.0" -celery = "5.2.3" -six = "1.11.0" -requests = "2.32.0" -demands = "3.0.0" -structlog = "18.2.0" -phonenumberslite = "8.9.15" -django-simple-history = "3.3.0" -openpyxl = "2.5.9" -iso-639 = {git = "https://github.com/noumar/iso639.git", tag = "0.4.5"} -django-prometheus = "2.2.0" -rapidpro-python = "2.6.1" -pycountry = "19.8.18" +Django = "^4.2.15" +djangorestframework = "^3.15.2" +coreapi = "^2.3.3" +Markdown = "^3.1.1" +dj-database-url = "^1.2.0" +django-environ = "^0.10.0" +psycopg2-binary = "^2.8.6" +raven = "^6.9.0" +django-filter = "^2.4.0" +celery = "^5.2.3" +six = "^1.11.0" +requests = "^2.32.0" +demands = "^3.0.0" +structlog = "^18.2.0" +phonenumberslite = "^8.9.15" +django-simple-history = "^3.3.0" +openpyxl = "^2.5.9" +django-prometheus = "^2.2.0" +rapidpro-python = "^2.6.1" +pycountry = "^19.8.18" attrs = "*" -iso6709 = "0.1.5" -redis = "4.5.4" -django-redis = "5.2.0" -celery_batches = "0.7" -python-dateutil = "2.8.2" +iso6709 = "^0.1.5" +redis = "^4.5.4" +django-redis = "^5.2.0" +celery_batches = "^0.7" +python-dateutil = "^2.8.2" [tool.poetry.group.dev.dependencies] ruff = "^0.6.9" -pytest = "7.2.1" -pytest-cov = "4.0.0" -pytest-django = "4.5.2" -pytest-asyncio = "0.21.0" -responses = "0.23.1" -pre-commit = "3.2.0" -freezegun = "1.2.2" +pytest = "^7.2.1" +pytest-cov = "^4.0.0" +pytest-django = "^4.5.2" +pytest-asyncio = "^0.21.0" +responses = "^0.23.1" +pre-commit = "^3.2.0" +freezegun = "^1.2.2" [build-system] requires = ["poetry-core"] diff --git a/requirements-dev.txt b/requirements-dev.txt deleted file mode 100644 index 1b134c19..00000000 --- a/requirements-dev.txt +++ /dev/null @@ -1,11 +0,0 @@ -pytest==7.2.1 -pytest-cov==4.0.0 -pytest-django==4.5.2 -pytest-asyncio==0.21.0 -flake8==6.0.0 -responses==0.23.1 -mypy==1.1.1 -black==24.3.0 -isort==5.12.0 -pre-commit==3.2.0 -freezegun==1.2.2 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 0b5bd7a7..00000000 --- a/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -# Our dependencies are all specified in setup.py. --e . diff --git a/setup.py b/setup.py deleted file mode 100644 index 9857052c..00000000 --- a/setup.py +++ /dev/null @@ -1,49 +0,0 @@ -from setuptools import find_packages, setup - -setup( - name="ndoh-hub", - version="0.10.25", - url="http://github.com/praekeltfoundation/ndoh-hub", - license="BSD", - author="Praekelt Foundation", - author_email="dev@praekeltfoundation.org", - packages=find_packages(), - include_package_data=True, - install_requires=[ - "Django==4.2.15", - "djangorestframework==3.15.2", - "coreapi==2.3.3", - "Markdown==3.1.1", - "dj-database-url==1.2.0", - "django-environ==0.10.0", - "psycopg2-binary==2.8.6", - "raven==6.9.0", - "django-filter==2.4.0", - "celery==5.2.3", - "six==1.11.0", - "requests==2.32.0", - "demands==3.0.0", - "structlog==18.2.0", - "phonenumberslite==8.9.15", - "django-simple-history==3.3.0", - "openpyxl==2.5.9", - "iso-639==0.4.5", - "django-prometheus==2.2.0", - "rapidpro-python==2.6.1", - "pycountry==19.8.18", - "attrs", - "iso6709==0.1.5", - "redis==4.5.4", - "django-redis==5.2.0", - "celery_batches==0.7", - "python-dateutil==2.8.2", - ], - classifiers=[ - "Development Status :: 4 - Beta", - "Framework :: Django", - "License :: OSI Approved :: BSD License", - "Programming Language :: Python", - "Programming Language :: Python :: 3.9.9", - "Topic :: Software Development :: Libraries :: Python Modules", - ], -) From 904614d3675fb4f815cf3d77a3e4f9148c40a9d7 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Thu, 17 Oct 2024 12:26:36 +0200 Subject: [PATCH 05/41] Pinned specific 'rapidpro-python' version --- poetry.lock | 25 +++++++++++++------------ pyproject.toml | 4 ++-- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/poetry.lock b/poetry.lock index b33e4d3d..57a796c3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -738,13 +738,13 @@ files = [ [[package]] name = "iso8601" -version = "0.1.16" +version = "2.1.0" description = "Simple module to parse ISO 8601 dates" optional = false -python-versions = "*" +python-versions = ">=3.7,<4.0" files = [ - {file = "iso8601-0.1.16-py2.py3-none-any.whl", hash = "sha256:906714829fedbc89955d52806c903f2332e3948ed94e31e85037f9e0226b8376"}, - {file = "iso8601-0.1.16.tar.gz", hash = "sha256:36532f77cc800594e8f16641edae7f1baf7932f05d8e508545b95fc53c6dc85b"}, + {file = "iso8601-2.1.0-py3-none-any.whl", hash = "sha256:aac4145c4dcb66ad8b648a02830f5e2ff6c24af20f4f482689be402db2429242"}, + {file = "iso8601-2.1.0.tar.gz", hash = "sha256:6b1d3829ee8921c4301998c909f7829fa9ed3cbdac0d3b16af2d743aed1ba8df"}, ] [[package]] @@ -1283,18 +1283,19 @@ files = [ [[package]] name = "rapidpro-python" -version = "2.15.0" -description = "Python client library for the RapidPro API" +version = "2.6.1" +description = "Python client library for the RapidPro" optional = false -python-versions = "<4.0,>=3.9" +python-versions = "*" files = [ - {file = "rapidpro_python-2.15.0-py3-none-any.whl", hash = "sha256:3bdd1d0777d18c18a7851d8837a8c62ef844bc443a6d41ab3eb89f485afdb918"}, - {file = "rapidpro_python-2.15.0.tar.gz", hash = "sha256:4bd6298d24c929b37ae1f51632beaf028c4d566f803848c57e28a54cf20cbbb4"}, + {file = "rapidpro-python-2.6.1.tar.gz", hash = "sha256:9dfa15fe9345553433f8a9f8ed9c0c53fdd60382b08a780cf95a317525f0be6f"}, + {file = "rapidpro_python-2.6.1-py2.py3-none-any.whl", hash = "sha256:5ca7174d68faa569f50c0d98858d31af4496cf413c146cd6c8b0f190e9f333d0"}, ] [package.dependencies] -iso8601 = ">=0.1.13,<0.2.0" -requests = ">=2.25.0,<3.0.0" +iso8601 = "*" +pytz = "*" +requests = "*" [[package]] name = "raven" @@ -1578,4 +1579,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "02a19101de08b0b2182dedb222de9f3ffc23622fc7fea9b78b01d7fdee5b50e1" +content-hash = "d55bbd5f0387736ec6d927f267f4f41f40271e802dec11f930d900fa1480be87" diff --git a/pyproject.toml b/pyproject.toml index 2468eaa2..357646d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,9 +34,9 @@ phonenumberslite = "^8.9.15" django-simple-history = "^3.3.0" openpyxl = "^2.5.9" django-prometheus = "^2.2.0" -rapidpro-python = "^2.6.1" +rapidpro-python = "2.6.1" #V2.7.0 removed the V1 API support, which we use pycountry = "^19.8.18" -attrs = "*" +attrs = "^24.2.0" iso6709 = "^0.1.5" redis = "^4.5.4" django-redis = "^5.2.0" From 5a88fc4795a6b95ad0cd9be55581e19c0cd4149a Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Thu, 17 Oct 2024 12:45:42 +0200 Subject: [PATCH 06/41] Added blanket ignores until ruff throws no errors --- pyproject.toml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 357646d1..b026f3ce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,6 +86,42 @@ ignore = [ "PTH118", # TODO: Switch to pathlib "PTH100", # TODO: `os.path.abspath()` should be replaced by `Path.resolve()` maybe use pathlib? "PTH120", # TODO: `os.path.dirname()` should be replaced by `Path.parent` maybe use pathlib? + "UP032", # TODO: Use f-string instead of `format` call + "PTH123", # TODO: `open()` should be replaced by `Path.open()` + "UP030", # TODO: Use implicit references for positional format fields + "C416", # TODO: Unnecessary `list` comprehension (rewrite using `list()`) + "UP004", # TODO: Class `Template` inherits from `object` + "S501", #TODO: Probable use of `requests` call with `verify=False` disabling SSL certificate checks + "B007", # TODO: Loop control variable `status_code` not used within loop body + "SIM115", # TODO: Use a context manager for opening files + "S106", # TODO: Possible hardcoded password assigned to argument + "S110", # TODO: `try`-`except`-`pass` detected, consider logging the exception + "S608", # TODO: Possible SQL injection vector through string-based query construction + "SIM110", # TODO: Use `return any("post" in group["name"].lower() for group in contact["groups"])` instead of `for` loop + "E721", # TODO: Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks + "SIM102", # TODO: Use a single `if` statement instead of nested `if` statements + "SIM105", # TODO: Use `contextlib.suppress(Exception)` instead of `try`-`except`-`pass` + "S112", # TODO: `try`-`except`-`continue` detected, consider logging the exception + "S101", # TODO: Use of `assert` detected + "UP031", # TODO: Use format specifiers instead of percent format + "UP008", # TODO: Use `super()` instead of `super(__class__, self)` + "UP031", # TODO: Use format specifiers instead of percent format + "S311", # TODO: Standard pseudo-random generators are not suitable for cryptographic purposes + "B904", # TODO: Within an `except` clause, raise exceptions with `raise ... from err` or `raise ... from None` + "UP010", # TODO: Unnecessary `__future__` imports `absolute_import`, `division` for target Python version + "S105", # TODO: Possible hardcoded password assigned + "B018", # TODO: Found useless expression. Either assign it to a variable or remove it. + "B006", # TODO: Do not use mutable data structures for argument defaults + "C417", # TODO: Unnecessary `map` usage (rewrite using a generator expression) + "UP019", # TODO: `typing.Text` is deprecated, use `str` + "SIM103", # TODO: Return the condition `label in labels` directly + "SIM108", # TODO: Use ternary operator instead of `if`-`else`-block + "SIM113", # TODO: Use `enumerate()` for index variable `total` in `for` loop + "F811", # TODO: Redefinition of unused `cursor` + + + + ] From a9f57f1b3fdf58cd03210d02e79883b88774bdb6 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 08:37:57 +0200 Subject: [PATCH 07/41] Redefinition of unused and ruff format --- aaq/tests/test_utils.py | 1 - aaq/views.py | 1 - eventstore/admin.py | 1 - eventstore/tests/test_views.py | 95 ++++++++++--------- pyproject.toml | 5 - .../management/commands/update_clinics.py | 1 - registrations/views.py | 1 - 7 files changed, 51 insertions(+), 54 deletions(-) diff --git a/aaq/tests/test_utils.py b/aaq/tests/test_utils.py index 9390c87a..b3b49b15 100644 --- a/aaq/tests/test_utils.py +++ b/aaq/tests/test_utils.py @@ -9,7 +9,6 @@ class SearchFunctionTest(APITestCase): - @responses.activate def test_search_function(self): user = get_user_model().objects.create_user("test") diff --git a/aaq/views.py b/aaq/views.py index 81742e63..c7352aaf 100644 --- a/aaq/views.py +++ b/aaq/views.py @@ -172,7 +172,6 @@ def response_feedback(request, *args, **kwargs): @api_view(("POST",)) @renderer_classes((JSONRenderer,)) def aaq_search(request): - serializer = SearchSerializer(data=request.data) serializer.is_valid(raise_exception=True) query_text = serializer.validated_data["query_text"] diff --git a/eventstore/admin.py b/eventstore/admin.py index 2f19b268..e2a7ad2e 100644 --- a/eventstore/admin.py +++ b/eventstore/admin.py @@ -42,7 +42,6 @@ class ApproximatePaginator(Paginator): @cached_property def count(self): - cursor = connection.cursor() with transaction.atomic(), connection.cursor() as cursor: cursor.execute("SET LOCAL statement_timeout TO 50") try: diff --git a/eventstore/tests/test_views.py b/eventstore/tests/test_views.py index 76e401b0..bc7552b4 100644 --- a/eventstore/tests/test_views.py +++ b/eventstore/tests/test_views.py @@ -1283,38 +1283,43 @@ def test_successful_inbound_messages_request(self, mock_handle_inbound): self.assertEqual(response.status_code, status.HTTP_201_CREATED) [messages] = Message.objects.all() self.assertEqual(str(messages.contact_id), "sender-wa-id") - self.assertEqual( - messages.timestamp, datetime.datetime(2018, 2, 15, 11, 38, 20, tzinfo=UTC) - ), - self.assertEqual(messages.id, "9e12d04c-af25-40b6-aa4f-57c72e8e3f91"), - self.assertEqual(messages.type, "image"), - self.assertEqual(messages.message_direction, Message.INBOUND), - self.assertEqual( - messages.data, - { - "context": { - "from": "sender-wa-id-of-context-message", - "group_id": "group-id-of-context-message", - "id": "message-id-of-context-message", - "mentions": ["wa-id1", "wa-id2"], - }, - "image": { - "file": "absolute-filepath-on-coreapp", - "id": "media-id", - "link": "link-to-image-file", - "mime_type": "media-mime-type", - "sha256": "checksum", - "caption": "image-caption", - }, - "location": { - "address": "1 Hacker Way, Menlo Park, CA, 94025", - "name": "location-name", + ( + self.assertEqual( + messages.timestamp, + datetime.datetime(2018, 2, 15, 11, 38, 20, tzinfo=UTC), + ), + ) + (self.assertEqual(messages.id, "9e12d04c-af25-40b6-aa4f-57c72e8e3f91"),) + (self.assertEqual(messages.type, "image"),) + (self.assertEqual(messages.message_direction, Message.INBOUND),) + ( + self.assertEqual( + messages.data, + { + "context": { + "from": "sender-wa-id-of-context-message", + "group_id": "group-id-of-context-message", + "id": "message-id-of-context-message", + "mentions": ["wa-id1", "wa-id2"], + }, + "image": { + "file": "absolute-filepath-on-coreapp", + "id": "media-id", + "link": "link-to-image-file", + "mime_type": "media-mime-type", + "sha256": "checksum", + "caption": "image-caption", + }, + "location": { + "address": "1 Hacker Way, Menlo Park, CA, 94025", + "name": "location-name", + }, + "system": {"body": "system-message-content"}, + "text": {"body": "text-message-content"}, + "random": "data", }, - "system": {"body": "system-message-content"}, - "text": {"body": "text-message-content"}, - "random": "data", - }, - ), + ), + ) self.assertEqual(messages.created_by, user.username) mock_handle_inbound.assert_called_with(messages) @@ -1390,19 +1395,21 @@ def test_successful_outbound_messages_request(self, mock_handle_outbound): self.assertEqual(response.status_code, status.HTTP_201_CREATED) [messages] = Message.objects.all() self.assertEqual(str(messages.contact_id), "whatsapp-id") - self.assertEqual(messages.id, "message-id"), - self.assertEqual(messages.type, "text"), - self.assertEqual(messages.message_direction, Message.OUTBOUND), - self.assertEqual( - messages.data, - { - "text": {"body": "your-text-message-content"}, - "render_mentions": True, - "preview_url": True, - "random": "data", - "recipient_type": "individual", - }, - ), + (self.assertEqual(messages.id, "message-id"),) + (self.assertEqual(messages.type, "text"),) + (self.assertEqual(messages.message_direction, Message.OUTBOUND),) + ( + self.assertEqual( + messages.data, + { + "text": {"body": "your-text-message-content"}, + "render_mentions": True, + "preview_url": True, + "random": "data", + "recipient_type": "individual", + }, + ), + ) self.assertEqual(messages.created_by, user.username) self.assertFalse(messages.fallback_channel) diff --git a/pyproject.toml b/pyproject.toml index b026f3ce..c46c9f6e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -117,11 +117,6 @@ ignore = [ "SIM103", # TODO: Return the condition `label in labels` directly "SIM108", # TODO: Use ternary operator instead of `if`-`else`-block "SIM113", # TODO: Use `enumerate()` for index variable `total` in `for` loop - "F811", # TODO: Redefinition of unused `cursor` - - - - ] diff --git a/registrations/management/commands/update_clinics.py b/registrations/management/commands/update_clinics.py index 654c80b3..86ee946d 100644 --- a/registrations/management/commands/update_clinics.py +++ b/registrations/management/commands/update_clinics.py @@ -16,7 +16,6 @@ def clean_name(name): class Command(BaseCommand): - def add_arguments(self, parser): parser.add_argument("csv_file", nargs="+", type=str) diff --git a/registrations/views.py b/registrations/views.py index 0675d045..90e3c701 100644 --- a/registrations/views.py +++ b/registrations/views.py @@ -22,7 +22,6 @@ class BearerTokenAuthentication(TokenAuthentication): class FacilityDetailsView(generics.RetrieveAPIView): - def get(self, request): try: facility_code = request.query_params["facility_code"] From 346e40fa42798474fffe3018eb2c1573b370d6d5 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 09:09:53 +0200 Subject: [PATCH 08/41] Use 'enumerate()' for index variable 'total' in 'for' loop --- .../commands/migrate_to_eventstore.py | 3 +- pyproject.toml | 50 +++++++++---------- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/eventstore/management/commands/migrate_to_eventstore.py b/eventstore/management/commands/migrate_to_eventstore.py index 6ed4359d..bf61b223 100644 --- a/eventstore/management/commands/migrate_to_eventstore.py +++ b/eventstore/management/commands/migrate_to_eventstore.py @@ -36,7 +36,7 @@ def add_arguments(self, parser): def execute_with_progress(self, func, iterator): total = 0 start, d_print = time.time(), time.time() - for arg in iterator: + for total, arg in enumerate(iterator): func(arg) if time.time() - d_print > 1: self.stdout.write( @@ -44,7 +44,6 @@ def execute_with_progress(self, func, iterator): ending="", ) d_print = time.time() - total += 1 self.stdout.write("") def handle_public_registration(self, reg): diff --git a/pyproject.toml b/pyproject.toml index c46c9f6e..db1e7460 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -84,51 +84,51 @@ ignore = [ "E501", # TODO: Something about these long lines. "S113", # TODO: Add request timeouts. "PTH118", # TODO: Switch to pathlib - "PTH100", # TODO: `os.path.abspath()` should be replaced by `Path.resolve()` maybe use pathlib? - "PTH120", # TODO: `os.path.dirname()` should be replaced by `Path.parent` maybe use pathlib? - "UP032", # TODO: Use f-string instead of `format` call - "PTH123", # TODO: `open()` should be replaced by `Path.open()` + "PTH100", # TODO: 'os.path.abspath()' should be replaced by 'Path.resolve()' maybe use pathlib? + "PTH120", # TODO: 'os.path.dirname()' should be replaced by 'Path.parent' maybe use pathlib? + "UP032", # TODO: Use f-string instead of 'format' call + "PTH123", # TODO: 'open()' should be replaced by 'Path.open()' "UP030", # TODO: Use implicit references for positional format fields - "C416", # TODO: Unnecessary `list` comprehension (rewrite using `list()`) - "UP004", # TODO: Class `Template` inherits from `object` - "S501", #TODO: Probable use of `requests` call with `verify=False` disabling SSL certificate checks - "B007", # TODO: Loop control variable `status_code` not used within loop body + "C416", # TODO: Unnecessary 'list' comprehension (rewrite using 'list()') + "UP004", # TODO: Class 'Template' inherits from 'object' + "S501", #TODO: Probable use of 'requests' call with 'verify=False' disabling SSL certificate checks + "B007", # TODO: Loop control variable 'status_code' not used within loop body "SIM115", # TODO: Use a context manager for opening files "S106", # TODO: Possible hardcoded password assigned to argument - "S110", # TODO: `try`-`except`-`pass` detected, consider logging the exception + "S110", # TODO: 'try'-'except'-'pass' detected, consider logging the exception "S608", # TODO: Possible SQL injection vector through string-based query construction - "SIM110", # TODO: Use `return any("post" in group["name"].lower() for group in contact["groups"])` instead of `for` loop - "E721", # TODO: Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - "SIM102", # TODO: Use a single `if` statement instead of nested `if` statements - "SIM105", # TODO: Use `contextlib.suppress(Exception)` instead of `try`-`except`-`pass` - "S112", # TODO: `try`-`except`-`continue` detected, consider logging the exception - "S101", # TODO: Use of `assert` detected + "SIM110", # TODO: Use 'return any("post" in group["name"].lower() for group in contact["groups"])' instead of 'for' loop + "E721", # TODO: Use 'is' and 'is not' for type comparisons, or 'isinstance()' for isinstance checks + "SIM102", # TODO: Use a single 'if' statement instead of nested 'if' statements + "SIM105", # TODO: Use 'contextlib.suppress(Exception)' instead of 'try'-'except'-'pass' + "S112", # TODO: 'try'-'except'-'continue' detected, consider logging the exception + "S101", # TODO: Use of 'assert' detected "UP031", # TODO: Use format specifiers instead of percent format - "UP008", # TODO: Use `super()` instead of `super(__class__, self)` + "UP008", # TODO: Use 'super()' instead of 'super(__class__, self)' "UP031", # TODO: Use format specifiers instead of percent format "S311", # TODO: Standard pseudo-random generators are not suitable for cryptographic purposes - "B904", # TODO: Within an `except` clause, raise exceptions with `raise ... from err` or `raise ... from None` - "UP010", # TODO: Unnecessary `__future__` imports `absolute_import`, `division` for target Python version + "B904", # TODO: Within an 'except' clause, raise exceptions with 'raise ... from err' or 'raise ... from None' + "UP010", # TODO: Unnecessary '__future__' imports 'absolute_import', 'division' for target Python version "S105", # TODO: Possible hardcoded password assigned "B018", # TODO: Found useless expression. Either assign it to a variable or remove it. "B006", # TODO: Do not use mutable data structures for argument defaults - "C417", # TODO: Unnecessary `map` usage (rewrite using a generator expression) - "UP019", # TODO: `typing.Text` is deprecated, use `str` - "SIM103", # TODO: Return the condition `label in labels` directly - "SIM108", # TODO: Use ternary operator instead of `if`-`else`-block - "SIM113", # TODO: Use `enumerate()` for index variable `total` in `for` loop + "C417", # TODO: Unnecessary 'map' usage (rewrite using a generator expression) + "UP019", # TODO: 'typing.Text' is deprecated, use 'str' + "SIM103", # TODO: Return the condition 'label in labels' directly + "SIM108", # TODO: Use ternary operator instead of 'if'-'else'-block + ] [tool.ruff.lint.per-file-ignores] "**/tests/**" = [ - "S101", # It's okay to use `assert` in tests. + "S101", # It's okay to use 'assert' in tests. "S106", # TODO: Possible hardcoded password assigned to argument: "TURN_AUTH_TOKEN" ] # TODO: Move this somewhere sensible? "**/tests.py" = [ - "S101", # It's okay to use `assert` in tests. + "S101", # It's okay to use 'assert' in tests. "S106", # TODO: Possible hardcoded password assigned to argument: "TURN_AUTH_TOKEN" ] From a7c53c2bdda94b593254e42b7934782f5d7f8ae3 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 09:15:00 +0200 Subject: [PATCH 09/41] Use ternary operator instead of 'if'-'else'-block --- .../commands/migrate_to_eventstore.py | 30 ++++--------------- pyproject.toml | 2 -- 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/eventstore/management/commands/migrate_to_eventstore.py b/eventstore/management/commands/migrate_to_eventstore.py index bf61b223..2a2c1ad7 100644 --- a/eventstore/management/commands/migrate_to_eventstore.py +++ b/eventstore/management/commands/migrate_to_eventstore.py @@ -48,18 +48,12 @@ def execute_with_progress(self, func, iterator): def handle_public_registration(self, reg): data = reg.data or {} - if "whatsapp" in reg.reg_type: - channel = "WhatsApp" - else: - channel = "SMS" + channel = "WhatsApp" if "whatsapp" in reg.reg_type else "SMS" uuid_registrant = data.pop("uuid_registrant", None) operator_id = data.pop("operator_id", None) uuid_device = data.pop("uuid_device", None) language = data.pop("language", "") - if language in LANGUAGES: - language = language.rstrip("_ZA") - else: - language = "" + language = language.rstrip("_ZA") if language in LANGUAGES else "" PublicRegistration.objects.update_or_create( id=reg.id, @@ -77,10 +71,7 @@ def handle_public_registration(self, reg): def handle_CHW_registration(self, reg): data = reg.data or {} - if "whatsapp" in reg.reg_type: - channel = "WhatsApp" - else: - channel = "SMS" + channel = "WhatsApp" if "whatsapp" in reg.reg_type else "SMS" uuid_registrant = data.pop("uuid_registrant", None) operator_id = data.pop("operator_id", None) uuid_device = data.pop("uuid_device", None) @@ -90,10 +81,7 @@ def handle_CHW_registration(self, reg): passport_number = data.pop("passport_no", "") date_of_birth = data.pop("mom_dob", None) language = data.pop("language", "") - if language in LANGUAGES: - language = language.rstrip("_ZA") - else: - language = "" + language = language.rstrip("_ZA") if language in LANGUAGES else "" CHWRegistration.objects.update_or_create( id=reg.id, @@ -116,10 +104,7 @@ def handle_CHW_registration(self, reg): def handle_prebirth_registration(self, reg): data = reg.data or {} - if "whatsapp" in reg.reg_type: - channel = "WhatsApp" - else: - channel = "SMS" + channel = "WhatsApp" if "whatsapp" in reg.reg_type else "SMS" uuid_registrant = data.pop("uuid_registrant", None) contact_id = reg.registrant_id or uuid_registrant uuid_device = data.pop("uuid_device", None) @@ -132,10 +117,7 @@ def handle_prebirth_registration(self, reg): facility_code = data.pop("faccode", "") edd = data.pop("edd", None) language = data.pop("language", "") - if language in LANGUAGES: - language = language.rstrip("_ZA") - else: - language = "" + language = language.rstrip("_ZA") if language in LANGUAGES else "" PrebirthRegistration.objects.update_or_create( id=reg.id, diff --git a/pyproject.toml b/pyproject.toml index db1e7460..0d0129f0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -115,8 +115,6 @@ ignore = [ "C417", # TODO: Unnecessary 'map' usage (rewrite using a generator expression) "UP019", # TODO: 'typing.Text' is deprecated, use 'str' "SIM103", # TODO: Return the condition 'label in labels' directly - "SIM108", # TODO: Use ternary operator instead of 'if'-'else'-block - ] From 3d470a698eff37f771401f1c25f8f2e4eaae5375 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 09:18:48 +0200 Subject: [PATCH 10/41] Return the condition 'label in labels' directly --- eventstore/models.py | 5 +---- pyproject.toml | 3 +-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/eventstore/models.py b/eventstore/models.py index f768c147..1f617d14 100644 --- a/eventstore/models.py +++ b/eventstore/models.py @@ -348,10 +348,7 @@ def has_label(self, label): .get("labels", []) ] - if label in labels: - return True - - return False + return label in labels class Event(models.Model): diff --git a/pyproject.toml b/pyproject.toml index 0d0129f0..b769a958 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -114,8 +114,7 @@ ignore = [ "B006", # TODO: Do not use mutable data structures for argument defaults "C417", # TODO: Unnecessary 'map' usage (rewrite using a generator expression) "UP019", # TODO: 'typing.Text' is deprecated, use 'str' - "SIM103", # TODO: Return the condition 'label in labels' directly - + ] [tool.ruff.lint.per-file-ignores] From 95a413ff6aec9681ce716f8767c47752ed981533 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 09:20:54 +0200 Subject: [PATCH 11/41] 'typing.Text' is deprecated, use 'str' --- eventstore/models.py | 3 +-- pyproject.toml | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/eventstore/models.py b/eventstore/models.py index 1f617d14..6c3d70ef 100644 --- a/eventstore/models.py +++ b/eventstore/models.py @@ -1,7 +1,6 @@ import random import uuid from datetime import date -from typing import Text import pycountry from django.conf import settings @@ -633,7 +632,7 @@ def save(self, *args, **kwargs): class HealthCheckUserProfileManager(models.Manager): - def get_or_prefill(self, msisdn: Text) -> "HealthCheckUserProfile": + def get_or_prefill(self, msisdn: str) -> "HealthCheckUserProfile": """ Either gets the existing user profile, or creates one using data in the historical healthchecks diff --git a/pyproject.toml b/pyproject.toml index b769a958..942a4c32 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -113,7 +113,6 @@ ignore = [ "B018", # TODO: Found useless expression. Either assign it to a variable or remove it. "B006", # TODO: Do not use mutable data structures for argument defaults "C417", # TODO: Unnecessary 'map' usage (rewrite using a generator expression) - "UP019", # TODO: 'typing.Text' is deprecated, use 'str' ] From e4fd7bdedfae6c9de4991607dc879edb3e2bfbdb Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 09:23:54 +0200 Subject: [PATCH 12/41] Unnecessary 'map' usage (rewrite using a generator expression) --- eventstore/tasks.py | 4 ++-- pyproject.toml | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/eventstore/tasks.py b/eventstore/tasks.py index 142562e5..271dae6f 100644 --- a/eventstore/tasks.py +++ b/eventstore/tasks.py @@ -705,8 +705,8 @@ def get_engage_inbound_and_reply(wa_contact_id, message_id): inbound_address = inbounds[0]["from"] inbound_text = map(get_text_or_caption_from_turn_message, inbounds) inbound_text = " | ".join(list(inbound_text)[::-1]) - labels = map(lambda m: m["_vnd"]["v1"]["labels"], inbounds) - labels = map(lambda label: label["value"], ichain.from_iterable(labels)) + labels = (m["_vnd"]["v1"]["labels"] for m in inbounds) + labels = (label["value"] for label in ichain.from_iterable(labels)) return { "inbound_text": inbound_text or "No Question", diff --git a/pyproject.toml b/pyproject.toml index 942a4c32..917abff2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -112,7 +112,6 @@ ignore = [ "S105", # TODO: Possible hardcoded password assigned "B018", # TODO: Found useless expression. Either assign it to a variable or remove it. "B006", # TODO: Do not use mutable data structures for argument defaults - "C417", # TODO: Unnecessary 'map' usage (rewrite using a generator expression) ] From a4e5d6496904d4f023bef76b7b357d17f834ebe1 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 09:26:30 +0200 Subject: [PATCH 13/41] Do not use mutable data structures for argument defaults --- eventstore/tests/test_tasks.py | 8 ++++++-- pyproject.toml | 1 - 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/eventstore/tests/test_tasks.py b/eventstore/tests/test_tasks.py index 8b451003..9f7f4225 100644 --- a/eventstore/tests/test_tasks.py +++ b/eventstore/tests/test_tasks.py @@ -29,8 +29,10 @@ def setUp(self): tasks.rapidpro = TembaClient("textit.in", "test-token") def add_rapidpro_contact_list_response( - self, contact_id, fields, urns=["whatsapp:27820001001"] + self, contact_id, fields, urns=None ): + if urns is None: + urns = ["whatsapp:27820001001"] responses.add( responses.GET, "https://textit.in/api/v2/contacts.json?group=Waiting+for+helpdesk", @@ -54,8 +56,10 @@ def add_rapidpro_contact_list_response( ) def add_rapidpro_contact_update_response( - self, contact_id, fields, urns=["whatsapp:27820001001"] + self, contact_id, fields, urns=None ): + if urns is None: + urns = ["whatsapp:27820001001"] responses.add( responses.POST, f"https://textit.in/api/v2/contacts.json?uuid={contact_id}", diff --git a/pyproject.toml b/pyproject.toml index 917abff2..b7cbb25f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -111,7 +111,6 @@ ignore = [ "UP010", # TODO: Unnecessary '__future__' imports 'absolute_import', 'division' for target Python version "S105", # TODO: Possible hardcoded password assigned "B018", # TODO: Found useless expression. Either assign it to a variable or remove it. - "B006", # TODO: Do not use mutable data structures for argument defaults ] From 570704f0dfa5eb4ab10d3aac6af45bb52c5b9cb9 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 09:30:27 +0200 Subject: [PATCH 14/41] Found useless expression. Either assign it to a variable or remove it. --- eventstore/tests/test_tasks.py | 8 ++------ eventstore/tests/test_whatsapp_actions.py | 2 +- pyproject.toml | 1 - 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/eventstore/tests/test_tasks.py b/eventstore/tests/test_tasks.py index 9f7f4225..13ee57a3 100644 --- a/eventstore/tests/test_tasks.py +++ b/eventstore/tests/test_tasks.py @@ -28,9 +28,7 @@ def setUp(self): tasks.get_today = override_get_today tasks.rapidpro = TembaClient("textit.in", "test-token") - def add_rapidpro_contact_list_response( - self, contact_id, fields, urns=None - ): + def add_rapidpro_contact_list_response(self, contact_id, fields, urns=None): if urns is None: urns = ["whatsapp:27820001001"] responses.add( @@ -55,9 +53,7 @@ def add_rapidpro_contact_list_response( }, ) - def add_rapidpro_contact_update_response( - self, contact_id, fields, urns=None - ): + def add_rapidpro_contact_update_response(self, contact_id, fields, urns=None): if urns is None: urns = ["whatsapp:27820001001"] responses.add( diff --git a/eventstore/tests/test_whatsapp_actions.py b/eventstore/tests/test_whatsapp_actions.py index 46e130c7..ca6eb3a9 100644 --- a/eventstore/tests/test_whatsapp_actions.py +++ b/eventstore/tests/test_whatsapp_actions.py @@ -201,7 +201,7 @@ def test_handle_edd_label_disabled(self): with patch("eventstore.whatsapp_actions.handle_edd_message") as handle: handle_inbound(message) - handle.assert_not_called + _var = handle.assert_not_called class UpdateRapidproAlertOptoutTests(DjangoTestCase): diff --git a/pyproject.toml b/pyproject.toml index b7cbb25f..618df128 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -110,7 +110,6 @@ ignore = [ "B904", # TODO: Within an 'except' clause, raise exceptions with 'raise ... from err' or 'raise ... from None' "UP010", # TODO: Unnecessary '__future__' imports 'absolute_import', 'division' for target Python version "S105", # TODO: Possible hardcoded password assigned - "B018", # TODO: Found useless expression. Either assign it to a variable or remove it. ] From d982515c98616dc3ab632a10250b6a02a38a9506 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 09:34:37 +0200 Subject: [PATCH 15/41] Possible hardcoded password assigned --- ndoh_hub/testsettings.py | 2 +- pyproject.toml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ndoh_hub/testsettings.py b/ndoh_hub/testsettings.py index e9fa8f9c..f40a8dc5 100644 --- a/ndoh_hub/testsettings.py +++ b/ndoh_hub/testsettings.py @@ -1,7 +1,7 @@ from ndoh_hub.settings import * # noqa: F403 # flake8: noqa # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = "TESTSEKRET" +SECRET_KEY = "TESTSEKRET" # noqa - Ok to use hardcoded secrets in tests # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True diff --git a/pyproject.toml b/pyproject.toml index 618df128..63cff46f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -109,7 +109,6 @@ ignore = [ "S311", # TODO: Standard pseudo-random generators are not suitable for cryptographic purposes "B904", # TODO: Within an 'except' clause, raise exceptions with 'raise ... from err' or 'raise ... from None' "UP010", # TODO: Unnecessary '__future__' imports 'absolute_import', 'division' for target Python version - "S105", # TODO: Possible hardcoded password assigned ] From 721c8257c612b1cb4f143349bc17af5a04e8ce0a Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 09:37:19 +0200 Subject: [PATCH 16/41] Unnecessary imports for target Python version --- ndoh_hub/celery.py | 2 -- ndoh_hub/utils.py | 2 -- pyproject.toml | 1 - 3 files changed, 5 deletions(-) diff --git a/ndoh_hub/celery.py b/ndoh_hub/celery.py index b3f687c2..15452fb5 100644 --- a/ndoh_hub/celery.py +++ b/ndoh_hub/celery.py @@ -1,5 +1,3 @@ -from __future__ import absolute_import - import os from celery import Celery diff --git a/ndoh_hub/utils.py b/ndoh_hub/utils.py index a9c59bcc..c6d6fd64 100644 --- a/ndoh_hub/utils.py +++ b/ndoh_hub/utils.py @@ -1,5 +1,3 @@ -from __future__ import absolute_import, division - import base64 import datetime import hmac diff --git a/pyproject.toml b/pyproject.toml index 63cff46f..a0e72b30 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -108,7 +108,6 @@ ignore = [ "UP031", # TODO: Use format specifiers instead of percent format "S311", # TODO: Standard pseudo-random generators are not suitable for cryptographic purposes "B904", # TODO: Within an 'except' clause, raise exceptions with 'raise ... from err' or 'raise ... from None' - "UP010", # TODO: Unnecessary '__future__' imports 'absolute_import', 'division' for target Python version ] From 462ce1ba02e7eed64b2a205a7c91ea10d7504a3f Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 09:42:55 +0200 Subject: [PATCH 17/41] Within an 'except' clause, raise exceptions with 'raise ... from err' or 'raise ... from None' --- eventstore/models.py | 6 +++--- eventstore/serializers.py | 2 +- eventstore/validators.py | 12 ++++++------ eventstore/views.py | 4 ++-- ndoh_hub/utils.py | 4 ++-- pyproject.toml | 1 - 6 files changed, 14 insertions(+), 15 deletions(-) diff --git a/eventstore/models.py b/eventstore/models.py index 6c3d70ef..a257243c 100644 --- a/eventstore/models.py +++ b/eventstore/models.py @@ -1048,7 +1048,7 @@ def clean(self): if not is_valid_edd_date(edd): raise ValidationError("EDD must be between now and 9 months") except ValueError as e: - raise ValidationError(f"Invalid EDD date, {str(e)}") + raise ValidationError(f"Invalid EDD date, {str(e)}") from e except TypeError: # Should be handled by the individual field validator pass @@ -1056,7 +1056,7 @@ def clean(self): try: date(self.baby_dob_year, self.baby_dob_month, self.baby_dob_day) except ValueError as e: - raise ValidationError(f"Invalid Baby DOB date, {str(e)}") + raise ValidationError(f"Invalid Baby DOB date, {str(e)}") from e except TypeError: # Should be handled by the individual field validator pass @@ -1089,7 +1089,7 @@ def clean(self): try: date(self.dob_year, self.dob_month, self.dob_day) except ValueError as e: - raise ValidationError(f"Invalid date of birth date, {str(e)}") + raise ValidationError(f"Invalid date of birth date, {str(e)}") from e class OpenHIMQueue(models.Model): diff --git a/eventstore/serializers.py b/eventstore/serializers.py index 6f1d9624..df2e7519 100644 --- a/eventstore/serializers.py +++ b/eventstore/serializers.py @@ -139,7 +139,7 @@ def to_internal_value(self, data): try: number = phonenumbers.parse(data, self.country) except phonenumbers.NumberParseException as e: - raise serializers.ValidationError(str(e)) + raise serializers.ValidationError(str(e)) from e if not phonenumbers.is_possible_number(number): raise serializers.ValidationError("Not a possible phone number") if not phonenumbers.is_valid_number(number): diff --git a/eventstore/validators.py b/eventstore/validators.py index 8a94689f..3823bd4a 100644 --- a/eventstore/validators.py +++ b/eventstore/validators.py @@ -41,7 +41,7 @@ def validate_sa_id_number(value): try: date(year, int(match.group("month")), int(match.group("day"))) except ValueError as e: - raise ValidationError(f"Invalid ID number date: {str(e)}") + raise ValidationError(f"Invalid ID number date: {str(e)}") from e if int(match.group("gender")) >= 5000: raise ValidationError("Invalid ID number: for male") if not luhn_verify(value): @@ -56,22 +56,22 @@ def validate_facility_code(value): def posix_timestamp(value): try: datetime.fromtimestamp(int(value)) - except ValueError: - raise ValidationError("Invalid POSIX timestamp.") + except ValueError as ve: + raise ValidationError("Invalid POSIX timestamp.") from ve def geographic_coordinate(value): try: Location(value) - except AttributeError: - raise ValidationError("Invalid ISO6709 geographic coordinate") + except AttributeError as ae: + raise ValidationError("Invalid ISO6709 geographic coordinate") from ae def _phone_number(value, country): try: number = phonenumbers.parse(value, country) except phonenumbers.NumberParseException as e: - raise ValidationError(str(e)) + raise ValidationError(str(e)) from e if not phonenumbers.is_possible_number(number): raise ValidationError("Not a possible phone number") if not phonenumbers.is_valid_number(number): diff --git a/eventstore/views.py b/eventstore/views.py index 2ec0ce9c..21d77a8a 100644 --- a/eventstore/views.py +++ b/eventstore/views.py @@ -573,8 +573,8 @@ class DeliveryFailureViewSet(GenericViewSet, CreateModelMixin, RetrieveModelMixi def get_object(self): try: obj = DeliveryFailure.objects.get(contact_id=self.kwargs["pk"]) - except DeliveryFailure.DoesNotExist: - raise Http404() + except DeliveryFailure.DoesNotExist as df: + raise Http404() from df self.check_object_permissions(self.request, obj) return obj diff --git a/ndoh_hub/utils.py b/ndoh_hub/utils.py index c6d6fd64..9f20b509 100644 --- a/ndoh_hub/utils.py +++ b/ndoh_hub/utils.py @@ -35,8 +35,8 @@ def validate_signature(request): secret = settings.TURN_HMAC_SECRET try: signature = request.META["HTTP_X_TURN_HOOK_SIGNATURE"] - except KeyError: - raise AuthenticationFailed("X-Turn-Hook-Signature header required") + except KeyError as ke: + raise AuthenticationFailed("X-Turn-Hook-Signature header required") from ke h = hmac.new(secret.encode(), request.body, sha256) diff --git a/pyproject.toml b/pyproject.toml index a0e72b30..15e59dfa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -107,7 +107,6 @@ ignore = [ "UP008", # TODO: Use 'super()' instead of 'super(__class__, self)' "UP031", # TODO: Use format specifiers instead of percent format "S311", # TODO: Standard pseudo-random generators are not suitable for cryptographic purposes - "B904", # TODO: Within an 'except' clause, raise exceptions with 'raise ... from err' or 'raise ... from None' ] From 3fb00c5af78b539cab5d598f1b998281fa1b0990 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 09:46:34 +0200 Subject: [PATCH 18/41] Standard pseudo-random generators are not suitable for cryptographic purposes --- eventstore/models.py | 6 +++--- ndoh_hub/utils.py | 2 +- pyproject.toml | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/eventstore/models.py b/eventstore/models.py index a257243c..a3fbb101 100644 --- a/eventstore/models.py +++ b/eventstore/models.py @@ -608,7 +608,7 @@ def get_random_study_b_arm(self): actual_total, actual_percentage = self.get_study_totals_per_province() if actual_total < target_total or actual_percentage < target_percentage: - return random.choice(self.STUDY_ARM_B_CHOICES)[0] + return random.choice(self.STUDY_ARM_B_CHOICES)[0] # noqa: S311 - Not being used for crypto purposes def get_study_totals_per_province(self): all_provinces = HCSStudyBRandomization.objects.filter( @@ -815,10 +815,10 @@ def get_random_study_arm(self): actual_total, actual_percentage = self.get_study_totals_per_province() if actual_total < target_total or actual_percentage < target_percentage: - return random.choice(self.STUDY_ARM_CHOICES)[0] + return random.choice(self.STUDY_ARM_CHOICES)[0] # noqa: S311 - Not being used for crypto purposes def get_random_study_quarantine_arm(self): - return random.choice(self.STUDY_ARM_QUARANTINE_CHOICES)[0] + return random.choice(self.STUDY_ARM_QUARANTINE_CHOICES)[0] # noqa: S311 - Not being used for crypto purposes class CDUAddressUpdate(models.Model): diff --git a/ndoh_hub/utils.py b/ndoh_hub/utils.py index 9f20b509..a4aca38a 100644 --- a/ndoh_hub/utils.py +++ b/ndoh_hub/utils.py @@ -190,7 +190,7 @@ def get_random_date(start_date=None): time_between_dates = end_date - start_date days_between_dates = time_between_dates.days - random_number_of_days = random.randrange(days_between_dates) + random_number_of_days = random.randrange(days_between_dates) # noqa: S311 - Not being used for crypto purposes return start_date + datetime.timedelta(days=random_number_of_days) diff --git a/pyproject.toml b/pyproject.toml index 15e59dfa..8e4138b5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -106,7 +106,6 @@ ignore = [ "UP031", # TODO: Use format specifiers instead of percent format "UP008", # TODO: Use 'super()' instead of 'super(__class__, self)' "UP031", # TODO: Use format specifiers instead of percent format - "S311", # TODO: Standard pseudo-random generators are not suitable for cryptographic purposes ] From fed49a6937addaefbe3eb9cbd885a330034733e7 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 09:49:36 +0200 Subject: [PATCH 19/41] Use 'super()' instead of 'super(__class__, self)' --- eventstore/serializers.py | 2 +- pyproject.toml | 2 -- registrations/test_views.py | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/eventstore/serializers.py b/eventstore/serializers.py index df2e7519..9f21faa7 100644 --- a/eventstore/serializers.py +++ b/eventstore/serializers.py @@ -129,7 +129,7 @@ class MSISDNField(serializers.CharField): def __init__(self, *args, **kwargs): self.country = kwargs.pop("country", None) - return super(MSISDNField, self).__init__(*args, **kwargs) + return super().__init__(*args, **kwargs) def to_representation(self, obj): number = phonenumbers.parse(obj, self.country) diff --git a/pyproject.toml b/pyproject.toml index 8e4138b5..0ebd77d2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -104,8 +104,6 @@ ignore = [ "S112", # TODO: 'try'-'except'-'continue' detected, consider logging the exception "S101", # TODO: Use of 'assert' detected "UP031", # TODO: Use format specifiers instead of percent format - "UP008", # TODO: Use 'super()' instead of 'super(__class__, self)' - "UP031", # TODO: Use format specifiers instead of percent format ] diff --git a/registrations/test_views.py b/registrations/test_views.py index 2735056c..02c93b7b 100644 --- a/registrations/test_views.py +++ b/registrations/test_views.py @@ -18,7 +18,7 @@ def setUp(self): class AuthenticatedAPITestCase(HUBAPITestCase): def setUp(self): - super(AuthenticatedAPITestCase, self).setUp() + super().setUp() # Normal User setup self.normalusername = "testnormaluser" From ac1974fc248892c576f814afb4a376d7741ce252 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 09:51:06 +0200 Subject: [PATCH 20/41] Use format specifiers instead of percent format --- eventstore/models.py | 6 +++--- ndoh_hub/utils.py | 2 +- registrations/models.py | 2 +- registrations/test_views.py | 4 +++- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/eventstore/models.py b/eventstore/models.py index a3fbb101..25cb7a5d 100644 --- a/eventstore/models.py +++ b/eventstore/models.py @@ -608,7 +608,7 @@ def get_random_study_b_arm(self): actual_total, actual_percentage = self.get_study_totals_per_province() if actual_total < target_total or actual_percentage < target_percentage: - return random.choice(self.STUDY_ARM_B_CHOICES)[0] # noqa: S311 - Not being used for crypto purposes + return random.choice(self.STUDY_ARM_B_CHOICES)[0] # noqa: S311 - Not being used for crypto purposes def get_study_totals_per_province(self): all_provinces = HCSStudyBRandomization.objects.filter( @@ -815,10 +815,10 @@ def get_random_study_arm(self): actual_total, actual_percentage = self.get_study_totals_per_province() if actual_total < target_total or actual_percentage < target_percentage: - return random.choice(self.STUDY_ARM_CHOICES)[0] # noqa: S311 - Not being used for crypto purposes + return random.choice(self.STUDY_ARM_CHOICES)[0] # noqa: S311 - Not being used for crypto purposes def get_random_study_quarantine_arm(self): - return random.choice(self.STUDY_ARM_QUARANTINE_CHOICES)[0] # noqa: S311 - Not being used for crypto purposes + return random.choice(self.STUDY_ARM_QUARANTINE_CHOICES)[0] # noqa: S311 - Not being used for crypto purposes class CDUAddressUpdate(models.Model): diff --git a/ndoh_hub/utils.py b/ndoh_hub/utils.py index a4aca38a..a601009b 100644 --- a/ndoh_hub/utils.py +++ b/ndoh_hub/utils.py @@ -190,7 +190,7 @@ def get_random_date(start_date=None): time_between_dates = end_date - start_date days_between_dates = time_between_dates.days - random_number_of_days = random.randrange(days_between_dates) # noqa: S311 - Not being used for crypto purposes + random_number_of_days = random.randrange(days_between_dates) # noqa: S311 - Not being used for crypto purposes return start_date + datetime.timedelta(days=random_number_of_days) diff --git a/registrations/models.py b/registrations/models.py index c96f6b8b..e4781ca4 100644 --- a/registrations/models.py +++ b/registrations/models.py @@ -28,7 +28,7 @@ class Source(models.Model): updated_at = models.DateTimeField(auto_now=True) def __str__(self): - return "%s" % self.name + return "{}".format(self.name) class Registration(models.Model): diff --git a/registrations/test_views.py b/registrations/test_views.py index 02c93b7b..a3c45341 100644 --- a/registrations/test_views.py +++ b/registrations/test_views.py @@ -127,7 +127,9 @@ def test_filter_by_code(self): class WhatsAppContactCheckViewTests(AuthenticatedAPITestCase): def setUp(self): super().setUp() - self.normalclient.credentials(HTTP_AUTHORIZATION="Bearer %s" % self.normaltoken) + self.normalclient.credentials( + HTTP_AUTHORIZATION="Bearer {}".format(self.normaltoken) + ) def test_authentication_required(self): """ From 61b890aaeaaa7f154feaf2127b260e66e21f5e1c Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 09:58:33 +0200 Subject: [PATCH 21/41] 'try'-'except'-'continue' detected, consider logging the exception --- pyproject.toml | 4 +--- scripts/migrate_to_rapidpro/collect_information.py | 4 +++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 0ebd77d2..e624d4d3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -101,9 +101,7 @@ ignore = [ "E721", # TODO: Use 'is' and 'is not' for type comparisons, or 'isinstance()' for isinstance checks "SIM102", # TODO: Use a single 'if' statement instead of nested 'if' statements "SIM105", # TODO: Use 'contextlib.suppress(Exception)' instead of 'try'-'except'-'pass' - "S112", # TODO: 'try'-'except'-'continue' detected, consider logging the exception - "S101", # TODO: Use of 'assert' detected - "UP031", # TODO: Use format specifiers instead of percent format + "S101", # TODO: Use of 'assert' detected - FWB: Looks like this is only used in migration files ] diff --git a/scripts/migrate_to_rapidpro/collect_information.py b/scripts/migrate_to_rapidpro/collect_information.py index cb133b47..82efbe9f 100644 --- a/scripts/migrate_to_rapidpro/collect_information.py +++ b/scripts/migrate_to_rapidpro/collect_information.py @@ -1,4 +1,5 @@ import json +import logging import os import time @@ -17,7 +18,8 @@ def get_addresses(addresses): assert phonenumbers.is_possible_number(p) assert phonenumbers.is_valid_number(p) p = phonenumbers.format_number(p, phonenumbers.PhoneNumberFormat.E164) - except Exception: + except Exception as _e: + logging.exception("Error occurred") continue if details.get("default"): return [p] From 13ec3dd4c3eaa786b9e24943cfc3903baf7d34e2 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 10:05:49 +0200 Subject: [PATCH 22/41] Use 'contextlib.suppress(Exception)' instead of 'try'-'except'-'pass' --- pyproject.toml | 2 +- scripts/migrate_to_rapidpro/collect_information.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e624d4d3..a01f2987 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -100,7 +100,7 @@ ignore = [ "SIM110", # TODO: Use 'return any("post" in group["name"].lower() for group in contact["groups"])' instead of 'for' loop "E721", # TODO: Use 'is' and 'is not' for type comparisons, or 'isinstance()' for isinstance checks "SIM102", # TODO: Use a single 'if' statement instead of nested 'if' statements - "SIM105", # TODO: Use 'contextlib.suppress(Exception)' instead of 'try'-'except'-'pass' + #Ignores below this line needs to be checked out "S101", # TODO: Use of 'assert' detected - FWB: Looks like this is only used in migration files ] diff --git a/scripts/migrate_to_rapidpro/collect_information.py b/scripts/migrate_to_rapidpro/collect_information.py index 82efbe9f..2141d47e 100644 --- a/scripts/migrate_to_rapidpro/collect_information.py +++ b/scripts/migrate_to_rapidpro/collect_information.py @@ -1,3 +1,4 @@ +import contextlib import json import logging import os @@ -104,10 +105,8 @@ def process_registration(identities, id, data): identities[id]["baby_dobs"].append(data["baby_dob"]) uuid_device = data.get("uuid_device") or data.get("operator_id") if uuid_device and not identities[id].get("msisdn_device"): - try: + with contextlib.suppress(Exception): identities[id]["msisdn_device"] = identities[uuid_device]["msisdns"][0] - except Exception: - pass if data.get("language") and not identities[id].get("language"): if data["language"] in LANGUAGES: identities[id]["language"] = data["language"].rstrip("_ZA") From 340904ebfa577b40c760304f95881343e9a425c4 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 10:29:00 +0200 Subject: [PATCH 23/41] Use a single 'if' statement instead of nested 'if' statements --- eventstore/models.py | 23 +++++++++++-------- pyproject.toml | 1 - .../collect_information.py | 14 ++++++----- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/eventstore/models.py b/eventstore/models.py index 25cb7a5d..b5f2cc08 100644 --- a/eventstore/models.py +++ b/eventstore/models.py @@ -588,9 +588,11 @@ class HCSStudyBRandomization(models.Model): ) def process_study_b(self): - if self.msisdn not in settings.HCS_STUDY_B_WHITELIST: - if not settings.HCS_STUDY_B_ACTIVE: - return + if ( + self.msisdn not in settings.HCS_STUDY_B_WHITELIST + and not settings.HCS_STUDY_B_ACTIVE + ): + return if self.created_by in settings.HCS_STUDY_B_CREATED_BY and not self.study_b_arm: self.study_b_arm = self.get_random_study_b_arm() @@ -754,9 +756,11 @@ def update_post_screening_study_arms(self, risk, created_by): self.process_study_c(risk, created_by) def process_study_a(self, created_by): - if self.msisdn not in settings.HCS_STUDY_A_WHITELIST: - if not settings.HCS_STUDY_A_ACTIVE: - return + if ( + self.msisdn not in settings.HCS_STUDY_A_WHITELIST + and not settings.HCS_STUDY_A_ACTIVE + ): + return if created_by == settings.HCS_STUDY_A_CREATED_BY and not self.hcs_study_a_arm: self.hcs_study_a_arm = self.get_random_study_arm() @@ -1077,9 +1081,10 @@ def clean(self): raise ValidationError("Passport country required for passport ID type") if self.id_type == self.IDType.PASSPORT and not self.passport_number: raise ValidationError("Passport number required for passport ID type") - if self.id_type == self.IDType.NONE: - if self.dob_year is None or self.dob_month is None or self.dob_year is None: - raise ValidationError("Date of birth required for none ID type") + if self.id_type == self.IDType.NONE and ( + self.dob_year is None or self.dob_month is None or self.dob_year is None + ): + raise ValidationError("Date of birth required for none ID type") if ( self.dob_year is not None diff --git a/pyproject.toml b/pyproject.toml index a01f2987..4b582404 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -99,7 +99,6 @@ ignore = [ "S608", # TODO: Possible SQL injection vector through string-based query construction "SIM110", # TODO: Use 'return any("post" in group["name"].lower() for group in contact["groups"])' instead of 'for' loop "E721", # TODO: Use 'is' and 'is not' for type comparisons, or 'isinstance()' for isinstance checks - "SIM102", # TODO: Use a single 'if' statement instead of nested 'if' statements #Ignores below this line needs to be checked out "S101", # TODO: Use of 'assert' detected - FWB: Looks like this is only used in migration files diff --git a/scripts/migrate_to_rapidpro/collect_information.py b/scripts/migrate_to_rapidpro/collect_information.py index 2141d47e..86b4bee4 100644 --- a/scripts/migrate_to_rapidpro/collect_information.py +++ b/scripts/migrate_to_rapidpro/collect_information.py @@ -95,9 +95,8 @@ def process_registration(identities, id, data): "sa_id_no", "consent", ]: - if data.get(k): - if not identities[id].get(k): - identities[id][k] = data[k] + if data.get(k) and not identities[id].get(k): + identities[id][k] = data[k] if data.get("baby_dob"): if not identities[id].get("baby_dobs"): identities[id]["baby_dobs"] = [data["baby_dob"]] @@ -107,9 +106,12 @@ def process_registration(identities, id, data): if uuid_device and not identities[id].get("msisdn_device"): with contextlib.suppress(Exception): identities[id]["msisdn_device"] = identities[uuid_device]["msisdns"][0] - if data.get("language") and not identities[id].get("language"): - if data["language"] in LANGUAGES: - identities[id]["language"] = data["language"].rstrip("_ZA") + if ( + data.get("language") + and not identities[id].get("language") + and data["language"] in LANGUAGES + ): + identities[id]["language"] = data["language"].rstrip("_ZA") def process_change(identities, id, action, data, created): From 3072035141c268be82b2870a654a075933951f73 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 10:32:11 +0200 Subject: [PATCH 24/41] Use 'is' and 'is not' for type comparisons, or 'isinstance()' for isinstance checks --- pyproject.toml | 1 - scripts/migrate_to_rapidpro/collect_information.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 4b582404..7fd18e5f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -98,7 +98,6 @@ ignore = [ "S110", # TODO: 'try'-'except'-'pass' detected, consider logging the exception "S608", # TODO: Possible SQL injection vector through string-based query construction "SIM110", # TODO: Use 'return any("post" in group["name"].lower() for group in contact["groups"])' instead of 'for' loop - "E721", # TODO: Use 'is' and 'is not' for type comparisons, or 'isinstance()' for isinstance checks #Ignores below this line needs to be checked out "S101", # TODO: Use of 'assert' detected - FWB: Looks like this is only used in migration files diff --git a/scripts/migrate_to_rapidpro/collect_information.py b/scripts/migrate_to_rapidpro/collect_information.py index 86b4bee4..4ff596f1 100644 --- a/scripts/migrate_to_rapidpro/collect_information.py +++ b/scripts/migrate_to_rapidpro/collect_information.py @@ -168,7 +168,7 @@ def process_subscription(identities, id, name, created_at): def merge_dicts(d1, d2): for k, v in d2.items(): - if type(v) == list: + if isinstance(v, list): d1[k] = d1.get(k, []) + v else: d1[k] = v From 7bd8a0fda3a4db3ef17644284592105ee003d748 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 10:37:44 +0200 Subject: [PATCH 25/41] Use 'return any(post in group[name].lower() for group in contact[groups])' instead of 'for' loop --- pyproject.toml | 1 - scripts/migrate_to_rapidpro/fix_auto_baby_switch_data.py | 6 +----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7fd18e5f..67b6e71a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -97,7 +97,6 @@ ignore = [ "S106", # TODO: Possible hardcoded password assigned to argument "S110", # TODO: 'try'-'except'-'pass' detected, consider logging the exception "S608", # TODO: Possible SQL injection vector through string-based query construction - "SIM110", # TODO: Use 'return any("post" in group["name"].lower() for group in contact["groups"])' instead of 'for' loop #Ignores below this line needs to be checked out "S101", # TODO: Use of 'assert' detected - FWB: Looks like this is only used in migration files diff --git a/scripts/migrate_to_rapidpro/fix_auto_baby_switch_data.py b/scripts/migrate_to_rapidpro/fix_auto_baby_switch_data.py index 2c3a7e78..020cb866 100644 --- a/scripts/migrate_to_rapidpro/fix_auto_baby_switch_data.py +++ b/scripts/migrate_to_rapidpro/fix_auto_baby_switch_data.py @@ -40,11 +40,7 @@ async def get_rapidpro_contact(session, contact_id): def in_postbirth_group(contact): - for group in contact["groups"]: - if "post" in group["name"].lower(): - return True - - return False + return any("post" in group["name"].lower() for group in contact["groups"]) def get_contact_msisdn(contact): From 1f1eb006b9948e1762855370412814d6729dea92 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 10:49:13 +0200 Subject: [PATCH 26/41] 'try'-'except'-'pass' detected, consider logging the exception --- pyproject.toml | 3 +-- scripts/migrate_to_rapidpro/upload_to_rapidpro.py | 9 +++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 67b6e71a..6c6ee28c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -95,10 +95,9 @@ ignore = [ "B007", # TODO: Loop control variable 'status_code' not used within loop body "SIM115", # TODO: Use a context manager for opening files "S106", # TODO: Possible hardcoded password assigned to argument - "S110", # TODO: 'try'-'except'-'pass' detected, consider logging the exception - "S608", # TODO: Possible SQL injection vector through string-based query construction #Ignores below this line needs to be checked out "S101", # TODO: Use of 'assert' detected - FWB: Looks like this is only used in migration files + "S608", # TODO: Possible SQL injection vector through string-based query construction ] diff --git a/scripts/migrate_to_rapidpro/upload_to_rapidpro.py b/scripts/migrate_to_rapidpro/upload_to_rapidpro.py index 8ab1c51a..857735ed 100644 --- a/scripts/migrate_to_rapidpro/upload_to_rapidpro.py +++ b/scripts/migrate_to_rapidpro/upload_to_rapidpro.py @@ -1,4 +1,5 @@ import json +import logging import time from datetime import datetime @@ -26,14 +27,14 @@ def boolean_field(field, value): def normalize_timestamp(value): try: return parse_datetime(value).isoformat() - except Exception: - pass + except Exception as _e: + logging.exception("Exception occurred") try: value = parse_date(value) value = datetime.combine(value, datetime.min.time()) return value.replace(tzinfo=utc).isoformat() - except Exception: - pass + except Exception as _e: + logging.exception("Exception occurred") def datetime_field(field, value): value = normalize_timestamp(value) From 143e247d885714ab23519973b95504eb1ffef575 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 10:51:49 +0200 Subject: [PATCH 27/41] Possible hardcoded password assigned to argument --- pyproject.toml | 1 - scripts/migrate_to_rapidpro/upload_to_rapidpro.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 6c6ee28c..0da05127 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -94,7 +94,6 @@ ignore = [ "S501", #TODO: Probable use of 'requests' call with 'verify=False' disabling SSL certificate checks "B007", # TODO: Loop control variable 'status_code' not used within loop body "SIM115", # TODO: Use a context manager for opening files - "S106", # TODO: Possible hardcoded password assigned to argument #Ignores below this line needs to be checked out "S101", # TODO: Use of 'assert' detected - FWB: Looks like this is only used in migration files "S608", # TODO: Possible SQL injection vector through string-based query construction diff --git a/scripts/migrate_to_rapidpro/upload_to_rapidpro.py b/scripts/migrate_to_rapidpro/upload_to_rapidpro.py index 857735ed..60516d93 100644 --- a/scripts/migrate_to_rapidpro/upload_to_rapidpro.py +++ b/scripts/migrate_to_rapidpro/upload_to_rapidpro.py @@ -78,7 +78,7 @@ def string_field(field, value): if __name__ == "__main__": - conn = psycopg2.connect(dbname="temba", user="temba", password="temba") + conn = psycopg2.connect(dbname="temba", user="temba", password="temba") # noqa: S106 - Probably OK here cursor = conn.cursor() cursor.execute( """ From e4e40d3bac5aa87f2df907b080aa240fb6232a50 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 11:12:37 +0200 Subject: [PATCH 28/41] Loop control variable 'status_code' not used within loop body --- pyproject.toml | 3 +-- scripts/growgreat_extract/msisdn_from_details.py | 2 +- .../migrate_to_rapidpro/postbirth_contacts_without_events.py | 2 +- .../migrate_to_rapidpro/prebirth_contacts_without_events.py | 2 +- .../resubmit_jembi_requests/resubmit_recent_jembi_errors.py | 2 +- 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 0da05127..a9abe11b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -92,9 +92,8 @@ ignore = [ "C416", # TODO: Unnecessary 'list' comprehension (rewrite using 'list()') "UP004", # TODO: Class 'Template' inherits from 'object' "S501", #TODO: Probable use of 'requests' call with 'verify=False' disabling SSL certificate checks - "B007", # TODO: Loop control variable 'status_code' not used within loop body - "SIM115", # TODO: Use a context manager for opening files #Ignores below this line needs to be checked out + "SIM115", # TODO: Use a context manager for opening files - FWB: Tried fixing these, but ran into errors on tests "S101", # TODO: Use of 'assert' detected - FWB: Looks like this is only used in migration files "S608", # TODO: Possible SQL injection vector through string-based query construction diff --git a/scripts/growgreat_extract/msisdn_from_details.py b/scripts/growgreat_extract/msisdn_from_details.py index dc742cb0..afd9c038 100644 --- a/scripts/growgreat_extract/msisdn_from_details.py +++ b/scripts/growgreat_extract/msisdn_from_details.py @@ -4,7 +4,7 @@ def get_msisdn(details): last = None - for addr, addr_dets in details.get("addresses", {}).get("msisdn", {}).items(): + for addr, _addr_dets in details.get("addresses", {}).get("msisdn", {}).items(): if details.get("default") is True: return addr if details.get("optedout") is not True: diff --git a/scripts/migrate_to_rapidpro/postbirth_contacts_without_events.py b/scripts/migrate_to_rapidpro/postbirth_contacts_without_events.py index c4ed79c0..4bb4f652 100644 --- a/scripts/migrate_to_rapidpro/postbirth_contacts_without_events.py +++ b/scripts/migrate_to_rapidpro/postbirth_contacts_without_events.py @@ -65,7 +65,7 @@ contact_id = 0 start, d_print = time.time(), time.time() - for contact_id, contact_uuid, fields, group_id, created_on in cursor: + for contact_id, contact_uuid, fields, _group_id, _created_on in cursor: should_receive_msgs = False fields_to_update = {} diff --git a/scripts/migrate_to_rapidpro/prebirth_contacts_without_events.py b/scripts/migrate_to_rapidpro/prebirth_contacts_without_events.py index 5a7b40b6..dbda4aa4 100644 --- a/scripts/migrate_to_rapidpro/prebirth_contacts_without_events.py +++ b/scripts/migrate_to_rapidpro/prebirth_contacts_without_events.py @@ -65,7 +65,7 @@ contact_id = 0 start, d_print = time.time(), time.time() - for contact_id, contact_uuid, fields, group_id, created_on in cursor: + for contact_id, contact_uuid, fields, _group_id, _created_on in cursor: should_receive_msgs = False fields_to_update = {} diff --git a/scripts/resubmit_jembi_requests/resubmit_recent_jembi_errors.py b/scripts/resubmit_jembi_requests/resubmit_recent_jembi_errors.py index 4910ab27..57ff88c5 100644 --- a/scripts/resubmit_jembi_requests/resubmit_recent_jembi_errors.py +++ b/scripts/resubmit_jembi_requests/resubmit_recent_jembi_errors.py @@ -40,7 +40,7 @@ webhook_calls = [] failed_again = [] - for request_id, url, request, status_code, contact_id, day in cursor: + for request_id, url, request, _status_code, contact_id, day in cursor: day = str(day).split(" ")[0] key = f"{url}_{contact_id}_{day}" From 4f8c9a98e31ff7bb98e201d347963f43fed74dc4 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 11:17:10 +0200 Subject: [PATCH 29/41] Class 'Template' inherits from 'object' --- eventstore/tests/test_views.py | 2 +- pyproject.toml | 3 +-- scripts/migrate_to_whatsapp_templates/base.py | 2 +- scripts/upload_whatsapp_templates/upload_whatsapp_templates.py | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/eventstore/tests/test_views.py b/eventstore/tests/test_views.py index bc7552b4..0fb0251f 100644 --- a/eventstore/tests/test_views.py +++ b/eventstore/tests/test_views.py @@ -58,7 +58,7 @@ ) -class BaseEventTestCase(object): +class BaseEventTestCase: def test_authentication_required(self): """ There must be an authenticated user to make the request diff --git a/pyproject.toml b/pyproject.toml index a9abe11b..d735541d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -90,9 +90,8 @@ ignore = [ "PTH123", # TODO: 'open()' should be replaced by 'Path.open()' "UP030", # TODO: Use implicit references for positional format fields "C416", # TODO: Unnecessary 'list' comprehension (rewrite using 'list()') - "UP004", # TODO: Class 'Template' inherits from 'object' + # Ignores below this line needs to be checked out by someone with more knowledge of the project "S501", #TODO: Probable use of 'requests' call with 'verify=False' disabling SSL certificate checks - #Ignores below this line needs to be checked out "SIM115", # TODO: Use a context manager for opening files - FWB: Tried fixing these, but ran into errors on tests "S101", # TODO: Use of 'assert' detected - FWB: Looks like this is only used in migration files "S608", # TODO: Possible SQL injection vector through string-based query construction diff --git a/scripts/migrate_to_whatsapp_templates/base.py b/scripts/migrate_to_whatsapp_templates/base.py index 6979f19b..a3cc25ca 100644 --- a/scripts/migrate_to_whatsapp_templates/base.py +++ b/scripts/migrate_to_whatsapp_templates/base.py @@ -4,7 +4,7 @@ from ndoh_hub.constants import WHATSAPP_LANGUAGE_MAP -class BaseMigration(object): +class BaseMigration: TEMPLATE_NAME = "" def get_template_variables(self, message): diff --git a/scripts/upload_whatsapp_templates/upload_whatsapp_templates.py b/scripts/upload_whatsapp_templates/upload_whatsapp_templates.py index 0ec77fc1..d307ecb6 100644 --- a/scripts/upload_whatsapp_templates/upload_whatsapp_templates.py +++ b/scripts/upload_whatsapp_templates/upload_whatsapp_templates.py @@ -18,7 +18,7 @@ def validate_length(instance, attribute, value): @attr.s -class Template(object): +class Template: category = attr.ib( validator=attr.validators.in_( ( From 2febd395833635aea0fab18bf85109770c36758e Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 11:19:36 +0200 Subject: [PATCH 30/41] Unnecessary 'list' comprehension (rewrite using 'list()') --- pyproject.toml | 1 - .../whatsapp_send_errors/send_rapidpro_wa_failures_to_hub.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index d735541d..b880960e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -89,7 +89,6 @@ ignore = [ "UP032", # TODO: Use f-string instead of 'format' call "PTH123", # TODO: 'open()' should be replaced by 'Path.open()' "UP030", # TODO: Use implicit references for positional format fields - "C416", # TODO: Unnecessary 'list' comprehension (rewrite using 'list()') # Ignores below this line needs to be checked out by someone with more knowledge of the project "S501", #TODO: Probable use of 'requests' call with 'verify=False' disabling SSL certificate checks "SIM115", # TODO: Use a context manager for opening files - FWB: Tried fixing these, but ran into errors on tests diff --git a/scripts/whatsapp_send_errors/send_rapidpro_wa_failures_to_hub.py b/scripts/whatsapp_send_errors/send_rapidpro_wa_failures_to_hub.py index f472be3f..6c3ffeaf 100644 --- a/scripts/whatsapp_send_errors/send_rapidpro_wa_failures_to_hub.py +++ b/scripts/whatsapp_send_errors/send_rapidpro_wa_failures_to_hub.py @@ -33,7 +33,7 @@ def get_send_errors(error_date): """, (error_date, CHANNEL_ID), ) - return [(urn, error_timestamp) for urn, error_timestamp in cursor] + return list(cursor) def send_error_to_hub(contact_id, timestamp): From 94575cdadb8ca7a01abe52329f82b38c5b24251c Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 11:21:58 +0200 Subject: [PATCH 31/41] Use implicit references for positional format fields --- ndoh_hub/celery.py | 2 +- pyproject.toml | 1 - tools/add-identity-to-jembi-csv.py | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ndoh_hub/celery.py b/ndoh_hub/celery.py index 15452fb5..8ecf2aa2 100644 --- a/ndoh_hub/celery.py +++ b/ndoh_hub/celery.py @@ -15,4 +15,4 @@ @app.task(bind=True) def debug_task(self): - print("Request: {0!r}".format(self.request)) + print("Request: {!r}".format(self.request)) diff --git a/pyproject.toml b/pyproject.toml index b880960e..9c7b5bcd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -88,7 +88,6 @@ ignore = [ "PTH120", # TODO: 'os.path.dirname()' should be replaced by 'Path.parent' maybe use pathlib? "UP032", # TODO: Use f-string instead of 'format' call "PTH123", # TODO: 'open()' should be replaced by 'Path.open()' - "UP030", # TODO: Use implicit references for positional format fields # Ignores below this line needs to be checked out by someone with more knowledge of the project "S501", #TODO: Probable use of 'requests' call with 'verify=False' disabling SSL certificate checks "SIM115", # TODO: Use a context manager for opening files - FWB: Tried fixing these, but ran into errors on tests diff --git a/tools/add-identity-to-jembi-csv.py b/tools/add-identity-to-jembi-csv.py index eca91d50..b0b6f645 100644 --- a/tools/add-identity-to-jembi-csv.py +++ b/tools/add-identity-to-jembi-csv.py @@ -29,7 +29,7 @@ reader = csv.reader(csv_file, delimiter=";") writer = csv.writer(out_file, delimiter=";") for row in reader: - msisdn = "+{0}".format(row[1]) + msisdn = "+{}".format(row[1]) res = con.execute(select([tbl.c.id]).where(tbl.c.msisdn == msisdn)).fetchone() new_row = list(row) if res: From 0c5fa390704eab96292a372828219765bbc22f5f Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 11:23:36 +0200 Subject: [PATCH 32/41] 'open()' should be replaced by 'Path.open()' maybe use pathlib --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 9c7b5bcd..93985614 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -87,7 +87,7 @@ ignore = [ "PTH100", # TODO: 'os.path.abspath()' should be replaced by 'Path.resolve()' maybe use pathlib? "PTH120", # TODO: 'os.path.dirname()' should be replaced by 'Path.parent' maybe use pathlib? "UP032", # TODO: Use f-string instead of 'format' call - "PTH123", # TODO: 'open()' should be replaced by 'Path.open()' + "PTH123", # TODO: 'open()' should be replaced by 'Path.open()' maybe use pathlib? # Ignores below this line needs to be checked out by someone with more knowledge of the project "S501", #TODO: Probable use of 'requests' call with 'verify=False' disabling SSL certificate checks "SIM115", # TODO: Use a context manager for opening files - FWB: Tried fixing these, but ran into errors on tests From 9a93005ef9a30b593c157cf5038fe6ba3be71316 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Mon, 21 Oct 2024 11:25:39 +0200 Subject: [PATCH 33/41] Use f-string instead of 'format' call --- eventstore/models.py | 4 +--- eventstore/tasks.py | 10 +++++----- eventstore/views.py | 2 +- ndoh_hub/auth.py | 2 +- ndoh_hub/celery.py | 2 +- ndoh_hub/utils.py | 2 +- pyproject.toml | 1 - registrations/models.py | 4 ++-- registrations/test_views.py | 4 +--- scripts/migrate_to_rapidpro/bulk_archive_chats.py | 6 +++--- .../send_rapidpro_wa_failures_to_hub.py | 2 +- tools/add-identity-to-jembi-csv.py | 4 ++-- 12 files changed, 19 insertions(+), 24 deletions(-) diff --git a/eventstore/models.py b/eventstore/models.py index b5f2cc08..dd095117 100644 --- a/eventstore/models.py +++ b/eventstore/models.py @@ -84,9 +84,7 @@ class OptOut(models.Model): data = models.JSONField(default=dict, blank=True, null=True) def __str__(self): - return "{} opt out: {} <{}>".format( - self.get_optout_type_display(), self.get_reason_display(), self.contact_id - ) + return f"{self.get_optout_type_display()} opt out: {self.get_reason_display()} <{self.contact_id}>" class BabySwitch(models.Model): diff --git a/eventstore/tasks.py b/eventstore/tasks.py index 271dae6f..c905cdee 100644 --- a/eventstore/tasks.py +++ b/eventstore/tasks.py @@ -265,7 +265,7 @@ def delete_rapidpro_contact_by_uuid(contact_uuid): ) def archive_turn_conversation(urn, message_id, reason): headers = { - "Authorization": "Bearer {}".format(settings.TURN_TOKEN), + "Authorization": f"Bearer {settings.TURN_TOKEN}", "Accept": "application/vnd.v1+json", "Content-Type": "application/json", } @@ -545,7 +545,7 @@ def post_random_contacts_to_slack_channel( def get_turn_profile_link(contact_number): if settings.TURN_URL and settings.TURN_TOKEN: turn_header = { - "Authorization": "Bearer {}".format(settings.TURN_TOKEN), + "Authorization": f"Bearer {settings.TURN_TOKEN}", "Accept": "application/vnd.v1+json", } @@ -606,7 +606,7 @@ def get_text_or_caption_from_turn_message(message: dict) -> str: pass for message_type in ("image", "document", "audio", "video", "voice", "sticker"): try: - return message[message_type].get("caption", "<{}>".format(message_type)) + return message[message_type].get("caption", f"<{message_type}>") except KeyError: pass @@ -665,9 +665,9 @@ def get_engage_inbound_and_reply(wa_contact_id, message_id): """ response = requests.get( - urljoin(settings.ENGAGE_URL, "v1/contacts/{}/messages".format(wa_contact_id)), + urljoin(settings.ENGAGE_URL, f"v1/contacts/{wa_contact_id}/messages"), headers={ - "Authorization": "Bearer {}".format(settings.ENGAGE_TOKEN), + "Authorization": f"Bearer {settings.ENGAGE_TOKEN}", "Accept": "application/vnd.v1+json", }, ) diff --git a/eventstore/views.py b/eventstore/views.py index 21d77a8a..267e8a22 100644 --- a/eventstore/views.py +++ b/eventstore/views.py @@ -92,7 +92,7 @@ def CursorPaginationFactory(field): class CustomCursorPagination(CursorPagination): ordering = field - name = "{}CursorPagination".format(field.capitalize()) + name = f"{field.capitalize()}CursorPagination" CustomCursorPagination.__name__ = name CustomCursorPagination.__qualname__ = name diff --git a/ndoh_hub/auth.py b/ndoh_hub/auth.py index ee1814d3..2ffc53ee 100644 --- a/ndoh_hub/auth.py +++ b/ndoh_hub/auth.py @@ -12,5 +12,5 @@ def authenticate_credentials(self, key): Does a cached lookup for a user for the given token """ return locmem_cache.get_or_set( - "authtoken:{}".format(key), partial(super().authenticate_credentials, key) + f"authtoken:{key}", partial(super().authenticate_credentials, key) ) diff --git a/ndoh_hub/celery.py b/ndoh_hub/celery.py index 8ecf2aa2..edc76238 100644 --- a/ndoh_hub/celery.py +++ b/ndoh_hub/celery.py @@ -15,4 +15,4 @@ @app.task(bind=True) def debug_task(self): - print("Request: {!r}".format(self.request)) + print(f"Request: {self.request!r}") diff --git a/ndoh_hub/utils.py b/ndoh_hub/utils.py index a601009b..0e2aa1c2 100644 --- a/ndoh_hub/utils.py +++ b/ndoh_hub/utils.py @@ -215,7 +215,7 @@ def update_turn_contact_details(wa_id, fields): "Accept": "application/vnd.v1+json", } response = requests.patch( - urljoin(settings.TURN_URL, "/v1/contacts/{}".format(wa_id)), + urljoin(settings.TURN_URL, f"/v1/contacts/{wa_id}"), json=fields, headers=headers, ) diff --git a/pyproject.toml b/pyproject.toml index 93985614..c42ad5a7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,7 +86,6 @@ ignore = [ "PTH118", # TODO: Switch to pathlib "PTH100", # TODO: 'os.path.abspath()' should be replaced by 'Path.resolve()' maybe use pathlib? "PTH120", # TODO: 'os.path.dirname()' should be replaced by 'Path.parent' maybe use pathlib? - "UP032", # TODO: Use f-string instead of 'format' call "PTH123", # TODO: 'open()' should be replaced by 'Path.open()' maybe use pathlib? # Ignores below this line needs to be checked out by someone with more knowledge of the project "S501", #TODO: Probable use of 'requests' call with 'verify=False' disabling SSL certificate checks diff --git a/registrations/models.py b/registrations/models.py index e4781ca4..9476d268 100644 --- a/registrations/models.py +++ b/registrations/models.py @@ -28,7 +28,7 @@ class Source(models.Model): updated_at = models.DateTimeField(auto_now=True) def __str__(self): - return "{}".format(self.name) + return f"{self.name}" class Registration(models.Model): @@ -212,7 +212,7 @@ def modified_at(self): return self.history.first().history_date def __str__(self): - return "{}: {}".format(self.label, self.position) + return f"{self.label}: {self.position}" class WhatsAppContact(models.Model): diff --git a/registrations/test_views.py b/registrations/test_views.py index a3c45341..ea6c8b08 100644 --- a/registrations/test_views.py +++ b/registrations/test_views.py @@ -127,9 +127,7 @@ def test_filter_by_code(self): class WhatsAppContactCheckViewTests(AuthenticatedAPITestCase): def setUp(self): super().setUp() - self.normalclient.credentials( - HTTP_AUTHORIZATION="Bearer {}".format(self.normaltoken) - ) + self.normalclient.credentials(HTTP_AUTHORIZATION=f"Bearer {self.normaltoken}") def test_authentication_required(self): """ diff --git a/scripts/migrate_to_rapidpro/bulk_archive_chats.py b/scripts/migrate_to_rapidpro/bulk_archive_chats.py index fc6a2378..ca98c052 100644 --- a/scripts/migrate_to_rapidpro/bulk_archive_chats.py +++ b/scripts/migrate_to_rapidpro/bulk_archive_chats.py @@ -22,12 +22,12 @@ def get_whatsapp_messages(wa_id): headers = { - "Authorization": "Bearer {}".format(TURN_TOKEN), + "Authorization": f"Bearer {TURN_TOKEN}", "Content-Type": "application/json", "Accept": "application/vnd.v1+json", } response = requests.get( - urllib_parse.urljoin(TURN_URL, "/v1/contacts/{}/messages".format(wa_id)), + urllib_parse.urljoin(TURN_URL, f"/v1/contacts/{wa_id}/messages"), headers=headers, ) return response.json() @@ -35,7 +35,7 @@ def get_whatsapp_messages(wa_id): def archive_turn_conversation(wa_id, message_id, reason): headers = { - "Authorization": "Bearer {}".format(TURN_TOKEN), + "Authorization": f"Bearer {TURN_TOKEN}", "Accept": "application/vnd.v1+json", "Content-Type": "application/json", } diff --git a/scripts/whatsapp_send_errors/send_rapidpro_wa_failures_to_hub.py b/scripts/whatsapp_send_errors/send_rapidpro_wa_failures_to_hub.py index 6c3ffeaf..ab7f2366 100644 --- a/scripts/whatsapp_send_errors/send_rapidpro_wa_failures_to_hub.py +++ b/scripts/whatsapp_send_errors/send_rapidpro_wa_failures_to_hub.py @@ -38,7 +38,7 @@ def get_send_errors(error_date): def send_error_to_hub(contact_id, timestamp): headers = { - "Authorization": "Token {}".format(HUB_TOKEN), + "Authorization": f"Token {HUB_TOKEN}", "Content-Type": "application/json", } response = requests.post( diff --git a/tools/add-identity-to-jembi-csv.py b/tools/add-identity-to-jembi-csv.py index b0b6f645..294a097b 100644 --- a/tools/add-identity-to-jembi-csv.py +++ b/tools/add-identity-to-jembi-csv.py @@ -29,12 +29,12 @@ reader = csv.reader(csv_file, delimiter=";") writer = csv.writer(out_file, delimiter=";") for row in reader: - msisdn = "+{}".format(row[1]) + msisdn = f"+{row[1]}" res = con.execute(select([tbl.c.id]).where(tbl.c.msisdn == msisdn)).fetchone() new_row = list(row) if res: new_row.append(res["id"]) else: - print("no msisdn match for {}".format(msisdn)) + print(f"no msisdn match for {msisdn}") new_row.append("") writer.writerow(new_row) From fd2c60f3f5a4985c71c76b44faced4d7b4e4ade6 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Tue, 22 Oct 2024 06:49:07 +0200 Subject: [PATCH 34/41] GitHub Actions update --- .github/workflows/build.yaml | 1 + .github/workflows/test.yaml | 35 +++++++++++++++++++---------------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 5635e680..b9d6e2ea 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -3,6 +3,7 @@ on: push: branches: - develop + - repo-consistency tags: - "*" diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index b97cb602..c19b8a68 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -24,27 +24,30 @@ jobs: env: HUB_DATABASE: postgres://postgres:postgres@localhost:5432/ndoh_hub steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install gettext run: sudo apt-get install gettext - - uses: actions/cache@v2 - with: - path: ~/.cache/pip - key: ${{ hashFiles('requirements.txt', 'requirements-dev.txt') }}-pip - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v5.0.0 with: python-version: 3.9 - - name: Install dependancies + - uses: abatilo/actions-poetry@v2.0.0 + with: + poetry-version: "1.8.3" + - name: Install dependencies + id: install-deps run: | - python -m pip install --upgrade pip - pip install -r requirements.txt -r requirements-dev.txt - django-admin compilemessages + poetry install + - name: Check formatting + # Lints/tests should always run, even if other lints/tests have failed. + if: success() || failure() && steps.install-deps.outcome == 'success' + run: | + poetry run ruff format --check - name: Lint + if: success() || failure() && steps.install-deps.outcome == 'success' run: | - flake8 - python manage.py makemigrations registrations changes eventstore --dry-run | grep 'No changes detected' || (echo 'There are changes which require migrations.' && exit 1) - black --check . - isort -c -rc . - - name: Test + poetry run ruff check + - name: Run tests + if: success() || failure() && steps.install-deps.outcome == 'success' run: | - py.test + poetry run pytest -vv + From 3b2c0bca17933b99b239f40e1ac7303162816f08 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Tue, 22 Oct 2024 06:53:16 +0200 Subject: [PATCH 35/41] Update Dockerfile --- Dockerfile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 7f1afd8e..e8717e15 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,12 @@ FROM ghcr.io/praekeltfoundation/docker-django-bootstrap-nw:py3.9-bullseye -COPY setup.py /app -RUN pip install --no-cache-dir -e . +RUN pip install poetry==1.8.3 ENV DJANGO_SETTINGS_MODULE "ndoh_hub.settings" COPY . /app +RUN poetry config virtualenvs.create false \ + && poetry install --no-dev --no-interaction --no-ansi --no-cache + RUN apt-get-install.sh gettext; \ django-admin compilemessages; \ apt-get-purge.sh gettext From 958975ef20895997fcaefa269b89ed8fad21a1d8 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Wed, 23 Oct 2024 12:22:46 +0200 Subject: [PATCH 36/41] Removed setup.py and updated test.yaml --- .github/workflows/test.yaml | 14 +++++++---- setup.py | 49 ------------------------------------- 2 files changed, 9 insertions(+), 54 deletions(-) delete mode 100644 setup.py diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index c19b8a68..b86206bb 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -27,12 +27,10 @@ jobs: - uses: actions/checkout@v4 - name: Install gettext run: sudo apt-get install gettext - - uses: actions/setup-python@v5.0.0 + - uses: actions/setup-python@v5 with: python-version: 3.9 - - uses: abatilo/actions-poetry@v2.0.0 - with: - poetry-version: "1.8.3" + - uses: abatilo/actions-poetry@v3 - name: Install dependencies id: install-deps run: | @@ -45,7 +43,13 @@ jobs: - name: Lint if: success() || failure() && steps.install-deps.outcome == 'success' run: | - poetry run ruff check + poetry run ruff check + - name: Run migrations + if: success() || failure() && steps.install-deps.outcome == 'success' + run: | + poetry run ./manage.py makemigrations registrations changes\ + eventstore --dry-run | grep 'No changes detected' || (echo 'There\ + are changes which require migrations.' && exit 1) - name: Run tests if: success() || failure() && steps.install-deps.outcome == 'success' run: | diff --git a/setup.py b/setup.py deleted file mode 100644 index 8097070e..00000000 --- a/setup.py +++ /dev/null @@ -1,49 +0,0 @@ -from setuptools import find_packages, setup - -setup( - name="ndoh-hub", - version="0.10.25", - url="http://github.com/praekeltfoundation/ndoh-hub", - license="BSD", - author="Praekelt Foundation", - author_email="dev@praekeltfoundation.org", - packages=find_packages(), - include_package_data=True, - install_requires=[ - "Django==4.2.16", - "djangorestframework==3.15.2", - "coreapi==2.3.3", - "Markdown==3.1.1", - "dj-database-url==1.2.0", - "django-environ==0.10.0", - "psycopg2-binary==2.8.6", - "raven==6.9.0", - "django-filter==2.4.0", - "celery==5.2.3", - "six==1.11.0", - "requests==2.32.0", - "demands==3.0.0", - "structlog==18.2.0", - "phonenumberslite==8.9.15", - "django-simple-history==3.3.0", - "openpyxl==2.5.9", - "iso-639==0.4.5", - "django-prometheus==2.2.0", - "rapidpro-python==2.6.1", - "pycountry==19.8.18", - "attrs", - "iso6709==0.1.5", - "redis==4.5.4", - "django-redis==5.2.0", - "celery_batches==0.7", - "python-dateutil==2.8.2", - ], - classifiers=[ - "Development Status :: 4 - Beta", - "Framework :: Django", - "License :: OSI Approved :: BSD License", - "Programming Language :: Python", - "Programming Language :: Python :: 3.9.9", - "Topic :: Software Development :: Libraries :: Python Modules", - ], -) From 5b2d52dd83d25ef5ad2a3f02dcb578ff899b6240 Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Wed, 23 Oct 2024 12:44:17 +0200 Subject: [PATCH 37/41] Removed global S106 ignore, and added inline ignores --- eventstore/tests/test_hcs_tasks.py | 2 +- eventstore/tests/test_tasks.py | 12 ++++++------ pyproject.toml | 3 +-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/eventstore/tests/test_hcs_tasks.py b/eventstore/tests/test_hcs_tasks.py index 6c45c19b..b45b290d 100644 --- a/eventstore/tests/test_hcs_tasks.py +++ b/eventstore/tests/test_hcs_tasks.py @@ -8,7 +8,7 @@ class UpdateTurnContactTaskTest(TestCase): @responses.activate - @override_settings(HC_TURN_URL="https://turn", HC_TURN_TOKEN="token") + @override_settings(HC_TURN_URL="https://turn", HC_TURN_TOKEN="token") # noqa: S106 - Its OK to hardcode passwords in tests def test_update_turn_contact_task(self): responses.add( responses.PATCH, diff --git a/eventstore/tests/test_tasks.py b/eventstore/tests/test_tasks.py index 13ee57a3..13b1e681 100644 --- a/eventstore/tests/test_tasks.py +++ b/eventstore/tests/test_tasks.py @@ -596,13 +596,13 @@ def setUp(self): @responses.activate @override_settings( TURN_URL="https://turn/", - TURN_TOKEN="token", + TURN_TOKEN="token", # noqa: S106 - Its OK to hardcode passwords in tests EXTERNAL_REGISTRATIONS_V2=True, SLACK_CHANNEL="test-slack", SLACK_URL="http://slack.com", RAPIDPRO_URL="rapidpro", - RAPIDPRO_TOKEN="rapidpro-token", - SLACK_TOKEN="slack-token", + RAPIDPRO_TOKEN="rapidpro-token", # noqa: S106 - Its OK to hardcode passwords in tests + SLACK_TOKEN="slack-token", # noqa: S106 - Its OK to hardcode passwords in tests ) def test_post_random_contacts_to_slack_channel(self): responses.add( @@ -678,7 +678,7 @@ def test_post_random_contacts_to_slack_channel(self): ) @responses.activate - @override_settings(TURN_URL="https://turn/", TURN_TOKEN="token") + @override_settings(TURN_URL="https://turn/", TURN_TOKEN="token") # noqa: S106 - Its OK to hardcode passwords in tests def test_get_random_contact(self): responses.add( responses.GET, @@ -711,7 +711,7 @@ def setUp(self): tasks.rapidpro = TembaClient("textit.in", "test-token") @responses.activate - @override_settings(TURN_URL="http://turn/", TURN_TOKEN="token") + @override_settings(TURN_URL="http://turn/", TURN_TOKEN="token") # noqa: S106 - Its OK to hardcode passwords in tests def test_get_turn_profile_link(self): responses.add( responses.GET, @@ -772,7 +772,7 @@ def setUp(self): ] @responses.activate - @override_settings(SLACK_URL="http://slack.com", SLACK_TOKEN="slack_token") + @override_settings(SLACK_URL="http://slack.com", SLACK_TOKEN="slack_token") # noqa: S106 - Its OK to hardcode passwords in tests def test_send_slack_message(self): responses.add( responses.POST, diff --git a/pyproject.toml b/pyproject.toml index c42ad5a7..2c114874 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -95,16 +95,15 @@ ignore = [ ] +# Do not add S106 or S105 global ignores. Rather use inline ignores (noqa) [tool.ruff.lint.per-file-ignores] "**/tests/**" = [ "S101", # It's okay to use 'assert' in tests. - "S106", # TODO: Possible hardcoded password assigned to argument: "TURN_AUTH_TOKEN" ] # TODO: Move this somewhere sensible? "**/tests.py" = [ "S101", # It's okay to use 'assert' in tests. - "S106", # TODO: Possible hardcoded password assigned to argument: "TURN_AUTH_TOKEN" ] "**/config/settings/{test,dev}.py" = [ From 7d8bc1073d33e21a5a96738e5abc2569e8bf5b8d Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Wed, 23 Oct 2024 13:38:29 +0200 Subject: [PATCH 38/41] RUF - enabled ruff-specific rules --- aaq/tests/helpers.py | 2 +- aaq/tests/test_views.py | 2 +- eventstore/models.py | 6 +++--- eventstore/tests/test_views.py | 2 +- eventstore/validators.py | 2 +- ndoh_hub/utils.py | 2 +- pyproject.toml | 3 ++- .../migrate_to_rapidpro/async_archive_chats_step1.py | 5 ++--- scripts/migrate_to_rapidpro/bulk_archive_chats.py | 4 ++-- scripts/migrate_to_rapidpro/fix_contact_urns.py | 10 +++++----- scripts/migrate_to_rapidpro/fix_duplicate_contacts.py | 10 +++++----- .../postbirth_contacts_without_events.py | 6 +++--- .../prebirth_contacts_without_events.py | 6 +++--- scripts/migrate_to_rapidpro/sync_fallback_channel.py | 6 +++--- .../resubmit_recent_jembi_errors.py | 8 ++++---- 15 files changed, 37 insertions(+), 37 deletions(-) diff --git a/aaq/tests/helpers.py b/aaq/tests/helpers.py index fc8aaac3..d5cb34e7 100644 --- a/aaq/tests/helpers.py +++ b/aaq/tests/helpers.py @@ -13,7 +13,7 @@ def post_inbound_check(self, request): [ "26", "Fainting in pregnancy", - "*Fainting could mean anemia – visit the clinic to find out", + "*Fainting could mean anemia - visit the clinic to find out", ], [ "114", diff --git a/aaq/tests/test_views.py b/aaq/tests/test_views.py index 1d9b1999..f6ad0cce 100644 --- a/aaq/tests/test_views.py +++ b/aaq/tests/test_views.py @@ -49,7 +49,7 @@ def test_get_first_page_view(self): "body": { "1": {"text": "*Yes, pregnancy can affect your breathing", "id": "21"}, "2": { - "text": "*Fainting could mean anemia – visit the clinic to " + "text": "*Fainting could mean anemia - visit the clinic to " "find out", "id": "26", }, diff --git a/eventstore/models.py b/eventstore/models.py index dd095117..bcb77814 100644 --- a/eventstore/models.py +++ b/eventstore/models.py @@ -1050,7 +1050,7 @@ def clean(self): if not is_valid_edd_date(edd): raise ValidationError("EDD must be between now and 9 months") except ValueError as e: - raise ValidationError(f"Invalid EDD date, {str(e)}") from e + raise ValidationError(f"Invalid EDD date, {e!s}") from e except TypeError: # Should be handled by the individual field validator pass @@ -1058,7 +1058,7 @@ def clean(self): try: date(self.baby_dob_year, self.baby_dob_month, self.baby_dob_day) except ValueError as e: - raise ValidationError(f"Invalid Baby DOB date, {str(e)}") from e + raise ValidationError(f"Invalid Baby DOB date, {e!s}") from e except TypeError: # Should be handled by the individual field validator pass @@ -1092,7 +1092,7 @@ def clean(self): try: date(self.dob_year, self.dob_month, self.dob_day) except ValueError as e: - raise ValidationError(f"Invalid date of birth date, {str(e)}") from e + raise ValidationError(f"Invalid date of birth date, {e!s}") from e class OpenHIMQueue(models.Model): diff --git a/eventstore/tests/test_views.py b/eventstore/tests/test_views.py index 0fb0251f..58f7c887 100644 --- a/eventstore/tests/test_views.py +++ b/eventstore/tests/test_views.py @@ -1989,7 +1989,7 @@ def test_get_list(self): ) response = self.client.get( f"{self.url}?" - f"{urlencode({'timestamp_gt': triage_old.timestamp.isoformat(), 'msisdn': '+27820001001'})}" # noqa + f"{urlencode({'timestamp_gt': triage_old.timestamp.isoformat(), 'msisdn': '+27820001001'})}" ) self.assertEqual( response.data["results"], diff --git a/eventstore/validators.py b/eventstore/validators.py index 3823bd4a..bcd2ddc1 100644 --- a/eventstore/validators.py +++ b/eventstore/validators.py @@ -41,7 +41,7 @@ def validate_sa_id_number(value): try: date(year, int(match.group("month")), int(match.group("day"))) except ValueError as e: - raise ValidationError(f"Invalid ID number date: {str(e)}") from e + raise ValidationError(f"Invalid ID number date: {e!s}") from e if int(match.group("gender")) >= 5000: raise ValidationError("Invalid ID number: for male") if not luhn_verify(value): diff --git a/ndoh_hub/utils.py b/ndoh_hub/utils.py index 0e2aa1c2..5661b8a4 100644 --- a/ndoh_hub/utils.py +++ b/ndoh_hub/utils.py @@ -18,7 +18,7 @@ from eventstore import models from ndoh_hub.auth import CachedTokenAuthentication -from ndoh_hub.constants import ID_TYPES, LANGUAGES, PASSPORT_ORIGINS # noqa:F401 +from ndoh_hub.constants import ID_TYPES, LANGUAGES, PASSPORT_ORIGINS rapidpro = None if settings.EXTERNAL_REGISTRATIONS_V2: diff --git a/pyproject.toml b/pyproject.toml index 2c114874..e797dc40 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -77,7 +77,7 @@ select = [ # "PT", # flake8-pytest-style "SIM", # flake8-simplify "PTH", # flake8-use-pathlib - # "RUF", # ruff-specific rules + "RUF", # ruff-specific rules ] ignore = [ @@ -92,6 +92,7 @@ ignore = [ "SIM115", # TODO: Use a context manager for opening files - FWB: Tried fixing these, but ran into errors on tests "S101", # TODO: Use of 'assert' detected - FWB: Looks like this is only used in migration files "S608", # TODO: Possible SQL injection vector through string-based query construction + "RUF012", # We usually want immutable instance attributes ] diff --git a/scripts/migrate_to_rapidpro/async_archive_chats_step1.py b/scripts/migrate_to_rapidpro/async_archive_chats_step1.py index bb15fcd4..aae011a9 100644 --- a/scripts/migrate_to_rapidpro/async_archive_chats_step1.py +++ b/scripts/migrate_to_rapidpro/async_archive_chats_step1.py @@ -111,7 +111,7 @@ async def process_conversation(session, row, writer): eligible_update += 1 if time.time() - d_print > 1: - print( # noqa + print( f"\rProcessed {processed} ({eligible_archive} & {eligible_update}" f" contacts at {processed/(time.time() - start):.0f}/s", end="", @@ -132,8 +132,7 @@ async def archive_turn_chats(source): with open(OUTPUT_FILE, "w", newline="") as target: writer = csv.DictWriter( target, - fieldnames=reader.fieldnames - + ["last_message_id", "wait_for_helpdesk", "helpdesk_timeout", "action"], + fieldnames=[*reader.fieldnames, "last_message_id", "wait_for_helpdesk", "helpdesk_timeout", "action"], ) writer.writeheader() diff --git a/scripts/migrate_to_rapidpro/bulk_archive_chats.py b/scripts/migrate_to_rapidpro/bulk_archive_chats.py index ca98c052..e06b07f6 100644 --- a/scripts/migrate_to_rapidpro/bulk_archive_chats.py +++ b/scripts/migrate_to_rapidpro/bulk_archive_chats.py @@ -148,7 +148,7 @@ def can_archive_msg(inbound): ) if time.time() - d_print > 1: - print( # noqa + print( f"\rProcessed {archived}/{total} contacts at " f"{total/(time.time() - start):.0f}/s", end="", @@ -157,7 +157,7 @@ def can_archive_msg(inbound): total += 1 -print( # noqa +print( f"\rProcessed {archived}/{total} contacts at " f"{total/(time.time() - start):.0f}/s" ) diff --git a/scripts/migrate_to_rapidpro/fix_contact_urns.py b/scripts/migrate_to_rapidpro/fix_contact_urns.py index 5b72a4d7..5c5ea3e2 100644 --- a/scripts/migrate_to_rapidpro/fix_contact_urns.py +++ b/scripts/migrate_to_rapidpro/fix_contact_urns.py @@ -14,7 +14,7 @@ cursor = conn.cursor("contact_urns") update_cursor = update_conn.cursor() - print("Processing contact urns...") # noqa + print("Processing contact urns...") cursor.execute( """ SELECT contacts_contacturn.id @@ -39,7 +39,7 @@ update_conn.commit() if time.time() - d_print > 1: - print( # noqa + print( f"\rProcessed {total} identities at " f"{total/(time.time() - start):.0f}/s", end="", @@ -51,10 +51,10 @@ error += 1 update_conn.rollback() - print(f"\nProcessed {total} contacts in {time.time() - start:.0f}s") # noqa + print(f"\nProcessed {total} contacts in {time.time() - start:.0f}s") start = time.time() update_conn.commit() - print(f"Committed changes in {time.time() - start:.0f}s") # noqa - print(f"Failed with IntegrityError: {error}") # noqa + print(f"Committed changes in {time.time() - start:.0f}s") + print(f"Failed with IntegrityError: {error}") diff --git a/scripts/migrate_to_rapidpro/fix_duplicate_contacts.py b/scripts/migrate_to_rapidpro/fix_duplicate_contacts.py index dd0fc49f..af2d53e2 100644 --- a/scripts/migrate_to_rapidpro/fix_duplicate_contacts.py +++ b/scripts/migrate_to_rapidpro/fix_duplicate_contacts.py @@ -47,7 +47,7 @@ def clear_fields_for_optouts(contact_fields): return contact_fields - print("Processing contacts...") # noqa + print("Processing contacts...") cursor.execute( """ SELECT @@ -161,7 +161,7 @@ def clear_fields_for_optouts(contact_fields): update_conn.commit() if time.time() - d_print > 1: - print( # noqa + print( f"\rProcessed {total} ({empty_duplicate}/{no_duplicate_found})" f" contacts at {total/(time.time() - start):.0f}/s", end="", @@ -174,6 +174,6 @@ def clear_fields_for_optouts(contact_fields): # This means correct urn is already linked update_conn.commit() - print("") # noqa - print(f"Processed: {total} ({empty_duplicate}/{no_duplicate_found})") # noqa - print(f"Total records: {total_total}") # noqa + print("") + print(f"Processed: {total} ({empty_duplicate}/{no_duplicate_found})") + print(f"Total records: {total_total}") diff --git a/scripts/migrate_to_rapidpro/postbirth_contacts_without_events.py b/scripts/migrate_to_rapidpro/postbirth_contacts_without_events.py index 4bb4f652..907667fa 100644 --- a/scripts/migrate_to_rapidpro/postbirth_contacts_without_events.py +++ b/scripts/migrate_to_rapidpro/postbirth_contacts_without_events.py @@ -35,7 +35,7 @@ now = datetime.date.today() - print("Processing contacts...") # noqa + print("Processing contacts...") cursor.execute( """ SELECT @@ -86,7 +86,7 @@ rapidpro_client.update_contact(contact_uuid, fields=fields_to_update) if time.time() - d_print > 1: - print( # noqa + print( f"\rProcessed {updated}/{total} contacts at " f"{total/(time.time() - start):.0f}/s - ({contact_id})", end="", @@ -95,7 +95,7 @@ total += 1 - print( # noqa + print( f"\rProcessed {updated}/{total} contacts at " f"{total/(time.time() - start):.0f}/s - ({contact_id})" ) diff --git a/scripts/migrate_to_rapidpro/prebirth_contacts_without_events.py b/scripts/migrate_to_rapidpro/prebirth_contacts_without_events.py index dbda4aa4..48daa5ab 100644 --- a/scripts/migrate_to_rapidpro/prebirth_contacts_without_events.py +++ b/scripts/migrate_to_rapidpro/prebirth_contacts_without_events.py @@ -35,7 +35,7 @@ now = datetime.date.today() - print("Processing contacts...") # noqa + print("Processing contacts...") cursor.execute( """ SELECT @@ -85,7 +85,7 @@ rapidpro_client.update_contact(contact_uuid, fields=fields_to_update) if time.time() - d_print > 1: - print( # noqa + print( f"\rProcessed {updated}/{total} contacts at " f"{total/(time.time() - start):.0f}/s - ({contact_id})", end="", @@ -94,7 +94,7 @@ total += 1 - print( # noqa + print( f"\rProcessed {updated}/{total} contacts at " f"{total/(time.time() - start):.0f}/s - ({contact_id})" ) diff --git a/scripts/migrate_to_rapidpro/sync_fallback_channel.py b/scripts/migrate_to_rapidpro/sync_fallback_channel.py index 32b2d88e..f76f3abc 100644 --- a/scripts/migrate_to_rapidpro/sync_fallback_channel.py +++ b/scripts/migrate_to_rapidpro/sync_fallback_channel.py @@ -53,7 +53,7 @@ def update_turn_contact_details(wa_id, details): ) field_mapping = dict(mapping_cursor) - print("Processing contacts...") # noqa + print("Processing contacts...") cursor.execute( """ SELECT @@ -103,7 +103,7 @@ def update_turn_contact_details(wa_id, details): updated += 1 if time.time() - d_print > 1: - print( # noqa + print( f"\rProcessed {total}/{updated} contacts at " f"{total/(time.time() - start):.0f}/s - ({contact_id})", end="", @@ -112,7 +112,7 @@ def update_turn_contact_details(wa_id, details): total += 1 - print( # noqa + print( f"\rProcessed {total}/{updated} contacts at " f"{total/(time.time() - start):.0f}/s - ({contact_id})" ) diff --git a/scripts/resubmit_jembi_requests/resubmit_recent_jembi_errors.py b/scripts/resubmit_jembi_requests/resubmit_recent_jembi_errors.py index 57ff88c5..feb1b491 100644 --- a/scripts/resubmit_jembi_requests/resubmit_recent_jembi_errors.py +++ b/scripts/resubmit_jembi_requests/resubmit_recent_jembi_errors.py @@ -66,7 +66,7 @@ failed_again.append(request_id) if time.time() - d_print > 1: - print( # noqa + print( f"\rProcessed {total}" f" webhooks at {total/(time.time() - start):.0f}/s", end="", @@ -75,6 +75,6 @@ total += 1 - print("") # noqa - print(f"Processed: {total}") # noqa - print(f"Failed again: {failed_again}") # noqa + print("") + print(f"Processed: {total}") + print(f"Failed again: {failed_again}") From e54ac24598e6ba7483329f546e429588dadb20ec Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Wed, 23 Oct 2024 13:40:59 +0200 Subject: [PATCH 39/41] Formatting --- scripts/migrate_to_rapidpro/async_archive_chats_step1.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/migrate_to_rapidpro/async_archive_chats_step1.py b/scripts/migrate_to_rapidpro/async_archive_chats_step1.py index aae011a9..8ec6dda3 100644 --- a/scripts/migrate_to_rapidpro/async_archive_chats_step1.py +++ b/scripts/migrate_to_rapidpro/async_archive_chats_step1.py @@ -132,7 +132,13 @@ async def archive_turn_chats(source): with open(OUTPUT_FILE, "w", newline="") as target: writer = csv.DictWriter( target, - fieldnames=[*reader.fieldnames, "last_message_id", "wait_for_helpdesk", "helpdesk_timeout", "action"], + fieldnames=[ + *reader.fieldnames, + "last_message_id", + "wait_for_helpdesk", + "helpdesk_timeout", + "action", + ], ) writer.writeheader() From 165fac8e107c7208644accd98205d58151fcb51b Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Wed, 23 Oct 2024 14:25:33 +0200 Subject: [PATCH 40/41] Updated wording for S106 inlines --- eventstore/tests/test_hcs_tasks.py | 2 +- eventstore/tests/test_tasks.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/eventstore/tests/test_hcs_tasks.py b/eventstore/tests/test_hcs_tasks.py index b45b290d..47f523b7 100644 --- a/eventstore/tests/test_hcs_tasks.py +++ b/eventstore/tests/test_hcs_tasks.py @@ -8,7 +8,7 @@ class UpdateTurnContactTaskTest(TestCase): @responses.activate - @override_settings(HC_TURN_URL="https://turn", HC_TURN_TOKEN="token") # noqa: S106 - Its OK to hardcode passwords in tests + @override_settings(HC_TURN_URL="https://turn", HC_TURN_TOKEN="token") # noqa: S106 - Fake password/token for test purposes def test_update_turn_contact_task(self): responses.add( responses.PATCH, diff --git a/eventstore/tests/test_tasks.py b/eventstore/tests/test_tasks.py index 13b1e681..567bb3af 100644 --- a/eventstore/tests/test_tasks.py +++ b/eventstore/tests/test_tasks.py @@ -596,13 +596,13 @@ def setUp(self): @responses.activate @override_settings( TURN_URL="https://turn/", - TURN_TOKEN="token", # noqa: S106 - Its OK to hardcode passwords in tests + TURN_TOKEN="token", # noqa: S106 - Fake password/token for test purposes EXTERNAL_REGISTRATIONS_V2=True, SLACK_CHANNEL="test-slack", SLACK_URL="http://slack.com", RAPIDPRO_URL="rapidpro", - RAPIDPRO_TOKEN="rapidpro-token", # noqa: S106 - Its OK to hardcode passwords in tests - SLACK_TOKEN="slack-token", # noqa: S106 - Its OK to hardcode passwords in tests + RAPIDPRO_TOKEN="rapidpro-token", # noqa: S106 - Fake password/token for test purposes + SLACK_TOKEN="slack-token", # noqa: S106 - Fake password/token for test purposes ) def test_post_random_contacts_to_slack_channel(self): responses.add( @@ -678,7 +678,7 @@ def test_post_random_contacts_to_slack_channel(self): ) @responses.activate - @override_settings(TURN_URL="https://turn/", TURN_TOKEN="token") # noqa: S106 - Its OK to hardcode passwords in tests + @override_settings(TURN_URL="https://turn/", TURN_TOKEN="token") # noqa: S106 - Fake password/token for test purposes def test_get_random_contact(self): responses.add( responses.GET, @@ -711,7 +711,7 @@ def setUp(self): tasks.rapidpro = TembaClient("textit.in", "test-token") @responses.activate - @override_settings(TURN_URL="http://turn/", TURN_TOKEN="token") # noqa: S106 - Its OK to hardcode passwords in tests + @override_settings(TURN_URL="http://turn/", TURN_TOKEN="token") # noqa: S106 - Fake password/token for test purposes def test_get_turn_profile_link(self): responses.add( responses.GET, @@ -772,7 +772,7 @@ def setUp(self): ] @responses.activate - @override_settings(SLACK_URL="http://slack.com", SLACK_TOKEN="slack_token") # noqa: S106 - Its OK to hardcode passwords in tests + @override_settings(SLACK_URL="http://slack.com", SLACK_TOKEN="slack_token") # noqa: S106 - Fake password/token for test purposes def test_send_slack_message(self): responses.add( responses.POST, From f54b07e21ed5c85e4c15c5c57be4c03b4b5c1e2a Mon Sep 17 00:00:00 2001 From: Fritz Brand Date: Thu, 24 Oct 2024 08:59:02 +0200 Subject: [PATCH 41/41] Updates after feedback --- Dockerfile | 3 ++- eventstore/tests/test_views.py | 12 ++++++------ eventstore/tests/test_whatsapp_actions.py | 2 +- scripts/growgreat_extract/msisdn_from_details.py | 2 +- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index e8717e15..34d55e67 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,10 @@ FROM ghcr.io/praekeltfoundation/docker-django-bootstrap-nw:py3.9-bullseye -RUN pip install poetry==1.8.3 ENV DJANGO_SETTINGS_MODULE "ndoh_hub.settings" COPY . /app + +RUN pip install poetry RUN poetry config virtualenvs.create false \ && poetry install --no-dev --no-interaction --no-ansi --no-cache diff --git a/eventstore/tests/test_views.py b/eventstore/tests/test_views.py index 58f7c887..b1e46ec4 100644 --- a/eventstore/tests/test_views.py +++ b/eventstore/tests/test_views.py @@ -1289,9 +1289,9 @@ def test_successful_inbound_messages_request(self, mock_handle_inbound): datetime.datetime(2018, 2, 15, 11, 38, 20, tzinfo=UTC), ), ) - (self.assertEqual(messages.id, "9e12d04c-af25-40b6-aa4f-57c72e8e3f91"),) - (self.assertEqual(messages.type, "image"),) - (self.assertEqual(messages.message_direction, Message.INBOUND),) + self.assertEqual(messages.id, "9e12d04c-af25-40b6-aa4f-57c72e8e3f91") + self.assertEqual(messages.type, "image") + self.assertEqual(messages.message_direction, Message.INBOUND) ( self.assertEqual( messages.data, @@ -1395,9 +1395,9 @@ def test_successful_outbound_messages_request(self, mock_handle_outbound): self.assertEqual(response.status_code, status.HTTP_201_CREATED) [messages] = Message.objects.all() self.assertEqual(str(messages.contact_id), "whatsapp-id") - (self.assertEqual(messages.id, "message-id"),) - (self.assertEqual(messages.type, "text"),) - (self.assertEqual(messages.message_direction, Message.OUTBOUND),) + self.assertEqual(messages.id, "message-id") + self.assertEqual(messages.type, "text") + self.assertEqual(messages.message_direction, Message.OUTBOUND) ( self.assertEqual( messages.data, diff --git a/eventstore/tests/test_whatsapp_actions.py b/eventstore/tests/test_whatsapp_actions.py index ca6eb3a9..8de4f78f 100644 --- a/eventstore/tests/test_whatsapp_actions.py +++ b/eventstore/tests/test_whatsapp_actions.py @@ -201,7 +201,7 @@ def test_handle_edd_label_disabled(self): with patch("eventstore.whatsapp_actions.handle_edd_message") as handle: handle_inbound(message) - _var = handle.assert_not_called + handle.assert_not_called() class UpdateRapidproAlertOptoutTests(DjangoTestCase): diff --git a/scripts/growgreat_extract/msisdn_from_details.py b/scripts/growgreat_extract/msisdn_from_details.py index afd9c038..ab80f934 100644 --- a/scripts/growgreat_extract/msisdn_from_details.py +++ b/scripts/growgreat_extract/msisdn_from_details.py @@ -4,7 +4,7 @@ def get_msisdn(details): last = None - for addr, _addr_dets in details.get("addresses", {}).get("msisdn", {}).items(): + for addr in details.get("addresses", {}).get("msisdn", {}): if details.get("default") is True: return addr if details.get("optedout") is not True: