From 47a84236a3bdf240c857f33b482f6b44e5029e47 Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Sun, 24 May 2026 13:28:05 +0200 Subject: [PATCH 01/27] update python, django and minor packages --- .gitignore | 153 +--- AHC_app/.python-version | 1 + AHC_app/AHC_app/settings.py | 4 - AHC_app/Pipfile | 3 - AHC_app/__init__.py | 0 AHC_app/pyproject.toml | 50 ++ AHC_app/uv.lock | 1470 +++++++++++++++++++++++++++++++++++ 7 files changed, 1546 insertions(+), 135 deletions(-) create mode 100644 AHC_app/.python-version delete mode 100644 AHC_app/__init__.py create mode 100644 AHC_app/pyproject.toml create mode 100644 AHC_app/uv.lock diff --git a/.gitignore b/.gitignore index f3464e5..e6dfafc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,165 +1,62 @@ -# Byte-compiled / optimized / DLL files +# Python __pycache__/ *.py[cod] -*$py.class - -# C extensions *.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg *.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt +*.egg-info/ +.Python -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ +# Testing .coverage .coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ +htmlcov/ .pytest_cache/ -cover/ - -# Translations -*.mo -*.pot +.hypothesis/ -# Django stuff: +# Django *.log local_settings.py db.sqlite3 db.sqlite3-journal -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - # Environments .env -.venv +.venv/ env/ venv/ -ENV/ -env.bak/ -venv.bak/ -# Spyder project settings -.spyderproject -.spyproject +# uv — commit uv.lock, do NOT add it here +# .python-version is intentionally tracked -# Rope project settings -.ropeproject +# Build / packaging +build/ +dist/ +wheels/ -# mkdocs documentation -/site +# Celery +celerybeat-schedule +celerybeat.pid -# mypy +# Type checkers .mypy_cache/ .dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ +.ty_cache/ -# Cython debug symbols -cython_debug/ +# Claude Code — local settings are machine-specific +.claude/settings.local.json -# PyCharm -# JetBrains specific template is maintainted in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. +# IDE .idea/ -# Collected static files - temporary +# Project-specific /AHC_app/static_collected/ /AHC_app/static/media/profile_pics/animals/ /AHC_app/static/media/attachments/ -# Kubernetes configuration +# Kubernetes /AHC_app/tars/ /kubernetes/**/*.tar secret.yaml -# volumens +# Volumes /db/ diff --git a/AHC_app/.python-version b/AHC_app/.python-version new file mode 100644 index 0000000..6324d40 --- /dev/null +++ b/AHC_app/.python-version @@ -0,0 +1 @@ +3.14 diff --git a/AHC_app/AHC_app/settings.py b/AHC_app/AHC_app/settings.py index f933f48..c1e968c 100644 --- a/AHC_app/AHC_app/settings.py +++ b/AHC_app/AHC_app/settings.py @@ -49,7 +49,6 @@ "compressor", "taggit", "django_crontab", - "django_cron", "homepage.apps.HomepageConfig", "users.apps.UsersConfig", "animals.apps.AnimalsConfig", @@ -210,9 +209,6 @@ ("6 * * * *", "AHC_app.celery_notifications.cron.send_discord_notes"), ] -CRON_CLASSES = [ - # 'AHC_app.celery_notifications.cron.SynchNotificationsCron', -] CELERY_BROKER_URL = config("CELERY_BROKER_URL") CELERY_BACKEND = config("CELERY_BACKEND") diff --git a/AHC_app/Pipfile b/AHC_app/Pipfile index 8fa3083..e76d50b 100644 --- a/AHC_app/Pipfile +++ b/AHC_app/Pipfile @@ -16,7 +16,6 @@ click-plugins = "==1.1.1" click-repl = "==0.3.0" colorama = "==0.4.6" contourpy = "==1.0.7" -couchdb = "==1.2" crispy-bootstrap4 = "==2022.1" cryptography = "==41.0.5" cycler = "==0.11.0" @@ -40,7 +39,6 @@ oauthlib = "==3.2.2" packaging = "==23.1" pillow = "==9.5.0" prompt-toolkit = "==3.0.39" -psycopg2 = "==2.9.6" pyasn1 = "==0.5.0" pyasn1-modules = "==0.3.0" pycparser = "==2.21" @@ -67,7 +65,6 @@ django-cron = "*" python-decouple = "*" pycouchdb = "*" discord = "*" -django-ajax = "*" psycopg2-binary = "*" django = "==4.2.11" celery = "5.3.4" diff --git a/AHC_app/__init__.py b/AHC_app/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/AHC_app/pyproject.toml b/AHC_app/pyproject.toml new file mode 100644 index 0000000..cb462e0 --- /dev/null +++ b/AHC_app/pyproject.toml @@ -0,0 +1,50 @@ +[project] +name = "animals-healthcare-application" +version = "0.1.0" +description = "Animals Healthcare Application — pet health data management" +requires-python = ">=3.14" + +dependencies = [ + "django>=5.2,<5.3", + "djangorestframework>=3.14", + "psycopg[binary]>=3.2", + "celery>=5.4", + "redis>=5.0", + "flower", + "pycouchdb", + "discord", + "python-decouple", + "pillow>=11.0", + "cryptography>=43", + "cffi>=1.17", + "django-crispy-forms", + "crispy-bootstrap4", + "django-bootstrap-modal-forms", + "django-compressor", + "django-libsass", + "libsass", + "django-appconf", + "django-taggit", + "django-timezone-field>=6.1", + "django-crontab", + "pytz", + "tzdata", + "python3-openid", + "requests", + "requests-oauthlib", + "httplib2", + "python-dateutil", + "pyjwt", + "defusedxml", + "icecream", +] + +[dependency-groups] +dev = [ + "pre-commit", + "black", + "isort", +] + +[tool.uv] +package = false diff --git a/AHC_app/uv.lock b/AHC_app/uv.lock new file mode 100644 index 0000000..390af96 --- /dev/null +++ b/AHC_app/uv.lock @@ -0,0 +1,1470 @@ +version = 1 +revision = 3 +requires-python = ">=3.14" + +[[package]] +name = "aiohappyeyeballs" +version = "2.6.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/33/c6/61a2d7b7572279226bb2e7f61d7a19ca7c90da0329c93fa0d560cbf288d8/aiohappyeyeballs-2.6.2.tar.gz", hash = "sha256:e202810ee718bd01fc6ef49e8ea53d023d5cb6b581076d7925aa499fa55dbe64", size = 22591, upload-time = "2026-05-20T15:12:24.631Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/fc/a7bf5b6e4e617b45f90f2d9d2a68519c249c81dd4fc2658c7a2a61c4f4b7/aiohappyeyeballs-2.6.2-py3-none-any.whl", hash = "sha256:4708045e2d7a6c6bdf8aafa8ed39649eaf926a4543b54560659129e3365953c4", size = 15062, upload-time = "2026-05-20T15:12:23.328Z" }, +] + +[[package]] +name = "aiohttp" +version = "3.13.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohappyeyeballs" }, + { name = "aiosignal" }, + { name = "attrs" }, + { name = "frozenlist" }, + { name = "multidict" }, + { name = "propcache" }, + { name = "yarl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/77/9a/152096d4808df8e4268befa55fba462f440f14beab85e8ad9bf990516918/aiohttp-3.13.5.tar.gz", hash = "sha256:9d98cc980ecc96be6eb4c1994ce35d28d8b1f5e5208a23b421187d1209dbb7d1", size = 7858271, upload-time = "2026-03-31T22:01:03.343Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/ce/46572759afc859e867a5bc8ec3487315869013f59281ce61764f76d879de/aiohttp-3.13.5-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:eb4639f32fd4a9904ab8fb45bf3383ba71137f3d9d4ba25b3b3f3109977c5b8c", size = 745721, upload-time = "2026-03-31T21:58:50.229Z" }, + { url = "https://files.pythonhosted.org/packages/13/fe/8a2efd7626dbe6049b2ef8ace18ffda8a4dfcbe1bcff3ac30c0c7575c20b/aiohttp-3.13.5-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:7e5dc4311bd5ac493886c63cbf76ab579dbe4641268e7c74e48e774c74b6f2be", size = 497663, upload-time = "2026-03-31T21:58:52.232Z" }, + { url = "https://files.pythonhosted.org/packages/9b/91/cc8cc78a111826c54743d88651e1687008133c37e5ee615fee9b57990fac/aiohttp-3.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:756c3c304d394977519824449600adaf2be0ccee76d206ee339c5e76b70ded25", size = 499094, upload-time = "2026-03-31T21:58:54.566Z" }, + { url = "https://files.pythonhosted.org/packages/0a/33/a8362cb15cf16a3af7e86ed11962d5cd7d59b449202dc576cdc731310bde/aiohttp-3.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecc26751323224cf8186efcf7fbcbc30f4e1d8c7970659daf25ad995e4032a56", size = 1726701, upload-time = "2026-03-31T21:58:56.864Z" }, + { url = "https://files.pythonhosted.org/packages/45/0c/c091ac5c3a17114bd76cbf85d674650969ddf93387876cf67f754204bd77/aiohttp-3.13.5-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10a75acfcf794edf9d8db50e5a7ec5fc818b2a8d3f591ce93bc7b1210df016d2", size = 1683360, upload-time = "2026-03-31T21:58:59.072Z" }, + { url = "https://files.pythonhosted.org/packages/23/73/bcee1c2b79bc275e964d1446c55c54441a461938e70267c86afaae6fba27/aiohttp-3.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0f7a18f258d124cd678c5fe072fe4432a4d5232b0657fca7c1847f599233c83a", size = 1773023, upload-time = "2026-03-31T21:59:01.776Z" }, + { url = "https://files.pythonhosted.org/packages/c7/ef/720e639df03004fee2d869f771799d8c23046dec47d5b81e396c7cda583a/aiohttp-3.13.5-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:df6104c009713d3a89621096f3e3e88cc323fd269dbd7c20afe18535094320be", size = 1853795, upload-time = "2026-03-31T21:59:04.568Z" }, + { url = "https://files.pythonhosted.org/packages/bd/c9/989f4034fb46841208de7aeeac2c6d8300745ab4f28c42f629ba77c2d916/aiohttp-3.13.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:241a94f7de7c0c3b616627aaad530fe2cb620084a8b144d3be7b6ecfe95bae3b", size = 1730405, upload-time = "2026-03-31T21:59:07.221Z" }, + { url = "https://files.pythonhosted.org/packages/ce/75/ee1fd286ca7dc599d824b5651dad7b3be7ff8d9a7e7b3fe9820d9180f7db/aiohttp-3.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c974fb66180e58709b6fc402846f13791240d180b74de81d23913abe48e96d94", size = 1558082, upload-time = "2026-03-31T21:59:09.484Z" }, + { url = "https://files.pythonhosted.org/packages/c3/20/1e9e6650dfc436340116b7aa89ff8cb2bbdf0abc11dfaceaad8f74273a10/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:6e27ea05d184afac78aabbac667450c75e54e35f62238d44463131bd3f96753d", size = 1692346, upload-time = "2026-03-31T21:59:12.068Z" }, + { url = "https://files.pythonhosted.org/packages/d8/40/8ebc6658d48ea630ac7903912fe0dd4e262f0e16825aa4c833c56c9f1f56/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a79a6d399cef33a11b6f004c67bb07741d91f2be01b8d712d52c75711b1e07c7", size = 1698891, upload-time = "2026-03-31T21:59:14.552Z" }, + { url = "https://files.pythonhosted.org/packages/d8/78/ea0ae5ec8ba7a5c10bdd6e318f1ba5e76fcde17db8275188772afc7917a4/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c632ce9c0b534fbe25b52c974515ed674937c5b99f549a92127c85f771a78772", size = 1742113, upload-time = "2026-03-31T21:59:17.068Z" }, + { url = "https://files.pythonhosted.org/packages/8a/66/9d308ed71e3f2491be1acb8769d96c6f0c47d92099f3bc9119cada27b357/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:fceedde51fbd67ee2bcc8c0b33d0126cc8b51ef3bbde2f86662bd6d5a6f10ec5", size = 1553088, upload-time = "2026-03-31T21:59:19.541Z" }, + { url = "https://files.pythonhosted.org/packages/da/a6/6cc25ed8dfc6e00c90f5c6d126a98e2cf28957ad06fa1036bd34b6f24a2c/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f92995dfec9420bb69ae629abf422e516923ba79ba4403bc750d94fb4a6c68c1", size = 1757976, upload-time = "2026-03-31T21:59:22.311Z" }, + { url = "https://files.pythonhosted.org/packages/c1/2b/cce5b0ffe0de99c83e5e36d8f828e4161e415660a9f3e58339d07cce3006/aiohttp-3.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20ae0ff08b1f2c8788d6fb85afcb798654ae6ba0b747575f8562de738078457b", size = 1712444, upload-time = "2026-03-31T21:59:24.635Z" }, + { url = "https://files.pythonhosted.org/packages/6c/cf/9e1795b4160c58d29421eafd1a69c6ce351e2f7c8d3c6b7e4ca44aea1a5b/aiohttp-3.13.5-cp314-cp314-win32.whl", hash = "sha256:b20df693de16f42b2472a9c485e1c948ee55524786a0a34345511afdd22246f3", size = 438128, upload-time = "2026-03-31T21:59:27.291Z" }, + { url = "https://files.pythonhosted.org/packages/22/4d/eaedff67fc805aeba4ba746aec891b4b24cebb1a7d078084b6300f79d063/aiohttp-3.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:f85c6f327bf0b8c29da7d93b1cabb6363fb5e4e160a32fa241ed2dce21b73162", size = 464029, upload-time = "2026-03-31T21:59:29.429Z" }, + { url = "https://files.pythonhosted.org/packages/79/11/c27d9332ee20d68dd164dc12a6ecdef2e2e35ecc97ed6cf0d2442844624b/aiohttp-3.13.5-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:1efb06900858bb618ff5cee184ae2de5828896c448403d51fb633f09e109be0a", size = 778758, upload-time = "2026-03-31T21:59:31.547Z" }, + { url = "https://files.pythonhosted.org/packages/04/fb/377aead2e0a3ba5f09b7624f702a964bdf4f08b5b6728a9799830c80041e/aiohttp-3.13.5-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:fee86b7c4bd29bdaf0d53d14739b08a106fdda809ca5fe032a15f52fae5fe254", size = 512883, upload-time = "2026-03-31T21:59:34.098Z" }, + { url = "https://files.pythonhosted.org/packages/bb/a6/aa109a33671f7a5d3bd78b46da9d852797c5e665bfda7d6b373f56bff2ec/aiohttp-3.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:20058e23909b9e65f9da62b396b77dfa95965cbe840f8def6e572538b1d32e36", size = 516668, upload-time = "2026-03-31T21:59:36.497Z" }, + { url = "https://files.pythonhosted.org/packages/79/b3/ca078f9f2fa9563c36fb8ef89053ea2bb146d6f792c5104574d49d8acb63/aiohttp-3.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cf20a8d6868cb15a73cab329ffc07291ba8c22b1b88176026106ae39aa6df0f", size = 1883461, upload-time = "2026-03-31T21:59:38.723Z" }, + { url = "https://files.pythonhosted.org/packages/b7/e3/a7ad633ca1ca497b852233a3cce6906a56c3225fb6d9217b5e5e60b7419d/aiohttp-3.13.5-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:330f5da04c987f1d5bdb8ae189137c77139f36bd1cb23779ca1a354a4b027800", size = 1747661, upload-time = "2026-03-31T21:59:41.187Z" }, + { url = "https://files.pythonhosted.org/packages/33/b9/cd6fe579bed34a906d3d783fe60f2fa297ef55b27bb4538438ee49d4dc41/aiohttp-3.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f1cbf0c7926d315c3c26c2da41fd2b5d2fe01ac0e157b78caefc51a782196cf", size = 1863800, upload-time = "2026-03-31T21:59:43.84Z" }, + { url = "https://files.pythonhosted.org/packages/c0/3f/2c1e2f5144cefa889c8afd5cf431994c32f3b29da9961698ff4e3811b79a/aiohttp-3.13.5-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:53fc049ed6390d05423ba33103ded7281fe897cf97878f369a527070bd95795b", size = 1958382, upload-time = "2026-03-31T21:59:46.187Z" }, + { url = "https://files.pythonhosted.org/packages/66/1d/f31ec3f1013723b3babe3609e7f119c2c2fb6ef33da90061a705ef3e1bc8/aiohttp-3.13.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:898703aa2667e3c5ca4c54ca36cd73f58b7a38ef87a5606414799ebce4d3fd3a", size = 1803724, upload-time = "2026-03-31T21:59:48.656Z" }, + { url = "https://files.pythonhosted.org/packages/0e/b4/57712dfc6f1542f067daa81eb61da282fab3e6f1966fca25db06c4fc62d5/aiohttp-3.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0494a01ca9584eea1e5fbd6d748e61ecff218c51b576ee1999c23db7066417d8", size = 1640027, upload-time = "2026-03-31T21:59:51.284Z" }, + { url = "https://files.pythonhosted.org/packages/25/3c/734c878fb43ec083d8e31bf029daae1beafeae582d1b35da234739e82ee7/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6cf81fe010b8c17b09495cbd15c1d35afbc8fb405c0c9cf4738e5ae3af1d65be", size = 1806644, upload-time = "2026-03-31T21:59:53.753Z" }, + { url = "https://files.pythonhosted.org/packages/20/a5/f671e5cbec1c21d044ff3078223f949748f3a7f86b14e34a365d74a5d21f/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:c564dd5f09ddc9d8f2c2d0a301cd30a79a2cc1b46dd1a73bef8f0038863d016b", size = 1791630, upload-time = "2026-03-31T21:59:56.239Z" }, + { url = "https://files.pythonhosted.org/packages/0b/63/fb8d0ad63a0b8a99be97deac8c04dacf0785721c158bdf23d679a87aa99e/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:2994be9f6e51046c4f864598fd9abeb4fba6e88f0b2152422c9666dcd4aea9c6", size = 1809403, upload-time = "2026-03-31T21:59:59.103Z" }, + { url = "https://files.pythonhosted.org/packages/59/0c/bfed7f30662fcf12206481c2aac57dedee43fe1c49275e85b3a1e1742294/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:157826e2fa245d2ef46c83ea8a5faf77ca19355d278d425c29fda0beb3318037", size = 1634924, upload-time = "2026-03-31T22:00:02.116Z" }, + { url = "https://files.pythonhosted.org/packages/17/d6/fd518d668a09fd5a3319ae5e984d4d80b9a4b3df4e21c52f02251ef5a32e/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:a8aca50daa9493e9e13c0f566201a9006f080e7c50e5e90d0b06f53146a54500", size = 1836119, upload-time = "2026-03-31T22:00:04.756Z" }, + { url = "https://files.pythonhosted.org/packages/78/b7/15fb7a9d52e112a25b621c67b69c167805cb1f2ab8f1708a5c490d1b52fe/aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3b13560160d07e047a93f23aaa30718606493036253d5430887514715b67c9d9", size = 1772072, upload-time = "2026-03-31T22:00:07.494Z" }, + { url = "https://files.pythonhosted.org/packages/7e/df/57ba7f0c4a553fc2bd8b6321df236870ec6fd64a2a473a8a13d4f733214e/aiohttp-3.13.5-cp314-cp314t-win32.whl", hash = "sha256:9a0f4474b6ea6818b41f82172d799e4b3d29e22c2c520ce4357856fced9af2f8", size = 471819, upload-time = "2026-03-31T22:00:10.277Z" }, + { url = "https://files.pythonhosted.org/packages/62/29/2f8418269e46454a26171bfdd6a055d74febf32234e474930f2f60a17145/aiohttp-3.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:18a2f6c1182c51baa1d28d68fea51513cb2a76612f038853c0ad3c145423d3d9", size = 505441, upload-time = "2026-03-31T22:00:12.791Z" }, +] + +[[package]] +name = "aiosignal" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "frozenlist" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, +] + +[[package]] +name = "amqp" +version = "5.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "vine" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/79/fc/ec94a357dfc6683d8c86f8b4cfa5416a4c36b28052ec8260c77aca96a443/amqp-5.3.1.tar.gz", hash = "sha256:cddc00c725449522023bad949f70fff7b48f0b1ade74d170a6f10ab044739432", size = 129013, upload-time = "2024-11-12T19:55:44.051Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/99/fc813cd978842c26c82534010ea849eee9ab3a13ea2b74e95cb9c99e747b/amqp-5.3.1-py3-none-any.whl", hash = "sha256:43b3319e1b4e7d1251833a93d672b4af1e40f3d632d479b98661a95f117880a2", size = 50944, upload-time = "2024-11-12T19:55:41.782Z" }, +] + +[[package]] +name = "animals-healthcare-application" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "celery" }, + { name = "cffi" }, + { name = "crispy-bootstrap4" }, + { name = "cryptography" }, + { name = "defusedxml" }, + { name = "discord" }, + { name = "django" }, + { name = "django-appconf" }, + { name = "django-bootstrap-modal-forms" }, + { name = "django-compressor" }, + { name = "django-crispy-forms" }, + { name = "django-crontab" }, + { name = "django-libsass" }, + { name = "django-taggit" }, + { name = "django-timezone-field" }, + { name = "djangorestframework" }, + { name = "flower" }, + { name = "httplib2" }, + { name = "icecream" }, + { name = "libsass" }, + { name = "pillow" }, + { name = "psycopg", extra = ["binary"] }, + { name = "pycouchdb" }, + { name = "pyjwt" }, + { name = "python-dateutil" }, + { name = "python-decouple" }, + { name = "python3-openid" }, + { name = "pytz" }, + { name = "redis" }, + { name = "requests" }, + { name = "requests-oauthlib" }, + { name = "tzdata" }, +] + +[package.dev-dependencies] +dev = [ + { name = "black" }, + { name = "isort" }, + { name = "pre-commit" }, +] + +[package.metadata] +requires-dist = [ + { name = "celery", specifier = ">=5.4" }, + { name = "cffi", specifier = ">=1.17" }, + { name = "crispy-bootstrap4" }, + { name = "cryptography", specifier = ">=43" }, + { name = "defusedxml" }, + { name = "discord" }, + { name = "django", specifier = ">=5.2,<5.3" }, + { name = "django-appconf" }, + { name = "django-bootstrap-modal-forms" }, + { name = "django-compressor" }, + { name = "django-crispy-forms" }, + { name = "django-crontab" }, + { name = "django-libsass" }, + { name = "django-taggit" }, + { name = "django-timezone-field", specifier = ">=6.1" }, + { name = "djangorestframework", specifier = ">=3.14" }, + { name = "flower" }, + { name = "httplib2" }, + { name = "icecream" }, + { name = "libsass" }, + { name = "pillow", specifier = ">=11.0" }, + { name = "psycopg", extras = ["binary"], specifier = ">=3.2" }, + { name = "pycouchdb" }, + { name = "pyjwt" }, + { name = "python-dateutil" }, + { name = "python-decouple" }, + { name = "python3-openid" }, + { name = "pytz" }, + { name = "redis", specifier = ">=5.0" }, + { name = "requests" }, + { name = "requests-oauthlib" }, + { name = "tzdata" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "black" }, + { name = "isort" }, + { name = "pre-commit" }, +] + +[[package]] +name = "asgiref" +version = "3.11.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/63/40/f03da1264ae8f7cfdbf9146542e5e7e8100a4c66ab48e791df9a03d3f6c0/asgiref-3.11.1.tar.gz", hash = "sha256:5f184dc43b7e763efe848065441eac62229c9f7b0475f41f80e207a114eda4ce", size = 38550, upload-time = "2026-02-03T13:30:14.33Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/0a/a72d10ed65068e115044937873362e6e32fab1b7dce0046aeb224682c989/asgiref-3.11.1-py3-none-any.whl", hash = "sha256:e8667a091e69529631969fd45dc268fa79b99c92c5fcdda727757e52146ec133", size = 24345, upload-time = "2026-02-03T13:30:13.039Z" }, +] + +[[package]] +name = "asttokens" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308, upload-time = "2025-11-15T16:43:48.578Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047, upload-time = "2025-11-15T16:43:16.109Z" }, +] + +[[package]] +name = "attrs" +version = "26.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", size = 952055, upload-time = "2026-03-19T14:22:25.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" }, +] + +[[package]] +name = "audioop-lts" +version = "0.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/38/53/946db57842a50b2da2e0c1e34bd37f36f5aadba1a929a3971c5d7841dbca/audioop_lts-0.2.2.tar.gz", hash = "sha256:64d0c62d88e67b98a1a5e71987b7aa7b5bcffc7dcee65b635823dbdd0a8dbbd0", size = 30686, upload-time = "2025-08-05T16:43:17.409Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/d4/94d277ca941de5a507b07f0b592f199c22454eeaec8f008a286b3fbbacd6/audioop_lts-0.2.2-cp313-abi3-macosx_10_13_universal2.whl", hash = "sha256:fd3d4602dc64914d462924a08c1a9816435a2155d74f325853c1f1ac3b2d9800", size = 46523, upload-time = "2025-08-05T16:42:20.836Z" }, + { url = "https://files.pythonhosted.org/packages/f8/5a/656d1c2da4b555920ce4177167bfeb8623d98765594af59702c8873f60ec/audioop_lts-0.2.2-cp313-abi3-macosx_10_13_x86_64.whl", hash = "sha256:550c114a8df0aafe9a05442a1162dfc8fec37e9af1d625ae6060fed6e756f303", size = 27455, upload-time = "2025-08-05T16:42:22.283Z" }, + { url = "https://files.pythonhosted.org/packages/1b/83/ea581e364ce7b0d41456fb79d6ee0ad482beda61faf0cab20cbd4c63a541/audioop_lts-0.2.2-cp313-abi3-macosx_11_0_arm64.whl", hash = "sha256:9a13dc409f2564de15dd68be65b462ba0dde01b19663720c68c1140c782d1d75", size = 26997, upload-time = "2025-08-05T16:42:23.849Z" }, + { url = "https://files.pythonhosted.org/packages/b8/3b/e8964210b5e216e5041593b7d33e97ee65967f17c282e8510d19c666dab4/audioop_lts-0.2.2-cp313-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:51c916108c56aa6e426ce611946f901badac950ee2ddaf302b7ed35d9958970d", size = 85844, upload-time = "2025-08-05T16:42:25.208Z" }, + { url = "https://files.pythonhosted.org/packages/c7/2e/0a1c52faf10d51def20531a59ce4c706cb7952323b11709e10de324d6493/audioop_lts-0.2.2-cp313-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:47eba38322370347b1c47024defbd36374a211e8dd5b0dcbce7b34fdb6f8847b", size = 85056, upload-time = "2025-08-05T16:42:26.559Z" }, + { url = "https://files.pythonhosted.org/packages/75/e8/cd95eef479656cb75ab05dfece8c1f8c395d17a7c651d88f8e6e291a63ab/audioop_lts-0.2.2-cp313-abi3-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba7c3a7e5f23e215cb271516197030c32aef2e754252c4c70a50aaff7031a2c8", size = 93892, upload-time = "2025-08-05T16:42:27.902Z" }, + { url = "https://files.pythonhosted.org/packages/5c/1e/a0c42570b74f83efa5cca34905b3eef03f7ab09fe5637015df538a7f3345/audioop_lts-0.2.2-cp313-abi3-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:def246fe9e180626731b26e89816e79aae2276f825420a07b4a647abaa84becc", size = 96660, upload-time = "2025-08-05T16:42:28.9Z" }, + { url = "https://files.pythonhosted.org/packages/50/d5/8a0ae607ca07dbb34027bac8db805498ee7bfecc05fd2c148cc1ed7646e7/audioop_lts-0.2.2-cp313-abi3-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e160bf9df356d841bb6c180eeeea1834085464626dc1b68fa4e1d59070affdc3", size = 79143, upload-time = "2025-08-05T16:42:29.929Z" }, + { url = "https://files.pythonhosted.org/packages/12/17/0d28c46179e7910bfb0bb62760ccb33edb5de973052cb2230b662c14ca2e/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4b4cd51a57b698b2d06cb9993b7ac8dfe89a3b2878e96bc7948e9f19ff51dba6", size = 84313, upload-time = "2025-08-05T16:42:30.949Z" }, + { url = "https://files.pythonhosted.org/packages/84/ba/bd5d3806641564f2024e97ca98ea8f8811d4e01d9b9f9831474bc9e14f9e/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:4a53aa7c16a60a6857e6b0b165261436396ef7293f8b5c9c828a3a203147ed4a", size = 93044, upload-time = "2025-08-05T16:42:31.959Z" }, + { url = "https://files.pythonhosted.org/packages/f9/5e/435ce8d5642f1f7679540d1e73c1c42d933331c0976eb397d1717d7f01a3/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_riscv64.whl", hash = "sha256:3fc38008969796f0f689f1453722a0f463da1b8a6fbee11987830bfbb664f623", size = 78766, upload-time = "2025-08-05T16:42:33.302Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3b/b909e76b606cbfd53875693ec8c156e93e15a1366a012f0b7e4fb52d3c34/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_s390x.whl", hash = "sha256:15ab25dd3e620790f40e9ead897f91e79c0d3ce65fe193c8ed6c26cffdd24be7", size = 87640, upload-time = "2025-08-05T16:42:34.854Z" }, + { url = "https://files.pythonhosted.org/packages/30/e7/8f1603b4572d79b775f2140d7952f200f5e6c62904585d08a01f0a70393a/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:03f061a1915538fd96272bac9551841859dbb2e3bf73ebe4a23ef043766f5449", size = 86052, upload-time = "2025-08-05T16:42:35.839Z" }, + { url = "https://files.pythonhosted.org/packages/b5/96/c37846df657ccdda62ba1ae2b6534fa90e2e1b1742ca8dcf8ebd38c53801/audioop_lts-0.2.2-cp313-abi3-win32.whl", hash = "sha256:3bcddaaf6cc5935a300a8387c99f7a7fbbe212a11568ec6cf6e4bc458c048636", size = 26185, upload-time = "2025-08-05T16:42:37.04Z" }, + { url = "https://files.pythonhosted.org/packages/34/a5/9d78fdb5b844a83da8a71226c7bdae7cc638861085fff7a1d707cb4823fa/audioop_lts-0.2.2-cp313-abi3-win_amd64.whl", hash = "sha256:a2c2a947fae7d1062ef08c4e369e0ba2086049a5e598fda41122535557012e9e", size = 30503, upload-time = "2025-08-05T16:42:38.427Z" }, + { url = "https://files.pythonhosted.org/packages/34/25/20d8fde083123e90c61b51afb547bb0ea7e77bab50d98c0ab243d02a0e43/audioop_lts-0.2.2-cp313-abi3-win_arm64.whl", hash = "sha256:5f93a5db13927a37d2d09637ccca4b2b6b48c19cd9eda7b17a2e9f77edee6a6f", size = 24173, upload-time = "2025-08-05T16:42:39.704Z" }, + { url = "https://files.pythonhosted.org/packages/5c/73/413b5a2804091e2c7d5def1d618e4837f1cb82464e230f827226278556b7/audioop_lts-0.2.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:f9ee9b52f5f857fbaf9d605a360884f034c92c1c23021fb90b2e39b8e64bede6", size = 47104, upload-time = "2025-08-05T16:42:58.518Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8c/daa3308dc6593944410c2c68306a5e217f5c05b70a12e70228e7dd42dc5c/audioop_lts-0.2.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:49ee1a41738a23e98d98b937a0638357a2477bc99e61b0f768a8f654f45d9b7a", size = 27754, upload-time = "2025-08-05T16:43:00.132Z" }, + { url = "https://files.pythonhosted.org/packages/4e/86/c2e0f627168fcf61781a8f72cab06b228fe1da4b9fa4ab39cfb791b5836b/audioop_lts-0.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5b00be98ccd0fc123dcfad31d50030d25fcf31488cde9e61692029cd7394733b", size = 27332, upload-time = "2025-08-05T16:43:01.666Z" }, + { url = "https://files.pythonhosted.org/packages/c7/bd/35dce665255434f54e5307de39e31912a6f902d4572da7c37582809de14f/audioop_lts-0.2.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a6d2e0f9f7a69403e388894d4ca5ada5c47230716a03f2847cfc7bd1ecb589d6", size = 92396, upload-time = "2025-08-05T16:43:02.991Z" }, + { url = "https://files.pythonhosted.org/packages/2d/d2/deeb9f51def1437b3afa35aeb729d577c04bcd89394cb56f9239a9f50b6f/audioop_lts-0.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f9b0b8a03ef474f56d1a842af1a2e01398b8f7654009823c6d9e0ecff4d5cfbf", size = 91811, upload-time = "2025-08-05T16:43:04.096Z" }, + { url = "https://files.pythonhosted.org/packages/76/3b/09f8b35b227cee28cc8231e296a82759ed80c1a08e349811d69773c48426/audioop_lts-0.2.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2b267b70747d82125f1a021506565bdc5609a2b24bcb4773c16d79d2bb260bbd", size = 100483, upload-time = "2025-08-05T16:43:05.085Z" }, + { url = "https://files.pythonhosted.org/packages/0b/15/05b48a935cf3b130c248bfdbdea71ce6437f5394ee8533e0edd7cfd93d5e/audioop_lts-0.2.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0337d658f9b81f4cd0fdb1f47635070cc084871a3d4646d9de74fdf4e7c3d24a", size = 103885, upload-time = "2025-08-05T16:43:06.197Z" }, + { url = "https://files.pythonhosted.org/packages/83/80/186b7fce6d35b68d3d739f228dc31d60b3412105854edb975aa155a58339/audioop_lts-0.2.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:167d3b62586faef8b6b2275c3218796b12621a60e43f7e9d5845d627b9c9b80e", size = 84899, upload-time = "2025-08-05T16:43:07.291Z" }, + { url = "https://files.pythonhosted.org/packages/49/89/c78cc5ac6cb5828f17514fb12966e299c850bc885e80f8ad94e38d450886/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0d9385e96f9f6da847f4d571ce3cb15b5091140edf3db97276872647ce37efd7", size = 89998, upload-time = "2025-08-05T16:43:08.335Z" }, + { url = "https://files.pythonhosted.org/packages/4c/4b/6401888d0c010e586c2ca50fce4c903d70a6bb55928b16cfbdfd957a13da/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:48159d96962674eccdca9a3df280e864e8ac75e40a577cc97c5c42667ffabfc5", size = 99046, upload-time = "2025-08-05T16:43:09.367Z" }, + { url = "https://files.pythonhosted.org/packages/de/f8/c874ca9bb447dae0e2ef2e231f6c4c2b0c39e31ae684d2420b0f9e97ee68/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8fefe5868cd082db1186f2837d64cfbfa78b548ea0d0543e9b28935ccce81ce9", size = 84843, upload-time = "2025-08-05T16:43:10.749Z" }, + { url = "https://files.pythonhosted.org/packages/3e/c0/0323e66f3daebc13fd46b36b30c3be47e3fc4257eae44f1e77eb828c703f/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:58cf54380c3884fb49fdd37dfb7a772632b6701d28edd3e2904743c5e1773602", size = 94490, upload-time = "2025-08-05T16:43:12.131Z" }, + { url = "https://files.pythonhosted.org/packages/98/6b/acc7734ac02d95ab791c10c3f17ffa3584ccb9ac5c18fd771c638ed6d1f5/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:088327f00488cdeed296edd9215ca159f3a5a5034741465789cad403fcf4bec0", size = 92297, upload-time = "2025-08-05T16:43:13.139Z" }, + { url = "https://files.pythonhosted.org/packages/13/c3/c3dc3f564ce6877ecd2a05f8d751b9b27a8c320c2533a98b0c86349778d0/audioop_lts-0.2.2-cp314-cp314t-win32.whl", hash = "sha256:068aa17a38b4e0e7de771c62c60bbca2455924b67a8814f3b0dee92b5820c0b3", size = 27331, upload-time = "2025-08-05T16:43:14.19Z" }, + { url = "https://files.pythonhosted.org/packages/72/bb/b4608537e9ffcb86449091939d52d24a055216a36a8bf66b936af8c3e7ac/audioop_lts-0.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:a5bf613e96f49712073de86f20dbdd4014ca18efd4d34ed18c75bd808337851b", size = 31697, upload-time = "2025-08-05T16:43:15.193Z" }, + { url = "https://files.pythonhosted.org/packages/f6/22/91616fe707a5c5510de2cac9b046a30defe7007ba8a0c04f9c08f27df312/audioop_lts-0.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:b492c3b040153e68b9fdaff5913305aaaba5bb433d8a7f73d5cf6a64ed3cc1dd", size = 25206, upload-time = "2025-08-05T16:43:16.444Z" }, +] + +[[package]] +name = "billiard" +version = "4.2.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/23/b12ac0bcdfb7360d664f40a00b1bda139cbbbced012c34e375506dbd0143/billiard-4.2.4.tar.gz", hash = "sha256:55f542c371209e03cd5862299b74e52e4fbcba8250ba611ad94276b369b6a85f", size = 156537, upload-time = "2025-11-30T13:28:48.52Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/87/8bab77b323f16d67be364031220069f79159117dd5e43eeb4be2fef1ac9b/billiard-4.2.4-py3-none-any.whl", hash = "sha256:525b42bdec68d2b983347ac312f892db930858495db601b5836ac24e6477cde5", size = 87070, upload-time = "2025-11-30T13:28:47.016Z" }, +] + +[[package]] +name = "black" +version = "26.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "mypy-extensions" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "platformdirs" }, + { name = "pytokens" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/37/5628dd55bf2b34257fc7603f0fe97c40e3aaf24265f416a9c85c95ca1436/black-26.5.1.tar.gz", hash = "sha256:dd321f668053961824bcc1be1cc1df748b2d7e4fa28086b08331e577b0100a73", size = 679439, upload-time = "2026-05-18T16:53:36.107Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a6/16/a8da8eb208c51c7f4ce74609a45d0dcc6d8a2141e45e81ee5289d1bb0d59/black-26.5.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e88976690a64b0af98312ca958415849cb42423423c5f2ee74af4b49a97a2168", size = 2004800, upload-time = "2026-05-18T17:05:38.182Z" }, + { url = "https://files.pythonhosted.org/packages/11/8a/a479296a19e383b70a725882a6cf3d786540601ff03cabbaaf1cce864c5a/black-26.5.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:32d5ea7f6c8bdfa6e648326ebca1f02b0764e2a029edc6f8dce2627e19d468c3", size = 1815576, upload-time = "2026-05-18T17:05:40.309Z" }, + { url = "https://files.pythonhosted.org/packages/81/6b/cfaf3d39f25132c156a068f6b805576c9103a84086019507c70e1911ee7d/black-26.5.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ea8d16dc41655aa113cd64665e7219446cd7e4ff2248d7178eaa905190c86b18", size = 1877927, upload-time = "2026-05-18T17:05:42.463Z" }, + { url = "https://files.pythonhosted.org/packages/66/76/302e313964bcff7e28df329d39f84f5270095730d85ff0acc260610a0d82/black-26.5.1-cp314-cp314-win_amd64.whl", hash = "sha256:577f21094ea469ef92ec1adaf2c9441a226d2144d01a5be2fa823cecf6543e50", size = 1511860, upload-time = "2026-05-18T17:05:43.943Z" }, + { url = "https://files.pythonhosted.org/packages/27/4e/a3827e35e0e567f9f9ee59e2a0ab979267dca98718f25547ca8c6733afd4/black-26.5.1-cp314-cp314-win_arm64.whl", hash = "sha256:ed1a20af114c301a0269bf01163d51dbef72737fd65f850001e7cbe7f3c7abae", size = 1316632, upload-time = "2026-05-18T17:05:45.521Z" }, + { url = "https://files.pythonhosted.org/packages/94/51/f975cae76d44274cc2868dc9040ac5d58d464784610234455b4e7b19c6ef/black-26.5.1-py3-none-any.whl", hash = "sha256:4ed7f7da04046d2e488437170797d3b4a4ad83906683bcb7dfc68b673bbce5e2", size = 213693, upload-time = "2026-05-18T16:53:33.964Z" }, +] + +[[package]] +name = "celery" +version = "5.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "billiard" }, + { name = "click" }, + { name = "click-didyoumean" }, + { name = "click-plugins" }, + { name = "click-repl" }, + { name = "kombu" }, + { name = "python-dateutil" }, + { name = "tzlocal" }, + { name = "vine" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e8/b4/a1233943ab5c8ea05fb877a88a0a0622bf47444b99e4991a8045ac37ea1d/celery-5.6.3.tar.gz", hash = "sha256:177006bd2054b882e9f01be59abd8529e88879ef50d7918a7050c5a9f4e12912", size = 1742243, upload-time = "2026-03-26T12:14:51.76Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cf/c9/6eccdda96e098f7ae843162db2d3c149c6931a24fda69fe4ab84d0027eb5/celery-5.6.3-py3-none-any.whl", hash = "sha256:0808f42f80909c4d5833202360ffafb2a4f83f4d8e23e1285d926610e9a7afa6", size = 451235, upload-time = "2026-03-26T12:14:49.491Z" }, +] + +[[package]] +name = "certifi" +version = "2026.5.20" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/ce/ee2ecad540810a79593028e88299baeae54d346cc7a0d94b6199988b89b1/certifi-2026.5.20.tar.gz", hash = "sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d", size = 135422, upload-time = "2026-05-20T11:46:50.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/59/8c/57e832b7af6d7c5abe66eb3fbe3a3a32f4d11ea23a1aa7131371035be991/certifi-2026.5.20-py3-none-any.whl", hash = "sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897", size = 134134, upload-time = "2026-05-20T11:46:48.578Z" }, +] + +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + +[[package]] +name = "cfgv" +version = "3.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, +] + +[[package]] +name = "chardet" +version = "5.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/f7b6ab21ec75897ed80c17d79b15951a719226b9fababf1e40ea74d69079/chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7", size = 2069618, upload-time = "2023-08-01T19:23:02.662Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/6f/f5fbc992a329ee4e0f288c1fe0e2ad9485ed064cac731ed2fe47dcc38cbf/chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970", size = 199385, upload-time = "2023-08-01T19:23:00.661Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/97/c8/c67cb8c70e19ef1960b97b22ed2a1567711de46c4ddf19799923adc836c2/charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0", size = 309234, upload-time = "2026-04-02T09:27:07.194Z" }, + { url = "https://files.pythonhosted.org/packages/99/85/c091fdee33f20de70d6c8b522743b6f831a2f1cd3ff86de4c6a827c48a76/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a", size = 208042, upload-time = "2026-04-02T09:27:08.749Z" }, + { url = "https://files.pythonhosted.org/packages/87/1c/ab2ce611b984d2fd5d86a5a8a19c1ae26acac6bad967da4967562c75114d/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b", size = 228706, upload-time = "2026-04-02T09:27:09.951Z" }, + { url = "https://files.pythonhosted.org/packages/a8/29/2b1d2cb00bf085f59d29eb773ce58ec2d325430f8c216804a0a5cd83cbca/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41", size = 224727, upload-time = "2026-04-02T09:27:11.175Z" }, + { url = "https://files.pythonhosted.org/packages/47/5c/032c2d5a07fe4d4855fea851209cca2b6f03ebeb6d4e3afdb3358386a684/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e", size = 215882, upload-time = "2026-04-02T09:27:12.446Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c2/356065d5a8b78ed04499cae5f339f091946a6a74f91e03476c33f0ab7100/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae", size = 200860, upload-time = "2026-04-02T09:27:13.721Z" }, + { url = "https://files.pythonhosted.org/packages/0c/cd/a32a84217ced5039f53b29f460962abb2d4420def55afabe45b1c3c7483d/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18", size = 211564, upload-time = "2026-04-02T09:27:15.272Z" }, + { url = "https://files.pythonhosted.org/packages/44/86/58e6f13ce26cc3b8f4a36b94a0f22ae2f00a72534520f4ae6857c4b81f89/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b", size = 211276, upload-time = "2026-04-02T09:27:16.834Z" }, + { url = "https://files.pythonhosted.org/packages/8f/fe/d17c32dc72e17e155e06883efa84514ca375f8a528ba2546bee73fc4df81/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356", size = 201238, upload-time = "2026-04-02T09:27:18.229Z" }, + { url = "https://files.pythonhosted.org/packages/6a/29/f33daa50b06525a237451cdb6c69da366c381a3dadcd833fa5676bc468b3/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab", size = 230189, upload-time = "2026-04-02T09:27:19.445Z" }, + { url = "https://files.pythonhosted.org/packages/b6/6e/52c84015394a6a0bdcd435210a7e944c5f94ea1055f5cc5d56c5fe368e7b/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46", size = 211352, upload-time = "2026-04-02T09:27:20.79Z" }, + { url = "https://files.pythonhosted.org/packages/8c/d7/4353be581b373033fb9198bf1da3cf8f09c1082561e8e922aa7b39bf9fe8/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44", size = 227024, upload-time = "2026-04-02T09:27:22.063Z" }, + { url = "https://files.pythonhosted.org/packages/30/45/99d18aa925bd1740098ccd3060e238e21115fffbfdcb8f3ece837d0ace6c/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72", size = 217869, upload-time = "2026-04-02T09:27:23.486Z" }, + { url = "https://files.pythonhosted.org/packages/5c/05/5ee478aa53f4bb7996482153d4bfe1b89e0f087f0ab6b294fcf92d595873/charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10", size = 148541, upload-time = "2026-04-02T09:27:25.146Z" }, + { url = "https://files.pythonhosted.org/packages/48/77/72dcb0921b2ce86420b2d79d454c7022bf5be40202a2a07906b9f2a35c97/charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f", size = 159634, upload-time = "2026-04-02T09:27:26.642Z" }, + { url = "https://files.pythonhosted.org/packages/c6/a3/c2369911cd72f02386e4e340770f6e158c7980267da16af8f668217abaa0/charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246", size = 148384, upload-time = "2026-04-02T09:27:28.271Z" }, + { url = "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24", size = 330133, upload-time = "2026-04-02T09:27:29.474Z" }, + { url = "https://files.pythonhosted.org/packages/8d/da/96975ddb11f8e977f706f45cddd8540fd8242f71ecdb5d18a80723dcf62c/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79", size = 216257, upload-time = "2026-04-02T09:27:30.793Z" }, + { url = "https://files.pythonhosted.org/packages/e5/e8/1d63bf8ef2d388e95c64b2098f45f84758f6d102a087552da1485912637b/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960", size = 234851, upload-time = "2026-04-02T09:27:32.44Z" }, + { url = "https://files.pythonhosted.org/packages/9b/40/e5ff04233e70da2681fa43969ad6f66ca5611d7e669be0246c4c7aaf6dc8/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4", size = 233393, upload-time = "2026-04-02T09:27:34.03Z" }, + { url = "https://files.pythonhosted.org/packages/be/c1/06c6c49d5a5450f76899992f1ee40b41d076aee9279b49cf9974d2f313d5/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e", size = 223251, upload-time = "2026-04-02T09:27:35.369Z" }, + { url = "https://files.pythonhosted.org/packages/2b/9f/f2ff16fb050946169e3e1f82134d107e5d4ae72647ec8a1b1446c148480f/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1", size = 206609, upload-time = "2026-04-02T09:27:36.661Z" }, + { url = "https://files.pythonhosted.org/packages/69/d5/a527c0cd8d64d2eab7459784fb4169a0ac76e5a6fc5237337982fd61347e/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44", size = 220014, upload-time = "2026-04-02T09:27:38.019Z" }, + { url = "https://files.pythonhosted.org/packages/7e/80/8a7b8104a3e203074dc9aa2c613d4b726c0e136bad1cc734594b02867972/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e", size = 218979, upload-time = "2026-04-02T09:27:39.37Z" }, + { url = "https://files.pythonhosted.org/packages/02/9a/b759b503d507f375b2b5c153e4d2ee0a75aa215b7f2489cf314f4541f2c0/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3", size = 209238, upload-time = "2026-04-02T09:27:40.722Z" }, + { url = "https://files.pythonhosted.org/packages/c2/4e/0f3f5d47b86bdb79256e7290b26ac847a2832d9a4033f7eb2cd4bcf4bb5b/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0", size = 236110, upload-time = "2026-04-02T09:27:42.33Z" }, + { url = "https://files.pythonhosted.org/packages/96/23/bce28734eb3ed2c91dcf93abeb8a5cf393a7b2749725030bb630e554fdd8/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e", size = 219824, upload-time = "2026-04-02T09:27:43.924Z" }, + { url = "https://files.pythonhosted.org/packages/2c/6f/6e897c6984cc4d41af319b077f2f600fc8214eb2fe2d6bcb79141b882400/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb", size = 233103, upload-time = "2026-04-02T09:27:45.348Z" }, + { url = "https://files.pythonhosted.org/packages/76/22/ef7bd0fe480a0ae9b656189ec00744b60933f68b4f42a7bb06589f6f576a/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe", size = 225194, upload-time = "2026-04-02T09:27:46.706Z" }, + { url = "https://files.pythonhosted.org/packages/c5/a7/0e0ab3e0b5bc1219bd80a6a0d4d72ca74d9250cb2382b7c699c147e06017/charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0", size = 159827, upload-time = "2026-04-02T09:27:48.053Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1d/29d32e0fb40864b1f878c7f5a0b343ae676c6e2b271a2d55cc3a152391da/charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c", size = 174168, upload-time = "2026-04-02T09:27:49.795Z" }, + { url = "https://files.pythonhosted.org/packages/de/32/d92444ad05c7a6e41fb2036749777c163baf7a0301a040cb672d6b2b1ae9/charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d", size = 153018, upload-time = "2026-04-02T09:27:51.116Z" }, + { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" }, +] + +[[package]] +name = "click" +version = "8.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9b/98/518d8e5081007684232226f475082b30087d0f585e8457db087298259f49/click-8.4.1.tar.gz", hash = "sha256:918b5633eddf6b41c32d4f454bf0de810065c74e3f7dbf8ee5452f8be88d3e96", size = 353007, upload-time = "2026-05-22T04:08:37.769Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/0d/67e5b4109ea4a837e80daa87c2c696711955e40449a97e8926672534def2/click-8.4.1-py3-none-any.whl", hash = "sha256:482be17c6991b8c19c5429a1e995d9b0efdbb63172824c41f99965dc0ade8ec2", size = 116639, upload-time = "2026-05-22T04:08:35.26Z" }, +] + +[[package]] +name = "click-didyoumean" +version = "0.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/30/ce/217289b77c590ea1e7c24242d9ddd6e249e52c795ff10fac2c50062c48cb/click_didyoumean-0.3.1.tar.gz", hash = "sha256:4f82fdff0dbe64ef8ab2279bd6aa3f6a99c3b28c05aa09cbfc07c9d7fbb5a463", size = 3089, upload-time = "2024-03-24T08:22:07.499Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl", hash = "sha256:5c4bb6007cfea5f2fd6583a2fb6701a22a41eb98957e63d0fac41c10e7c3117c", size = 3631, upload-time = "2024-03-24T08:22:06.356Z" }, +] + +[[package]] +name = "click-plugins" +version = "1.1.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c3/a4/34847b59150da33690a36da3681d6bbc2ec14ee9a846bc30a6746e5984e4/click_plugins-1.1.1.2.tar.gz", hash = "sha256:d7af3984a99d243c131aa1a828331e7630f4a88a9741fd05c927b204bcf92261", size = 8343, upload-time = "2025-06-25T00:47:37.555Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl", hash = "sha256:008d65743833ffc1f5417bf0e78e8d2c23aab04d9745ba817bd3e71b0feb6aa6", size = 11051, upload-time = "2025-06-25T00:47:36.731Z" }, +] + +[[package]] +name = "click-repl" +version = "0.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "prompt-toolkit" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cb/a2/57f4ac79838cfae6912f997b4d1a64a858fb0c86d7fcaae6f7b58d267fca/click-repl-0.3.0.tar.gz", hash = "sha256:17849c23dba3d667247dc4defe1757fff98694e90fe37474f3feebb69ced26a9", size = 10449, upload-time = "2023-06-15T12:43:51.141Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/40/9d857001228658f0d59e97ebd4c346fe73e138c6de1bce61dc568a57c7f8/click_repl-0.3.0-py3-none-any.whl", hash = "sha256:fb7e06deb8da8de86180a33a9da97ac316751c094c6899382da7feeeeb51b812", size = 10289, upload-time = "2023-06-15T12:43:48.626Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "crispy-bootstrap4" +version = "2026.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, + { name = "django-crispy-forms" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5b/cc/638d36595da9fbb2c9d0be98bf6007442a65a521b614cf4645d04311b061/crispy_bootstrap4-2026.2.tar.gz", hash = "sha256:66f8f14bf9c2c16ed94243236ed253a94e5a625afa1ee64022ce29db98c6cd85", size = 34645, upload-time = "2026-02-11T22:45:05.422Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/6d/b90d601ea2449cc6b35b4b08be90fb1f6ca1baf2be383ed195f7bfa91a32/crispy_bootstrap4-2026.2-py3-none-any.whl", hash = "sha256:4b2b99dfe3e3cacb548702159462110901bd38792b650b770e50c62284ac2227", size = 23178, upload-time = "2026-02-11T22:45:04.108Z" }, +] + +[[package]] +name = "cryptography" +version = "48.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9f/a9/db8f313fdcd85d767d4973515e1db101f9c71f95fced83233de224673757/cryptography-48.0.0.tar.gz", hash = "sha256:5c3932f4436d1cccb036cb0eaef46e6e2db91035166f1ad6505c3c9d5a635920", size = 832984, upload-time = "2026-05-04T22:59:38.133Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/3d/01f6dd9190170a5a241e0e98c2d04be3664a9e6f5b9b872cde63aff1c3dd/cryptography-48.0.0-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:0c558d2cdffd8f4bbb30fc7134c74d2ca9a476f830bb053074498fbc86f41ed6", size = 8001587, upload-time = "2026-05-04T22:57:36.803Z" }, + { url = "https://files.pythonhosted.org/packages/b2/6e/e90527eef33f309beb811cf7c982c3aeffcce8e3edb178baa4ca3ae4a6fa/cryptography-48.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f5333311663ea94f75dd408665686aaf426563556bb5283554a3539177e03b8c", size = 4690433, upload-time = "2026-05-04T22:57:40.373Z" }, + { url = "https://files.pythonhosted.org/packages/90/04/673510ed51ddff56575f306cf1617d80411ee76831ccd3097599140efdfe/cryptography-48.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7995ef305d7165c3f11ae07f2517e5a4f1d5c18da1376a0a9ed496336b69e5f3", size = 4710620, upload-time = "2026-05-04T22:57:42.935Z" }, + { url = "https://files.pythonhosted.org/packages/14/d5/e9c4ef932c8d800490c34d8bd589d64a31d5890e27ec9e9ad532be893294/cryptography-48.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:40ba1f85eaa6959837b1d51c9767e230e14612eea4ef110ee8854ada22da1bf5", size = 4696283, upload-time = "2026-05-04T22:57:45.294Z" }, + { url = "https://files.pythonhosted.org/packages/0c/29/174b9dfb60b12d59ecfc6cfa04bc88c21b42a54f01b8aae09bb6e51e4c7f/cryptography-48.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:369a6348999f94bbd53435c894377b20ab95f25a9065c283570e70150d8abc3c", size = 5296573, upload-time = "2026-05-04T22:57:47.933Z" }, + { url = "https://files.pythonhosted.org/packages/95/38/0d29a6fd7d0d1373f0c0c88a04ba20e359b257753ac497564cd660fc1d55/cryptography-48.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a0e692c683f4df67815a2d258b324e66f4738bd7a96a218c826dce4f4bd05d8f", size = 4743677, upload-time = "2026-05-04T22:57:50.067Z" }, + { url = "https://files.pythonhosted.org/packages/30/be/eef653013d5c63b6a490529e0316f9ac14a37602965d4903efed1399f32b/cryptography-48.0.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:18349bbc56f4743c8b12dc32e2bccb2cf83ee8b69a3bba74ef8ae857e26b3d25", size = 4330808, upload-time = "2026-05-04T22:57:52.301Z" }, + { url = "https://files.pythonhosted.org/packages/84/9e/500463e87abb7a0a0f9f256ec21123ecde0a7b5541a15e840ea54551fd81/cryptography-48.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:7e8eac43dfca5c4cccc6dad9a80504436fca53bb9bc3100a2386d730fbe6b602", size = 4695941, upload-time = "2026-05-04T22:57:54.603Z" }, + { url = "https://files.pythonhosted.org/packages/e3/dc/7303087450c2ec9e7fbb750e17c2abfbc658f23cbd0e54009509b7cc4091/cryptography-48.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9ccdac7d40688ecb5a3b4a604b8a88c8002e3442d6c60aead1db2a89a041560c", size = 5252579, upload-time = "2026-05-04T22:57:57.207Z" }, + { url = "https://files.pythonhosted.org/packages/d0/c0/7101d3b7215edcdc90c45da544961fd8ed2d6448f77577460fa75a8443f7/cryptography-48.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:bd72e68b06bb1e96913f97dd4901119bc17f39d4586a5adf2d3e47bc2b9d58b5", size = 4743326, upload-time = "2026-05-04T22:57:59.535Z" }, + { url = "https://files.pythonhosted.org/packages/ac/d8/5b833bad13016f562ab9d063d68199a4bd121d18458e439515601d3357ec/cryptography-48.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:59baa2cb386c4f0b9905bd6eb4c2a79a69a128408fd31d32ca4d7102d4156321", size = 4826672, upload-time = "2026-05-04T22:58:01.996Z" }, + { url = "https://files.pythonhosted.org/packages/98/e1/7074eb8bf3c135558c73fc2bcf0f5633f912e6fb87e868a55c454080ef09/cryptography-48.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9249e3cd978541d665967ac2cb2787fd6a62bddf1e75b3e347a594d7dacf4f74", size = 4972574, upload-time = "2026-05-04T22:58:03.968Z" }, + { url = "https://files.pythonhosted.org/packages/04/70/e5a1b41d325f797f39427aa44ef8baf0be500065ab6d8e10369d850d4a4f/cryptography-48.0.0-cp311-abi3-win32.whl", hash = "sha256:9c459db21422be75e2809370b829a87eb37f74cd785fc4aa9ea1e5f43b47cda4", size = 3294868, upload-time = "2026-05-04T22:58:06.467Z" }, + { url = "https://files.pythonhosted.org/packages/f4/ac/8ac51b4a5fc5932eb7ee5c517ba7dc8cd834f0048962b6b352f00f41ebf9/cryptography-48.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:5b012212e08b8dd5edc78ef54da83dd9892fd9105323b3993eff6bea65dc21d7", size = 3817107, upload-time = "2026-05-04T22:58:08.845Z" }, + { url = "https://files.pythonhosted.org/packages/6b/84/70e3feea9feea87fd7cbe77efb2712ae1e3e6edf10749dc6e95f4e60e455/cryptography-48.0.0-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:3cb07a3ed6431663cd321ea8a000a1314c74211f823e4177fefa2255e057d1ec", size = 7986556, upload-time = "2026-05-04T22:58:11.172Z" }, + { url = "https://files.pythonhosted.org/packages/89/6e/18e07a618bb5442ba10cf4df16e99c071365528aa570dfcb8c02e25a303b/cryptography-48.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8c7378637d7d88016fa6791c159f698b3d3eed28ebf844ac36b9dc04a14dae18", size = 4684776, upload-time = "2026-05-04T22:58:13.712Z" }, + { url = "https://files.pythonhosted.org/packages/be/6a/4ea3b4c6c6759794d5ee2103c304a5076dc4b19ae1f9fe47dba439e159e9/cryptography-48.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc90c0b39b2e3c65ef52c804b72e3c58f8a04ab2a1871272798e5f9572c17d20", size = 4698121, upload-time = "2026-05-04T22:58:16.448Z" }, + { url = "https://files.pythonhosted.org/packages/2f/59/6ff6ad6cae03bb887da2a5860b2c9805f8dac969ef01ce563336c49bd1d1/cryptography-48.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:76341972e1eff8b4bea859f09c0d3e64b96ce931b084f9b9b7db8ef364c30eff", size = 4690042, upload-time = "2026-05-04T22:58:18.544Z" }, + { url = "https://files.pythonhosted.org/packages/ca/b4/fc334ed8cfd705aca282fe4d8f5ae64a8e0f74932e9feecb344610cf6e4d/cryptography-48.0.0-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:55b7718303bf06a5753dcdccf2f3945cf18ad7bffde41b61226e4db31ab89a9c", size = 5282526, upload-time = "2026-05-04T22:58:20.75Z" }, + { url = "https://files.pythonhosted.org/packages/11/08/9f8c5386cc4cd90d8255c7cdd0f5baf459a08502a09de30dc51f553d38dc/cryptography-48.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:a64697c641c7b1b2178e573cbc31c7c6684cd56883a478d75143dbb7118036db", size = 4733116, upload-time = "2026-05-04T22:58:23.627Z" }, + { url = "https://files.pythonhosted.org/packages/b8/77/99307d7574045699f8805aa500fa0fb83422d115b5400a064ddd306d7750/cryptography-48.0.0-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:561215ea3879cb1cbbf272867e2efda62476f240fb58c64de6b393ae19246741", size = 4316030, upload-time = "2026-05-04T22:58:25.581Z" }, + { url = "https://files.pythonhosted.org/packages/fd/36/a608b98337af3cb2aff4818e406649d30572b7031918b04c87d979495348/cryptography-48.0.0-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:ad64688338ed4bc1a6618076ba75fd7194a5f1797ac60b47afe926285adb3166", size = 4689640, upload-time = "2026-05-04T22:58:27.747Z" }, + { url = "https://files.pythonhosted.org/packages/dd/a6/825010a291b4438aecc1f568bc428189fc1175515223632477c07dc0a6df/cryptography-48.0.0-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:906cbf0670286c6e0044156bc7d4af9cbb0ef6db9f73e52c3ec56ba6bdde5336", size = 5237657, upload-time = "2026-05-04T22:58:29.848Z" }, + { url = "https://files.pythonhosted.org/packages/b9/09/4e76a09b4caa29aad535ddc806f5d4c5d01885bd978bd984fbc6ca032cae/cryptography-48.0.0-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:ea8990436d914540a40ab24b6a77c0969695ed52f4a4874c5137ccf7045a7057", size = 4732362, upload-time = "2026-05-04T22:58:32.009Z" }, + { url = "https://files.pythonhosted.org/packages/18/78/444fa04a77d0cb95f417dda20d450e13c56ba8e5220fc892a1658f44f882/cryptography-48.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c18684a7f0cc9a3cb60328f496b8e3372def7c5d2df39ac267878b05565aaaae", size = 4819580, upload-time = "2026-05-04T22:58:34.254Z" }, + { url = "https://files.pythonhosted.org/packages/38/85/ea67067c70a1fd4be2c63d35eeed82658023021affccc7b17705f8527dd2/cryptography-48.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9be5aafa5736574f8f15f262adc81b2a9869e2cfe9014d52a44633905b40d52c", size = 4963283, upload-time = "2026-05-04T22:58:36.376Z" }, + { url = "https://files.pythonhosted.org/packages/75/54/cc6d0f3deac3e81c7f847e8a189a12b6cdd65059b43dad25d4316abd849a/cryptography-48.0.0-cp314-cp314t-win32.whl", hash = "sha256:c17dfe85494deaeddc5ce251aebd1d60bbe6afc8b62071bb0b469431a000124f", size = 3270954, upload-time = "2026-05-04T22:58:38.791Z" }, + { url = "https://files.pythonhosted.org/packages/49/67/cc947e288c0758a4e5473d1dcb743037ab7785541265a969240b8885441a/cryptography-48.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27241b1dc9962e056062a8eef1991d02c3a24569c95975bd2322a8a52c6e5e12", size = 3797313, upload-time = "2026-05-04T22:58:40.746Z" }, + { url = "https://files.pythonhosted.org/packages/f2/63/61d4a4e1c6b6bab6ce1e213cd36a24c415d90e76d78c5eb8577c5541d2e8/cryptography-48.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:58d00498e8933e4a194f3076aee1b4a97dfec1a6da444535755822fe5d8b0b86", size = 7983482, upload-time = "2026-05-04T22:58:43.769Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ac/f5b5995b87770c693e2596559ffafe195b4033a57f14a82268a2842953f3/cryptography-48.0.0-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:614d0949f4790582d2cc25553abd09dd723025f0c0e7c67376a1d77196743d6e", size = 4683266, upload-time = "2026-05-04T22:58:46.064Z" }, + { url = "https://files.pythonhosted.org/packages/ec/c6/8b14f67e18338fbc4adb76f66c001f5c3610b3e2d1837f268f47a347dbbb/cryptography-48.0.0-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7ce4bfae76319a532a2dc68f82cc32f5676ee792a983187dac07183690e5c66f", size = 4696228, upload-time = "2026-05-04T22:58:48.22Z" }, + { url = "https://files.pythonhosted.org/packages/ea/73/f808fbae9514bd91b47875b003f13e284c8c6bdfd904b7944e803937eec1/cryptography-48.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:2eb992bbd4661238c5a397594c83f5b4dc2bc5b848c365c8f991b6780efcc5c7", size = 4689097, upload-time = "2026-05-04T22:58:50.9Z" }, + { url = "https://files.pythonhosted.org/packages/93/01/d86632d7d28db8ae83221995752eeb6639ffb374c2d22955648cf8d52797/cryptography-48.0.0-cp39-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:22a5cb272895dce158b2cacdfdc3debd299019659f42947dbdac6f32d68fe832", size = 5283582, upload-time = "2026-05-04T22:58:53.017Z" }, + { url = "https://files.pythonhosted.org/packages/02/e1/50edc7a50334807cc4791fc4a0ce7468b4a1416d9138eab358bfc9a3d70b/cryptography-48.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2b4d59804e8408e2fea7d1fbaf218e5ec984325221db76e6a241a9abd6cdd95c", size = 4730479, upload-time = "2026-05-04T22:58:55.611Z" }, + { url = "https://files.pythonhosted.org/packages/6f/af/99a582b1b1641ff5911ac559beb45097cf79efd4ead4657f578ef1af2d47/cryptography-48.0.0-cp39-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:984a20b0f62a26f48a3396c72e4bc34c66e356d356bf370053066b3b6d54634a", size = 4326481, upload-time = "2026-05-04T22:58:57.607Z" }, + { url = "https://files.pythonhosted.org/packages/90/ee/89aa26a06ef0a7d7611788ffd571a7c50e368cc6a4d5eef8b4884e866edb/cryptography-48.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:5a5ed8fde7a1d09376ca0b40e68cd59c69fe23b1f9768bd5824f54681626032a", size = 4688713, upload-time = "2026-05-04T22:59:00.077Z" }, + { url = "https://files.pythonhosted.org/packages/70/ba/bcb1b0bb7a33d4c7c0c4d4c7874b4a62ae4f56113a5f4baefa362dfb1f0f/cryptography-48.0.0-cp39-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:8cd666227ef7af430aa5914a9910e0ddd703e75f039cef0825cd0da71b6b711a", size = 5238165, upload-time = "2026-05-04T22:59:02.317Z" }, + { url = "https://files.pythonhosted.org/packages/c9/70/ca4003b1ce5ca3dc3186ada51908c8a9b9ff7d5cab83cc0d43ee14ec144f/cryptography-48.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:9071196d81abc88b3516ac8cdfad32e2b66dd4a5393a8e68a961e9161ddc6239", size = 4729947, upload-time = "2026-05-04T22:59:05.255Z" }, + { url = "https://files.pythonhosted.org/packages/44/a0/4ec7cf774207905aef1a8d11c3750d5a1db805eb380ee4e16df317870128/cryptography-48.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1e2d54c8be6152856a36f0882ab231e70f8ec7f14e93cf87db8a2ed056bf160c", size = 4822059, upload-time = "2026-05-04T22:59:07.802Z" }, + { url = "https://files.pythonhosted.org/packages/1e/75/a2e55f99c16fcac7b5d6c1eb19ad8e00799854d6be5ca845f9259eae1681/cryptography-48.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a5da777e32ffed6f85a7b2b3f7c5cbc88c146bfcd0a1d7baf5fcc6c52ee35dd4", size = 4960575, upload-time = "2026-05-04T22:59:09.851Z" }, + { url = "https://files.pythonhosted.org/packages/b8/23/6e6f32143ab5d8b36ca848a502c4bcd477ae75b9e1677e3530d669062578/cryptography-48.0.0-cp39-abi3-win32.whl", hash = "sha256:77a2ccbbe917f6710e05ba9adaa25fb5075620bf3ea6fb751997875aff4ae4bd", size = 3279117, upload-time = "2026-05-04T22:59:12.019Z" }, + { url = "https://files.pythonhosted.org/packages/9d/9a/0fea98a70cf1749d41d738836f6349d97945f7c89433a259a6c2642eefeb/cryptography-48.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:16cd65b9330583e4619939b3a3843eec1e6e789744bb01e7c7e2e62e33c239c8", size = 3792100, upload-time = "2026-05-04T22:59:14.884Z" }, +] + +[[package]] +name = "defusedxml" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520, upload-time = "2021-03-08T10:59:26.269Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" }, +] + +[[package]] +name = "discord" +version = "2.3.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "discord-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7e/9f/0763429949416aeff9c6f33051270831b72e5582273acd28053b9b949462/discord-2.3.2.tar.gz", hash = "sha256:cc1ee2dbe6df218ca51519af355b97e87309f8230f58c7f34885feb8e8a76145", size = 1137, upload-time = "2023-08-10T21:45:07.93Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/38/d91ac49e8169b6c0f724f7aad26704eec07c4ecf31e067ca3d46a87e33d6/discord-2.3.2-py3-none-any.whl", hash = "sha256:d7959418799dd3b1e896685812d880169c193468b061b3431fa2a4664febd3da", size = 1132, upload-time = "2023-08-10T21:45:06.334Z" }, +] + +[[package]] +name = "discord-py" +version = "2.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "audioop-lts" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/57/9a2d9abdabdc9db8ef28ce0cf4129669e1c8717ba28d607b5ba357c4de3b/discord_py-2.7.1.tar.gz", hash = "sha256:24d5e6a45535152e4b98148a9dd6b550d25dc2c9fb41b6d670319411641249da", size = 1106326, upload-time = "2026-03-03T18:40:46.24Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/a7/17208c3b3f92319e7fad259f1c6d5a5baf8fd0654c54846ced329f83c3eb/discord_py-2.7.1-py3-none-any.whl", hash = "sha256:849dca2c63b171146f3a7f3f8acc04248098e9e6203412ce3cf2745f284f7439", size = 1227550, upload-time = "2026-03-03T18:40:44.492Z" }, +] + +[[package]] +name = "distlib" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, +] + +[[package]] +name = "django" +version = "5.2.14" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asgiref" }, + { name = "sqlparse" }, + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/65/95/95f7faa0950867afaa0bef2460c6263afd6a2c78cc9434046ed28160b015/django-5.2.14.tar.gz", hash = "sha256:58a63ba841662e5c686b57ba1fec52ddd68c0b93bd96ac3029d55728f00bf8a2", size = 10895118, upload-time = "2026-05-05T13:57:31.104Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/44/f172870cf87aa25afef48fb72adba89ee8b77fcab6f3b23d240b923f1528/django-5.2.14-py3-none-any.whl", hash = "sha256:6f712143bd3064310d1f50fac859c3e9a274bdcfc9595339853be7779297fc76", size = 8311320, upload-time = "2026-05-05T13:57:25.795Z" }, +] + +[[package]] +name = "django-appconf" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d1/a2/e58bec8d7941b914af52a67c35b5709eceed2caa2848f28437f1666ed668/django_appconf-1.2.0.tar.gz", hash = "sha256:15a88d60dd942d6059f467412fe4581db632ef03018a3c183fb415d6fc9e5cec", size = 16127, upload-time = "2025-11-08T15:46:27.304Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/e6/4c34d94dfb74bbcbc489606e61f1924933de30d22c593dd1f429f35fbd7f/django_appconf-1.2.0-py3-none-any.whl", hash = "sha256:b81bce5ef0ceb9d84df48dfb623a32235d941c78cc5e45dbb6947f154ea277f4", size = 6500, upload-time = "2025-11-08T15:46:25.957Z" }, +] + +[[package]] +name = "django-bootstrap-modal-forms" +version = "3.0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4f/92/d1d37315c897e2ad311242d617d87e26f507e0446bdfd6a0ef265501d138/django_bootstrap_modal_forms-3.0.5.tar.gz", hash = "sha256:322930953c68e1dcd4c5dc073612c77ff4d68c46074a55d98db2de6e7860050b", size = 38292, upload-time = "2024-09-28T13:39:55.656Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/e7/84a437e7d413e14627b82d6f3478960d01e88b5e927f673cee536e6907ba/django_bootstrap_modal_forms-3.0.5-py3-none-any.whl", hash = "sha256:e56bbe05fb29c5aa9e0f3c0277b0d8363b81cc6c4e4aaf152cedea883edae58a", size = 29560, upload-time = "2024-09-28T13:39:53.645Z" }, +] + +[[package]] +name = "django-compressor" +version = "4.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, + { name = "django-appconf" }, + { name = "rcssmin" }, + { name = "rjsmin" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a2/e4/c6d87b1341d744ceafa85eeceb2adabb1c62b795b8207cbc580fb70df8f4/django_compressor-4.6.0.tar.gz", hash = "sha256:c7478feab98f3368780591f9ee28a433350f5277dd28811f7f710f5bc6dff3c0", size = 99735, upload-time = "2025-11-10T13:12:11.439Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d5/9d/9a0ba39f33574994e5b33aea55a68e8fad72b8dd923a82300e4e91774f59/django_compressor-4.6.0-py3-none-any.whl", hash = "sha256:6e7b21020a0d86272c5e37000c33accc4ebeb77394a3dd86d775a09aae7aade4", size = 96828, upload-time = "2025-11-10T13:12:10.001Z" }, +] + +[[package]] +name = "django-crispy-forms" +version = "2.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/73/42/c2cfb672493730b963ef377b103e29871c56348a215d0ae8cf362fe8ab1e/django_crispy_forms-2.6.tar.gz", hash = "sha256:4921a1087c6cd4f9fa3c139654c1de1c1c385f8bd6729aaee530bc0121ab4b93", size = 1097838, upload-time = "2026-03-01T09:03:37.138Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/96/e3/4c5915a732d6ab54da8871400852b67529518eedfb6b78ecf10bbccfcabb/django_crispy_forms-2.6-py3-none-any.whl", hash = "sha256:8ee0ae28b6b0ac41ff48a65944480c049fe8d1b0047086874fd7efabf4ec1374", size = 31479, upload-time = "2026-03-01T09:03:36.048Z" }, +] + +[[package]] +name = "django-crontab" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/37/bd/a122ba96167f5dfab70a58ca22fa046b7ef1ebad9ff026f7831bd6c2a49c/django-crontab-0.7.1.tar.gz", hash = "sha256:1201810a212460aaaa48eb6a766738740daf42c1a4f6aafecfb1525036929236", size = 7089, upload-time = "2016-03-07T19:35:54.714Z" } + +[[package]] +name = "django-libsass" +version = "0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django-compressor" }, + { name = "libsass" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d2/6c/fe7c95536eed569960daf139726c8f83eaf8c4ae01d908c22d94d60f31c2/django-libsass-0.9.tar.gz", hash = "sha256:bfbbb55a8950bb40fa04dd416605f92da34ad1f303b10a41abc3232386ec27b5", size = 6754, upload-time = "2021-07-08T14:16:55.346Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/ee/65935acc5a36c418fa17d5190a4aeb339cfdf98b6a93ca1c59134cf1e6aa/django_libsass-0.9-py3-none-any.whl", hash = "sha256:5234d29100889cac79e36a0f44207ec6d275adfd2da1acb6a94b55c89fe2bd97", size = 6572, upload-time = "2021-07-08T14:16:53.501Z" }, +] + +[[package]] +name = "django-taggit" +version = "6.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/34/a6/f1beaf8f552fe90c153cc039316ebab942c23dfbc88588dde081fefca816/django_taggit-6.1.0.tar.gz", hash = "sha256:c4d1199e6df34125dd36db5eb0efe545b254dec3980ce5dd80e6bab3e78757c3", size = 38151, upload-time = "2024-09-29T08:07:39.477Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/34/4185c345530b91d05cb82e05d07148f481a5eb5dc2ac44e092b3daa6f206/django_taggit-6.1.0-py3-none-any.whl", hash = "sha256:ab776264bbc76cb3d7e49e1bf9054962457831bd21c3a42db9138b41956e4cf0", size = 75749, upload-time = "2024-09-29T08:07:14.612Z" }, +] + +[[package]] +name = "django-timezone-field" +version = "7.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/da/05/9b93a66452cdb8a08ab26f08d5766d2332673e659a8b2aeb73f2a904d421/django_timezone_field-7.2.1.tar.gz", hash = "sha256:def846f9e7200b7b8f2a28fcce2b78fb2d470f6a9f272b07c4e014f6ba4c6d2e", size = 13096, upload-time = "2025-12-06T23:50:44.591Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/7f/d885667401515b467f84569c56075bc9add72c9fd425fca51a25f4c997e1/django_timezone_field-7.2.1-py3-none-any.whl", hash = "sha256:276915b72c5816f57c3baf9e43f816c695ef940d1b21f91ebf6203c09bf4ad44", size = 13284, upload-time = "2025-12-06T23:50:43.302Z" }, +] + +[[package]] +name = "djangorestframework" +version = "3.17.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ca/d7/c016e69fac19ff8afdc89db9d31d9ae43ae031e4d1993b20aca179b8301a/djangorestframework-3.17.1.tar.gz", hash = "sha256:a6def5f447fe78ff853bff1d47a3c59bf38f5434b031780b351b0c73a62db1a5", size = 905742, upload-time = "2026-03-24T16:58:33.705Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/e1/2c516bdc83652b1a60c6119366ac2c0607b479ed05cd6093f916ca8928f8/djangorestframework-3.17.1-py3-none-any.whl", hash = "sha256:c3c74dd3e83a5a3efc37b3c18d92bd6f86a6791c7b7d4dff62bb068500e76457", size = 898844, upload-time = "2026-03-24T16:58:31.845Z" }, +] + +[[package]] +name = "executing" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, +] + +[[package]] +name = "filelock" +version = "3.29.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/fe/997687a931ab51049acce6fa1f23e8f01216374ea81374ddee763c493db5/filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90", size = 57571, upload-time = "2026-04-19T15:39:10.068Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258", size = 39812, upload-time = "2026-04-19T15:39:08.752Z" }, +] + +[[package]] +name = "flower" +version = "2.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "celery" }, + { name = "humanize" }, + { name = "prometheus-client" }, + { name = "pytz" }, + { name = "tornado" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/09/a1/357f1b5d8946deafdcfdd604f51baae9de10aafa2908d0b7322597155f92/flower-2.0.1.tar.gz", hash = "sha256:5ab717b979530770c16afb48b50d2a98d23c3e9fe39851dcf6bc4d01845a02a0", size = 3220408, upload-time = "2023-08-13T14:37:46.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a6/ff/ee2f67c0ff146ec98b5df1df637b2bc2d17beeb05df9f427a67bd7a7d79c/flower-2.0.1-py2.py3-none-any.whl", hash = "sha256:9db2c621eeefbc844c8dd88be64aef61e84e2deb29b271e02ab2b5b9f01068e2", size = 383553, upload-time = "2023-08-13T14:37:41.552Z" }, +] + +[[package]] +name = "frozenlist" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/c8/85da824b7e7b9b6e7f7705b2ecaf9591ba6f79c1177f324c2735e41d36a2/frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0", size = 86127, upload-time = "2025-10-06T05:37:08.438Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e8/a1185e236ec66c20afd72399522f142c3724c785789255202d27ae992818/frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f", size = 49698, upload-time = "2025-10-06T05:37:09.48Z" }, + { url = "https://files.pythonhosted.org/packages/a1/93/72b1736d68f03fda5fdf0f2180fb6caaae3894f1b854d006ac61ecc727ee/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c", size = 49749, upload-time = "2025-10-06T05:37:10.569Z" }, + { url = "https://files.pythonhosted.org/packages/a7/b2/fabede9fafd976b991e9f1b9c8c873ed86f202889b864756f240ce6dd855/frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2", size = 231298, upload-time = "2025-10-06T05:37:11.993Z" }, + { url = "https://files.pythonhosted.org/packages/3a/3b/d9b1e0b0eed36e70477ffb8360c49c85c8ca8ef9700a4e6711f39a6e8b45/frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8", size = 232015, upload-time = "2025-10-06T05:37:13.194Z" }, + { url = "https://files.pythonhosted.org/packages/dc/94/be719d2766c1138148564a3960fc2c06eb688da592bdc25adcf856101be7/frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686", size = 225038, upload-time = "2025-10-06T05:37:14.577Z" }, + { url = "https://files.pythonhosted.org/packages/e4/09/6712b6c5465f083f52f50cf74167b92d4ea2f50e46a9eea0523d658454ae/frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e", size = 240130, upload-time = "2025-10-06T05:37:15.781Z" }, + { url = "https://files.pythonhosted.org/packages/f8/d4/cd065cdcf21550b54f3ce6a22e143ac9e4836ca42a0de1022da8498eac89/frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a", size = 242845, upload-time = "2025-10-06T05:37:17.037Z" }, + { url = "https://files.pythonhosted.org/packages/62/c3/f57a5c8c70cd1ead3d5d5f776f89d33110b1addae0ab010ad774d9a44fb9/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128", size = 229131, upload-time = "2025-10-06T05:37:18.221Z" }, + { url = "https://files.pythonhosted.org/packages/6c/52/232476fe9cb64f0742f3fde2b7d26c1dac18b6d62071c74d4ded55e0ef94/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f", size = 240542, upload-time = "2025-10-06T05:37:19.771Z" }, + { url = "https://files.pythonhosted.org/packages/5f/85/07bf3f5d0fb5414aee5f47d33c6f5c77bfe49aac680bfece33d4fdf6a246/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7", size = 237308, upload-time = "2025-10-06T05:37:20.969Z" }, + { url = "https://files.pythonhosted.org/packages/11/99/ae3a33d5befd41ac0ca2cc7fd3aa707c9c324de2e89db0e0f45db9a64c26/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30", size = 238210, upload-time = "2025-10-06T05:37:22.252Z" }, + { url = "https://files.pythonhosted.org/packages/b2/60/b1d2da22f4970e7a155f0adde9b1435712ece01b3cd45ba63702aea33938/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7", size = 231972, upload-time = "2025-10-06T05:37:23.5Z" }, + { url = "https://files.pythonhosted.org/packages/3f/ab/945b2f32de889993b9c9133216c068b7fcf257d8595a0ac420ac8677cab0/frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806", size = 40536, upload-time = "2025-10-06T05:37:25.581Z" }, + { url = "https://files.pythonhosted.org/packages/59/ad/9caa9b9c836d9ad6f067157a531ac48b7d36499f5036d4141ce78c230b1b/frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0", size = 44330, upload-time = "2025-10-06T05:37:26.928Z" }, + { url = "https://files.pythonhosted.org/packages/82/13/e6950121764f2676f43534c555249f57030150260aee9dcf7d64efda11dd/frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b", size = 40627, upload-time = "2025-10-06T05:37:28.075Z" }, + { url = "https://files.pythonhosted.org/packages/c0/c7/43200656ecc4e02d3f8bc248df68256cd9572b3f0017f0a0c4e93440ae23/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d", size = 89238, upload-time = "2025-10-06T05:37:29.373Z" }, + { url = "https://files.pythonhosted.org/packages/d1/29/55c5f0689b9c0fb765055629f472c0de484dcaf0acee2f7707266ae3583c/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed", size = 50738, upload-time = "2025-10-06T05:37:30.792Z" }, + { url = "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930", size = 51739, upload-time = "2025-10-06T05:37:32.127Z" }, + { url = "https://files.pythonhosted.org/packages/62/1c/3d8622e60d0b767a5510d1d3cf21065b9db874696a51ea6d7a43180a259c/frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c", size = 284186, upload-time = "2025-10-06T05:37:33.21Z" }, + { url = "https://files.pythonhosted.org/packages/2d/14/aa36d5f85a89679a85a1d44cd7a6657e0b1c75f61e7cad987b203d2daca8/frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24", size = 292196, upload-time = "2025-10-06T05:37:36.107Z" }, + { url = "https://files.pythonhosted.org/packages/05/23/6bde59eb55abd407d34f77d39a5126fb7b4f109a3f611d3929f14b700c66/frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37", size = 273830, upload-time = "2025-10-06T05:37:37.663Z" }, + { url = "https://files.pythonhosted.org/packages/d2/3f/22cff331bfad7a8afa616289000ba793347fcd7bc275f3b28ecea2a27909/frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a", size = 294289, upload-time = "2025-10-06T05:37:39.261Z" }, + { url = "https://files.pythonhosted.org/packages/a4/89/5b057c799de4838b6c69aa82b79705f2027615e01be996d2486a69ca99c4/frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2", size = 300318, upload-time = "2025-10-06T05:37:43.213Z" }, + { url = "https://files.pythonhosted.org/packages/30/de/2c22ab3eb2a8af6d69dc799e48455813bab3690c760de58e1bf43b36da3e/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef", size = 282814, upload-time = "2025-10-06T05:37:45.337Z" }, + { url = "https://files.pythonhosted.org/packages/59/f7/970141a6a8dbd7f556d94977858cfb36fa9b66e0892c6dd780d2219d8cd8/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe", size = 291762, upload-time = "2025-10-06T05:37:46.657Z" }, + { url = "https://files.pythonhosted.org/packages/c1/15/ca1adae83a719f82df9116d66f5bb28bb95557b3951903d39135620ef157/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8", size = 289470, upload-time = "2025-10-06T05:37:47.946Z" }, + { url = "https://files.pythonhosted.org/packages/ac/83/dca6dc53bf657d371fbc88ddeb21b79891e747189c5de990b9dfff2ccba1/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a", size = 289042, upload-time = "2025-10-06T05:37:49.499Z" }, + { url = "https://files.pythonhosted.org/packages/96/52/abddd34ca99be142f354398700536c5bd315880ed0a213812bc491cff5e4/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e", size = 283148, upload-time = "2025-10-06T05:37:50.745Z" }, + { url = "https://files.pythonhosted.org/packages/af/d3/76bd4ed4317e7119c2b7f57c3f6934aba26d277acc6309f873341640e21f/frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df", size = 44676, upload-time = "2025-10-06T05:37:52.222Z" }, + { url = "https://files.pythonhosted.org/packages/89/76/c615883b7b521ead2944bb3480398cbb07e12b7b4e4d073d3752eb721558/frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd", size = 49451, upload-time = "2025-10-06T05:37:53.425Z" }, + { url = "https://files.pythonhosted.org/packages/e0/a3/5982da14e113d07b325230f95060e2169f5311b1017ea8af2a29b374c289/frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79", size = 42507, upload-time = "2025-10-06T05:37:54.513Z" }, + { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, +] + +[[package]] +name = "httplib2" +version = "0.31.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyparsing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c1/1f/e86365613582c027dda5ddb64e1010e57a3d53e99ab8a72093fa13d565ec/httplib2-0.31.2.tar.gz", hash = "sha256:385e0869d7397484f4eab426197a4c020b606edd43372492337c0b4010ae5d24", size = 250800, upload-time = "2026-01-23T11:04:44.165Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2f/90/fd509079dfcab01102c0fdd87f3a9506894bc70afcf9e9785ef6b2b3aff6/httplib2-0.31.2-py3-none-any.whl", hash = "sha256:dbf0c2fa3862acf3c55c078ea9c0bc4481d7dc5117cae71be9514912cf9f8349", size = 91099, upload-time = "2026-01-23T11:04:42.78Z" }, +] + +[[package]] +name = "humanize" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/66/a3921783d54be8a6870ac4ccffcd15c4dc0dd7fcce51c6d63b8c63935276/humanize-4.15.0.tar.gz", hash = "sha256:1dd098483eb1c7ee8e32eb2e99ad1910baefa4b75c3aff3a82f4d78688993b10", size = 83599, upload-time = "2025-12-20T20:16:13.19Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/7b/bca5613a0c3b542420cf92bd5e5fb8ebd5435ce1011a091f66bb7693285e/humanize-4.15.0-py3-none-any.whl", hash = "sha256:b1186eb9f5a9749cd9cb8565aee77919dd7c8d076161cf44d70e59e3301e1769", size = 132203, upload-time = "2025-12-20T20:16:11.67Z" }, +] + +[[package]] +name = "icecream" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asttokens" }, + { name = "colorama" }, + { name = "executing" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/10/84/6ebc95844feae8a6a29c7fd57e9e3a7ac4817ffab384dc4f0ed53b8e3c46/icecream-2.2.0.tar.gz", hash = "sha256:9d7f244187f00a13f4ac77d176990e187e9c279d6cac4f7548e338291ad97343", size = 14267, upload-time = "2026-04-03T17:42:51.387Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/82/9707c7b0336bca53b75f52fc350956a93da66eb6be632b370bc933216fb4/icecream-2.2.0-py3-none-any.whl", hash = "sha256:f8df7343b3e787023eec22f42fbe4722df2f93099d394fd820b91e16b2e6cb56", size = 16707, upload-time = "2026-04-03T17:42:50.001Z" }, +] + +[[package]] +name = "identify" +version = "2.6.19" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/52/63/51723b5f116cc04b061cb6f5a561790abf249d25931d515cd375e063e0f4/identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842", size = 99567, upload-time = "2026-04-17T18:39:50.265Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a", size = 99397, upload-time = "2026-04-17T18:39:49.221Z" }, +] + +[[package]] +name = "idna" +version = "3.16" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1a/88/bcf9709822fe69d02c2a6a77956c98ce6ea8ca8767a9aadcedc7eb6a2390/idna-3.16.tar.gz", hash = "sha256:d7a6da03db833450fca25d2358ac9ff06cd624577a4aea3a596d5c0f77b8e03d", size = 203770, upload-time = "2026-05-22T00:16:18.781Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/16/70255075a9859a0e3adb789b68ceb0e210dec03934245fd98d248226572f/idna-3.16-py3-none-any.whl", hash = "sha256:cc246e3a3f89580c3a951b5ad298ca4638078b2cdd4f115654332b5c26daded5", size = 74165, upload-time = "2026-05-22T00:16:16.698Z" }, +] + +[[package]] +name = "isort" +version = "8.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ef/7c/ec4ab396d31b3b395e2e999c8f46dec78c5e29209fac49d1f4dace04041d/isort-8.0.1.tar.gz", hash = "sha256:171ac4ff559cdc060bcfff550bc8404a486fee0caab245679c2abe7cb253c78d", size = 769592, upload-time = "2026-02-28T10:08:20.685Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3e/95/c7c34aa53c16353c56d0b802fba48d5f5caa2cdee7958acbcb795c830416/isort-8.0.1-py3-none-any.whl", hash = "sha256:28b89bc70f751b559aeca209e6120393d43fbe2490de0559662be7a9787e3d75", size = 89733, upload-time = "2026-02-28T10:08:19.466Z" }, +] + +[[package]] +name = "kombu" +version = "5.6.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "amqp" }, + { name = "packaging" }, + { name = "tzdata" }, + { name = "vine" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b6/a5/607e533ed6c83ae1a696969b8e1c137dfebd5759a2e9682e26ff1b97740b/kombu-5.6.2.tar.gz", hash = "sha256:8060497058066c6f5aed7c26d7cd0d3b574990b09de842a8c5aaed0b92cc5a55", size = 472594, upload-time = "2025-12-29T20:30:07.779Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/0f/834427d8c03ff1d7e867d3db3d176470c64871753252b21b4f4897d1fa45/kombu-5.6.2-py3-none-any.whl", hash = "sha256:efcfc559da324d41d61ca311b0c64965ea35b4c55cc04ee36e55386145dace93", size = 214219, upload-time = "2025-12-29T20:30:05.74Z" }, +] + +[[package]] +name = "libsass" +version = "0.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/79/b4/ab091585eaa77299558e3289ca206846aefc123fb320b5656ab2542c20ad/libsass-0.23.0.tar.gz", hash = "sha256:6f209955ede26684e76912caf329f4ccb57e4a043fd77fe0e7348dd9574f1880", size = 316068, upload-time = "2024-01-06T18:53:05.404Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/13/fc1bea1de880ca935137183727c7d4dd921c4128fc08b8ddc3698ba5a8a3/libsass-0.23.0-cp38-abi3-macosx_11_0_x86_64.whl", hash = "sha256:34cae047cbbfc4ffa832a61cbb110f3c95f5471c6170c842d3fed161e40814dc", size = 1086783, upload-time = "2024-01-06T19:02:38.903Z" }, + { url = "https://files.pythonhosted.org/packages/55/2f/6af938651ff3aec0a0b00742209df1172bc297fa73531f292801693b7315/libsass-0.23.0-cp38-abi3-macosx_14_0_arm64.whl", hash = "sha256:ea97d1b45cdc2fc3590cb9d7b60f1d8915d3ce17a98c1f2d4dd47ee0d9c68ce6", size = 982759, upload-time = "2024-01-06T19:02:41.331Z" }, + { url = "https://files.pythonhosted.org/packages/fd/5a/eb5b62641df0459a3291fc206cf5bd669c0feed7814dded8edef4ade8512/libsass-0.23.0-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4a218406d605f325d234e4678bd57126a66a88841cb95bee2caeafdc6f138306", size = 9444543, upload-time = "2024-01-06T19:02:43.191Z" }, + { url = "https://files.pythonhosted.org/packages/e5/fc/275783f5120970d859ae37d04b6a60c13bdec2aa4294b9dfa8a37b5c2513/libsass-0.23.0-cp38-abi3-win32.whl", hash = "sha256:31e86d92a5c7a551df844b72d83fc2b5e50abc6fbbb31e296f7bebd6489ed1b4", size = 775481, upload-time = "2024-01-06T19:02:46.05Z" }, + { url = "https://files.pythonhosted.org/packages/ef/20/caf3c7cf2432d85263119798c45221ddf67bdd7dae8f626d14ff8db04040/libsass-0.23.0-cp38-abi3-win_amd64.whl", hash = "sha256:a2ec85d819f353cbe807432d7275d653710d12b08ec7ef61c124a580a8352f3c", size = 872914, upload-time = "2024-01-06T19:02:47.61Z" }, +] + +[[package]] +name = "multidict" +version = "6.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010, upload-time = "2026-01-26T02:46:45.979Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/cc/db74228a8be41884a567e88a62fd589a913708fcf180d029898c17a9a371/multidict-6.7.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8f333ec9c5eb1b7105e3b84b53141e66ca05a19a605368c55450b6ba208cb9ee", size = 75190, upload-time = "2026-01-26T02:45:10.651Z" }, + { url = "https://files.pythonhosted.org/packages/d5/22/492f2246bb5b534abd44804292e81eeaf835388901f0c574bac4eeec73c5/multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a407f13c188f804c759fc6a9f88286a565c242a76b27626594c133b82883b5c2", size = 44486, upload-time = "2026-01-26T02:45:11.938Z" }, + { url = "https://files.pythonhosted.org/packages/f1/4f/733c48f270565d78b4544f2baddc2fb2a245e5a8640254b12c36ac7ac68e/multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0e161ddf326db5577c3a4cc2d8648f81456e8a20d40415541587a71620d7a7d1", size = 43219, upload-time = "2026-01-26T02:45:14.346Z" }, + { url = "https://files.pythonhosted.org/packages/24/bb/2c0c2287963f4259c85e8bcbba9182ced8d7fca65c780c38e99e61629d11/multidict-6.7.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1e3a8bb24342a8201d178c3b4984c26ba81a577c80d4d525727427460a50c22d", size = 245132, upload-time = "2026-01-26T02:45:15.712Z" }, + { url = "https://files.pythonhosted.org/packages/a7/f9/44d4b3064c65079d2467888794dea218d1601898ac50222ab8a9a8094460/multidict-6.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97231140a50f5d447d3164f994b86a0bed7cd016e2682f8650d6a9158e14fd31", size = 252420, upload-time = "2026-01-26T02:45:17.293Z" }, + { url = "https://files.pythonhosted.org/packages/8b/13/78f7275e73fa17b24c9a51b0bd9d73ba64bb32d0ed51b02a746eb876abe7/multidict-6.7.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6b10359683bd8806a200fd2909e7c8ca3a7b24ec1d8132e483d58e791d881048", size = 233510, upload-time = "2026-01-26T02:45:19.356Z" }, + { url = "https://files.pythonhosted.org/packages/4b/25/8167187f62ae3cbd52da7893f58cb036b47ea3fb67138787c76800158982/multidict-6.7.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:283ddac99f7ac25a4acadbf004cb5ae34480bbeb063520f70ce397b281859362", size = 264094, upload-time = "2026-01-26T02:45:20.834Z" }, + { url = "https://files.pythonhosted.org/packages/a1/e7/69a3a83b7b030cf283fb06ce074a05a02322359783424d7edf0f15fe5022/multidict-6.7.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:538cec1e18c067d0e6103aa9a74f9e832904c957adc260e61cd9d8cf0c3b3d37", size = 260786, upload-time = "2026-01-26T02:45:22.818Z" }, + { url = "https://files.pythonhosted.org/packages/fe/3b/8ec5074bcfc450fe84273713b4b0a0dd47c0249358f5d82eb8104ffe2520/multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eee46ccb30ff48a1e35bb818cc90846c6be2b68240e42a78599166722cea709", size = 248483, upload-time = "2026-01-26T02:45:24.368Z" }, + { url = "https://files.pythonhosted.org/packages/48/5a/d5a99e3acbca0e29c5d9cba8f92ceb15dce78bab963b308ae692981e3a5d/multidict-6.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa263a02f4f2dd2d11a7b1bb4362aa7cb1049f84a9235d31adf63f30143469a0", size = 248403, upload-time = "2026-01-26T02:45:25.982Z" }, + { url = "https://files.pythonhosted.org/packages/35/48/e58cd31f6c7d5102f2a4bf89f96b9cf7e00b6c6f3d04ecc44417c00a5a3c/multidict-6.7.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2e1425e2f99ec5bd36c15a01b690a1a2456209c5deed58f95469ffb46039ccbb", size = 240315, upload-time = "2026-01-26T02:45:27.487Z" }, + { url = "https://files.pythonhosted.org/packages/94/33/1cd210229559cb90b6786c30676bb0c58249ff42f942765f88793b41fdce/multidict-6.7.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:497394b3239fc6f0e13a78a3e1b61296e72bf1c5f94b4c4eb80b265c37a131cd", size = 245528, upload-time = "2026-01-26T02:45:28.991Z" }, + { url = "https://files.pythonhosted.org/packages/64/f2/6e1107d226278c876c783056b7db43d800bb64c6131cec9c8dfb6903698e/multidict-6.7.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:233b398c29d3f1b9676b4b6f75c518a06fcb2ea0b925119fb2c1bc35c05e1601", size = 258784, upload-time = "2026-01-26T02:45:30.503Z" }, + { url = "https://files.pythonhosted.org/packages/4d/c1/11f664f14d525e4a1b5327a82d4de61a1db604ab34c6603bb3c2cc63ad34/multidict-6.7.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:93b1818e4a6e0930454f0f2af7dfce69307ca03cdcfb3739bf4d91241967b6c1", size = 251980, upload-time = "2026-01-26T02:45:32.603Z" }, + { url = "https://files.pythonhosted.org/packages/e1/9f/75a9ac888121d0c5bbd4ecf4eead45668b1766f6baabfb3b7f66a410e231/multidict-6.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f33dc2a3abe9249ea5d8360f969ec7f4142e7ac45ee7014d8f8d5acddf178b7b", size = 243602, upload-time = "2026-01-26T02:45:34.043Z" }, + { url = "https://files.pythonhosted.org/packages/9a/e7/50bf7b004cc8525d80dbbbedfdc7aed3e4c323810890be4413e589074032/multidict-6.7.1-cp314-cp314-win32.whl", hash = "sha256:3ab8b9d8b75aef9df299595d5388b14530839f6422333357af1339443cff777d", size = 40930, upload-time = "2026-01-26T02:45:36.278Z" }, + { url = "https://files.pythonhosted.org/packages/e0/bf/52f25716bbe93745595800f36fb17b73711f14da59ed0bb2eba141bc9f0f/multidict-6.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:5e01429a929600e7dab7b166062d9bb54a5eed752384c7384c968c2afab8f50f", size = 45074, upload-time = "2026-01-26T02:45:37.546Z" }, + { url = "https://files.pythonhosted.org/packages/97/ab/22803b03285fa3a525f48217963da3a65ae40f6a1b6f6cf2768879e208f9/multidict-6.7.1-cp314-cp314-win_arm64.whl", hash = "sha256:4885cb0e817aef5d00a2e8451d4665c1808378dc27c2705f1bf4ef8505c0d2e5", size = 42471, upload-time = "2026-01-26T02:45:38.889Z" }, + { url = "https://files.pythonhosted.org/packages/e0/6d/f9293baa6146ba9507e360ea0292b6422b016907c393e2f63fc40ab7b7b5/multidict-6.7.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0458c978acd8e6ea53c81eefaddbbee9c6c5e591f41b3f5e8e194780fe026581", size = 82401, upload-time = "2026-01-26T02:45:40.254Z" }, + { url = "https://files.pythonhosted.org/packages/7a/68/53b5494738d83558d87c3c71a486504d8373421c3e0dbb6d0db48ad42ee0/multidict-6.7.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c0abd12629b0af3cf590982c0b413b1e7395cd4ec026f30986818ab95bfaa94a", size = 48143, upload-time = "2026-01-26T02:45:41.635Z" }, + { url = "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:14525a5f61d7d0c94b368a42cff4c9a4e7ba2d52e2672a7b23d84dc86fb02b0c", size = 46507, upload-time = "2026-01-26T02:45:42.99Z" }, + { url = "https://files.pythonhosted.org/packages/e4/fc/6800d0e5b3875568b4083ecf5f310dcf91d86d52573160834fb4bfcf5e4f/multidict-6.7.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17307b22c217b4cf05033dabefe68255a534d637c6c9b0cc8382718f87be4262", size = 239358, upload-time = "2026-01-26T02:45:44.376Z" }, + { url = "https://files.pythonhosted.org/packages/41/75/4ad0973179361cdf3a113905e6e088173198349131be2b390f9fa4da5fc6/multidict-6.7.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a7e590ff876a3eaf1c02a4dfe0724b6e69a9e9de6d8f556816f29c496046e59", size = 246884, upload-time = "2026-01-26T02:45:47.167Z" }, + { url = "https://files.pythonhosted.org/packages/c3/9c/095bb28b5da139bd41fb9a5d5caff412584f377914bd8787c2aa98717130/multidict-6.7.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5fa6a95dfee63893d80a34758cd0e0c118a30b8dcb46372bf75106c591b77889", size = 225878, upload-time = "2026-01-26T02:45:48.698Z" }, + { url = "https://files.pythonhosted.org/packages/07/d0/c0a72000243756e8f5a277b6b514fa005f2c73d481b7d9e47cd4568aa2e4/multidict-6.7.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a0543217a6a017692aa6ae5cc39adb75e587af0f3a82288b1492eb73dd6cc2a4", size = 253542, upload-time = "2026-01-26T02:45:50.164Z" }, + { url = "https://files.pythonhosted.org/packages/c0/6b/f69da15289e384ecf2a68837ec8b5ad8c33e973aa18b266f50fe55f24b8c/multidict-6.7.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f99fe611c312b3c1c0ace793f92464d8cd263cc3b26b5721950d977b006b6c4d", size = 252403, upload-time = "2026-01-26T02:45:51.779Z" }, + { url = "https://files.pythonhosted.org/packages/a2/76/b9669547afa5a1a25cd93eaca91c0da1c095b06b6d2d8ec25b713588d3a1/multidict-6.7.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9004d8386d133b7e6135679424c91b0b854d2d164af6ea3f289f8f2761064609", size = 244889, upload-time = "2026-01-26T02:45:53.27Z" }, + { url = "https://files.pythonhosted.org/packages/7e/a9/a50d2669e506dad33cfc45b5d574a205587b7b8a5f426f2fbb2e90882588/multidict-6.7.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e628ef0e6859ffd8273c69412a2465c4be4a9517d07261b33334b5ec6f3c7489", size = 241982, upload-time = "2026-01-26T02:45:54.919Z" }, + { url = "https://files.pythonhosted.org/packages/c5/bb/1609558ad8b456b4827d3c5a5b775c93b87878fd3117ed3db3423dfbce1b/multidict-6.7.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:841189848ba629c3552035a6a7f5bf3b02eb304e9fea7492ca220a8eda6b0e5c", size = 232415, upload-time = "2026-01-26T02:45:56.981Z" }, + { url = "https://files.pythonhosted.org/packages/d8/59/6f61039d2aa9261871e03ab9dc058a550d240f25859b05b67fd70f80d4b3/multidict-6.7.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ce1bbd7d780bb5a0da032e095c951f7014d6b0a205f8318308140f1a6aba159e", size = 240337, upload-time = "2026-01-26T02:45:58.698Z" }, + { url = "https://files.pythonhosted.org/packages/a1/29/fdc6a43c203890dc2ae9249971ecd0c41deaedfe00d25cb6564b2edd99eb/multidict-6.7.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b26684587228afed0d50cf804cc71062cc9c1cdf55051c4c6345d372947b268c", size = 248788, upload-time = "2026-01-26T02:46:00.862Z" }, + { url = "https://files.pythonhosted.org/packages/a9/14/a153a06101323e4cf086ecee3faadba52ff71633d471f9685c42e3736163/multidict-6.7.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9f9af11306994335398293f9958071019e3ab95e9a707dc1383a35613f6abcb9", size = 242842, upload-time = "2026-01-26T02:46:02.824Z" }, + { url = "https://files.pythonhosted.org/packages/41/5f/604ae839e64a4a6efc80db94465348d3b328ee955e37acb24badbcd24d83/multidict-6.7.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b4938326284c4f1224178a560987b6cf8b4d38458b113d9b8c1db1a836e640a2", size = 240237, upload-time = "2026-01-26T02:46:05.898Z" }, + { url = "https://files.pythonhosted.org/packages/5f/60/c3a5187bf66f6fb546ff4ab8fb5a077cbdd832d7b1908d4365c7f74a1917/multidict-6.7.1-cp314-cp314t-win32.whl", hash = "sha256:98655c737850c064a65e006a3df7c997cd3b220be4ec8fe26215760b9697d4d7", size = 48008, upload-time = "2026-01-26T02:46:07.468Z" }, + { url = "https://files.pythonhosted.org/packages/0c/f7/addf1087b860ac60e6f382240f64fb99f8bfb532bb06f7c542b83c29ca61/multidict-6.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:497bde6223c212ba11d462853cfa4f0ae6ef97465033e7dc9940cdb3ab5b48e5", size = 53542, upload-time = "2026-01-26T02:46:08.809Z" }, + { url = "https://files.pythonhosted.org/packages/4c/81/4629d0aa32302ef7b2ec65c75a728cc5ff4fa410c50096174c1632e70b3e/multidict-6.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:2bbd113e0d4af5db41d5ebfe9ccaff89de2120578164f86a5d17d5a576d1e5b2", size = 44719, upload-time = "2026-01-26T02:46:11.146Z" }, + { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload-time = "2026-01-26T02:46:44.004Z" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, +] + +[[package]] +name = "nodeenv" +version = "1.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, +] + +[[package]] +name = "oauthlib" +version = "3.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/5f/19930f824ffeb0ad4372da4812c50edbd1434f678c90c2733e1188edfc63/oauthlib-3.3.1.tar.gz", hash = "sha256:0f0f8aa759826a193cf66c12ea1af1637f87b9b4622d46e866952bb022e538c9", size = 185918, upload-time = "2025-06-19T22:48:08.269Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/9c/92789c596b8df838baa98fa71844d84283302f7604ed565dafe5a6b5041a/oauthlib-3.3.1-py3-none-any.whl", hash = "sha256:88119c938d2b8fb88561af5f6ee0eec8cc8d552b7bb1f712743136eb7523b7a1", size = 160065, upload-time = "2025-06-19T22:48:06.508Z" }, +] + +[[package]] +name = "packaging" +version = "26.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, +] + +[[package]] +name = "pathspec" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" }, +] + +[[package]] +name = "pillow" +version = "12.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/21/c2bcdd5906101a30244eaffc1b6e6ce71a31bd0742a01eb89e660ebfac2d/pillow-12.2.0.tar.gz", hash = "sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5", size = 46987819, upload-time = "2026-04-01T14:46:17.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/98/4595daa2365416a86cb0d495248a393dfc84e96d62ad080c8546256cb9c0/pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:3adc9215e8be0448ed6e814966ecf3d9952f0ea40eb14e89a102b87f450660d8", size = 4100848, upload-time = "2026-04-01T14:44:48.48Z" }, + { url = "https://files.pythonhosted.org/packages/0b/79/40184d464cf89f6663e18dfcf7ca21aae2491fff1a16127681bf1fa9b8cf/pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:6a9adfc6d24b10f89588096364cc726174118c62130c817c2837c60cf08a392b", size = 4176515, upload-time = "2026-04-01T14:44:51.353Z" }, + { url = "https://files.pythonhosted.org/packages/b0/63/703f86fd4c422a9cf722833670f4f71418fb116b2853ff7da722ea43f184/pillow-12.2.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:6a6e67ea2e6feda684ed370f9a1c52e7a243631c025ba42149a2cc5934dec295", size = 3640159, upload-time = "2026-04-01T14:44:53.588Z" }, + { url = "https://files.pythonhosted.org/packages/71/e0/fb22f797187d0be2270f83500aab851536101b254bfa1eae10795709d283/pillow-12.2.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2bb4a8d594eacdfc59d9e5ad972aa8afdd48d584ffd5f13a937a664c3e7db0ed", size = 5312185, upload-time = "2026-04-01T14:44:56.039Z" }, + { url = "https://files.pythonhosted.org/packages/ba/8c/1a9e46228571de18f8e28f16fabdfc20212a5d019f3e3303452b3f0a580d/pillow-12.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:80b2da48193b2f33ed0c32c38140f9d3186583ce7d516526d462645fd98660ae", size = 4695386, upload-time = "2026-04-01T14:44:58.663Z" }, + { url = "https://files.pythonhosted.org/packages/70/62/98f6b7f0c88b9addd0e87c217ded307b36be024d4ff8869a812b241d1345/pillow-12.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22db17c68434de69d8ecfc2fe821569195c0c373b25cccb9cbdacf2c6e53c601", size = 6280384, upload-time = "2026-04-01T14:45:01.5Z" }, + { url = "https://files.pythonhosted.org/packages/5e/03/688747d2e91cfbe0e64f316cd2e8005698f76ada3130d0194664174fa5de/pillow-12.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7b14cc0106cd9aecda615dd6903840a058b4700fcb817687d0ee4fc8b6e389be", size = 8091599, upload-time = "2026-04-01T14:45:04.5Z" }, + { url = "https://files.pythonhosted.org/packages/f6/35/577e22b936fcdd66537329b33af0b4ccfefaeabd8aec04b266528cddb33c/pillow-12.2.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cbeb542b2ebc6fcdacabf8aca8c1a97c9b3ad3927d46b8723f9d4f033288a0f", size = 6396021, upload-time = "2026-04-01T14:45:07.117Z" }, + { url = "https://files.pythonhosted.org/packages/11/8d/d2532ad2a603ca2b93ad9f5135732124e57811d0168155852f37fbce2458/pillow-12.2.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4bfd07bc812fbd20395212969e41931001fd59eb55a60658b0e5710872e95286", size = 7083360, upload-time = "2026-04-01T14:45:09.763Z" }, + { url = "https://files.pythonhosted.org/packages/5e/26/d325f9f56c7e039034897e7380e9cc202b1e368bfd04d4cbe6a441f02885/pillow-12.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9aba9a17b623ef750a4d11b742cbafffeb48a869821252b30ee21b5e91392c50", size = 6507628, upload-time = "2026-04-01T14:45:12.378Z" }, + { url = "https://files.pythonhosted.org/packages/5f/f7/769d5632ffb0988f1c5e7660b3e731e30f7f8ec4318e94d0a5d674eb65a4/pillow-12.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:deede7c263feb25dba4e82ea23058a235dcc2fe1f6021025dc71f2b618e26104", size = 7209321, upload-time = "2026-04-01T14:45:15.122Z" }, + { url = "https://files.pythonhosted.org/packages/6a/7a/c253e3c645cd47f1aceea6a8bacdba9991bf45bb7dfe927f7c893e89c93c/pillow-12.2.0-cp314-cp314-win32.whl", hash = "sha256:632ff19b2778e43162304d50da0181ce24ac5bb8180122cbe1bf4673428328c7", size = 6479723, upload-time = "2026-04-01T14:45:17.797Z" }, + { url = "https://files.pythonhosted.org/packages/cd/8b/601e6566b957ca50e28725cb6c355c59c2c8609751efbecd980db44e0349/pillow-12.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:4e6c62e9d237e9b65fac06857d511e90d8461a32adcc1b9065ea0c0fa3a28150", size = 7217400, upload-time = "2026-04-01T14:45:20.529Z" }, + { url = "https://files.pythonhosted.org/packages/d6/94/220e46c73065c3e2951bb91c11a1fb636c8c9ad427ac3ce7d7f3359b9b2f/pillow-12.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:b1c1fbd8a5a1af3412a0810d060a78b5136ec0836c8a4ef9aa11807f2a22f4e1", size = 2554835, upload-time = "2026-04-01T14:45:23.162Z" }, + { url = "https://files.pythonhosted.org/packages/b6/ab/1b426a3974cb0e7da5c29ccff4807871d48110933a57207b5a676cccc155/pillow-12.2.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:57850958fe9c751670e49b2cecf6294acc99e562531f4bd317fa5ddee2068463", size = 5314225, upload-time = "2026-04-01T14:45:25.637Z" }, + { url = "https://files.pythonhosted.org/packages/19/1e/dce46f371be2438eecfee2a1960ee2a243bbe5e961890146d2dee1ff0f12/pillow-12.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d5d38f1411c0ed9f97bcb49b7bd59b6b7c314e0e27420e34d99d844b9ce3b6f3", size = 4698541, upload-time = "2026-04-01T14:45:28.355Z" }, + { url = "https://files.pythonhosted.org/packages/55/c3/7fbecf70adb3a0c33b77a300dc52e424dc22ad8cdc06557a2e49523b703d/pillow-12.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5c0a9f29ca8e79f09de89293f82fc9b0270bb4af1d58bc98f540cc4aedf03166", size = 6322251, upload-time = "2026-04-01T14:45:30.924Z" }, + { url = "https://files.pythonhosted.org/packages/1c/3c/7fbc17cfb7e4fe0ef1642e0abc17fc6c94c9f7a16be41498e12e2ba60408/pillow-12.2.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1610dd6c61621ae1cf811bef44d77e149ce3f7b95afe66a4512f8c59f25d9ebe", size = 8127807, upload-time = "2026-04-01T14:45:33.908Z" }, + { url = "https://files.pythonhosted.org/packages/ff/c3/a8ae14d6defd2e448493ff512fae903b1e9bd40b72efb6ec55ce0048c8ce/pillow-12.2.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a34329707af4f73cf1782a36cd2289c0368880654a2c11f027bcee9052d35dd", size = 6433935, upload-time = "2026-04-01T14:45:36.623Z" }, + { url = "https://files.pythonhosted.org/packages/6e/32/2880fb3a074847ac159d8f902cb43278a61e85f681661e7419e6596803ed/pillow-12.2.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e9c4f5b3c546fa3458a29ab22646c1c6c787ea8f5ef51300e5a60300736905e", size = 7116720, upload-time = "2026-04-01T14:45:39.258Z" }, + { url = "https://files.pythonhosted.org/packages/46/87/495cc9c30e0129501643f24d320076f4cc54f718341df18cc70ec94c44e1/pillow-12.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fb043ee2f06b41473269765c2feae53fc2e2fbf96e5e22ca94fb5ad677856f06", size = 6540498, upload-time = "2026-04-01T14:45:41.879Z" }, + { url = "https://files.pythonhosted.org/packages/18/53/773f5edca692009d883a72211b60fdaf8871cbef075eaa9d577f0a2f989e/pillow-12.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f278f034eb75b4e8a13a54a876cc4a5ab39173d2cdd93a638e1b467fc545ac43", size = 7239413, upload-time = "2026-04-01T14:45:44.705Z" }, + { url = "https://files.pythonhosted.org/packages/c9/e4/4b64a97d71b2a83158134abbb2f5bd3f8a2ea691361282f010998f339ec7/pillow-12.2.0-cp314-cp314t-win32.whl", hash = "sha256:6bb77b2dcb06b20f9f4b4a8454caa581cd4dd0643a08bacf821216a16d9c8354", size = 6482084, upload-time = "2026-04-01T14:45:47.568Z" }, + { url = "https://files.pythonhosted.org/packages/ba/13/306d275efd3a3453f72114b7431c877d10b1154014c1ebbedd067770d629/pillow-12.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6562ace0d3fb5f20ed7290f1f929cae41b25ae29528f2af1722966a0a02e2aa1", size = 7225152, upload-time = "2026-04-01T14:45:50.032Z" }, + { url = "https://files.pythonhosted.org/packages/ff/6e/cf826fae916b8658848d7b9f38d88da6396895c676e8086fc0988073aaf8/pillow-12.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:aa88ccfe4e32d362816319ed727a004423aab09c5cea43c01a4b435643fa34eb", size = 2556579, upload-time = "2026-04-01T14:45:52.529Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.9.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9f/4a/0883b8e3802965322523f0b200ecf33d31f10991d0401162f4b23c698b42/platformdirs-4.9.6.tar.gz", hash = "sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a", size = 29400, upload-time = "2026-04-09T00:04:10.812Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/75/a6/a0a304dc33b49145b21f4808d763822111e67d1c3a32b524a1baf947b6e1/platformdirs-4.9.6-py3-none-any.whl", hash = "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917", size = 21348, upload-time = "2026-04-09T00:04:09.463Z" }, +] + +[[package]] +name = "pre-commit" +version = "4.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cfgv" }, + { name = "identify" }, + { name = "nodeenv" }, + { name = "pyyaml" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8e/22/2de9408ac81acbb8a7d05d4cc064a152ccf33b3d480ebe0cd292153db239/pre_commit-4.6.0.tar.gz", hash = "sha256:718d2208cef53fdc38206e40524a6d4d9576d103eb16f0fec11c875e7716e9d9", size = 198525, upload-time = "2026-04-21T20:31:41.613Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/80/6e/4b28b62ecb6aae56769c34a8ff1d661473ec1e9519e2d5f8b2c150086b26/pre_commit-4.6.0-py2.py3-none-any.whl", hash = "sha256:e2cf246f7299edcabcf15f9b0571fdce06058527f0a06535068a86d38089f29b", size = 226472, upload-time = "2026-04-21T20:31:40.092Z" }, +] + +[[package]] +name = "prometheus-client" +version = "0.25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/fb/d9aa83ffe43ce1f19e557c0971d04b90561b0cfd50762aafb01968285553/prometheus_client-0.25.0.tar.gz", hash = "sha256:5e373b75c31afb3c86f1a52fa1ad470c9aace18082d39ec0d2f918d11cc9ba28", size = 86035, upload-time = "2026-04-09T19:53:42.359Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8d/9b/d4b1e644385499c8346fa9b622a3f030dce14cd6ef8a1871c221a17a67e7/prometheus_client-0.25.0-py3-none-any.whl", hash = "sha256:d5aec89e349a6ec230805d0df882f3807f74fd6c1a2fa86864e3c2279059fed1", size = 64154, upload-time = "2026-04-09T19:53:41.324Z" }, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.52" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, +] + +[[package]] +name = "propcache" +version = "0.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/44/c87281c333769159c50594f22610f77398a47ccbfbbf23074e744e86f87c/propcache-0.5.2.tar.gz", hash = "sha256:01c4fc7480cd0598bb4b57022df55b9ca296da7fc5a8760bd8451a7e63a7d427", size = 50208, upload-time = "2026-05-08T21:02:12.199Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e2/ea/23ee535d90ce8bcc465a3028eb3cc0ce3bd1005f4bb27710b30587de798d/propcache-0.5.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:46088abff4cba581dea21ae0467a480526cb25aa5f3c269e909f800328bc3999", size = 94662, upload-time = "2026-05-08T21:01:22.683Z" }, + { url = "https://files.pythonhosted.org/packages/b5/06/c5a52f419b5d8972f8d46a7577476090d8e3263ff589ce40b5ca4968d5be/propcache-0.5.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fc88b26f08d634f7bc819a7852e5214f5802641ab8d9fd5326892292eee1993e", size = 53928, upload-time = "2026-05-08T21:01:23.986Z" }, + { url = "https://files.pythonhosted.org/packages/63/b1/4260d67d6bd85e58a66b72d54ce15d5de789b6f3870cc6bedf8ff9667401/propcache-0.5.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:97797ebb098e670a2f92dd66f32897e30d7615b14e7f59711de23e30a9072539", size = 54650, upload-time = "2026-05-08T21:01:25.305Z" }, + { url = "https://files.pythonhosted.org/packages/70/06/2f46c318e3307cd7a6a7481def374ce838c0fe20084b39dd54b0879d0e99/propcache-0.5.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba57fffe4ac99c5d30076161b5866336d97600769bad35cc68f7774b15298a4e", size = 59912, upload-time = "2026-05-08T21:01:26.545Z" }, + { url = "https://files.pythonhosted.org/packages/4c/29/fe1aebec2ce57ab985a9c382bded1124431f85078113aa222c5d278430d4/propcache-0.5.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:583c19759d9eec1e5b69e2fbef36a7d9c326041be9746cb822d335c8cedc2979", size = 63300, upload-time = "2026-05-08T21:01:27.937Z" }, + { url = "https://files.pythonhosted.org/packages/b4/18/2334b26768b6c82be8c69e83671b767d5ef426aa09b0cba6c2ea47816774/propcache-0.5.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d0326e2e5e1f3163fa306c834e48e8d490e5fae607a097a40c0648109b47ba80", size = 64208, upload-time = "2026-05-08T21:01:29.484Z" }, + { url = "https://files.pythonhosted.org/packages/2b/76/7f1bfd6afff4c5e38e36a3c6d68eb5f4b7311ea80baf693db78d95b603c4/propcache-0.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e00820e192c8dbebcafb383ebbf99030895f09905e7a0eb2e0340a0bcc2bc825", size = 61633, upload-time = "2026-05-08T21:01:31.068Z" }, + { url = "https://files.pythonhosted.org/packages/c4/46/b3ff8aba2b4953a3e50de2cf72f1b5748b8eca93b15f3dc2c84339084c09/propcache-0.5.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c66afea89b1e43725731d2004732a046fe6fe955d51f952c3e95a7314a284a39", size = 61724, upload-time = "2026-05-08T21:01:32.374Z" }, + { url = "https://files.pythonhosted.org/packages/c5/01/814cfcafbcff954f94c01cf30e097ddc88a076b5440fbcf4570753437d40/propcache-0.5.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d4dc37dec6c6cdad0b57881a5658fd14fbf53e333b1a86cf86559f190e1d9ec4", size = 60069, upload-time = "2026-05-08T21:01:33.67Z" }, + { url = "https://files.pythonhosted.org/packages/da/68/5c6f7622d510cc666a300687e06fd060c1a43361c0c9b20d284f06d8096a/propcache-0.5.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:5570dbcc97571c15f68068e529c92715a12f8d54030e272d264b377e22bd17a5", size = 57099, upload-time = "2026-05-08T21:01:34.915Z" }, + { url = "https://files.pythonhosted.org/packages/55/27/9cb0b4c679124085327957d42521c99dba04c88c90c3e55a6f0b633ebccc/propcache-0.5.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f814362777a9f841adddb200ecdf8f5cb1e5a3c4b7a86378edbd6ccb26edd702", size = 63391, upload-time = "2026-05-08T21:01:36.231Z" }, + { url = "https://files.pythonhosted.org/packages/f0/9d/7258aaa5bdf60fc6f27591eef6fe52768cb0beda7140be477c8b12c9794a/propcache-0.5.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:196913dea116aeb5a2ba95af4ddcb7ea85559ae07d8eee8751688310d09168c3", size = 61626, upload-time = "2026-05-08T21:01:37.545Z" }, + { url = "https://files.pythonhosted.org/packages/8e/0d/41c602003e8a9b16fe1e7eadf62c7bfba9d5474370b24200bf48b315f45f/propcache-0.5.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:6e7b8719005dd1175be4ab1cd25e9b98659a5e0347331506ec6760d2773a7fb5", size = 64781, upload-time = "2026-05-08T21:01:38.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f3/38e66b1856e9bd079deea015bc4a55f7767c0e4db2f7dcf69e7e680ba4ce/propcache-0.5.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:51f96d685ab16e88cab128cd37a52c5da540809c8b879fa047731bfcb4ad35a4", size = 62570, upload-time = "2026-05-08T21:01:40.415Z" }, + { url = "https://files.pythonhosted.org/packages/95/ca/bbfe9b910ce57dde8bb4876b4520fc02a4e89497c10de26be936758a3aaa/propcache-0.5.2-cp314-cp314-win32.whl", hash = "sha256:cc6fc3cc62e8501d3ed62894425040d2728ecddb1ed072737a5c70bd537aa9f0", size = 39436, upload-time = "2026-05-08T21:01:41.654Z" }, + { url = "https://files.pythonhosted.org/packages/61/d2/45c9defbaa1ea297035d9d4cce9e8f80daafbf19319c6007f157c6256ea9/propcache-0.5.2-cp314-cp314-win_amd64.whl", hash = "sha256:81e3a30b0bb60caa22033dd0f8a3618d1d67356212514f62c57db75cb0ef410c", size = 42373, upload-time = "2026-05-08T21:01:43.041Z" }, + { url = "https://files.pythonhosted.org/packages/44/68/9ea5103f41d5217d7d6ec24db90018e23aebec070c3f9a6e54d12b841fd8/propcache-0.5.2-cp314-cp314-win_arm64.whl", hash = "sha256:0d2c9bf8528f135dbb805ce027567e09164f7efa51a2be07458a2c0420f292d0", size = 38554, upload-time = "2026-05-08T21:01:44.336Z" }, + { url = "https://files.pythonhosted.org/packages/8a/81/fadf555f42d3b762eea8a53950b0489fdc0aa9da5f8ed9e10ce0a4e01b48/propcache-0.5.2-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:4bc8ff1feffc6a61c7002ffe84634c41b822e104990ae009f44a0834430070bb", size = 99395, upload-time = "2026-05-08T21:01:45.883Z" }, + { url = "https://files.pythonhosted.org/packages/f5/c9/c61e134a686949cf7971af3a390148b1156f7be81c73bc0cd12c873e2d48/propcache-0.5.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:79aa3ff0a9b566633b642fa9caf7e21ed1c13d6feca718187873f199e1514078", size = 56653, upload-time = "2026-05-08T21:01:47.307Z" }, + { url = "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1b31822f4474c4036bae62de9402710051d431a606d6a0f907fec79935a071aa", size = 56914, upload-time = "2026-05-08T21:01:48.573Z" }, + { url = "https://files.pythonhosted.org/packages/79/9f/aba959b435ea18617edd7cf0a7ad0b9c574b8fc7e3d2cd55fb59cb255d33/propcache-0.5.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13fef48778b5a2a756523fdb781326b028ca75e32858b04f2cdd19f394564917", size = 62567, upload-time = "2026-05-08T21:01:49.903Z" }, + { url = "https://files.pythonhosted.org/packages/6c/a1/859942de9a791ff42f6141736f5b37749b8f53e65edfa49638c67dd67e6a/propcache-0.5.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8b73ab70f1a3351fbc71f663b3e645af6dd0329100c353081cf69c37433fc6fe", size = 65542, upload-time = "2026-05-08T21:01:51.204Z" }, + { url = "https://files.pythonhosted.org/packages/b5/61/315bc0fd6c0fc7f80a528b8afd209e5fc4a875ea79571b91b8f50f442907/propcache-0.5.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5538d2c13d93e4698af7e092b57bc7298fd35d1d58e656ae18f23ee0d0378e03", size = 66845, upload-time = "2026-05-08T21:01:52.539Z" }, + { url = "https://files.pythonhosted.org/packages/47/f7/9f8122e3132e8e354ac41975ef8f1099be7d5a16bc7ae562734e993665c0/propcache-0.5.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd645f03898405cabe694fb8bc35241e3a9c332ec85627584fe3de201452b335", size = 63985, upload-time = "2026-05-08T21:01:53.847Z" }, + { url = "https://files.pythonhosted.org/packages/c8/54/c317819ec157cbf6f35df9df9657a6f82daf34d5faf15948b2f639c2192e/propcache-0.5.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a473b3440261e0c60706e732b2ed2f517857344fc21bf48fdfe211e2d98eb285", size = 63999, upload-time = "2026-05-08T21:01:55.179Z" }, + { url = "https://files.pythonhosted.org/packages/5a/56/387e3f7dfce0a9233df41fb888aa1c30222cb4bbbf09537c02dd9bd85fe2/propcache-0.5.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7afa37062e6650640e932e4cc9297d81f9f42d9944029cc386b8247dea4da837", size = 62779, upload-time = "2026-05-08T21:01:57.489Z" }, + { url = "https://files.pythonhosted.org/packages/a1/9c/596784cb5824ed61ee960d3f8655a3f0993e107c6e98ab6c818b7fb92ccb/propcache-0.5.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:8a90efd5777e996e42d568db9ac740b944d691e565cbfd31b2f7832f9184b2b8", size = 59796, upload-time = "2026-05-08T21:01:58.736Z" }, + { url = "https://files.pythonhosted.org/packages/c2/3d/1a6cfa1726a48542c1e8784a0761421476a5b68e09b7f36bf95eb954aaba/propcache-0.5.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:f19bb891234d72535764d703bfed1153cc34f4214d5bd7150aee1eec9e8f4366", size = 66023, upload-time = "2026-05-08T21:02:00.228Z" }, + { url = "https://files.pythonhosted.org/packages/e4/0e/05fd6990369477076e4e280bcb970de760fddf0161a46e988bc95f7940ec/propcache-0.5.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:32775082acd2d807ee3db715c7770d38767b817870acfa08c29e057f3c4d5b56", size = 64448, upload-time = "2026-05-08T21:02:01.888Z" }, + { url = "https://files.pythonhosted.org/packages/cd/86/5f8da315a4309c62c10c0b2516b17492d5d3bbe1bb862b96604db67e2a37/propcache-0.5.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9282fb1a3bccd038da9f768b927b24a0c753e466c086b7c4f3c6982851eefb2d", size = 67329, upload-time = "2026-05-08T21:02:03.484Z" }, + { url = "https://files.pythonhosted.org/packages/da/d3/3368efe79ab21f0cdf86ef49895811c9cc933131d4cde1f28a624e22e712/propcache-0.5.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cc49723e2f60d6b32a0f0b08a3fd6d13203c07f1cd9566cfce0f12a917c967a2", size = 65172, upload-time = "2026-05-08T21:02:04.745Z" }, + { url = "https://files.pythonhosted.org/packages/d5/07/127e8b0bacfb325396196f9d976a22453049b89b9b2b08477cc3145faa44/propcache-0.5.2-cp314-cp314t-win32.whl", hash = "sha256:2d7aa89ebca5acc98cba9d1472d976e394782f587bad6661003602a619fd1821", size = 43813, upload-time = "2026-05-08T21:02:06.025Z" }, + { url = "https://files.pythonhosted.org/packages/88/fb/46dad6c0ae49ed230ab1b16c890c2b6314e2403e6c412976f4a72d64a527/propcache-0.5.2-cp314-cp314t-win_amd64.whl", hash = "sha256:d447bb0b3054be5818458fbb171208b1d9ff11eba14e18ca18b90cbb45767370", size = 47764, upload-time = "2026-05-08T21:02:07.353Z" }, + { url = "https://files.pythonhosted.org/packages/e7/c4/a47d0a63aa309d10d59ede6e9d4cff03a344a79d1f0f4cd0cd74997b53e0/propcache-0.5.2-cp314-cp314t-win_arm64.whl", hash = "sha256:fe67a3d11cd9b4efabfa45c3d00ffba2b26811442a73a581a94b67c2b5faccf6", size = 41140, upload-time = "2026-05-08T21:02:09.065Z" }, + { url = "https://files.pythonhosted.org/packages/3a/ed/1cdcab6ba3d6ab7feca11fc14f0eeea80755bb53ef4e892079f31b10a25f/propcache-0.5.2-py3-none-any.whl", hash = "sha256:be1ddfcbb376e3de5d2e2db1d58d6d67463e6b4f9f040c000de8e300295465fe", size = 14036, upload-time = "2026-05-08T21:02:10.673Z" }, +] + +[[package]] +name = "psycopg" +version = "3.3.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/db/2f/cb91e5502ec9de1de6f1b76cfbf69531932725361168bb06963620c77e2e/psycopg-3.3.4.tar.gz", hash = "sha256:e21207764952cff81b6b8bdacad9a3939f2793367fdac2987b3aac36a651b5bc", size = 165799, upload-time = "2026-05-01T23:31:55.179Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/e0/7b3dee031daae7743609ce3c746565d4a3ed7c2c186479eb48e34e838c64/psycopg-3.3.4-py3-none-any.whl", hash = "sha256:b6bbc25ccf05c8fad3b061d9db2ef0909a555171b84b07f29458a447253d679a", size = 213001, upload-time = "2026-05-01T23:20:50.816Z" }, +] + +[package.optional-dependencies] +binary = [ + { name = "psycopg-binary", marker = "implementation_name != 'pypy'" }, +] + +[[package]] +name = "psycopg-binary" +version = "3.3.4" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/a6/828c9185701dab71b234c2a76c38a08b098ebfec5020716b4e93807492b5/psycopg_binary-3.3.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:28b7398fdd19db3232c884fb24550bdfe951221f510e195e233299e4c9b78f97", size = 4607292, upload-time = "2026-05-01T23:30:38.962Z" }, + { url = "https://files.pythonhosted.org/packages/92/58/5b40dbc9d839045c9dae956960e4fb6d20bcabe6c59a2aa34fc3a371913f/psycopg_binary-3.3.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1fbaa292a3c8bb61b45df1ad3da1908ccee7cb889db9425e3557d9e34e2a4829", size = 4687023, upload-time = "2026-05-01T23:30:47.227Z" }, + { url = "https://files.pythonhosted.org/packages/85/a9/793f0ac107a9003b48441d0d1f9f616d96e0f37458dd8dc12528ceff55fb/psycopg_binary-3.3.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:94596f9e7633ee3f6440711d43bb70aa31cc0a46a900ab8b4201a366ace5c9e7", size = 5486985, upload-time = "2026-05-01T23:30:55.517Z" }, + { url = "https://files.pythonhosted.org/packages/8f/26/42e8533497e2592334f68ec529cf5f840f7fa4e99575a4bb61aa184dbfbf/psycopg_binary-3.3.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8c0056529e68dbe9184cd4019a1f3d8f3a4ead2f6fc7a5afcf27d3314edd1277", size = 5168745, upload-time = "2026-05-01T23:31:01.904Z" }, + { url = "https://files.pythonhosted.org/packages/15/af/b7151776cc08d5935d45c833ec818a9beb417cf7c08239af1aafbdae78ee/psycopg_binary-3.3.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c09aad7051326e7603c14e50636db9c01f78272dc54b3accff03d46370461e6", size = 6761486, upload-time = "2026-05-01T23:31:14.511Z" }, + { url = "https://files.pythonhosted.org/packages/d0/ed/c92533b9124712d592cbf1cd6c76da933a2e0acea81dfe1fbe7e735f0cff/psycopg_binary-3.3.4-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:514404ed543efd620c85602b747df2a23cf1241b4067199e1a66f2d2757aaa41", size = 4997427, upload-time = "2026-05-01T23:31:20.901Z" }, + { url = "https://files.pythonhosted.org/packages/a2/23/ccadfd0de416aa188356daa199453af24087b042e296088706d190ae0295/psycopg_binary-3.3.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:46893c26858be12cc49ca4226ed6a60b4bfccadd946b3bebb783a60b38788228", size = 4533549, upload-time = "2026-05-01T23:31:26.204Z" }, + { url = "https://files.pythonhosted.org/packages/fd/a0/c8f43cee36386f7bc891ab41a9d31ea07cf9826038e732da79f26b1e5f34/psycopg_binary-3.3.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:df1d567fc430f6df15c9fcf67d87685fc49bdb325adc0db5af1adfb2f44eb5c9", size = 4210256, upload-time = "2026-05-01T23:31:33.884Z" }, + { url = "https://files.pythonhosted.org/packages/4e/2c/c1547871be3790676e8868b38655496422f94f0978dfb66b74bdba2f1676/psycopg_binary-3.3.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:6b9016b1714da4dd5ecaaa75b82098aa5a0b87854ce9b092e21c27c4ae23e014", size = 3946204, upload-time = "2026-05-01T23:31:39.626Z" }, + { url = "https://files.pythonhosted.org/packages/c4/b1/f6670f00fa7ea601584623f6c11602ab92117d83eaff885e0210f6de7418/psycopg_binary-3.3.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:47c656a8a7ba6eb0cff1801a4caaa9c8bdc12d03080e273aff1c8ac39971a77e", size = 4255811, upload-time = "2026-05-01T23:31:44.986Z" }, + { url = "https://files.pythonhosted.org/packages/eb/e6/5fff07a70d1f945ed90ae131c3bd76cab32beff7c58c6db15ad5820b6d1f/psycopg_binary-3.3.4-cp314-cp314-win_amd64.whl", hash = "sha256:c37e024c07308cd06cf3ec51bfd0e7f6157585a4d84d1bce4a7f5f7913719bf8", size = 3666849, upload-time = "2026-05-01T23:31:51.165Z" }, +] + +[[package]] +name = "pycouchdb" +version = "1.16.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "chardet" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c1/b4/4f699a686a2ce14ab31cb17902693f2cf201ba51c3a6fb7aba210725c154/pycouchdb-1.16.0.tar.gz", hash = "sha256:309d71c3ce3f98bbee5731db00f514753438b81e6e7adefbb8c134312200a4f9", size = 11351, upload-time = "2024-05-29T10:00:11.726Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/63/b4397a7215c089c7951afb258069cc58a06788224f1bb6a0d4f976f2d476/pycouchdb-1.16.0-py3-none-any.whl", hash = "sha256:e26ce58f626fcabbe2f5b15b3ad2b89cdd3f6d666da673632037476d1191ab67", size = 12560, upload-time = "2024-05-29T10:00:09.31Z" }, +] + +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, +] + +[[package]] +name = "pygments" +version = "2.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, +] + +[[package]] +name = "pyjwt" +version = "2.13.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3b/81/58d0ac84e1ef3a3843791d6954d94c0b33d526c75eeb1efbce9d0a4c4077/pyjwt-2.13.0.tar.gz", hash = "sha256:41571c89ca91598c79e8ef18a2d07367d4810fbbd6f637794879baf1b7703423", size = 107515, upload-time = "2026-05-21T19:54:36.618Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl", hash = "sha256:66adcc2aff09b3f1bbd95fc1e1577df8ac8723c978552fd43304c8a290ac5728", size = 31274, upload-time = "2026-05-21T19:54:35.362Z" }, +] + +[[package]] +name = "pyparsing" +version = "3.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "python-decouple" +version = "3.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/97/373dcd5844ec0ea5893e13c39a2c67e7537987ad8de3842fe078db4582fa/python-decouple-3.8.tar.gz", hash = "sha256:ba6e2657d4f376ecc46f77a3a615e058d93ba5e465c01bbe57289bfb7cce680f", size = 9612, upload-time = "2023-03-01T19:38:38.143Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/d4/9193206c4563ec771faf2ccf54815ca7918529fe81f6adb22ee6d0e06622/python_decouple-3.8-py3-none-any.whl", hash = "sha256:d0d45340815b25f4de59c974b855bb38d03151d81b037d9e3f463b0c9f8cbd66", size = 9947, upload-time = "2023-03-01T19:38:36.015Z" }, +] + +[[package]] +name = "python-discovery" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/48/60/e88788207d81e46362cfbef0d4aaf4c0f49efc3c12d4c3fa3f542c34ebec/python_discovery-1.3.1.tar.gz", hash = "sha256:62f6db28064c9613e7ca76cb3f00c38c839a07c31c00dfe7ed0986493d2150a6", size = 68011, upload-time = "2026-05-12T20:53:36.336Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/6f/a05a317a66fee0aad270011461f1a63a453ed12471249f172f7d2e2bc7b4/python_discovery-1.3.1-py3-none-any.whl", hash = "sha256:ed188687ebb3b82c01a17cd5ac62fc94d9f6487a7f1a0f9dfe89753fec91039c", size = 33185, upload-time = "2026-05-12T20:53:34.969Z" }, +] + +[[package]] +name = "python3-openid" +version = "3.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "defusedxml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5f/4a/29feb8da6c44f77007dcd29518fea73a3d5653ee02a587ae1f17f1f5ddb5/python3-openid-3.2.0.tar.gz", hash = "sha256:33fbf6928f401e0b790151ed2b5290b02545e8775f982485205a066f874aaeaf", size = 305600, upload-time = "2020-06-29T12:15:49.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/a5/c6ba13860bdf5525f1ab01e01cc667578d6f1efc8a1dba355700fb04c29b/python3_openid-3.2.0-py3-none-any.whl", hash = "sha256:6626f771e0417486701e0b4daff762e7212e820ca5b29fcc0d05f6f8736dfa6b", size = 133681, upload-time = "2020-06-29T12:15:47.502Z" }, +] + +[[package]] +name = "pytokens" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b6/34/b4e015b99031667a7b960f888889c5bd34ef585c85e1cb56a594b92836ac/pytokens-0.4.1.tar.gz", hash = "sha256:292052fe80923aae2260c073f822ceba21f3872ced9a68bb7953b348e561179a", size = 23015, upload-time = "2026-01-30T01:03:45.924Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/a7/b470f672e6fc5fee0a01d9e75005a0e617e162381974213a945fcd274843/pytokens-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4a14d5f5fc78ce85e426aa159489e2d5961acf0e47575e08f35584009178e321", size = 160821, upload-time = "2026-01-30T01:03:19.684Z" }, + { url = "https://files.pythonhosted.org/packages/80/98/e83a36fe8d170c911f864bfded690d2542bfcfacb9c649d11a9e6eb9dc41/pytokens-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f50fd18543be72da51dd505e2ed20d2228c74e0464e4262e4899797803d7fa", size = 254263, upload-time = "2026-01-30T01:03:20.834Z" }, + { url = "https://files.pythonhosted.org/packages/0f/95/70d7041273890f9f97a24234c00b746e8da86df462620194cef1d411ddeb/pytokens-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dc74c035f9bfca0255c1af77ddd2d6ae8419012805453e4b0e7513e17904545d", size = 268071, upload-time = "2026-01-30T01:03:21.888Z" }, + { url = "https://files.pythonhosted.org/packages/da/79/76e6d09ae19c99404656d7db9c35dfd20f2086f3eb6ecb496b5b31163bad/pytokens-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f66a6bbe741bd431f6d741e617e0f39ec7257ca1f89089593479347cc4d13324", size = 271716, upload-time = "2026-01-30T01:03:23.633Z" }, + { url = "https://files.pythonhosted.org/packages/79/37/482e55fa1602e0a7ff012661d8c946bafdc05e480ea5a32f4f7e336d4aa9/pytokens-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:b35d7e5ad269804f6697727702da3c517bb8a5228afa450ab0fa787732055fc9", size = 104539, upload-time = "2026-01-30T01:03:24.788Z" }, + { url = "https://files.pythonhosted.org/packages/30/e8/20e7db907c23f3d63b0be3b8a4fd1927f6da2395f5bcc7f72242bb963dfe/pytokens-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8fcb9ba3709ff77e77f1c7022ff11d13553f3c30299a9fe246a166903e9091eb", size = 168474, upload-time = "2026-01-30T01:03:26.428Z" }, + { url = "https://files.pythonhosted.org/packages/d6/81/88a95ee9fafdd8f5f3452107748fd04c24930d500b9aba9738f3ade642cc/pytokens-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79fc6b8699564e1f9b521582c35435f1bd32dd06822322ec44afdeba666d8cb3", size = 290473, upload-time = "2026-01-30T01:03:27.415Z" }, + { url = "https://files.pythonhosted.org/packages/cf/35/3aa899645e29b6375b4aed9f8d21df219e7c958c4c186b465e42ee0a06bf/pytokens-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d31b97b3de0f61571a124a00ffe9a81fb9939146c122c11060725bd5aea79975", size = 303485, upload-time = "2026-01-30T01:03:28.558Z" }, + { url = "https://files.pythonhosted.org/packages/52/a0/07907b6ff512674d9b201859f7d212298c44933633c946703a20c25e9d81/pytokens-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:967cf6e3fd4adf7de8fc73cd3043754ae79c36475c1c11d514fc72cf5490094a", size = 306698, upload-time = "2026-01-30T01:03:29.653Z" }, + { url = "https://files.pythonhosted.org/packages/39/2a/cbbf9250020a4a8dd53ba83a46c097b69e5eb49dd14e708f496f548c6612/pytokens-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:584c80c24b078eec1e227079d56dc22ff755e0ba8654d8383b2c549107528918", size = 116287, upload-time = "2026-01-30T01:03:30.912Z" }, + { url = "https://files.pythonhosted.org/packages/c6/78/397db326746f0a342855b81216ae1f0a32965deccfd7c830a2dbc66d2483/pytokens-0.4.1-py3-none-any.whl", hash = "sha256:26cef14744a8385f35d0e095dc8b3a7583f6c953c2e3d269c7f82484bf5ad2de", size = 13729, upload-time = "2026-01-30T01:03:45.029Z" }, +] + +[[package]] +name = "pytz" +version = "2026.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ff/46/dd499ec9038423421951e4fad73051febaa13d2df82b4064f87af8b8c0c3/pytz-2026.2.tar.gz", hash = "sha256:0e60b47b29f21574376f218fe21abc009894a2321ea16c6754f3cad6eb7cdd6a", size = 320861, upload-time = "2026-05-04T01:35:29.667Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/dd/96da98f892250475bdf2328112d7468abdd4acc7b902b6af23f4ed958ea0/pytz-2026.2-py2.py3-none-any.whl", hash = "sha256:04156e608bee23d3792fd45c94ae47fae1036688e75032eea2e3bf0323d1f126", size = 510141, upload-time = "2026-05-04T01:35:27.408Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, +] + +[[package]] +name = "rcssmin" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/81/af/c9654b4f9b054ec163ed7cb20d8db0e5ae05e2e9ce99a4c11d91a2180b3f/rcssmin-1.2.2.tar.gz", hash = "sha256:806986eaf7414545edc28a1d29523e9560e49e151ff4a337d9d1f0271d6e1cc4", size = 587012, upload-time = "2025-10-12T10:48:08.932Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/40/9c4cb3133f6d4ddfbeada76988a10ff2a974706fd6fcbb97edd8c0f4cc76/rcssmin-1.2.2-cp314-cp314-manylinux1_i686.whl", hash = "sha256:540dd3aa586b5f8f4c4b90db37e6a31c04718cdf90dbe9bec43c3b4dd50519e7", size = 49032, upload-time = "2025-10-12T10:48:53.014Z" }, + { url = "https://files.pythonhosted.org/packages/07/84/a411a48fd4179a88c68a2ad3649b408fa7887a421d3435c10ae6f5724e3a/rcssmin-1.2.2-cp314-cp314-manylinux1_x86_64.whl", hash = "sha256:6ea38a38eec263858b70bed6715478dcfed7fbc5d63333a8c512631ee22baad9", size = 49497, upload-time = "2025-10-12T10:48:54.009Z" }, + { url = "https://files.pythonhosted.org/packages/a1/32/5663a71a9304e0c9f33b765264508229d026359cfff746e1d0a593d809ea/rcssmin-1.2.2-cp314-cp314-manylinux2014_aarch64.whl", hash = "sha256:07dc7d352e8eb08de82fc4c545dd04f9f487466c8370051e0bee4eb1e4dc85d0", size = 50382, upload-time = "2025-10-12T10:48:55.079Z" }, + { url = "https://files.pythonhosted.org/packages/d7/28/e411eb191ffff7bd712f2eb0f691cb7ca514b1876d6bff2f5ae61359b8db/rcssmin-1.2.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:cdccb0e08281f0dd5d463c16ec61a06bd1534de50206dc72918be3c10dcb82e5", size = 50962, upload-time = "2025-10-12T10:48:56.494Z" }, + { url = "https://files.pythonhosted.org/packages/fb/3f/cdb99526d294c5dd4b919dc4ef492b7bd11e08b585d15ec641dfb9423493/rcssmin-1.2.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:2b6d5e2e2fd65738d57ef65aaaed2cff2288eccff7f704bf3d579e6f451cb60a", size = 52504, upload-time = "2025-10-12T10:48:57.886Z" }, + { url = "https://files.pythonhosted.org/packages/e8/60/a8183401fa64e93e1d52b2cdf275a2c11e0993f5f3162c573a67872b535d/rcssmin-1.2.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7018d4197713c7797d1a67ed47ab53d4706c2e9ed134123c30a47d389dda5386", size = 50561, upload-time = "2025-10-12T10:48:58.935Z" }, + { url = "https://files.pythonhosted.org/packages/47/5e/496d6c9c309e2fe79e6a69f25f7a6d18f545edb4ea3584f461b9f84b0d60/rcssmin-1.2.2-cp314-cp314t-manylinux1_i686.whl", hash = "sha256:0162c32ce946978edc834d4fba705ac5f9422d7f556f3264cc4fc67c7ee39171", size = 51214, upload-time = "2025-10-12T10:49:00.021Z" }, + { url = "https://files.pythonhosted.org/packages/5e/78/87da6706d5856ceee71421ba831d2f5d93c3e6865acfbb56ace8d54587cc/rcssmin-1.2.2-cp314-cp314t-manylinux1_x86_64.whl", hash = "sha256:f17dc92553a46412c49f972f0ab31088032b9482a9c421bc2d39691a5d8842aa", size = 51608, upload-time = "2025-10-12T10:49:01.422Z" }, + { url = "https://files.pythonhosted.org/packages/cd/6c/204b0262c11ac2da2b8df2d8fed76f1959273fbc8376450d0ac022d754b7/rcssmin-1.2.2-cp314-cp314t-manylinux2014_aarch64.whl", hash = "sha256:40c7dfba098bbd129d8c35dd8b604275585f9dc0496e5d17dbe7fd6b873b0233", size = 53349, upload-time = "2025-10-12T10:49:02.512Z" }, + { url = "https://files.pythonhosted.org/packages/c3/7b/9aae16756d3f33cbc512760ba3e69c3856a51aa293e463f2ca97760d1b1b/rcssmin-1.2.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d0197fab78ebbe33f5df9caf2572ef2d44bbe243a9130881a0c5c53ba03641fa", size = 53066, upload-time = "2025-10-12T10:49:03.589Z" }, + { url = "https://files.pythonhosted.org/packages/4e/18/b06fadfa9b85e486bb1571050217cb539c062d1ae4cd32b1a31c36f67fd4/rcssmin-1.2.2-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:19e53c58768369366fdaef00da59f275f724f229994ea885309df6ca368ff3c8", size = 54271, upload-time = "2025-10-12T10:49:04.735Z" }, + { url = "https://files.pythonhosted.org/packages/79/55/f29ce21f8e5a1f3c19d43b67b907268d227b7edcda2ca200ca0028734a5e/rcssmin-1.2.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8d3de1a870e00d157f3a7b1797498fdc09a3774629079572350f75783bb94b9a", size = 52423, upload-time = "2025-10-12T10:49:06.04Z" }, +] + +[[package]] +name = "redis" +version = "7.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7b/7f/3759b1d0d72b7c92f0d70ffd9dc962b7b7b5ee74e135f9d7d8ab06b8a318/redis-7.4.0.tar.gz", hash = "sha256:64a6ea7bf567ad43c964d2c30d82853f8df927c5c9017766c55a1d1ed95d18ad", size = 4943913, upload-time = "2026-03-24T09:14:37.53Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/3a/95deec7db1eb53979973ebd156f3369a72732208d1391cd2e5d127062a32/redis-7.4.0-py3-none-any.whl", hash = "sha256:a9c74a5c893a5ef8455a5adb793a31bb70feb821c86eccb62eebef5a19c429ec", size = 409772, upload-time = "2026-03-24T09:14:35.968Z" }, +] + +[[package]] +name = "requests" +version = "2.34.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" }, +] + +[[package]] +name = "requests-oauthlib" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "oauthlib" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/f2/05f29bc3913aea15eb670be136045bf5c5bbf4b99ecb839da9b422bb2c85/requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9", size = 55650, upload-time = "2024-03-22T20:32:29.939Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/5d/63d4ae3b9daea098d5d6f5da83984853c1bbacd5dc826764b249fe119d24/requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36", size = 24179, upload-time = "2024-03-22T20:32:28.055Z" }, +] + +[[package]] +name = "rjsmin" +version = "1.2.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/59/16/14288d309d0f42c6586440c47bf6ec1a880218f698f30293fa3782db4008/rjsmin-1.2.5.tar.gz", hash = "sha256:a3f8040b0273dec773e0e807e86a4d0a9535516c0a0a35aa1bb6de6e15bb1f09", size = 427399, upload-time = "2025-10-12T10:50:27.422Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b8/ed/b472d5a3fd7d63c016893f7d438e677901fea28089b5d30cd1a115bcc887/rjsmin-1.2.5-cp314-cp314-manylinux1_i686.whl", hash = "sha256:7096357ed596fdfe0acb750f8cbfca338f3c845cc12def3861e23ed811589d15", size = 31983, upload-time = "2025-10-12T10:51:11.361Z" }, + { url = "https://files.pythonhosted.org/packages/9c/e8/e76fa527fde17fd08288e4efef25c0aba7979ed5740eeab7bdff507bdeba/rjsmin-1.2.5-cp314-cp314-manylinux1_x86_64.whl", hash = "sha256:4e80b05803749502995fe33b6f5fd589b51dc46e50d873baf0b515c8f6e7b668", size = 32002, upload-time = "2025-10-12T10:51:12.257Z" }, + { url = "https://files.pythonhosted.org/packages/87/6c/ee395ef8ee117ba2d158a23a9502bc4a706e02f63bfdf6d01b802ae6ee9a/rjsmin-1.2.5-cp314-cp314-manylinux2014_aarch64.whl", hash = "sha256:b6d0bc092acc3f54ea63ec1dcb808edaac5e956141d89fd0d038e80de5322052", size = 32435, upload-time = "2025-10-12T10:51:13.147Z" }, + { url = "https://files.pythonhosted.org/packages/1a/78/c157d33aa6148f0e8c57bb91a41969e1a4aab929f3bb0a8d9ff3b5e21556/rjsmin-1.2.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1e2943259be7beafdcb0847c2a901f223bf9044bdfa8105e1be1ad67d6c47795", size = 32877, upload-time = "2025-10-12T10:51:14.545Z" }, + { url = "https://files.pythonhosted.org/packages/e9/49/6252145bf85d87c815aaf441c5efdf1ce918db5ab6e915cf6d0d99ca3969/rjsmin-1.2.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:e0387568c27fb49e55c1d0dfc27b54fc63d04b7756b1fed9743078130262907f", size = 32957, upload-time = "2025-10-12T10:51:15.964Z" }, + { url = "https://files.pythonhosted.org/packages/15/7e/c321c047b1a2fb7fa5ac818c37c1a15d348e1c12a1148de8ca5192a83b8f/rjsmin-1.2.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8196f1ecb0dff6c8647d4622e496869e94f1be92567ea2e941aa18d49a1a4347", size = 32456, upload-time = "2025-10-12T10:51:16.885Z" }, + { url = "https://files.pythonhosted.org/packages/5b/d7/2d190ce5ad10832df62edd4d9b1ae7092fd259ca58b39a1e202337f511a9/rjsmin-1.2.5-cp314-cp314t-manylinux1_i686.whl", hash = "sha256:9dd9f66568be9c8676278f140aa54102fab9af7feb59adf0c7a85bef49fe70df", size = 34115, upload-time = "2025-10-12T10:51:17.911Z" }, + { url = "https://files.pythonhosted.org/packages/76/ab/e7bcf261ede4cef7a0693927d7dcd1612bb59ba6c05191f58a92deec9f01/rjsmin-1.2.5-cp314-cp314t-manylinux1_x86_64.whl", hash = "sha256:5b8f72f7d96e5e1d30a33182cb39d4eb4516ddcd9b2f984813a9eefe66f8e180", size = 33977, upload-time = "2025-10-12T10:51:18.996Z" }, + { url = "https://files.pythonhosted.org/packages/a7/75/f1ff5f2199437b534204b40aa46c55c703489063cf7806c948a1a665575e/rjsmin-1.2.5-cp314-cp314t-manylinux2014_aarch64.whl", hash = "sha256:8c5906bd8830f616e992ad5e7277d0ea12c530110da188b2b9da23e9524a7cbc", size = 34604, upload-time = "2025-10-12T10:51:20.031Z" }, + { url = "https://files.pythonhosted.org/packages/d2/dc/acd463d88c56476cc683f1c6cce893c590007dccd390747e824b8e923d63/rjsmin-1.2.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8207bac0d3bab7791fd667f0863b5f32e51047845179b94b28c716e6514a9234", size = 34775, upload-time = "2025-10-12T10:51:21.364Z" }, + { url = "https://files.pythonhosted.org/packages/ce/56/e6f61718d1c36e646aabe552ad1f8f77744a4c57524eaa782b5b44eba220/rjsmin-1.2.5-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:1e3ab93a51d7581ba0a3b6a383df2929b86d9d55f9516764678f9b4e409826e8", size = 34682, upload-time = "2025-10-12T10:51:22.755Z" }, + { url = "https://files.pythonhosted.org/packages/00/f3/37a4672ddb1307eb57d9b54ba89a48f483a04a63cac4e1471fdb4cba76e6/rjsmin-1.2.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:47dad1732a2c4779bdc76d5b3183fdf2ec27838f31071fa9dfcc79483d3480e2", size = 34161, upload-time = "2025-10-12T10:51:23.761Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sqlparse" +version = "0.5.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/90/76/437d71068094df0726366574cf3432a4ed754217b436eb7429415cf2d480/sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e", size = 120815, upload-time = "2025-12-19T07:17:45.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba", size = 46138, upload-time = "2025-12-19T07:17:46.573Z" }, +] + +[[package]] +name = "tornado" +version = "6.5.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/f1/3173dfa4a18db4a9b03e5d55325559dab51ee653763bb8745a75af491286/tornado-6.5.5.tar.gz", hash = "sha256:192b8f3ea91bd7f1f50c06955416ed76c6b72f96779b962f07f911b91e8d30e9", size = 516006, upload-time = "2026-03-10T21:31:02.067Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/59/8c/77f5097695f4dd8255ecbd08b2a1ed8ba8b953d337804dd7080f199e12bf/tornado-6.5.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:487dc9cc380e29f58c7ab88f9e27cdeef04b2140862e5076a66fb6bb68bb1bfa", size = 445983, upload-time = "2026-03-10T21:30:44.28Z" }, + { url = "https://files.pythonhosted.org/packages/ab/5e/7625b76cd10f98f1516c36ce0346de62061156352353ef2da44e5c21523c/tornado-6.5.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:65a7f1d46d4bb41df1ac99f5fcb685fb25c7e61613742d5108b010975a9a6521", size = 444246, upload-time = "2026-03-10T21:30:46.571Z" }, + { url = "https://files.pythonhosted.org/packages/b2/04/7b5705d5b3c0fab088f434f9c83edac1573830ca49ccf29fb83bf7178eec/tornado-6.5.5-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e74c92e8e65086b338fd56333fb9a68b9f6f2fe7ad532645a290a464bcf46be5", size = 447229, upload-time = "2026-03-10T21:30:48.273Z" }, + { url = "https://files.pythonhosted.org/packages/34/01/74e034a30ef59afb4097ef8659515e96a39d910b712a89af76f5e4e1f93c/tornado-6.5.5-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:435319e9e340276428bbdb4e7fa732c2d399386d1de5686cb331ec8eee754f07", size = 448192, upload-time = "2026-03-10T21:30:51.22Z" }, + { url = "https://files.pythonhosted.org/packages/be/00/fe9e02c5a96429fce1a1d15a517f5d8444f9c412e0bb9eadfbe3b0fc55bf/tornado-6.5.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3f54aa540bdbfee7b9eb268ead60e7d199de5021facd276819c193c0fb28ea4e", size = 448039, upload-time = "2026-03-10T21:30:53.52Z" }, + { url = "https://files.pythonhosted.org/packages/82/9e/656ee4cec0398b1d18d0f1eb6372c41c6b889722641d84948351ae19556d/tornado-6.5.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:36abed1754faeb80fbd6e64db2758091e1320f6bba74a4cf8c09cd18ccce8aca", size = 447445, upload-time = "2026-03-10T21:30:55.541Z" }, + { url = "https://files.pythonhosted.org/packages/5a/76/4921c00511f88af86a33de770d64141170f1cfd9c00311aea689949e274e/tornado-6.5.5-cp39-abi3-win32.whl", hash = "sha256:dd3eafaaeec1c7f2f8fdcd5f964e8907ad788fe8a5a32c4426fbbdda621223b7", size = 448582, upload-time = "2026-03-10T21:30:57.142Z" }, + { url = "https://files.pythonhosted.org/packages/2c/23/f6c6112a04d28eed765e374435fb1a9198f73e1ec4b4024184f21faeb1ad/tornado-6.5.5-cp39-abi3-win_amd64.whl", hash = "sha256:6443a794ba961a9f619b1ae926a2e900ac20c34483eea67be4ed8f1e58d3ef7b", size = 448990, upload-time = "2026-03-10T21:30:58.857Z" }, + { url = "https://files.pythonhosted.org/packages/b7/c8/876602cbc96469911f0939f703453c1157b0c826ecb05bdd32e023397d4e/tornado-6.5.5-cp39-abi3-win_arm64.whl", hash = "sha256:2c9a876e094109333f888539ddb2de4361743e5d21eece20688e3e351e4990a6", size = 448016, upload-time = "2026-03-10T21:31:00.43Z" }, +] + +[[package]] +name = "tzdata" +version = "2026.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/19/1b9b0e29f30c6d35cb345486df41110984ea67ae69dddbc0e8a100999493/tzdata-2026.2.tar.gz", hash = "sha256:9173fde7d80d9018e02a662e168e5a2d04f87c41ea174b139fbef642eda62d10", size = 198254, upload-time = "2026-04-24T15:22:08.651Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl", hash = "sha256:bbe9af844f658da81a5f95019480da3a89415801f6cc966806612cc7169bffe7", size = 349321, upload-time = "2026-04-24T15:22:05.876Z" }, +] + +[[package]] +name = "tzlocal" +version = "5.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8b/2e/c14812d3d4d9cd1773c6be938f89e5735a1f11a9f184ac3639b93cef35d5/tzlocal-5.3.1.tar.gz", hash = "sha256:cceffc7edecefea1f595541dbd6e990cb1ea3d19bf01b2809f362a03dd7921fd", size = 30761, upload-time = "2025-03-05T21:17:41.549Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/14/e2a54fabd4f08cd7af1c07030603c3356b74da07f7cc056e600436edfa17/tzlocal-5.3.1-py3-none-any.whl", hash = "sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d", size = 18026, upload-time = "2025-03-05T21:17:39.857Z" }, +] + +[[package]] +name = "urllib3" +version = "2.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, +] + +[[package]] +name = "vine" +version = "5.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/e4/d07b5f29d283596b9727dd5275ccbceb63c44a1a82aa9e4bfd20426762ac/vine-5.1.0.tar.gz", hash = "sha256:8b62e981d35c41049211cf62a0a1242d8c1ee9bd15bb196ce38aefd6799e61e0", size = 48980, upload-time = "2023-11-05T08:46:53.857Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl", hash = "sha256:40fdf3c48b2cfe1c38a49e9ae2da6fda88e4794c810050a728bd7413811fb1dc", size = 9636, upload-time = "2023-11-05T08:46:51.205Z" }, +] + +[[package]] +name = "virtualenv" +version = "21.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, + { name = "python-discovery" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/15/ba/1f6e8c957e4932be060dcdc482d339c12e0216351478add3645cdaa53c05/virtualenv-21.3.3.tar.gz", hash = "sha256:f5bda277e553b1c2b3c1a8debfc30496e1288cc93ce6b7b71b3280047e317328", size = 7613784, upload-time = "2026-05-13T18:01:30.19Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/34/a9dbe051de88a63eb7408ea66630bac38e72f7f6077d4be58737106860d9/virtualenv-21.3.3-py3-none-any.whl", hash = "sha256:7d5987d8369e098e41406efb780a3d4ca79280097293899e351a6407ee153ab3", size = 7594554, upload-time = "2026-05-13T18:01:27.815Z" }, +] + +[[package]] +name = "wcwidth" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/ee/afaf0f85a9a18fe47a67f1e4422ed6cf1fe642f0ae0a2f81166231303c52/wcwidth-0.7.0.tar.gz", hash = "sha256:90e3a7ea092341c44b99562e75d09e4d5160fe7a3974c6fb842a101a95e7eed0", size = 182132, upload-time = "2026-05-02T16:04:12.653Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/52/e465037f5375f43533d1a80b6923955201596a99142ed524d77b571a1418/wcwidth-0.7.0-py3-none-any.whl", hash = "sha256:5d69154c429a82910e241c738cd0e2976fac8a2dd47a1a805f4afed1c0f136f2", size = 110825, upload-time = "2026-05-02T16:04:11.033Z" }, +] + +[[package]] +name = "yarl" +version = "1.24.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "multidict" }, + { name = "propcache" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/79/12/1e8f37460ea0f7eb59c221fdaf0ed75e7ac43e97f8093b9c6f411df50a78/yarl-1.24.2.tar.gz", hash = "sha256:9ac374123c6fd7abf64d1fec93962b0bd4ee2c19751755a762a72dd96c0378f8", size = 210798, upload-time = "2026-05-19T21:31:05.599Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/0e/e08087695fc12789263821c5dc0f8dc52b5b17efd0887cacf419f8a43ba3/yarl-1.24.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:f9312b3c02d9b3d23840f67952913c9c8721d7f1b7db305289faefa878f364c2", size = 129670, upload-time = "2026-05-19T21:29:56.631Z" }, + { url = "https://files.pythonhosted.org/packages/3a/98/ab4b5ed1b1b5cd973c8a3eb994c3a6aefb6ce6d399e21bb5f0316c33815c/yarl-1.24.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a4f4d6cd615823bfc7fb7e9b5987c3f41666371d870d51058f77e2680fbe9630", size = 91916, upload-time = "2026-05-19T21:29:58.645Z" }, + { url = "https://files.pythonhosted.org/packages/ba/b1/5297bb6a7df4782f7605bffc43b31f5044070935fbbcaa6c705a07e6ac65/yarl-1.24.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0c3063e5c0a8e8e62fae6c2596fa01da1561e4cd1da6fec5789f5cf99a8aefd8", size = 91625, upload-time = "2026-05-19T21:30:00.412Z" }, + { url = "https://files.pythonhosted.org/packages/02/a7/45baabfff76829264e623b185cff0c340d7e11bf3e1cd9ea37e7d17934bd/yarl-1.24.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fecd17873a096036c1c87ab3486f1aef7f269ada7f23f7f856f93b1cc7744f14", size = 104574, upload-time = "2026-05-19T21:30:02.544Z" }, + { url = "https://files.pythonhosted.org/packages/f3/40/3a5ab144d3d650ca37d4f4b57e56169be8af3ca34c448793e064b30baaed/yarl-1.24.2-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a46d1ab4ba4d32e6dc80daf8a28ce0bd83d08df52fbc32f3e288663427734535", size = 97534, upload-time = "2026-05-19T21:30:04.319Z" }, + { url = "https://files.pythonhosted.org/packages/9c/b5/5658fef3681fb5776b4513b052bec750009f47b3a592251c705d75375798/yarl-1.24.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:73e68edf6dfd5f73f9ca127d84e2a6f9213c65bdffb736bda19524c0564fcd14", size = 111481, upload-time = "2026-05-19T21:30:05.988Z" }, + { url = "https://files.pythonhosted.org/packages/4c/06/fdcd7dde037f00866dce123ed4ba23dba94beb56fc4cf561668d27be37f2/yarl-1.24.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a296ca617f2d25fbceafb962b88750d627e5984e75732c712154d058ae8d79a3", size = 111529, upload-time = "2026-05-19T21:30:07.738Z" }, + { url = "https://files.pythonhosted.org/packages/c2/53/d81269aaafccea0d33396c03035de997b743f11e648e6e27a0df99c72980/yarl-1.24.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51b2cf5ec89a8b8470177641ed62a3ba22d74e1e898e06ad53aa77972487208", size = 107338, upload-time = "2026-05-19T21:30:09.713Z" }, + { url = "https://files.pythonhosted.org/packages/ae/04/23049463f729bd899df203a7960505a75333edd499cda8aa1d5a82b64df5/yarl-1.24.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:310fc687f7b2044ec54e372c8cbe923bb88f5c37bded0d3079e5791c2fc3cf50", size = 106147, upload-time = "2026-05-19T21:30:11.365Z" }, + { url = "https://files.pythonhosted.org/packages/14/18/04a4b5830b43ed5e4c5015b40e9f6241ad91487d71611061b4e111d6ac80/yarl-1.24.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:297a2fe352ecf858b30a98f87948746ec16f001d279f84aebdbd3bd965e2f1bd", size = 104272, upload-time = "2026-05-19T21:30:12.978Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f7/8cffdf319aee7a7c1dbd07b61d91c3e3fda460c7a93b5f93e445f3806c4c/yarl-1.24.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2a263e76b97bc42bdcd7c5f4953dec1f7cd62a1112fa7f869e57255229390d67", size = 99962, upload-time = "2026-05-19T21:30:15.001Z" }, + { url = "https://files.pythonhosted.org/packages/d7/39/b3cce3b7dbef64ac700ad4cea156a207d01bede0f507587616c364b5468e/yarl-1.24.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:822519b64cf0b474f1a0aaef1dc621438ea46bb77c94df97a5b4d213a7d8a8b1", size = 111063, upload-time = "2026-05-19T21:30:16.683Z" }, + { url = "https://files.pythonhosted.org/packages/a1/ea/100818505e7ebf165c7242ff17fdf7d9fee79e27234aeca871c1082920d7/yarl-1.24.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:b6067060d9dc594899ba83e6db6c48c68d1e494a6dab158156ed86977ca7bcb1", size = 105438, upload-time = "2026-05-19T21:30:18.769Z" }, + { url = "https://files.pythonhosted.org/packages/8f/d2/e075a0b32aa6625087de9e653087df0759fed5de4a435fef594181102a77/yarl-1.24.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:0063adad533e57171b79db3943b229d40dfafeeee579767f96541f106bac5f1b", size = 111458, upload-time = "2026-05-19T21:30:21.024Z" }, + { url = "https://files.pythonhosted.org/packages/e6/5c/ceea7ba98b65c8eb8d947fdc52f9bedfcd43c6a57c9e3c90c17be8f324a3/yarl-1.24.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ee8e3fb34513e8dc082b586ef4910c98335d43a6fab688cd44d4851bacfce3e8", size = 107589, upload-time = "2026-05-19T21:30:23.412Z" }, + { url = "https://files.pythonhosted.org/packages/fa/d9/5582d57e2b2db9b85eb6663a22efdd78e08805f3f5389566e9fcad254d1b/yarl-1.24.2-cp314-cp314-win_amd64.whl", hash = "sha256:afb00d7fd8e0f285ca29a44cc50df2d622ff2f7a6d933fa641577b5f9d5f3db0", size = 94424, upload-time = "2026-05-19T21:30:25.425Z" }, + { url = "https://files.pythonhosted.org/packages/92/10/7dc07a0e22806a9280f42a57361395506e800c64e22737cd7b0886feab42/yarl-1.24.2-cp314-cp314-win_arm64.whl", hash = "sha256:68cf6eacd6028ef1142bc4b48376b81566385ca6f9e7dde3b0fa91be08ffcb57", size = 88690, upload-time = "2026-05-19T21:30:27.623Z" }, + { url = "https://files.pythonhosted.org/packages/9e/13/d5b8e2c8667db955bcb3de233f18798fefe7edf1d7429c2c9d4f9c401114/yarl-1.24.2-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:221ce1dd921ac4f603957f17d7c18c5cc0797fbb52f156941f92e04605d1d67b", size = 136248, upload-time = "2026-05-19T21:30:29.297Z" }, + { url = "https://files.pythonhosted.org/packages/de/46/a4a97c05c9c9b8fd266bb2a0df12992c7fbd02391eb9640583411b6dab32/yarl-1.24.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5f3224db28173a00d7afacdee07045cc4673dfab2b15492c7ae10deddbece761", size = 95084, upload-time = "2026-05-19T21:30:31.031Z" }, + { url = "https://files.pythonhosted.org/packages/95/b2/845cf2074a015e6fe0d0808cf1a2d9e868386c4220d657ebd8302b199043/yarl-1.24.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c557165320d6244ebe3a02431b2a201a20080e02f41f0cfa0ccc47a183765da8", size = 95272, upload-time = "2026-05-19T21:30:33.062Z" }, + { url = "https://files.pythonhosted.org/packages/fe/16/e69d4aa244aef45235ddfebc0e04036a6829842bc5a6a795aedc6c998d23/yarl-1.24.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:904065e6e85b1fa54d0d87438bd58c14c0bad97aad654ad1077fd9d87e8478ed", size = 101497, upload-time = "2026-05-19T21:30:34.842Z" }, + { url = "https://files.pythonhosted.org/packages/15/94/c07107715d621076863ee88b3ddf183fa5e9d4aba5769623c9979828410a/yarl-1.24.2-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8cec2a38d70edc10e0e856ceda886af5327a017ccbde8e1de1bd44d300357543", size = 94002, upload-time = "2026-05-19T21:30:37.724Z" }, + { url = "https://files.pythonhosted.org/packages/a9/35/fc1bbdd895b5e4010b8fdd037f7ed3aa289d3863e08231b30231ca9a0815/yarl-1.24.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e7484b9361ed222ee1ca5b4337aa4cbdcc4618ce5aff57d9ef1582fd95893fc0", size = 106524, upload-time = "2026-05-19T21:30:40.196Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f2/32b66d0a4ba47c296cf86d03e2c67bff58399fe6d6d84d5205c04c66cc6d/yarl-1.24.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:84f9670b89f34db07f81e53aee83e0b938a3412329d51c8f922488be7fcc4024", size = 106165, upload-time = "2026-05-19T21:30:41.888Z" }, + { url = "https://files.pythonhosted.org/packages/95/47/37cb5ff50c5e825d4d38e81bb04d1b7e96bf960f7ab89f9850b162f3f114/yarl-1.24.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:abb2759733d63a28b4956500a5dd57140f26486c92b2caedfb964ab7d9b79dbf", size = 103010, upload-time = "2026-05-19T21:30:43.985Z" }, + { url = "https://files.pythonhosted.org/packages/6f/d2/4597912315096f7bb359e46e13bf8b60994fcbb2db29b804c0902ef4eff5/yarl-1.24.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:081c2bf54efe03774d0311172bc04fedf9ca01e644d4cd8c805688e527209bdc", size = 101128, upload-time = "2026-05-19T21:30:46.291Z" }, + { url = "https://files.pythonhosted.org/packages/b9/d5/c8e86e120521e646013d02a8e3b8884392e28494be8f392366e50d208efc/yarl-1.24.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:86746bef442aa479107fe28132e1277237f9c24c2f00b0b0cf22b3ee0904f2bb", size = 101382, upload-time = "2026-05-19T21:30:48.085Z" }, + { url = "https://files.pythonhosted.org/packages/fa/98/70b229236118f89dbeb739b76f10225bbf53b5497725502594c9a01d699a/yarl-1.24.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:2d07d21d0bc4b17558e8de0b02fbfdf1e347d3bb3699edd00bb92e7c57925420", size = 95964, upload-time = "2026-05-19T21:30:49.785Z" }, + { url = "https://files.pythonhosted.org/packages/87/f8/56c386981e3c8648d279fdef2397ffec577e8320fd5649745e34d54faeb7/yarl-1.24.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:4fb1ac3fc5fecd8ae7453ea237e4d22b49befa70266dfe1629924245c21a0c7f", size = 106204, upload-time = "2026-05-19T21:30:51.862Z" }, + { url = "https://files.pythonhosted.org/packages/1a/1e/765afe97811ca35933e2a7de70ac57b1997ea2e4ee895719ee7a231fb7e5/yarl-1.24.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:4da31a5512ed1729ca8d8aacde3f7faeb8843cde3165d6bcf7f88f74f17bb8aa", size = 101510, upload-time = "2026-05-19T21:30:53.62Z" }, + { url = "https://files.pythonhosted.org/packages/ee/78/393913f4b9039e1edd09ae8a9bbb9d539be909a8abf6d8a2084585bed4b7/yarl-1.24.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:533ded4dceb5f1f3da7906244f4e82cf46cfd40d84c69a1faf5ac506aa65ecbe", size = 105584, upload-time = "2026-05-19T21:30:55.962Z" }, + { url = "https://files.pythonhosted.org/packages/78/87/deb17b7049bbe74ea11a713b86f8f27800cc1c8648b0b797243ebb4830ba/yarl-1.24.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7b3a85525f6e7eeabcfdd372862b21ee1915db1b498a04e8bf0e389b607ff0bd", size = 103410, upload-time = "2026-05-19T21:30:57.962Z" }, + { url = "https://files.pythonhosted.org/packages/8f/be/f9f7594e23b5b93affff0318e4593c1920331bcaefda326cabcad94296a1/yarl-1.24.2-cp314-cp314t-win_amd64.whl", hash = "sha256:a7624b1ca46ca5d7b864ef0d2f8efe3091454085ee1855b4e992314529972215", size = 102980, upload-time = "2026-05-19T21:30:59.735Z" }, + { url = "https://files.pythonhosted.org/packages/65/a4/ba80dccd3593ff1f01051a818694d07b58cb8232677ee9a22a5a1f93a9fc/yarl-1.24.2-cp314-cp314t-win_arm64.whl", hash = "sha256:e434a45ce2e7a947f951fc5a8944c8cc080b7e59f9c50ae80fd39107cf88126d", size = 91219, upload-time = "2026-05-19T21:31:01.934Z" }, + { url = "https://files.pythonhosted.org/packages/fd/4d/4b880086bd0d3e034d25647be1d830afc3e3f610e98c4ab3490af6b1b6d5/yarl-1.24.2-py3-none-any.whl", hash = "sha256:2783d9226db8797636cd6896e4de81feed252d1db72265686c9558d97a4d94b9", size = 53576, upload-time = "2026-05-19T21:31:03.909Z" }, +] From cc84a7c7d2a459c6c95ca8592dc82956f75b88b8 Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Sun, 24 May 2026 13:58:10 +0200 Subject: [PATCH 02/27] dockerized --- .github/workflows/django.yml | 54 +- AHC_app/.dockerignore | 7 + AHC_app/Dockerfile-queue | 20 +- AHC_app/Dockerfile-web | 26 +- AHC_app/Pipfile | 78 -- AHC_app/Pipfile.lock | 1786 ---------------------------------- 6 files changed, 50 insertions(+), 1921 deletions(-) delete mode 100644 AHC_app/Pipfile delete mode 100644 AHC_app/Pipfile.lock diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml index 37ee701..fbbc571 100644 --- a/.github/workflows/django.yml +++ b/.github/workflows/django.yml @@ -8,7 +8,7 @@ on: jobs: test: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest env: POSTGRES_DB: ${{ secrets.POSTGRES_DB }} POSTGRES_USER: ${{ secrets.POSTGRES_USER }} @@ -34,50 +34,24 @@ jobs: EMAIL_HOST_PASSWORD: ${{ secrets.EMAIL_HOST_PASSWORD }} DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }} PYTHONUNBUFFERED: "1" - PYTHONPATH: "/home/runner/work/Animals_Healthcare_Application/Animals_Healthcare_Application/AHC_app" -# strategy: -# max-parallel: 4 steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - - name: Setup Python - uses: actions/setup-python@v5 + - name: Setup uv + uses: astral-sh/setup-uv@v3 with: - python-version: 3.12 - - - name: Install PostgreSQL dependencies - run: sudo apt-get install -y libpq-dev - - - name: Install pipenv - run: pip install pipenv - - - name: Prepare environment - run: | - cd ./AHC_app - pipenv install --dev - pipenv graph - - - name: Show Python version - run: python --version - working-directory: ./AHC_app + enable-cache: true + cache-dependency-glob: "AHC_app/uv.lock" + python-version: "3.14" - - name: Show pip version - run: pip --version + - name: Install dependencies + run: uv sync --no-group dev working-directory: ./AHC_app - - name: Show pipenv version - run: pipenv --version - working-directory: ./AHC_app - - - name: List installed packages - run: pipenv run pip list - working-directory: ./AHC_app - - - name: Prepare environment and run tests - run: | - PYTHONPATH=$(pwd) pipenv run python manage.py test + - name: Run tests + run: PYTHONPATH=$(pwd) uv run python manage.py test working-directory: ./AHC_app build-and-push: @@ -87,7 +61,7 @@ jobs: if: ${{ github.ref == 'refs/heads/main' }} steps: - name: Checkout Repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v1 @@ -106,8 +80,8 @@ jobs: ECR_URI: ${{ secrets.ECR_URI_APPENDIXES_DB }} IMAGE_TAG: latest run: | - docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG . - docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG + docker build -t $ECR_URI:$IMAGE_TAG . + docker push $ECR_URI:$IMAGE_TAG - name: Build, tag and push the celery-flower image to ECR id: build-image-celery-flower diff --git a/AHC_app/.dockerignore b/AHC_app/.dockerignore index 1b1aaee..1f45f28 100644 --- a/AHC_app/.dockerignore +++ b/AHC_app/.dockerignore @@ -1,2 +1,9 @@ ./tars/* *.tar +.venv/ +__pycache__/ +*.py[cod] +db.sqlite3 +static_collected/ +static/media/profile_pics/ +static/media/attachments/ diff --git a/AHC_app/Dockerfile-queue b/AHC_app/Dockerfile-queue index 0cc351b..c4ca1d3 100644 --- a/AHC_app/Dockerfile-queue +++ b/AHC_app/Dockerfile-queue @@ -1,10 +1,16 @@ -FROM python:3.12 -LABEL authors="AM" +# syntax=docker/dockerfile:1.7 +FROM python:3.14-slim AS builder WORKDIR /app -COPY Pipfile Pipfile.lock ./ - -RUN python -m pip install --upgrade pip && \ - pip install --no-cache-dir pipenv && \ - pipenv install --dev --system --deploy +RUN pip install uv --break-system-packages +COPY pyproject.toml uv.lock ./ +ENV UV_PYTHON_PREFERENCE=only-system \ + UV_PROJECT_ENVIRONMENT=/opt/venv +RUN --mount=type=cache,target=/root/.cache/uv,sharing=locked \ + uv sync --no-group dev +FROM python:3.14-slim AS runtime +LABEL authors="AM" +WORKDIR /app +COPY --from=builder /opt/venv /opt/venv +ENV PATH="/opt/venv/bin:$PATH" COPY . . diff --git a/AHC_app/Dockerfile-web b/AHC_app/Dockerfile-web index a664b69..cea64ab 100644 --- a/AHC_app/Dockerfile-web +++ b/AHC_app/Dockerfile-web @@ -1,13 +1,19 @@ -FROM python:3.12 -LABEL authors="AM" +# syntax=docker/dockerfile:1.7 +FROM python:3.14-slim AS builder WORKDIR /app -COPY Pipfile Pipfile.lock ./ - -RUN python -m pip install --upgrade pip && \ - pip install --no-cache-dir pipenv && \ - pipenv install --dev --system --deploy - -RUN apt-get update && \ - apt-get install -y cron +RUN pip install uv --break-system-packages +COPY pyproject.toml uv.lock ./ +ENV UV_PYTHON_PREFERENCE=only-system \ + UV_PROJECT_ENVIRONMENT=/opt/venv +RUN --mount=type=cache,target=/root/.cache/uv,sharing=locked \ + uv sync --no-group dev +FROM python:3.14-slim AS runtime +LABEL authors="AM" +RUN apt-get update && \ + apt-get install -y --no-install-recommends cron && \ + rm -rf /var/lib/apt/lists/* +WORKDIR /app +COPY --from=builder /opt/venv /opt/venv +ENV PATH="/opt/venv/bin:$PATH" COPY . . diff --git a/AHC_app/Pipfile b/AHC_app/Pipfile deleted file mode 100644 index e76d50b..0000000 --- a/AHC_app/Pipfile +++ /dev/null @@ -1,78 +0,0 @@ -[[source]] -url = "https://pypi.org/simple" -verify_ssl = true -name = "pypi" - -[packages] -amqp = "==5.1.1" -billiard = "==4.1.0" -cachetools = "==5.3.2" -certifi = "==2023.7.22" -cffi = "==1.16.0" -charset-normalizer = "==3.3.1" -click = "==8.1.7" -click-didyoumean = "==0.3.0" -click-plugins = "==1.1.1" -click-repl = "==0.3.0" -colorama = "==0.4.6" -contourpy = "==1.0.7" -crispy-bootstrap4 = "==2022.1" -cryptography = "==41.0.5" -cycler = "==0.11.0" -defusedxml = "==0.7.1" -django-appconf = "==1.0.5" -django-bootstrap-modal-forms = "==3.0.4" -django-compressor = "==4.4" -django-crispy-forms = "==2.0" -django-crontab = "==0.7.1" -django-libsass = "==0.9" -django-taggit = "==4.0.0" -django-timezone-field = "==6.0.1" -djangorestframework = "==3.14.0" -fonttools = "==4.39.4" -httplib2 = "==0.22.0" -idna = "==3.4" -kiwisolver = "==1.4.4" -kombu = "==5.3.2" -libsass = "==0.22.0" -oauthlib = "==3.2.2" -packaging = "==23.1" -pillow = "==9.5.0" -prompt-toolkit = "==3.0.39" -pyasn1 = "==0.5.0" -pyasn1-modules = "==0.3.0" -pycparser = "==2.21" -pyjwt = "==2.8.0" -pyparsing = "==3.0.9" -python-dateutil = "==2.8.2" -python3-openid = "==3.2.0" -pytz = "==2023.3" -rcssmin = "==1.1.1" -redis = "==5.0.1" -requests = "==2.31.0" -requests-oauthlib = "==1.3.1" -rjsmin = "==1.2.1" -rsa = "==4.9" -six = "==1.16.0" -sqlparse = "==0.4.4" -tzdata = "==2023.3" -urllib3 = "==2.0.7" -vine = "==5.0.0" -wcwidth = "==0.2.8" -icecream = "*" -flower = "*" -django-cron = "*" -python-decouple = "*" -pycouchdb = "*" -discord = "*" -psycopg2-binary = "*" -django = "==4.2.11" -celery = "5.3.4" - -[dev-packages] -pre-commit = "*" -isort = "*" -black = "*" - -[requires] -python_version = "3.12" diff --git a/AHC_app/Pipfile.lock b/AHC_app/Pipfile.lock deleted file mode 100644 index ddf2690..0000000 --- a/AHC_app/Pipfile.lock +++ /dev/null @@ -1,1786 +0,0 @@ -{ - "_meta": { - "hash": { - - "sha256": "adc7b4e1a58ad54950df7b0133e5a7ddaa4bd8dbcb727885188ac9528a5c3c24" - - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.12" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "aiohttp": { - "hashes": [ - - "sha256:0605cc2c0088fcaae79f01c913a38611ad09ba68ff482402d3410bf59039bfb8", - "sha256:0a158704edf0abcac8ac371fbb54044f3270bdbc93e254a82b6c82be1ef08f3c", - "sha256:0cbf56238f4bbf49dab8c2dc2e6b1b68502b1e88d335bea59b3f5b9f4c001475", - "sha256:1732102949ff6087589408d76cd6dea656b93c896b011ecafff418c9661dc4ed", - "sha256:18f634d540dd099c262e9f887c8bbacc959827cfe5da7a0e2e1cf3f14dbf2daf", - "sha256:239f975589a944eeb1bad26b8b140a59a3a320067fb3cd10b75c3092405a1372", - "sha256:2faa61a904b83142747fc6a6d7ad8fccff898c849123030f8e75d5d967fd4a81", - "sha256:320e8618eda64e19d11bdb3bd04ccc0a816c17eaecb7e4945d01deee2a22f95f", - "sha256:38d80498e2e169bc61418ff36170e0aad0cd268da8b38a17c4cf29d254a8b3f1", - "sha256:3916c8692dbd9d55c523374a3b8213e628424d19116ac4308e434dbf6d95bbdd", - "sha256:393c7aba2b55559ef7ab791c94b44f7482a07bf7640d17b341b79081f5e5cd1a", - "sha256:3b7b30258348082826d274504fbc7c849959f1989d86c29bc355107accec6cfb", - "sha256:3fcb4046d2904378e3aeea1df51f697b0467f2aac55d232c87ba162709478c46", - "sha256:4109adee842b90671f1b689901b948f347325045c15f46b39797ae1bf17019de", - "sha256:4558e5012ee03d2638c681e156461d37b7a113fe13970d438d95d10173d25f78", - "sha256:45731330e754f5811c314901cebdf19dd776a44b31927fa4b4dbecab9e457b0c", - "sha256:4715a9b778f4293b9f8ae7a0a7cef9829f02ff8d6277a39d7f40565c737d3771", - "sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb", - "sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430", - "sha256:4ff550491f5492ab5ed3533e76b8567f4b37bd2995e780a1f46bca2024223233", - "sha256:52c27110f3862a1afbcb2af4281fc9fdc40327fa286c4625dfee247c3ba90156", - "sha256:55b39c8684a46e56ef8c8d24faf02de4a2b2ac60d26cee93bc595651ff545de9", - "sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59", - "sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888", - "sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c", - "sha256:60cdbd56f4cad9f69c35eaac0fbbdf1f77b0ff9456cebd4902f3dd1cf096464c", - "sha256:6380c039ec52866c06d69b5c7aad5478b24ed11696f0e72f6b807cfb261453da", - "sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424", - "sha256:66331d00fb28dc90aa606d9a54304af76b335ae204d1836f65797d6fe27f1ca2", - "sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb", - "sha256:694d828b5c41255e54bc2dddb51a9f5150b4eefa9886e38b52605a05d96566e8", - "sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a", - "sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10", - "sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0", - "sha256:7b179eea70833c8dee51ec42f3b4097bd6370892fa93f510f76762105568cf09", - "sha256:7f64cbd44443e80094309875d4f9c71d0401e966d191c3d469cde4642bc2e031", - "sha256:82a6a97d9771cb48ae16979c3a3a9a18b600a8505b1115cfe354dfb2054468b4", - "sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3", - "sha256:8676e8fd73141ded15ea586de0b7cda1542960a7b9ad89b2b06428e97125d4fa", - "sha256:88e311d98cc0bf45b62fc46c66753a83445f5ab20038bcc1b8a1cc05666f428a", - "sha256:8b4f72fbb66279624bfe83fd5eb6aea0022dad8eec62b71e7bf63ee1caadeafe", - "sha256:8c64a6dc3fe5db7b1b4d2b5cb84c4f677768bdc340611eca673afb7cf416ef5a", - "sha256:8cf142aa6c1a751fcb364158fd710b8a9be874b81889c2bd13aa8893197455e2", - "sha256:8d1964eb7617907c792ca00b341b5ec3e01ae8c280825deadbbd678447b127e1", - "sha256:93e22add827447d2e26d67c9ac0161756007f152fdc5210277d00a85f6c92323", - "sha256:9c69e77370cce2d6df5d12b4e12bdcca60c47ba13d1cbbc8645dd005a20b738b", - "sha256:9dbc053ac75ccc63dc3a3cc547b98c7258ec35a215a92bd9f983e0aac95d3d5b", - "sha256:9e3a1ae66e3d0c17cf65c08968a5ee3180c5a95920ec2731f53343fac9bad106", - "sha256:a6ea1a5b409a85477fd8e5ee6ad8f0e40bf2844c270955e09360418cfd09abac", - "sha256:a81b1143d42b66ffc40a441379387076243ef7b51019204fd3ec36b9f69e77d6", - "sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832", - "sha256:afc52b8d969eff14e069a710057d15ab9ac17cd4b6753042c407dcea0e40bf75", - "sha256:b3df71da99c98534be076196791adca8819761f0bf6e08e07fd7da25127150d6", - "sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d", - "sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72", - "sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db", - "sha256:c6021d296318cb6f9414b48e6a439a7f5d1f665464da507e8ff640848ee2a58a", - "sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da", - "sha256:c7a4b7a6cf5b6eb11e109a9755fd4fda7d57395f8c575e166d363b9fc3ec4678", - "sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b", - "sha256:cd2adf5c87ff6d8b277814a28a535b59e20bfea40a101db6b3bdca7e9926bc24", - "sha256:d1469f228cd9ffddd396d9948b8c9cd8022b6d1bf1e40c6f25b0fb90b4f893ed", - "sha256:d153f652a687a8e95ad367a86a61e8d53d528b0530ef382ec5aaf533140ed00f", - "sha256:d5ab8e1f6bee051a4bf6195e38a5c13e5e161cb7bad83d8854524798bd9fcd6e", - "sha256:da00da442a0e31f1c69d26d224e1efd3a1ca5bcbf210978a2ca7426dfcae9f58", - "sha256:da22dab31d7180f8c3ac7c7635f3bcd53808f374f6aa333fe0b0b9e14b01f91a", - "sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342", - "sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558", - "sha256:e9a3d838441bebcf5cf442700e3963f58b5c33f015341f9ea86dcd7d503c07e2", - "sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551", - "sha256:f22eb3a6c1080d862befa0a89c380b4dafce29dc6cd56083f630073d102eb595", - "sha256:f26383adb94da5e7fb388d441bf09c61e5e35f455a3217bfd790c6b6bc64b2ee", - "sha256:f3c2890ca8c59ee683fd09adf32321a40fe1cf164e3387799efb2acebf090c11", - "sha256:f64fd07515dad67f24b6ea4a66ae2876c01031de91c93075b8093f07c0a2d93d", - "sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7", - "sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f" - ], - "markers": "python_version >= '3.8'", - "version": "==3.9.5" - - }, - "aiosignal": { - "hashes": [ - "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc", - "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17" - ], - "markers": "python_version >= '3.7'", - "version": "==1.3.1" - }, - "amqp": { - "hashes": [ - "sha256:2c1b13fecc0893e946c65cbd5f36427861cffa4ea2201d8f6fca22e2a373b5e2", - "sha256:6f0956d2c23d8fa6e7691934d8c3930eadb44972cbbd1a7ae3a520f735d43359" - ], - "index": "pypi", - "markers": "python_version >= '3.6'", - "version": "==5.1.1" - }, - "asgiref": { - "hashes": [ - "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47", - "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590" - ], - - "markers": "python_version >= '3.8'", - "version": "==3.8.1" - - }, - "asttokens": { - "hashes": [ - "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24", - "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0" - ], - "version": "==2.4.1" - }, - "attrs": { - "hashes": [ - "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", - "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" - ], - "markers": "python_version >= '3.7'", - "version": "==23.2.0" - }, - "billiard": { - "hashes": [ - "sha256:0f50d6be051c6b2b75bfbc8bfd85af195c5739c281d3f5b86a5640c65563614a", - "sha256:1ad2eeae8e28053d729ba3373d34d9d6e210f6e4d8bf0a9c64f92bd053f1edf5" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==4.1.0" - }, - "cachetools": { - "hashes": [ - "sha256:086ee420196f7b2ab9ca2db2520aca326318b68fe5ba8bc4d49cca91add450f2", - "sha256:861f35a13a451f94e301ce2bec7cac63e881232ccce7ed67fab9b5df4d3beaa1" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==5.3.2" - }, - "celery": { - "hashes": [ - "sha256:1e6ed40af72695464ce98ca2c201ad0ef8fd192246f6c9eac8bba343b980ad34", - "sha256:9023df6a8962da79eb30c0c84d5f4863d9793a466354cc931d7f72423996de28" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==5.3.4" - }, - "certifi": { - "hashes": [ - "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082", - "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9" - ], - "index": "pypi", - "markers": "python_version >= '3.6'", - "version": "==2023.7.22" - }, - "cffi": { - "hashes": [ - "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc", - "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a", - "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417", - "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab", - "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520", - "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36", - "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743", - "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8", - "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed", - "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684", - "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56", - "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324", - "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d", - "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235", - "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e", - "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088", - "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000", - "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7", - "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e", - "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673", - "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c", - "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe", - "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2", - "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098", - "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8", - "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a", - "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0", - "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b", - "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896", - "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e", - "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9", - "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2", - "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b", - "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6", - "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404", - "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f", - "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0", - "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4", - "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc", - "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936", - "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba", - "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872", - "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb", - "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614", - "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1", - "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d", - "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969", - "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b", - "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4", - "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627", - "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956", - "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==1.16.0" - }, - "charset-normalizer": { - "hashes": [ - "sha256:06cf46bdff72f58645434d467bf5228080801298fbba19fe268a01b4534467f5", - "sha256:0c8c61fb505c7dad1d251c284e712d4e0372cef3b067f7ddf82a7fa82e1e9a93", - "sha256:10b8dd31e10f32410751b3430996f9807fc4d1587ca69772e2aa940a82ab571a", - "sha256:1171ef1fc5ab4693c5d151ae0fdad7f7349920eabbaca6271f95969fa0756c2d", - "sha256:17a866d61259c7de1bdadef418a37755050ddb4b922df8b356503234fff7932c", - "sha256:1d6bfc32a68bc0933819cfdfe45f9abc3cae3877e1d90aac7259d57e6e0f85b1", - "sha256:1ec937546cad86d0dce5396748bf392bb7b62a9eeb8c66efac60e947697f0e58", - "sha256:223b4d54561c01048f657fa6ce41461d5ad8ff128b9678cfe8b2ecd951e3f8a2", - "sha256:2465aa50c9299d615d757c1c888bc6fef384b7c4aec81c05a0172b4400f98557", - "sha256:28f512b9a33235545fbbdac6a330a510b63be278a50071a336afc1b78781b147", - "sha256:2c092be3885a1b7899cd85ce24acedc1034199d6fca1483fa2c3a35c86e43041", - "sha256:2c4c99f98fc3a1835af8179dcc9013f93594d0670e2fa80c83aa36346ee763d2", - "sha256:31445f38053476a0c4e6d12b047b08ced81e2c7c712e5a1ad97bc913256f91b2", - "sha256:31bbaba7218904d2eabecf4feec0d07469284e952a27400f23b6628439439fa7", - "sha256:34d95638ff3613849f473afc33f65c401a89f3b9528d0d213c7037c398a51296", - "sha256:352a88c3df0d1fa886562384b86f9a9e27563d4704ee0e9d56ec6fcd270ea690", - "sha256:39b70a6f88eebe239fa775190796d55a33cfb6d36b9ffdd37843f7c4c1b5dc67", - "sha256:3c66df3f41abee950d6638adc7eac4730a306b022570f71dd0bd6ba53503ab57", - "sha256:3f70fd716855cd3b855316b226a1ac8bdb3caf4f7ea96edcccc6f484217c9597", - "sha256:3f9bc2ce123637a60ebe819f9fccc614da1bcc05798bbbaf2dd4ec91f3e08846", - "sha256:3fb765362688821404ad6cf86772fc54993ec11577cd5a92ac44b4c2ba52155b", - "sha256:45f053a0ece92c734d874861ffe6e3cc92150e32136dd59ab1fb070575189c97", - "sha256:46fb9970aa5eeca547d7aa0de5d4b124a288b42eaefac677bde805013c95725c", - "sha256:4cb50a0335382aac15c31b61d8531bc9bb657cfd848b1d7158009472189f3d62", - "sha256:4e12f8ee80aa35e746230a2af83e81bd6b52daa92a8afaef4fea4a2ce9b9f4fa", - "sha256:4f3100d86dcd03c03f7e9c3fdb23d92e32abbca07e7c13ebd7ddfbcb06f5991f", - "sha256:4f6e2a839f83a6a76854d12dbebde50e4b1afa63e27761549d006fa53e9aa80e", - "sha256:4f861d94c2a450b974b86093c6c027888627b8082f1299dfd5a4bae8e2292821", - "sha256:501adc5eb6cd5f40a6f77fbd90e5ab915c8fd6e8c614af2db5561e16c600d6f3", - "sha256:520b7a142d2524f999447b3a0cf95115df81c4f33003c51a6ab637cbda9d0bf4", - "sha256:548eefad783ed787b38cb6f9a574bd8664468cc76d1538215d510a3cd41406cb", - "sha256:555fe186da0068d3354cdf4bbcbc609b0ecae4d04c921cc13e209eece7720727", - "sha256:55602981b2dbf8184c098bc10287e8c245e351cd4fdcad050bd7199d5a8bf514", - "sha256:58e875eb7016fd014c0eea46c6fa92b87b62c0cb31b9feae25cbbe62c919f54d", - "sha256:5a3580a4fdc4ac05f9e53c57f965e3594b2f99796231380adb2baaab96e22761", - "sha256:5b70bab78accbc672f50e878a5b73ca692f45f5b5e25c8066d748c09405e6a55", - "sha256:5ceca5876032362ae73b83347be8b5dbd2d1faf3358deb38c9c88776779b2e2f", - "sha256:61f1e3fb621f5420523abb71f5771a204b33c21d31e7d9d86881b2cffe92c47c", - "sha256:633968254f8d421e70f91c6ebe71ed0ab140220469cf87a9857e21c16687c034", - "sha256:63a6f59e2d01310f754c270e4a257426fe5a591dc487f1983b3bbe793cf6bac6", - "sha256:63accd11149c0f9a99e3bc095bbdb5a464862d77a7e309ad5938fbc8721235ae", - "sha256:6db3cfb9b4fcecb4390db154e75b49578c87a3b9979b40cdf90d7e4b945656e1", - "sha256:71ef3b9be10070360f289aea4838c784f8b851be3ba58cf796262b57775c2f14", - "sha256:7ae8e5142dcc7a49168f4055255dbcced01dc1714a90a21f87448dc8d90617d1", - "sha256:7b6cefa579e1237ce198619b76eaa148b71894fb0d6bcf9024460f9bf30fd228", - "sha256:800561453acdecedaac137bf09cd719c7a440b6800ec182f077bb8e7025fb708", - "sha256:82ca51ff0fc5b641a2d4e1cc8c5ff108699b7a56d7f3ad6f6da9dbb6f0145b48", - "sha256:851cf693fb3aaef71031237cd68699dded198657ec1e76a76eb8be58c03a5d1f", - "sha256:854cc74367180beb327ab9d00f964f6d91da06450b0855cbbb09187bcdb02de5", - "sha256:87071618d3d8ec8b186d53cb6e66955ef2a0e4fa63ccd3709c0c90ac5a43520f", - "sha256:871d045d6ccc181fd863a3cd66ee8e395523ebfbc57f85f91f035f50cee8e3d4", - "sha256:8aee051c89e13565c6bd366813c386939f8e928af93c29fda4af86d25b73d8f8", - "sha256:8af5a8917b8af42295e86b64903156b4f110a30dca5f3b5aedea123fbd638bff", - "sha256:8ec8ef42c6cd5856a7613dcd1eaf21e5573b2185263d87d27c8edcae33b62a61", - "sha256:91e43805ccafa0a91831f9cd5443aa34528c0c3f2cc48c4cb3d9a7721053874b", - "sha256:9505dc359edb6a330efcd2be825fdb73ee3e628d9010597aa1aee5aa63442e97", - "sha256:985c7965f62f6f32bf432e2681173db41336a9c2611693247069288bcb0c7f8b", - "sha256:9a74041ba0bfa9bc9b9bb2cd3238a6ab3b7618e759b41bd15b5f6ad958d17605", - "sha256:9edbe6a5bf8b56a4a84533ba2b2f489d0046e755c29616ef8830f9e7d9cf5728", - "sha256:a15c1fe6d26e83fd2e5972425a772cca158eae58b05d4a25a4e474c221053e2d", - "sha256:a66bcdf19c1a523e41b8e9d53d0cedbfbac2e93c649a2e9502cb26c014d0980c", - "sha256:ae4070f741f8d809075ef697877fd350ecf0b7c5837ed68738607ee0a2c572cf", - "sha256:ae55d592b02c4349525b6ed8f74c692509e5adffa842e582c0f861751701a673", - "sha256:b578cbe580e3b41ad17b1c428f382c814b32a6ce90f2d8e39e2e635d49e498d1", - "sha256:b891a2f68e09c5ef989007fac11476ed33c5c9994449a4e2c3386529d703dc8b", - "sha256:baec8148d6b8bd5cee1ae138ba658c71f5b03e0d69d5907703e3e1df96db5e41", - "sha256:bb06098d019766ca16fc915ecaa455c1f1cd594204e7f840cd6258237b5079a8", - "sha256:bc791ec3fd0c4309a753f95bb6c749ef0d8ea3aea91f07ee1cf06b7b02118f2f", - "sha256:bd28b31730f0e982ace8663d108e01199098432a30a4c410d06fe08fdb9e93f4", - "sha256:be4d9c2770044a59715eb57c1144dedea7c5d5ae80c68fb9959515037cde2008", - "sha256:c0c72d34e7de5604df0fde3644cc079feee5e55464967d10b24b1de268deceb9", - "sha256:c0e842112fe3f1a4ffcf64b06dc4c61a88441c2f02f373367f7b4c1aa9be2ad5", - "sha256:c15070ebf11b8b7fd1bfff7217e9324963c82dbdf6182ff7050519e350e7ad9f", - "sha256:c2000c54c395d9e5e44c99dc7c20a64dc371f777faf8bae4919ad3e99ce5253e", - "sha256:c30187840d36d0ba2893bc3271a36a517a717f9fd383a98e2697ee890a37c273", - "sha256:cb7cd68814308aade9d0c93c5bd2ade9f9441666f8ba5aa9c2d4b389cb5e2a45", - "sha256:cd805513198304026bd379d1d516afbf6c3c13f4382134a2c526b8b854da1c2e", - "sha256:d0bf89afcbcf4d1bb2652f6580e5e55a840fdf87384f6063c4a4f0c95e378656", - "sha256:d9137a876020661972ca6eec0766d81aef8a5627df628b664b234b73396e727e", - "sha256:dbd95e300367aa0827496fe75a1766d198d34385a58f97683fe6e07f89ca3e3c", - "sha256:dced27917823df984fe0c80a5c4ad75cf58df0fbfae890bc08004cd3888922a2", - "sha256:de0b4caa1c8a21394e8ce971997614a17648f94e1cd0640fbd6b4d14cab13a72", - "sha256:debb633f3f7856f95ad957d9b9c781f8e2c6303ef21724ec94bea2ce2fcbd056", - "sha256:e372d7dfd154009142631de2d316adad3cc1c36c32a38b16a4751ba78da2a397", - "sha256:ecd26be9f112c4f96718290c10f4caea6cc798459a3a76636b817a0ed7874e42", - "sha256:edc0202099ea1d82844316604e17d2b175044f9bcb6b398aab781eba957224bd", - "sha256:f194cce575e59ffe442c10a360182a986535fd90b57f7debfaa5c845c409ecc3", - "sha256:f5fb672c396d826ca16a022ac04c9dce74e00a1c344f6ad1a0fdc1ba1f332213", - "sha256:f6a02a3c7950cafaadcd46a226ad9e12fc9744652cc69f9e5534f98b47f3bbcf", - "sha256:fe81b35c33772e56f4b6cf62cf4aedc1762ef7162a31e6ac7fe5e40d0149eb67" - ], - "index": "pypi", - "markers": "python_full_version >= '3.7.0'", - "version": "==3.3.1" - }, - "click": { - "hashes": [ - "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", - "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==8.1.7" - }, - "click-didyoumean": { - "hashes": [ - "sha256:a0713dc7a1de3f06bc0df5a9567ad19ead2d3d5689b434768a6145bff77c0667", - "sha256:f184f0d851d96b6d29297354ed981b7dd71df7ff500d82fa6d11f0856bee8035" - ], - "index": "pypi", - "markers": "python_full_version >= '3.6.2' and python_full_version < '4.0.0'", - "version": "==0.3.0" - }, - "click-plugins": { - "hashes": [ - "sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b", - "sha256:5d262006d3222f5057fd81e1623d4443e41dcda5dc815c06b442aa3c02889fc8" - ], - "index": "pypi", - "version": "==1.1.1" - }, - "click-repl": { - "hashes": [ - "sha256:17849c23dba3d667247dc4defe1757fff98694e90fe37474f3feebb69ced26a9", - "sha256:fb7e06deb8da8de86180a33a9da97ac316751c094c6899382da7feeeeb51b812" - ], - "index": "pypi", - "markers": "python_version >= '3.6'", - "version": "==0.3.0" - }, - "colorama": { - "hashes": [ - "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", - "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" - ], - "index": "pypi", - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'", - "version": "==0.4.6" - }, - "contourpy": { - "hashes": [ - "sha256:031154ed61f7328ad7f97662e48660a150ef84ee1bc8876b6472af88bf5a9b98", - "sha256:0f9d350b639db6c2c233d92c7f213d94d2e444d8e8fc5ca44c9706cf72193772", - "sha256:130230b7e49825c98edf0b428b7aa1125503d91732735ef897786fe5452b1ec2", - "sha256:152fd8f730c31fd67fe0ffebe1df38ab6a669403da93df218801a893645c6ccc", - "sha256:1c71fdd8f1c0f84ffd58fca37d00ca4ebaa9e502fb49825484da075ac0b0b803", - "sha256:24847601071f740837aefb730e01bd169fbcaa610209779a78db7ebb6e6a7051", - "sha256:2e9ebb4425fc1b658e13bace354c48a933b842d53c458f02c86f371cecbedecc", - "sha256:30676ca45084ee61e9c3da589042c24a57592e375d4b138bd84d8709893a1ba4", - "sha256:31a55dccc8426e71817e3fe09b37d6d48ae40aae4ecbc8c7ad59d6893569c436", - "sha256:366a0cf0fc079af5204801786ad7a1c007714ee3909e364dbac1729f5b0849e5", - "sha256:38e2e577f0f092b8e6774459317c05a69935a1755ecfb621c0a98f0e3c09c9a5", - "sha256:3c184ad2433635f216645fdf0493011a4667e8d46b34082f5a3de702b6ec42e3", - "sha256:3caea6365b13119626ee996711ab63e0c9d7496f65641f4459c60a009a1f3e80", - "sha256:3e927b3868bd1e12acee7cc8f3747d815b4ab3e445a28d2e5373a7f4a6e76ba1", - "sha256:4ee3ee247f795a69e53cd91d927146fb16c4e803c7ac86c84104940c7d2cabf0", - "sha256:54d43960d809c4c12508a60b66cb936e7ed57d51fb5e30b513934a4a23874fae", - "sha256:57119b0116e3f408acbdccf9eb6ef19d7fe7baf0d1e9aaa5381489bc1aa56556", - "sha256:58569c491e7f7e874f11519ef46737cea1d6eda1b514e4eb5ac7dab6aa864d02", - "sha256:5a011cf354107b47c58ea932d13b04d93c6d1d69b8b6dce885e642531f847566", - "sha256:5caeacc68642e5f19d707471890f037a13007feba8427eb7f2a60811a1fc1350", - "sha256:5dd34c1ae752515318224cba7fc62b53130c45ac6a1040c8b7c1a223c46e8967", - "sha256:60835badb5ed5f4e194a6f21c09283dd6e007664a86101431bf870d9e86266c4", - "sha256:62398c80ef57589bdbe1eb8537127321c1abcfdf8c5f14f479dbbe27d0322e66", - "sha256:6381fa66866b0ea35e15d197fc06ac3840a9b2643a6475c8fff267db8b9f1e69", - "sha256:64757f6460fc55d7e16ed4f1de193f362104285c667c112b50a804d482777edd", - "sha256:69f8ff4db108815addd900a74df665e135dbbd6547a8a69333a68e1f6e368ac2", - "sha256:6c180d89a28787e4b73b07e9b0e2dac7741261dbdca95f2b489c4f8f887dd810", - "sha256:71b0bf0c30d432278793d2141362ac853859e87de0a7dee24a1cea35231f0d50", - "sha256:769eef00437edf115e24d87f8926955f00f7704bede656ce605097584f9966dc", - "sha256:7f6979d20ee5693a1057ab53e043adffa1e7418d734c1532e2d9e915b08d8ec2", - "sha256:87f4d8941a9564cda3f7fa6a6cd9b32ec575830780677932abdec7bcb61717b0", - "sha256:89ba9bb365446a22411f0673abf6ee1fea3b2cf47b37533b970904880ceb72f3", - "sha256:8acf74b5d383414401926c1598ed77825cd530ac7b463ebc2e4f46638f56cce6", - "sha256:9056c5310eb1daa33fc234ef39ebfb8c8e2533f088bbf0bc7350f70a29bde1ac", - "sha256:95c3acddf921944f241b6773b767f1cbce71d03307270e2d769fd584d5d1092d", - "sha256:9e20e5a1908e18aaa60d9077a6d8753090e3f85ca25da6e25d30dc0a9e84c2c6", - "sha256:a1e97b86f73715e8670ef45292d7cc033548266f07d54e2183ecb3c87598888f", - "sha256:a877ada905f7d69b2a31796c4b66e31a8068b37aa9b78832d41c82fc3e056ddd", - "sha256:a9d7587d2fdc820cc9177139b56795c39fb8560f540bba9ceea215f1f66e1566", - "sha256:abf298af1e7ad44eeb93501e40eb5a67abbf93b5d90e468d01fc0c4451971afa", - "sha256:ae90d5a8590e5310c32a7630b4b8618cef7563cebf649011da80874d0aa8f414", - "sha256:b6d0f9e1d39dbfb3977f9dd79f156c86eb03e57a7face96f199e02b18e58d32a", - "sha256:b8d587cc39057d0afd4166083d289bdeff221ac6d3ee5046aef2d480dc4b503c", - "sha256:c5210e5d5117e9aec8c47d9156d1d3835570dd909a899171b9535cb4a3f32693", - "sha256:cc331c13902d0f50845099434cd936d49d7a2ca76cb654b39691974cb1e4812d", - "sha256:ce41676b3d0dd16dbcfabcc1dc46090aaf4688fd6e819ef343dbda5a57ef0161", - "sha256:d8165a088d31798b59e91117d1f5fc3df8168d8b48c4acc10fc0df0d0bdbcc5e", - "sha256:e7281244c99fd7c6f27c1c6bfafba878517b0b62925a09b586d88ce750a016d2", - "sha256:e96a08b62bb8de960d3a6afbc5ed8421bf1a2d9c85cc4ea73f4bc81b4910500f", - "sha256:ed33433fc3820263a6368e532f19ddb4c5990855e4886088ad84fd7c4e561c71", - "sha256:efb8f6d08ca7998cf59eaf50c9d60717f29a1a0a09caa46460d33b2924839dbd", - "sha256:efe99298ba37e37787f6a2ea868265465410822f7bea163edcc1bd3903354ea9", - "sha256:f99e9486bf1bb979d95d5cffed40689cb595abb2b841f2991fc894b3452290e8", - "sha256:fc1464c97579da9f3ab16763c32e5c5d5bb5fa1ec7ce509a4ca6108b61b84fab", - "sha256:fd7dc0e6812b799a34f6d12fcb1000539098c249c8da54f3566c6a6461d0dbad" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==1.0.7" - }, - "couchdb": { - "hashes": [ - "sha256:1386a1a43f25bed3667e3b805222054940d674fa1967fa48e9d2012a18630ab7", - "sha256:13a28a1159c49f8346732e8724b9a4d65cba54bec017c4a7eeb1499fe88151d1" - ], - "index": "pypi", - "version": "==1.2" - }, - "crispy-bootstrap4": { - "hashes": [ - "sha256:5241ab1dc2188c95560aa786439bcbedec7416e6b0f5a52dded82380810367ec", - "sha256:f18386c4d96180c1bb1212487d6e8f5a3dd1a9bb58d3032183973d4d130b55f9" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==2022.1" - }, - "cryptography": { - "hashes": [ - "sha256:0c327cac00f082013c7c9fb6c46b7cc9fa3c288ca702c74773968173bda421bf", - "sha256:0d2a6a598847c46e3e321a7aef8af1436f11c27f1254933746304ff014664d84", - "sha256:227ec057cd32a41c6651701abc0328135e472ed450f47c2766f23267b792a88e", - "sha256:22892cc830d8b2c89ea60148227631bb96a7da0c1b722f2aac8824b1b7c0b6b8", - "sha256:392cb88b597247177172e02da6b7a63deeff1937fa6fec3bbf902ebd75d97ec7", - "sha256:3be3ca726e1572517d2bef99a818378bbcf7d7799d5372a46c79c29eb8d166c1", - "sha256:573eb7128cbca75f9157dcde974781209463ce56b5804983e11a1c462f0f4e88", - "sha256:580afc7b7216deeb87a098ef0674d6ee34ab55993140838b14c9b83312b37b86", - "sha256:5a70187954ba7292c7876734183e810b728b4f3965fbe571421cb2434d279179", - "sha256:73801ac9736741f220e20435f84ecec75ed70eda90f781a148f1bad546963d81", - "sha256:7d208c21e47940369accfc9e85f0de7693d9a5d843c2509b3846b2db170dfd20", - "sha256:8254962e6ba1f4d2090c44daf50a547cd5f0bf446dc658a8e5f8156cae0d8548", - "sha256:88417bff20162f635f24f849ab182b092697922088b477a7abd6664ddd82291d", - "sha256:a48e74dad1fb349f3dc1d449ed88e0017d792997a7ad2ec9587ed17405667e6d", - "sha256:b948e09fe5fb18517d99994184854ebd50b57248736fd4c720ad540560174ec5", - "sha256:c707f7afd813478e2019ae32a7c49cd932dd60ab2d2a93e796f68236b7e1fbf1", - "sha256:d38e6031e113b7421db1de0c1b1f7739564a88f1684c6b89234fbf6c11b75147", - "sha256:d3977f0e276f6f5bf245c403156673db103283266601405376f075c849a0b936", - "sha256:da6a0ff8f1016ccc7477e6339e1d50ce5f59b88905585f77193ebd5068f1e797", - "sha256:e270c04f4d9b5671ebcc792b3ba5d4488bf7c42c3c241a3748e2599776f29696", - "sha256:e886098619d3815e0ad5790c973afeee2c0e6e04b4da90b88e6bd06e2a0b1b72", - "sha256:ec3b055ff8f1dce8e6ef28f626e0972981475173d7973d63f271b29c8a2897da", - "sha256:fba1e91467c65fe64a82c689dc6cf58151158993b13eb7a7f3f4b7f395636723" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==41.0.5" - }, - "cycler": { - "hashes": [ - "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3", - "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f" - ], - "index": "pypi", - "markers": "python_version >= '3.6'", - "version": "==0.11.0" - }, - "defusedxml": { - "hashes": [ - "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", - "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61" - ], - "index": "pypi", - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==0.7.1" - }, - "discord": { - "hashes": [ - "sha256:cc1ee2dbe6df218ca51519af355b97e87309f8230f58c7f34885feb8e8a76145", - "sha256:d7959418799dd3b1e896685812d880169c193468b061b3431fa2a4664febd3da" - ], - "index": "pypi", - "version": "==2.3.2" - }, - "discord.py": { - "hashes": [ - "sha256:4560f70f2eddba7e83370ecebd237ac09fbb4980dc66507482b0c0e5b8f76b9c", - "sha256:9da4679fc3cb10c64b388284700dc998663e0e57328283bbfcfc2525ec5960a6" - ], - "markers": "python_full_version >= '3.8.0'", - "version": "==2.3.2" - }, - "django": { - "hashes": [ - "sha256:6e6ff3db2d8dd0c986b4eec8554c8e4f919b5c1ff62a5b4390c17aff2ed6e5c4", - "sha256:ddc24a0a8280a0430baa37aff11f28574720af05888c62b7cfe71d219f4599d3" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==4.2.11" - }, - "django-ajax": { - "hashes": [ - "sha256:f45a4c5b0240a0c5e0e088e056e71ec3b381bbd8fa2e6b2bc307c9ff6b64bf33" - ], - "index": "pypi", - "version": "==0.3.0" - }, - "django-appconf": { - "hashes": [ - "sha256:ae9f864ee1958c815a965ed63b3fba4874eec13de10236ba063a788f9a17389d", - "sha256:be3db0be6c81fa84742000b89a81c016d70ae66a7ccb620cdef592b1f1a6aaa4" - ], - "index": "pypi", - "markers": "python_version >= '3.6'", - "version": "==1.0.5" - }, - "django-bootstrap-modal-forms": { - "hashes": [ - "sha256:47a4f303724182a5e4958da94772f5a6a7359fac6d6ae204442aadfd56c03133", - "sha256:ff33b9b89608c8bcb9eba811524e9fb7ec1c843a73bd78a7d38fbb94cc9bdd4a" - ], - "index": "pypi", - "version": "==3.0.4" - }, - "django-compressor": { - "hashes": [ - "sha256:1b0acc9cfba9f69bc38e7c41da9b0d70a20bc95587b643ffef9609cf46064f67", - "sha256:6e2b0c0becb9607f5099c2546a824c5b84a6918a34bc37a8a622ffa250313596" - ], - "index": "pypi", - "version": "==4.4" - }, - "django-crispy-forms": { - "hashes": [ - "sha256:90193b068bf948d9c68449bc8260afed1a8e2afe11ee0bac8c4ebfaeb175b322", - "sha256:d1d4e585929058a9ab3b797666ea5b69320b9ba7937f9d146d32173246a6fd13" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==2.0" - }, - "django-cron": { - "hashes": [ - "sha256:016203554748512b7f19d7363b4fde8741c6ff63fe8a15051f3031f4a0506a41", - "sha256:dc3c0d3433a2e4e7012f77f6d8415ad90367ba068649db2674325bc36f935841" - ], - "index": "pypi", - "version": "==0.6.0" - }, - "django-crontab": { - "hashes": [ - "sha256:1201810a212460aaaa48eb6a766738740daf42c1a4f6aafecfb1525036929236" - ], - "index": "pypi", - "version": "==0.7.1" - }, - "django-libsass": { - "hashes": [ - "sha256:5234d29100889cac79e36a0f44207ec6d275adfd2da1acb6a94b55c89fe2bd97", - "sha256:bfbbb55a8950bb40fa04dd416605f92da34ad1f303b10a41abc3232386ec27b5" - ], - "index": "pypi", - "version": "==0.9" - }, - "django-taggit": { - "hashes": [ - "sha256:4d52de9d37245a9b9f98c0ec71fdccf1d2283e38e8866d40a7ae6a3b6787a161", - "sha256:eb800dabef5f0a4e047ab0751f82cf805bc4a9e972037ef12bf519f52cd92480" - ], - "index": "pypi", - "markers": "python_version >= '3.6'", - "version": "==4.0.0" - }, - "django-timezone-field": { - "hashes": [ - "sha256:916d0fd924443462f099f02122cc38d6a6e901ea17f1206c343836199df8bc49", - "sha256:ed28d3ff8e3500f2bc173cdf1aab7a3244ef607d06ad890611512de1bae6074d" - ], - "index": "pypi", - "markers": "python_version >= '3.8' and python_version < '4.0'", - "version": "==6.0.1" - }, - "djangorestframework": { - "hashes": [ - "sha256:579a333e6256b09489cbe0a067e66abe55c6595d8926be6b99423786334350c8", - "sha256:eb63f58c9f218e1a7d064d17a70751f528ed4e1d35547fdade9aaf4cd103fd08" - ], - "index": "pypi", - "markers": "python_version >= '3.6'", - "version": "==3.14.0" - }, - "executing": { - "hashes": [ - "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147", - "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc" - ], - "markers": "python_version >= '3.5'", - "version": "==2.0.1" - }, - "flower": { - "hashes": [ - "sha256:5ab717b979530770c16afb48b50d2a98d23c3e9fe39851dcf6bc4d01845a02a0", - "sha256:9db2c621eeefbc844c8dd88be64aef61e84e2deb29b271e02ab2b5b9f01068e2" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==2.0.1" - }, - "fonttools": { - "hashes": [ - "sha256:106caf6167c4597556b31a8d9175a3fdc0356fdcd70ab19973c3b0d4c893c461", - "sha256:dba8d7cdb8e2bac1b3da28c5ed5960de09e59a2fe7e63bb73f5a59e57b0430d2" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==4.39.4" - }, - "frozenlist": { - "hashes": [ - "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7", - "sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98", - "sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad", - "sha256:0c250a29735d4f15321007fb02865f0e6b6a41a6b88f1f523ca1596ab5f50bd5", - "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae", - "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e", - "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a", - "sha256:1d0ce09d36d53bbbe566fe296965b23b961764c0bcf3ce2fa45f463745c04701", - "sha256:20b51fa3f588ff2fe658663db52a41a4f7aa6c04f6201449c6c7c476bd255c0d", - "sha256:23b2d7679b73fe0e5a4560b672a39f98dfc6f60df63823b0a9970525325b95f6", - "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6", - "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106", - "sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75", - "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868", - "sha256:32453c1de775c889eb4e22f1197fe3bdfe457d16476ea407472b9442e6295f7a", - "sha256:3a670dc61eb0d0eb7080890c13de3066790f9049b47b0de04007090807c776b0", - "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1", - "sha256:410478a0c562d1a5bcc2f7ea448359fcb050ed48b3c6f6f4f18c313a9bdb1826", - "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec", - "sha256:48f6a4533887e189dae092f1cf981f2e3885175f7a0f33c91fb5b7b682b6bab6", - "sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950", - "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19", - "sha256:55fdc093b5a3cb41d420884cdaf37a1e74c3c37a31f46e66286d9145d2063bd0", - "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8", - "sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a", - "sha256:5a7d70357e7cee13f470c7883a063aae5fe209a493c57d86eb7f5a6f910fae09", - "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86", - "sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c", - "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5", - "sha256:693945278a31f2086d9bf3df0fe8254bbeaef1fe71e1351c3bd730aa7d31c41b", - "sha256:6db4667b187a6742b33afbbaf05a7bc551ffcf1ced0000a571aedbb4aa42fc7b", - "sha256:6eb73fa5426ea69ee0e012fb59cdc76a15b1283d6e32e4f8dc4482ec67d1194d", - "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0", - "sha256:7268252af60904bf52c26173cbadc3a071cece75f873705419c8681f24d3edea", - "sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776", - "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a", - "sha256:82e8211d69a4f4bc360ea22cd6555f8e61a1bd211d1d5d39d3d228b48c83a897", - "sha256:89aa2c2eeb20957be2d950b85974b30a01a762f3308cd02bb15e1ad632e22dc7", - "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09", - "sha256:96ec70beabbd3b10e8bfe52616a13561e58fe84c0101dd031dc78f250d5128b9", - "sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe", - "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd", - "sha256:9d3e0c25a2350080e9319724dede4f31f43a6c9779be48021a7f4ebde8b2d742", - "sha256:a06339f38e9ed3a64e4c4e43aec7f59084033647f908e4259d279a52d3757d09", - "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0", - "sha256:a7496bfe1da7fb1a4e1cc23bb67c58fab69311cc7d32b5a99c2007b4b2a0e932", - "sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1", - "sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a", - "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49", - "sha256:b7e3ed87d4138356775346e6845cccbe66cd9e207f3cd11d2f0b9fd13681359d", - "sha256:b7f2f9f912dca3934c1baec2e4585a674ef16fe00218d833856408c48d5beee7", - "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480", - "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89", - "sha256:bfa4a17e17ce9abf47a74ae02f32d014c5e9404b6d9ac7f729e01562bbee601e", - "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b", - "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82", - "sha256:c6321c9efe29975232da3bd0af0ad216800a47e93d763ce64f291917a381b8eb", - "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068", - "sha256:c99169d4ff810155ca50b4da3b075cbde79752443117d89429595c2e8e37fed8", - "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b", - "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb", - "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2", - "sha256:dca69045298ce5c11fd539682cff879cc1e664c245d1c64da929813e54241d11", - "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b", - "sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc", - "sha256:e6a20a581f9ce92d389a8c7d7c3dd47c81fd5d6e655c8dddf341e14aa48659d0", - "sha256:e7004be74cbb7d9f34553a5ce5fb08be14fb33bc86f332fb71cbe5216362a497", - "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17", - "sha256:edb678da49d9f72c9f6c609fbe41a5dfb9a9282f9e6a2253d5a91e0fc382d7c0", - "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2", - "sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439", - "sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5", - "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac", - "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825", - "sha256:fbeb989b5cc29e8daf7f976b421c220f1b8c731cbf22b9130d8815418ea45887", - "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced", - "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74" - ], - "markers": "python_version >= '3.8'", - "version": "==1.4.1" - }, - "httplib2": { - "hashes": [ - "sha256:14ae0a53c1ba8f3d37e9e27cf37eabb0fb9980f435ba405d546948b009dd64dc", - "sha256:d7a10bc5ef5ab08322488bde8c726eeee5c8618723fdb399597ec58f3d82df81" - ], - "index": "pypi", - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.22.0" - }, - "humanize": { - "hashes": [ - "sha256:582a265c931c683a7e9b8ed9559089dea7edcf6cc95be39a3cbc2c5d5ac2bcfa", - "sha256:ce284a76d5b1377fd8836733b983bfb0b76f1aa1c090de2566fcf008d7f6ab16" - ], - "markers": "python_version >= '3.8'", - "version": "==4.9.0" - }, - "icecream": { - "hashes": [ - "sha256:0aa4a7c3374ec36153a1d08f81e3080e83d8ac1eefd97d2f4fe9544e8f9b49de", - "sha256:757aec31ad4488b949bc4f499d18e6e5973c40cc4d4fc607229e78cfaec94c34" - ], - "index": "pypi", - "version": "==2.1.3" - }, - "idna": { - "hashes": [ - "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", - "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2" - ], - "index": "pypi", - "markers": "python_version >= '3.5'", - "version": "==3.4" - }, - "kiwisolver": { - "hashes": [ - "sha256:02f79693ec433cb4b5f51694e8477ae83b3205768a6fb48ffba60549080e295b", - "sha256:03baab2d6b4a54ddbb43bba1a3a2d1627e82d205c5cf8f4c924dc49284b87166", - "sha256:1041feb4cda8708ce73bb4dcb9ce1ccf49d553bf87c3954bdfa46f0c3f77252c", - "sha256:10ee06759482c78bdb864f4109886dff7b8a56529bc1609d4f1112b93fe6423c", - "sha256:1d1573129aa0fd901076e2bfb4275a35f5b7aa60fbfb984499d661ec950320b0", - "sha256:283dffbf061a4ec60391d51e6155e372a1f7a4f5b15d59c8505339454f8989e4", - "sha256:28bc5b299f48150b5f822ce68624e445040595a4ac3d59251703779836eceff9", - "sha256:2a66fdfb34e05b705620dd567f5a03f239a088d5a3f321e7b6ac3239d22aa286", - "sha256:2e307eb9bd99801f82789b44bb45e9f541961831c7311521b13a6c85afc09767", - "sha256:2e407cb4bd5a13984a6c2c0fe1845e4e41e96f183e5e5cd4d77a857d9693494c", - "sha256:2f5e60fabb7343a836360c4f0919b8cd0d6dbf08ad2ca6b9cf90bf0c76a3c4f6", - "sha256:36dafec3d6d6088d34e2de6b85f9d8e2324eb734162fba59d2ba9ed7a2043d5b", - "sha256:3fe20f63c9ecee44560d0e7f116b3a747a5d7203376abeea292ab3152334d004", - "sha256:41dae968a94b1ef1897cb322b39360a0812661dba7c682aa45098eb8e193dbdf", - "sha256:4bd472dbe5e136f96a4b18f295d159d7f26fd399136f5b17b08c4e5f498cd494", - "sha256:4ea39b0ccc4f5d803e3337dd46bcce60b702be4d86fd0b3d7531ef10fd99a1ac", - "sha256:5853eb494c71e267912275e5586fe281444eb5e722de4e131cddf9d442615626", - "sha256:5bce61af018b0cb2055e0e72e7d65290d822d3feee430b7b8203d8a855e78766", - "sha256:6295ecd49304dcf3bfbfa45d9a081c96509e95f4b9d0eb7ee4ec0530c4a96514", - "sha256:62ac9cc684da4cf1778d07a89bf5f81b35834cb96ca523d3a7fb32509380cbf6", - "sha256:70e7c2e7b750585569564e2e5ca9845acfaa5da56ac46df68414f29fea97be9f", - "sha256:7577c1987baa3adc4b3c62c33bd1118c3ef5c8ddef36f0f2c950ae0b199e100d", - "sha256:75facbe9606748f43428fc91a43edb46c7ff68889b91fa31f53b58894503a191", - "sha256:787518a6789009c159453da4d6b683f468ef7a65bbde796bcea803ccf191058d", - "sha256:78d6601aed50c74e0ef02f4204da1816147a6d3fbdc8b3872d263338a9052c51", - "sha256:7c43e1e1206cd421cd92e6b3280d4385d41d7166b3ed577ac20444b6995a445f", - "sha256:81e38381b782cc7e1e46c4e14cd997ee6040768101aefc8fa3c24a4cc58e98f8", - "sha256:841293b17ad704d70c578f1f0013c890e219952169ce8a24ebc063eecf775454", - "sha256:872b8ca05c40d309ed13eb2e582cab0c5a05e81e987ab9c521bf05ad1d5cf5cb", - "sha256:877272cf6b4b7e94c9614f9b10140e198d2186363728ed0f701c6eee1baec1da", - "sha256:8c808594c88a025d4e322d5bb549282c93c8e1ba71b790f539567932722d7bd8", - "sha256:8ed58b8acf29798b036d347791141767ccf65eee7f26bde03a71c944449e53de", - "sha256:91672bacaa030f92fc2f43b620d7b337fd9a5af28b0d6ed3f77afc43c4a64b5a", - "sha256:968f44fdbf6dd757d12920d63b566eeb4d5b395fd2d00d29d7ef00a00582aac9", - "sha256:9f85003f5dfa867e86d53fac6f7e6f30c045673fa27b603c397753bebadc3008", - "sha256:a553dadda40fef6bfa1456dc4be49b113aa92c2a9a9e8711e955618cd69622e3", - "sha256:a68b62a02953b9841730db7797422f983935aeefceb1679f0fc85cbfbd311c32", - "sha256:abbe9fa13da955feb8202e215c4018f4bb57469b1b78c7a4c5c7b93001699938", - "sha256:ad881edc7ccb9d65b0224f4e4d05a1e85cf62d73aab798943df6d48ab0cd79a1", - "sha256:b1792d939ec70abe76f5054d3f36ed5656021dcad1322d1cc996d4e54165cef9", - "sha256:b428ef021242344340460fa4c9185d0b1f66fbdbfecc6c63eff4b7c29fad429d", - "sha256:b533558eae785e33e8c148a8d9921692a9fe5aa516efbdff8606e7d87b9d5824", - "sha256:ba59c92039ec0a66103b1d5fe588fa546373587a7d68f5c96f743c3396afc04b", - "sha256:bc8d3bd6c72b2dd9decf16ce70e20abcb3274ba01b4e1c96031e0c4067d1e7cd", - "sha256:bc9db8a3efb3e403e4ecc6cd9489ea2bac94244f80c78e27c31dcc00d2790ac2", - "sha256:bf7d9fce9bcc4752ca4a1b80aabd38f6d19009ea5cbda0e0856983cf6d0023f5", - "sha256:c2dbb44c3f7e6c4d3487b31037b1bdbf424d97687c1747ce4ff2895795c9bf69", - "sha256:c79ebe8f3676a4c6630fd3f777f3cfecf9289666c84e775a67d1d358578dc2e3", - "sha256:c97528e64cb9ebeff9701e7938653a9951922f2a38bd847787d4a8e498cc83ae", - "sha256:d0611a0a2a518464c05ddd5a3a1a0e856ccc10e67079bb17f265ad19ab3c7597", - "sha256:d06adcfa62a4431d404c31216f0f8ac97397d799cd53800e9d3efc2fbb3cf14e", - "sha256:d41997519fcba4a1e46eb4a2fe31bc12f0ff957b2b81bac28db24744f333e955", - "sha256:d5b61785a9ce44e5a4b880272baa7cf6c8f48a5180c3e81c59553ba0cb0821ca", - "sha256:da152d8cdcab0e56e4f45eb08b9aea6455845ec83172092f09b0e077ece2cf7a", - "sha256:da7e547706e69e45d95e116e6939488d62174e033b763ab1496b4c29b76fabea", - "sha256:db5283d90da4174865d520e7366801a93777201e91e79bacbac6e6927cbceede", - "sha256:db608a6757adabb32f1cfe6066e39b3706d8c3aa69bbc353a5b61edad36a5cb4", - "sha256:e0ea21f66820452a3f5d1655f8704a60d66ba1191359b96541eaf457710a5fc6", - "sha256:e7da3fec7408813a7cebc9e4ec55afed2d0fd65c4754bc376bf03498d4e92686", - "sha256:e92a513161077b53447160b9bd8f522edfbed4bd9759e4c18ab05d7ef7e49408", - "sha256:ecb1fa0db7bf4cff9dac752abb19505a233c7f16684c5826d1f11ebd9472b871", - "sha256:efda5fc8cc1c61e4f639b8067d118e742b812c930f708e6667a5ce0d13499e29", - "sha256:f0a1dbdb5ecbef0d34eb77e56fcb3e95bbd7e50835d9782a45df81cc46949750", - "sha256:f0a71d85ecdd570ded8ac3d1c0f480842f49a40beb423bb8014539a9f32a5897", - "sha256:f4f270de01dd3e129a72efad823da90cc4d6aafb64c410c9033aba70db9f1ff0", - "sha256:f6cb459eea32a4e2cf18ba5fcece2dbdf496384413bc1bae15583f19e567f3b2", - "sha256:f8ad8285b01b0d4695102546b342b493b3ccc6781fc28c8c6a1bb63e95d22f09", - "sha256:f9f39e2f049db33a908319cf46624a569b36983c7c78318e9726a4cb8923b26c" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==1.4.4" - }, - "kombu": { - "hashes": [ - "sha256:0ba213f630a2cb2772728aef56ac6883dc3a2f13435e10048f6e97d48506dbbd", - "sha256:b753c9cfc9b1e976e637a7cbc1a65d446a22e45546cd996ea28f932082b7dc9e" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==5.3.2" - }, - "libsass": { - "hashes": [ - "sha256:081e256ab3c5f3f09c7b8dea3bf3bf5e64a97c6995fd9eea880639b3f93a9f9a", - "sha256:3ab5ad18e47db560f4f0c09e3d28cf3bb1a44711257488ac2adad69f4f7f8425", - "sha256:5fb2297a4754a6c8e25cfe5c015a3b51a2b6b9021b333f989bb8ce9d60eb5828", - "sha256:65455a2728b696b62100eb5932604aa13a29f4ac9a305d95773c14aaa7200aaf", - "sha256:89c5ce497fcf3aba1dd1b19aae93b99f68257e5f2026b731b00a872f13324c7f", - "sha256:f1efc1b612299c88aec9e39d6ca0c266d360daa5b19d9430bdeaffffa86993f9" - ], - "index": "pypi", - "markers": "python_version >= '3.6'", - "version": "==0.22.0" - }, - "multidict": { - "hashes": [ - "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556", - "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c", - "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29", - "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b", - "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8", - "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7", - "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd", - "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40", - "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6", - "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3", - "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c", - "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9", - "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5", - "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae", - "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442", - "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9", - "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc", - "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c", - "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea", - "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5", - "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50", - "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182", - "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453", - "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e", - "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600", - "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733", - "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda", - "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241", - "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461", - "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e", - "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e", - "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b", - "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e", - "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7", - "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386", - "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd", - "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9", - "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf", - "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee", - "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5", - "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a", - "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271", - "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54", - "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4", - "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496", - "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb", - "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319", - "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3", - "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f", - "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527", - "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed", - "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604", - "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef", - "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8", - "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5", - "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5", - "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626", - "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c", - "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d", - "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c", - "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc", - "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc", - "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b", - "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38", - "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450", - "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1", - "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f", - "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3", - "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755", - "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226", - "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a", - "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046", - "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf", - "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479", - "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e", - "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1", - "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a", - "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83", - "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929", - "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93", - "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a", - "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c", - "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44", - "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89", - "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba", - "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e", - "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da", - "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24", - "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423", - "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef" - ], - "markers": "python_version >= '3.7'", - "version": "==6.0.5" - }, - "numpy": { - "hashes": [ - "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b", - "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818", - "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20", - "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0", - "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", - "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a", - "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea", - "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c", - "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71", - "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110", - "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be", - "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a", - "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a", - "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5", - "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed", - "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd", - "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c", - "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e", - "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0", - "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c", - "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a", - "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b", - "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", - "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6", - "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2", - "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a", - "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30", - "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218", - "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5", - "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07", - "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2", - "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4", - "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764", - "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef", - "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3", - "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f" - ], - "markers": "python_version >= '3.9'", - "version": "==1.26.4" - }, - "oauthlib": { - "hashes": [ - "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca", - "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918" - ], - "index": "pypi", - "markers": "python_version >= '3.6'", - "version": "==3.2.2" - }, - "packaging": { - "hashes": [ - "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61", - "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==23.1" - }, - "pillow": { - "hashes": [ - "sha256:07999f5834bdc404c442146942a2ecadd1cb6292f5229f4ed3b31e0a108746b1", - "sha256:0852ddb76d85f127c135b6dd1f0bb88dbb9ee990d2cd9aa9e28526c93e794fba", - "sha256:1781a624c229cb35a2ac31cc4a77e28cafc8900733a864870c49bfeedacd106a", - "sha256:1e7723bd90ef94eda669a3c2c19d549874dd5badaeefabefd26053304abe5799", - "sha256:229e2c79c00e85989a34b5981a2b67aa079fd08c903f0aaead522a1d68d79e51", - "sha256:22baf0c3cf0c7f26e82d6e1adf118027afb325e703922c8dfc1d5d0156bb2eeb", - "sha256:252a03f1bdddce077eff2354c3861bf437c892fb1832f75ce813ee94347aa9b5", - "sha256:2dfaaf10b6172697b9bceb9a3bd7b951819d1ca339a5ef294d1f1ac6d7f63270", - "sha256:322724c0032af6692456cd6ed554bb85f8149214d97398bb80613b04e33769f6", - "sha256:35f6e77122a0c0762268216315bf239cf52b88865bba522999dc38f1c52b9b47", - "sha256:375f6e5ee9620a271acb6820b3d1e94ffa8e741c0601db4c0c4d3cb0a9c224bf", - "sha256:3ded42b9ad70e5f1754fb7c2e2d6465a9c842e41d178f262e08b8c85ed8a1d8e", - "sha256:432b975c009cf649420615388561c0ce7cc31ce9b2e374db659ee4f7d57a1f8b", - "sha256:482877592e927fd263028c105b36272398e3e1be3269efda09f6ba21fd83ec66", - "sha256:489f8389261e5ed43ac8ff7b453162af39c3e8abd730af8363587ba64bb2e865", - "sha256:54f7102ad31a3de5666827526e248c3530b3a33539dbda27c6843d19d72644ec", - "sha256:560737e70cb9c6255d6dcba3de6578a9e2ec4b573659943a5e7e4af13f298f5c", - "sha256:5671583eab84af046a397d6d0ba25343c00cd50bce03787948e0fff01d4fd9b1", - "sha256:5ba1b81ee69573fe7124881762bb4cd2e4b6ed9dd28c9c60a632902fe8db8b38", - "sha256:5d4ebf8e1db4441a55c509c4baa7a0587a0210f7cd25fcfe74dbbce7a4bd1906", - "sha256:60037a8db8750e474af7ffc9faa9b5859e6c6d0a50e55c45576bf28be7419705", - "sha256:608488bdcbdb4ba7837461442b90ea6f3079397ddc968c31265c1e056964f1ef", - "sha256:6608ff3bf781eee0cd14d0901a2b9cc3d3834516532e3bd673a0a204dc8615fc", - "sha256:662da1f3f89a302cc22faa9f14a262c2e3951f9dbc9617609a47521c69dd9f8f", - "sha256:7002d0797a3e4193c7cdee3198d7c14f92c0836d6b4a3f3046a64bd1ce8df2bf", - "sha256:763782b2e03e45e2c77d7779875f4432e25121ef002a41829d8868700d119392", - "sha256:77165c4a5e7d5a284f10a6efaa39a0ae8ba839da344f20b111d62cc932fa4e5d", - "sha256:7c9af5a3b406a50e313467e3565fc99929717f780164fe6fbb7704edba0cebbe", - "sha256:7ec6f6ce99dab90b52da21cf0dc519e21095e332ff3b399a357c187b1a5eee32", - "sha256:833b86a98e0ede388fa29363159c9b1a294b0905b5128baf01db683672f230f5", - "sha256:84a6f19ce086c1bf894644b43cd129702f781ba5751ca8572f08aa40ef0ab7b7", - "sha256:8507eda3cd0608a1f94f58c64817e83ec12fa93a9436938b191b80d9e4c0fc44", - "sha256:85ec677246533e27770b0de5cf0f9d6e4ec0c212a1f89dfc941b64b21226009d", - "sha256:8aca1152d93dcc27dc55395604dcfc55bed5f25ef4c98716a928bacba90d33a3", - "sha256:8d935f924bbab8f0a9a28404422da8af4904e36d5c33fc6f677e4c4485515625", - "sha256:8f36397bf3f7d7c6a3abdea815ecf6fd14e7fcd4418ab24bae01008d8d8ca15e", - "sha256:91ec6fe47b5eb5a9968c79ad9ed78c342b1f97a091677ba0e012701add857829", - "sha256:965e4a05ef364e7b973dd17fc765f42233415974d773e82144c9bbaaaea5d089", - "sha256:96e88745a55b88a7c64fa49bceff363a1a27d9a64e04019c2281049444a571e3", - "sha256:99eb6cafb6ba90e436684e08dad8be1637efb71c4f2180ee6b8f940739406e78", - "sha256:9adf58f5d64e474bed00d69bcd86ec4bcaa4123bfa70a65ce72e424bfb88ed96", - "sha256:9b1af95c3a967bf1da94f253e56b6286b50af23392a886720f563c547e48e964", - "sha256:a0aa9417994d91301056f3d0038af1199eb7adc86e646a36b9e050b06f526597", - "sha256:a0f9bb6c80e6efcde93ffc51256d5cfb2155ff8f78292f074f60f9e70b942d99", - "sha256:a127ae76092974abfbfa38ca2d12cbeddcdeac0fb71f9627cc1135bedaf9d51a", - "sha256:aaf305d6d40bd9632198c766fb64f0c1a83ca5b667f16c1e79e1661ab5060140", - "sha256:aca1c196f407ec7cf04dcbb15d19a43c507a81f7ffc45b690899d6a76ac9fda7", - "sha256:ace6ca218308447b9077c14ea4ef381ba0b67ee78d64046b3f19cf4e1139ad16", - "sha256:b416f03d37d27290cb93597335a2f85ed446731200705b22bb927405320de903", - "sha256:bf548479d336726d7a0eceb6e767e179fbde37833ae42794602631a070d630f1", - "sha256:c1170d6b195555644f0616fd6ed929dfcf6333b8675fcca044ae5ab110ded296", - "sha256:c380b27d041209b849ed246b111b7c166ba36d7933ec6e41175fd15ab9eb1572", - "sha256:c446d2245ba29820d405315083d55299a796695d747efceb5717a8b450324115", - "sha256:c830a02caeb789633863b466b9de10c015bded434deb3ec87c768e53752ad22a", - "sha256:cb841572862f629b99725ebaec3287fc6d275be9b14443ea746c1dd325053cbd", - "sha256:cfa4561277f677ecf651e2b22dc43e8f5368b74a25a8f7d1d4a3a243e573f2d4", - "sha256:cfcc2c53c06f2ccb8976fb5c71d448bdd0a07d26d8e07e321c103416444c7ad1", - "sha256:d3c6b54e304c60c4181da1c9dadf83e4a54fd266a99c70ba646a9baa626819eb", - "sha256:d3d403753c9d5adc04d4694d35cf0391f0f3d57c8e0030aac09d7678fa8030aa", - "sha256:d9c206c29b46cfd343ea7cdfe1232443072bbb270d6a46f59c259460db76779a", - "sha256:e49eb4e95ff6fd7c0c402508894b1ef0e01b99a44320ba7d8ecbabefddcc5569", - "sha256:f8286396b351785801a976b1e85ea88e937712ee2c3ac653710a4a57a8da5d9c", - "sha256:f8fc330c3370a81bbf3f88557097d1ea26cd8b019d6433aa59f71195f5ddebbf", - "sha256:fbd359831c1657d69bb81f0db962905ee05e5e9451913b18b831febfe0519082", - "sha256:fe7e1c262d3392afcf5071df9afa574544f28eac825284596ac6db56e6d11062", - "sha256:fed1e1cf6a42577953abbe8e6cf2fe2f566daebde7c34724ec8803c4c0cda579" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==9.5.0" - }, - "prometheus-client": { - "hashes": [ - "sha256:287629d00b147a32dcb2be0b9df905da599b2d82f80377083ec8463309a4bb89", - "sha256:cde524a85bce83ca359cc837f28b8c0db5cac7aa653a588fd7e84ba061c329e7" - ], - "markers": "python_version >= '3.8'", - "version": "==0.20.0" - }, - "prompt-toolkit": { - "hashes": [ - "sha256:04505ade687dc26dc4284b1ad19a83be2f2afe83e7a828ace0c72f3a1df72aac", - "sha256:9dffbe1d8acf91e3de75f3b544e4842382fc06c6babe903ac9acb74dc6e08d88" - ], - "index": "pypi", - "markers": "python_full_version >= '3.7.0'", - "version": "==3.0.39" - }, - "psycopg2": { - "hashes": [ - "sha256:11aca705ec888e4f4cea97289a0bf0f22a067a32614f6ef64fcf7b8bfbc53744", - "sha256:1861a53a6a0fd248e42ea37c957d36950da00266378746588eab4f4b5649e95f", - "sha256:2362ee4d07ac85ff0ad93e22c693d0f37ff63e28f0615a16b6635a645f4b9214", - "sha256:36c941a767341d11549c0fbdbb2bf5be2eda4caf87f65dfcd7d146828bd27f39", - "sha256:53f4ad0a3988f983e9b49a5d9765d663bbe84f508ed655affdb810af9d0972ad", - "sha256:869776630c04f335d4124f120b7fb377fe44b0a7645ab3c34b4ba42516951889", - "sha256:a8ad4a47f42aa6aec8d061fdae21eaed8d864d4bb0f0cade5ad32ca16fcd6258", - "sha256:b81fcb9ecfc584f661b71c889edeae70bae30d3ef74fa0ca388ecda50b1222b7", - "sha256:d24ead3716a7d093b90b27b3d73459fe8cd90fd7065cf43b3c40966221d8c394", - "sha256:ded2faa2e6dfb430af7713d87ab4abbfc764d8d7fb73eafe96a24155f906ebf5", - "sha256:f15158418fd826831b28585e2ab48ed8df2d0d98f502a2b4fe619e7d5ca29011", - "sha256:f75001a1cbbe523e00b0ef896a5a1ada2da93ccd752b7636db5a99bc57c44494", - "sha256:f7a7a5ee78ba7dc74265ba69e010ae89dae635eea0e97b055fb641a01a31d2b1" - ], - "index": "pypi", - "markers": "python_version >= '3.6'", - "version": "==2.9.6" - }, - "psycopg2-binary": { - "hashes": [ - "sha256:03ef7df18daf2c4c07e2695e8cfd5ee7f748a1d54d802330985a78d2a5a6dca9", - "sha256:0a602ea5aff39bb9fac6308e9c9d82b9a35c2bf288e184a816002c9fae930b77", - "sha256:0c009475ee389757e6e34611d75f6e4f05f0cf5ebb76c6037508318e1a1e0d7e", - "sha256:0ef4854e82c09e84cc63084a9e4ccd6d9b154f1dbdd283efb92ecd0b5e2b8c84", - "sha256:1236ed0952fbd919c100bc839eaa4a39ebc397ed1c08a97fc45fee2a595aa1b3", - "sha256:143072318f793f53819048fdfe30c321890af0c3ec7cb1dfc9cc87aa88241de2", - "sha256:15208be1c50b99203fe88d15695f22a5bed95ab3f84354c494bcb1d08557df67", - "sha256:1873aade94b74715be2246321c8650cabf5a0d098a95bab81145ffffa4c13876", - "sha256:18d0ef97766055fec15b5de2c06dd8e7654705ce3e5e5eed3b6651a1d2a9a152", - "sha256:1ea665f8ce695bcc37a90ee52de7a7980be5161375d42a0b6c6abedbf0d81f0f", - "sha256:2293b001e319ab0d869d660a704942c9e2cce19745262a8aba2115ef41a0a42a", - "sha256:246b123cc54bb5361588acc54218c8c9fb73068bf227a4a531d8ed56fa3ca7d6", - "sha256:275ff571376626195ab95a746e6a04c7df8ea34638b99fc11160de91f2fef503", - "sha256:281309265596e388ef483250db3640e5f414168c5a67e9c665cafce9492eda2f", - "sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493", - "sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996", - "sha256:30dcc86377618a4c8f3b72418df92e77be4254d8f89f14b8e8f57d6d43603c0f", - "sha256:31a34c508c003a4347d389a9e6fcc2307cc2150eb516462a7a17512130de109e", - "sha256:323ba25b92454adb36fa425dc5cf6f8f19f78948cbad2e7bc6cdf7b0d7982e59", - "sha256:34eccd14566f8fe14b2b95bb13b11572f7c7d5c36da61caf414d23b91fcc5d94", - "sha256:3a58c98a7e9c021f357348867f537017057c2ed7f77337fd914d0bedb35dace7", - "sha256:3f78fd71c4f43a13d342be74ebbc0666fe1f555b8837eb113cb7416856c79682", - "sha256:4154ad09dac630a0f13f37b583eae260c6aa885d67dfbccb5b02c33f31a6d420", - "sha256:420f9bbf47a02616e8554e825208cb947969451978dceb77f95ad09c37791dae", - "sha256:4686818798f9194d03c9129a4d9a702d9e113a89cb03bffe08c6cf799e053291", - "sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe", - "sha256:60989127da422b74a04345096c10d416c2b41bd7bf2a380eb541059e4e999980", - "sha256:64cf30263844fa208851ebb13b0732ce674d8ec6a0c86a4e160495d299ba3c93", - "sha256:68fc1f1ba168724771e38bee37d940d2865cb0f562380a1fb1ffb428b75cb692", - "sha256:6e6f98446430fdf41bd36d4faa6cb409f5140c1c2cf58ce0bbdaf16af7d3f119", - "sha256:729177eaf0aefca0994ce4cffe96ad3c75e377c7b6f4efa59ebf003b6d398716", - "sha256:72dffbd8b4194858d0941062a9766f8297e8868e1dd07a7b36212aaa90f49472", - "sha256:75723c3c0fbbf34350b46a3199eb50638ab22a0228f93fb472ef4d9becc2382b", - "sha256:77853062a2c45be16fd6b8d6de2a99278ee1d985a7bd8b103e97e41c034006d2", - "sha256:78151aa3ec21dccd5cdef6c74c3e73386dcdfaf19bced944169697d7ac7482fc", - "sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c", - "sha256:804d99b24ad523a1fe18cc707bf741670332f7c7412e9d49cb5eab67e886b9b5", - "sha256:81ff62668af011f9a48787564ab7eded4e9fb17a4a6a74af5ffa6a457400d2ab", - "sha256:8359bf4791968c5a78c56103702000105501adb557f3cf772b2c207284273984", - "sha256:83791a65b51ad6ee6cf0845634859d69a038ea9b03d7b26e703f94c7e93dbcf9", - "sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf", - "sha256:876801744b0dee379e4e3c38b76fc89f88834bb15bf92ee07d94acd06ec890a0", - "sha256:8dbf6d1bc73f1d04ec1734bae3b4fb0ee3cb2a493d35ede9badbeb901fb40f6f", - "sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212", - "sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb", - "sha256:977646e05232579d2e7b9c59e21dbe5261f403a88417f6a6512e70d3f8a046be", - "sha256:9dba73be7305b399924709b91682299794887cbbd88e38226ed9f6712eabee90", - "sha256:a148c5d507bb9b4f2030a2025c545fccb0e1ef317393eaba42e7eabd28eb6041", - "sha256:a6cdcc3ede532f4a4b96000b6362099591ab4a3e913d70bcbac2b56c872446f7", - "sha256:ac05fb791acf5e1a3e39402641827780fe44d27e72567a000412c648a85ba860", - "sha256:b0605eaed3eb239e87df0d5e3c6489daae3f7388d455d0c0b4df899519c6a38d", - "sha256:b58b4710c7f4161b5e9dcbe73bb7c62d65670a87df7bcce9e1faaad43e715245", - "sha256:b6356793b84728d9d50ead16ab43c187673831e9d4019013f1402c41b1db9b27", - "sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417", - "sha256:bc7bb56d04601d443f24094e9e31ae6deec9ccb23581f75343feebaf30423359", - "sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202", - "sha256:c332c8d69fb64979ebf76613c66b985414927a40f8defa16cf1bc028b7b0a7b0", - "sha256:c6af2a6d4b7ee9615cbb162b0738f6e1fd1f5c3eda7e5da17861eacf4c717ea7", - "sha256:c77e3d1862452565875eb31bdb45ac62502feabbd53429fdc39a1cc341d681ba", - "sha256:ca08decd2697fdea0aea364b370b1249d47336aec935f87b8bbfd7da5b2ee9c1", - "sha256:ca49a8119c6cbd77375ae303b0cfd8c11f011abbbd64601167ecca18a87e7cdd", - "sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07", - "sha256:d2997c458c690ec2bc6b0b7ecbafd02b029b7b4283078d3b32a852a7ce3ddd98", - "sha256:d3f82c171b4ccd83bbaf35aa05e44e690113bd4f3b7b6cc54d2219b132f3ae55", - "sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d", - "sha256:ead20f7913a9c1e894aebe47cccf9dc834e1618b7aa96155d2091a626e59c972", - "sha256:ebdc36bea43063116f0486869652cb2ed7032dbc59fbcb4445c4862b5c1ecf7f", - "sha256:ed1184ab8f113e8d660ce49a56390ca181f2981066acc27cf637d5c1e10ce46e", - "sha256:ee825e70b1a209475622f7f7b776785bd68f34af6e7a46e2e42f27b659b5bc26", - "sha256:f7ae5d65ccfbebdfa761585228eb4d0df3a8b15cfb53bd953e713e09fbb12957", - "sha256:f7fc5a5acafb7d6ccca13bfa8c90f8c51f13d8fb87d95656d3950f0158d3ce53", - "sha256:f9b5571d33660d5009a8b3c25dc1db560206e2d2f89d3df1cb32d72c0d117d52" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==2.9.9" - }, - "pyasn1": { - "hashes": [ - "sha256:87a2121042a1ac9358cabcaf1d07680ff97ee6404333bacca15f76aa8ad01a57", - "sha256:97b7290ca68e62a832558ec3976f15cbf911bf5d7c7039d8b861c2a0ece69fde" - ], - "index": "pypi", - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==0.5.0" - }, - "pyasn1-modules": { - "hashes": [ - "sha256:5bd01446b736eb9d31512a30d46c1ac3395d676c6f3cafa4c03eb54b9925631c", - "sha256:d3ccd6ed470d9ffbc716be08bd90efbd44d0734bc9303818f7336070984a162d" - ], - "index": "pypi", - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==0.3.0" - }, - "pycouchdb": { - "hashes": [ - "sha256:00bc6c7dd4744895920b9153cb9537bc5ecaff72002ea10209c05580e186e0eb", - "sha256:434758aa6b49c6a67fcf89e71a11c36e2ec2df51e2998c38bcd570eab94cc288" - ], - "index": "pypi", - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.14.2" - }, - "pycparser": { - "hashes": [ - "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9", - "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206" - ], - "index": "pypi", - "version": "==2.21" - }, - "pygments": { - "hashes": [ - "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", - "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a" - ], - "markers": "python_version >= '3.8'", - "version": "==2.18.0" - }, - "pyjwt": { - "hashes": [ - "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de", - "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==2.8.0" - }, - "pyparsing": { - "hashes": [ - "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb", - "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc" - ], - "index": "pypi", - "markers": "python_full_version >= '3.6.8'", - "version": "==3.0.9" - }, - "python-dateutil": { - "hashes": [ - "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", - "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" - ], - "index": "pypi", - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.8.2" - }, - "python-decouple": { - "hashes": [ - "sha256:ba6e2657d4f376ecc46f77a3a615e058d93ba5e465c01bbe57289bfb7cce680f", - "sha256:d0d45340815b25f4de59c974b855bb38d03151d81b037d9e3f463b0c9f8cbd66" - ], - "index": "pypi", - "version": "==3.8" - }, - "python3-openid": { - "hashes": [ - "sha256:33fbf6928f401e0b790151ed2b5290b02545e8775f982485205a066f874aaeaf", - "sha256:6626f771e0417486701e0b4daff762e7212e820ca5b29fcc0d05f6f8736dfa6b" - ], - "index": "pypi", - "version": "==3.2.0" - }, - "pytz": { - "hashes": [ - "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588", - "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb" - ], - "index": "pypi", - "version": "==2023.3" - }, - "rcssmin": { - "hashes": [ - "sha256:271e3d2f8614a6d4637ed8fff3d90007f03e2a654cd9444f37d888797662ba72", - "sha256:35da6a6999e9e2c5b0e691b42ed56cc479373e0ecab33ef5277dfecce625e44a", - "sha256:42576d95dfad53d77df2e68dfdec95b89b10fad320f241f1af3ca1438578254a", - "sha256:4f9400b4366d29f5f5446f58e78549afa8338e6a59740c73115e9f6ac413dc64", - "sha256:705c9112d0ed54ea40aecf97e7fd29bdf0f1c46d278a32d8f957f31dde90778a", - "sha256:79421230dd67c37ec61ed9892813d2b839b68f2f48ef55c75f976e81701d60b4", - "sha256:868215e1fd0e92a6122e0ed5973dfc7bb8330fe1e92274d05b2585253b38c0ca", - "sha256:8a26fec3c1e6b7a3765ccbaccc20fbb5c0ed3422cc381e01a2607f08d7621c44", - "sha256:8fcfd10ae2a1c4ce231a33013f2539e07c3836bf17cc945cc25cc30bf8e68e45", - "sha256:908fe072efd2432fb0975a61124609a8e05021367f6a3463d45f5e3e74c4fdda", - "sha256:914e589f40573035006913861ed2adc28fbe70082a8b6bff5be7ee430b7b5c2e", - "sha256:a04d58a2a21e9a089306d3f99c4b12bf5b656a79c198ef2321e80f8fd9afab06", - "sha256:a417735d4023d47d048a6288c88dbceadd20abaaf65a11bb4fda1e8458057019", - "sha256:c30f8bc839747b6da59274e0c6e4361915d66532e26448d589cb2b1846d7bf11", - "sha256:c7278c1c25bb90d8e554df92cfb3b6a1195004ead50f764653d3093933ee0877", - "sha256:c7728e3b546b1b6ea08cab721e8e21409dbcc11b881d0b87d10b0be8930af2a2", - "sha256:cf74d7ea5e191f0f344b354eed8b7c83eeafbd9a97bec3a579c3d26edf11b005", - "sha256:d0afc6e7b64ef30d6dcde88830ec1a237b9f16a39f920a8fd159928684ccf8db", - "sha256:d4e263fa9428704fd94c2cb565c7519ca1d225217943f71caffe6741ab5b9df1", - "sha256:e923c105100ab70abde1c01d3196ddd6b07255e32073685542be4e3a60870c8e", - "sha256:ee386bec6d62f8c814d65c011d604a7c82d24aa3f718facd66e850eea8d6a5a1", - "sha256:f15673e97f0a68b4c378c4d15b088fe96d60bc106d278c88829923118833c20f", - "sha256:f7a1fcdbafaacac0530da04edca4a44303baab430ea42e7d59aece4b3f3e9a51" - ], - "index": "pypi", - "version": "==1.1.1" - }, - "redis": { - "hashes": [ - "sha256:0dab495cd5753069d3bc650a0dde8a8f9edde16fc5691b689a566eda58100d0f", - "sha256:ed4802971884ae19d640775ba3b03aa2e7bd5e8fb8dfaed2decce4d0fc48391f" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==5.0.1" - }, - "requests": { - "hashes": [ - "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", - "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==2.31.0" - }, - "requests-oauthlib": { - "hashes": [ - "sha256:2577c501a2fb8d05a304c09d090d6e47c306fef15809d102b327cf8364bddab5", - "sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a" - ], - "index": "pypi", - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.3.1" - }, - "rjsmin": { - "hashes": [ - "sha256:113132a40ce7d03b2ced4fac215f0297338ed1c207394b739266efab7831988b", - "sha256:122aa52bcf7ad9f12728d309012d1308c6ecfe4d6b09ea867a110dcad7b7728c", - "sha256:145c6af8df42d8af102d0d39a6de2e5fa66aef9e38947cfb9d65377d1b9940b2", - "sha256:1f982be8e011438777a94307279b40134a3935fc0f079312ee299725b8af5411", - "sha256:3453ee6d5e7a2723ec45c2909e2382371783400e8d51952b692884c6d850a3d0", - "sha256:35827844d2085bd59d34214dfba6f1fc42a215c455887437b07dbf9c73019cc1", - "sha256:35f21046504544e2941e04190ce24161255479133751550e36ddb3f4af0ecdca", - "sha256:5d67ec09da46a492186e35cabca02a0d092eda5ef5b408a419b99ee4acf28d5c", - "sha256:747bc9d3bc8a220f40858e6aad50b2ae2eb7f69c924d4fa3803b81be1c1ddd02", - "sha256:7dd58b5ed88233bc61dc80b0ed87b93a1786031d9977c70d335221ef1ac5581a", - "sha256:812af25c08d6a5ae98019a2e1b47ebb47f7469abd351670c353d619eaeae4064", - "sha256:8a6710e358c661dcdcfd027e67de3afd72a6af4c88101dcf110de39e9bbded39", - "sha256:8c340e251619c97571a5ade20f147f1f7e8664f66a2d6d7319e05e3ef6a4423c", - "sha256:99c074cd6a8302ff47118a9c3d086f89328dc8e5c4b105aa1f348fb85c765a30", - "sha256:b8464629a18fe69f70677854c93a3707976024b226a0ce62707c618f923e1346", - "sha256:bbd7a0abaa394afd951f5d4e05249d306fec1c9674bfee179787674dddd0bdb7", - "sha256:bc5bc2f94e59bc81562c572b7f1bdd6bcec4f61168dc68a2993bad2d355b6e19", - "sha256:bd1faedc425006d9e86b23837d164f01d105b7a8b66b767a9766d0014773db2a", - "sha256:ca90630b84fe94bb07739c3e3793e87d30c6ee450dde08653121f0d9153c8d0d", - "sha256:d332e44a1b21ad63401cc7eebc81157e3d982d5fb503bb4faaea5028068d71e9", - "sha256:eb770aaf637919b0011c4eb87b9ac6317079fb9800eb17c90dda05fc9de4ebc3", - "sha256:f0895b360dccf7e2d6af8762a52985e3fbaa56778de1bf6b20dbc96134253807", - "sha256:f7cd33602ec0f393a0058e883284496bb4dbbdd34e0bbe23b594c8933ddf9b65" - ], - "index": "pypi", - "version": "==1.2.1" - }, - "rsa": { - "hashes": [ - "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7", - "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21" - ], - "index": "pypi", - "markers": "python_version >= '3.6' and python_version < '4'", - "version": "==4.9" - }, - "six": { - "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" - ], - "index": "pypi", - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.16.0" - }, - "sqlparse": { - "hashes": [ - "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3", - "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c" - ], - "index": "pypi", - "markers": "python_version >= '3.5'", - "version": "==0.4.4" - }, - "tornado": { - "hashes": [ - "sha256:02ccefc7d8211e5a7f9e8bc3f9e5b0ad6262ba2fbb683a6443ecc804e5224ce0", - "sha256:10aeaa8006333433da48dec9fe417877f8bcc21f48dda8d661ae79da357b2a63", - "sha256:27787de946a9cffd63ce5814c33f734c627a87072ec7eed71f7fc4417bb16263", - "sha256:6f8a6c77900f5ae93d8b4ae1196472d0ccc2775cc1dfdc9e7727889145c45052", - "sha256:71ddfc23a0e03ef2df1c1397d859868d158c8276a0603b96cf86892bff58149f", - "sha256:72291fa6e6bc84e626589f1c29d90a5a6d593ef5ae68052ee2ef000dfd273dee", - "sha256:88b84956273fbd73420e6d4b8d5ccbe913c65d31351b4c004ae362eba06e1f78", - "sha256:e43bc2e5370a6a8e413e1e1cd0c91bedc5bd62a74a532371042a18ef19e10579", - "sha256:f0251554cdd50b4b44362f73ad5ba7126fc5b2c2895cc62b14a1c2d7ea32f212", - "sha256:f7894c581ecdcf91666a0912f18ce5e757213999e183ebfc2c3fdbf4d5bd764e", - "sha256:fd03192e287fbd0899dd8f81c6fb9cbbc69194d2074b38f384cb6fa72b80e9c2" - ], - "markers": "python_version >= '3.8'", - "version": "==6.4" - }, - "tzdata": { - "hashes": [ - "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a", - "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda" - ], - "index": "pypi", - "markers": "python_version >= '2'", - "version": "==2023.3" - }, - "urllib3": { - "hashes": [ - "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84", - "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==2.0.7" - }, - "vine": { - "hashes": [ - "sha256:4c9dceab6f76ed92105027c49c823800dd33cacce13bdedc5b914e3514b7fb30", - "sha256:7d3b1624a953da82ef63462013bbd271d3eb75751489f9807598e8f340bd637e" - ], - "index": "pypi", - "markers": "python_version >= '3.6'", - "version": "==5.0.0" - }, - "wcwidth": { - "hashes": [ - "sha256:77f719e01648ed600dfa5402c347481c0992263b81a027344f3e1ba25493a704", - "sha256:8705c569999ffbb4f6a87c6d1b80f324bd6db952f5eb0b95bc07517f4c1813d4" - ], - "index": "pypi", - "version": "==0.2.8" - }, - "yarl": { - "hashes": [ - "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51", - "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce", - "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559", - "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0", - "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81", - "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc", - "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4", - "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c", - "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130", - "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136", - "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e", - "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec", - "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7", - "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1", - "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455", - "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099", - "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129", - "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10", - "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142", - "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98", - "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa", - "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7", - "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525", - "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c", - "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9", - "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c", - "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8", - "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b", - "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf", - "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23", - "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd", - "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27", - "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f", - "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece", - "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434", - "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec", - "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff", - "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78", - "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d", - "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863", - "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53", - "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31", - "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15", - "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5", - "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b", - "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57", - "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3", - "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1", - "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f", - "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad", - "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c", - "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7", - "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2", - "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b", - "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2", - "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b", - "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9", - "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be", - "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e", - "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984", - "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4", - "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074", - "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2", - "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392", - "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91", - "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541", - "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf", - "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572", - "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66", - "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575", - "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14", - "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5", - "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1", - "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e", - "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551", - "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17", - "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead", - "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0", - "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe", - "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234", - "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0", - "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7", - "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34", - "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42", - "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385", - "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78", - "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be", - "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958", - "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749", - "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec" - ], - "markers": "python_version >= '3.7'", - "version": "==1.9.4" - } - }, - "develop": { - "black": { - "hashes": [ - - "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474", - "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1", - "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0", - "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8", - "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96", - "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1", - "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04", - "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021", - "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94", - "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d", - "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c", - "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7", - "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c", - "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc", - "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7", - "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d", - "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c", - "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741", - "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce", - "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb", - "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063", - "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e" - ], - "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==24.4.2" - - }, - "cfgv": { - "hashes": [ - "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", - "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560" - ], - "markers": "python_version >= '3.8'", - "version": "==3.4.0" - }, - "click": { - "hashes": [ - "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", - "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==8.1.7" - }, - "colorama": { - "hashes": [ - "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", - "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" - ], - "index": "pypi", - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'", - "version": "==0.4.6" - }, - "distlib": { - "hashes": [ - "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784", - "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64" - ], - "version": "==0.3.8" - }, - "filelock": { - "hashes": [ - "sha256:43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f", - "sha256:6ea72da3be9b8c82afd3edcf99f2fffbb5076335a5ae4d03248bb5b6c3eae78a" - ], - "markers": "python_version >= '3.8'", - "version": "==3.14.0" - }, - "identify": { - "hashes": [ - - "sha256:37d93f380f4de590500d9dba7db359d0d3da95ffe7f9de1753faa159e71e7dfa", - "sha256:e5e00f54165f9047fbebeb4a560f9acfb8af4c88232be60a488e9b68d122745d" - ], - "markers": "python_version >= '3.8'", - "version": "==2.5.36" - - }, - "isort": { - "hashes": [ - "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109", - "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6" - ], - "index": "pypi", - "markers": "python_full_version >= '3.8.0'", - "version": "==5.13.2" - }, - "mypy-extensions": { - "hashes": [ - "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", - "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782" - ], - "markers": "python_version >= '3.5'", - "version": "==1.0.0" - }, - "nodeenv": { - "hashes": [ - "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2", - "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'", - "version": "==1.8.0" - }, - "packaging": { - "hashes": [ - "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61", - "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==23.1" - }, - "pathspec": { - "hashes": [ - "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", - "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712" - ], - "markers": "python_version >= '3.8'", - "version": "==0.12.1" - }, - "platformdirs": { - "hashes": [ - - "sha256:031cd18d4ec63ec53e82dceaac0417d218a6863f7745dfcc9efe7793b7039bdf", - "sha256:17d5a1161b3fd67b390023cb2d3b026bbd40abde6fdb052dfbd3a29c3ba22ee1" - ], - "markers": "python_version >= '3.8'", - "version": "==4.2.1" - }, - "pre-commit": { - "hashes": [ - "sha256:5eae9e10c2b5ac51577c3452ec0a490455c45a0533f7960f993a0d01e59decab", - "sha256:e209d61b8acdcf742404408531f0c37d49d2c734fd7cff2d6076083d191cb060" - ], - "index": "pypi", - "markers": "python_version >= '3.9'", - "version": "==3.7.0" - - }, - "pyyaml": { - "hashes": [ - "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5", - "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc", - "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", - "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741", - "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206", - "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27", - "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595", - "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62", - "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98", - "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696", - "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290", - "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9", - "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d", - "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6", - "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867", - "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47", - "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486", - "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6", - "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3", - "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007", - "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938", - "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0", - "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c", - "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735", - "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d", - "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28", - "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", - "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", - "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", - "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef", - "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", - "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd", - "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3", - "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0", - "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515", - "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c", - "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c", - "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924", - "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34", - "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43", - "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859", - "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673", - "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54", - "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a", - "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b", - "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab", - "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa", - "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c", - "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585", - "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d", - "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f" - ], - "markers": "python_version >= '3.6'", - "version": "==6.0.1" - }, - "setuptools": { - "hashes": [ - - "sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987", - "sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32" - ], - "markers": "python_version >= '3.8'", - "version": "==69.5.1" - }, - "virtualenv": { - "hashes": [ - "sha256:604bfdceaeece392802e6ae48e69cec49168b9c5f4a44e483963f9242eb0e78b", - "sha256:7aa9982a728ae5892558bff6a2839c00b9ed145523ece2274fad6f414690ae75" - ], - "markers": "python_version >= '3.7'", - "version": "==20.26.1" - - } - } -} From 5dceb8602ee2012ce094ae121a42d430565124bb Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Sun, 24 May 2026 19:53:44 +0200 Subject: [PATCH 03/27] refactor(toolchain): swap lint stack to ruff, codespell and bandit --- .gitattributes | 4 + .gitignore | 5 +- .pre-commit-config.yaml | 41 ++++ AHC_app/.pre-commit-config.yaml | 29 --- AHC_app/AHC_app/celery_notifications/cron.py | 9 +- .../utils/discord_utils.py | 3 +- .../utils/sending_utils.py | 7 +- AHC_app/AHC_app/settings.py | 6 +- AHC_app/AHC_app/urls.py | 4 +- AHC_app/animals/forms.py | 3 +- AHC_app/animals/migrations/0001_initial.py | 16 +- .../mixins/animal_owner_permissions.py | 3 +- AHC_app/animals/models.py | 1 + AHC_app/animals/signals.py | 3 +- .../templates/animals/all_animals_stable.html | 2 +- .../animals/animal_confirm_delete.html | 2 +- .../templates/animals/change_birthday.html | 2 +- .../animals/change_first_contact.html | 2 +- AHC_app/animals/templates/animals/image.html | 2 +- .../animals/templatetags/custom_timesince.py | 17 +- AHC_app/animals/urls.py | 7 +- AHC_app/animals/utils_owner/forms.py | 8 +- AHC_app/animals/utils_owner/views.py | 13 +- AHC_app/animals/views.py | 5 +- AHC_app/homepage/admin.py | 1 + AHC_app/homepage/management/__init__.py | 2 +- .../management/commands/sync_cronjobs.py | 1 + AHC_app/homepage/migrations/0001_initial.py | 3 +- .../0002_alter_profilebackground_content.py | 3 +- AHC_app/homepage/models.py | 3 +- AHC_app/homepage/tests/test_homepage.py | 1 + AHC_app/homepage/urls.py | 1 + AHC_app/homepage/views.py | 4 +- AHC_app/manage.py | 1 + AHC_app/medical_notes/admin.py | 2 - .../medical_notes/forms/type_basic_note.py | 6 +- .../medical_notes/forms/type_feeding_notes.py | 5 +- .../forms/type_measurement_notes.py | 14 +- .../medical_notes/migrations/0001_initial.py | 16 +- .../0005_medicalrecordattachment.py | 5 +- ...notification_last_modification_and_more.py | 1 - ...notification_last_modification_and_more.py | 1 - ...011_medicalrecordattachment_description.py | 1 - ...icalrecordattachment_file_name_and_more.py | 1 - ...ve_medicalrecordattachment_url_and_more.py | 1 - ...notification_last_modification_and_more.py | 1 - .../medical_notes/models/type_basic_note.py | 3 +- .../models/type_feeding_notes.py | 3 +- .../models/type_measurement_notes.py | 19 +- .../signals/type_feeding_notes.py | 1 + .../signals/type_measurement_notes.py | 1 + .../templatetags/custom_file_name.py | 3 +- AHC_app/medical_notes/tests.py | 2 - AHC_app/medical_notes/urls.py | 3 +- .../medical_notes/views/type_basic_note.py | 13 +- .../medical_notes/views/type_feeding_notes.py | 5 +- .../views/type_measurement_notes.py | 9 +- AHC_app/pyproject.toml | 31 ++- AHC_app/users/admin.py | 1 + AHC_app/users/forms.py | 1 + ...0002_profile_allow_recennt_animals_list.py | 1 - .../migrations/0003_profile_pinned_animals.py | 1 - AHC_app/users/models.py | 3 +- AHC_app/users/signals.py | 3 +- AHC_app/users/templates/users/login.html | 2 +- .../users/templates/users/login_success.html | 2 +- .../users/templates/users/password_reset.html | 6 +- .../users/password_reset_complete.html | 4 +- .../users/password_reset_confirm.html | 10 +- .../templates/users/password_reset_done.html | 2 +- .../templates/users/password_reset_email.html | 2 +- AHC_app/users/tests.py | 2 - AHC_app/users/urls.py | 5 +- AHC_app/users/views.py | 1 + AHC_app/uv.lock | 195 +++++++++++------- README.md | 4 +- doc/01_adr_functionality.md | 14 +- doc/02_adr_django.md | 14 +- doc/03_adr_monolit.md | 12 +- doc/04_adr_monorepo.md | 14 +- doc/05_adr_matlibplot.md | 12 +- doc/06_adr_html_template.md | 8 +- doc/07_adr_drf.md | 10 +- doc/08_adr_databases.md | 18 +- doc/09_adr_user_data.md | 24 +-- doc/10_adr_notification_trigger.md | 10 +- 86 files changed, 407 insertions(+), 335 deletions(-) create mode 100644 .pre-commit-config.yaml delete mode 100644 AHC_app/.pre-commit-config.yaml diff --git a/.gitattributes b/.gitattributes index dfe0770..287d346 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,6 @@ # Auto detect text files and perform LF normalization * text=auto + +# Vendor static files — preserve LF line endings as published +AHC_app/static/**/* text eol=lf +AHC_app/static_collected/**/* text eol=lf diff --git a/.gitignore b/.gitignore index e6dfafc..60345ef 100644 --- a/.gitignore +++ b/.gitignore @@ -42,8 +42,9 @@ celerybeat.pid .dmypy.json .ty_cache/ -# Claude Code — local settings are machine-specific -.claude/settings.local.json +# Claude Code — not tracked in this repository +.claude/ +CLAUDE.md # IDE .idea/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..1a9f553 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,41 @@ +exclude: 'AHC_app/static/|AHC_app/static_collected/' + +repos: +- repo: local + hooks: + - id: uv-lock-check + name: uv lock --check + entry: uv --directory AHC_app lock --check + language: system + pass_filenames: false + files: ^AHC_app/pyproject\.toml$ + +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: end-of-file-fixer + exclude: '\.sh$' + - id: trailing-whitespace + +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.15.14 + hooks: + - id: ruff + args: [--fix] + - id: ruff-format + +- repo: https://github.com/codespell-project/codespell + rev: v2.4.2 + hooks: + - id: codespell + types_or: [python, markdown, yaml] + +- repo: local + hooks: + - id: bandit + name: bandit + entry: bandit -r AHC_app -c AHC_app/pyproject.toml + language: python + additional_dependencies: ["bandit[toml]==1.9.4"] + pass_filenames: false + always_run: true diff --git a/AHC_app/.pre-commit-config.yaml b/AHC_app/.pre-commit-config.yaml deleted file mode 100644 index 7f61623..0000000 --- a/AHC_app/.pre-commit-config.yaml +++ /dev/null @@ -1,29 +0,0 @@ -repos: -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 - hooks: - - id: end-of-file-fixer - exclude: '\.sh$' - - id: trailing-whitespace -- repo: https://github.com/PyCQA/autoflake - rev: v2.1.1 - hooks: - - id: autoflake - name: autoflake - entry: autoflake - language: python - types: [python] - require_serial: true - args: ['--in-place', '--remove-all-unused-imports'] - exclude: '^requirements\.txt$|^setup_couchdb\.sh$|^.yaml$' -- repo: https://github.com/PyCQA/isort - rev: 5.12.0 - hooks: - - id: isort - args: ['--profile', 'black', '--lines-between-types', '1', '--filter-files'] -- repo: https://github.com/psf/black - rev: 22.3.0 - hooks: - - id: black - language_version: python3.12 - args: ['--line-length', '120'] diff --git a/AHC_app/AHC_app/celery_notifications/cron.py b/AHC_app/AHC_app/celery_notifications/cron.py index a46ed4c..4a197fa 100644 --- a/AHC_app/AHC_app/celery_notifications/cron.py +++ b/AHC_app/AHC_app/celery_notifications/cron.py @@ -3,26 +3,25 @@ import logging.config import logging.handlers import pathlib - from datetime import date, datetime, time, timedelta from functools import wraps from django.db.models import Q, QuerySet from django.utils import timezone -from medical_notes.models.type_feeding_notes import EmailNotification from AHC_app.celery_notifications.config import ( send_discord_notifications, send_email_notifications, ) from AHC_app.celery_notifications.utils.example_task import send_mail_fnc +from medical_notes.models.type_feeding_notes import EmailNotification logger = logging.getLogger("crons_logger") def setup_logging(): config_file = pathlib.Path("AHC_app/celery_notifications/logger_config.json") - with open(config_file, "r") as file: + with open(config_file) as file: config = json.load(file) logging.config.dictConfig(config) @@ -85,7 +84,7 @@ def send_emails() -> None: return None for notification in notifications_to_send: - user_set_zone: str = notification.timezone + _user_set_zone: str = notification.timezone # user_weekday_number: int = datetime.now( # tz=pytz.timezone(user_set_zone) # ).weekday() @@ -103,7 +102,7 @@ def send_emails() -> None: # "note_edit", kwargs={"pk": notification.related_note.id} # ) note_url: str = "" - center: str = f"{message} \n\n " f"For further information:\n{note_url}" + center: str = f"{message} \n\n For further information:\n{note_url}" sender: str = notification.related_note.related_note.author footer: str = f"Best regards \n{sender}" diff --git a/AHC_app/AHC_app/celery_notifications/utils/discord_utils.py b/AHC_app/AHC_app/celery_notifications/utils/discord_utils.py index 87da4e7..c7585f0 100644 --- a/AHC_app/AHC_app/celery_notifications/utils/discord_utils.py +++ b/AHC_app/AHC_app/celery_notifications/utils/discord_utils.py @@ -2,10 +2,9 @@ from discord import Client, Intents from discord.ext import commands -from django.conf import settings # TOKEN = settings.DISCORD_TOKEN -TOKEN = "none" +TOKEN = "none" # nosec B105 def send_via_discord(user_id: int, user_message: str) -> None: diff --git a/AHC_app/AHC_app/celery_notifications/utils/sending_utils.py b/AHC_app/AHC_app/celery_notifications/utils/sending_utils.py index 3d8caea..fe3de81 100644 --- a/AHC_app/AHC_app/celery_notifications/utils/sending_utils.py +++ b/AHC_app/AHC_app/celery_notifications/utils/sending_utils.py @@ -9,8 +9,8 @@ def standardize_message_size(message: str, max_length: int = 2500) -> str: def send_via_email(**kwargs): - recipient_list = kwargs.get("email") - subject = kwargs.get("subject") + _recipient_list = kwargs.get("email") + _subject = kwargs.get("subject") message = kwargs.get("message") message = standardize_message_size(message, max_length=2500) sender_email = settings.EMAIL_HOST_USER @@ -33,7 +33,8 @@ def send_via_email(**kwargs): server.login("0c425676241dc7", "3ca81a9102980f") server.sendmail(sender, receiver, message) - # send_mail(subject=subject, message=message, from_email=sender_email, recipient_list=recipient_list, fail_silently=False) + # send_mail(subject=subject, message=message, from_email=sender_email, + # recipient_list=recipient_list, fail_silently=False) def send_via_sms(**kwargs): diff --git a/AHC_app/AHC_app/settings.py b/AHC_app/AHC_app/settings.py index c1e968c..45bcaf3 100644 --- a/AHC_app/AHC_app/settings.py +++ b/AHC_app/AHC_app/settings.py @@ -9,13 +9,12 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/4.2/ref/settings/ """ + import os import sys - from pathlib import Path import pycouchdb - from decouple import config # Build paths inside the project like this: BASE_DIR / 'subdir'. @@ -26,7 +25,7 @@ # See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = "django-insecure-x#q0@altnjw2yrhh)edi)co2)n3p8q&0qmz7m8oxu-*jhd8d9-" +SECRET_KEY = "django-insecure-x#q0@altnjw2yrhh)edi)co2)n3p8q&0qmz7m8oxu-*jhd8d9-" # nosec B105 # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True @@ -117,7 +116,6 @@ # COUCH_CONNECTOR = (config("COUCH_CONNECTOR"),) if "test" not in sys.argv: - COUCHDB_USER = config("COUCHDB_USER") COUCHDB_PASSWORD = config("COUCHDB_PASSWORD") COUCHDB_PORT = config("COUCHDB_PORT") diff --git a/AHC_app/AHC_app/urls.py b/AHC_app/AHC_app/urls.py index 4ef5aef..1f92f89 100644 --- a/AHC_app/AHC_app/urls.py +++ b/AHC_app/AHC_app/urls.py @@ -14,6 +14,7 @@ 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ + from django.conf import settings from django.conf.urls.static import static from django.contrib import admin @@ -30,4 +31,5 @@ "favicon.ico", RedirectView.as_view(url=static("media/icons/chinchilla.png")), ), -] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + *static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT), +] diff --git a/AHC_app/animals/forms.py b/AHC_app/animals/forms.py index fa3d045..41503d0 100644 --- a/AHC_app/animals/forms.py +++ b/AHC_app/animals/forms.py @@ -1,8 +1,9 @@ -from animals.models import Animal from django import forms from django.core.validators import MaxLengthValidator, MinLengthValidator from django.db.models import Q +from animals.models import Animal + class AnimalRegisterForm(forms.ModelForm): class Meta: diff --git a/AHC_app/animals/migrations/0001_initial.py b/AHC_app/animals/migrations/0001_initial.py index 898346b..64da9bb 100644 --- a/AHC_app/animals/migrations/0001_initial.py +++ b/AHC_app/animals/migrations/0001_initial.py @@ -29,15 +29,11 @@ class Migration(migrations.Migration): ("full_name", models.CharField(max_length=50)), ( "short_description", - models.CharField( - blank=True, default=None, max_length=250, null=True - ), + models.CharField(blank=True, default=None, max_length=250, null=True), ), ( "long_description", - models.CharField( - blank=True, default=None, max_length=2500, null=True - ), + models.CharField(blank=True, default=None, max_length=2500, null=True), ), ("birthdate", models.DateField(default=None, null=True)), ( @@ -50,15 +46,11 @@ class Migration(migrations.Migration): ("creation_date", models.DateTimeField(auto_now_add=True)), ( "first_contact_vet", - models.CharField( - blank=True, default=None, max_length=250, null=True - ), + models.CharField(blank=True, default=None, max_length=250, null=True), ), ( "first_contact_medical_place", - models.CharField( - blank=True, default=None, max_length=250, null=True - ), + models.CharField(blank=True, default=None, max_length=250, null=True), ), ("last_control_visit", models.DateTimeField(default=None, null=True)), ( diff --git a/AHC_app/animals/mixins/animal_owner_permissions.py b/AHC_app/animals/mixins/animal_owner_permissions.py index 378f8c0..4ebf125 100644 --- a/AHC_app/animals/mixins/animal_owner_permissions.py +++ b/AHC_app/animals/mixins/animal_owner_permissions.py @@ -1,6 +1,7 @@ -from animals.models import Animal from django.contrib.auth.mixins import UserPassesTestMixin +from animals.models import Animal + class UserPassesOwnershipTestMixin(UserPassesTestMixin): def test_func(self): diff --git a/AHC_app/animals/models.py b/AHC_app/animals/models.py index d64a8d1..14cab2f 100644 --- a/AHC_app/animals/models.py +++ b/AHC_app/animals/models.py @@ -1,6 +1,7 @@ import uuid from django.db import models + from users.models import Profile as UserProfile diff --git a/AHC_app/animals/signals.py b/AHC_app/animals/signals.py index 05ebd4f..f0d6a88 100644 --- a/AHC_app/animals/signals.py +++ b/AHC_app/animals/signals.py @@ -1,8 +1,9 @@ import os -from animals.models import Animal from django.db.models.signals import post_delete, post_save, pre_delete from django.dispatch import receiver + +from animals.models import Animal from users.models import Profile diff --git a/AHC_app/animals/templates/animals/all_animals_stable.html b/AHC_app/animals/templates/animals/all_animals_stable.html index b0a72e1..7221dd3 100644 --- a/AHC_app/animals/templates/animals/all_animals_stable.html +++ b/AHC_app/animals/templates/animals/all_animals_stable.html @@ -33,4 +33,4 @@

Operations:

{% endif %} -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/AHC_app/animals/templates/animals/animal_confirm_delete.html b/AHC_app/animals/templates/animals/animal_confirm_delete.html index c1d4e3c..2145247 100644 --- a/AHC_app/animals/templates/animals/animal_confirm_delete.html +++ b/AHC_app/animals/templates/animals/animal_confirm_delete.html @@ -10,4 +10,4 @@

Delete Animal


Cancel -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/AHC_app/animals/templates/animals/change_birthday.html b/AHC_app/animals/templates/animals/change_birthday.html index 67c180d..5109645 100644 --- a/AHC_app/animals/templates/animals/change_birthday.html +++ b/AHC_app/animals/templates/animals/change_birthday.html @@ -9,4 +9,4 @@

Return to profile

-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/AHC_app/animals/templates/animals/change_first_contact.html b/AHC_app/animals/templates/animals/change_first_contact.html index 562871b..4ef1549 100644 --- a/AHC_app/animals/templates/animals/change_first_contact.html +++ b/AHC_app/animals/templates/animals/change_first_contact.html @@ -19,4 +19,4 @@

Current first contact medical place:

Return to profile

-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/AHC_app/animals/templates/animals/image.html b/AHC_app/animals/templates/animals/image.html index 6382fa1..ef53601 100644 --- a/AHC_app/animals/templates/animals/image.html +++ b/AHC_app/animals/templates/animals/image.html @@ -9,4 +9,4 @@

Return to profile

-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/AHC_app/animals/templatetags/custom_timesince.py b/AHC_app/animals/templatetags/custom_timesince.py index a9465d5..46267dc 100644 --- a/AHC_app/animals/templatetags/custom_timesince.py +++ b/AHC_app/animals/templatetags/custom_timesince.py @@ -16,19 +16,8 @@ def years_and_months_since(value, arg): years -= 1 months += 12 - if years == 1: - years_str = "1 year" - else: - years_str = f"{years} years" - - if months == 1: - months_str = "1 month" - else: - months_str = f"{months} months" - - if years > 0: - response = f"{years_str}, {months_str}" - else: - response = f"{months_str}" + years_str = "1 year" if years == 1 else f"{years} years" + months_str = "1 month" if months == 1 else f"{months} months" + response = f"{years_str}, {months_str}" if years > 0 else f"{months_str}" return response diff --git a/AHC_app/animals/urls.py b/AHC_app/animals/urls.py index f741254..0ab0ade 100644 --- a/AHC_app/animals/urls.py +++ b/AHC_app/animals/urls.py @@ -1,14 +1,13 @@ +from django.urls import path + from animals import views as animal_views from animals.utils_owner import views as animal_owner_views -from django.urls import path urlpatterns = [ path("create/", animal_views.CreateAnimalView.as_view(), name="animal_create"), path("/delete/", animal_owner_views.AnimalDeleteView.as_view(), name="animal_delete"), path("/owner/", animal_owner_views.ChangeOwnerView.as_view(), name="animal_ownership"), - path( - "/cnt/", animal_owner_views.ChangeFirstContactView.as_view(), name="animal_first_contact" - ), # TO change + path("/cnt/", animal_owner_views.ChangeFirstContactView.as_view(), name="animal_first_contact"), # TO change path("/btd/", animal_owner_views.ChangeBirthdayView.as_view(), name="animal_birthday"), path("/", animal_views.AnimalProfileDetailView.as_view(), name="animal_profile"), path("/upload-image/", animal_owner_views.ImageUploadView.as_view(), name="upload_image"), diff --git a/AHC_app/animals/utils_owner/forms.py b/AHC_app/animals/utils_owner/forms.py index 868e015..14fa925 100644 --- a/AHC_app/animals/utils_owner/forms.py +++ b/AHC_app/animals/utils_owner/forms.py @@ -1,8 +1,9 @@ from datetime import date -from animals.models import Animal from django import forms from PIL import Image + +from animals.models import Animal from users.models import Profile @@ -23,9 +24,8 @@ def clean_profile_image(self): if extension not in self.ALLOWED_EXTENSIONS: raise forms.ValidationError("Invalid file extension.") - if image: - if image.size > self.MAX_IMAGE_SIZE_MB * 1024 * 1024: - raise forms.ValidationError("Image size is too large.") + if image and image.size > self.MAX_IMAGE_SIZE_MB * 1024 * 1024: + raise forms.ValidationError("Image size is too large.") if image: img = Image.open(image) diff --git a/AHC_app/animals/utils_owner/views.py b/AHC_app/animals/utils_owner/views.py index 963d817..4e6f706 100644 --- a/AHC_app/animals/utils_owner/views.py +++ b/AHC_app/animals/utils_owner/views.py @@ -1,3 +1,10 @@ +from django.contrib.auth.mixins import LoginRequiredMixin +from django.shortcuts import get_object_or_404, redirect +from django.urls import reverse, reverse_lazy +from django.views.generic import DeleteView +from django.views.generic.edit import FormView +from PIL import Image + from animals.mixins.animal_owner_permissions import UserPassesOwnershipTestMixin from animals.models import Animal from animals.utils_owner.forms import ( @@ -7,12 +14,6 @@ ImageUploadForm, ManageKeepersForm, ) -from django.contrib.auth.mixins import LoginRequiredMixin -from django.shortcuts import get_object_or_404, redirect -from django.urls import reverse, reverse_lazy -from django.views.generic import DeleteView -from django.views.generic.edit import FormView -from PIL import Image class AnimalDeleteView(LoginRequiredMixin, UserPassesOwnershipTestMixin, DeleteView): diff --git a/AHC_app/animals/views.py b/AHC_app/animals/views.py index 84f1c0b..d4d362d 100644 --- a/AHC_app/animals/views.py +++ b/AHC_app/animals/views.py @@ -1,5 +1,3 @@ -from animals.forms import AnimalRegisterForm, PinAnimalForm -from animals.models import Animal from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin from django.db.models import Q from django.http import JsonResponse @@ -8,6 +6,9 @@ from django.views.generic import TemplateView, View from django.views.generic.detail import DetailView from django.views.generic.edit import FormView + +from animals.forms import AnimalRegisterForm, PinAnimalForm +from animals.models import Animal from medical_notes.models.type_basic_note import MedicalRecord # from users.models import Profile as UserProfile diff --git a/AHC_app/homepage/admin.py b/AHC_app/homepage/admin.py index 23fc0d8..bc300d6 100644 --- a/AHC_app/homepage/admin.py +++ b/AHC_app/homepage/admin.py @@ -1,4 +1,5 @@ from django.contrib import admin + from homepage.models import AnimalTitle, CronJob admin.site.register(AnimalTitle) diff --git a/AHC_app/homepage/management/__init__.py b/AHC_app/homepage/management/__init__.py index cb65698..bd9f50c 100644 --- a/AHC_app/homepage/management/__init__.py +++ b/AHC_app/homepage/management/__init__.py @@ -1 +1 @@ -from .commands.sync_cronjobs import Command +from .commands.sync_cronjobs import Command # noqa: F401 diff --git a/AHC_app/homepage/management/commands/sync_cronjobs.py b/AHC_app/homepage/management/commands/sync_cronjobs.py index 80ccaa6..fc2ec7e 100644 --- a/AHC_app/homepage/management/commands/sync_cronjobs.py +++ b/AHC_app/homepage/management/commands/sync_cronjobs.py @@ -1,6 +1,7 @@ import subprocess from django.core.management.base import BaseCommand + from homepage.models import CronJob diff --git a/AHC_app/homepage/migrations/0001_initial.py b/AHC_app/homepage/migrations/0001_initial.py index e5a9f45..4c846ca 100644 --- a/AHC_app/homepage/migrations/0001_initial.py +++ b/AHC_app/homepage/migrations/0001_initial.py @@ -1,10 +1,11 @@ # Generated by Django 4.2.1 on 2023-10-12 07:43 import django.db.models.deletion -import homepage.utils from django.conf import settings from django.db import migrations, models +import homepage.utils + class Migration(migrations.Migration): initial = True diff --git a/AHC_app/homepage/migrations/0002_alter_profilebackground_content.py b/AHC_app/homepage/migrations/0002_alter_profilebackground_content.py index d75b47b..273b3bb 100644 --- a/AHC_app/homepage/migrations/0002_alter_profilebackground_content.py +++ b/AHC_app/homepage/migrations/0002_alter_profilebackground_content.py @@ -1,8 +1,9 @@ # Generated by Django 4.2.1 on 2023-10-06 16:41 -import homepage.utils from django.db import migrations, models +import homepage.utils + class Migration(migrations.Migration): dependencies = [ diff --git a/AHC_app/homepage/models.py b/AHC_app/homepage/models.py index fab7fc2..8091afb 100644 --- a/AHC_app/homepage/models.py +++ b/AHC_app/homepage/models.py @@ -1,6 +1,7 @@ from django.contrib.auth.models import User from django.db import models from django.urls import reverse + from homepage.utils import ImageGenerator @@ -8,7 +9,7 @@ class Privilege(models.Model): title = models.CharField(max_length=30) privilege_to_delete_animal = models.BooleanField(default=False) - # TODO: reconsider usage to simplyfy priveliges test mixins + # TODO: reconsider usage to simplify privileges test mixins def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) raise NotImplementedError diff --git a/AHC_app/homepage/tests/test_homepage.py b/AHC_app/homepage/tests/test_homepage.py index fe3ad54..fa3783f 100644 --- a/AHC_app/homepage/tests/test_homepage.py +++ b/AHC_app/homepage/tests/test_homepage.py @@ -2,6 +2,7 @@ from django.contrib.auth.models import User from django.test import Client, TestCase + from homepage.models import AnimalTitle client = Client() diff --git a/AHC_app/homepage/urls.py b/AHC_app/homepage/urls.py index 6f65fb3..30af557 100644 --- a/AHC_app/homepage/urls.py +++ b/AHC_app/homepage/urls.py @@ -1,4 +1,5 @@ from django.urls import path + from homepage.views import HomepageView urlpatterns = [ diff --git a/AHC_app/homepage/views.py b/AHC_app/homepage/views.py index 1a51f30..611875f 100644 --- a/AHC_app/homepage/views.py +++ b/AHC_app/homepage/views.py @@ -1,6 +1,7 @@ -from animals.models import Animal from django.db.models import Q from django.views.generic import TemplateView + +from animals.models import Animal from users.models import Profile as UserProfile @@ -23,7 +24,6 @@ def get_context_data(self, **kwargs): context["pinned_animals"] = pinned_animals_query if user_query.allow_recennt_animals_list: - recent_created_animals_query = Animal.objects.filter( Q(owner=self.request.user.profile) | Q(allowed_users=self.request.user.profile) ).order_by("-creation_date")[:3] diff --git a/AHC_app/manage.py b/AHC_app/manage.py index db3b9dc..c262845 100644 --- a/AHC_app/manage.py +++ b/AHC_app/manage.py @@ -1,5 +1,6 @@ #!/usr/bin/env python """Django's command-line utility for administrative tasks.""" + import os import sys diff --git a/AHC_app/medical_notes/admin.py b/AHC_app/medical_notes/admin.py index 8c38f3f..846f6b4 100644 --- a/AHC_app/medical_notes/admin.py +++ b/AHC_app/medical_notes/admin.py @@ -1,3 +1 @@ -from django.contrib import admin - # Register your models here. diff --git a/AHC_app/medical_notes/forms/type_basic_note.py b/AHC_app/medical_notes/forms/type_basic_note.py index 8263457..a03bc1b 100644 --- a/AHC_app/medical_notes/forms/type_basic_note.py +++ b/AHC_app/medical_notes/forms/type_basic_note.py @@ -47,7 +47,7 @@ class Meta: def __init__(self, *args, **kwargs): animal_choices = kwargs.pop("animal_choices", None) type_of_event_param = kwargs.pop("type_of_event_param", None) - super(MedicalRecordForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) # self.Meta.fields.append('TYPES_OF_EVENTS') if animal_choices: @@ -64,7 +64,7 @@ def __init__(self, *args, **kwargs): class MedicalRecordEditForm(MedicalRecordForm): def __init__(self, *args, **kwargs): animal = kwargs.pop("animal", None) - super(MedicalRecordEditForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.animal = animal tag_names = list(self.instance.note_tags.values_list("name", flat=True)) self.initial["note_tags"] = ", ".join(tag_names) @@ -91,7 +91,7 @@ def __init__(self, *args, **kwargs): kwargs.pop("animal") animal_choices = kwargs.pop("animal_choices", None) is_author = kwargs.pop("is_author", None) - super(MedicalRecordEditRelatedAnimalsForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) if animal_choices: self.fields["animal"].widget.choices = animal_choices diff --git a/AHC_app/medical_notes/forms/type_feeding_notes.py b/AHC_app/medical_notes/forms/type_feeding_notes.py index 3e4fb4e..2ded162 100644 --- a/AHC_app/medical_notes/forms/type_feeding_notes.py +++ b/AHC_app/medical_notes/forms/type_feeding_notes.py @@ -1,8 +1,9 @@ from django import forms from django.conf import settings -from medical_notes.models.type_feeding_notes import EmailNotification, FeedingNote from timezone_field import TimeZoneFormField +from medical_notes.models.type_feeding_notes import EmailNotification, FeedingNote + class DietRecordForm(forms.ModelForm): class Meta: @@ -77,6 +78,6 @@ class Meta: days_of_week = forms.MultipleChoiceField(choices=days_of_week_choices, widget=forms.CheckboxSelectMultiple) def __init__(self, *args, **kwargs): - super(NotificationRecordForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields["timezone"].initial = str(settings.TIME_ZONE) diff --git a/AHC_app/medical_notes/forms/type_measurement_notes.py b/AHC_app/medical_notes/forms/type_measurement_notes.py index ae4fe25..7fa41f3 100644 --- a/AHC_app/medical_notes/forms/type_measurement_notes.py +++ b/AHC_app/medical_notes/forms/type_measurement_notes.py @@ -1,5 +1,7 @@ from django import forms +from medical_notes.models.type_measurement_notes import BiometricHeightRecords, BiometricWeightRecords + class BiometricRecordForm(forms.Form): RECORD_CHOICES = [ @@ -21,14 +23,10 @@ class BiometricRecordForm(forms.Form): custom_unit = forms.CharField(max_length=12, required=False) def __init__(self, *args, **kwargs): - super(BiometricRecordForm, self).__init__(*args, **kwargs) - - default_height_unit_to_present = BiometricHeightRecords._meta.get_field( - "height_unit_to_present" - ).get_default() - default_weight_unit_to_present = BiometricWeightRecords._meta.get_field( - "weight_unit_to_present" - ).get_default() + super().__init__(*args, **kwargs) + + default_height_unit_to_present = BiometricHeightRecords._meta.get_field("height_unit_to_present").get_default() + default_weight_unit_to_present = BiometricWeightRecords._meta.get_field("weight_unit_to_present").get_default() self.fields["height_unit_to_present"].initial = default_height_unit_to_present self.fields["weight_unit_to_present"].initial = default_weight_unit_to_present diff --git a/AHC_app/medical_notes/migrations/0001_initial.py b/AHC_app/medical_notes/migrations/0001_initial.py index 7f28f34..8eed680 100644 --- a/AHC_app/medical_notes/migrations/0001_initial.py +++ b/AHC_app/medical_notes/migrations/0001_initial.py @@ -146,9 +146,7 @@ class Migration(migrations.Migration): ), ( "animal", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="animals.animal" - ), + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="animals.animal"), ), ( "author", @@ -199,9 +197,7 @@ class Migration(migrations.Migration): ), ( "animal", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="animals.animal" - ), + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="animals.animal"), ), ], ), @@ -225,9 +221,7 @@ class Migration(migrations.Migration): ("description", models.CharField(max_length=250)), ( "animal", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="animals.animal" - ), + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="animals.animal"), ), ], ), @@ -246,9 +240,7 @@ class Migration(migrations.Migration): ("date_updated", models.DateTimeField(auto_now_add=True)), ( "animal", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, to="animals.animal" - ), + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="animals.animal"), ), ( "custom_biometric_record", diff --git a/AHC_app/medical_notes/migrations/0005_medicalrecordattachment.py b/AHC_app/medical_notes/migrations/0005_medicalrecordattachment.py index 921f03e..a93c2ec 100644 --- a/AHC_app/medical_notes/migrations/0005_medicalrecordattachment.py +++ b/AHC_app/medical_notes/migrations/0005_medicalrecordattachment.py @@ -1,9 +1,10 @@ # Generated by Django 4.2.1 on 2023-12-28 16:40 -from django.db import migrations, models -import django.db.models.deletion import uuid +import django.db.models.deletion +from django.db import migrations, models + class Migration(migrations.Migration): dependencies = [ diff --git a/AHC_app/medical_notes/migrations/0009_discordnotification_last_modification_and_more.py b/AHC_app/medical_notes/migrations/0009_discordnotification_last_modification_and_more.py index 4e9e757..29c4e8d 100644 --- a/AHC_app/medical_notes/migrations/0009_discordnotification_last_modification_and_more.py +++ b/AHC_app/medical_notes/migrations/0009_discordnotification_last_modification_and_more.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("medical_notes", "0008_alter_medicalrecordattachment_file"), ] diff --git a/AHC_app/medical_notes/migrations/0010_alter_discordnotification_last_modification_and_more.py b/AHC_app/medical_notes/migrations/0010_alter_discordnotification_last_modification_and_more.py index c0dc312..70e6d6d 100644 --- a/AHC_app/medical_notes/migrations/0010_alter_discordnotification_last_modification_and_more.py +++ b/AHC_app/medical_notes/migrations/0010_alter_discordnotification_last_modification_and_more.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("medical_notes", "0009_discordnotification_last_modification_and_more"), ] diff --git a/AHC_app/medical_notes/migrations/0011_medicalrecordattachment_description.py b/AHC_app/medical_notes/migrations/0011_medicalrecordattachment_description.py index 7690074..2e74989 100644 --- a/AHC_app/medical_notes/migrations/0011_medicalrecordattachment_description.py +++ b/AHC_app/medical_notes/migrations/0011_medicalrecordattachment_description.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("medical_notes", "0010_alter_discordnotification_last_modification_and_more"), ] diff --git a/AHC_app/medical_notes/migrations/0012_medicalrecordattachment_file_name_and_more.py b/AHC_app/medical_notes/migrations/0012_medicalrecordattachment_file_name_and_more.py index 0639d1d..075e3aa 100644 --- a/AHC_app/medical_notes/migrations/0012_medicalrecordattachment_file_name_and_more.py +++ b/AHC_app/medical_notes/migrations/0012_medicalrecordattachment_file_name_and_more.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("medical_notes", "0011_medicalrecordattachment_description"), ] diff --git a/AHC_app/medical_notes/migrations/0013_remove_medicalrecordattachment_url_and_more.py b/AHC_app/medical_notes/migrations/0013_remove_medicalrecordattachment_url_and_more.py index 57ce211..b87311c 100644 --- a/AHC_app/medical_notes/migrations/0013_remove_medicalrecordattachment_url_and_more.py +++ b/AHC_app/medical_notes/migrations/0013_remove_medicalrecordattachment_url_and_more.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("medical_notes", "0012_medicalrecordattachment_file_name_and_more"), ] diff --git a/AHC_app/medical_notes/migrations/0014_alter_discordnotification_last_modification_and_more.py b/AHC_app/medical_notes/migrations/0014_alter_discordnotification_last_modification_and_more.py index 4e0b8bb..9d99dea 100644 --- a/AHC_app/medical_notes/migrations/0014_alter_discordnotification_last_modification_and_more.py +++ b/AHC_app/medical_notes/migrations/0014_alter_discordnotification_last_modification_and_more.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("medical_notes", "0013_remove_medicalrecordattachment_url_and_more"), ] diff --git a/AHC_app/medical_notes/models/type_basic_note.py b/AHC_app/medical_notes/models/type_basic_note.py index b5ce3d4..1edb49c 100644 --- a/AHC_app/medical_notes/models/type_basic_note.py +++ b/AHC_app/medical_notes/models/type_basic_note.py @@ -1,9 +1,10 @@ import uuid -from animals.models import Animal from django.db import models from taggit.managers import TaggableManager from taggit.models import GenericUUIDTaggedItemBase, TaggedItemBase + +from animals.models import Animal from users.models import Profile as UserProfile diff --git a/AHC_app/medical_notes/models/type_feeding_notes.py b/AHC_app/medical_notes/models/type_feeding_notes.py index e48c449..87725b8 100644 --- a/AHC_app/medical_notes/models/type_feeding_notes.py +++ b/AHC_app/medical_notes/models/type_feeding_notes.py @@ -3,9 +3,10 @@ from django.contrib.postgres.fields import ArrayField from django.db import models -from medical_notes.models.type_basic_note import MedicalRecord from timezone_field import TimeZoneField +from medical_notes.models.type_basic_note import MedicalRecord + class FeedingNote(models.Model): related_note = models.ForeignKey(MedicalRecord, on_delete=models.CASCADE, null=False, blank=False) diff --git a/AHC_app/medical_notes/models/type_measurement_notes.py b/AHC_app/medical_notes/models/type_measurement_notes.py index 1c36dda..84eb0ec 100644 --- a/AHC_app/medical_notes/models/type_measurement_notes.py +++ b/AHC_app/medical_notes/models/type_measurement_notes.py @@ -1,5 +1,6 @@ -from animals.models import Animal from django.db import models + +from animals.models import Animal from medical_notes.models.type_basic_note import MedicalRecord @@ -23,17 +24,9 @@ class BiometricCustomRecords(models.Model): class BiometricRecord(models.Model): animal = models.ForeignKey(Animal, on_delete=models.CASCADE) - related_note = models.ForeignKey( - MedicalRecord, on_delete=models.SET_NULL, blank=True, null=True - ) + related_note = models.ForeignKey(MedicalRecord, on_delete=models.SET_NULL, blank=True, null=True) date_updated = models.DateTimeField(auto_now_add=True, editable=True) - weight_biometric_record = models.OneToOneField( - BiometricWeightRecords, on_delete=models.CASCADE, blank=True, null=True - ) - height_biometric_record = models.OneToOneField( - BiometricHeightRecords, on_delete=models.CASCADE, blank=True, null=True - ) - custom_biometric_record = models.OneToOneField( - BiometricCustomRecords, on_delete=models.CASCADE, blank=True, null=True - ) + weight_biometric_record = models.OneToOneField(BiometricWeightRecords, on_delete=models.CASCADE, blank=True, null=True) + height_biometric_record = models.OneToOneField(BiometricHeightRecords, on_delete=models.CASCADE, blank=True, null=True) + custom_biometric_record = models.OneToOneField(BiometricCustomRecords, on_delete=models.CASCADE, blank=True, null=True) diff --git a/AHC_app/medical_notes/signals/type_feeding_notes.py b/AHC_app/medical_notes/signals/type_feeding_notes.py index ce07d43..9fa7dc5 100644 --- a/AHC_app/medical_notes/signals/type_feeding_notes.py +++ b/AHC_app/medical_notes/signals/type_feeding_notes.py @@ -1,6 +1,7 @@ from django.db import transaction from django.db.models.signals import post_save from django.dispatch import receiver + from medical_notes.models.type_feeding_notes import FeedingNote from users.models import Profile as UserProfile diff --git a/AHC_app/medical_notes/signals/type_measurement_notes.py b/AHC_app/medical_notes/signals/type_measurement_notes.py index 6e7cb9e..63783b1 100644 --- a/AHC_app/medical_notes/signals/type_measurement_notes.py +++ b/AHC_app/medical_notes/signals/type_measurement_notes.py @@ -2,6 +2,7 @@ from django.db.models import Q from django.db.models.signals import post_save, pre_save from django.dispatch import receiver + from medical_notes.models.type_basic_note import MedicalRecord from medical_notes.models.type_measurement_notes import BiometricRecord from users.models import Profile as UserProfile diff --git a/AHC_app/medical_notes/templatetags/custom_file_name.py b/AHC_app/medical_notes/templatetags/custom_file_name.py index 82d6968..9932126 100644 --- a/AHC_app/medical_notes/templatetags/custom_file_name.py +++ b/AHC_app/medical_notes/templatetags/custom_file_name.py @@ -1,4 +1,5 @@ from django import template + from medical_notes.models.type_feeding_notes import FeedingNotification register = template.Library() @@ -10,6 +11,6 @@ def to_class_name(value): raise template.TemplateSyntaxError("Value cannot be None") if FeedingNotification not in value.__class__.__bases__: - raise template.TemplateSyntaxError(f"Not allowed to use on the model") + raise template.TemplateSyntaxError("Not allowed to use on the model") return value.__class__.__name__ diff --git a/AHC_app/medical_notes/tests.py b/AHC_app/medical_notes/tests.py index 7ce503c..a39b155 100644 --- a/AHC_app/medical_notes/tests.py +++ b/AHC_app/medical_notes/tests.py @@ -1,3 +1 @@ -from django.test import TestCase - # Create your tests here. diff --git a/AHC_app/medical_notes/urls.py b/AHC_app/medical_notes/urls.py index dea5590..e9fbfab 100644 --- a/AHC_app/medical_notes/urls.py +++ b/AHC_app/medical_notes/urls.py @@ -1,4 +1,5 @@ from django.urls import path + from medical_notes.views import type_basic_note as notes_views from medical_notes.views import type_feeding_notes as feeding_views from medical_notes.views import type_measurement_notes as measurement_views @@ -7,7 +8,7 @@ path("/create/", notes_views.CreateNoteFormView.as_view(), name="note_create"), path("/edit/", notes_views.EditNoteView.as_view(), name="note_edit"), path("/delete/", notes_views.DeleteNoteView.as_view(), name="note_delete"), - path("/realted/", notes_views.EditRelatedAnimalsView.as_view(), name="note_animals_edit"), + path("/related/", notes_views.EditRelatedAnimalsView.as_view(), name="note_animals_edit"), path("/notes/", notes_views.FullTimelineOfNotes.as_view(), name="full_timeline_of_notes"), path("/feeding_create/", feeding_views.DietRecordCreateView.as_view(), name="feeding_create"), path("/feeding_edit/", feeding_views.EditDietRecordView.as_view(), name="feeding_edit"), diff --git a/AHC_app/medical_notes/views/type_basic_note.py b/AHC_app/medical_notes/views/type_basic_note.py index 7748361..b7271ba 100644 --- a/AHC_app/medical_notes/views/type_basic_note.py +++ b/AHC_app/medical_notes/views/type_basic_note.py @@ -1,4 +1,3 @@ -from animals.models import Animal as AnimalProfile from django.conf import settings from django.contrib import messages from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin @@ -12,6 +11,8 @@ from django.views.generic import View from django.views.generic.edit import DeleteView, FormView, UpdateView from django.views.generic.list import ListView + +from animals.models import Animal as AnimalProfile from medical_notes.forms.type_basic_note import ( MedicalRecordEditForm, MedicalRecordEditRelatedAnimalsForm, @@ -32,9 +33,7 @@ def get_form_kwargs(self): kwargs = super().get_form_kwargs() query = ( - AnimalProfile.objects.filter( - Q(owner=self.request.user.profile) | Q(allowed_users=self.request.user.profile) - ) + AnimalProfile.objects.filter(Q(owner=self.request.user.profile) | Q(allowed_users=self.request.user.profile)) .exclude(id=self.kwargs.get("pk")) .order_by("-creation_date") ) @@ -133,7 +132,7 @@ def get_context_data(self, **kwargs): form.fields["medical_record_id"].initial = str(note.id) upload_forms.append(form) - notes_with_forms = zip(context["notes"], upload_forms) + notes_with_forms = zip(context["notes"], upload_forms, strict=False) context["notes"] = notes_with_forms @@ -182,7 +181,7 @@ def post(self, request, *args, **kwargs): else: print(form.errors) - for field, errors in form.errors.items(): + for _field, errors in form.errors.items(): messages.error(request, f"Failed to upload: {', '.join(errors)}") return redirect(request.path) @@ -371,7 +370,7 @@ def test_func(self): def get(self, request, *args, **kwargs): couch_connector = settings.COUCH_DB reference_id = self.kwargs.get("id") - filename = self.kwargs.get("name") + _filename = self.kwargs.get("name") attachment = couch_connector.get(reference_id) if not attachment: diff --git a/AHC_app/medical_notes/views/type_feeding_notes.py b/AHC_app/medical_notes/views/type_feeding_notes.py index 7fe7c76..8c23a6b 100644 --- a/AHC_app/medical_notes/views/type_feeding_notes.py +++ b/AHC_app/medical_notes/views/type_feeding_notes.py @@ -1,4 +1,3 @@ -from animals.models import Animal as AnimalProfile from django.conf import settings from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin from django.http import HttpResponseRedirect @@ -6,6 +5,8 @@ from django.urls import reverse_lazy from django.views.generic.edit import FormView, UpdateView from django.views.generic.list import ListView + +from animals.models import Animal as AnimalProfile from medical_notes.forms.type_feeding_notes import ( DietRecordForm, NotificationRecordForm, @@ -27,7 +28,7 @@ def form_valid(self, form): note_id = self.kwargs.get("pk") related_note = get_object_or_404(MedicalRecord, id=note_id) - animal = related_note.animal + _animal = related_note.animal feeding_note = form.save(commit=False) feeding_note.related_note = related_note diff --git a/AHC_app/medical_notes/views/type_measurement_notes.py b/AHC_app/medical_notes/views/type_measurement_notes.py index e4c0a3b..7d89125 100644 --- a/AHC_app/medical_notes/views/type_measurement_notes.py +++ b/AHC_app/medical_notes/views/type_measurement_notes.py @@ -1,6 +1,7 @@ -from animals.models import Animal as AnimalProfile from django.shortcuts import get_object_or_404, redirect, reverse from django.views.generic.edit import FormView + +from animals.models import Animal as AnimalProfile from medical_notes.forms.type_measurement_notes import BiometricRecordForm from medical_notes.models.type_basic_note import MedicalRecord from medical_notes.models.type_measurement_notes import ( @@ -34,7 +35,7 @@ def form_valid(self, form): weight = form.cleaned_data["weight"] unit = form.cleaned_data["weight_unit_to_present"] weight_record = BiometricWeightRecords.objects.create(weight=weight, weight_unit_to_present=unit) - biometric_record = BiometricRecord.objects.create( + _biometric_record = BiometricRecord.objects.create( animal=animal, related_note=related_note, weight_biometric_record=weight_record, @@ -43,7 +44,7 @@ def form_valid(self, form): height = form.cleaned_data["height"] unit = form.cleaned_data["height_unit_to_present"] height_record = BiometricHeightRecords.objects.create(height=height, height_unit_to_present=unit) - biometric_record = BiometricRecord.objects.create( + _biometric_record = BiometricRecord.objects.create( animal=animal, related_note=related_note, height_biometric_record=height_record, @@ -57,7 +58,7 @@ def form_valid(self, form): record_value=custom_value, record_unit=custom_unit, ) - biometric_record = BiometricRecord.objects.create( + _biometric_record = BiometricRecord.objects.create( animal=animal, related_note=related_note, custom_biometric_record=custom_record, diff --git a/AHC_app/pyproject.toml b/AHC_app/pyproject.toml index cb462e0..f93635a 100644 --- a/AHC_app/pyproject.toml +++ b/AHC_app/pyproject.toml @@ -42,9 +42,36 @@ dependencies = [ [dependency-groups] dev = [ "pre-commit", - "black", - "isort", + "ruff", + "ty", + "codespell", + "bandit[toml]", ] [tool.uv] package = false + +[tool.ruff] +line-length = 124 + +[tool.ruff.lint] +select = ["E", "F", "UP", "B", "SIM", "I", "RUF", "DJ"] +ignore = [ + "DJ001", + "DJ008", + "RUF012", +] + +[tool.ruff.format] +quote-style = "double" +indent-style = "space" + +[tool.ty.environment] +python-version = "3.14" + +[tool.codespell] +skip = "uv.lock,./static,./static_collected" + +[tool.bandit] +exclude_dirs = [".venv"] +skips = ["B101", "B404", "B603", "B607"] diff --git a/AHC_app/users/admin.py b/AHC_app/users/admin.py index ed54a24..8886aeb 100644 --- a/AHC_app/users/admin.py +++ b/AHC_app/users/admin.py @@ -1,4 +1,5 @@ from django.contrib import admin + from users.models import Profile admin.site.register(Profile) diff --git a/AHC_app/users/forms.py b/AHC_app/users/forms.py index 37c2b8d..9a4bd29 100644 --- a/AHC_app/users/forms.py +++ b/AHC_app/users/forms.py @@ -1,5 +1,6 @@ from django import forms from django.contrib.auth.forms import User, UserCreationForm + from users.models import Profile diff --git a/AHC_app/users/migrations/0002_profile_allow_recennt_animals_list.py b/AHC_app/users/migrations/0002_profile_allow_recennt_animals_list.py index 7fee793..f7296ae 100644 --- a/AHC_app/users/migrations/0002_profile_allow_recennt_animals_list.py +++ b/AHC_app/users/migrations/0002_profile_allow_recennt_animals_list.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("users", "0001_initial"), ] diff --git a/AHC_app/users/migrations/0003_profile_pinned_animals.py b/AHC_app/users/migrations/0003_profile_pinned_animals.py index c039789..4087290 100644 --- a/AHC_app/users/migrations/0003_profile_pinned_animals.py +++ b/AHC_app/users/migrations/0003_profile_pinned_animals.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("animals", "0001_initial"), ("users", "0002_profile_allow_recennt_animals_list"), diff --git a/AHC_app/users/models.py b/AHC_app/users/models.py index 9a67048..f64ad5a 100644 --- a/AHC_app/users/models.py +++ b/AHC_app/users/models.py @@ -1,8 +1,9 @@ from django.contrib.auth.models import User from django.db import models -from homepage.models import Privilege, ProfileBackground from PIL import Image +from homepage.models import Privilege, ProfileBackground + class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) diff --git a/AHC_app/users/signals.py b/AHC_app/users/signals.py index 6821573..068927b 100644 --- a/AHC_app/users/signals.py +++ b/AHC_app/users/signals.py @@ -1,6 +1,7 @@ from django.contrib.auth.models import User from django.db.models.signals import post_save, pre_save from django.dispatch import receiver + from homepage.models import Privilege, ProfileBackground from users.models import Profile @@ -22,7 +23,7 @@ def create_background(sender, instance, **kwargs): @receiver(post_save, sender=User) def create_profile(sender, instance, created, **kwargs): if created: - background, _ = ProfileBackground.objects.get_or_create(title="Default Background") + _background, _ = ProfileBackground.objects.get_or_create(title="Default Background") Profile.objects.create(user=instance) diff --git a/AHC_app/users/templates/users/login.html b/AHC_app/users/templates/users/login.html index b08716c..2322254 100644 --- a/AHC_app/users/templates/users/login.html +++ b/AHC_app/users/templates/users/login.html @@ -23,4 +23,4 @@ -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/AHC_app/users/templates/users/login_success.html b/AHC_app/users/templates/users/login_success.html index cf6e929..106bfab 100644 --- a/AHC_app/users/templates/users/login_success.html +++ b/AHC_app/users/templates/users/login_success.html @@ -21,4 +21,4 @@ -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/AHC_app/users/templates/users/password_reset.html b/AHC_app/users/templates/users/password_reset.html index 1c2f919..02384ea 100644 --- a/AHC_app/users/templates/users/password_reset.html +++ b/AHC_app/users/templates/users/password_reset.html @@ -5,10 +5,10 @@ {% csrf_token %}

Reset Password

{% for field in form %} - {{ field.label_tag }} + {{ field.label_tag }} {{ field }} {% if field.errors %} - {{ field.errors|striptags }} + {{ field.errors|striptags }} {% endif %} {% endfor %}
@@ -17,4 +17,4 @@

Reset Password

-{%endblock content%} \ No newline at end of file +{%endblock content%} diff --git a/AHC_app/users/templates/users/password_reset_complete.html b/AHC_app/users/templates/users/password_reset_complete.html index 23a11e2..c7160eb 100644 --- a/AHC_app/users/templates/users/password_reset_complete.html +++ b/AHC_app/users/templates/users/password_reset_complete.html @@ -4,5 +4,5 @@

Your password has been changed successfully. Please Login

- -{%endblock content%} \ No newline at end of file + +{%endblock content%} diff --git a/AHC_app/users/templates/users/password_reset_confirm.html b/AHC_app/users/templates/users/password_reset_confirm.html index 4ddd783..5e3d36c 100644 --- a/AHC_app/users/templates/users/password_reset_confirm.html +++ b/AHC_app/users/templates/users/password_reset_confirm.html @@ -5,16 +5,16 @@
{% csrf_token %}

Password Reset Confirm

- + {% for field in form %} - {{ field.label_tag }} + {{ field.label_tag }} {{ field }} {% if field.errors %} - {{ field.errors|striptags }} + {{ field.errors|striptags }} {% endif %} {% endfor %} - - + +
diff --git a/AHC_app/users/templates/users/password_reset_done.html b/AHC_app/users/templates/users/password_reset_done.html index adf83a3..f92eef6 100644 --- a/AHC_app/users/templates/users/password_reset_done.html +++ b/AHC_app/users/templates/users/password_reset_done.html @@ -6,4 +6,4 @@

Reset Password

Please check your inbox and follow the instruction to reset your password.

-{%endblock content%} \ No newline at end of file +{%endblock content%} diff --git a/AHC_app/users/templates/users/password_reset_email.html b/AHC_app/users/templates/users/password_reset_email.html index 098d1e9..7c768d7 100644 --- a/AHC_app/users/templates/users/password_reset_email.html +++ b/AHC_app/users/templates/users/password_reset_email.html @@ -7,4 +7,4 @@ {{ protocol }}://{{ domain }}{% url "password_reset_confirm" uidb64=uid token=token %}

Thanks

-

Todo App Team

\ No newline at end of file +

Todo App Team

diff --git a/AHC_app/users/tests.py b/AHC_app/users/tests.py index 7ce503c..a39b155 100644 --- a/AHC_app/users/tests.py +++ b/AHC_app/users/tests.py @@ -1,3 +1 @@ -from django.test import TestCase - # Create your tests here. diff --git a/AHC_app/users/urls.py b/AHC_app/users/urls.py index b0a23c4..056bd50 100644 --- a/AHC_app/users/urls.py +++ b/AHC_app/users/urls.py @@ -6,15 +6,14 @@ PasswordResetView, ) from django.urls import path + from users import views as user_views urlpatterns = [ path("", auth_views.LoginView.as_view(template_name="users/login.html"), name="login"), path("login/", auth_views.LoginView.as_view(template_name="users/login.html"), name="login"), path("register/", user_views.UserRegisterView.as_view(), name="register"), - path( - "login_success/", auth_views.LoginView.as_view(template_name="users/login_success.html"), name="login_success" - ), + path("login_success/", auth_views.LoginView.as_view(template_name="users/login_success.html"), name="login_success"), path("logout/", auth_views.LogoutView.as_view(template_name="users/logout.html"), name="logout"), path("profile/", user_views.UserProfileView.as_view(), name="profile"), path( diff --git a/AHC_app/users/views.py b/AHC_app/users/views.py index dc39aeb..538cbd9 100644 --- a/AHC_app/users/views.py +++ b/AHC_app/users/views.py @@ -2,6 +2,7 @@ from django.contrib.auth.mixins import LoginRequiredMixin from django.urls import reverse_lazy from django.views.generic import CreateView, UpdateView + from users.forms import ProfileUpdateForm, UserRegisterForm, UserUpdateForm from users.models import Profile diff --git a/AHC_app/uv.lock b/AHC_app/uv.lock index 390af96..4c03322 100644 --- a/AHC_app/uv.lock +++ b/AHC_app/uv.lock @@ -127,9 +127,11 @@ dependencies = [ [package.dev-dependencies] dev = [ - { name = "black" }, - { name = "isort" }, + { name = "bandit" }, + { name = "codespell" }, { name = "pre-commit" }, + { name = "ruff" }, + { name = "ty" }, ] [package.metadata] @@ -170,9 +172,11 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ - { name = "black" }, - { name = "isort" }, + { name = "bandit", extras = ["toml"] }, + { name = "codespell" }, { name = "pre-commit" }, + { name = "ruff" }, + { name = "ty" }, ] [[package]] @@ -243,34 +247,27 @@ wheels = [ ] [[package]] -name = "billiard" -version = "4.2.4" +name = "bandit" +version = "1.9.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/23/b12ac0bcdfb7360d664f40a00b1bda139cbbbced012c34e375506dbd0143/billiard-4.2.4.tar.gz", hash = "sha256:55f542c371209e03cd5862299b74e52e4fbcba8250ba611ad94276b369b6a85f", size = 156537, upload-time = "2025-11-30T13:28:48.52Z" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "pyyaml" }, + { name = "rich" }, + { name = "stevedore" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/aa/c3/0cb80dfe0f3076e5da7e4c5ad8e57bac6ac357ff4a6406205501cade4965/bandit-1.9.4.tar.gz", hash = "sha256:b589e5de2afe70bd4d53fa0c1da6199f4085af666fde00e8a034f152a52cd628", size = 4242677, upload-time = "2026-02-25T06:44:15.503Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/87/8bab77b323f16d67be364031220069f79159117dd5e43eeb4be2fef1ac9b/billiard-4.2.4-py3-none-any.whl", hash = "sha256:525b42bdec68d2b983347ac312f892db930858495db601b5836ac24e6477cde5", size = 87070, upload-time = "2025-11-30T13:28:47.016Z" }, + { url = "https://files.pythonhosted.org/packages/05/a4/a26d5b25671d27e03afb5401a0be5899d94ff8fab6a698b1ac5be3ec29ef/bandit-1.9.4-py3-none-any.whl", hash = "sha256:f89ffa663767f5a0585ea075f01020207e966a9c0f2b9ef56a57c7963a3f6f8e", size = 134741, upload-time = "2026-02-25T06:44:13.694Z" }, ] [[package]] -name = "black" -version = "26.5.1" +name = "billiard" +version = "4.2.4" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "mypy-extensions" }, - { name = "packaging" }, - { name = "pathspec" }, - { name = "platformdirs" }, - { name = "pytokens" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c0/37/5628dd55bf2b34257fc7603f0fe97c40e3aaf24265f416a9c85c95ca1436/black-26.5.1.tar.gz", hash = "sha256:dd321f668053961824bcc1be1cc1df748b2d7e4fa28086b08331e577b0100a73", size = 679439, upload-time = "2026-05-18T16:53:36.107Z" } +sdist = { url = "https://files.pythonhosted.org/packages/58/23/b12ac0bcdfb7360d664f40a00b1bda139cbbbced012c34e375506dbd0143/billiard-4.2.4.tar.gz", hash = "sha256:55f542c371209e03cd5862299b74e52e4fbcba8250ba611ad94276b369b6a85f", size = 156537, upload-time = "2025-11-30T13:28:48.52Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a6/16/a8da8eb208c51c7f4ce74609a45d0dcc6d8a2141e45e81ee5289d1bb0d59/black-26.5.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e88976690a64b0af98312ca958415849cb42423423c5f2ee74af4b49a97a2168", size = 2004800, upload-time = "2026-05-18T17:05:38.182Z" }, - { url = "https://files.pythonhosted.org/packages/11/8a/a479296a19e383b70a725882a6cf3d786540601ff03cabbaaf1cce864c5a/black-26.5.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:32d5ea7f6c8bdfa6e648326ebca1f02b0764e2a029edc6f8dce2627e19d468c3", size = 1815576, upload-time = "2026-05-18T17:05:40.309Z" }, - { url = "https://files.pythonhosted.org/packages/81/6b/cfaf3d39f25132c156a068f6b805576c9103a84086019507c70e1911ee7d/black-26.5.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ea8d16dc41655aa113cd64665e7219446cd7e4ff2248d7178eaa905190c86b18", size = 1877927, upload-time = "2026-05-18T17:05:42.463Z" }, - { url = "https://files.pythonhosted.org/packages/66/76/302e313964bcff7e28df329d39f84f5270095730d85ff0acc260610a0d82/black-26.5.1-cp314-cp314-win_amd64.whl", hash = "sha256:577f21094ea469ef92ec1adaf2c9441a226d2144d01a5be2fa823cecf6543e50", size = 1511860, upload-time = "2026-05-18T17:05:43.943Z" }, - { url = "https://files.pythonhosted.org/packages/27/4e/a3827e35e0e567f9f9ee59e2a0ab979267dca98718f25547ca8c6733afd4/black-26.5.1-cp314-cp314-win_arm64.whl", hash = "sha256:ed1a20af114c301a0269bf01163d51dbef72737fd65f850001e7cbe7f3c7abae", size = 1316632, upload-time = "2026-05-18T17:05:45.521Z" }, - { url = "https://files.pythonhosted.org/packages/94/51/f975cae76d44274cc2868dc9040ac5d58d464784610234455b4e7b19c6ef/black-26.5.1-py3-none-any.whl", hash = "sha256:4ed7f7da04046d2e488437170797d3b4a4ad83906683bcb7dfc68b673bbce5e2", size = 213693, upload-time = "2026-05-18T16:53:33.964Z" }, + { url = "https://files.pythonhosted.org/packages/cb/87/8bab77b323f16d67be364031220069f79159117dd5e43eeb4be2fef1ac9b/billiard-4.2.4-py3-none-any.whl", hash = "sha256:525b42bdec68d2b983347ac312f892db930858495db601b5836ac24e6477cde5", size = 87070, upload-time = "2025-11-30T13:28:47.016Z" }, ] [[package]] @@ -443,6 +440,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/52/40/9d857001228658f0d59e97ebd4c346fe73e138c6de1bce61dc568a57c7f8/click_repl-0.3.0-py3-none-any.whl", hash = "sha256:fb7e06deb8da8de86180a33a9da97ac316751c094c6899382da7feeeeb51b812", size = 10289, upload-time = "2023-06-15T12:43:48.626Z" }, ] +[[package]] +name = "codespell" +version = "2.4.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/9d/1d0903dff693160f893ca6abcabad545088e7a2ee0a6deae7c24e958be69/codespell-2.4.2.tar.gz", hash = "sha256:3c33be9ae34543807f088aeb4832dfad8cb2dae38da61cac0a7045dd376cfdf3", size = 352058, upload-time = "2026-03-05T18:10:42.936Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/a1/52fa05533e95fe45bcc09bcf8a503874b1c08f221a4e35608017e0938f55/codespell-2.4.2-py3-none-any.whl", hash = "sha256:97e0c1060cf46bd1d5db89a936c98db8c2b804e1fdd4b5c645e82a1ec6b1f886", size = 353715, upload-time = "2026-03-05T18:10:41.398Z" }, +] + [[package]] name = "colorama" version = "0.4.6" @@ -813,15 +819,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/94/16/70255075a9859a0e3adb789b68ceb0e210dec03934245fd98d248226572f/idna-3.16-py3-none-any.whl", hash = "sha256:cc246e3a3f89580c3a951b5ad298ca4638078b2cdd4f115654332b5c26daded5", size = 74165, upload-time = "2026-05-22T00:16:16.698Z" }, ] -[[package]] -name = "isort" -version = "8.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ef/7c/ec4ab396d31b3b395e2e999c8f46dec78c5e29209fac49d1f4dace04041d/isort-8.0.1.tar.gz", hash = "sha256:171ac4ff559cdc060bcfff550bc8404a486fee0caab245679c2abe7cb253c78d", size = 769592, upload-time = "2026-02-28T10:08:20.685Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3e/95/c7c34aa53c16353c56d0b802fba48d5f5caa2cdee7958acbcb795c830416/isort-8.0.1-py3-none-any.whl", hash = "sha256:28b89bc70f751b559aeca209e6120393d43fbe2490de0559662be7a9787e3d75", size = 89733, upload-time = "2026-02-28T10:08:19.466Z" }, -] - [[package]] name = "kombu" version = "5.6.2" @@ -850,6 +847,27 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ef/20/caf3c7cf2432d85263119798c45221ddf67bdd7dae8f626d14ff8db04040/libsass-0.23.0-cp38-abi3-win_amd64.whl", hash = "sha256:a2ec85d819f353cbe807432d7275d653710d12b08ec7ef61c124a580a8352f3c", size = 872914, upload-time = "2024-01-06T19:02:47.61Z" }, ] +[[package]] +name = "markdown-it-py" +version = "4.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687, upload-time = "2026-05-07T12:08:27.182Z" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + [[package]] name = "multidict" version = "6.7.1" @@ -895,15 +913,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload-time = "2026-01-26T02:46:44.004Z" }, ] -[[package]] -name = "mypy-extensions" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, -] - [[package]] name = "nodeenv" version = "1.10.0" @@ -931,15 +940,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, ] -[[package]] -name = "pathspec" -version = "1.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" }, -] - [[package]] name = "pillow" version = "12.2.0" @@ -1192,25 +1192,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e0/a5/c6ba13860bdf5525f1ab01e01cc667578d6f1efc8a1dba355700fb04c29b/python3_openid-3.2.0-py3-none-any.whl", hash = "sha256:6626f771e0417486701e0b4daff762e7212e820ca5b29fcc0d05f6f8736dfa6b", size = 133681, upload-time = "2020-06-29T12:15:47.502Z" }, ] -[[package]] -name = "pytokens" -version = "0.4.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b6/34/b4e015b99031667a7b960f888889c5bd34ef585c85e1cb56a594b92836ac/pytokens-0.4.1.tar.gz", hash = "sha256:292052fe80923aae2260c073f822ceba21f3872ced9a68bb7953b348e561179a", size = 23015, upload-time = "2026-01-30T01:03:45.924Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/a7/b470f672e6fc5fee0a01d9e75005a0e617e162381974213a945fcd274843/pytokens-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4a14d5f5fc78ce85e426aa159489e2d5961acf0e47575e08f35584009178e321", size = 160821, upload-time = "2026-01-30T01:03:19.684Z" }, - { url = "https://files.pythonhosted.org/packages/80/98/e83a36fe8d170c911f864bfded690d2542bfcfacb9c649d11a9e6eb9dc41/pytokens-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f50fd18543be72da51dd505e2ed20d2228c74e0464e4262e4899797803d7fa", size = 254263, upload-time = "2026-01-30T01:03:20.834Z" }, - { url = "https://files.pythonhosted.org/packages/0f/95/70d7041273890f9f97a24234c00b746e8da86df462620194cef1d411ddeb/pytokens-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dc74c035f9bfca0255c1af77ddd2d6ae8419012805453e4b0e7513e17904545d", size = 268071, upload-time = "2026-01-30T01:03:21.888Z" }, - { url = "https://files.pythonhosted.org/packages/da/79/76e6d09ae19c99404656d7db9c35dfd20f2086f3eb6ecb496b5b31163bad/pytokens-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f66a6bbe741bd431f6d741e617e0f39ec7257ca1f89089593479347cc4d13324", size = 271716, upload-time = "2026-01-30T01:03:23.633Z" }, - { url = "https://files.pythonhosted.org/packages/79/37/482e55fa1602e0a7ff012661d8c946bafdc05e480ea5a32f4f7e336d4aa9/pytokens-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:b35d7e5ad269804f6697727702da3c517bb8a5228afa450ab0fa787732055fc9", size = 104539, upload-time = "2026-01-30T01:03:24.788Z" }, - { url = "https://files.pythonhosted.org/packages/30/e8/20e7db907c23f3d63b0be3b8a4fd1927f6da2395f5bcc7f72242bb963dfe/pytokens-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8fcb9ba3709ff77e77f1c7022ff11d13553f3c30299a9fe246a166903e9091eb", size = 168474, upload-time = "2026-01-30T01:03:26.428Z" }, - { url = "https://files.pythonhosted.org/packages/d6/81/88a95ee9fafdd8f5f3452107748fd04c24930d500b9aba9738f3ade642cc/pytokens-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79fc6b8699564e1f9b521582c35435f1bd32dd06822322ec44afdeba666d8cb3", size = 290473, upload-time = "2026-01-30T01:03:27.415Z" }, - { url = "https://files.pythonhosted.org/packages/cf/35/3aa899645e29b6375b4aed9f8d21df219e7c958c4c186b465e42ee0a06bf/pytokens-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d31b97b3de0f61571a124a00ffe9a81fb9939146c122c11060725bd5aea79975", size = 303485, upload-time = "2026-01-30T01:03:28.558Z" }, - { url = "https://files.pythonhosted.org/packages/52/a0/07907b6ff512674d9b201859f7d212298c44933633c946703a20c25e9d81/pytokens-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:967cf6e3fd4adf7de8fc73cd3043754ae79c36475c1c11d514fc72cf5490094a", size = 306698, upload-time = "2026-01-30T01:03:29.653Z" }, - { url = "https://files.pythonhosted.org/packages/39/2a/cbbf9250020a4a8dd53ba83a46c097b69e5eb49dd14e708f496f548c6612/pytokens-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:584c80c24b078eec1e227079d56dc22ff755e0ba8654d8383b2c549107528918", size = 116287, upload-time = "2026-01-30T01:03:30.912Z" }, - { url = "https://files.pythonhosted.org/packages/c6/78/397db326746f0a342855b81216ae1f0a32965deccfd7c830a2dbc66d2483/pytokens-0.4.1-py3-none-any.whl", hash = "sha256:26cef14744a8385f35d0e095dc8b3a7583f6c953c2e3d269c7f82484bf5ad2de", size = 13729, upload-time = "2026-01-30T01:03:45.029Z" }, -] - [[package]] name = "pytz" version = "2026.2" @@ -1303,6 +1284,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3b/5d/63d4ae3b9daea098d5d6f5da83984853c1bbacd5dc826764b249fe119d24/requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36", size = 24179, upload-time = "2024-03-22T20:32:28.055Z" }, ] +[[package]] +name = "rich" +version = "15.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" }, +] + [[package]] name = "rjsmin" version = "1.2.5" @@ -1323,6 +1317,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/00/f3/37a4672ddb1307eb57d9b54ba89a48f483a04a63cac4e1471fdb4cba76e6/rjsmin-1.2.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:47dad1732a2c4779bdc76d5b3183fdf2ec27838f31071fa9dfcc79483d3480e2", size = 34161, upload-time = "2025-10-12T10:51:23.761Z" }, ] +[[package]] +name = "ruff" +version = "0.15.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/8a/8bce2894573e9dae6ff4d77fe34ad727d79b9e6238ad288c5638990d90f6/ruff-0.15.14.tar.gz", hash = "sha256:48e866b165be4a9bdbf310f7d3c9a07edef2fe8cd63ffeb4e00bb590506ebf9f", size = 4700910, upload-time = "2026-05-21T14:34:55.177Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/c8/74a92c6ff9fcfb4f1f947126d3ebee8389276e161ecc85de5bda7cda51bd/ruff-0.15.14-py3-none-linux_armv6l.whl", hash = "sha256:8dd2db9416e487c8d4b01fa7056bb02c4d05969d4f8d17a08c229c2f4ff3c108", size = 10739177, upload-time = "2026-05-21T14:34:37.332Z" }, + { url = "https://files.pythonhosted.org/packages/45/91/254a35c20acc38a7223c9d2d594af12e794432464f2cdeb52af1dc4a892d/ruff-0.15.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:be4ff55af755bd71a00ab3dc6bd7ffc467bd76e0df6881e286c2e3d23e8fb43b", size = 11144969, upload-time = "2026-05-21T14:34:43.978Z" }, + { url = "https://files.pythonhosted.org/packages/56/9e/d13e40f83b8d0a94430e6778ce1d94a43b38cf2efe63278bdd2b4c65abbf/ruff-0.15.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:48d5909d7d06276ce7dde6d32bfa4b0d4cb2651145cd8ee4b440722cbc77832f", size = 10478207, upload-time = "2026-05-21T14:34:48.378Z" }, + { url = "https://files.pythonhosted.org/packages/8d/f1/b15a7839fa4f332f8acec78e20564f26bb2d866e3d21710b877fd0263000/ruff-0.15.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca8cbfa94c4f90984a67561978602746d4cd27103568f745fa90eee3f0d4107d", size = 10818459, upload-time = "2026-05-21T14:34:22.318Z" }, + { url = "https://files.pythonhosted.org/packages/45/33/53d651177f84f94b400a0e27f8824eeada3dddc9d5ee8aeb048f4352a520/ruff-0.15.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a6bbc0333f1ab053423bcbf6226477d266ca7cec7738c4c8e3f55647803f3c4", size = 10541800, upload-time = "2026-05-21T14:34:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/b8/a6/868f87e0bf9786ed24b5d0d0ad8676b8a94fd1912f42cddf9cfc7857818a/ruff-0.15.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a24a4f7605d7003a6674d4387651effd939dead3fddd0f36561eb77a9a2e542", size = 11342149, upload-time = "2026-05-21T14:34:46.365Z" }, + { url = "https://files.pythonhosted.org/packages/a7/8b/38cd5c19faffdcc05a408d2b78edccc69492ab9720eadb49ea15ef80d768/ruff-0.15.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:049b5326e53ed80978f2fc041a280603f69dd6b0c95464342a2bb4572d9d9e2f", size = 12212563, upload-time = "2026-05-21T14:34:28.579Z" }, + { url = "https://files.pythonhosted.org/packages/3e/4d/a3c5b874a556d5731e3e657aaf04311bb76f0a5c3ec220ed43051be6b64b/ruff-0.15.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4ed42e6696c8dfa5f06728e6441993901f548eb92d73bc472cb5a38d1395fbf", size = 11493299, upload-time = "2026-05-21T14:34:41.836Z" }, + { url = "https://files.pythonhosted.org/packages/1e/c0/56472c251d09858a53e51efbd485b09e1995d8731668b76d52e5dd6ee0f1/ruff-0.15.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:715c543cf450c4888251f91c52f1942a800541d9bddd7ac060aa4e6b77ae7cba", size = 11455931, upload-time = "2026-05-21T14:34:57.276Z" }, + { url = "https://files.pythonhosted.org/packages/2c/4a/e2e7b4d8dbf233d4eace59c75bc3435fa6d8bd3bae82d351d4e4300c0fd1/ruff-0.15.14-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:72ebab6013ec887d439d8b7593737a0a4ffb06d45d209d4e4bf2e92813082d3f", size = 11400794, upload-time = "2026-05-21T14:34:39.773Z" }, + { url = "https://files.pythonhosted.org/packages/97/c7/83c0539fe34c3e09136204d1e75d6052492364e0b3cb05e9465423f567d7/ruff-0.15.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:49072d36abdbe97a8dd7f480afe9c675699c0c495d4c84076e2c1203c4550581", size = 10804759, upload-time = "2026-05-21T14:34:31.045Z" }, + { url = "https://files.pythonhosted.org/packages/86/a6/18f2bfc095a2ab4a78745644e428205532ce6653a5d0fa8501572891534d/ruff-0.15.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:958522aee105068640c2c2ceae08f413ae44d922f52a1374ac13d6a96032fc93", size = 10539517, upload-time = "2026-05-21T14:34:53.064Z" }, + { url = "https://files.pythonhosted.org/packages/54/3a/5a8b3b69c654d4e4bf1d246ac5b49cbcdac6eaab6905925f8915f31e3b80/ruff-0.15.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f3707da619a143a2e8830e2abab8224478d69ace2d28cb6c20543ae97c36bf61", size = 11065169, upload-time = "2026-05-21T14:34:24.484Z" }, + { url = "https://files.pythonhosted.org/packages/ed/c5/8864e4e7925b836ea354b31d57641ec03830564e281a8b6f061f8c3e0ec1/ruff-0.15.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:bb01d645694e3ec0102105d07ef2d53703970407d59c04e59d3ba0b7a1d53553", size = 11560214, upload-time = "2026-05-21T14:34:50.975Z" }, + { url = "https://files.pythonhosted.org/packages/36/38/012bf76752e1f89ed50b77b99532d90f3a3e287bc7918e1fc0948ac866ac/ruff-0.15.14-py3-none-win32.whl", hash = "sha256:6d0c1ad2a0ab718d39b6d8fd2217981ce4d625cd96a720095f798fb47d8b13e6", size = 10805548, upload-time = "2026-05-21T14:34:33.453Z" }, + { url = "https://files.pythonhosted.org/packages/d1/b7/4ea2c170f10ad760fff2a5250beb18897719dc8b52b53a24cddbb9dd3f19/ruff-0.15.14-py3-none-win_amd64.whl", hash = "sha256:802342981e056db3851a7836e5b070f8f15f67d4a685ae2a6160939d364b2902", size = 11939523, upload-time = "2026-05-21T14:34:18.077Z" }, + { url = "https://files.pythonhosted.org/packages/62/d5/bc97ff895ec35cf3925d4bd60f3b39d822f377a446906ec9bcc87405e59b/ruff-0.15.14-py3-none-win_arm64.whl", hash = "sha256:ff47b90a9ef6a40c9e2f3b479c1fb78531adf055b94c1eba0a7ba04b31951826", size = 11208607, upload-time = "2026-05-21T14:34:26.525Z" }, +] + [[package]] name = "six" version = "1.17.0" @@ -1341,6 +1360,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba", size = 46138, upload-time = "2025-12-19T07:17:46.573Z" }, ] +[[package]] +name = "stevedore" +version = "5.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e9/88/35e4d27d9177d7df76d060e0a18f69c6c5794c96960c94042e20a12c8ba2/stevedore-5.8.0.tar.gz", hash = "sha256:b49867b32ca3016e94100e68dbf26e72aa7b8708d0a3f73c08aeb220370ac715", size = 514710, upload-time = "2026-05-18T09:15:27.731Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f5/ac/19f9941c74add59d17694930ec8105d5eddeee4ce56dd8632b765ca16d6c/stevedore-5.8.0-py3-none-any.whl", hash = "sha256:88eede9e66ca80e34085b9174e2327da2c61ac91f24f70e41c3ad76e4bb4872b", size = 54553, upload-time = "2026-05-18T09:15:25.82Z" }, +] + [[package]] name = "tornado" version = "6.5.5" @@ -1358,6 +1386,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/c8/876602cbc96469911f0939f703453c1157b0c826ecb05bdd32e023397d4e/tornado-6.5.5-cp39-abi3-win_arm64.whl", hash = "sha256:2c9a876e094109333f888539ddb2de4361743e5d21eece20688e3e351e4990a6", size = 448016, upload-time = "2026-03-10T21:31:00.43Z" }, ] +[[package]] +name = "ty" +version = "0.0.39" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/8d/7b5c74dc287fbcb37bae9853cec13bf44717c1735298500e4aeba31579a9/ty-0.0.39.tar.gz", hash = "sha256:f750277e76a01ecd86185960eca73823c26a53c51103568d56d4d904575159fd", size = 5702365, upload-time = "2026-05-22T21:09:56.403Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/17/9b89802c26d12d0f7a27bc25d4066d941d42891e8898f9f26499f0067e32/ty-0.0.39-py3-none-linux_armv6l.whl", hash = "sha256:c1bb7ac70f1f7d70cc6655fd96558039e4562b10f489fa49c7ebfd5fcee73ad1", size = 11360431, upload-time = "2026-05-22T21:09:18.689Z" }, + { url = "https://files.pythonhosted.org/packages/9c/c6/663ded50e823dbf9fb9d002eca46b7cb1fb2c72b744b84f22ce732a0ee0b/ty-0.0.39-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:3435b64c1e59c14c9aa39c20cc018823937cd38d55db853e74d95b8f420569b0", size = 11096281, upload-time = "2026-05-22T21:09:15.383Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ae/5d38ba9a6456ff4c78d212cf464fd8b9a25d8118465197b0b2dc891c0b19/ty-0.0.39-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5f136377ce46c73677701a9e1ad730bf72f699bcec046e422eb79d0886cac3ab", size = 10529674, upload-time = "2026-05-22T21:09:46.471Z" }, + { url = "https://files.pythonhosted.org/packages/be/6f/43638cb8106445d3c8817256a0731cde9dd7b6a53ae2e881294bc1930ca3/ty-0.0.39-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36b65fb0cc17f03e851d40e210d420be94ab8bc52d041328ad1e45f616036a61", size = 11055561, upload-time = "2026-05-22T21:09:36.981Z" }, + { url = "https://files.pythonhosted.org/packages/91/17/95e62cf4458527ce78dc386eba18f8b10c3fb64cd8c9e7e59b262ff6029d/ty-0.0.39-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4967967bfadf3860ff84c3fccdbaec8edf8aa20d0d727521084733d853de6657", size = 11127185, upload-time = "2026-05-22T21:09:31.395Z" }, + { url = "https://files.pythonhosted.org/packages/4e/c0/93666c213db5c71ab1b1f1a0db5f66bf8c7c0e0b0bf59859f5da8f0b3c36/ty-0.0.39-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e10ecb1297099ddf9a1f054f8bd921d1863ce85fb819a3c96ed27865a1ba6ed", size = 11608459, upload-time = "2026-05-22T21:09:12.862Z" }, + { url = "https://files.pythonhosted.org/packages/79/85/3b26585afc8b50230d6464bb0642feef4fab3f847e38b1f0ffa971a81446/ty-0.0.39-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9b19cca70e465d71b0510656343883d62372bbe74b7845cae7c0e701d6d5264b", size = 12177101, upload-time = "2026-05-22T21:09:40.519Z" }, + { url = "https://files.pythonhosted.org/packages/49/4a/1039e4f6afc576dc1c3a4d22a6478904a1ad3766597cd0b93c077ab9dfce/ty-0.0.39-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:56c6704b01b9b3d80ff26b2918423b742516d1e469bef830e9254dcedc9185bf", size = 11827815, upload-time = "2026-05-22T21:09:49.89Z" }, + { url = "https://files.pythonhosted.org/packages/e2/c5/4688652870e350a76a8157f7ffb59ad54f37d5d10725aa7076f66ac94ec8/ty-0.0.39-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b7840ff46764b6a6757f4ade1cd0530fc3e8a0b435ca93e7602360e4cb90b6", size = 11694429, upload-time = "2026-05-22T21:09:21.568Z" }, + { url = "https://files.pythonhosted.org/packages/fc/72/8a1c4e823bb5bdc935a1c8140e100304e36a68a4139592f170aa9736fdb7/ty-0.0.39-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:1c62a3a87ce26b50819f0dbf03bd95f23f19eeb87bbc7aa732ec64277c77f1aa", size = 11869846, upload-time = "2026-05-22T21:09:28.053Z" }, + { url = "https://files.pythonhosted.org/packages/17/9f/cf982457b861ae22d657c5dcdbc631199f7f90264279db1d17230dfbc3ff/ty-0.0.39-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f8c34bc81a9c3516e49904e9d8330aac385377cca98390193ea02b903a40fcf0", size = 11029763, upload-time = "2026-05-22T21:09:06.791Z" }, + { url = "https://files.pythonhosted.org/packages/46/c9/95b64f6d43ae6e8f0b7e13dacf9c196d35819af22b1924171fba31383156/ty-0.0.39-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:66f5ab11586a64e79cb692ad685ee5469325c31b5f30bd3554f52f36dbe28cc4", size = 11146761, upload-time = "2026-05-22T21:09:10.178Z" }, + { url = "https://files.pythonhosted.org/packages/52/69/0a89cfb06f7632a05bf56c78e0affb4a40f81759e275376cea75c9c5abe9/ty-0.0.39-py3-none-musllinux_1_2_i686.whl", hash = "sha256:e8d89732bcbbcb091f439e556dfc4932f198b118b47d5b85212c60662099670e", size = 11281843, upload-time = "2026-05-22T21:09:34.234Z" }, + { url = "https://files.pythonhosted.org/packages/0e/53/64c4a27067a46643fea2b3fcf21a8a2f838d91a65ffdd14f2e82945b9538/ty-0.0.39-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:eceb6c91dcd05a231119f82abdd9aa337513de23ca6ac990bc44f88791dc1799", size = 11792477, upload-time = "2026-05-22T21:09:24.923Z" }, + { url = "https://files.pythonhosted.org/packages/1a/e8/02f4dd4a12bcdbda0006f9c7ff3b99a4be06bd0d257d3bd4a5b66de074e6/ty-0.0.39-py3-none-win32.whl", hash = "sha256:891c3262314dbc80bf3e872634d23dd216306945daa9a9fcc206ce5ed21ac4c9", size = 10615377, upload-time = "2026-05-22T21:09:43.167Z" }, + { url = "https://files.pythonhosted.org/packages/b5/5a/aaeb22faa8d4dae90a287d4c3636c671edcff3b99be5f4fc8b79ad71eef6/ty-0.0.39-py3-none-win_amd64.whl", hash = "sha256:ba7f2d54452535419e90f6f03ff39282999e87b43c21c00559f6d7ad711a36d5", size = 11710711, upload-time = "2026-05-22T21:09:53.179Z" }, + { url = "https://files.pythonhosted.org/packages/a3/17/ae7339651bfcaa5f54698c8c70eaf5031baa400ecb67baec31d03a56cbd4/ty-0.0.39-py3-none-win_arm64.whl", hash = "sha256:eb4cf0fefbbfedf9a352597bb2431ebdcb7eb3a595c0f825f228e897a0ec285d", size = 11081409, upload-time = "2026-05-22T21:09:03.741Z" }, +] + [[package]] name = "tzdata" version = "2026.2" diff --git a/README.md b/README.md index 9fceab6..e770e65 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ 1. Download repository. 2. Set .env file based on template. 3. Install Docker Desktop. -4. Run containters: +4. Run containers: ``` docker-compose up -d --build ``` @@ -78,7 +78,7 @@ ``` pre-commit install ``` -7. Run containters: +7. Run containers: ``` docker-compose up -d --build ``` diff --git a/doc/01_adr_functionality.md b/doc/01_adr_functionality.md index dff92df..b4f56c0 100644 --- a/doc/01_adr_functionality.md +++ b/doc/01_adr_functionality.md @@ -5,15 +5,15 @@ `2023-06-04` -### Status +### Status In-building -### Context +### Context We need to create a list of main functions to define business justification of first version of an application and decide what functionality should be canceled or suspended to further implementation in next releases. -### Decision +### Decision A first brainstorm created a list of basic functions expectted to implement: - Create a databases to contain at least data like: @@ -25,18 +25,18 @@ A first brainstorm created a list of basic functions expectted to implement: - Generate static diagrams on button demand, like a charts of weight and consumed amount of medicines, - Creat sticky notes kanboard to manage a feeding period per purchased food, - Sending visit notifications via at least one of: sms, whatsap, messenger, e-mail, discord, -- Printable notes and charts into pdf reports, +- Printable notes and charts into pdf reports, - Synchronization into a google calendar, - Basic API to consider a transfer of charts into Dash-Plotly. List to-do's suspended until next iterations of application: - Interactive dashboards, -- Implementation all of proposed notification methods, +- Implementation all of proposed notification methods, - Direct chat between users, without using animal's notes. -### Consequences -An effortful list of functionality has been created to exercise a building process of web applications. +### Consequences +An effortful list of functionality has been created to exercise a building process of web applications. The demands have been divided into quickly attainable goals, leaving a basic draft of a further development. diff --git a/doc/02_adr_django.md b/doc/02_adr_django.md index adb99b8..454a427 100644 --- a/doc/02_adr_django.md +++ b/doc/02_adr_django.md @@ -5,35 +5,35 @@ `2023-06-05` -### Status +### Status Done -### Context +### Context We need to choose a main web framework for the project to create the core of the application.\ Considered technologies: -- [x] Django, +- [x] Django, - [ ] Flask, - [ ] Dash Plotly. -### Decision +### Decision Django was selected. The developer has the most recent experience and the desire to systematize knowledge. Flask, as a microframework, could extend the time to the first working prototype. -Dash is a derivative framework for Flask with extensive features for generating interactive dashboards. +Dash is a derivative framework for Flask with extensive features for generating interactive dashboards. This functionality has been postponed to a later stage of the application development. -### Consequences +### Consequences An expected short time to prepare the first working prototype. With good community support, plugins supporting specific functionalities should be available (ORM, logging, api, etc.). ### Keywords - Django, -- Flask, +- Flask, - Dash Plotly, - web framework. diff --git a/doc/03_adr_monolit.md b/doc/03_adr_monolit.md index 4f42667..fbd98a4 100644 --- a/doc/03_adr_monolit.md +++ b/doc/03_adr_monolit.md @@ -5,23 +5,23 @@ `2023-06-05` -### Status +### Status Done -### Context +### Context We need to choose an approach to building the project's application structure.\ -Considered approaches: +Considered approaches: - [x] Monolith, - [ ] Microservices. -### Decision -Due to the selection of Django as the main framework, an application in the monolithic architecture will be created, +### Decision +Due to the selection of Django as the main framework, an application in the monolithic architecture will be created, open via APIs to the possibility of adding selective functionalities in the form of microservices. -### Consequences +### Consequences Each new functionality will need to be considered to determine it will be easier to implement as a fragment of the monolith or as a new microservice. diff --git a/doc/04_adr_monorepo.md b/doc/04_adr_monorepo.md index 86d7b64..a9da6d9 100644 --- a/doc/04_adr_monorepo.md +++ b/doc/04_adr_monorepo.md @@ -5,13 +5,13 @@ `2023-06-05` -### Status +### Status Done -### Context +### Context We need to choose an approach to building and maintaining the repositories and branches.\ -Considered approaches: +Considered approaches: - [x] Monorepo, - [ ] Polirepo, --- @@ -21,14 +21,14 @@ Considered approaches: - [ ] Trunk-based development. -### Decision +### Decision The Monorepo approach will be used due to the small number of developers and the expected number of parallel branches. -The number of developers also affects the decision to manage branches and approach to deployment. -GitHub-Flow was selected. In a small organization, a least detailed approach will suffice. +The number of developers also affects the decision to manage branches and approach to deployment. +GitHub-Flow was selected. In a small organization, a least detailed approach will suffice. -### Consequences +### Consequences Possible future migrations will be easier in the direction from simpler to more complicated. diff --git a/doc/05_adr_matlibplot.md b/doc/05_adr_matlibplot.md index cc3f0fa..8f171bc 100644 --- a/doc/05_adr_matlibplot.md +++ b/doc/05_adr_matlibplot.md @@ -5,13 +5,13 @@ `2023-06-05` -### Status +### Status Proposed -### Context +### Context We need to choose a technology to create charts for the application.\ -Considered approaches: +Considered approaches: - [x] Static charts: - [x] Matplotlib, @@ -21,12 +21,12 @@ Considered approaches: - [x] Chart.js, -### Decision -To avoid the proliferation of microservices, a decision has been made to prototype using a static method of generating charts. +### Decision +To avoid the proliferation of microservices, a decision has been made to prototype using a static method of generating charts. The presented data is not expected to require frequent refreshing and filtering of the range. -### Consequences +### Consequences A faster development process and the possibility of future functionality replacement. After preparing the static prototype, tests with Chart.js will be carried out and the cost of implementation will be estimated. diff --git a/doc/06_adr_html_template.md b/doc/06_adr_html_template.md index 9caf563..62dc2db 100644 --- a/doc/06_adr_html_template.md +++ b/doc/06_adr_html_template.md @@ -5,19 +5,19 @@ `2023-06-05` -### Status +### Status Done -### Context +### Context We need to choose a main template for frontend part of the project. -### Decision +### Decision pass -### Consequences +### Consequences pass ### Keywords diff --git a/doc/07_adr_drf.md b/doc/07_adr_drf.md index 5e2c3db..45335b2 100644 --- a/doc/07_adr_drf.md +++ b/doc/07_adr_drf.md @@ -5,23 +5,23 @@ `2023-06-05` -### Status +### Status Proposed -### Context +### Context We need to choose a basic API framework to inside and outside communication.\ -Considered approaches: +Considered approaches: - Django REST Framework, - Django Ninja, - FastAPI, - GraphQL. -### Decision +### Decision pass -### Consequences +### Consequences pass diff --git a/doc/08_adr_databases.md b/doc/08_adr_databases.md index 18d6162..9c7e12a 100644 --- a/doc/08_adr_databases.md +++ b/doc/08_adr_databases.md @@ -5,13 +5,13 @@ `2023-06-05` -### Status +### Status In-building -### Context +### Context We need to choose a database for a specific task within the application.\ -Considered DBMS: +Considered DBMS: - [x] PostgreSQL, - [ ] MS SQL, - [ ] MySQL, @@ -22,7 +22,7 @@ Considered DBMS: - [x] CouchDB. -### Decision +### Decision Tree databases have been selected for routing testing. PostgreSQL - quick database creation and configuration with a good SQL interface. It has many use cases with Django. @@ -32,8 +32,8 @@ CouchDB - native support for files as attachments. Non-relational database, inte Redis - default broker for Celery queue. -### Consequences -In basic form database routing is required. +### Consequences +In basic form database routing is required. The implementation should be quick, as the second database will be used only for storing attachment files. @@ -53,11 +53,11 @@ Homepages: https://www.sqlite.org/index.html https://www.mongodb.com/ - + https://redis.io/ - + https://firebirdsql.org/ - + https://couchdb.apache.org/ *[2023-01-24]*\ diff --git a/doc/09_adr_user_data.md b/doc/09_adr_user_data.md index 49839c4..257e8df 100644 --- a/doc/09_adr_user_data.md +++ b/doc/09_adr_user_data.md @@ -5,13 +5,13 @@ `2023-07-09` -### Status +### Status In-building -### Context +### Context We need to set up a place in documentation to list all collect all data about users and group them by correct place in databases and direct tables. -Main sections of data by sources: +Main sections of data by sources: - user, - animal, - medical record note, @@ -19,14 +19,14 @@ Main sections of data by sources: - medicines, - medical facility, - veterinarian, -- dates sheduling, +- dates scheduling, - costs counting. -### Decision +### Decision User datatables: - collected by the registration process: - - basic provided by user informations: + - basic provided by user information: - name, - email, - password, @@ -34,21 +34,21 @@ User datatables: - date of registration, - default profile image, - default background image, - - default user priviliges (viever, owner, creator, moderator, admin etc.) + - default user privileges (viewer, owner, creator, moderator, admin etc.) - collected after the registration process: - provided in profil page: - profile image, - - bacground image choosen, + - background image chosen, - email-change, - password-change, - date of birthday, - stable view(compedium of animals: owned and cared) - connections other models: - - animal - ovner, viewer, - - medical record nove - participation in visit + - animal - owner, viewer, + - medical record note - participation in visit - medical_place_id, - note_ - - + - Medical records (animal timeline) @@ -73,7 +73,7 @@ Medical records (animal timeline) -### Consequences +### Consequences ##### _Placeholder_ diff --git a/doc/10_adr_notification_trigger.md b/doc/10_adr_notification_trigger.md index fc9047c..72f9713 100644 --- a/doc/10_adr_notification_trigger.md +++ b/doc/10_adr_notification_trigger.md @@ -5,11 +5,11 @@ `2023-12-19` -### Status +### Status In-building -### Context +### Context We need to choose a technology for sending set by users notifications. The basic channel for sending notifications include: - e-mail, @@ -25,11 +25,11 @@ Options: - django-cron. -### Decision +### Decision Django-crontab -### Consequences +### Consequences 1. **Integration with Django:** django-crontab is a Django extension, making it a natural choice for seamlessly scheduling tasks in a Django-based application. This integration facilitates code maintenance and management. @@ -43,7 +43,7 @@ Django-crontab ### Keywords - Celery, - Cronjobs, -- queue, +- queue, - broker, - subscriptions,. From 90670ec2108ea5eae4683d05caebe72728af975e Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Sun, 24 May 2026 20:06:52 +0200 Subject: [PATCH 04/27] refactor(tests): migrate test runner to pytest with markers --- .github/workflows/django.yml | 8 +- AHC_app/AHC_app/settings.py | 9 +- AHC_app/conftest.py | 0 AHC_app/homepage/tests/test_homepage.py | 3 + AHC_app/pyproject.toml | 13 +++ AHC_app/uv.lock | 105 ++++++++++++++++++++++++ 6 files changed, 134 insertions(+), 4 deletions(-) create mode 100644 AHC_app/conftest.py diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml index fbbc571..37672a8 100644 --- a/.github/workflows/django.yml +++ b/.github/workflows/django.yml @@ -47,13 +47,17 @@ jobs: python-version: "3.14" - name: Install dependencies - run: uv sync --no-group dev + run: uv sync working-directory: ./AHC_app - - name: Run tests + - name: Run tests (Django runner) run: PYTHONPATH=$(pwd) uv run python manage.py test working-directory: ./AHC_app + - name: Run tests (pytest) + run: uv run pytest -m "not slow" + working-directory: ./AHC_app + build-and-push: name: Build and Push to ECR runs-on: ubuntu-latest diff --git a/AHC_app/AHC_app/settings.py b/AHC_app/AHC_app/settings.py index 45bcaf3..4ddaed6 100644 --- a/AHC_app/AHC_app/settings.py +++ b/AHC_app/AHC_app/settings.py @@ -17,6 +17,11 @@ import pycouchdb from decouple import config + +def _is_test_run() -> bool: + return "test" in sys.argv or (bool(sys.argv) and "pytest" in sys.argv[0]) + + # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent @@ -94,7 +99,7 @@ # Database # https://docs.djangoproject.com/en/4.2/ref/settings/#databases -if "test" in sys.argv: +if _is_test_run(): DATABASES = { "default": { "ENGINE": "django.db.backends.sqlite3", @@ -115,7 +120,7 @@ # COUCH_CONNECTOR = (config("COUCH_CONNECTOR"),) -if "test" not in sys.argv: +if not _is_test_run(): COUCHDB_USER = config("COUCHDB_USER") COUCHDB_PASSWORD = config("COUCHDB_PASSWORD") COUCHDB_PORT = config("COUCHDB_PORT") diff --git a/AHC_app/conftest.py b/AHC_app/conftest.py new file mode 100644 index 0000000..e69de29 diff --git a/AHC_app/homepage/tests/test_homepage.py b/AHC_app/homepage/tests/test_homepage.py index fa3783f..ac3ac0b 100644 --- a/AHC_app/homepage/tests/test_homepage.py +++ b/AHC_app/homepage/tests/test_homepage.py @@ -1,5 +1,6 @@ from html.parser import HTMLParser +import pytest from django.contrib.auth.models import User from django.test import Client, TestCase @@ -18,6 +19,8 @@ def handle_starttag(self, tag, attrs): self.found_href = True +@pytest.mark.integration +@pytest.mark.django_db class TestHomepage(TestCase): def setUp(self) -> None: my_user = User.objects.create(username="test_user_placeholder") diff --git a/AHC_app/pyproject.toml b/AHC_app/pyproject.toml index f93635a..843520b 100644 --- a/AHC_app/pyproject.toml +++ b/AHC_app/pyproject.toml @@ -46,6 +46,9 @@ dev = [ "ty", "codespell", "bandit[toml]", + "pytest", + "pytest-django", + "pytest-cov", ] [tool.uv] @@ -66,6 +69,16 @@ ignore = [ quote-style = "double" indent-style = "space" +[tool.pytest.ini_options] +DJANGO_SETTINGS_MODULE = "AHC_app.settings" +python_files = ["test_*.py", "tests.py"] +addopts = "--strict-markers" +markers = [ + "unit: fast isolated tests with no DB access", + "integration: tests that use the DB or external services", + "slow: tests that take more than a few seconds", +] + [tool.ty.environment] python-version = "3.14" diff --git a/AHC_app/uv.lock b/AHC_app/uv.lock index 4c03322..e2de1ba 100644 --- a/AHC_app/uv.lock +++ b/AHC_app/uv.lock @@ -130,6 +130,9 @@ dev = [ { name = "bandit" }, { name = "codespell" }, { name = "pre-commit" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "pytest-django" }, { name = "ruff" }, { name = "ty" }, ] @@ -175,6 +178,9 @@ dev = [ { name = "bandit", extras = ["toml"] }, { name = "codespell" }, { name = "pre-commit" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "pytest-django" }, { name = "ruff" }, { name = "ty" }, ] @@ -458,6 +464,45 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] +[[package]] +name = "coverage" +version = "7.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/23/7f/d0720730a397a999ffc0fd3f5bebef347338e3a47b727da66fbb228e2ff2/coverage-7.14.0.tar.gz", hash = "sha256:057a6af2f160a85384cde4ab36f0d2777bae1057bae255f95413cdd382aa5c74", size = 919489, upload-time = "2026-05-10T18:02:31.397Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1c/18/b9a6586d73992807c26f9a5f274131be3d76b56b18a82b9392e2a25d2e45/coverage-7.14.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:9aed9fa983514ca032790f3fe0d1c0e42ca7e16b42432af1706b50a9a46bef5d", size = 220036, upload-time = "2026-05-10T18:01:33.057Z" }, + { url = "https://files.pythonhosted.org/packages/f3/9b/4165a1d56ddc302a0e2d518fd9d412a4fd0b57562618c78c5f21c57194f5/coverage-7.14.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ba3b8390db29296dbbf49e91b6fe08f990743a90c8f447ba4c2ffc29670dfa63", size = 220368, upload-time = "2026-05-10T18:01:34.705Z" }, + { url = "https://files.pythonhosted.org/packages/69/aa/c12e52a5ba148d9995229d557e3be6e554fe469addc0e9241b2f0956d8ea/coverage-7.14.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3a5d8e876dfa2f102e970b183863d6dedd023d3c0eeca1fe7a9787bc5f28b212", size = 251417, upload-time = "2026-05-10T18:01:36.949Z" }, + { url = "https://files.pythonhosted.org/packages/d7/51/ec641c26e6dca1b25a7d2035ba6ecb7c884ef1a100a9e42fbe4ce4405139/coverage-7.14.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5ebb8f4614a3787d567e610bbfdf96a4798dd69a1afb1bd8ad228d4111fe6ff3", size = 253924, upload-time = "2026-05-10T18:01:38.985Z" }, + { url = "https://files.pythonhosted.org/packages/33/c4/59c3de0bd1b538824173fd518fed51c1ce740ca5ed68e74545983f4053a9/coverage-7.14.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b9bf47223dd8db3d4c4b2e443b02bace480d428f0822c3f991600448a176c97", size = 255269, upload-time = "2026-05-10T18:01:40.957Z" }, + { url = "https://files.pythonhosted.org/packages/7b/a9/36dfa153a62040296f6e7febfdb20a5720622f6ef5a81a41e8237b9a5344/coverage-7.14.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3485a836550b303d006d57cc06e3d5afaabc642c77050b7c985a97b13e3776b8", size = 257583, upload-time = "2026-05-10T18:01:42.607Z" }, + { url = "https://files.pythonhosted.org/packages/26/7b/cc2c048d4114d9ab1c2409e9ee365e5ae10736df6dffcfc9444effa6c708/coverage-7.14.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3e7e88110bae996d199d1693ca8ec3fd52441d426401ae963437598667b4c5eb", size = 251434, upload-time = "2026-05-10T18:01:44.537Z" }, + { url = "https://files.pythonhosted.org/packages/ee/df/6770eaa576e604575e9a78055313250faef5faa84bd6f71a39fece519c43/coverage-7.14.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:15228a6800ce7bdf1b74800595e56db7138cecb338fdbf044806e10dcf182dfe", size = 253280, upload-time = "2026-05-10T18:01:46.175Z" }, + { url = "https://files.pythonhosted.org/packages/ad/9e/1c0264514a3f98259a6d64765a397b2c8373e3ba59ee722a4802d3ec0c61/coverage-7.14.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:9d26ac7f5398bafc5b57421ad994e8a4749e8a7a0e62d05ec7d53014d5963bfa", size = 251241, upload-time = "2026-05-10T18:01:48.732Z" }, + { url = "https://files.pythonhosted.org/packages/64/16/4efdf3e3c4079cdbf0ece56a2fea872df9e8a3e15a13a0af4400e1075944/coverage-7.14.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2fb73254ff43c911c967a899e1359bc5049b4b115d6e8fbdde4937d0a2246cd5", size = 255516, upload-time = "2026-05-10T18:01:50.819Z" }, + { url = "https://files.pythonhosted.org/packages/93/69/b1de96346603881b3d1bc8d6447c83200e1c9700ffbaff926ba01ff5724c/coverage-7.14.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:454a380af72c6adada298ed270d38c7a391288198dbfb8467f786f588751a90c", size = 251059, upload-time = "2026-05-10T18:01:52.773Z" }, + { url = "https://files.pythonhosted.org/packages/a4/66/2881853e0363a5e0a724d1103e53650795367471b6afb234f8b49e713bc6/coverage-7.14.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:65c86fb646d2bd2972e96bd1a8b45817ed907cee68655d6295fe7ec031d04cca", size = 252716, upload-time = "2026-05-10T18:01:54.506Z" }, + { url = "https://files.pythonhosted.org/packages/55/5c/0d3305d002c41dcde873dbe456491e663dc55152ca526b630b5c47efd62f/coverage-7.14.0-cp314-cp314-win32.whl", hash = "sha256:6a6516b02a6101398e19a3f44820f69bab2590697f7def4331f668b14adaf828", size = 222788, upload-time = "2026-05-10T18:01:56.487Z" }, + { url = "https://files.pythonhosted.org/packages/f9/58/6e1b8f52fdc3184b47dc5037f5070d83a3d11042db1594b02d2a44d786c8/coverage-7.14.0-cp314-cp314-win_amd64.whl", hash = "sha256:45e0f79d8351fa76e256716df91eab12890d32678b9590df7ae1042e4bd4cf5d", size = 223600, upload-time = "2026-05-10T18:01:58.497Z" }, + { url = "https://files.pythonhosted.org/packages/00/70/a18c408e674bc26281cadaedc7351f929bd2094e191e4b15271c30b084cc/coverage-7.14.0-cp314-cp314-win_arm64.whl", hash = "sha256:4b899594a8b2d81e5cc064a0d7f9cac2081fed91049456cae7676787e41549c9", size = 222168, upload-time = "2026-05-10T18:02:00.411Z" }, + { url = "https://files.pythonhosted.org/packages/3d/89/2681f071d238b62aff8dfc2ab44fc24cfdb38d1c01f391a80522ff5d3a16/coverage-7.14.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:f580f8c80acd94ac72e863efe2cab791d8c38d153e0b463b92dfa000d5c84cd1", size = 220766, upload-time = "2026-05-10T18:02:02.313Z" }, + { url = "https://files.pythonhosted.org/packages/bd/c7/c987babafd9207ffa1995e1ef1f9b26762cf4963aa768a66b6f0501e4616/coverage-7.14.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a2bd259c442cd43c49b30fbafc51776eb19ea396faf159d26a83e6a0a5f13b0c", size = 221035, upload-time = "2026-05-10T18:02:04.017Z" }, + { url = "https://files.pythonhosted.org/packages/5a/e9/d6a5ac3b333088143d6fc877d398a9a674dc03124a2f776e131f03864823/coverage-7.14.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a706b908dfa85538863504c624b237a3cc34232bf403c057414ebfdb3b4d9f84", size = 262405, upload-time = "2026-05-10T18:02:05.915Z" }, + { url = "https://files.pythonhosted.org/packages/38/b1/e70838d29a7c08e22d44398a46db90815bbcbf28de06992bd9210d1a8d8e/coverage-7.14.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7333cd944ee4393b9b3d3c1b598c936d4fc8d70573a4c7dacfec5590dd50e436", size = 264530, upload-time = "2026-05-10T18:02:07.582Z" }, + { url = "https://files.pythonhosted.org/packages/6b/73/5c31ef97763288d03d9995152b96d5475b527c63d91c84b01caea894b83a/coverage-7.14.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f162bc9a15b82d947b02651b0c7e1609d6f7a8735ca330cfadec8481dd97d5a", size = 266932, upload-time = "2026-05-10T18:02:09.401Z" }, + { url = "https://files.pythonhosted.org/packages/e1/76/dd56d80f29c5f05b4d76f7e7c6d47cafacae017189c75c5759d24f9ff0cc/coverage-7.14.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:362cb78e01a5dc82009d88004cf60f2e6b6d6fcbfdec05b05af73b0abf40118f", size = 268062, upload-time = "2026-05-10T18:02:11.399Z" }, + { url = "https://files.pythonhosted.org/packages/6e/c7/27ba85cd5b95614f159ff93ebff1901584a8d192e2e5e24c4943a7453f59/coverage-7.14.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:acebd068fca5512c3a6fde9c045f901613478781a73f0e82b307b214daef23fb", size = 261504, upload-time = "2026-05-10T18:02:13.257Z" }, + { url = "https://files.pythonhosted.org/packages/13/2e/e8149f60ab5d5684c6eee881bdf34b127115cddbb958b196768dd9d63473/coverage-7.14.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:29fe3da551dface75deb2ccbf87b6b66e2e7ef38f6d89050b428be94afff3490", size = 264398, upload-time = "2026-05-10T18:02:15.063Z" }, + { url = "https://files.pythonhosted.org/packages/d9/7f/1261b025285323225f4b4abffa5a643649dfd67e25ddca7ebcbdea3b7cb3/coverage-7.14.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b4cc4fce8672fffcb09b0eafc167b396b3ba53c4a7230f54b7aaffbf6c835fa9", size = 262000, upload-time = "2026-05-10T18:02:16.756Z" }, + { url = "https://files.pythonhosted.org/packages/d3/dc/829c54f60b9d08389439c00f813c752781c496fc5788c78d8006db4b4f2b/coverage-7.14.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:5d4a51aad8ba8bdcd2b8bd8f03d4aca19693fa2327a3470e4718a25b03481020", size = 265732, upload-time = "2026-05-10T18:02:18.817Z" }, + { url = "https://files.pythonhosted.org/packages/ed/b0/70bd1419941652fa062689cba9c3eeafb8f5e6fbb890bce41c3bdda5dbd6/coverage-7.14.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:9f323af3e1e4f68b60b7b247e37b8515563a61375518fa59de1af48ba28a3db6", size = 260847, upload-time = "2026-05-10T18:02:20.528Z" }, + { url = "https://files.pythonhosted.org/packages/f2/73/be40b2390656c654d35ea0015ea7ba3d945769cf80790ad5e0bb2d56d2ba/coverage-7.14.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:1a0abc7342ea9711c469dd8b821c6c311e6bc6aac1442e5fbd6b27fae0a8f3db", size = 263166, upload-time = "2026-05-10T18:02:22.337Z" }, + { url = "https://files.pythonhosted.org/packages/29/55/4a643f712fcf7cf2881f8ec1e0ccb7b164aff3108f69b51801246c8799f2/coverage-7.14.0-cp314-cp314t-win32.whl", hash = "sha256:a9f864ef57b7172e2db87a096642dd51e179e085ab6b2c371c29e885f65c8fb2", size = 223573, upload-time = "2026-05-10T18:02:24.11Z" }, + { url = "https://files.pythonhosted.org/packages/27/96/3acae5da0953be042c0b4dea6d6789d2f080701c77b88e44d5bd41b9219b/coverage-7.14.0-cp314-cp314t-win_amd64.whl", hash = "sha256:29943e552fdc08e082eb51400fb2f58e118a83b5542bd06531214e084399b644", size = 224680, upload-time = "2026-05-10T18:02:25.896Z" }, + { url = "https://files.pythonhosted.org/packages/93/3d/6ab5d2dd8325d838737c6f8d83d62eb6230e0d70b87b51b57bbfd08fa767/coverage-7.14.0-cp314-cp314t-win_arm64.whl", hash = "sha256:742a73ea621953b012f2c4c2219b512180dd84489acf5b1596b0aafc55b9100b", size = 222703, upload-time = "2026-05-10T18:02:27.822Z" }, + { url = "https://files.pythonhosted.org/packages/61/e8/cb8e80d6f9f55b99588625062822bf946cf03ed06315df4bd8397f5632a1/coverage-7.14.0-py3-none-any.whl", hash = "sha256:8de5b61163aee3d05c8a2beab6f47913df7981dad1baf82c414d99158c286ab1", size = 211764, upload-time = "2026-05-10T18:02:29.538Z" }, +] + [[package]] name = "crispy-bootstrap4" version = "2026.2" @@ -819,6 +864,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/94/16/70255075a9859a0e3adb789b68ceb0e210dec03934245fd98d248226572f/idna-3.16-py3-none-any.whl", hash = "sha256:cc246e3a3f89580c3a951b5ad298ca4638078b2cdd4f115654332b5c26daded5", size = 74165, upload-time = "2026-05-22T00:16:16.698Z" }, ] +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + [[package]] name = "kombu" version = "5.6.2" @@ -982,6 +1036,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/75/a6/a0a304dc33b49145b21f4808d763822111e67d1c3a32b524a1baf947b6e1/platformdirs-4.9.6-py3-none-any.whl", hash = "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917", size = 21348, upload-time = "2026-04-09T00:04:09.463Z" }, ] +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + [[package]] name = "pre-commit" version = "4.6.0" @@ -1146,6 +1209,48 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, ] +[[package]] +name = "pytest" +version = "9.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165, upload-time = "2026-04-07T17:16:18.027Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16.13Z" }, +] + +[[package]] +name = "pytest-cov" +version = "7.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage" }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/51/a849f96e117386044471c8ec2bd6cfebacda285da9525c9106aeb28da671/pytest_cov-7.1.0.tar.gz", hash = "sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2", size = 55592, upload-time = "2026-03-21T20:11:16.284Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678", size = 22876, upload-time = "2026-03-21T20:11:14.438Z" }, +] + +[[package]] +name = "pytest-django" +version = "4.12.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/13/2b/db9a193df89e5660137f5428063bcc2ced7ad790003b26974adf5c5ceb3b/pytest_django-4.12.0.tar.gz", hash = "sha256:df94ec819a83c8979c8f6de13d9cdfbe76e8c21d39473cfe2b40c9fc9be3c758", size = 91156, upload-time = "2026-02-14T18:40:49.235Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/a5/41d091f697c09609e7ef1d5d61925494e0454ebf51de7de05f0f0a728f1d/pytest_django-4.12.0-py3-none-any.whl", hash = "sha256:3ff300c49f8350ba2953b90297d23bf5f589db69545f56f1ec5f8cff5da83e85", size = 26123, upload-time = "2026-02-14T18:40:47.381Z" }, +] + [[package]] name = "python-dateutil" version = "2.9.0.post0" From 70655b5b5571761b75ba11713253249b4c0fd289 Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Sun, 24 May 2026 20:09:58 +0200 Subject: [PATCH 05/27] chore(toolchain): add justfile with dev task recipes --- AHC_app/justfile | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 AHC_app/justfile diff --git a/AHC_app/justfile b/AHC_app/justfile new file mode 100644 index 0000000..87dccf8 --- /dev/null +++ b/AHC_app/justfile @@ -0,0 +1,52 @@ +set shell := ["pwsh", "-NoLogo", "-Command"] + +# Install all dependencies including dev group +install: + uv sync + +# Run all linters (ruff check, codespell, bandit) +lint: + uv run ruff check . + uv run codespell + uv run bandit -r . -c pyproject.toml + +# Format code and auto-fix lint issues +format: + uv run ruff format . + uv run ruff check --fix . + +# Run all tests excluding slow +test: + uv run pytest -m "not slow" + +# Run only unit tests +test-unit: + uv run pytest -m unit -v + +# Run only integration tests +test-integration: + uv run pytest -m integration -v + +# Start Django development server +runserver: + uv run python manage.py runserver + +# Apply database migrations +migrate: + uv run python manage.py migrate + +# Open Django shell +shell: + uv run python manage.py shell + +# Start all Docker services +docker-up: + docker-compose up -d --build + +# Stop all Docker services +docker-down: + docker-compose down + +# Run pre-commit hooks on all files +precommit: + uv run pre-commit run --all-files From 9be91b8634d71d642d526511797f7acd4314c492 Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Sun, 24 May 2026 20:15:05 +0200 Subject: [PATCH 06/27] refactor(settings): migrate STATICFILES_STORAGE to STORAGES for Django 5.1+ --- AHC_app/AHC_app/settings.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/AHC_app/AHC_app/settings.py b/AHC_app/AHC_app/settings.py index 4ddaed6..3c5dc3e 100644 --- a/AHC_app/AHC_app/settings.py +++ b/AHC_app/AHC_app/settings.py @@ -184,7 +184,14 @@ def _is_test_run() -> bool: COMPRESS_PRECOMPILERS = (("text/x-scss", "django_libsass.SassCompiler"),) COMPRESS_OFFLINE = True LIBSASS_OUTPUT_STYLE = "compressed" -STATICFILES_STORAGE = "django.contrib.staticfiles.storage.ManifestStaticFilesStorage" +STORAGES = { + "default": { + "BACKEND": "django.core.files.storage.FileSystemStorage", + }, + "staticfiles": { + "BACKEND": "django.contrib.staticfiles.storage.ManifestStaticFilesStorage", + }, +} """ DOCUMENTATION TO CUSTOM SCSS: https://picocss.com/docs/customization.html From 33c4a0137671338ff5862a0a331d5d08f462bd38 Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Sun, 24 May 2026 20:17:33 +0200 Subject: [PATCH 07/27] docs(readme): update stack references from Pipenv to uv and pytest --- README.md | 46 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index e770e65..4688021 100644 --- a/README.md +++ b/README.md @@ -44,11 +44,13 @@ --- ### Requirements: -- Python 3.12.2 +- Python 3.14 +- [uv](https://docs.astral.sh/uv/) (package manager) +- [just](https://just.systems/) (task runner, optional) - Docker & Docker Compose - PostgreSQL 15 (instance for volumes) - Apache CouchDB 3.3.3 (instance for volumes) -- [Packages](AHC_app/Pipfile) +- [Packages](AHC_app/pyproject.toml) - [pico-1.5.10](https://github.com/picocss/pico/archive/refs/tags/v1.5.10.zip) --- @@ -65,24 +67,30 @@ ### Dev-instance steps: 1. Download repository. 2. Set .env file based on the template. -3. Install Python, Docker Desktop, PostgreSQL and CouchDB as in _Requirements_. -4. Install pipenv: +3. Install Python 3.14, Docker Desktop, PostgreSQL and CouchDB as in _Requirements_. +4. Install uv and sync dependencies: ``` - pipenv install + pip install uv + cd AHC_app + uv sync ``` -5. Deploy vevn and synch requirements: +5. Install pre-commit hooks: ``` - pipenv install --dev + uv run pre-commit install ``` -6. Install precommit hooks: - ``` - pre-commit install - ``` -7. Run containers: +6. Run containers: ``` docker-compose up -d --build ``` +With `just` installed, steps 4–6 simplify to: +``` +cd AHC_app +just install +just precommit +just docker-up +``` + --- ### Kubernetes Deploy steps (alternative deploy): 1. Download repository. @@ -127,8 +135,18 @@ --- ### Test running: -- by now tests are only reachable by terminal in main container's terminal (container_name: web) -- simply run command "python manage.py test" or use with needed flags +```bash +# pytest (recommended) +cd AHC_app +uv run pytest -m integration + +# or with just +just test +just test-integration + +# Django runner (legacy, still supported) +uv run python manage.py test +``` --- ### Sources: From 7f80bfdc68f476b1ee330a1b1f33e6345451af89 Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Sun, 24 May 2026 20:23:17 +0200 Subject: [PATCH 08/27] chore(infra): align PostgreSQL image to 18-alpine across docker-compose and k8s --- AHC_app/docker-compose.yml | 2 +- kubernetes/db/postgres/deployment.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AHC_app/docker-compose.yml b/AHC_app/docker-compose.yml index fdd7181..016aeaf 100644 --- a/AHC_app/docker-compose.yml +++ b/AHC_app/docker-compose.yml @@ -32,7 +32,7 @@ services: python manage.py runserver 0.0.0.0:8000 postgres_db: - image: postgres:15-alpine + image: postgres:18-alpine container_name: main-db environment: - POSTGRES_DB=${POSTGRES_DB} diff --git a/kubernetes/db/postgres/deployment.yaml b/kubernetes/db/postgres/deployment.yaml index 886dd56..19dc611 100644 --- a/kubernetes/db/postgres/deployment.yaml +++ b/kubernetes/db/postgres/deployment.yaml @@ -17,7 +17,7 @@ spec: spec: containers: - name: postgres-db - image: postgres:16 + image: postgres:18-alpine imagePullPolicy: IfNotPresent ports: - containerPort: 5433 From 8be4f60fd82f2cc29c3260e433d903cc0fbfb243 Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Sun, 24 May 2026 20:51:26 +0200 Subject: [PATCH 09/27] refactor(settings): skip CouchDB init for offline manage.py commands --- AHC_app/AHC_app/celery_notifications/cron.py | 6 ----- AHC_app/AHC_app/settings.py | 24 +++++++++++++++++++- AHC_app/pyproject.toml | 1 - AHC_app/uv.lock | 2 -- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/AHC_app/AHC_app/celery_notifications/cron.py b/AHC_app/AHC_app/celery_notifications/cron.py index 4a197fa..059fef4 100644 --- a/AHC_app/AHC_app/celery_notifications/cron.py +++ b/AHC_app/AHC_app/celery_notifications/cron.py @@ -85,12 +85,6 @@ def send_emails() -> None: for notification in notifications_to_send: _user_set_zone: str = notification.timezone - # user_weekday_number: int = datetime.now( - # tz=pytz.timezone(user_set_zone) - # ).weekday() - # - # if user_weekday_number in notification.related_note.days_of_week: - # break email: str = notification.email animal: str = notification.related_note.related_note.animal diff --git a/AHC_app/AHC_app/settings.py b/AHC_app/AHC_app/settings.py index 3c5dc3e..b8f7095 100644 --- a/AHC_app/AHC_app/settings.py +++ b/AHC_app/AHC_app/settings.py @@ -17,11 +17,33 @@ import pycouchdb from decouple import config +_OFFLINE_COMMANDS = { + "check", + "collectstatic", + "compress", + "crontab", + "makemigrations", + "migrate", + "shell", + "showmigrations", + "sqlmigrate", + "test", +} + def _is_test_run() -> bool: return "test" in sys.argv or (bool(sys.argv) and "pytest" in sys.argv[0]) +def _skip_external_services() -> bool: + """Return True when live network backends (CouchDB) must not be initialised. + + Covers: pytest invocations, manage.py test, and any manage.py command that + does not require a running CouchDB connection at import time. + """ + return _is_test_run() or any(cmd in sys.argv for cmd in _OFFLINE_COMMANDS) + + # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent @@ -120,7 +142,7 @@ def _is_test_run() -> bool: # COUCH_CONNECTOR = (config("COUCH_CONNECTOR"),) -if not _is_test_run(): +if not _skip_external_services(): COUCHDB_USER = config("COUCHDB_USER") COUCHDB_PASSWORD = config("COUCHDB_PASSWORD") COUCHDB_PORT = config("COUCHDB_PORT") diff --git a/AHC_app/pyproject.toml b/AHC_app/pyproject.toml index 843520b..fc31cc6 100644 --- a/AHC_app/pyproject.toml +++ b/AHC_app/pyproject.toml @@ -27,7 +27,6 @@ dependencies = [ "django-taggit", "django-timezone-field>=6.1", "django-crontab", - "pytz", "tzdata", "python3-openid", "requests", diff --git a/AHC_app/uv.lock b/AHC_app/uv.lock index e2de1ba..15c1aef 100644 --- a/AHC_app/uv.lock +++ b/AHC_app/uv.lock @@ -118,7 +118,6 @@ dependencies = [ { name = "python-dateutil" }, { name = "python-decouple" }, { name = "python3-openid" }, - { name = "pytz" }, { name = "redis" }, { name = "requests" }, { name = "requests-oauthlib" }, @@ -166,7 +165,6 @@ requires-dist = [ { name = "python-dateutil" }, { name = "python-decouple" }, { name = "python3-openid" }, - { name = "pytz" }, { name = "redis", specifier = ">=5.0" }, { name = "requests" }, { name = "requests-oauthlib" }, From 079c397d0199fce245e8788e4810b500bbfef6f7 Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Sun, 24 May 2026 21:13:19 +0200 Subject: [PATCH 10/27] refactor(celery): replace django-crontab with Celery Beat for discord notifications --- .../AHC_app/celery_notifications/config.py | 16 +++++++ AHC_app/AHC_app/settings.py | 10 ----- AHC_app/Dockerfile-web | 3 -- AHC_app/docker-compose.yml | 21 ++++++++-- AHC_app/homepage/management/__init__.py | 1 - .../management/commands/sync_cronjobs.py | 24 ----------- AHC_app/pyproject.toml | 1 - AHC_app/uv.lock | 11 ----- kubernetes/queue/celery-beat/deployment.yaml | 42 +++++++++++++++++++ .../queue/celery-beat/kustomization.yaml | 2 + kubernetes/queue/kustomization.yaml | 1 + 11 files changed, 78 insertions(+), 54 deletions(-) delete mode 100644 AHC_app/homepage/management/commands/sync_cronjobs.py create mode 100644 kubernetes/queue/celery-beat/deployment.yaml create mode 100644 kubernetes/queue/celery-beat/kustomization.yaml diff --git a/AHC_app/AHC_app/celery_notifications/config.py b/AHC_app/AHC_app/celery_notifications/config.py index bcfa1c6..c474b79 100644 --- a/AHC_app/AHC_app/celery_notifications/config.py +++ b/AHC_app/AHC_app/celery_notifications/config.py @@ -1,6 +1,7 @@ import os from celery import Celery, shared_task +from celery.schedules import crontab from celery.utils.log import get_task_logger from django.conf import settings @@ -18,6 +19,21 @@ celery_obj.autodiscover_tasks(["AHC_app"]) +@celery_obj.task(name="ahc.beat.dispatch_discord_notes") +def dispatch_discord_notes(): + from AHC_app.celery_notifications.cron import send_discord_notes + + send_discord_notes() + + +celery_obj.conf.beat_schedule = { + "send-discord-notes-hourly": { + "task": "ahc.beat.dispatch_discord_notes", + "schedule": crontab(minute=6), + }, +} + + @celery_obj.task() def send_email_notifications(*args, **kwargs): recipient_list = kwargs.get("email") diff --git a/AHC_app/AHC_app/settings.py b/AHC_app/AHC_app/settings.py index b8f7095..5b45f13 100644 --- a/AHC_app/AHC_app/settings.py +++ b/AHC_app/AHC_app/settings.py @@ -74,7 +74,6 @@ def _skip_external_services() -> bool: "bootstrap_modal_forms", "compressor", "taggit", - "django_crontab", "homepage.apps.HomepageConfig", "users.apps.UsersConfig", "animals.apps.AnimalsConfig", @@ -233,15 +232,6 @@ def _skip_external_services() -> bool: DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" -CRONJOBS = [ - # ("*/4 * * * *", "AHC_app.celery_notifications.cron.send_emails"), - # ("*/2 * * * *", "AHC_app.celery_notifications.cron.send_email_example"), - # # ('2 * * * *', 'AHC_app.celery_notifications.cron:send_emails'), - # ("4 * * * *", "AHC_app.celery_notifications.cron.send_sms"), - ("6 * * * *", "AHC_app.celery_notifications.cron.send_discord_notes"), -] - - CELERY_BROKER_URL = config("CELERY_BROKER_URL") CELERY_BACKEND = config("CELERY_BACKEND") diff --git a/AHC_app/Dockerfile-web b/AHC_app/Dockerfile-web index cea64ab..c4ca1d3 100644 --- a/AHC_app/Dockerfile-web +++ b/AHC_app/Dockerfile-web @@ -10,9 +10,6 @@ RUN --mount=type=cache,target=/root/.cache/uv,sharing=locked \ FROM python:3.14-slim AS runtime LABEL authors="AM" -RUN apt-get update && \ - apt-get install -y --no-install-recommends cron && \ - rm -rf /var/lib/apt/lists/* WORKDIR /app COPY --from=builder /opt/venv /opt/venv ENV PATH="/opt/venv/bin:$PATH" diff --git a/AHC_app/docker-compose.yml b/AHC_app/docker-compose.yml index 016aeaf..d59a072 100644 --- a/AHC_app/docker-compose.yml +++ b/AHC_app/docker-compose.yml @@ -25,10 +25,6 @@ services: python manage.py makemigrations python manage.py migrate python manage.py collectstatic --noinput - python manage.py crontab remove - python manage.py crontab add - python manage.py sync_cronjobs - python manage.py runcrons python manage.py runserver 0.0.0.0:8000 postgres_db: @@ -91,6 +87,23 @@ services: - PYTHONUNBUFFERED=1 - PYTHONPATH=/app + celery_beat: + build: + context: . + dockerfile: Dockerfile-queue + command: celery -A AHC_app.celery_notifications.config:celery_obj beat -l info + depends_on: + redis: + condition: service_healthy + postgres_db: + condition: service_healthy + environment: + - DJANGO_SETTINGS_MODULE=AHC_app.settings + - PYTHONUNBUFFERED=1 + - PYTHONPATH=/app + env_file: + - .env + redis: image: redis:7-alpine healthcheck: diff --git a/AHC_app/homepage/management/__init__.py b/AHC_app/homepage/management/__init__.py index bd9f50c..e69de29 100644 --- a/AHC_app/homepage/management/__init__.py +++ b/AHC_app/homepage/management/__init__.py @@ -1 +0,0 @@ -from .commands.sync_cronjobs import Command # noqa: F401 diff --git a/AHC_app/homepage/management/commands/sync_cronjobs.py b/AHC_app/homepage/management/commands/sync_cronjobs.py deleted file mode 100644 index fc2ec7e..0000000 --- a/AHC_app/homepage/management/commands/sync_cronjobs.py +++ /dev/null @@ -1,24 +0,0 @@ -import subprocess - -from django.core.management.base import BaseCommand - -from homepage.models import CronJob - - -class Command(BaseCommand): - help = "Sync cronjobs with the actual cron configuration" - - def handle(self, *args, **options): - cronjob_info = subprocess.run(["crontab", "-l"], stdout=subprocess.PIPE, text=True).stdout.splitlines() - - CronJob.objects.all().delete() - - for job_info in cronjob_info: - schedule, command = job_info.split(" /", 1) - function_name = command.strip().split(".")[-1] - cron_job = CronJob(schedule=schedule, command=command) - - cron_job.name = f"Cron Job: {function_name}" - cron_job.last_execution = None - cron_job.next_execution = None - cron_job.save() diff --git a/AHC_app/pyproject.toml b/AHC_app/pyproject.toml index fc31cc6..9eb9319 100644 --- a/AHC_app/pyproject.toml +++ b/AHC_app/pyproject.toml @@ -26,7 +26,6 @@ dependencies = [ "django-appconf", "django-taggit", "django-timezone-field>=6.1", - "django-crontab", "tzdata", "python3-openid", "requests", diff --git a/AHC_app/uv.lock b/AHC_app/uv.lock index 15c1aef..ccec51b 100644 --- a/AHC_app/uv.lock +++ b/AHC_app/uv.lock @@ -102,7 +102,6 @@ dependencies = [ { name = "django-bootstrap-modal-forms" }, { name = "django-compressor" }, { name = "django-crispy-forms" }, - { name = "django-crontab" }, { name = "django-libsass" }, { name = "django-taggit" }, { name = "django-timezone-field" }, @@ -149,7 +148,6 @@ requires-dist = [ { name = "django-bootstrap-modal-forms" }, { name = "django-compressor" }, { name = "django-crispy-forms" }, - { name = "django-crontab" }, { name = "django-libsass" }, { name = "django-taggit" }, { name = "django-timezone-field", specifier = ">=6.1" }, @@ -675,15 +673,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/96/e3/4c5915a732d6ab54da8871400852b67529518eedfb6b78ecf10bbccfcabb/django_crispy_forms-2.6-py3-none-any.whl", hash = "sha256:8ee0ae28b6b0ac41ff48a65944480c049fe8d1b0047086874fd7efabf4ec1374", size = 31479, upload-time = "2026-03-01T09:03:36.048Z" }, ] -[[package]] -name = "django-crontab" -version = "0.7.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "django" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/37/bd/a122ba96167f5dfab70a58ca22fa046b7ef1ebad9ff026f7831bd6c2a49c/django-crontab-0.7.1.tar.gz", hash = "sha256:1201810a212460aaaa48eb6a766738740daf42c1a4f6aafecfb1525036929236", size = 7089, upload-time = "2016-03-07T19:35:54.714Z" } - [[package]] name = "django-libsass" version = "0.9" diff --git a/kubernetes/queue/celery-beat/deployment.yaml b/kubernetes/queue/celery-beat/deployment.yaml new file mode 100644 index 0000000..d7e4e6f --- /dev/null +++ b/kubernetes/queue/celery-beat/deployment.yaml @@ -0,0 +1,42 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: celery-beat + labels: + app: celery-beat +spec: + replicas: 1 + selector: + matchLabels: + app: celery-beat + template: + metadata: + name: celery-beat + labels: + app: celery-beat + spec: + initContainers: + - name: init-myservice + image: busybox + command: [ 'sh', '-c', 'env' ] + envFrom: + - secretRef: + name: web-secrets + containers: + - name: celery-beat + image: ahc_app-queue:latest + imagePullPolicy: Never + command: [ "celery", "-A", "AHC_app.celery_notifications.config:celery_obj", "beat", "-l", "info" ] + env: + - name: PYTHONUNBUFFERED + value: "1" + - name: PYTHONPATH + value: "/app" + envFrom: + - secretRef: + name: web-secrets + resources: + limits: + memory: "128Mi" + cpu: "250m" + restartPolicy: Always diff --git a/kubernetes/queue/celery-beat/kustomization.yaml b/kubernetes/queue/celery-beat/kustomization.yaml new file mode 100644 index 0000000..9519a26 --- /dev/null +++ b/kubernetes/queue/celery-beat/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - deployment.yaml diff --git a/kubernetes/queue/kustomization.yaml b/kubernetes/queue/kustomization.yaml index 1503853..d578b4a 100644 --- a/kubernetes/queue/kustomization.yaml +++ b/kubernetes/queue/kustomization.yaml @@ -1,5 +1,6 @@ resources: - secret.yaml - celery/ + - celery-beat/ - flower/ - redis/ From eddbbf89bdab97e277b789617380bd6a585dc157 Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Sun, 24 May 2026 22:58:53 +0200 Subject: [PATCH 11/27] feat(django): bump to 6.0.5 and register django.contrib.postgres for ArrayField --- AHC_app/AHC_app/settings.py | 1 + AHC_app/pyproject.toml | 2 +- AHC_app/uv.lock | 8 ++++---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/AHC_app/AHC_app/settings.py b/AHC_app/AHC_app/settings.py index 5b45f13..b03f41d 100644 --- a/AHC_app/AHC_app/settings.py +++ b/AHC_app/AHC_app/settings.py @@ -69,6 +69,7 @@ def _skip_external_services() -> bool: "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", + "django.contrib.postgres", "crispy_forms", "crispy_bootstrap4", "bootstrap_modal_forms", diff --git a/AHC_app/pyproject.toml b/AHC_app/pyproject.toml index 9eb9319..9fa84dd 100644 --- a/AHC_app/pyproject.toml +++ b/AHC_app/pyproject.toml @@ -5,7 +5,7 @@ description = "Animals Healthcare Application — pet health data management" requires-python = ">=3.14" dependencies = [ - "django>=5.2,<5.3", + "django>=6.0,<6.1", "djangorestframework>=3.14", "psycopg[binary]>=3.2", "celery>=5.4", diff --git a/AHC_app/uv.lock b/AHC_app/uv.lock index ccec51b..1a6dab0 100644 --- a/AHC_app/uv.lock +++ b/AHC_app/uv.lock @@ -143,7 +143,7 @@ requires-dist = [ { name = "cryptography", specifier = ">=43" }, { name = "defusedxml" }, { name = "discord" }, - { name = "django", specifier = ">=5.2,<5.3" }, + { name = "django", specifier = ">=6.0,<6.1" }, { name = "django-appconf" }, { name = "django-bootstrap-modal-forms" }, { name = "django-compressor" }, @@ -610,16 +610,16 @@ wheels = [ [[package]] name = "django" -version = "5.2.14" +version = "6.0.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "asgiref" }, { name = "sqlparse" }, { name = "tzdata", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/65/95/95f7faa0950867afaa0bef2460c6263afd6a2c78cc9434046ed28160b015/django-5.2.14.tar.gz", hash = "sha256:58a63ba841662e5c686b57ba1fec52ddd68c0b93bd96ac3029d55728f00bf8a2", size = 10895118, upload-time = "2026-05-05T13:57:31.104Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/f1/bf85f0d29ef76abf901f193fe8fef4769d3da7794197832bc30151c071d8/django-6.0.5.tar.gz", hash = "sha256:bc6d6872e98a2864c836e42edd644b362db311147dd5aa8d5b82ba7a032f5269", size = 10924131, upload-time = "2026-05-05T13:54:39.329Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/44/f172870cf87aa25afef48fb72adba89ee8b77fcab6f3b23d240b923f1528/django-5.2.14-py3-none-any.whl", hash = "sha256:6f712143bd3064310d1f50fac859c3e9a274bdcfc9595339853be7779297fc76", size = 8311320, upload-time = "2026-05-05T13:57:25.795Z" }, + { url = "https://files.pythonhosted.org/packages/94/5b/1328f8b84fce040c404f76822bf8c57d254e368e8cbd8bd67ec2b26d75f5/django-6.0.5-py3-none-any.whl", hash = "sha256:9d58a7cb49244e74c8e161d5e403a46d6209f1009ba40f5a66d6aa0d0786a8f0", size = 8368680, upload-time = "2026-05-05T13:54:33.532Z" }, ] [[package]] From 3971293f77a1d4644ad19f4bb9e6f6a0ca23578e Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Sun, 24 May 2026 23:04:11 +0200 Subject: [PATCH 12/27] feat(django6): add CSP middleware, Template Partials, and Background Tasks API --- AHC_app/AHC_app/celery_notifications/cron.py | 32 +++++++------------ AHC_app/AHC_app/settings.py | 21 ++++++++++++ .../templates/animals/all_animals_stable.html | 6 +--- .../homepage/templates/homepage/homepage.html | 12 ++----- AHC_app/templates/partials/animal_card.html | 7 ++++ 5 files changed, 42 insertions(+), 36 deletions(-) create mode 100644 AHC_app/templates/partials/animal_card.html diff --git a/AHC_app/AHC_app/celery_notifications/cron.py b/AHC_app/AHC_app/celery_notifications/cron.py index 059fef4..12d4009 100644 --- a/AHC_app/AHC_app/celery_notifications/cron.py +++ b/AHC_app/AHC_app/celery_notifications/cron.py @@ -7,6 +7,7 @@ from functools import wraps from django.db.models import Q, QuerySet +from django.tasks import task from django.utils import timezone from AHC_app.celery_notifications.config import ( @@ -146,24 +147,13 @@ def send_discord_notes(): send_discord_notifications.apply_async(kwargs={"user_id": user_id, "user_message": user_message}, countdown=delay) -# class SynchNotificationsCron(CronJobBase): -# RUN_EVERY_MINS = 60 -# -# schedule = Schedule(run_every_mins=RUN_EVERY_MINS) -# code = "AHC_app.SynchNotificationsCronJob" -# -# # run_at_times = ["55"] -# -# @staticmethod -# def cron_send_emails(): -# from icecream import ic -# ic() -# -# send_emails() -# -# @staticmethod -# def cron_send_discord(): -# from icecream import ic -# ic() -# -# send_discord_notes() +@task +def log_notification_count() -> int: + """Django Background Tasks example. Use for simple in-process tasks. + + For distributed / retryable work, use Celery (@shared_task). + Enqueue with: log_notification_count.enqueue() + """ + count = EmailNotification.objects.filter(is_active=True).count() + logger.info("Active email notifications: %d", count) + return count diff --git a/AHC_app/AHC_app/settings.py b/AHC_app/AHC_app/settings.py index b03f41d..6bec7d9 100644 --- a/AHC_app/AHC_app/settings.py +++ b/AHC_app/AHC_app/settings.py @@ -83,6 +83,7 @@ def _skip_external_services() -> bool: MIDDLEWARE = [ "django.middleware.security.SecurityMiddleware", + "django.middleware.csp.ContentSecurityPolicyMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", @@ -247,3 +248,23 @@ def _skip_external_services() -> bool: DISCORD_TOKEN = config("DISCORD_TOKEN") TEST_RUNNER = "django.test.runner.DiscoverRunner" + +from django.utils.csp import CSP # noqa: E402 + +SECURE_CSP = { + "default-src": [CSP.SELF], + "script-src": [CSP.SELF], + "style-src": [CSP.SELF, CSP.UNSAFE_INLINE, "https://fonts.googleapis.com"], + "img-src": [CSP.SELF, "data:"], + "font-src": [CSP.SELF, "https://fonts.gstatic.com"], + "connect-src": [CSP.SELF], + "object-src": [CSP.NONE], + "base-uri": [CSP.SELF], +} +SECURE_CSP_REPORT_ONLY = SECURE_CSP + +TASKS = { + "default": { + "BACKEND": "django.tasks.backends.immediate.ImmediateBackend", + }, +} diff --git a/AHC_app/animals/templates/animals/all_animals_stable.html b/AHC_app/animals/templates/animals/all_animals_stable.html index 7221dd3..b246f58 100644 --- a/AHC_app/animals/templates/animals/all_animals_stable.html +++ b/AHC_app/animals/templates/animals/all_animals_stable.html @@ -15,11 +15,7 @@

Placeholder title

All pets:

{% for animal in animals %} - {{ animal.full_name }} + {% partial "partials/animal_card.html#animal_card" %} {% endfor %}
{% endif %} diff --git a/AHC_app/homepage/templates/homepage/homepage.html b/AHC_app/homepage/templates/homepage/homepage.html index 83df364..18db231 100644 --- a/AHC_app/homepage/templates/homepage/homepage.html +++ b/AHC_app/homepage/templates/homepage/homepage.html @@ -28,11 +28,7 @@

Pinned up:

{% for animal in recent_animals %} - {{ animal.full_name }} + {% partial "partials/animal_card.html#animal_card" %} {% endfor %}

@@ -47,11 +43,7 @@

Recent added:

{% for animal in recent_animals %} - {{ animal.full_name }} + {% partial "partials/animal_card.html#animal_card" %} {% endfor %}

diff --git a/AHC_app/templates/partials/animal_card.html b/AHC_app/templates/partials/animal_card.html new file mode 100644 index 0000000..38ac3b1 --- /dev/null +++ b/AHC_app/templates/partials/animal_card.html @@ -0,0 +1,7 @@ +{% partialdef animal_card %} +{{ animal.full_name }} +{% endpartialdef %} From a2d124ba512d94105f8d58a17d4a6787b46b9ef5 Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Sun, 24 May 2026 23:11:08 +0200 Subject: [PATCH 13/27] test(homepage): add CSP header tests and fix static manifest in CI --- AHC_app/AHC_app/settings.py | 8 +++++++- AHC_app/homepage/tests/test_csp.py | 21 +++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 AHC_app/homepage/tests/test_csp.py diff --git a/AHC_app/AHC_app/settings.py b/AHC_app/AHC_app/settings.py index 6bec7d9..7ea92f3 100644 --- a/AHC_app/AHC_app/settings.py +++ b/AHC_app/AHC_app/settings.py @@ -207,12 +207,18 @@ def _skip_external_services() -> bool: COMPRESS_PRECOMPILERS = (("text/x-scss", "django_libsass.SassCompiler"),) COMPRESS_OFFLINE = True LIBSASS_OUTPUT_STYLE = "compressed" + +_staticfiles_backend = ( + "django.contrib.staticfiles.storage.StaticFilesStorage" + if _is_test_run() + else "django.contrib.staticfiles.storage.ManifestStaticFilesStorage" +) STORAGES = { "default": { "BACKEND": "django.core.files.storage.FileSystemStorage", }, "staticfiles": { - "BACKEND": "django.contrib.staticfiles.storage.ManifestStaticFilesStorage", + "BACKEND": _staticfiles_backend, }, } diff --git a/AHC_app/homepage/tests/test_csp.py b/AHC_app/homepage/tests/test_csp.py new file mode 100644 index 0000000..c52486e --- /dev/null +++ b/AHC_app/homepage/tests/test_csp.py @@ -0,0 +1,21 @@ +import pytest +from django.test import Client, TestCase + + +@pytest.mark.integration +@pytest.mark.django_db +class TestCSPHeaders(TestCase): + def test_report_only_header_present(self): + response = Client().get("/") + self.assertIn("Content-Security-Policy-Report-Only", response.headers) + + def test_report_only_default_src_self(self): + response = Client().get("/") + header = response.headers.get("Content-Security-Policy-Report-Only", "") + self.assertIn("default-src 'self'", header) + + def test_report_only_no_unsafe_scripts(self): + response = Client().get("/") + header = response.headers.get("Content-Security-Policy-Report-Only", "") + self.assertIn("script-src 'self'", header) + self.assertNotIn("'unsafe-inline'", header.split("script-src")[1].split(";")[0]) From 37b4e9d601631958105dec8551b211644a19c47d Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Mon, 25 May 2026 00:34:46 +0200 Subject: [PATCH 14/27] refactor(layout): hoist tooling files from AHC_app/ to repo root --- AHC_app/.env.template => .env.template | 0 .github/workflows/django.yml | 7 ++-- .pre-commit-config.yaml | 6 ++-- AHC_app/.python-version => .python-version | 0 README.md | 4 +-- AHC_app/conftest.py => conftest.py | 0 AHC_app/justfile => justfile | 4 +-- AHC_app/manage.py => manage.py | 2 ++ AHC_app/pyproject.toml => pyproject.toml | 1 + .../CACHE/css/custom_pico.fc2f6099451a.css | 32 +++++++++++++++++++ AHC_app/uv.lock => uv.lock | 0 11 files changed, 44 insertions(+), 12 deletions(-) rename AHC_app/.env.template => .env.template (100%) rename AHC_app/.python-version => .python-version (100%) rename AHC_app/conftest.py => conftest.py (100%) rename AHC_app/justfile => justfile (89%) rename AHC_app/manage.py => manage.py (87%) rename AHC_app/pyproject.toml => pyproject.toml (98%) create mode 100644 static_collected/CACHE/css/custom_pico.fc2f6099451a.css rename AHC_app/uv.lock => uv.lock (100%) diff --git a/AHC_app/.env.template b/.env.template similarity index 100% rename from AHC_app/.env.template rename to .env.template diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml index 37672a8..0de0866 100644 --- a/.github/workflows/django.yml +++ b/.github/workflows/django.yml @@ -43,20 +43,17 @@ jobs: uses: astral-sh/setup-uv@v3 with: enable-cache: true - cache-dependency-glob: "AHC_app/uv.lock" + cache-dependency-glob: "uv.lock" python-version: "3.14" - name: Install dependencies run: uv sync - working-directory: ./AHC_app - name: Run tests (Django runner) - run: PYTHONPATH=$(pwd) uv run python manage.py test - working-directory: ./AHC_app + run: PYTHONPATH=AHC_app uv run python manage.py test - name: Run tests (pytest) run: uv run pytest -m "not slow" - working-directory: ./AHC_app build-and-push: name: Build and Push to ECR diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1a9f553..65414c6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,10 +5,10 @@ repos: hooks: - id: uv-lock-check name: uv lock --check - entry: uv --directory AHC_app lock --check + entry: uv lock --check language: system pass_filenames: false - files: ^AHC_app/pyproject\.toml$ + files: ^pyproject\.toml$ - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 @@ -34,7 +34,7 @@ repos: hooks: - id: bandit name: bandit - entry: bandit -r AHC_app -c AHC_app/pyproject.toml + entry: bandit -r AHC_app -c pyproject.toml language: python additional_dependencies: ["bandit[toml]==1.9.4"] pass_filenames: false diff --git a/AHC_app/.python-version b/.python-version similarity index 100% rename from AHC_app/.python-version rename to .python-version diff --git a/README.md b/README.md index 4688021..68d1c1e 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ just docker-up docker image save -o ahc_app-web.tar ahc_app-web:latest docker image save -o ahc_app-queue.tar ahc_app-queue:latest docker image save -o ahc_app-couch_db.tar ahc_app-couch_db:latest - docker image save -o postgres.tar postgres:15-alpine + docker image save -o postgres.tar postgres:18-alpine ``` 5. Push Docker images to a registry: @@ -115,7 +115,7 @@ just docker-up minikube image load ahc_app-web.tar minikube image load ahc_app-queue.tar minikube image load ahc_app-couch_db.tar - minikube image load postgres.tar + minikube image load postgres.tar # postgres:18-alpine ``` 6. Deploy to Kubernetes using kustom files: diff --git a/AHC_app/conftest.py b/conftest.py similarity index 100% rename from AHC_app/conftest.py rename to conftest.py diff --git a/AHC_app/justfile b/justfile similarity index 89% rename from AHC_app/justfile rename to justfile index 87dccf8..5bb1bae 100644 --- a/AHC_app/justfile +++ b/justfile @@ -41,11 +41,11 @@ shell: # Start all Docker services docker-up: - docker-compose up -d --build + docker-compose -f AHC_app/docker-compose.yml up -d --build # Stop all Docker services docker-down: - docker-compose down + docker-compose -f AHC_app/docker-compose.yml down # Run pre-commit hooks on all files precommit: diff --git a/AHC_app/manage.py b/manage.py similarity index 87% rename from AHC_app/manage.py rename to manage.py index c262845..e51f677 100644 --- a/AHC_app/manage.py +++ b/manage.py @@ -3,10 +3,12 @@ import os import sys +from pathlib import Path def main(): """Run administrative tasks.""" + sys.path.insert(0, str(Path(__file__).resolve().parent / "AHC_app")) os.environ.setdefault("DJANGO_SETTINGS_MODULE", "AHC_app.settings") try: from django.core.management import execute_from_command_line diff --git a/AHC_app/pyproject.toml b/pyproject.toml similarity index 98% rename from AHC_app/pyproject.toml rename to pyproject.toml index 9fa84dd..510afe5 100644 --- a/AHC_app/pyproject.toml +++ b/pyproject.toml @@ -69,6 +69,7 @@ indent-style = "space" [tool.pytest.ini_options] DJANGO_SETTINGS_MODULE = "AHC_app.settings" +pythonpath = ["AHC_app"] python_files = ["test_*.py", "tests.py"] addopts = "--strict-markers" markers = [ diff --git a/static_collected/CACHE/css/custom_pico.fc2f6099451a.css b/static_collected/CACHE/css/custom_pico.fc2f6099451a.css new file mode 100644 index 0000000..62dafb0 --- /dev/null +++ b/static_collected/CACHE/css/custom_pico.fc2f6099451a.css @@ -0,0 +1,32 @@ +/*! + * Pico CSS v1.5.9 (https://picocss.com) + * Copyright 2019-2023 - Licensed under MIT + */:root{--font-family: system-ui, -apple-system, "Segoe UI", "Roboto", "Ubuntu", + "Cantarell", "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", + "Segoe UI Symbol", "Noto Color Emoji";--line-height: 1.5;--font-weight: 400;--font-size: 16px;--border-radius: 0.25rem;--border-width: 1px;--outline-width: 3px;--spacing: 1rem;--typography-spacing-vertical: 1.5rem;--block-spacing-vertical: calc(var(--spacing) * 2);--block-spacing-horizontal: var(--spacing);--grid-spacing-vertical: 0;--grid-spacing-horizontal: var(--spacing);--form-element-spacing-vertical: 0.75rem;--form-element-spacing-horizontal: 1rem;--nav-element-spacing-vertical: 1rem;--nav-element-spacing-horizontal: 0.5rem;--nav-link-spacing-vertical: 0.5rem;--nav-link-spacing-horizontal: 0.5rem;--form-label-font-weight: var(--font-weight);--transition: 0.2s ease-in-out;--modal-overlay-backdrop-filter: blur(0.25rem)}@media (min-width: 576px){:root{--font-size: 17px}}@media (min-width: 768px){:root{--font-size: 18px}}@media (min-width: 992px){:root{--font-size: 19px}}@media (min-width: 1200px){:root{--font-size: 20px}}@media (min-width: 576px){body>header,body>main,body>footer,section{--block-spacing-vertical: calc(var(--spacing) * 2.5)}}@media (min-width: 768px){body>header,body>main,body>footer,section{--block-spacing-vertical: calc(var(--spacing) * 3)}}@media (min-width: 992px){body>header,body>main,body>footer,section{--block-spacing-vertical: calc(var(--spacing) * 3.5)}}@media (min-width: 1200px){body>header,body>main,body>footer,section{--block-spacing-vertical: calc(var(--spacing) * 4)}}@media (min-width: 576px){article{--block-spacing-horizontal: calc(var(--spacing) * 1.25)}}@media (min-width: 768px){article{--block-spacing-horizontal: calc(var(--spacing) * 1.5)}}@media (min-width: 992px){article{--block-spacing-horizontal: calc(var(--spacing) * 1.75)}}@media (min-width: 1200px){article{--block-spacing-horizontal: calc(var(--spacing) * 2)}}dialog>article{--block-spacing-vertical: calc(var(--spacing) * 2);--block-spacing-horizontal: var(--spacing)}@media (min-width: 576px){dialog>article{--block-spacing-vertical: calc(var(--spacing) * 2.5);--block-spacing-horizontal: calc(var(--spacing) * 1.25)}}@media (min-width: 768px){dialog>article{--block-spacing-vertical: calc(var(--spacing) * 3);--block-spacing-horizontal: calc(var(--spacing) * 1.5)}}a{--text-decoration: none}a.secondary,a.contrast{--text-decoration: underline}small{--font-size: 0.875em}h1,h2,h3,h4,h5,h6{--font-weight: 700}h1{--font-size: 2rem;--typography-spacing-vertical: 3rem}h2{--font-size: 1.75rem;--typography-spacing-vertical: 2.625rem}h3{--font-size: 1.5rem;--typography-spacing-vertical: 2.25rem}h4{--font-size: 1.25rem;--typography-spacing-vertical: 1.874rem}h5{--font-size: 1.125rem;--typography-spacing-vertical: 1.6875rem}[type="checkbox"],[type="radio"]{--border-width: 2px}[type="checkbox"][role="switch"]{--border-width: 3px}thead th,thead td,tfoot th,tfoot td{--border-width: 3px}:not(thead,tfoot)>*>td{--font-size: 0.875em}pre,code,kbd,samp{--font-family: "Menlo", "Consolas", "Roboto Mono", "Ubuntu Monospace", + "Noto Mono", "Oxygen Mono", "Liberation Mono", monospace, + "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"}kbd{--font-weight: bolder}[data-theme="light"],:root:not([data-theme="dark"]){--background-color: #fff;--color: #415462;--h1-color: #1b2832;--h2-color: #23333e;--h3-color: #2c3d49;--h4-color: #374956;--h5-color: #415462;--h6-color: #998133;--muted-color: #73828c;--muted-border-color: #edf0f3;--primary: #fdd835;--primary-hover: #fbc02d;--primary-focus: rgba(253,216,53,0.125);--primary-inverse: #fff;--secondary: #F0AD05;--secondary-hover: #415462;--secondary-focus: rgba(240,173,5,0.125);--secondary-inverse: #fff;--contrast: #1b2832;--contrast-hover: #000;--contrast-focus: rgba(240,173,5,0.125);--contrast-inverse: #fff;--mark-background-color: #fff2ca;--mark-color: #543a25;--ins-color: #388e3c;--del-color: #c62828;--blockquote-border-color: var(--muted-border-color);--blockquote-footer-color: var(--muted-color);--button-box-shadow: 0 0 0 rgba(0, 0, 0, 0);--button-hover-box-shadow: 0 0 0 rgba(0, 0, 0, 0);--form-element-background-color: transparent;--form-element-border-color: #a2afb9;--form-element-color: var(--color);--form-element-placeholder-color: var(--muted-color);--form-element-active-background-color: transparent;--form-element-active-border-color: var(--primary);--form-element-focus-color: var(--primary-focus);--form-element-disabled-background-color: #fbc02d;--form-element-disabled-border-color: #a2afb9;--form-element-disabled-opacity: 0.5;--form-element-invalid-border-color: #c62828;--form-element-invalid-active-border-color: #d32f2f;--form-element-invalid-focus-color: rgba(211,47,47,0.125);--form-element-valid-border-color: #388e3c;--form-element-valid-active-border-color: #43a047;--form-element-valid-focus-color: rgba(67,160,71,0.125);--switch-background-color: #bbc6ce;--switch-color: var(--primary-inverse);--switch-checked-background-color: var(--primary);--range-border-color: #fbc02d;--range-active-border-color: #bbc6ce;--range-thumb-border-color: var(--background-color);--range-thumb-color: var(--secondary);--range-thumb-hover-color: var(--secondary-hover);--range-thumb-active-color: var(--primary);--table-border-color: var(--muted-border-color);--table-row-stripped-background-color: #f6f8f9;--code-background-color: #edf0f3;--code-color: var(--muted-color);--code-kbd-background-color: var(--contrast);--code-kbd-color: var(--contrast-inverse);--code-tag-color: #b34d80;--code-property-color: #3d888f;--code-value-color: #986;--code-comment-color: #a2afb9;--accordion-border-color: var(--muted-border-color);--accordion-close-summary-color: var(--color);--accordion-open-summary-color: var(--muted-color);--card-background-color: var(--background-color);--card-border-color: var(--muted-border-color);--card-box-shadow: + .0145rem .029rem .174rem rgba(27,40,50,0.01698), + .0335rem .067rem .402rem rgba(27,40,50,0.024), + .0625rem .125rem .75rem rgba(27,40,50,0.03), + .1125rem .225rem 1.35rem rgba(27,40,50,0.036), + .2085rem .417rem 2.502rem rgba(27,40,50,0.04302), + .5rem 1rem 6rem rgba(27,40,50,0.06), + 0 0 0 0.0625rem rgba(27,40,50,0.015);--card-sectionning-background-color: #fafbfc;--dropdown-background-color: #fafbfc;--dropdown-border-color: #f4d890;--dropdown-box-shadow: var(--card-box-shadow);--dropdown-color: var(--color);--dropdown-hover-background-color: #edf0f3;--modal-overlay-background-color: rgba(251,192,45,0.7);--progress-background-color: #fbc02d;--progress-color: var(--primary);--loading-spinner-opacity: 0.5;--tooltip-background-color: var(--contrast);--tooltip-color: var(--contrast-inverse);--icon-checkbox: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(65.28, 84.32, 97.92)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron-button: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron-button-inverse: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-close: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(114.75, 129.625, 140.25)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E");--icon-date: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(65.28, 84.32, 97.92)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E");--icon-invalid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(198, 40, 40)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E");--icon-minus: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E");--icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(65.28, 84.32, 97.92)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E");--icon-time: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(65.28, 84.32, 97.92)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E");--icon-valid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(56, 142, 60)' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");color-scheme:light}@media only screen and (prefers-color-scheme: dark){:root:not([data-theme]){--background-color: #11191f;--color: #bbc6ce;--h1-color: #edf0f3;--h2-color: #f4d890;--h3-color: #fbc02d;--h4-color: #dbc37d;--h5-color: #bbc6ce;--h6-color: #aebbc3;--muted-color: #73828c;--muted-border-color: #1f2d38;--primary: #fdd835;--primary-hover: #ffeb3b;--primary-focus: rgba(253,216,53,0.25);--primary-inverse: #fff;--secondary: #F0AD05;--secondary-hover: #73828c;--secondary-focus: rgba(115,130,140,0.25);--secondary-inverse: #fff;--contrast: #edf0f3;--contrast-hover: #fff;--contrast-focus: rgba(115,130,140,0.25);--contrast-inverse: #000;--mark-background-color: #d0c284;--mark-color: #11191f;--ins-color: #388e3c;--del-color: #c62828;--blockquote-border-color: var(--muted-border-color);--blockquote-footer-color: var(--muted-color);--button-box-shadow: 0 0 0 rgba(0, 0, 0, 0);--button-hover-box-shadow: 0 0 0 rgba(0, 0, 0, 0);--form-element-background-color: #11191f;--form-element-border-color: #374956;--form-element-color: var(--color);--form-element-placeholder-color: var(--muted-color);--form-element-active-background-color: var(--form-element-background-color);--form-element-active-border-color: var(--primary);--form-element-focus-color: var(--primary-focus);--form-element-disabled-background-color: #2c3d49;--form-element-disabled-border-color: #415462;--form-element-disabled-opacity: 0.5;--form-element-invalid-border-color: #b71c1c;--form-element-invalid-active-border-color: #c62828;--form-element-invalid-focus-color: rgba(198,40,40,0.25);--form-element-valid-border-color: #2e7d32;--form-element-valid-active-border-color: #388e3c;--form-element-valid-focus-color: rgba(56,142,60,0.25);--switch-background-color: #374956;--switch-color: var(--primary-inverse);--switch-checked-background-color: var(--primary);--range-border-color: #23333e;--range-active-border-color: #2c3d49;--range-thumb-border-color: var(--background-color);--range-thumb-color: var(--secondary);--range-thumb-hover-color: var(--secondary-hover);--range-thumb-active-color: var(--primary);--table-border-color: var(--muted-border-color);--table-row-stripped-background-color: rgba(115,130,140,0.05);--code-background-color: #17232c;--code-color: var(--muted-color);--code-kbd-background-color: var(--contrast);--code-kbd-color: var(--contrast-inverse);--code-tag-color: #a65980;--code-property-color: #599fa6;--code-value-color: #8c8473;--code-comment-color: #998133;--accordion-border-color: var(--muted-border-color);--accordion-active-summary-color: var(--primary);--accordion-close-summary-color: var(--color);--accordion-open-summary-color: var(--muted-color);--card-background-color: #141e25;--card-border-color: var(--card-background-color);--card-box-shadow: + .0145rem .029rem .174rem rgba(0,0,0,0.01698), + .0335rem .067rem .402rem rgba(0,0,0,0.024), + .0625rem .125rem .75rem rgba(0,0,0,0.03), + .1125rem .225rem 1.35rem rgba(0,0,0,0.036), + .2085rem .417rem 2.502rem rgba(0,0,0,0.04302), + .5rem 1rem 6rem rgba(0,0,0,0.06), + 0 0 0 0.0625rem rgba(0,0,0,0.015);--card-sectionning-background-color: #17232c;--dropdown-background-color: #1b2832;--dropdown-border-color: #23333e;--dropdown-box-shadow: var(--card-box-shadow);--dropdown-color: var(--color);--dropdown-hover-background-color: rgba(35,51,62,0.75);--modal-overlay-background-color: rgba(35,51,62,0.8);--progress-background-color: #23333e;--progress-color: var(--primary);--loading-spinner-opacity: 0.5;--tooltip-background-color: var(--contrast);--tooltip-color: var(--contrast-inverse);--icon-checkbox: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(161.976, 175.304, 184.824)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron-button: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron-button-inverse: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(0, 0, 0)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-close: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(114.75, 129.625, 140.25)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E");--icon-date: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(161.976, 175.304, 184.824)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E");--icon-invalid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(183, 28, 28)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E");--icon-minus: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E");--icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(161.976, 175.304, 184.824)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E");--icon-time: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(161.976, 175.304, 184.824)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E");--icon-valid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(46, 125, 50)' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");color-scheme:dark}}[data-theme="dark"]{--background-color: #11191f;--color: #bbc6ce;--h1-color: #edf0f3;--h2-color: #f4d890;--h3-color: #fbc02d;--h4-color: #dbc37d;--h5-color: #bbc6ce;--h6-color: #aebbc3;--muted-color: #73828c;--muted-border-color: #1f2d38;--primary: #fdd835;--primary-hover: #ffeb3b;--primary-focus: rgba(253,216,53,0.25);--primary-inverse: #fff;--secondary: #F0AD05;--secondary-hover: #73828c;--secondary-focus: rgba(115,130,140,0.25);--secondary-inverse: #fff;--contrast: #edf0f3;--contrast-hover: #fff;--contrast-focus: rgba(115,130,140,0.25);--contrast-inverse: #000;--mark-background-color: #d0c284;--mark-color: #11191f;--ins-color: #388e3c;--del-color: #c62828;--blockquote-border-color: var(--muted-border-color);--blockquote-footer-color: var(--muted-color);--button-box-shadow: 0 0 0 rgba(0, 0, 0, 0);--button-hover-box-shadow: 0 0 0 rgba(0, 0, 0, 0);--form-element-background-color: #11191f;--form-element-border-color: #374956;--form-element-color: var(--color);--form-element-placeholder-color: var(--muted-color);--form-element-active-background-color: var(--form-element-background-color);--form-element-active-border-color: var(--primary);--form-element-focus-color: var(--primary-focus);--form-element-disabled-background-color: #2c3d49;--form-element-disabled-border-color: #415462;--form-element-disabled-opacity: 0.5;--form-element-invalid-border-color: #b71c1c;--form-element-invalid-active-border-color: #c62828;--form-element-invalid-focus-color: rgba(198,40,40,0.25);--form-element-valid-border-color: #2e7d32;--form-element-valid-active-border-color: #388e3c;--form-element-valid-focus-color: rgba(56,142,60,0.25);--switch-background-color: #374956;--switch-color: var(--primary-inverse);--switch-checked-background-color: var(--primary);--range-border-color: #23333e;--range-active-border-color: #2c3d49;--range-thumb-border-color: var(--background-color);--range-thumb-color: var(--secondary);--range-thumb-hover-color: var(--secondary-hover);--range-thumb-active-color: var(--primary);--table-border-color: var(--muted-border-color);--table-row-stripped-background-color: rgba(115,130,140,0.05);--code-background-color: #17232c;--code-color: var(--muted-color);--code-kbd-background-color: var(--contrast);--code-kbd-color: var(--contrast-inverse);--code-tag-color: #a65980;--code-property-color: #599fa6;--code-value-color: #8c8473;--code-comment-color: #998133;--accordion-border-color: var(--muted-border-color);--accordion-active-summary-color: var(--primary);--accordion-close-summary-color: var(--color);--accordion-open-summary-color: var(--muted-color);--card-background-color: #141e25;--card-border-color: var(--card-background-color);--card-box-shadow: + .0145rem .029rem .174rem rgba(0,0,0,0.01698), + .0335rem .067rem .402rem rgba(0,0,0,0.024), + .0625rem .125rem .75rem rgba(0,0,0,0.03), + .1125rem .225rem 1.35rem rgba(0,0,0,0.036), + .2085rem .417rem 2.502rem rgba(0,0,0,0.04302), + .5rem 1rem 6rem rgba(0,0,0,0.06), + 0 0 0 0.0625rem rgba(0,0,0,0.015);--card-sectionning-background-color: #17232c;--dropdown-background-color: #1b2832;--dropdown-border-color: #23333e;--dropdown-box-shadow: var(--card-box-shadow);--dropdown-color: var(--color);--dropdown-hover-background-color: rgba(35,51,62,0.75);--modal-overlay-background-color: rgba(35,51,62,0.8);--progress-background-color: #23333e;--progress-color: var(--primary);--loading-spinner-opacity: 0.5;--tooltip-background-color: var(--contrast);--tooltip-color: var(--contrast-inverse);--icon-checkbox: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(161.976, 175.304, 184.824)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron-button: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-chevron-button-inverse: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(0, 0, 0)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--icon-close: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(114.75, 129.625, 140.25)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E");--icon-date: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(161.976, 175.304, 184.824)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E");--icon-invalid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(183, 28, 28)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E");--icon-minus: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E");--icon-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(161.976, 175.304, 184.824)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E");--icon-time: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(161.976, 175.304, 184.824)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E");--icon-valid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(46, 125, 50)' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");color-scheme:dark}progress,[type="checkbox"],[type="radio"],[type="range"]{accent-color:var(--primary)}*,*::before,*::after{box-sizing:border-box;background-repeat:no-repeat}::before,::after{text-decoration:inherit;vertical-align:inherit}:where(:root){-webkit-tap-highlight-color:transparent;-webkit-text-size-adjust:100%;text-size-adjust:100%;background-color:var(--background-color);color:var(--color);font-weight:var(--font-weight);font-size:var(--font-size);line-height:var(--line-height);font-family:var(--font-family);text-rendering:optimizeLegibility;overflow-wrap:break-word;cursor:default;tab-size:4}main{display:block}body{width:100%;margin:0}body>header,body>main,body>footer{width:100%;margin-right:auto;margin-left:auto;padding:var(--block-spacing-vertical) 0}.container,.container-fluid{width:100%;margin-right:auto;margin-left:auto;padding-right:var(--spacing);padding-left:var(--spacing)}@media (min-width: 576px){.container{max-width:510px;padding-right:0;padding-left:0}}@media (min-width: 768px){.container{max-width:700px}}@media (min-width: 992px){.container{max-width:920px}}@media (min-width: 1200px){.container{max-width:1130px}}section{margin-bottom:var(--block-spacing-vertical)}.grid{grid-column-gap:var(--grid-spacing-horizontal);grid-row-gap:var(--grid-spacing-vertical);display:grid;grid-template-columns:1fr;margin:0}@media (min-width: 992px){.grid{grid-template-columns:repeat(auto-fit, minmax(0%, 1fr))}}.grid>*{min-width:0}figure{display:block;margin:0;padding:0;overflow-x:auto}figure figcaption{padding:calc(var(--spacing) * 0.5) 0;color:var(--muted-color)}b,strong{font-weight:bolder}sub,sup{position:relative;font-size:0.75em;line-height:0;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}address,blockquote,dl,figure,form,ol,p,pre,table,ul{margin-top:0;margin-bottom:var(--typography-spacing-vertical);color:var(--color);font-style:normal;font-weight:var(--font-weight);font-size:var(--font-size)}a,[role="link"]{--color: var(--primary);--background-color: transparent;outline:none;background-color:var(--background-color);color:var(--color);text-decoration:var(--text-decoration);transition:background-color var(--transition),color var(--transition),text-decoration var(--transition),box-shadow var(--transition)}a:is([aria-current], :hover, :active, :focus),[role="link"]:is([aria-current], :hover, :active, :focus){--color: var(--primary-hover);--text-decoration: underline}a:focus,[role="link"]:focus{--background-color: var(--primary-focus)}a.secondary,[role="link"].secondary{--color: var(--secondary)}a.secondary:is([aria-current], :hover, :active, :focus),[role="link"].secondary:is([aria-current], :hover, :active, :focus){--color: var(--secondary-hover)}a.secondary:focus,[role="link"].secondary:focus{--background-color: var(--secondary-focus)}a.contrast,[role="link"].contrast{--color: var(--contrast)}a.contrast:is([aria-current], :hover, :active, :focus),[role="link"].contrast:is([aria-current], :hover, :active, :focus){--color: var(--contrast-hover)}a.contrast:focus,[role="link"].contrast:focus{--background-color: var(--contrast-focus)}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:var(--typography-spacing-vertical);color:var(--color);font-weight:var(--font-weight);font-size:var(--font-size);font-family:var(--font-family)}h1{--color: var(--h1-color)}h2{--color: var(--h2-color)}h3{--color: var(--h3-color)}h4{--color: var(--h4-color)}h5{--color: var(--h5-color)}h6{--color: var(--h6-color)}:where(address, blockquote, dl, figure, form, ol, p, pre, table, ul)~:is(h1, h2, h3, h4, h5, h6){margin-top:var(--typography-spacing-vertical)}hgroup,.headings{margin-bottom:var(--typography-spacing-vertical)}hgroup>*,.headings>*{margin-bottom:0}hgroup>*:last-child,.headings>*:last-child{--color: var(--muted-color);--font-weight: unset;font-size:1rem;font-family:unset}p{margin-bottom:var(--typography-spacing-vertical)}small{font-size:var(--font-size)}:where(dl, ol, ul){padding-right:0;padding-left:var(--spacing);padding-inline-start:var(--spacing);padding-inline-end:0}:where(dl, ol, ul) li{margin-bottom:calc(var(--typography-spacing-vertical) * 0.25)}:where(dl, ol, ul) :is(dl, ol, ul){margin:0;margin-top:calc(var(--typography-spacing-vertical) * 0.25)}ul li{list-style:square}mark{padding:0.125rem 0.25rem;background-color:var(--mark-background-color);color:var(--mark-color);vertical-align:baseline}blockquote{display:block;margin:var(--typography-spacing-vertical) 0;padding:var(--spacing);border-right:none;border-left:0.25rem solid var(--blockquote-border-color);border-inline-start:0.25rem solid var(--blockquote-border-color);border-inline-end:none}blockquote footer{margin-top:calc(var(--typography-spacing-vertical) * 0.5);color:var(--blockquote-footer-color)}abbr[title]{border-bottom:1px dotted;text-decoration:none;cursor:help}ins{color:var(--ins-color);text-decoration:none}del{color:var(--del-color)}::selection{background-color:var(--primary-focus)}:where(audio, canvas, iframe, img, svg, video){vertical-align:middle}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}:where(iframe){border-style:none}img{max-width:100%;height:auto;border-style:none}:where(svg:not([fill])){fill:currentColor}svg:not(:root){overflow:hidden}button{margin:0;overflow:visible;font-family:inherit;text-transform:none}button,[type="button"],[type="reset"],[type="submit"]{-webkit-appearance:button}button{display:block;width:100%;margin-bottom:var(--spacing)}[role="button"]{display:inline-block;text-decoration:none}button,input[type="submit"],input[type="button"],input[type="reset"],[role="button"]{--background-color: var(--primary);--border-color: var(--primary);--color: var(--primary-inverse);--box-shadow: var(--button-box-shadow, 0 0 0 rgba(0, 0, 0, 0));padding:var(--form-element-spacing-vertical) var(--form-element-spacing-horizontal);border:var(--border-width) solid var(--border-color);border-radius:var(--border-radius);outline:none;background-color:var(--background-color);box-shadow:var(--box-shadow);color:var(--color);font-weight:var(--font-weight);font-size:1rem;line-height:var(--line-height);text-align:center;cursor:pointer;transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition)}button:is([aria-current], :hover, :active, :focus),input[type="submit"]:is([aria-current], :hover, :active, :focus),input[type="button"]:is([aria-current], :hover, :active, :focus),input[type="reset"]:is([aria-current], :hover, :active, :focus),[role="button"]:is([aria-current], :hover, :active, :focus){--background-color: var(--primary-hover);--border-color: var(--primary-hover);--box-shadow: var(--button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0));--color: var(--primary-inverse)}button:focus,input[type="submit"]:focus,input[type="button"]:focus,input[type="reset"]:focus,[role="button"]:focus{--box-shadow: var(--button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)), + 0 0 0 var(--outline-width) var(--primary-focus)}:is(button, input[type="submit"], input[type="button"], [role="button"]).secondary,input[type="reset"]{--background-color: var(--secondary);--border-color: var(--secondary);--color: var(--secondary-inverse);cursor:pointer}:is(button, input[type="submit"], input[type="button"], [role="button"]).secondary:is([aria-current], :hover, :active, :focus),input[type="reset"]:is([aria-current], :hover, :active, :focus){--background-color: var(--secondary-hover);--border-color: var(--secondary-hover);--color: var(--secondary-inverse)}:is(button, input[type="submit"], input[type="button"], [role="button"]).secondary:focus,input[type="reset"]:focus{--box-shadow: var(--button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)), + 0 0 0 var(--outline-width) var(--secondary-focus)}:is(button, input[type="submit"], input[type="button"], [role="button"]).contrast{--background-color: var(--contrast);--border-color: var(--contrast);--color: var(--contrast-inverse)}:is(button, input[type="submit"], input[type="button"], [role="button"]).contrast:is([aria-current], :hover, :active, :focus){--background-color: var(--contrast-hover);--border-color: var(--contrast-hover);--color: var(--contrast-inverse)}:is(button, input[type="submit"], input[type="button"], [role="button"]).contrast:focus{--box-shadow: var(--button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)), + 0 0 0 var(--outline-width) var(--contrast-focus)}:is(button, input[type="submit"], input[type="button"], [role="button"]).outline,input[type="reset"].outline{--background-color: transparent;--color: var(--primary)}:is(button, input[type="submit"], input[type="button"], [role="button"]).outline:is([aria-current], :hover, :active, :focus),input[type="reset"].outline:is([aria-current], :hover, :active, :focus){--background-color: transparent;--color: var(--primary-hover)}:is(button, input[type="submit"], input[type="button"], [role="button"]).outline.secondary,input[type="reset"].outline{--color: var(--secondary)}:is(button, input[type="submit"], input[type="button"], [role="button"]).outline.secondary:is([aria-current], :hover, :active, :focus),input[type="reset"].outline:is([aria-current], :hover, :active, :focus){--color: var(--secondary-hover)}:is(button, input[type="submit"], input[type="button"], [role="button"]).outline.contrast{--color: var(--contrast)}:is(button, input[type="submit"], input[type="button"], [role="button"]).outline.contrast:is([aria-current], :hover, :active, :focus){--color: var(--contrast-hover)}:where(button, [type="submit"], [type="button"], [type="reset"], [role="button"])[disabled],:where(fieldset[disabled]) :is(button, [type="submit"], [type="button"], [type="reset"], [role="button"]),a[role="button"]:not([href]){opacity:0.5;pointer-events:none}input,optgroup,select,textarea{margin:0;font-size:1rem;line-height:var(--line-height);font-family:inherit;letter-spacing:inherit}input{overflow:visible}select{text-transform:none}legend{max-width:100%;padding:0;color:inherit;white-space:normal}textarea{overflow:auto}[type="checkbox"],[type="radio"]{padding:0}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type="search"]{-webkit-appearance:textfield;outline-offset:-2px}[type="search"]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}::-moz-focus-inner{padding:0;border-style:none}:-moz-focusring{outline:none}:-moz-ui-invalid{box-shadow:none}::-ms-expand{display:none}[type="file"],[type="range"]{padding:0;border-width:0}input:not([type="checkbox"],[type="radio"],[type="range"]){height:calc( (1rem * var(--line-height)) + (var(--form-element-spacing-vertical) * 2) + (var(--border-width) * 2))}fieldset{margin:0;margin-bottom:var(--spacing);padding:0;border:0}label,fieldset legend{display:block;margin-bottom:calc(var(--spacing) * 0.25);font-weight:var(--form-label-font-weight, var(--font-weight))}input:not([type="checkbox"],[type="radio"]),select,textarea{width:100%}input:not([type="checkbox"],[type="radio"],[type="range"],[type="file"]),select,textarea{appearance:none;padding:var(--form-element-spacing-vertical) var(--form-element-spacing-horizontal)}input,select,textarea{--background-color: var(--form-element-background-color);--border-color: var(--form-element-border-color);--color: var(--form-element-color);--box-shadow: none;border:var(--border-width) solid var(--border-color);border-radius:var(--border-radius);outline:none;background-color:var(--background-color);box-shadow:var(--box-shadow);color:var(--color);font-weight:var(--font-weight);transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition)}input:not([type="submit"],[type="button"],[type="reset"],[type="checkbox"],[type="radio"],[readonly]):is(:active, :focus),:where(select, textarea):is(:active, :focus){--background-color: var(--form-element-active-background-color)}input:not([type="submit"],[type="button"],[type="reset"],[role="switch"],[readonly]):is(:active, :focus),:where(select, textarea):is(:active, :focus){--border-color: var(--form-element-active-border-color)}input:not([type="submit"],[type="button"],[type="reset"],[type="range"],[type="file"],[readonly]):focus,select:focus,textarea:focus{--box-shadow: 0 0 0 var(--outline-width) var(--form-element-focus-color)}input:not([type="submit"],[type="button"],[type="reset"])[disabled],select[disabled],textarea[disabled],:where(fieldset[disabled]) :is(input:not([type="submit"], [type="button"], [type="reset"]), select, textarea){--background-color: var(--form-element-disabled-background-color);--border-color: var(--form-element-disabled-border-color);opacity:var(--form-element-disabled-opacity);pointer-events:none}:where(input, select, textarea):not([type="checkbox"],[type="radio"],[type="date"],[type="datetime-local"],[type="month"],[type="time"],[type="week"])[aria-invalid]{padding-right:calc( var(--form-element-spacing-horizontal) + 1.5rem) !important;padding-left:var(--form-element-spacing-horizontal);padding-inline-start:var(--form-element-spacing-horizontal) !important;padding-inline-end:calc( var(--form-element-spacing-horizontal) + 1.5rem) !important;background-position:center right 0.75rem;background-size:1rem auto;background-repeat:no-repeat}:where(input, select, textarea):not([type="checkbox"],[type="radio"],[type="date"],[type="datetime-local"],[type="month"],[type="time"],[type="week"])[aria-invalid="false"]{background-image:var(--icon-valid)}:where(input, select, textarea):not([type="checkbox"],[type="radio"],[type="date"],[type="datetime-local"],[type="month"],[type="time"],[type="week"])[aria-invalid="true"]{background-image:var(--icon-invalid)}:where(input, select, textarea)[aria-invalid="false"]{--border-color: var(--form-element-valid-border-color)}:where(input, select, textarea)[aria-invalid="false"]:is(:active, :focus){--border-color: var(--form-element-valid-active-border-color) !important;--box-shadow: 0 0 0 var(--outline-width) var(--form-element-valid-focus-color) !important}:where(input, select, textarea)[aria-invalid="true"]{--border-color: var(--form-element-invalid-border-color)}:where(input, select, textarea)[aria-invalid="true"]:is(:active, :focus){--border-color: var(--form-element-invalid-active-border-color) !important;--box-shadow: 0 0 0 var(--outline-width) var(--form-element-invalid-focus-color) !important}[dir="rtl"] :where(input, select, textarea):not([type="checkbox"],[type="radio"]):is([aria-invalid], [aria-invalid="true"], [aria-invalid="false"] ){background-position:center left 0.75rem}input::placeholder,input::-webkit-input-placeholder,textarea::placeholder,textarea::-webkit-input-placeholder,select:invalid{color:var(--form-element-placeholder-color);opacity:1}input:not([type="checkbox"],[type="radio"]),select,textarea{margin-bottom:var(--spacing)}select::-ms-expand{border:0;background-color:transparent}select:not([multiple],[size]){padding-right:calc(var(--form-element-spacing-horizontal) + 1.5rem);padding-left:var(--form-element-spacing-horizontal);padding-inline-start:var(--form-element-spacing-horizontal);padding-inline-end:calc(var(--form-element-spacing-horizontal) + 1.5rem);background-image:var(--icon-chevron);background-position:center right 0.75rem;background-size:1rem auto;background-repeat:no-repeat}[dir="rtl"] select:not([multiple],[size]){background-position:center left 0.75rem}:where(input, select, textarea, .grid)+small{display:block;width:100%;margin-top:calc(var(--spacing) * -0.75);margin-bottom:var(--spacing);color:var(--muted-color)}label>:where(input, select, textarea){margin-top:calc(var(--spacing) * 0.25)}[type="checkbox"],[type="radio"]{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:1.25em;height:1.25em;margin-top:-0.125em;margin-right:0.375em;margin-left:0;margin-inline-start:0;margin-inline-end:0.375em;border-width:var(--border-width);font-size:inherit;vertical-align:middle;cursor:pointer}[type="checkbox"]::-ms-check,[type="radio"]::-ms-check{display:none}[type="checkbox"]:checked,[type="checkbox"]:checked:active,[type="checkbox"]:checked:focus,[type="radio"]:checked,[type="radio"]:checked:active,[type="radio"]:checked:focus{--background-color: var(--primary);--border-color: var(--primary);background-image:var(--icon-checkbox);background-position:center;background-size:0.75em auto;background-repeat:no-repeat}[type="checkbox"]~label,[type="radio"]~label{display:inline-block;margin-right:0.375em;margin-bottom:0;cursor:pointer}[type="checkbox"]:indeterminate{--background-color: var(--primary);--border-color: var(--primary);background-image:var(--icon-minus);background-position:center;background-size:0.75em auto;background-repeat:no-repeat}[type="radio"]{border-radius:50%}[type="radio"]:checked,[type="radio"]:checked:active,[type="radio"]:checked:focus{--background-color: var(--primary-inverse);border-width:0.35em;background-image:none}[type="checkbox"][role="switch"]{--background-color: var(--switch-background-color);--border-color: var(--switch-background-color);--color: var(--switch-color);width:2.25em;height:1.25em;border:var(--border-width) solid var(--border-color);border-radius:1.25em;background-color:var(--background-color);line-height:1.25em}[type="checkbox"][role="switch"]:focus{--background-color: var(--switch-background-color);--border-color: var(--switch-background-color)}[type="checkbox"][role="switch"]:checked{--background-color: var(--switch-checked-background-color);--border-color: var(--switch-checked-background-color)}[type="checkbox"][role="switch"]:before{display:block;width:calc(1.25em - (var(--border-width) * 2));height:100%;border-radius:50%;background-color:var(--color);content:"";transition:margin 0.1s ease-in-out}[type="checkbox"][role="switch"]:checked{background-image:none}[type="checkbox"][role="switch"]:checked::before{margin-left:calc(1.125em - var(--border-width));margin-inline-start:calc(1.125em - var(--border-width))}[type="checkbox"][aria-invalid="false"],[type="checkbox"]:checked[aria-invalid="false"],[type="radio"][aria-invalid="false"],[type="radio"]:checked[aria-invalid="false"],[type="checkbox"][role="switch"][aria-invalid="false"],[type="checkbox"][role="switch"]:checked[aria-invalid="false"]{--border-color: var(--form-element-valid-border-color)}[type="checkbox"][aria-invalid="true"],[type="checkbox"]:checked[aria-invalid="true"],[type="radio"][aria-invalid="true"],[type="radio"]:checked[aria-invalid="true"],[type="checkbox"][role="switch"][aria-invalid="true"],[type="checkbox"][role="switch"]:checked[aria-invalid="true"]{--border-color: var(--form-element-invalid-border-color)}[type="color"]::-webkit-color-swatch-wrapper{padding:0}[type="color"]::-moz-focus-inner{padding:0}[type="color"]::-webkit-color-swatch{border:0;border-radius:calc(var(--border-radius) * 0.5)}[type="color"]::-moz-color-swatch{border:0;border-radius:calc(var(--border-radius) * 0.5)}input:not([type="checkbox"],[type="radio"],[type="range"],[type="file"]):is([type="date"], [type="datetime-local"], [type="month"], [type="time"], [type="week"]){--icon-position: 0.75rem;--icon-width: 1rem;padding-right:calc(var(--icon-width) + var(--icon-position));background-image:var(--icon-date);background-position:center right var(--icon-position);background-size:var(--icon-width) auto;background-repeat:no-repeat}input:not([type="checkbox"],[type="radio"],[type="range"],[type="file"])[type="time"]{background-image:var(--icon-time)}[type="date"]::-webkit-calendar-picker-indicator,[type="datetime-local"]::-webkit-calendar-picker-indicator,[type="month"]::-webkit-calendar-picker-indicator,[type="time"]::-webkit-calendar-picker-indicator,[type="week"]::-webkit-calendar-picker-indicator{width:var(--icon-width);margin-right:calc(var(--icon-width) * -1);margin-left:var(--icon-position);opacity:0}[dir="rtl"] :is([type="date"], [type="datetime-local"], [type="month"], [type="time"], [type="week"]){text-align:right}[type="file"]{--color: var(--muted-color);padding:calc(var(--form-element-spacing-vertical) * 0.5) 0;border:0;border-radius:0;background:none}[type="file"]::file-selector-button{--background-color: var(--secondary);--border-color: var(--secondary);--color: var(--secondary-inverse);margin-right:calc(var(--spacing) / 2);margin-left:0;margin-inline-start:0;margin-inline-end:calc(var(--spacing) / 2);padding:calc(var(--form-element-spacing-vertical) * 0.5) calc(var(--form-element-spacing-horizontal) * 0.5);border:var(--border-width) solid var(--border-color);border-radius:var(--border-radius);outline:none;background-color:var(--background-color);box-shadow:var(--box-shadow);color:var(--color);font-weight:var(--font-weight);font-size:1rem;line-height:var(--line-height);text-align:center;cursor:pointer;transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition)}[type="file"]::file-selector-button:is(:hover, :active, :focus){--background-color: var(--secondary-hover);--border-color: var(--secondary-hover)}[type="file"]::-webkit-file-upload-button{--background-color: var(--secondary);--border-color: var(--secondary);--color: var(--secondary-inverse);margin-right:calc(var(--spacing) / 2);margin-left:0;margin-inline-start:0;margin-inline-end:calc(var(--spacing) / 2);padding:calc(var(--form-element-spacing-vertical) * 0.5) calc(var(--form-element-spacing-horizontal) * 0.5);border:var(--border-width) solid var(--border-color);border-radius:var(--border-radius);outline:none;background-color:var(--background-color);box-shadow:var(--box-shadow);color:var(--color);font-weight:var(--font-weight);font-size:1rem;line-height:var(--line-height);text-align:center;cursor:pointer;transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition)}[type="file"]::-webkit-file-upload-button:is(:hover, :active, :focus){--background-color: var(--secondary-hover);--border-color: var(--secondary-hover)}[type="file"]::-ms-browse{--background-color: var(--secondary);--border-color: var(--secondary);--color: var(--secondary-inverse);margin-right:calc(var(--spacing) / 2);margin-left:0;margin-inline-start:0;margin-inline-end:calc(var(--spacing) / 2);padding:calc(var(--form-element-spacing-vertical) * 0.5) calc(var(--form-element-spacing-horizontal) * 0.5);border:var(--border-width) solid var(--border-color);border-radius:var(--border-radius);outline:none;background-color:var(--background-color);box-shadow:var(--box-shadow);color:var(--color);font-weight:var(--font-weight);font-size:1rem;line-height:var(--line-height);text-align:center;cursor:pointer;transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition)}[type="file"]::-ms-browse:is(:hover, :active, :focus){--background-color: var(--secondary-hover);--border-color: var(--secondary-hover)}[type="range"]{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;height:1.25rem;background:none}[type="range"]::-webkit-slider-runnable-track{width:100%;height:.25rem;border-radius:var(--border-radius);background-color:var(--range-border-color);transition:background-color var(--transition),box-shadow var(--transition)}[type="range"]::-moz-range-track{width:100%;height:.25rem;border-radius:var(--border-radius);background-color:var(--range-border-color);transition:background-color var(--transition),box-shadow var(--transition)}[type="range"]::-ms-track{width:100%;height:.25rem;border-radius:var(--border-radius);background-color:var(--range-border-color);transition:background-color var(--transition),box-shadow var(--transition)}[type="range"]::-webkit-slider-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.5rem;border:2px solid var(--range-thumb-border-color);border-radius:50%;background-color:var(--range-thumb-color);cursor:pointer;transition:background-color var(--transition),transform var(--transition)}[type="range"]::-moz-range-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.5rem;border:2px solid var(--range-thumb-border-color);border-radius:50%;background-color:var(--range-thumb-color);cursor:pointer;transition:background-color var(--transition),transform var(--transition)}[type="range"]::-ms-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.5rem;border:2px solid var(--range-thumb-border-color);border-radius:50%;background-color:var(--range-thumb-color);cursor:pointer;transition:background-color var(--transition),transform var(--transition)}[type="range"]:hover,[type="range"]:focus{--range-border-color: var(--range-active-border-color);--range-thumb-color: var(--range-thumb-hover-color)}[type="range"]:active{--range-thumb-color: var(--range-thumb-active-color)}[type="range"]:active::-webkit-slider-thumb{transform:scale(1.25)}[type="range"]:active::-moz-range-thumb{transform:scale(1.25)}[type="range"]:active::-ms-thumb{transform:scale(1.25)}input:not([type="checkbox"],[type="radio"],[type="range"],[type="file"])[type="search"]{padding-inline-start:calc(var(--form-element-spacing-horizontal) + 1.75rem);border-radius:5rem;background-image:var(--icon-search);background-position:center left 1.125rem;background-size:1rem auto;background-repeat:no-repeat}input:not([type="checkbox"],[type="radio"],[type="range"],[type="file"])[type="search"][aria-invalid]{padding-inline-start:calc(var(--form-element-spacing-horizontal) + 1.75rem) !important;background-position:center left 1.125rem, center right 0.75rem}input:not([type="checkbox"],[type="radio"],[type="range"],[type="file"])[type="search"][aria-invalid="false"]{background-image:var(--icon-search),var(--icon-valid)}input:not([type="checkbox"],[type="radio"],[type="range"],[type="file"])[type="search"][aria-invalid="true"]{background-image:var(--icon-search),var(--icon-invalid)}[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;display:none}[dir="rtl"] :where(input):not([type="checkbox"],[type="radio"],[type="range"],[type="file"])[type="search"]{background-position:center right 1.125rem}[dir="rtl"] :where(input):not([type="checkbox"],[type="radio"],[type="range"],[type="file"])[type="search"][aria-invalid]{background-position:center right 1.125rem, center left 0.75rem}:where(table){width:100%;border-collapse:collapse;border-spacing:0;text-indent:0}th,td{padding:calc(var(--spacing) / 2) var(--spacing);border-bottom:var(--border-width) solid var(--table-border-color);color:var(--color);font-weight:var(--font-weight);font-size:var(--font-size);text-align:left;text-align:start}tfoot th,tfoot td{border-top:var(--border-width) solid var(--table-border-color);border-bottom:0}table[role="grid"] tbody tr:nth-child(odd){background-color:var(--table-row-stripped-background-color)}pre,code,kbd,samp{font-size:0.875em;font-family:var(--font-family)}pre{-ms-overflow-style:scrollbar;overflow:auto}pre,code,kbd{border-radius:var(--border-radius);background:var(--code-background-color);color:var(--code-color);font-weight:var(--font-weight);line-height:initial}code,kbd{display:inline-block;padding:0.375rem 0.5rem}pre{display:block;margin-bottom:var(--spacing);overflow-x:auto}pre>code{display:block;padding:var(--spacing);background:none;font-size:14px;line-height:var(--line-height)}code b{color:var(--code-tag-color);font-weight:var(--font-weight)}code i{color:var(--code-property-color);font-style:normal}code u{color:var(--code-value-color);text-decoration:none}code em{color:var(--code-comment-color);font-style:normal}kbd{background-color:var(--code-kbd-background-color);color:var(--code-kbd-color);vertical-align:baseline}hr{height:0;border:0;border-top:1px solid var(--muted-border-color);color:inherit}[hidden],template{display:none !important}canvas{display:inline-block}details{display:block;margin-bottom:var(--spacing);padding-bottom:var(--spacing);border-bottom:var(--border-width) solid var(--accordion-border-color)}details summary{line-height:1rem;list-style-type:none;cursor:pointer;transition:color var(--transition)}details summary:not([role]){color:var(--accordion-close-summary-color)}details summary::-webkit-details-marker{display:none}details summary::marker{display:none}details summary::-moz-list-bullet{list-style-type:none}details summary::after{display:block;width:1rem;height:1rem;margin-inline-start:calc(var(--spacing, 1rem) * 0.5);float:right;transform:rotate(-90deg);background-image:var(--icon-chevron);background-position:right center;background-size:1rem auto;background-repeat:no-repeat;content:"";transition:transform var(--transition)}details summary:focus{outline:none}details summary:focus:not([role="button"]){color:var(--accordion-active-summary-color)}details summary[role="button"]{width:100%;text-align:left}details summary[role="button"]::after{height:calc(1rem * var(--line-height, 1.5));background-image:var(--icon-chevron-button)}details summary[role="button"]:not(.outline).contrast::after{background-image:var(--icon-chevron-button-inverse)}details[open]>summary{margin-bottom:calc(var(--spacing))}details[open]>summary:not([role]):not(:focus){color:var(--accordion-open-summary-color)}details[open]>summary::after{transform:rotate(0)}[dir="rtl"] details summary{text-align:right}[dir="rtl"] details summary::after{float:left;background-position:left center}article{margin:var(--block-spacing-vertical) 0;padding:var(--block-spacing-vertical) var(--block-spacing-horizontal);border-radius:var(--border-radius);background:var(--card-background-color);box-shadow:var(--card-box-shadow)}article>header,article>footer{margin-right:calc(var(--block-spacing-horizontal) * -1);margin-left:calc(var(--block-spacing-horizontal) * -1);padding:calc(var(--block-spacing-vertical) * 0.66) var(--block-spacing-horizontal);background-color:var(--card-sectionning-background-color)}article>header{margin-top:calc(var(--block-spacing-vertical) * -1);margin-bottom:var(--block-spacing-vertical);border-bottom:var(--border-width) solid var(--card-border-color);border-top-right-radius:var(--border-radius);border-top-left-radius:var(--border-radius)}article>footer{margin-top:var(--block-spacing-vertical);margin-bottom:calc(var(--block-spacing-vertical) * -1);border-top:var(--border-width) solid var(--card-border-color);border-bottom-right-radius:var(--border-radius);border-bottom-left-radius:var(--border-radius)}:root{--scrollbar-width: 0px}dialog{display:flex;z-index:999;position:fixed;top:0;right:0;bottom:0;left:0;align-items:center;justify-content:center;width:inherit;min-width:100%;height:inherit;min-height:100%;padding:var(--spacing);border:0;backdrop-filter:var(--modal-overlay-backdrop-filter);background-color:var(--modal-overlay-background-color);color:var(--color)}dialog article{max-height:calc(100vh - var(--spacing) * 2);overflow:auto}@media (min-width: 576px){dialog article{max-width:510px}}@media (min-width: 768px){dialog article{max-width:700px}}dialog article>header,dialog article>footer{padding:calc(var(--block-spacing-vertical) * 0.5) var(--block-spacing-horizontal)}dialog article>header .close{margin:0;margin-left:var(--spacing);float:right}dialog article>footer{text-align:right}dialog article>footer [role="button"]{margin-bottom:0}dialog article>footer [role="button"]:not(:first-of-type){margin-left:calc(var(--spacing) * 0.5)}dialog article p:last-of-type{margin:0}dialog article .close{display:block;width:1rem;height:1rem;margin-top:calc(var(--block-spacing-vertical) * -0.5);margin-bottom:var(--typography-spacing-vertical);margin-left:auto;background-image:var(--icon-close);background-position:center;background-size:auto 1rem;background-repeat:no-repeat;opacity:0.5;transition:opacity var(--transition)}dialog article .close:is([aria-current], :hover, :active, :focus){opacity:1}dialog:not([open]),dialog[open="false"]{display:none}.modal-is-open{padding-right:var(--scrollbar-width, 0px);overflow:hidden;pointer-events:none;touch-action:none}.modal-is-open dialog{pointer-events:auto}:where(.modal-is-opening, .modal-is-closing) dialog,:where(.modal-is-opening, .modal-is-closing) dialog>article{animation-duration:.2s;animation-timing-function:ease-in-out;animation-fill-mode:both}:where(.modal-is-opening, .modal-is-closing) dialog{animation-duration:.8s;animation-name:modal-overlay}:where(.modal-is-opening, .modal-is-closing) dialog>article{animation-delay:.2s;animation-name:modal}.modal-is-closing dialog,.modal-is-closing dialog>article{animation-delay:0s;animation-direction:reverse}@keyframes modal-overlay{from{backdrop-filter:none;background-color:transparent}}@keyframes modal{from{transform:translateY(-100%);opacity:0}}:where(nav li)::before{float:left;content:"\200B"}nav,nav ul{display:flex}nav{justify-content:space-between}nav ol,nav ul{align-items:center;margin-bottom:0;padding:0;list-style:none}nav ol:first-of-type,nav ul:first-of-type{margin-left:calc(var(--nav-element-spacing-horizontal) * -1)}nav ol:last-of-type,nav ul:last-of-type{margin-right:calc(var(--nav-element-spacing-horizontal) * -1)}nav li{display:inline-block;margin:0;padding:var(--nav-element-spacing-vertical) var(--nav-element-spacing-horizontal)}nav li>*{--spacing: 0}nav :where(a, [role="link"]){display:inline-block;margin:calc(var(--nav-link-spacing-vertical) * -1) calc(var(--nav-link-spacing-horizontal) * -1);padding:var(--nav-link-spacing-vertical) var(--nav-link-spacing-horizontal);border-radius:var(--border-radius);text-decoration:none}nav :where(a, [role="link"]):is([aria-current], :hover, :active, :focus){text-decoration:none}nav[aria-label="breadcrumb"]{align-items:center;justify-content:start}nav[aria-label="breadcrumb"] ul li:not(:first-child){margin-inline-start:var(--nav-link-spacing-horizontal)}nav[aria-label="breadcrumb"] ul li:not(:last-child) ::after{position:absolute;width:calc(var(--nav-link-spacing-horizontal) * 2);margin-inline-start:calc(var(--nav-link-spacing-horizontal) / 2);content:"/";color:var(--muted-color);text-align:center}nav[aria-label="breadcrumb"] a[aria-current]{background-color:transparent;color:inherit;text-decoration:none;pointer-events:none}nav [role="button"]{margin-right:inherit;margin-left:inherit;padding:var(--nav-link-spacing-vertical) var(--nav-link-spacing-horizontal)}aside nav,aside ol,aside ul,aside li{display:block}aside li{padding:calc(var(--nav-element-spacing-vertical) * 0.5) var(--nav-element-spacing-horizontal)}aside li a{display:block}aside li [role="button"]{margin:inherit}[dir="rtl"] nav[aria-label="breadcrumb"] ul li:not(:last-child) ::after{content:"\\"}progress{display:inline-block;vertical-align:baseline}progress{-webkit-appearance:none;-moz-appearance:none;display:inline-block;appearance:none;width:100%;height:0.5rem;margin-bottom:calc(var(--spacing) * 0.5);overflow:hidden;border:0;border-radius:var(--border-radius);background-color:var(--progress-background-color);color:var(--progress-color)}progress::-webkit-progress-bar{border-radius:var(--border-radius);background:none}progress[value]::-webkit-progress-value{background-color:var(--progress-color)}progress::-moz-progress-bar{background-color:var(--progress-color)}@media (prefers-reduced-motion: no-preference){progress:indeterminate{background:var(--progress-background-color) linear-gradient(to right, var(--progress-color) 30%, var(--progress-background-color) 30%) top left/150% 150% no-repeat;animation:progress-indeterminate 1s linear infinite}progress:indeterminate[value]::-webkit-progress-value{background-color:transparent}progress:indeterminate::-moz-progress-bar{background-color:transparent}}@media (prefers-reduced-motion: no-preference){[dir="rtl"] progress:indeterminate{animation-direction:reverse}}@keyframes progress-indeterminate{0%{background-position:200% 0}100%{background-position:-200% 0}}details[role="list"],li[role="list"]{position:relative}details[role="list"] summary+ul,li[role="list"]>ul{display:flex;z-index:99;position:absolute;top:auto;right:0;left:0;flex-direction:column;margin:0;padding:0;border:var(--border-width) solid var(--dropdown-border-color);border-radius:var(--border-radius);border-top-right-radius:0;border-top-left-radius:0;background-color:var(--dropdown-background-color);box-shadow:var(--card-box-shadow);color:var(--dropdown-color);white-space:nowrap}details[role="list"] summary+ul li,li[role="list"]>ul li{width:100%;margin-bottom:0;padding:calc(var(--form-element-spacing-vertical) * 0.5) var(--form-element-spacing-horizontal);list-style:none}details[role="list"] summary+ul li:first-of-type,li[role="list"]>ul li:first-of-type{margin-top:calc(var(--form-element-spacing-vertical) * 0.5)}details[role="list"] summary+ul li:last-of-type,li[role="list"]>ul li:last-of-type{margin-bottom:calc(var(--form-element-spacing-vertical) * 0.5)}details[role="list"] summary+ul li a,li[role="list"]>ul li a{display:block;margin:calc(var(--form-element-spacing-vertical) * -0.5) calc(var(--form-element-spacing-horizontal) * -1);padding:calc(var(--form-element-spacing-vertical) * 0.5) var(--form-element-spacing-horizontal);overflow:hidden;color:var(--dropdown-color);text-decoration:none;text-overflow:ellipsis}details[role="list"] summary+ul li a:hover,li[role="list"]>ul li a:hover{background-color:var(--dropdown-hover-background-color)}details[role="list"] summary::after,li[role="list"]>a::after{display:block;width:1rem;height:calc(1rem * var(--line-height, 1.5));margin-inline-start:0.5rem;float:right;transform:rotate(0deg);background-position:right center;background-size:1rem auto;background-repeat:no-repeat;content:""}details[role="list"]{padding:0;border-bottom:none}details[role="list"] summary{margin-bottom:0}details[role="list"] summary:not([role]){height:calc( 1rem * var(--line-height) + var(--form-element-spacing-vertical) * 2 + var(--border-width) * 2);padding:var(--form-element-spacing-vertical) var(--form-element-spacing-horizontal);border:var(--border-width) solid var(--form-element-border-color);border-radius:var(--border-radius);background-color:var(--form-element-background-color);color:var(--form-element-placeholder-color);line-height:inherit;cursor:pointer;transition:background-color var(--transition),border-color var(--transition),color var(--transition),box-shadow var(--transition)}details[role="list"] summary:not([role]):active,details[role="list"] summary:not([role]):focus{border-color:var(--form-element-active-border-color);background-color:var(--form-element-active-background-color)}details[role="list"] summary:not([role]):focus{box-shadow:0 0 0 var(--outline-width) var(--form-element-focus-color)}details[role="list"][open] summary{border-bottom-right-radius:0;border-bottom-left-radius:0}details[role="list"][open] summary::before{display:block;z-index:1;position:fixed;top:0;right:0;bottom:0;left:0;background:none;content:"";cursor:default}nav details[role="list"] summary,nav li[role="list"] a{display:flex;direction:ltr}nav details[role="list"] summary+ul,nav li[role="list"]>ul{min-width:fit-content;border-radius:var(--border-radius)}nav details[role="list"] summary+ul li a,nav li[role="list"]>ul li a{border-radius:0}nav details[role="list"] summary,nav details[role="list"] summary:not([role]){height:auto;padding:var(--nav-link-spacing-vertical) var(--nav-link-spacing-horizontal)}nav details[role="list"][open] summary{border-radius:var(--border-radius)}nav details[role="list"] summary+ul{margin-top:var(--outline-width);margin-inline-start:0}nav details[role="list"] summary[role="link"]{margin-bottom:calc(var(--nav-link-spacing-vertical) * -1);line-height:var(--line-height)}nav details[role="list"] summary[role="link"]+ul{margin-top:calc(var(--nav-link-spacing-vertical) + var(--outline-width));margin-inline-start:calc(var(--nav-link-spacing-horizontal) * -1)}li[role="list"]:hover>ul,li[role="list"] a:active~ul,li[role="list"] a:focus~ul{display:flex}li[role="list"]>ul{display:none;margin-top:calc(var(--nav-link-spacing-vertical) + var(--outline-width));margin-inline-start:calc( var(--nav-element-spacing-horizontal) - var(--nav-link-spacing-horizontal))}li[role="list"]>a::after{background-image:var(--icon-chevron)}label>details[role="list"]{margin-top:calc(var(--spacing) * .25);margin-bottom:var(--spacing)}[aria-busy="true"]{cursor:progress}[aria-busy="true"]:not(input,select,textarea)::before{display:inline-block;width:1em;height:1em;border:0.1875em solid currentColor;border-radius:1em;border-right-color:transparent;content:"";vertical-align:text-bottom;vertical-align:-.125em;animation:spinner 0.75s linear infinite;opacity:var(--loading-spinner-opacity)}[aria-busy="true"]:not(input,select,textarea):not(:empty)::before{margin-right:calc(var(--spacing) * 0.5);margin-left:0;margin-inline-start:0;margin-inline-end:calc(var(--spacing) * 0.5)}[aria-busy="true"]:not(input,select,textarea):empty{text-align:center}button[aria-busy="true"],input[type="submit"][aria-busy="true"],input[type="button"][aria-busy="true"],input[type="reset"][aria-busy="true"],a[aria-busy="true"]{pointer-events:none}@keyframes spinner{to{transform:rotate(360deg)}}[data-tooltip]{position:relative}[data-tooltip]:not(a,button,input){border-bottom:1px dotted;text-decoration:none;cursor:help}[data-tooltip][data-placement="top"]::before,[data-tooltip][data-placement="top"]::after,[data-tooltip]::before,[data-tooltip]::after{display:block;z-index:99;position:absolute;bottom:100%;left:50%;padding:.25rem .5rem;overflow:hidden;transform:translate(-50%, -0.25rem);border-radius:var(--border-radius);background:var(--tooltip-background-color);content:attr(data-tooltip);color:var(--tooltip-color);font-style:normal;font-weight:var(--font-weight);font-size:.875rem;text-decoration:none;text-overflow:ellipsis;white-space:nowrap;opacity:0;pointer-events:none}[data-tooltip][data-placement="top"]::after,[data-tooltip]::after{padding:0;transform:translate(-50%, 0rem);border-top:.3rem solid;border-right:.3rem solid transparent;border-left:.3rem solid transparent;border-radius:0;background-color:transparent;content:"";color:var(--tooltip-background-color)}[data-tooltip][data-placement="bottom"]::before,[data-tooltip][data-placement="bottom"]::after{top:100%;bottom:auto;transform:translate(-50%, 0.25rem)}[data-tooltip][data-placement="bottom"]:after{transform:translate(-50%, -0.3rem);border:.3rem solid transparent;border-bottom:.3rem solid}[data-tooltip][data-placement="left"]::before,[data-tooltip][data-placement="left"]::after{top:50%;right:100%;bottom:auto;left:auto;transform:translate(-0.25rem, -50%)}[data-tooltip][data-placement="left"]:after{transform:translate(0.3rem, -50%);border:.3rem solid transparent;border-left:.3rem solid}[data-tooltip][data-placement="right"]::before,[data-tooltip][data-placement="right"]::after{top:50%;right:auto;bottom:auto;left:100%;transform:translate(0.25rem, -50%)}[data-tooltip][data-placement="right"]:after{transform:translate(-0.3rem, -50%);border:.3rem solid transparent;border-right:.3rem solid}[data-tooltip]:focus::before,[data-tooltip]:focus::after,[data-tooltip]:hover::before,[data-tooltip]:hover::after{opacity:1}@media (hover: hover) and (pointer: fine){[data-tooltip][data-placement="bottom"]:focus::before,[data-tooltip][data-placement="bottom"]:focus::after,[data-tooltip][data-placement="bottom"]:hover [data-tooltip]:focus::before,[data-tooltip][data-placement="bottom"]:hover [data-tooltip]:focus::after,[data-tooltip]:hover::before,[data-tooltip]:hover::after{animation-duration:.2s;animation-name:tooltip-slide-top}[data-tooltip][data-placement="bottom"]:focus::after,[data-tooltip][data-placement="bottom"]:hover [data-tooltip]:focus::after,[data-tooltip]:hover::after{animation-name:tooltip-caret-slide-top}[data-tooltip][data-placement="bottom"]:focus::before,[data-tooltip][data-placement="bottom"]:focus::after,[data-tooltip][data-placement="bottom"]:hover::before,[data-tooltip][data-placement="bottom"]:hover::after{animation-duration:.2s;animation-name:tooltip-slide-bottom}[data-tooltip][data-placement="bottom"]:focus::after,[data-tooltip][data-placement="bottom"]:hover::after{animation-name:tooltip-caret-slide-bottom}[data-tooltip][data-placement="left"]:focus::before,[data-tooltip][data-placement="left"]:focus::after,[data-tooltip][data-placement="left"]:hover::before,[data-tooltip][data-placement="left"]:hover::after{animation-duration:.2s;animation-name:tooltip-slide-left}[data-tooltip][data-placement="left"]:focus::after,[data-tooltip][data-placement="left"]:hover::after{animation-name:tooltip-caret-slide-left}[data-tooltip][data-placement="right"]:focus::before,[data-tooltip][data-placement="right"]:focus::after,[data-tooltip][data-placement="right"]:hover::before,[data-tooltip][data-placement="right"]:hover::after{animation-duration:.2s;animation-name:tooltip-slide-right}[data-tooltip][data-placement="right"]:focus::after,[data-tooltip][data-placement="right"]:hover::after{animation-name:tooltip-caret-slide-right}}@keyframes tooltip-slide-top{from{transform:translate(-50%, 0.75rem);opacity:0}to{transform:translate(-50%, -0.25rem);opacity:1}}@keyframes tooltip-caret-slide-top{from{opacity:0}50%{transform:translate(-50%, -0.25rem);opacity:0}to{transform:translate(-50%, 0rem);opacity:1}}@keyframes tooltip-slide-bottom{from{transform:translate(-50%, -0.75rem);opacity:0}to{transform:translate(-50%, 0.25rem);opacity:1}}@keyframes tooltip-caret-slide-bottom{from{opacity:0}50%{transform:translate(-50%, -0.5rem);opacity:0}to{transform:translate(-50%, -0.3rem);opacity:1}}@keyframes tooltip-slide-left{from{transform:translate(0.75rem, -50%);opacity:0}to{transform:translate(-0.25rem, -50%);opacity:1}}@keyframes tooltip-caret-slide-left{from{opacity:0}50%{transform:translate(0.05rem, -50%);opacity:0}to{transform:translate(0.3rem, -50%);opacity:1}}@keyframes tooltip-slide-right{from{transform:translate(-0.75rem, -50%);opacity:0}to{transform:translate(0.25rem, -50%);opacity:1}}@keyframes tooltip-caret-slide-right{from{opacity:0}50%{transform:translate(-0.05rem, -50%);opacity:0}to{transform:translate(-0.3rem, -50%);opacity:1}}[aria-controls]{cursor:pointer}[aria-disabled="true"],[disabled]{cursor:not-allowed}[aria-hidden="false"][hidden]{display:initial}[aria-hidden="false"][hidden]:not(:focus){clip:rect(0, 0, 0, 0);position:absolute}a,area,button,input,label,select,summary,textarea,[tabindex]{-ms-touch-action:manipulation}[dir="rtl"]{direction:rtl}@media (prefers-reduced-motion: reduce){*:not([aria-busy="true"]),:not([aria-busy="true"])::before,:not([aria-busy="true"])::after{background-attachment:initial !important;animation-duration:1ms !important;animation-delay:-1ms !important;animation-iteration-count:1 !important;scroll-behavior:auto !important;transition-delay:0s !important;transition-duration:0s !important}} diff --git a/AHC_app/uv.lock b/uv.lock similarity index 100% rename from AHC_app/uv.lock rename to uv.lock From 68be5d7a22e594ba52df622963b55f4aa4a1af7a Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Mon, 25 May 2026 00:38:12 +0200 Subject: [PATCH 15/27] refactor(docker): move Docker files to docker/ and update build contexts --- {AHC_app => docker}/.dockerignore | 0 {AHC_app => docker}/Dockerfile-couchdb | 2 +- {AHC_app => docker}/Dockerfile-queue | 0 {AHC_app => docker}/Dockerfile-web | 0 {AHC_app => docker}/docker-compose.yml | 26 +++++++++++++------------- {AHC_app => docker}/setup_couchdb.sh | 0 justfile | 4 ++-- 7 files changed, 16 insertions(+), 16 deletions(-) rename {AHC_app => docker}/.dockerignore (100%) rename {AHC_app => docker}/Dockerfile-couchdb (76%) rename {AHC_app => docker}/Dockerfile-queue (100%) rename {AHC_app => docker}/Dockerfile-web (100%) rename {AHC_app => docker}/docker-compose.yml (88%) rename {AHC_app => docker}/setup_couchdb.sh (100%) diff --git a/AHC_app/.dockerignore b/docker/.dockerignore similarity index 100% rename from AHC_app/.dockerignore rename to docker/.dockerignore diff --git a/AHC_app/Dockerfile-couchdb b/docker/Dockerfile-couchdb similarity index 76% rename from AHC_app/Dockerfile-couchdb rename to docker/Dockerfile-couchdb index 1e71bdb..bf03851 100644 --- a/AHC_app/Dockerfile-couchdb +++ b/docker/Dockerfile-couchdb @@ -5,6 +5,6 @@ ARG COUCHDB_PASSWORD ARG COUCHDB_PORT EXPOSE ${COUCHDB_PORT} -COPY setup_couchdb.sh setup_couchdb.sh +COPY docker/setup_couchdb.sh setup_couchdb.sh RUN chmod +x setup_couchdb.sh RUN sh setup_couchdb.sh diff --git a/AHC_app/Dockerfile-queue b/docker/Dockerfile-queue similarity index 100% rename from AHC_app/Dockerfile-queue rename to docker/Dockerfile-queue diff --git a/AHC_app/Dockerfile-web b/docker/Dockerfile-web similarity index 100% rename from AHC_app/Dockerfile-web rename to docker/Dockerfile-web diff --git a/AHC_app/docker-compose.yml b/docker/docker-compose.yml similarity index 88% rename from AHC_app/docker-compose.yml rename to docker/docker-compose.yml index d59a072..8c6b900 100644 --- a/AHC_app/docker-compose.yml +++ b/docker/docker-compose.yml @@ -2,13 +2,13 @@ version: "3.9" services: web: build: - context: . - dockerfile: Dockerfile-web + context: .. + dockerfile: docker/Dockerfile-web image: ahc_app-web:latest ports: - "8000:8000" volumes: - - .:/app + - ..:/app depends_on: postgres_db: condition: service_healthy @@ -18,7 +18,7 @@ services: condition: service_healthy environment: - PYTHONUNBUFFERED=1 - - PYTHONPATH=/app + - PYTHONPATH=/app/AHC_app entrypoint: ["/bin/bash", "-c"] command: - | @@ -47,8 +47,8 @@ services: couch_db: build: - context: . - dockerfile: Dockerfile-couchdb + context: .. + dockerfile: docker/Dockerfile-couchdb args: COUCHDB_USER: ${COUCHDB_USER} COUCHDB_PASSWORD: ${COUCHDB_PASSWORD} @@ -70,8 +70,8 @@ services: queue: build: - context: . - dockerfile: Dockerfile-queue + context: .. + dockerfile: docker/Dockerfile-queue command: celery -A AHC_app.celery_notifications.config:celery_obj worker -l info depends_on: redis: @@ -85,12 +85,12 @@ services: environment: - DJANGO_SETTINGS_MODULE=AHC_app.settings - PYTHONUNBUFFERED=1 - - PYTHONPATH=/app + - PYTHONPATH=/app/AHC_app celery_beat: build: - context: . - dockerfile: Dockerfile-queue + context: .. + dockerfile: docker/Dockerfile-queue command: celery -A AHC_app.celery_notifications.config:celery_obj beat -l info depends_on: redis: @@ -100,9 +100,9 @@ services: environment: - DJANGO_SETTINGS_MODULE=AHC_app.settings - PYTHONUNBUFFERED=1 - - PYTHONPATH=/app + - PYTHONPATH=/app/AHC_app env_file: - - .env + - ../.env redis: image: redis:7-alpine diff --git a/AHC_app/setup_couchdb.sh b/docker/setup_couchdb.sh similarity index 100% rename from AHC_app/setup_couchdb.sh rename to docker/setup_couchdb.sh diff --git a/justfile b/justfile index 5bb1bae..242ee8f 100644 --- a/justfile +++ b/justfile @@ -41,11 +41,11 @@ shell: # Start all Docker services docker-up: - docker-compose -f AHC_app/docker-compose.yml up -d --build + docker-compose -f docker/docker-compose.yml up -d --build # Stop all Docker services docker-down: - docker-compose -f AHC_app/docker-compose.yml down + docker-compose -f docker/docker-compose.yml down # Run pre-commit hooks on all files precommit: From a5dbae27cfbea19dc50821f270129ac58c2880e3 Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Mon, 25 May 2026 01:11:54 +0200 Subject: [PATCH 16/27] refactor(layout): move Django project package to src/ahc/ --- .github/workflows/django.yml | 2 +- docker/docker-compose.yml | 4 ++-- kubernetes/backend/web/secret.yaml.template | 2 +- kubernetes/queue/celery/configmap.yaml | 2 +- kubernetes/queue/celery/secret.yaml.template | 2 +- manage.py | 5 +++-- pyproject.toml | 4 ++-- {AHC_app/AHC_app => src}/__init__.py | 0 src/ahc/__init__.py | 0 src/ahc/apps/__init__.py | 0 {AHC_app/AHC_app => src/ahc}/asgi.py | 2 +- {AHC_app/AHC_app => src/ahc}/settings.py | 12 ++++++------ {AHC_app/AHC_app => src/ahc}/urls.py | 0 {AHC_app/AHC_app => src/ahc}/wsgi.py | 2 +- 14 files changed, 19 insertions(+), 18 deletions(-) rename {AHC_app/AHC_app => src}/__init__.py (100%) create mode 100644 src/ahc/__init__.py create mode 100644 src/ahc/apps/__init__.py rename {AHC_app/AHC_app => src/ahc}/asgi.py (82%) rename {AHC_app/AHC_app => src/ahc}/settings.py (96%) rename {AHC_app/AHC_app => src/ahc}/urls.py (100%) rename {AHC_app/AHC_app => src/ahc}/wsgi.py (82%) diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml index 0de0866..41680ad 100644 --- a/.github/workflows/django.yml +++ b/.github/workflows/django.yml @@ -50,7 +50,7 @@ jobs: run: uv sync - name: Run tests (Django runner) - run: PYTHONPATH=AHC_app uv run python manage.py test + run: PYTHONPATH=src:AHC_app uv run python manage.py test - name: Run tests (pytest) run: uv run pytest -m "not slow" diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 8c6b900..f158cd1 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -83,7 +83,7 @@ services: ports: - "5000:5000" environment: - - DJANGO_SETTINGS_MODULE=AHC_app.settings + - DJANGO_SETTINGS_MODULE=ahc.settings - PYTHONUNBUFFERED=1 - PYTHONPATH=/app/AHC_app @@ -98,7 +98,7 @@ services: postgres_db: condition: service_healthy environment: - - DJANGO_SETTINGS_MODULE=AHC_app.settings + - DJANGO_SETTINGS_MODULE=ahc.settings - PYTHONUNBUFFERED=1 - PYTHONPATH=/app/AHC_app env_file: diff --git a/kubernetes/backend/web/secret.yaml.template b/kubernetes/backend/web/secret.yaml.template index 879694f..9b64c58 100644 --- a/kubernetes/backend/web/secret.yaml.template +++ b/kubernetes/backend/web/secret.yaml.template @@ -22,7 +22,7 @@ stringData: COUCH_CONNECTOR: "Server(\"http://127.0.0.1:5982\")" CELERY_BACKEND: "redis://redis:6379/0" - DJANGO_SETTINGS_MODULE: "AHC_app" + DJANGO_SETTINGS_MODULE: "ahc.settings" EMAIL_BACKEND: "django.core.mail.backends.smtp.EmailBackend" EMAIL_HOST: "sandbox.smtp.mailtrap.io" diff --git a/kubernetes/queue/celery/configmap.yaml b/kubernetes/queue/celery/configmap.yaml index f5c5e73..4b28051 100644 --- a/kubernetes/queue/celery/configmap.yaml +++ b/kubernetes/queue/celery/configmap.yaml @@ -3,4 +3,4 @@ #metadata: # name: celery-config #data: -# DJANGO_SETTINGS_MODULE: AHC_app.settings +# DJANGO_SETTINGS_MODULE: ahc.settings diff --git a/kubernetes/queue/celery/secret.yaml.template b/kubernetes/queue/celery/secret.yaml.template index 3757913..6e95f60 100644 --- a/kubernetes/queue/celery/secret.yaml.template +++ b/kubernetes/queue/celery/secret.yaml.template @@ -22,7 +22,7 @@ stringData: COUCH_CONNECTOR: "Server(\"http://127.0.0.1:5982\")" CELERY_BACKEND: "redis://redis:6379/0" - DJANGO_SETTINGS_MODULE: "AHC_app" + DJANGO_SETTINGS_MODULE: "ahc.settings" EMAIL_BACKEND: "django.core.mail.backends.smtp.EmailBackend" EMAIL_HOST: "sandbox.smtp.mailtrap.io" diff --git a/manage.py b/manage.py index e51f677..cce3cfd 100644 --- a/manage.py +++ b/manage.py @@ -8,8 +8,9 @@ def main(): """Run administrative tasks.""" - sys.path.insert(0, str(Path(__file__).resolve().parent / "AHC_app")) - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "AHC_app.settings") + sys.path.insert(0, str(Path(__file__).resolve().parent / "src")) + sys.path.insert(1, str(Path(__file__).resolve().parent / "AHC_app")) + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ahc.settings") try: from django.core.management import execute_from_command_line except ImportError as exc: diff --git a/pyproject.toml b/pyproject.toml index 510afe5..12a478c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,8 +68,8 @@ quote-style = "double" indent-style = "space" [tool.pytest.ini_options] -DJANGO_SETTINGS_MODULE = "AHC_app.settings" -pythonpath = ["AHC_app"] +DJANGO_SETTINGS_MODULE = "ahc.settings" +pythonpath = ["src", "AHC_app"] python_files = ["test_*.py", "tests.py"] addopts = "--strict-markers" markers = [ diff --git a/AHC_app/AHC_app/__init__.py b/src/__init__.py similarity index 100% rename from AHC_app/AHC_app/__init__.py rename to src/__init__.py diff --git a/src/ahc/__init__.py b/src/ahc/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/ahc/apps/__init__.py b/src/ahc/apps/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/AHC_app/AHC_app/asgi.py b/src/ahc/asgi.py similarity index 82% rename from AHC_app/AHC_app/asgi.py rename to src/ahc/asgi.py index 5ce600a..edf19c7 100644 --- a/AHC_app/AHC_app/asgi.py +++ b/src/ahc/asgi.py @@ -11,6 +11,6 @@ from django.core.asgi import get_asgi_application -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "AHC_app.settings") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ahc.settings") application = get_asgi_application() diff --git a/AHC_app/AHC_app/settings.py b/src/ahc/settings.py similarity index 96% rename from AHC_app/AHC_app/settings.py rename to src/ahc/settings.py index 7ea92f3..0e97190 100644 --- a/AHC_app/AHC_app/settings.py +++ b/src/ahc/settings.py @@ -45,7 +45,7 @@ def _skip_external_services() -> bool: # Build paths inside the project like this: BASE_DIR / 'subdir'. -BASE_DIR = Path(__file__).resolve().parent.parent +BASE_DIR = Path(__file__).resolve().parents[2] # Quick-start development settings - unsuitable for production @@ -92,13 +92,13 @@ def _skip_external_services() -> bool: "django.middleware.clickjacking.XFrameOptionsMiddleware", ] -ROOT_URLCONF = "AHC_app.urls" +ROOT_URLCONF = "ahc.urls" TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", # 'DIRS': [], - "DIRS": [BASE_DIR / "templates"], + "DIRS": [BASE_DIR / "AHC_app" / "templates"], "APP_DIRS": True, "OPTIONS": { "context_processors": [ @@ -116,7 +116,7 @@ def _skip_external_services() -> bool: CRISPY_TEMPLATE_PACK = "bootstrap4" -WSGI_APPLICATION = "AHC_app.wsgi.application" +WSGI_APPLICATION = "ahc.wsgi.application" # Database @@ -194,7 +194,7 @@ def _skip_external_services() -> bool: STATIC_URL = "/static/" STATIC_ROOT = "static_collected" STATICFILES_DIRS = [ - os.path.join(BASE_DIR, "static/"), + os.path.join(BASE_DIR, "AHC_app/static/"), ] STATICFILES_FINDERS = [ @@ -232,7 +232,7 @@ def _skip_external_services() -> bool: """ MEDIA_URL = "/media/" -MEDIA_ROOT = os.path.join(BASE_DIR, "static/media") +MEDIA_ROOT = os.path.join(BASE_DIR, "AHC_app/static/media") # Default primary key field type # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field diff --git a/AHC_app/AHC_app/urls.py b/src/ahc/urls.py similarity index 100% rename from AHC_app/AHC_app/urls.py rename to src/ahc/urls.py diff --git a/AHC_app/AHC_app/wsgi.py b/src/ahc/wsgi.py similarity index 82% rename from AHC_app/AHC_app/wsgi.py rename to src/ahc/wsgi.py index 7375290..96b6880 100644 --- a/AHC_app/AHC_app/wsgi.py +++ b/src/ahc/wsgi.py @@ -11,6 +11,6 @@ from django.core.wsgi import get_wsgi_application -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "AHC_app.settings") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ahc.settings") application = get_wsgi_application() From 199006b63ec8d673e03ef28df4634d9d6609ec56 Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Fri, 29 May 2026 19:33:45 +0200 Subject: [PATCH 17/27] refactor(celery): move celery_notifications to src/celery_notifications/ Stage 4 of src-layout refactor. Extract celery_notifications from AHC_app/AHC_app/ to src/ so it lives alongside the ahc project package. - Fix all AHC_app.celery_notifications.* imports -> celery_notifications.* - Fix logger_config.json path to use __file__-relative resolution - Fix DJANGO_SETTINGS_MODULE typo and stale "django_with_celery" values - Switch autodiscover_tasks() to use INSTALLED_APPS (no argument) - Update docker-compose queue/celery_beat commands and PYTHONPATH - Update k8s celery/celery-beat commands and PYTHONPATH pyproject.toml pythonpath keeps ["src", "AHC_app"] until Stage 5; medical_notes (still in AHC_app/) is imported by cron.py. --- docker/docker-compose.yml | 10 +++++----- kubernetes/queue/celery-beat/deployment.yaml | 4 ++-- kubernetes/queue/celery/deployment.yaml | 4 ++-- .../AHC_app => src}/celery_notifications/__init__.py | 0 .../AHC_app => src}/celery_notifications/config.py | 12 ++++++------ .../AHC_app => src}/celery_notifications/cron.py | 8 ++++---- .../celery_notifications/logger_config.json | 0 .../celery_notifications/utils/__init__.py | 0 .../celery_notifications/utils/discord_utils.py | 0 .../celery_notifications/utils/example_task.py | 0 .../celery_notifications/utils/sending_utils.py | 0 11 files changed, 19 insertions(+), 19 deletions(-) rename {AHC_app/AHC_app => src}/celery_notifications/__init__.py (100%) rename {AHC_app/AHC_app => src}/celery_notifications/config.py (77%) rename {AHC_app/AHC_app => src}/celery_notifications/cron.py (95%) rename {AHC_app/AHC_app => src}/celery_notifications/logger_config.json (100%) rename {AHC_app/AHC_app => src}/celery_notifications/utils/__init__.py (100%) rename {AHC_app/AHC_app => src}/celery_notifications/utils/discord_utils.py (100%) rename {AHC_app/AHC_app => src}/celery_notifications/utils/example_task.py (100%) rename {AHC_app/AHC_app => src}/celery_notifications/utils/sending_utils.py (100%) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index f158cd1..b8aab76 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -18,7 +18,7 @@ services: condition: service_healthy environment: - PYTHONUNBUFFERED=1 - - PYTHONPATH=/app/AHC_app + - PYTHONPATH=/app/src:/app/AHC_app entrypoint: ["/bin/bash", "-c"] command: - | @@ -72,7 +72,7 @@ services: build: context: .. dockerfile: docker/Dockerfile-queue - command: celery -A AHC_app.celery_notifications.config:celery_obj worker -l info + command: celery -A celery_notifications.config:celery_obj worker -l info depends_on: redis: condition: service_healthy @@ -85,13 +85,13 @@ services: environment: - DJANGO_SETTINGS_MODULE=ahc.settings - PYTHONUNBUFFERED=1 - - PYTHONPATH=/app/AHC_app + - PYTHONPATH=/app/src:/app/AHC_app celery_beat: build: context: .. dockerfile: docker/Dockerfile-queue - command: celery -A AHC_app.celery_notifications.config:celery_obj beat -l info + command: celery -A celery_notifications.config:celery_obj beat -l info depends_on: redis: condition: service_healthy @@ -100,7 +100,7 @@ services: environment: - DJANGO_SETTINGS_MODULE=ahc.settings - PYTHONUNBUFFERED=1 - - PYTHONPATH=/app/AHC_app + - PYTHONPATH=/app/src:/app/AHC_app env_file: - ../.env diff --git a/kubernetes/queue/celery-beat/deployment.yaml b/kubernetes/queue/celery-beat/deployment.yaml index d7e4e6f..c4b655d 100644 --- a/kubernetes/queue/celery-beat/deployment.yaml +++ b/kubernetes/queue/celery-beat/deployment.yaml @@ -26,12 +26,12 @@ spec: - name: celery-beat image: ahc_app-queue:latest imagePullPolicy: Never - command: [ "celery", "-A", "AHC_app.celery_notifications.config:celery_obj", "beat", "-l", "info" ] + command: [ "celery", "-A", "celery_notifications.config:celery_obj", "beat", "-l", "info" ] env: - name: PYTHONUNBUFFERED value: "1" - name: PYTHONPATH - value: "/app" + value: "/app/src:/app/AHC_app" envFrom: - secretRef: name: web-secrets diff --git a/kubernetes/queue/celery/deployment.yaml b/kubernetes/queue/celery/deployment.yaml index ccfc7d9..fe4dc11 100644 --- a/kubernetes/queue/celery/deployment.yaml +++ b/kubernetes/queue/celery/deployment.yaml @@ -26,12 +26,12 @@ spec: - name: queue image: ahc_app-queue:latest imagePullPolicy: Never - command: [ "celery", "-A", "AHC_app.celery_notifications.config:celery_obj", "worker", "-l", "info"] + command: [ "celery", "-A", "celery_notifications.config:celery_obj", "worker", "-l", "info"] env: - name: PYTHONUNBUFFERED value: "1" - name: PYTHONPATH - value: "/app" + value: "/app/src:/app/AHC_app" envFrom: - secretRef: name: web-secrets diff --git a/AHC_app/AHC_app/celery_notifications/__init__.py b/src/celery_notifications/__init__.py similarity index 100% rename from AHC_app/AHC_app/celery_notifications/__init__.py rename to src/celery_notifications/__init__.py diff --git a/AHC_app/AHC_app/celery_notifications/config.py b/src/celery_notifications/config.py similarity index 77% rename from AHC_app/AHC_app/celery_notifications/config.py rename to src/celery_notifications/config.py index c474b79..6f4a3b1 100644 --- a/AHC_app/AHC_app/celery_notifications/config.py +++ b/src/celery_notifications/config.py @@ -5,23 +5,23 @@ from celery.utils.log import get_task_logger from django.conf import settings -# from AHC_app.celery_notifications.utils.discord_utils import send_via_discord -from AHC_app.celery_notifications.utils.sending_utils import send_via_email +# from celery_notifications.utils.discord_utils import send_via_discord +from celery_notifications.utils.sending_utils import send_via_email logger = get_task_logger(__name__) -os.environ.setdefault("DJANGO_SETTING_MODULE", "django_with_celery.settings") -celery_obj = Celery("django_with_celery") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ahc.settings") +celery_obj = Celery("ahc") celery_obj.config_from_object("django.conf:settings", namespace="CELERY") celery_obj.conf.broker_connection_retry_on_startup = True -celery_obj.autodiscover_tasks(["AHC_app"]) +celery_obj.autodiscover_tasks() @celery_obj.task(name="ahc.beat.dispatch_discord_notes") def dispatch_discord_notes(): - from AHC_app.celery_notifications.cron import send_discord_notes + from celery_notifications.cron import send_discord_notes send_discord_notes() diff --git a/AHC_app/AHC_app/celery_notifications/cron.py b/src/celery_notifications/cron.py similarity index 95% rename from AHC_app/AHC_app/celery_notifications/cron.py rename to src/celery_notifications/cron.py index 12d4009..a4aa3fe 100644 --- a/AHC_app/AHC_app/celery_notifications/cron.py +++ b/src/celery_notifications/cron.py @@ -9,19 +9,19 @@ from django.db.models import Q, QuerySet from django.tasks import task from django.utils import timezone +from medical_notes.models.type_feeding_notes import EmailNotification -from AHC_app.celery_notifications.config import ( +from celery_notifications.config import ( send_discord_notifications, send_email_notifications, ) -from AHC_app.celery_notifications.utils.example_task import send_mail_fnc -from medical_notes.models.type_feeding_notes import EmailNotification +from celery_notifications.utils.example_task import send_mail_fnc logger = logging.getLogger("crons_logger") def setup_logging(): - config_file = pathlib.Path("AHC_app/celery_notifications/logger_config.json") + config_file = pathlib.Path(__file__).parent / "logger_config.json" with open(config_file) as file: config = json.load(file) logging.config.dictConfig(config) diff --git a/AHC_app/AHC_app/celery_notifications/logger_config.json b/src/celery_notifications/logger_config.json similarity index 100% rename from AHC_app/AHC_app/celery_notifications/logger_config.json rename to src/celery_notifications/logger_config.json diff --git a/AHC_app/AHC_app/celery_notifications/utils/__init__.py b/src/celery_notifications/utils/__init__.py similarity index 100% rename from AHC_app/AHC_app/celery_notifications/utils/__init__.py rename to src/celery_notifications/utils/__init__.py diff --git a/AHC_app/AHC_app/celery_notifications/utils/discord_utils.py b/src/celery_notifications/utils/discord_utils.py similarity index 100% rename from AHC_app/AHC_app/celery_notifications/utils/discord_utils.py rename to src/celery_notifications/utils/discord_utils.py diff --git a/AHC_app/AHC_app/celery_notifications/utils/example_task.py b/src/celery_notifications/utils/example_task.py similarity index 100% rename from AHC_app/AHC_app/celery_notifications/utils/example_task.py rename to src/celery_notifications/utils/example_task.py diff --git a/AHC_app/AHC_app/celery_notifications/utils/sending_utils.py b/src/celery_notifications/utils/sending_utils.py similarity index 100% rename from AHC_app/AHC_app/celery_notifications/utils/sending_utils.py rename to src/celery_notifications/utils/sending_utils.py From 1d2267ca009eb03c3fe5596fd3c679e05e889c08 Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Fri, 29 May 2026 20:22:19 +0200 Subject: [PATCH 18/27] refactor(layout): move Django apps to src/ahc/apps/ --- .github/workflows/django.yml | 2 +- .pre-commit-config.yaml | 2 +- docker/docker-compose.yml | 6 +++--- justfile | 2 +- kubernetes/queue/celery-beat/deployment.yaml | 2 +- kubernetes/queue/celery/deployment.yaml | 2 +- manage.py | 1 - pyproject.toml | 4 ++-- {AHC_app => src/ahc/apps}/animals/__init__.py | 0 {AHC_app => src/ahc/apps}/animals/admin.py | 0 {AHC_app => src/ahc/apps}/animals/apps.py | 2 +- {AHC_app => src/ahc/apps}/animals/forms.py | 2 +- .../ahc/apps}/animals/migrations/0001_initial.py | 0 {AHC_app => src/ahc/apps}/animals/migrations/__init__.py | 0 {AHC_app => src/ahc/apps}/animals/mixins/__init__.py | 0 .../ahc/apps}/animals/mixins/animal_owner_permissions.py | 2 +- {AHC_app => src/ahc/apps}/animals/models.py | 2 +- {AHC_app => src/ahc/apps}/animals/signals.py | 4 ++-- .../animals/templates/animals/all_animals_stable.html | 0 .../animals/templates/animals/animal_confirm_delete.html | 0 .../apps}/animals/templates/animals/change_birthday.html | 0 .../animals/templates/animals/change_first_contact.html | 0 .../ahc/apps}/animals/templates/animals/change_owner.html | 0 .../ahc/apps}/animals/templates/animals/create.html | 0 .../ahc/apps}/animals/templates/animals/image.html | 0 .../apps}/animals/templates/animals/manage_keepers.html | 0 .../ahc/apps}/animals/templates/animals/profile.html | 0 .../ahc/apps}/animals/templatetags/__init__.py | 0 .../ahc/apps}/animals/templatetags/custom_timesince.py | 0 {AHC_app => src/ahc/apps}/animals/tests.py | 0 {AHC_app => src/ahc/apps}/animals/urls.py | 4 ++-- {AHC_app => src/ahc/apps}/animals/utils_owner/__init__.py | 0 {AHC_app => src/ahc/apps}/animals/utils_owner/forms.py | 4 ++-- {AHC_app => src/ahc/apps}/animals/utils_owner/views.py | 6 +++--- {AHC_app => src/ahc/apps}/animals/views.py | 6 +++--- {AHC_app => src/ahc/apps}/homepage/__init__.py | 0 {AHC_app => src/ahc/apps}/homepage/admin.py | 2 +- {AHC_app => src/ahc/apps}/homepage/apps.py | 2 +- {AHC_app => src/ahc/apps}/homepage/management/__init__.py | 0 .../ahc/apps}/homepage/management/commands/__init__.py | 0 .../ahc/apps}/homepage/migrations/0001_initial.py | 4 ++-- .../migrations/0002_alter_profilebackground_content.py | 4 ++-- .../ahc/apps}/homepage/migrations/0003_cronjob.py | 0 {AHC_app => src/ahc/apps}/homepage/migrations/__init__.py | 0 {AHC_app => src/ahc/apps}/homepage/models.py | 2 +- .../ahc/apps}/homepage/templates/homepage/base.html | 0 .../homepage/templates/homepage/change_list_results.html | 0 .../ahc/apps}/homepage/templates/homepage/homepage.html | 0 {AHC_app => src/ahc/apps}/homepage/tests/__init__.py | 0 .../ahc/apps}/homepage/tests/models/__init__.py | 0 .../ahc/apps}/homepage/tests/models/test_animal_title.py | 0 {AHC_app => src/ahc/apps}/homepage/tests/test_csp.py | 0 {AHC_app => src/ahc/apps}/homepage/tests/test_homepage.py | 2 +- {AHC_app => src/ahc/apps}/homepage/urls.py | 2 +- {AHC_app => src/ahc/apps}/homepage/utils.py | 0 {AHC_app => src/ahc/apps}/homepage/views.py | 4 ++-- {AHC_app => src/ahc/apps}/medical_notes/__init__.py | 0 {AHC_app => src/ahc/apps}/medical_notes/admin.py | 0 {AHC_app => src/ahc/apps}/medical_notes/apps.py | 2 +- {AHC_app => src/ahc/apps}/medical_notes/forms.py | 0 {AHC_app => src/ahc/apps}/medical_notes/forms/__init__.py | 0 .../ahc/apps}/medical_notes/forms/type_basic_note.py | 2 +- .../ahc/apps}/medical_notes/forms/type_feeding_notes.py | 2 +- .../apps}/medical_notes/forms/type_measurement_notes.py | 2 +- .../ahc/apps}/medical_notes/migrations/0001_initial.py | 0 ..._currentmedicine_animal_delete_currentdiet_and_more.py | 0 ...dingnote_smsnotification_emailnotification_and_more.py | 0 .../0004_alter_discordnotification_timezone_and_more.py | 0 .../migrations/0005_medicalrecordattachment.py | 0 .../0006_remove_medicalrecordattachment_description.py | 0 .../migrations/0007_medicalrecordattachment_url.py | 0 .../migrations/0008_alter_medicalrecordattachment_file.py | 0 ...0009_discordnotification_last_modification_and_more.py | 0 ...lter_discordnotification_last_modification_and_more.py | 0 .../0011_medicalrecordattachment_description.py | 0 .../0012_medicalrecordattachment_file_name_and_more.py | 0 .../0013_remove_medicalrecordattachment_url_and_more.py | 0 ...lter_discordnotification_last_modification_and_more.py | 0 .../ahc/apps}/medical_notes/migrations/__init__.py | 0 {AHC_app => src/ahc/apps}/medical_notes/models.py | 0 .../ahc/apps}/medical_notes/models/__init__.py | 0 .../ahc/apps}/medical_notes/models/type_basic_note.py | 4 ++-- .../ahc/apps}/medical_notes/models/type_feeding_notes.py | 2 +- .../apps}/medical_notes/models/type_measurement_notes.py | 4 ++-- {AHC_app => src/ahc/apps}/medical_notes/signals.py | 0 .../ahc/apps}/medical_notes/signals/__init__.py | 0 .../ahc/apps}/medical_notes/signals/type_feeding_notes.py | 4 ++-- .../apps}/medical_notes/signals/type_measurement_notes.py | 6 +++--- .../medical_notes/templates/medical_notes/create.html | 0 .../templates/medical_notes/create_notify.html | 0 .../templates/medical_notes/delete_confirm.html | 0 .../apps}/medical_notes/templates/medical_notes/edit.html | 0 .../templates/medical_notes/feeding_notes_list.html | 0 .../templates/medical_notes/full_timeline_of_notes.html | 0 .../templates/medical_notes/notification_list.html | 0 .../ahc/apps}/medical_notes/templatetags/__init__.py | 0 .../apps}/medical_notes/templatetags/custom_file_name.py | 2 +- .../medical_notes/templatetags/custom_to_class_name.py | 0 {AHC_app => src/ahc/apps}/medical_notes/tests.py | 0 {AHC_app => src/ahc/apps}/medical_notes/urls.py | 6 +++--- {AHC_app => src/ahc/apps}/medical_notes/views.py | 0 {AHC_app => src/ahc/apps}/medical_notes/views/__init__.py | 0 .../medical_notes/views/mixins/user_animal_permisions.py | 0 .../ahc/apps}/medical_notes/views/type_basic_note.py | 6 +++--- .../ahc/apps}/medical_notes/views/type_feeding_notes.py | 8 ++++---- .../apps}/medical_notes/views/type_measurement_notes.py | 8 ++++---- {AHC_app => src/ahc/apps}/users/__init__.py | 0 {AHC_app => src/ahc/apps}/users/admin.py | 2 +- {AHC_app => src/ahc/apps}/users/apps.py | 2 +- {AHC_app => src/ahc/apps}/users/forms.py | 2 +- .../ahc/apps}/users/migrations/0001_initial.py | 0 .../migrations/0002_profile_allow_recennt_animals_list.py | 0 .../apps}/users/migrations/0003_profile_pinned_animals.py | 0 {AHC_app => src/ahc/apps}/users/migrations/__init__.py | 0 {AHC_app => src/ahc/apps}/users/models.py | 2 +- {AHC_app => src/ahc/apps}/users/signals.py | 4 ++-- .../ahc/apps}/users/templates/users/login.html | 0 .../ahc/apps}/users/templates/users/login_success.html | 0 .../ahc/apps}/users/templates/users/logout.html | 0 .../ahc/apps}/users/templates/users/password_reset.html | 0 .../users/templates/users/password_reset_complete.html | 0 .../users/templates/users/password_reset_confirm.html | 0 .../apps}/users/templates/users/password_reset_done.html | 0 .../apps}/users/templates/users/password_reset_email.html | 0 .../ahc/apps}/users/templates/users/profile.html | 0 .../ahc/apps}/users/templates/users/register.html | 0 {AHC_app => src/ahc/apps}/users/tests.py | 0 {AHC_app => src/ahc/apps}/users/urls.py | 2 +- {AHC_app => src/ahc/apps}/users/views.py | 4 ++-- src/ahc/settings.py | 8 ++++---- src/ahc/urls.py | 8 ++++---- src/celery_notifications/cron.py | 2 +- 132 files changed, 84 insertions(+), 85 deletions(-) rename {AHC_app => src/ahc/apps}/animals/__init__.py (100%) rename {AHC_app => src/ahc/apps}/animals/admin.py (100%) rename {AHC_app => src/ahc/apps}/animals/apps.py (84%) rename {AHC_app => src/ahc/apps}/animals/forms.py (96%) rename {AHC_app => src/ahc/apps}/animals/migrations/0001_initial.py (100%) rename {AHC_app => src/ahc/apps}/animals/migrations/__init__.py (100%) rename {AHC_app => src/ahc/apps}/animals/mixins/__init__.py (100%) rename {AHC_app => src/ahc/apps}/animals/mixins/animal_owner_permissions.py (86%) rename {AHC_app => src/ahc/apps}/animals/models.py (95%) rename {AHC_app => src/ahc/apps}/animals/signals.py (95%) rename {AHC_app => src/ahc/apps}/animals/templates/animals/all_animals_stable.html (100%) rename {AHC_app => src/ahc/apps}/animals/templates/animals/animal_confirm_delete.html (100%) rename {AHC_app => src/ahc/apps}/animals/templates/animals/change_birthday.html (100%) rename {AHC_app => src/ahc/apps}/animals/templates/animals/change_first_contact.html (100%) rename {AHC_app => src/ahc/apps}/animals/templates/animals/change_owner.html (100%) rename {AHC_app => src/ahc/apps}/animals/templates/animals/create.html (100%) rename {AHC_app => src/ahc/apps}/animals/templates/animals/image.html (100%) rename {AHC_app => src/ahc/apps}/animals/templates/animals/manage_keepers.html (100%) rename {AHC_app => src/ahc/apps}/animals/templates/animals/profile.html (100%) rename {AHC_app => src/ahc/apps}/animals/templatetags/__init__.py (100%) rename {AHC_app => src/ahc/apps}/animals/templatetags/custom_timesince.py (100%) rename {AHC_app => src/ahc/apps}/animals/tests.py (100%) rename {AHC_app => src/ahc/apps}/animals/urls.py (89%) rename {AHC_app => src/ahc/apps}/animals/utils_owner/__init__.py (100%) rename {AHC_app => src/ahc/apps}/animals/utils_owner/forms.py (97%) rename {AHC_app => src/ahc/apps}/animals/utils_owner/views.py (96%) rename {AHC_app => src/ahc/apps}/animals/views.py (94%) rename {AHC_app => src/ahc/apps}/homepage/__init__.py (100%) rename {AHC_app => src/ahc/apps}/homepage/admin.py (92%) rename {AHC_app => src/ahc/apps}/homepage/apps.py (80%) rename {AHC_app => src/ahc/apps}/homepage/management/__init__.py (100%) rename {AHC_app => src/ahc/apps}/homepage/management/commands/__init__.py (100%) rename {AHC_app => src/ahc/apps}/homepage/migrations/0001_initial.py (95%) rename {AHC_app => src/ahc/apps}/homepage/migrations/0002_alter_profilebackground_content.py (79%) rename {AHC_app => src/ahc/apps}/homepage/migrations/0003_cronjob.py (100%) rename {AHC_app => src/ahc/apps}/homepage/migrations/__init__.py (100%) rename {AHC_app => src/ahc/apps}/homepage/models.py (97%) rename {AHC_app => src/ahc/apps}/homepage/templates/homepage/base.html (100%) rename {AHC_app => src/ahc/apps}/homepage/templates/homepage/change_list_results.html (100%) rename {AHC_app => src/ahc/apps}/homepage/templates/homepage/homepage.html (100%) rename {AHC_app => src/ahc/apps}/homepage/tests/__init__.py (100%) rename {AHC_app => src/ahc/apps}/homepage/tests/models/__init__.py (100%) rename {AHC_app => src/ahc/apps}/homepage/tests/models/test_animal_title.py (100%) rename {AHC_app => src/ahc/apps}/homepage/tests/test_csp.py (100%) rename {AHC_app => src/ahc/apps}/homepage/tests/test_homepage.py (97%) rename {AHC_app => src/ahc/apps}/homepage/urls.py (67%) rename {AHC_app => src/ahc/apps}/homepage/utils.py (100%) rename {AHC_app => src/ahc/apps}/homepage/views.py (90%) rename {AHC_app => src/ahc/apps}/medical_notes/__init__.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/admin.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/apps.py (82%) rename {AHC_app => src/ahc/apps}/medical_notes/forms.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/forms/__init__.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/forms/type_basic_note.py (98%) rename {AHC_app => src/ahc/apps}/medical_notes/forms/type_feeding_notes.py (96%) rename {AHC_app => src/ahc/apps}/medical_notes/forms/type_measurement_notes.py (91%) rename {AHC_app => src/ahc/apps}/medical_notes/migrations/0001_initial.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/migrations/0002_remove_currentmedicine_animal_delete_currentdiet_and_more.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/migrations/0003_feedingnote_smsnotification_emailnotification_and_more.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/migrations/0004_alter_discordnotification_timezone_and_more.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/migrations/0005_medicalrecordattachment.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/migrations/0006_remove_medicalrecordattachment_description.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/migrations/0007_medicalrecordattachment_url.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/migrations/0008_alter_medicalrecordattachment_file.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/migrations/0009_discordnotification_last_modification_and_more.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/migrations/0010_alter_discordnotification_last_modification_and_more.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/migrations/0011_medicalrecordattachment_description.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/migrations/0012_medicalrecordattachment_file_name_and_more.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/migrations/0013_remove_medicalrecordattachment_url_and_more.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/migrations/0014_alter_discordnotification_last_modification_and_more.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/migrations/__init__.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/models.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/models/__init__.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/models/type_basic_note.py (95%) rename {AHC_app => src/ahc/apps}/medical_notes/models/type_feeding_notes.py (97%) rename {AHC_app => src/ahc/apps}/medical_notes/models/type_measurement_notes.py (93%) rename {AHC_app => src/ahc/apps}/medical_notes/signals.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/signals/__init__.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/signals/type_feeding_notes.py (77%) rename {AHC_app => src/ahc/apps}/medical_notes/signals/type_measurement_notes.py (86%) rename {AHC_app => src/ahc/apps}/medical_notes/templates/medical_notes/create.html (100%) rename {AHC_app => src/ahc/apps}/medical_notes/templates/medical_notes/create_notify.html (100%) rename {AHC_app => src/ahc/apps}/medical_notes/templates/medical_notes/delete_confirm.html (100%) rename {AHC_app => src/ahc/apps}/medical_notes/templates/medical_notes/edit.html (100%) rename {AHC_app => src/ahc/apps}/medical_notes/templates/medical_notes/feeding_notes_list.html (100%) rename {AHC_app => src/ahc/apps}/medical_notes/templates/medical_notes/full_timeline_of_notes.html (100%) rename {AHC_app => src/ahc/apps}/medical_notes/templates/medical_notes/notification_list.html (100%) rename {AHC_app => src/ahc/apps}/medical_notes/templatetags/__init__.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/templatetags/custom_file_name.py (82%) rename {AHC_app => src/ahc/apps}/medical_notes/templatetags/custom_to_class_name.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/tests.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/urls.py (88%) rename {AHC_app => src/ahc/apps}/medical_notes/views.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/views/__init__.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/views/mixins/user_animal_permisions.py (100%) rename {AHC_app => src/ahc/apps}/medical_notes/views/type_basic_note.py (98%) rename {AHC_app => src/ahc/apps}/medical_notes/views/type_feeding_notes.py (96%) rename {AHC_app => src/ahc/apps}/medical_notes/views/type_measurement_notes.py (90%) rename {AHC_app => src/ahc/apps}/users/__init__.py (100%) rename {AHC_app => src/ahc/apps}/users/admin.py (60%) rename {AHC_app => src/ahc/apps}/users/apps.py (84%) rename {AHC_app => src/ahc/apps}/users/forms.py (92%) rename {AHC_app => src/ahc/apps}/users/migrations/0001_initial.py (100%) rename {AHC_app => src/ahc/apps}/users/migrations/0002_profile_allow_recennt_animals_list.py (100%) rename {AHC_app => src/ahc/apps}/users/migrations/0003_profile_pinned_animals.py (100%) rename {AHC_app => src/ahc/apps}/users/migrations/__init__.py (100%) rename {AHC_app => src/ahc/apps}/users/models.py (94%) rename {AHC_app => src/ahc/apps}/users/signals.py (90%) rename {AHC_app => src/ahc/apps}/users/templates/users/login.html (100%) rename {AHC_app => src/ahc/apps}/users/templates/users/login_success.html (100%) rename {AHC_app => src/ahc/apps}/users/templates/users/logout.html (100%) rename {AHC_app => src/ahc/apps}/users/templates/users/password_reset.html (100%) rename {AHC_app => src/ahc/apps}/users/templates/users/password_reset_complete.html (100%) rename {AHC_app => src/ahc/apps}/users/templates/users/password_reset_confirm.html (100%) rename {AHC_app => src/ahc/apps}/users/templates/users/password_reset_done.html (100%) rename {AHC_app => src/ahc/apps}/users/templates/users/password_reset_email.html (100%) rename {AHC_app => src/ahc/apps}/users/templates/users/profile.html (100%) rename {AHC_app => src/ahc/apps}/users/templates/users/register.html (100%) rename {AHC_app => src/ahc/apps}/users/tests.py (100%) rename {AHC_app => src/ahc/apps}/users/urls.py (97%) rename {AHC_app => src/ahc/apps}/users/views.py (90%) diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml index 41680ad..65986f7 100644 --- a/.github/workflows/django.yml +++ b/.github/workflows/django.yml @@ -50,7 +50,7 @@ jobs: run: uv sync - name: Run tests (Django runner) - run: PYTHONPATH=src:AHC_app uv run python manage.py test + run: PYTHONPATH=src uv run python manage.py test - name: Run tests (pytest) run: uv run pytest -m "not slow" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 65414c6..682aad7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -34,7 +34,7 @@ repos: hooks: - id: bandit name: bandit - entry: bandit -r AHC_app -c pyproject.toml + entry: bandit -r src -c pyproject.toml -q language: python additional_dependencies: ["bandit[toml]==1.9.4"] pass_filenames: false diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index b8aab76..380ed09 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -18,7 +18,7 @@ services: condition: service_healthy environment: - PYTHONUNBUFFERED=1 - - PYTHONPATH=/app/src:/app/AHC_app + - PYTHONPATH=/app/src entrypoint: ["/bin/bash", "-c"] command: - | @@ -85,7 +85,7 @@ services: environment: - DJANGO_SETTINGS_MODULE=ahc.settings - PYTHONUNBUFFERED=1 - - PYTHONPATH=/app/src:/app/AHC_app + - PYTHONPATH=/app/src celery_beat: build: @@ -100,7 +100,7 @@ services: environment: - DJANGO_SETTINGS_MODULE=ahc.settings - PYTHONUNBUFFERED=1 - - PYTHONPATH=/app/src:/app/AHC_app + - PYTHONPATH=/app/src env_file: - ../.env diff --git a/justfile b/justfile index 242ee8f..ccaa8dc 100644 --- a/justfile +++ b/justfile @@ -8,7 +8,7 @@ install: lint: uv run ruff check . uv run codespell - uv run bandit -r . -c pyproject.toml + uv run bandit -r . -c pyproject.toml -q # Format code and auto-fix lint issues format: diff --git a/kubernetes/queue/celery-beat/deployment.yaml b/kubernetes/queue/celery-beat/deployment.yaml index c4b655d..5952f2e 100644 --- a/kubernetes/queue/celery-beat/deployment.yaml +++ b/kubernetes/queue/celery-beat/deployment.yaml @@ -31,7 +31,7 @@ spec: - name: PYTHONUNBUFFERED value: "1" - name: PYTHONPATH - value: "/app/src:/app/AHC_app" + value: "/app/src" envFrom: - secretRef: name: web-secrets diff --git a/kubernetes/queue/celery/deployment.yaml b/kubernetes/queue/celery/deployment.yaml index fe4dc11..e89a7cc 100644 --- a/kubernetes/queue/celery/deployment.yaml +++ b/kubernetes/queue/celery/deployment.yaml @@ -31,7 +31,7 @@ spec: - name: PYTHONUNBUFFERED value: "1" - name: PYTHONPATH - value: "/app/src:/app/AHC_app" + value: "/app/src" envFrom: - secretRef: name: web-secrets diff --git a/manage.py b/manage.py index cce3cfd..fe42511 100644 --- a/manage.py +++ b/manage.py @@ -9,7 +9,6 @@ def main(): """Run administrative tasks.""" sys.path.insert(0, str(Path(__file__).resolve().parent / "src")) - sys.path.insert(1, str(Path(__file__).resolve().parent / "AHC_app")) os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ahc.settings") try: from django.core.management import execute_from_command_line diff --git a/pyproject.toml b/pyproject.toml index 12a478c..afd39e3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,7 +69,7 @@ indent-style = "space" [tool.pytest.ini_options] DJANGO_SETTINGS_MODULE = "ahc.settings" -pythonpath = ["src", "AHC_app"] +pythonpath = ["src"] python_files = ["test_*.py", "tests.py"] addopts = "--strict-markers" markers = [ @@ -82,7 +82,7 @@ markers = [ python-version = "3.14" [tool.codespell] -skip = "uv.lock,./static,./static_collected" +skip = "uv.lock,./AHC_app/static,./AHC_app/static_collected,./static,./static_collected" [tool.bandit] exclude_dirs = [".venv"] diff --git a/AHC_app/animals/__init__.py b/src/ahc/apps/animals/__init__.py similarity index 100% rename from AHC_app/animals/__init__.py rename to src/ahc/apps/animals/__init__.py diff --git a/AHC_app/animals/admin.py b/src/ahc/apps/animals/admin.py similarity index 100% rename from AHC_app/animals/admin.py rename to src/ahc/apps/animals/admin.py diff --git a/AHC_app/animals/apps.py b/src/ahc/apps/animals/apps.py similarity index 84% rename from AHC_app/animals/apps.py rename to src/ahc/apps/animals/apps.py index 47778cd..1023188 100644 --- a/AHC_app/animals/apps.py +++ b/src/ahc/apps/animals/apps.py @@ -3,7 +3,7 @@ class AnimalsConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" - name = "animals" + name = "ahc.apps.animals" def ready(self): pass diff --git a/AHC_app/animals/forms.py b/src/ahc/apps/animals/forms.py similarity index 96% rename from AHC_app/animals/forms.py rename to src/ahc/apps/animals/forms.py index 41503d0..ee9e217 100644 --- a/AHC_app/animals/forms.py +++ b/src/ahc/apps/animals/forms.py @@ -2,7 +2,7 @@ from django.core.validators import MaxLengthValidator, MinLengthValidator from django.db.models import Q -from animals.models import Animal +from ahc.apps.animals.models import Animal class AnimalRegisterForm(forms.ModelForm): diff --git a/AHC_app/animals/migrations/0001_initial.py b/src/ahc/apps/animals/migrations/0001_initial.py similarity index 100% rename from AHC_app/animals/migrations/0001_initial.py rename to src/ahc/apps/animals/migrations/0001_initial.py diff --git a/AHC_app/animals/migrations/__init__.py b/src/ahc/apps/animals/migrations/__init__.py similarity index 100% rename from AHC_app/animals/migrations/__init__.py rename to src/ahc/apps/animals/migrations/__init__.py diff --git a/AHC_app/animals/mixins/__init__.py b/src/ahc/apps/animals/mixins/__init__.py similarity index 100% rename from AHC_app/animals/mixins/__init__.py rename to src/ahc/apps/animals/mixins/__init__.py diff --git a/AHC_app/animals/mixins/animal_owner_permissions.py b/src/ahc/apps/animals/mixins/animal_owner_permissions.py similarity index 86% rename from AHC_app/animals/mixins/animal_owner_permissions.py rename to src/ahc/apps/animals/mixins/animal_owner_permissions.py index 4ebf125..e62efdb 100644 --- a/AHC_app/animals/mixins/animal_owner_permissions.py +++ b/src/ahc/apps/animals/mixins/animal_owner_permissions.py @@ -1,6 +1,6 @@ from django.contrib.auth.mixins import UserPassesTestMixin -from animals.models import Animal +from ahc.apps.animals.models import Animal class UserPassesOwnershipTestMixin(UserPassesTestMixin): diff --git a/AHC_app/animals/models.py b/src/ahc/apps/animals/models.py similarity index 95% rename from AHC_app/animals/models.py rename to src/ahc/apps/animals/models.py index 14cab2f..962f461 100644 --- a/AHC_app/animals/models.py +++ b/src/ahc/apps/animals/models.py @@ -2,7 +2,7 @@ from django.db import models -from users.models import Profile as UserProfile +from ahc.apps.users.models import Profile as UserProfile class Animal(models.Model): diff --git a/AHC_app/animals/signals.py b/src/ahc/apps/animals/signals.py similarity index 95% rename from AHC_app/animals/signals.py rename to src/ahc/apps/animals/signals.py index f0d6a88..daddc0f 100644 --- a/AHC_app/animals/signals.py +++ b/src/ahc/apps/animals/signals.py @@ -3,8 +3,8 @@ from django.db.models.signals import post_delete, post_save, pre_delete from django.dispatch import receiver -from animals.models import Animal -from users.models import Profile +from ahc.apps.animals.models import Animal +from ahc.apps.users.models import Profile @receiver(post_save, sender=Animal) diff --git a/AHC_app/animals/templates/animals/all_animals_stable.html b/src/ahc/apps/animals/templates/animals/all_animals_stable.html similarity index 100% rename from AHC_app/animals/templates/animals/all_animals_stable.html rename to src/ahc/apps/animals/templates/animals/all_animals_stable.html diff --git a/AHC_app/animals/templates/animals/animal_confirm_delete.html b/src/ahc/apps/animals/templates/animals/animal_confirm_delete.html similarity index 100% rename from AHC_app/animals/templates/animals/animal_confirm_delete.html rename to src/ahc/apps/animals/templates/animals/animal_confirm_delete.html diff --git a/AHC_app/animals/templates/animals/change_birthday.html b/src/ahc/apps/animals/templates/animals/change_birthday.html similarity index 100% rename from AHC_app/animals/templates/animals/change_birthday.html rename to src/ahc/apps/animals/templates/animals/change_birthday.html diff --git a/AHC_app/animals/templates/animals/change_first_contact.html b/src/ahc/apps/animals/templates/animals/change_first_contact.html similarity index 100% rename from AHC_app/animals/templates/animals/change_first_contact.html rename to src/ahc/apps/animals/templates/animals/change_first_contact.html diff --git a/AHC_app/animals/templates/animals/change_owner.html b/src/ahc/apps/animals/templates/animals/change_owner.html similarity index 100% rename from AHC_app/animals/templates/animals/change_owner.html rename to src/ahc/apps/animals/templates/animals/change_owner.html diff --git a/AHC_app/animals/templates/animals/create.html b/src/ahc/apps/animals/templates/animals/create.html similarity index 100% rename from AHC_app/animals/templates/animals/create.html rename to src/ahc/apps/animals/templates/animals/create.html diff --git a/AHC_app/animals/templates/animals/image.html b/src/ahc/apps/animals/templates/animals/image.html similarity index 100% rename from AHC_app/animals/templates/animals/image.html rename to src/ahc/apps/animals/templates/animals/image.html diff --git a/AHC_app/animals/templates/animals/manage_keepers.html b/src/ahc/apps/animals/templates/animals/manage_keepers.html similarity index 100% rename from AHC_app/animals/templates/animals/manage_keepers.html rename to src/ahc/apps/animals/templates/animals/manage_keepers.html diff --git a/AHC_app/animals/templates/animals/profile.html b/src/ahc/apps/animals/templates/animals/profile.html similarity index 100% rename from AHC_app/animals/templates/animals/profile.html rename to src/ahc/apps/animals/templates/animals/profile.html diff --git a/AHC_app/animals/templatetags/__init__.py b/src/ahc/apps/animals/templatetags/__init__.py similarity index 100% rename from AHC_app/animals/templatetags/__init__.py rename to src/ahc/apps/animals/templatetags/__init__.py diff --git a/AHC_app/animals/templatetags/custom_timesince.py b/src/ahc/apps/animals/templatetags/custom_timesince.py similarity index 100% rename from AHC_app/animals/templatetags/custom_timesince.py rename to src/ahc/apps/animals/templatetags/custom_timesince.py diff --git a/AHC_app/animals/tests.py b/src/ahc/apps/animals/tests.py similarity index 100% rename from AHC_app/animals/tests.py rename to src/ahc/apps/animals/tests.py diff --git a/AHC_app/animals/urls.py b/src/ahc/apps/animals/urls.py similarity index 89% rename from AHC_app/animals/urls.py rename to src/ahc/apps/animals/urls.py index 0ab0ade..f636055 100644 --- a/AHC_app/animals/urls.py +++ b/src/ahc/apps/animals/urls.py @@ -1,7 +1,7 @@ from django.urls import path -from animals import views as animal_views -from animals.utils_owner import views as animal_owner_views +from ahc.apps.animals import views as animal_views +from ahc.apps.animals.utils_owner import views as animal_owner_views urlpatterns = [ path("create/", animal_views.CreateAnimalView.as_view(), name="animal_create"), diff --git a/AHC_app/animals/utils_owner/__init__.py b/src/ahc/apps/animals/utils_owner/__init__.py similarity index 100% rename from AHC_app/animals/utils_owner/__init__.py rename to src/ahc/apps/animals/utils_owner/__init__.py diff --git a/AHC_app/animals/utils_owner/forms.py b/src/ahc/apps/animals/utils_owner/forms.py similarity index 97% rename from AHC_app/animals/utils_owner/forms.py rename to src/ahc/apps/animals/utils_owner/forms.py index 14fa925..fb7cf7f 100644 --- a/AHC_app/animals/utils_owner/forms.py +++ b/src/ahc/apps/animals/utils_owner/forms.py @@ -3,8 +3,8 @@ from django import forms from PIL import Image -from animals.models import Animal -from users.models import Profile +from ahc.apps.animals.models import Animal +from ahc.apps.users.models import Profile class ImageUploadForm(forms.ModelForm): diff --git a/AHC_app/animals/utils_owner/views.py b/src/ahc/apps/animals/utils_owner/views.py similarity index 96% rename from AHC_app/animals/utils_owner/views.py rename to src/ahc/apps/animals/utils_owner/views.py index 4e6f706..fe72dad 100644 --- a/AHC_app/animals/utils_owner/views.py +++ b/src/ahc/apps/animals/utils_owner/views.py @@ -5,9 +5,9 @@ from django.views.generic.edit import FormView from PIL import Image -from animals.mixins.animal_owner_permissions import UserPassesOwnershipTestMixin -from animals.models import Animal -from animals.utils_owner.forms import ( +from ahc.apps.animals.mixins.animal_owner_permissions import UserPassesOwnershipTestMixin +from ahc.apps.animals.models import Animal +from ahc.apps.animals.utils_owner.forms import ( ChangeBirthdayForm, ChangeFirstContactForm, ChangeOwnerForm, diff --git a/AHC_app/animals/views.py b/src/ahc/apps/animals/views.py similarity index 94% rename from AHC_app/animals/views.py rename to src/ahc/apps/animals/views.py index d4d362d..f3eed53 100644 --- a/AHC_app/animals/views.py +++ b/src/ahc/apps/animals/views.py @@ -7,9 +7,9 @@ from django.views.generic.detail import DetailView from django.views.generic.edit import FormView -from animals.forms import AnimalRegisterForm, PinAnimalForm -from animals.models import Animal -from medical_notes.models.type_basic_note import MedicalRecord +from ahc.apps.animals.forms import AnimalRegisterForm, PinAnimalForm +from ahc.apps.animals.models import Animal +from ahc.apps.medical_notes.models.type_basic_note import MedicalRecord # from users.models import Profile as UserProfile diff --git a/AHC_app/homepage/__init__.py b/src/ahc/apps/homepage/__init__.py similarity index 100% rename from AHC_app/homepage/__init__.py rename to src/ahc/apps/homepage/__init__.py diff --git a/AHC_app/homepage/admin.py b/src/ahc/apps/homepage/admin.py similarity index 92% rename from AHC_app/homepage/admin.py rename to src/ahc/apps/homepage/admin.py index bc300d6..1307303 100644 --- a/AHC_app/homepage/admin.py +++ b/src/ahc/apps/homepage/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from homepage.models import AnimalTitle, CronJob +from ahc.apps.homepage.models import AnimalTitle, CronJob admin.site.register(AnimalTitle) diff --git a/AHC_app/homepage/apps.py b/src/ahc/apps/homepage/apps.py similarity index 80% rename from AHC_app/homepage/apps.py rename to src/ahc/apps/homepage/apps.py index a4c9949..ef7e748 100644 --- a/AHC_app/homepage/apps.py +++ b/src/ahc/apps/homepage/apps.py @@ -3,4 +3,4 @@ class HomepageConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" - name = "homepage" + name = "ahc.apps.homepage" diff --git a/AHC_app/homepage/management/__init__.py b/src/ahc/apps/homepage/management/__init__.py similarity index 100% rename from AHC_app/homepage/management/__init__.py rename to src/ahc/apps/homepage/management/__init__.py diff --git a/AHC_app/homepage/management/commands/__init__.py b/src/ahc/apps/homepage/management/commands/__init__.py similarity index 100% rename from AHC_app/homepage/management/commands/__init__.py rename to src/ahc/apps/homepage/management/commands/__init__.py diff --git a/AHC_app/homepage/migrations/0001_initial.py b/src/ahc/apps/homepage/migrations/0001_initial.py similarity index 95% rename from AHC_app/homepage/migrations/0001_initial.py rename to src/ahc/apps/homepage/migrations/0001_initial.py index 4c846ca..47a51d2 100644 --- a/AHC_app/homepage/migrations/0001_initial.py +++ b/src/ahc/apps/homepage/migrations/0001_initial.py @@ -4,7 +4,7 @@ from django.conf import settings from django.db import migrations, models -import homepage.utils +import ahc.apps.homepage.utils class Migration(migrations.Migration): @@ -47,7 +47,7 @@ class Migration(migrations.Migration): ( "content", models.ImageField( - default=homepage.utils.ImageGenerator.default_profile_image, + default=ahc.apps.homepage.utils.ImageGenerator.default_profile_image, upload_to="static/media/background", ), ), diff --git a/AHC_app/homepage/migrations/0002_alter_profilebackground_content.py b/src/ahc/apps/homepage/migrations/0002_alter_profilebackground_content.py similarity index 79% rename from AHC_app/homepage/migrations/0002_alter_profilebackground_content.py rename to src/ahc/apps/homepage/migrations/0002_alter_profilebackground_content.py index 273b3bb..572cb3e 100644 --- a/AHC_app/homepage/migrations/0002_alter_profilebackground_content.py +++ b/src/ahc/apps/homepage/migrations/0002_alter_profilebackground_content.py @@ -2,7 +2,7 @@ from django.db import migrations, models -import homepage.utils +import ahc.apps.homepage.utils class Migration(migrations.Migration): @@ -15,7 +15,7 @@ class Migration(migrations.Migration): model_name="profilebackground", name="content", field=models.ImageField( - default=homepage.utils.ImageGenerator.default_profile_image, + default=ahc.apps.homepage.utils.ImageGenerator.default_profile_image, upload_to="static/media/background", ), ), diff --git a/AHC_app/homepage/migrations/0003_cronjob.py b/src/ahc/apps/homepage/migrations/0003_cronjob.py similarity index 100% rename from AHC_app/homepage/migrations/0003_cronjob.py rename to src/ahc/apps/homepage/migrations/0003_cronjob.py diff --git a/AHC_app/homepage/migrations/__init__.py b/src/ahc/apps/homepage/migrations/__init__.py similarity index 100% rename from AHC_app/homepage/migrations/__init__.py rename to src/ahc/apps/homepage/migrations/__init__.py diff --git a/AHC_app/homepage/models.py b/src/ahc/apps/homepage/models.py similarity index 97% rename from AHC_app/homepage/models.py rename to src/ahc/apps/homepage/models.py index 8091afb..43cc191 100644 --- a/AHC_app/homepage/models.py +++ b/src/ahc/apps/homepage/models.py @@ -2,7 +2,7 @@ from django.db import models from django.urls import reverse -from homepage.utils import ImageGenerator +from ahc.apps.homepage.utils import ImageGenerator class Privilege(models.Model): diff --git a/AHC_app/homepage/templates/homepage/base.html b/src/ahc/apps/homepage/templates/homepage/base.html similarity index 100% rename from AHC_app/homepage/templates/homepage/base.html rename to src/ahc/apps/homepage/templates/homepage/base.html diff --git a/AHC_app/homepage/templates/homepage/change_list_results.html b/src/ahc/apps/homepage/templates/homepage/change_list_results.html similarity index 100% rename from AHC_app/homepage/templates/homepage/change_list_results.html rename to src/ahc/apps/homepage/templates/homepage/change_list_results.html diff --git a/AHC_app/homepage/templates/homepage/homepage.html b/src/ahc/apps/homepage/templates/homepage/homepage.html similarity index 100% rename from AHC_app/homepage/templates/homepage/homepage.html rename to src/ahc/apps/homepage/templates/homepage/homepage.html diff --git a/AHC_app/homepage/tests/__init__.py b/src/ahc/apps/homepage/tests/__init__.py similarity index 100% rename from AHC_app/homepage/tests/__init__.py rename to src/ahc/apps/homepage/tests/__init__.py diff --git a/AHC_app/homepage/tests/models/__init__.py b/src/ahc/apps/homepage/tests/models/__init__.py similarity index 100% rename from AHC_app/homepage/tests/models/__init__.py rename to src/ahc/apps/homepage/tests/models/__init__.py diff --git a/AHC_app/homepage/tests/models/test_animal_title.py b/src/ahc/apps/homepage/tests/models/test_animal_title.py similarity index 100% rename from AHC_app/homepage/tests/models/test_animal_title.py rename to src/ahc/apps/homepage/tests/models/test_animal_title.py diff --git a/AHC_app/homepage/tests/test_csp.py b/src/ahc/apps/homepage/tests/test_csp.py similarity index 100% rename from AHC_app/homepage/tests/test_csp.py rename to src/ahc/apps/homepage/tests/test_csp.py diff --git a/AHC_app/homepage/tests/test_homepage.py b/src/ahc/apps/homepage/tests/test_homepage.py similarity index 97% rename from AHC_app/homepage/tests/test_homepage.py rename to src/ahc/apps/homepage/tests/test_homepage.py index ac3ac0b..97b9797 100644 --- a/AHC_app/homepage/tests/test_homepage.py +++ b/src/ahc/apps/homepage/tests/test_homepage.py @@ -4,7 +4,7 @@ from django.contrib.auth.models import User from django.test import Client, TestCase -from homepage.models import AnimalTitle +from ahc.apps.homepage.models import AnimalTitle client = Client() diff --git a/AHC_app/homepage/urls.py b/src/ahc/apps/homepage/urls.py similarity index 67% rename from AHC_app/homepage/urls.py rename to src/ahc/apps/homepage/urls.py index 30af557..1ce25d8 100644 --- a/AHC_app/homepage/urls.py +++ b/src/ahc/apps/homepage/urls.py @@ -1,6 +1,6 @@ from django.urls import path -from homepage.views import HomepageView +from ahc.apps.homepage.views import HomepageView urlpatterns = [ path("", HomepageView.as_view(), name="Homepage"), diff --git a/AHC_app/homepage/utils.py b/src/ahc/apps/homepage/utils.py similarity index 100% rename from AHC_app/homepage/utils.py rename to src/ahc/apps/homepage/utils.py diff --git a/AHC_app/homepage/views.py b/src/ahc/apps/homepage/views.py similarity index 90% rename from AHC_app/homepage/views.py rename to src/ahc/apps/homepage/views.py index 611875f..e100c62 100644 --- a/AHC_app/homepage/views.py +++ b/src/ahc/apps/homepage/views.py @@ -1,8 +1,8 @@ from django.db.models import Q from django.views.generic import TemplateView -from animals.models import Animal -from users.models import Profile as UserProfile +from ahc.apps.animals.models import Animal +from ahc.apps.users.models import Profile as UserProfile class HomepageView(TemplateView): diff --git a/AHC_app/medical_notes/__init__.py b/src/ahc/apps/medical_notes/__init__.py similarity index 100% rename from AHC_app/medical_notes/__init__.py rename to src/ahc/apps/medical_notes/__init__.py diff --git a/AHC_app/medical_notes/admin.py b/src/ahc/apps/medical_notes/admin.py similarity index 100% rename from AHC_app/medical_notes/admin.py rename to src/ahc/apps/medical_notes/admin.py diff --git a/AHC_app/medical_notes/apps.py b/src/ahc/apps/medical_notes/apps.py similarity index 82% rename from AHC_app/medical_notes/apps.py rename to src/ahc/apps/medical_notes/apps.py index 2fc8826..5d5a03a 100644 --- a/AHC_app/medical_notes/apps.py +++ b/src/ahc/apps/medical_notes/apps.py @@ -3,7 +3,7 @@ class MedicalNotesConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" - name = "medical_notes" + name = "ahc.apps.medical_notes" def ready(self): pass diff --git a/AHC_app/medical_notes/forms.py b/src/ahc/apps/medical_notes/forms.py similarity index 100% rename from AHC_app/medical_notes/forms.py rename to src/ahc/apps/medical_notes/forms.py diff --git a/AHC_app/medical_notes/forms/__init__.py b/src/ahc/apps/medical_notes/forms/__init__.py similarity index 100% rename from AHC_app/medical_notes/forms/__init__.py rename to src/ahc/apps/medical_notes/forms/__init__.py diff --git a/AHC_app/medical_notes/forms/type_basic_note.py b/src/ahc/apps/medical_notes/forms/type_basic_note.py similarity index 98% rename from AHC_app/medical_notes/forms/type_basic_note.py rename to src/ahc/apps/medical_notes/forms/type_basic_note.py index a03bc1b..766d818 100644 --- a/AHC_app/medical_notes/forms/type_basic_note.py +++ b/src/ahc/apps/medical_notes/forms/type_basic_note.py @@ -1,7 +1,7 @@ from django import forms # from animals.models import Animal as AnimalProfile -from medical_notes.models.type_basic_note import MedicalRecord, MedicalRecordAttachment +from ahc.apps.medical_notes.models.type_basic_note import MedicalRecord, MedicalRecordAttachment # from django.core.validators import MaxLengthValidator, MinLengthValidator # from django.db.models import Q diff --git a/AHC_app/medical_notes/forms/type_feeding_notes.py b/src/ahc/apps/medical_notes/forms/type_feeding_notes.py similarity index 96% rename from AHC_app/medical_notes/forms/type_feeding_notes.py rename to src/ahc/apps/medical_notes/forms/type_feeding_notes.py index 2ded162..31a8660 100644 --- a/AHC_app/medical_notes/forms/type_feeding_notes.py +++ b/src/ahc/apps/medical_notes/forms/type_feeding_notes.py @@ -2,7 +2,7 @@ from django.conf import settings from timezone_field import TimeZoneFormField -from medical_notes.models.type_feeding_notes import EmailNotification, FeedingNote +from ahc.apps.medical_notes.models.type_feeding_notes import EmailNotification, FeedingNote class DietRecordForm(forms.ModelForm): diff --git a/AHC_app/medical_notes/forms/type_measurement_notes.py b/src/ahc/apps/medical_notes/forms/type_measurement_notes.py similarity index 91% rename from AHC_app/medical_notes/forms/type_measurement_notes.py rename to src/ahc/apps/medical_notes/forms/type_measurement_notes.py index 7fa41f3..3923682 100644 --- a/AHC_app/medical_notes/forms/type_measurement_notes.py +++ b/src/ahc/apps/medical_notes/forms/type_measurement_notes.py @@ -1,6 +1,6 @@ from django import forms -from medical_notes.models.type_measurement_notes import BiometricHeightRecords, BiometricWeightRecords +from ahc.apps.medical_notes.models.type_measurement_notes import BiometricHeightRecords, BiometricWeightRecords class BiometricRecordForm(forms.Form): diff --git a/AHC_app/medical_notes/migrations/0001_initial.py b/src/ahc/apps/medical_notes/migrations/0001_initial.py similarity index 100% rename from AHC_app/medical_notes/migrations/0001_initial.py rename to src/ahc/apps/medical_notes/migrations/0001_initial.py diff --git a/AHC_app/medical_notes/migrations/0002_remove_currentmedicine_animal_delete_currentdiet_and_more.py b/src/ahc/apps/medical_notes/migrations/0002_remove_currentmedicine_animal_delete_currentdiet_and_more.py similarity index 100% rename from AHC_app/medical_notes/migrations/0002_remove_currentmedicine_animal_delete_currentdiet_and_more.py rename to src/ahc/apps/medical_notes/migrations/0002_remove_currentmedicine_animal_delete_currentdiet_and_more.py diff --git a/AHC_app/medical_notes/migrations/0003_feedingnote_smsnotification_emailnotification_and_more.py b/src/ahc/apps/medical_notes/migrations/0003_feedingnote_smsnotification_emailnotification_and_more.py similarity index 100% rename from AHC_app/medical_notes/migrations/0003_feedingnote_smsnotification_emailnotification_and_more.py rename to src/ahc/apps/medical_notes/migrations/0003_feedingnote_smsnotification_emailnotification_and_more.py diff --git a/AHC_app/medical_notes/migrations/0004_alter_discordnotification_timezone_and_more.py b/src/ahc/apps/medical_notes/migrations/0004_alter_discordnotification_timezone_and_more.py similarity index 100% rename from AHC_app/medical_notes/migrations/0004_alter_discordnotification_timezone_and_more.py rename to src/ahc/apps/medical_notes/migrations/0004_alter_discordnotification_timezone_and_more.py diff --git a/AHC_app/medical_notes/migrations/0005_medicalrecordattachment.py b/src/ahc/apps/medical_notes/migrations/0005_medicalrecordattachment.py similarity index 100% rename from AHC_app/medical_notes/migrations/0005_medicalrecordattachment.py rename to src/ahc/apps/medical_notes/migrations/0005_medicalrecordattachment.py diff --git a/AHC_app/medical_notes/migrations/0006_remove_medicalrecordattachment_description.py b/src/ahc/apps/medical_notes/migrations/0006_remove_medicalrecordattachment_description.py similarity index 100% rename from AHC_app/medical_notes/migrations/0006_remove_medicalrecordattachment_description.py rename to src/ahc/apps/medical_notes/migrations/0006_remove_medicalrecordattachment_description.py diff --git a/AHC_app/medical_notes/migrations/0007_medicalrecordattachment_url.py b/src/ahc/apps/medical_notes/migrations/0007_medicalrecordattachment_url.py similarity index 100% rename from AHC_app/medical_notes/migrations/0007_medicalrecordattachment_url.py rename to src/ahc/apps/medical_notes/migrations/0007_medicalrecordattachment_url.py diff --git a/AHC_app/medical_notes/migrations/0008_alter_medicalrecordattachment_file.py b/src/ahc/apps/medical_notes/migrations/0008_alter_medicalrecordattachment_file.py similarity index 100% rename from AHC_app/medical_notes/migrations/0008_alter_medicalrecordattachment_file.py rename to src/ahc/apps/medical_notes/migrations/0008_alter_medicalrecordattachment_file.py diff --git a/AHC_app/medical_notes/migrations/0009_discordnotification_last_modification_and_more.py b/src/ahc/apps/medical_notes/migrations/0009_discordnotification_last_modification_and_more.py similarity index 100% rename from AHC_app/medical_notes/migrations/0009_discordnotification_last_modification_and_more.py rename to src/ahc/apps/medical_notes/migrations/0009_discordnotification_last_modification_and_more.py diff --git a/AHC_app/medical_notes/migrations/0010_alter_discordnotification_last_modification_and_more.py b/src/ahc/apps/medical_notes/migrations/0010_alter_discordnotification_last_modification_and_more.py similarity index 100% rename from AHC_app/medical_notes/migrations/0010_alter_discordnotification_last_modification_and_more.py rename to src/ahc/apps/medical_notes/migrations/0010_alter_discordnotification_last_modification_and_more.py diff --git a/AHC_app/medical_notes/migrations/0011_medicalrecordattachment_description.py b/src/ahc/apps/medical_notes/migrations/0011_medicalrecordattachment_description.py similarity index 100% rename from AHC_app/medical_notes/migrations/0011_medicalrecordattachment_description.py rename to src/ahc/apps/medical_notes/migrations/0011_medicalrecordattachment_description.py diff --git a/AHC_app/medical_notes/migrations/0012_medicalrecordattachment_file_name_and_more.py b/src/ahc/apps/medical_notes/migrations/0012_medicalrecordattachment_file_name_and_more.py similarity index 100% rename from AHC_app/medical_notes/migrations/0012_medicalrecordattachment_file_name_and_more.py rename to src/ahc/apps/medical_notes/migrations/0012_medicalrecordattachment_file_name_and_more.py diff --git a/AHC_app/medical_notes/migrations/0013_remove_medicalrecordattachment_url_and_more.py b/src/ahc/apps/medical_notes/migrations/0013_remove_medicalrecordattachment_url_and_more.py similarity index 100% rename from AHC_app/medical_notes/migrations/0013_remove_medicalrecordattachment_url_and_more.py rename to src/ahc/apps/medical_notes/migrations/0013_remove_medicalrecordattachment_url_and_more.py diff --git a/AHC_app/medical_notes/migrations/0014_alter_discordnotification_last_modification_and_more.py b/src/ahc/apps/medical_notes/migrations/0014_alter_discordnotification_last_modification_and_more.py similarity index 100% rename from AHC_app/medical_notes/migrations/0014_alter_discordnotification_last_modification_and_more.py rename to src/ahc/apps/medical_notes/migrations/0014_alter_discordnotification_last_modification_and_more.py diff --git a/AHC_app/medical_notes/migrations/__init__.py b/src/ahc/apps/medical_notes/migrations/__init__.py similarity index 100% rename from AHC_app/medical_notes/migrations/__init__.py rename to src/ahc/apps/medical_notes/migrations/__init__.py diff --git a/AHC_app/medical_notes/models.py b/src/ahc/apps/medical_notes/models.py similarity index 100% rename from AHC_app/medical_notes/models.py rename to src/ahc/apps/medical_notes/models.py diff --git a/AHC_app/medical_notes/models/__init__.py b/src/ahc/apps/medical_notes/models/__init__.py similarity index 100% rename from AHC_app/medical_notes/models/__init__.py rename to src/ahc/apps/medical_notes/models/__init__.py diff --git a/AHC_app/medical_notes/models/type_basic_note.py b/src/ahc/apps/medical_notes/models/type_basic_note.py similarity index 95% rename from AHC_app/medical_notes/models/type_basic_note.py rename to src/ahc/apps/medical_notes/models/type_basic_note.py index 1edb49c..757be9e 100644 --- a/AHC_app/medical_notes/models/type_basic_note.py +++ b/src/ahc/apps/medical_notes/models/type_basic_note.py @@ -4,8 +4,8 @@ from taggit.managers import TaggableManager from taggit.models import GenericUUIDTaggedItemBase, TaggedItemBase -from animals.models import Animal -from users.models import Profile as UserProfile +from ahc.apps.animals.models import Animal +from ahc.apps.users.models import Profile as UserProfile class UUIDTaggedItem(GenericUUIDTaggedItemBase, TaggedItemBase): diff --git a/AHC_app/medical_notes/models/type_feeding_notes.py b/src/ahc/apps/medical_notes/models/type_feeding_notes.py similarity index 97% rename from AHC_app/medical_notes/models/type_feeding_notes.py rename to src/ahc/apps/medical_notes/models/type_feeding_notes.py index 87725b8..67a31c0 100644 --- a/AHC_app/medical_notes/models/type_feeding_notes.py +++ b/src/ahc/apps/medical_notes/models/type_feeding_notes.py @@ -5,7 +5,7 @@ from django.db import models from timezone_field import TimeZoneField -from medical_notes.models.type_basic_note import MedicalRecord +from ahc.apps.medical_notes.models.type_basic_note import MedicalRecord class FeedingNote(models.Model): diff --git a/AHC_app/medical_notes/models/type_measurement_notes.py b/src/ahc/apps/medical_notes/models/type_measurement_notes.py similarity index 93% rename from AHC_app/medical_notes/models/type_measurement_notes.py rename to src/ahc/apps/medical_notes/models/type_measurement_notes.py index 84eb0ec..d2a0925 100644 --- a/AHC_app/medical_notes/models/type_measurement_notes.py +++ b/src/ahc/apps/medical_notes/models/type_measurement_notes.py @@ -1,7 +1,7 @@ from django.db import models -from animals.models import Animal -from medical_notes.models.type_basic_note import MedicalRecord +from ahc.apps.animals.models import Animal +from ahc.apps.medical_notes.models.type_basic_note import MedicalRecord class BiometricHeightRecords(models.Model): diff --git a/AHC_app/medical_notes/signals.py b/src/ahc/apps/medical_notes/signals.py similarity index 100% rename from AHC_app/medical_notes/signals.py rename to src/ahc/apps/medical_notes/signals.py diff --git a/AHC_app/medical_notes/signals/__init__.py b/src/ahc/apps/medical_notes/signals/__init__.py similarity index 100% rename from AHC_app/medical_notes/signals/__init__.py rename to src/ahc/apps/medical_notes/signals/__init__.py diff --git a/AHC_app/medical_notes/signals/type_feeding_notes.py b/src/ahc/apps/medical_notes/signals/type_feeding_notes.py similarity index 77% rename from AHC_app/medical_notes/signals/type_feeding_notes.py rename to src/ahc/apps/medical_notes/signals/type_feeding_notes.py index 9fa7dc5..28dc8d5 100644 --- a/AHC_app/medical_notes/signals/type_feeding_notes.py +++ b/src/ahc/apps/medical_notes/signals/type_feeding_notes.py @@ -2,8 +2,8 @@ from django.db.models.signals import post_save from django.dispatch import receiver -from medical_notes.models.type_feeding_notes import FeedingNote -from users.models import Profile as UserProfile +from ahc.apps.medical_notes.models.type_feeding_notes import FeedingNote +from ahc.apps.users.models import Profile as UserProfile @receiver(post_save, sender=FeedingNote) diff --git a/AHC_app/medical_notes/signals/type_measurement_notes.py b/src/ahc/apps/medical_notes/signals/type_measurement_notes.py similarity index 86% rename from AHC_app/medical_notes/signals/type_measurement_notes.py rename to src/ahc/apps/medical_notes/signals/type_measurement_notes.py index 63783b1..38e3507 100644 --- a/AHC_app/medical_notes/signals/type_measurement_notes.py +++ b/src/ahc/apps/medical_notes/signals/type_measurement_notes.py @@ -3,9 +3,9 @@ from django.db.models.signals import post_save, pre_save from django.dispatch import receiver -from medical_notes.models.type_basic_note import MedicalRecord -from medical_notes.models.type_measurement_notes import BiometricRecord -from users.models import Profile as UserProfile +from ahc.apps.medical_notes.models.type_basic_note import MedicalRecord +from ahc.apps.medical_notes.models.type_measurement_notes import BiometricRecord +from ahc.apps.users.models import Profile as UserProfile @receiver(pre_save, sender=BiometricRecord) diff --git a/AHC_app/medical_notes/templates/medical_notes/create.html b/src/ahc/apps/medical_notes/templates/medical_notes/create.html similarity index 100% rename from AHC_app/medical_notes/templates/medical_notes/create.html rename to src/ahc/apps/medical_notes/templates/medical_notes/create.html diff --git a/AHC_app/medical_notes/templates/medical_notes/create_notify.html b/src/ahc/apps/medical_notes/templates/medical_notes/create_notify.html similarity index 100% rename from AHC_app/medical_notes/templates/medical_notes/create_notify.html rename to src/ahc/apps/medical_notes/templates/medical_notes/create_notify.html diff --git a/AHC_app/medical_notes/templates/medical_notes/delete_confirm.html b/src/ahc/apps/medical_notes/templates/medical_notes/delete_confirm.html similarity index 100% rename from AHC_app/medical_notes/templates/medical_notes/delete_confirm.html rename to src/ahc/apps/medical_notes/templates/medical_notes/delete_confirm.html diff --git a/AHC_app/medical_notes/templates/medical_notes/edit.html b/src/ahc/apps/medical_notes/templates/medical_notes/edit.html similarity index 100% rename from AHC_app/medical_notes/templates/medical_notes/edit.html rename to src/ahc/apps/medical_notes/templates/medical_notes/edit.html diff --git a/AHC_app/medical_notes/templates/medical_notes/feeding_notes_list.html b/src/ahc/apps/medical_notes/templates/medical_notes/feeding_notes_list.html similarity index 100% rename from AHC_app/medical_notes/templates/medical_notes/feeding_notes_list.html rename to src/ahc/apps/medical_notes/templates/medical_notes/feeding_notes_list.html diff --git a/AHC_app/medical_notes/templates/medical_notes/full_timeline_of_notes.html b/src/ahc/apps/medical_notes/templates/medical_notes/full_timeline_of_notes.html similarity index 100% rename from AHC_app/medical_notes/templates/medical_notes/full_timeline_of_notes.html rename to src/ahc/apps/medical_notes/templates/medical_notes/full_timeline_of_notes.html diff --git a/AHC_app/medical_notes/templates/medical_notes/notification_list.html b/src/ahc/apps/medical_notes/templates/medical_notes/notification_list.html similarity index 100% rename from AHC_app/medical_notes/templates/medical_notes/notification_list.html rename to src/ahc/apps/medical_notes/templates/medical_notes/notification_list.html diff --git a/AHC_app/medical_notes/templatetags/__init__.py b/src/ahc/apps/medical_notes/templatetags/__init__.py similarity index 100% rename from AHC_app/medical_notes/templatetags/__init__.py rename to src/ahc/apps/medical_notes/templatetags/__init__.py diff --git a/AHC_app/medical_notes/templatetags/custom_file_name.py b/src/ahc/apps/medical_notes/templatetags/custom_file_name.py similarity index 82% rename from AHC_app/medical_notes/templatetags/custom_file_name.py rename to src/ahc/apps/medical_notes/templatetags/custom_file_name.py index 9932126..79421c0 100644 --- a/AHC_app/medical_notes/templatetags/custom_file_name.py +++ b/src/ahc/apps/medical_notes/templatetags/custom_file_name.py @@ -1,6 +1,6 @@ from django import template -from medical_notes.models.type_feeding_notes import FeedingNotification +from ahc.apps.medical_notes.models.type_feeding_notes import FeedingNotification register = template.Library() diff --git a/AHC_app/medical_notes/templatetags/custom_to_class_name.py b/src/ahc/apps/medical_notes/templatetags/custom_to_class_name.py similarity index 100% rename from AHC_app/medical_notes/templatetags/custom_to_class_name.py rename to src/ahc/apps/medical_notes/templatetags/custom_to_class_name.py diff --git a/AHC_app/medical_notes/tests.py b/src/ahc/apps/medical_notes/tests.py similarity index 100% rename from AHC_app/medical_notes/tests.py rename to src/ahc/apps/medical_notes/tests.py diff --git a/AHC_app/medical_notes/urls.py b/src/ahc/apps/medical_notes/urls.py similarity index 88% rename from AHC_app/medical_notes/urls.py rename to src/ahc/apps/medical_notes/urls.py index e9fbfab..cf54c43 100644 --- a/AHC_app/medical_notes/urls.py +++ b/src/ahc/apps/medical_notes/urls.py @@ -1,8 +1,8 @@ from django.urls import path -from medical_notes.views import type_basic_note as notes_views -from medical_notes.views import type_feeding_notes as feeding_views -from medical_notes.views import type_measurement_notes as measurement_views +from ahc.apps.medical_notes.views import type_basic_note as notes_views +from ahc.apps.medical_notes.views import type_feeding_notes as feeding_views +from ahc.apps.medical_notes.views import type_measurement_notes as measurement_views urlpatterns = [ path("/create/", notes_views.CreateNoteFormView.as_view(), name="note_create"), diff --git a/AHC_app/medical_notes/views.py b/src/ahc/apps/medical_notes/views.py similarity index 100% rename from AHC_app/medical_notes/views.py rename to src/ahc/apps/medical_notes/views.py diff --git a/AHC_app/medical_notes/views/__init__.py b/src/ahc/apps/medical_notes/views/__init__.py similarity index 100% rename from AHC_app/medical_notes/views/__init__.py rename to src/ahc/apps/medical_notes/views/__init__.py diff --git a/AHC_app/medical_notes/views/mixins/user_animal_permisions.py b/src/ahc/apps/medical_notes/views/mixins/user_animal_permisions.py similarity index 100% rename from AHC_app/medical_notes/views/mixins/user_animal_permisions.py rename to src/ahc/apps/medical_notes/views/mixins/user_animal_permisions.py diff --git a/AHC_app/medical_notes/views/type_basic_note.py b/src/ahc/apps/medical_notes/views/type_basic_note.py similarity index 98% rename from AHC_app/medical_notes/views/type_basic_note.py rename to src/ahc/apps/medical_notes/views/type_basic_note.py index b7271ba..13110d8 100644 --- a/AHC_app/medical_notes/views/type_basic_note.py +++ b/src/ahc/apps/medical_notes/views/type_basic_note.py @@ -12,14 +12,14 @@ from django.views.generic.edit import DeleteView, FormView, UpdateView from django.views.generic.list import ListView -from animals.models import Animal as AnimalProfile -from medical_notes.forms.type_basic_note import ( +from ahc.apps.animals.models import Animal as AnimalProfile +from ahc.apps.medical_notes.forms.type_basic_note import ( MedicalRecordEditForm, MedicalRecordEditRelatedAnimalsForm, MedicalRecordForm, UploadAppendixForm, ) -from medical_notes.models.type_basic_note import MedicalRecord, MedicalRecordAttachment +from ahc.apps.medical_notes.models.type_basic_note import MedicalRecord, MedicalRecordAttachment # UploadAppendixFormSet = formset_factory(UploadAppendixForm, extra=0) diff --git a/AHC_app/medical_notes/views/type_feeding_notes.py b/src/ahc/apps/medical_notes/views/type_feeding_notes.py similarity index 96% rename from AHC_app/medical_notes/views/type_feeding_notes.py rename to src/ahc/apps/medical_notes/views/type_feeding_notes.py index 8c23a6b..13a4fc1 100644 --- a/AHC_app/medical_notes/views/type_feeding_notes.py +++ b/src/ahc/apps/medical_notes/views/type_feeding_notes.py @@ -6,13 +6,13 @@ from django.views.generic.edit import FormView, UpdateView from django.views.generic.list import ListView -from animals.models import Animal as AnimalProfile -from medical_notes.forms.type_feeding_notes import ( +from ahc.apps.animals.models import Animal as AnimalProfile +from ahc.apps.medical_notes.forms.type_feeding_notes import ( DietRecordForm, NotificationRecordForm, ) -from medical_notes.models.type_basic_note import MedicalRecord -from medical_notes.models.type_feeding_notes import EmailNotification, FeedingNote +from ahc.apps.medical_notes.models.type_basic_note import MedicalRecord +from ahc.apps.medical_notes.models.type_feeding_notes import EmailNotification, FeedingNote class DietRecordCreateView(LoginRequiredMixin, UserPassesTestMixin, FormView): diff --git a/AHC_app/medical_notes/views/type_measurement_notes.py b/src/ahc/apps/medical_notes/views/type_measurement_notes.py similarity index 90% rename from AHC_app/medical_notes/views/type_measurement_notes.py rename to src/ahc/apps/medical_notes/views/type_measurement_notes.py index 7d89125..0e48e33 100644 --- a/AHC_app/medical_notes/views/type_measurement_notes.py +++ b/src/ahc/apps/medical_notes/views/type_measurement_notes.py @@ -1,10 +1,10 @@ from django.shortcuts import get_object_or_404, redirect, reverse from django.views.generic.edit import FormView -from animals.models import Animal as AnimalProfile -from medical_notes.forms.type_measurement_notes import BiometricRecordForm -from medical_notes.models.type_basic_note import MedicalRecord -from medical_notes.models.type_measurement_notes import ( +from ahc.apps.animals.models import Animal as AnimalProfile +from ahc.apps.medical_notes.forms.type_measurement_notes import BiometricRecordForm +from ahc.apps.medical_notes.models.type_basic_note import MedicalRecord +from ahc.apps.medical_notes.models.type_measurement_notes import ( BiometricCustomRecords, BiometricHeightRecords, BiometricRecord, diff --git a/AHC_app/users/__init__.py b/src/ahc/apps/users/__init__.py similarity index 100% rename from AHC_app/users/__init__.py rename to src/ahc/apps/users/__init__.py diff --git a/AHC_app/users/admin.py b/src/ahc/apps/users/admin.py similarity index 60% rename from AHC_app/users/admin.py rename to src/ahc/apps/users/admin.py index 8886aeb..6074baa 100644 --- a/AHC_app/users/admin.py +++ b/src/ahc/apps/users/admin.py @@ -1,5 +1,5 @@ from django.contrib import admin -from users.models import Profile +from ahc.apps.users.models import Profile admin.site.register(Profile) diff --git a/AHC_app/users/apps.py b/src/ahc/apps/users/apps.py similarity index 84% rename from AHC_app/users/apps.py rename to src/ahc/apps/users/apps.py index d7ff0b2..ab86c76 100644 --- a/AHC_app/users/apps.py +++ b/src/ahc/apps/users/apps.py @@ -3,7 +3,7 @@ class UsersConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" - name = "users" + name = "ahc.apps.users" def ready(self): pass diff --git a/AHC_app/users/forms.py b/src/ahc/apps/users/forms.py similarity index 92% rename from AHC_app/users/forms.py rename to src/ahc/apps/users/forms.py index 9a4bd29..acc0b2f 100644 --- a/AHC_app/users/forms.py +++ b/src/ahc/apps/users/forms.py @@ -1,7 +1,7 @@ from django import forms from django.contrib.auth.forms import User, UserCreationForm -from users.models import Profile +from ahc.apps.users.models import Profile class UserRegisterForm(UserCreationForm): diff --git a/AHC_app/users/migrations/0001_initial.py b/src/ahc/apps/users/migrations/0001_initial.py similarity index 100% rename from AHC_app/users/migrations/0001_initial.py rename to src/ahc/apps/users/migrations/0001_initial.py diff --git a/AHC_app/users/migrations/0002_profile_allow_recennt_animals_list.py b/src/ahc/apps/users/migrations/0002_profile_allow_recennt_animals_list.py similarity index 100% rename from AHC_app/users/migrations/0002_profile_allow_recennt_animals_list.py rename to src/ahc/apps/users/migrations/0002_profile_allow_recennt_animals_list.py diff --git a/AHC_app/users/migrations/0003_profile_pinned_animals.py b/src/ahc/apps/users/migrations/0003_profile_pinned_animals.py similarity index 100% rename from AHC_app/users/migrations/0003_profile_pinned_animals.py rename to src/ahc/apps/users/migrations/0003_profile_pinned_animals.py diff --git a/AHC_app/users/migrations/__init__.py b/src/ahc/apps/users/migrations/__init__.py similarity index 100% rename from AHC_app/users/migrations/__init__.py rename to src/ahc/apps/users/migrations/__init__.py diff --git a/AHC_app/users/models.py b/src/ahc/apps/users/models.py similarity index 94% rename from AHC_app/users/models.py rename to src/ahc/apps/users/models.py index f64ad5a..badcf02 100644 --- a/AHC_app/users/models.py +++ b/src/ahc/apps/users/models.py @@ -2,7 +2,7 @@ from django.db import models from PIL import Image -from homepage.models import Privilege, ProfileBackground +from ahc.apps.homepage.models import Privilege, ProfileBackground class Profile(models.Model): diff --git a/AHC_app/users/signals.py b/src/ahc/apps/users/signals.py similarity index 90% rename from AHC_app/users/signals.py rename to src/ahc/apps/users/signals.py index 068927b..6a7f786 100644 --- a/AHC_app/users/signals.py +++ b/src/ahc/apps/users/signals.py @@ -2,8 +2,8 @@ from django.db.models.signals import post_save, pre_save from django.dispatch import receiver -from homepage.models import Privilege, ProfileBackground -from users.models import Profile +from ahc.apps.homepage.models import Privilege, ProfileBackground +from ahc.apps.users.models import Profile @receiver(pre_save, sender=Profile) diff --git a/AHC_app/users/templates/users/login.html b/src/ahc/apps/users/templates/users/login.html similarity index 100% rename from AHC_app/users/templates/users/login.html rename to src/ahc/apps/users/templates/users/login.html diff --git a/AHC_app/users/templates/users/login_success.html b/src/ahc/apps/users/templates/users/login_success.html similarity index 100% rename from AHC_app/users/templates/users/login_success.html rename to src/ahc/apps/users/templates/users/login_success.html diff --git a/AHC_app/users/templates/users/logout.html b/src/ahc/apps/users/templates/users/logout.html similarity index 100% rename from AHC_app/users/templates/users/logout.html rename to src/ahc/apps/users/templates/users/logout.html diff --git a/AHC_app/users/templates/users/password_reset.html b/src/ahc/apps/users/templates/users/password_reset.html similarity index 100% rename from AHC_app/users/templates/users/password_reset.html rename to src/ahc/apps/users/templates/users/password_reset.html diff --git a/AHC_app/users/templates/users/password_reset_complete.html b/src/ahc/apps/users/templates/users/password_reset_complete.html similarity index 100% rename from AHC_app/users/templates/users/password_reset_complete.html rename to src/ahc/apps/users/templates/users/password_reset_complete.html diff --git a/AHC_app/users/templates/users/password_reset_confirm.html b/src/ahc/apps/users/templates/users/password_reset_confirm.html similarity index 100% rename from AHC_app/users/templates/users/password_reset_confirm.html rename to src/ahc/apps/users/templates/users/password_reset_confirm.html diff --git a/AHC_app/users/templates/users/password_reset_done.html b/src/ahc/apps/users/templates/users/password_reset_done.html similarity index 100% rename from AHC_app/users/templates/users/password_reset_done.html rename to src/ahc/apps/users/templates/users/password_reset_done.html diff --git a/AHC_app/users/templates/users/password_reset_email.html b/src/ahc/apps/users/templates/users/password_reset_email.html similarity index 100% rename from AHC_app/users/templates/users/password_reset_email.html rename to src/ahc/apps/users/templates/users/password_reset_email.html diff --git a/AHC_app/users/templates/users/profile.html b/src/ahc/apps/users/templates/users/profile.html similarity index 100% rename from AHC_app/users/templates/users/profile.html rename to src/ahc/apps/users/templates/users/profile.html diff --git a/AHC_app/users/templates/users/register.html b/src/ahc/apps/users/templates/users/register.html similarity index 100% rename from AHC_app/users/templates/users/register.html rename to src/ahc/apps/users/templates/users/register.html diff --git a/AHC_app/users/tests.py b/src/ahc/apps/users/tests.py similarity index 100% rename from AHC_app/users/tests.py rename to src/ahc/apps/users/tests.py diff --git a/AHC_app/users/urls.py b/src/ahc/apps/users/urls.py similarity index 97% rename from AHC_app/users/urls.py rename to src/ahc/apps/users/urls.py index 056bd50..33b0792 100644 --- a/AHC_app/users/urls.py +++ b/src/ahc/apps/users/urls.py @@ -7,7 +7,7 @@ ) from django.urls import path -from users import views as user_views +from ahc.apps.users import views as user_views urlpatterns = [ path("", auth_views.LoginView.as_view(template_name="users/login.html"), name="login"), diff --git a/AHC_app/users/views.py b/src/ahc/apps/users/views.py similarity index 90% rename from AHC_app/users/views.py rename to src/ahc/apps/users/views.py index 538cbd9..bb7e5c1 100644 --- a/AHC_app/users/views.py +++ b/src/ahc/apps/users/views.py @@ -3,8 +3,8 @@ from django.urls import reverse_lazy from django.views.generic import CreateView, UpdateView -from users.forms import ProfileUpdateForm, UserRegisterForm, UserUpdateForm -from users.models import Profile +from ahc.apps.users.forms import ProfileUpdateForm, UserRegisterForm, UserUpdateForm +from ahc.apps.users.models import Profile class UserRegisterView(CreateView): diff --git a/src/ahc/settings.py b/src/ahc/settings.py index 0e97190..bf3b365 100644 --- a/src/ahc/settings.py +++ b/src/ahc/settings.py @@ -75,10 +75,10 @@ def _skip_external_services() -> bool: "bootstrap_modal_forms", "compressor", "taggit", - "homepage.apps.HomepageConfig", - "users.apps.UsersConfig", - "animals.apps.AnimalsConfig", - "medical_notes.apps.MedicalNotesConfig", + "ahc.apps.homepage.apps.HomepageConfig", + "ahc.apps.users.apps.UsersConfig", + "ahc.apps.animals.apps.AnimalsConfig", + "ahc.apps.medical_notes.apps.MedicalNotesConfig", ] MIDDLEWARE = [ diff --git a/src/ahc/urls.py b/src/ahc/urls.py index 1f92f89..cb0ff0d 100644 --- a/src/ahc/urls.py +++ b/src/ahc/urls.py @@ -23,10 +23,10 @@ urlpatterns = [ path("admin/", admin.site.urls), - path("", include("homepage.urls")), - path("user/", include("users.urls")), - path("pet/", include("animals.urls")), - path("note/", include("medical_notes.urls")), + path("", include("ahc.apps.homepage.urls")), + path("user/", include("ahc.apps.users.urls")), + path("pet/", include("ahc.apps.animals.urls")), + path("note/", include("ahc.apps.medical_notes.urls")), path( "favicon.ico", RedirectView.as_view(url=static("media/icons/chinchilla.png")), diff --git a/src/celery_notifications/cron.py b/src/celery_notifications/cron.py index a4aa3fe..de1a3c2 100644 --- a/src/celery_notifications/cron.py +++ b/src/celery_notifications/cron.py @@ -9,8 +9,8 @@ from django.db.models import Q, QuerySet from django.tasks import task from django.utils import timezone -from medical_notes.models.type_feeding_notes import EmailNotification +from ahc.apps.medical_notes.models.type_feeding_notes import EmailNotification from celery_notifications.config import ( send_discord_notifications, send_email_notifications, From 3f15c973fd16c93b80bbf851627b87ebecf6608a Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Sat, 30 May 2026 11:23:04 +0200 Subject: [PATCH 19/27] docs(layout): finalize src-layout refactor documentation --- .gitattributes | 4 ++-- .gitignore | 8 ++++---- .pre-commit-config.yaml | 2 +- README.md | 13 +++++-------- pyproject.toml | 2 +- src/ahc/settings.py | 7 +++---- {AHC_app/static => static}/AHC_app/base.css | 0 .../static => static}/css/expanding_sections.css | 0 .../css/hide_large_description.css | 0 .../css/pico-1.5.9/.github/CONTRIBUTING.md | 0 .../.github/ISSUE_TEMPLATE/bug_report.md | 0 .../pico-1.5.9/.github/ISSUE_TEMPLATE/config.yml | 0 .../css/pico-1.5.9/.github/examples.jpg | Bin .../css/pico-1.5.9/.github/logo.svg | 0 .../static => static}/css/pico-1.5.9/.gitignore | 0 .../static => static}/css/pico-1.5.9/LICENSE.md | 0 .../static => static}/css/pico-1.5.9/README.md | 0 .../static => static}/css/pico-1.5.9/composer.json | 0 .../css/pico-1.5.9/css/pico.classless.css | 0 .../css/pico-1.5.9/css/pico.classless.css.map | 0 .../css/pico-1.5.9/css/pico.classless.min.css | 0 .../css/pico-1.5.9/css/pico.classless.min.css.map | 0 .../static => static}/css/pico-1.5.9/css/pico.css | 0 .../css/pico-1.5.9/css/pico.css.map | 0 .../css/pico-1.5.9/css/pico.fluid.classless.css | 0 .../pico-1.5.9/css/pico.fluid.classless.css.map | 0 .../pico-1.5.9/css/pico.fluid.classless.min.css | 0 .../css/pico.fluid.classless.min.css.map | 0 .../css/pico-1.5.9/css/pico.min.css | 0 .../css/pico-1.5.9/css/pico.min.css.map | 0 .../css/pico-1.5.9/css/pico.slim.css | 0 .../css/pico-1.5.9/css/pico.slim.css.map | 0 .../css/pico-1.5.9/css/pico.slim.min.css | 0 .../css/pico-1.5.9/css/pico.slim.min.css.map | 0 .../css/pico-1.5.9/css/postcss.config.js | 0 .../css/pico-1.5.9/css/themes/default.css | 0 .../css/pico-1.5.9/css/themes/default.css.map | 0 .../css/pico-1.5.9/css/themes/default.min.css | 0 .../css/pico-1.5.9/css/themes/default.min.css.map | 0 .../css/pico-1.5.9/docs/accordions.html | 0 .../css/pico-1.5.9/docs/buttons.html | 0 .../css/pico-1.5.9/docs/cards.html | 0 .../css/pico-1.5.9/docs/classless.html | 0 .../css/pico-1.5.9/docs/containers.html | 0 .../css/pico-1.5.9/docs/css/pico.docs.css | 0 .../css/pico-1.5.9/docs/css/pico.docs.css.map | 0 .../css/pico-1.5.9/docs/css/pico.docs.min.css | 0 .../css/pico-1.5.9/docs/css/pico.docs.min.css.map | 0 .../css/pico-1.5.9/docs/customization.html | 0 .../css/pico-1.5.9/docs/dropdowns.html | 0 .../css/pico-1.5.9/docs/forms.html | 0 .../css/pico-1.5.9/docs/grid.html | 0 .../css/pico-1.5.9/docs/index.html | 0 .../css/pico-1.5.9/docs/js/commons.js | 0 .../css/pico-1.5.9/docs/js/commons.min.js | 0 .../css/pico-1.5.9/docs/js/customization.js | 0 .../css/pico-1.5.9/docs/js/customization.min.js | 0 .../css/pico-1.5.9/docs/js/grid.js | 0 .../css/pico-1.5.9/docs/js/grid.min.js | 0 .../css/pico-1.5.9/docs/js/modal.js | 0 .../css/pico-1.5.9/docs/js/modal.min.js | 0 .../css/pico-1.5.9/docs/js/src/color-picker.js | 0 .../docs/js/src/material-design-colors.js | 0 .../css/pico-1.5.9/docs/js/src/theme-switcher.js | 0 .../pico-1.5.9/docs/js/src/toggle-navigation.js | 0 .../css/pico-1.5.9/docs/loading.html | 0 .../css/pico-1.5.9/docs/modal.html | 0 .../css/pico-1.5.9/docs/navs.html | 0 .../css/pico-1.5.9/docs/progress.html | 0 .../static => static}/css/pico-1.5.9/docs/rtl.html | 0 .../css/pico-1.5.9/docs/scroller.html | 0 .../pico-1.5.9/docs/scss/components/_modal.scss | 0 .../css/pico-1.5.9/docs/scss/components/_nav.scss | 0 .../docs/scss/components/_theme-switcher.scss | 0 .../css/pico-1.5.9/docs/scss/content/_code.scss | 0 .../pico-1.5.9/docs/scss/content/_typography.scss | 0 .../css/pico-1.5.9/docs/scss/layout/_aside.scss | 0 .../css/pico-1.5.9/docs/scss/layout/_document.scss | 0 .../docs/scss/layout/_documentation.scss | 0 .../css/pico-1.5.9/docs/scss/layout/_main.scss | 0 .../css/pico-1.5.9/docs/scss/pico.docs.scss | 0 .../css/pico-1.5.9/docs/scss/themes/_docs.scss | 0 .../pico-1.5.9/docs/scss/themes/docs/_dark.scss | 0 .../pico-1.5.9/docs/scss/themes/docs/_icons.scss | 0 .../pico-1.5.9/docs/scss/themes/docs/_light.scss | 0 .../css/pico-1.5.9/docs/src/_footer.html | 0 .../css/pico-1.5.9/docs/src/_head.html | 0 .../css/pico-1.5.9/docs/src/_nav.html | 0 .../css/pico-1.5.9/docs/src/_sidebar.html | 0 .../css/pico-1.5.9/docs/src/accordions.html | 0 .../css/pico-1.5.9/docs/src/buttons.html | 0 .../css/pico-1.5.9/docs/src/cards.html | 0 .../css/pico-1.5.9/docs/src/classless.html | 0 .../css/pico-1.5.9/docs/src/containers.html | 0 .../css/pico-1.5.9/docs/src/customization.html | 0 .../css/pico-1.5.9/docs/src/dropdowns.html | 0 .../css/pico-1.5.9/docs/src/forms.html | 0 .../css/pico-1.5.9/docs/src/grid.html | 0 .../css/pico-1.5.9/docs/src/index.html | 0 .../css/pico-1.5.9/docs/src/loading.html | 0 .../css/pico-1.5.9/docs/src/modal.html | 0 .../css/pico-1.5.9/docs/src/navs.html | 0 .../css/pico-1.5.9/docs/src/progress.html | 0 .../css/pico-1.5.9/docs/src/rtl.html | 0 .../css/pico-1.5.9/docs/src/scroller.html | 0 .../css/pico-1.5.9/docs/src/tables.html | 0 .../css/pico-1.5.9/docs/src/themes.html | 0 .../css/pico-1.5.9/docs/src/tooltips.html | 0 .../css/pico-1.5.9/docs/src/typography.html | 0 .../css/pico-1.5.9/docs/src/we-love-classes.html | 0 .../css/pico-1.5.9/docs/tables.html | 0 .../css/pico-1.5.9/docs/themes.html | 0 .../css/pico-1.5.9/docs/tooltips.html | 0 .../css/pico-1.5.9/docs/typography.html | 0 .../css/pico-1.5.9/docs/we-love-classes.html | 0 .../css/pico-1.5.9/package-lock.json | 0 .../static => static}/css/pico-1.5.9/package.json | 0 .../css/pico-1.5.9/scss/_functions.scss | 0 .../css/pico-1.5.9/scss/_variables.scss | 0 .../css/pico-1.5.9/scss/components/_accordion.scss | 0 .../css/pico-1.5.9/scss/components/_card.scss | 0 .../css/pico-1.5.9/scss/components/_dropdown.scss | 0 .../css/pico-1.5.9/scss/components/_modal.scss | 0 .../css/pico-1.5.9/scss/components/_nav.scss | 0 .../css/pico-1.5.9/scss/components/_progress.scss | 0 .../css/pico-1.5.9/scss/content/_button.scss | 0 .../css/pico-1.5.9/scss/content/_code.scss | 0 .../css/pico-1.5.9/scss/content/_embedded.scss | 0 .../scss/content/_form-alt-input-types.scss | 0 .../scss/content/_form-checkbox-radio.scss | 0 .../css/pico-1.5.9/scss/content/_form.scss | 0 .../css/pico-1.5.9/scss/content/_miscs.scss | 0 .../css/pico-1.5.9/scss/content/_table.scss | 0 .../css/pico-1.5.9/scss/content/_typography.scss | 0 .../css/pico-1.5.9/scss/layout/_container.scss | 0 .../css/pico-1.5.9/scss/layout/_document.scss | 0 .../css/pico-1.5.9/scss/layout/_grid.scss | 0 .../css/pico-1.5.9/scss/layout/_scroller.scss | 0 .../css/pico-1.5.9/scss/layout/_section.scss | 0 .../css/pico-1.5.9/scss/layout/_sectioning.scss | 0 .../css/pico-1.5.9/scss/pico.classless.scss | 0 .../css/pico-1.5.9/scss/pico.fluid.classless.scss | 0 .../css/pico-1.5.9/scss/pico.scss | 0 .../css/pico-1.5.9/scss/pico.slim.scss | 0 .../css/pico-1.5.9/scss/postcss.config.js | 0 .../css/pico-1.5.9/scss/themes/default.scss | 0 .../pico-1.5.9/scss/themes/default/_colors.scss | 0 .../css/pico-1.5.9/scss/themes/default/_dark.scss | 0 .../css/pico-1.5.9/scss/themes/default/_light.scss | 0 .../pico-1.5.9/scss/themes/default/_styles.scss | 0 .../pico-1.5.9/scss/utilities/_accessibility.scss | 0 .../css/pico-1.5.9/scss/utilities/_loading.scss | 0 .../pico-1.5.9/scss/utilities/_reduce-motion.scss | 0 .../css/pico-1.5.9/scss/utilities/_tooltip.scss | 0 {AHC_app/static => static}/css/stable_grid.css | 0 {AHC_app/static => static}/css/timeline.css | 0 {AHC_app/static => static}/custom_pico.scss | 0 .../static => static}/js/expanding_sections.js | 0 .../js/hiding_note_fields_in_form.js | 0 .../js/hiding_note_fields_in_measurement_form.js | 0 {AHC_app/static => static}/js/pin_animal.js | 0 {AHC_app/static => static}/js/timeline.js | 0 .../media/background/background-1169534_1920.png | Bin .../static => static}/media/background/black.jpg | Bin .../media/background/default_title.jpg | Bin .../static => static}/media/background/lizard2.jpg | Bin .../static => static}/media/icons/chinchilla.png | Bin .../media/profile_pics/pet-care-icon.png | Bin .../media/profile_pics/pet-care.png | Bin .../media/profile_pics/signup.png | Bin .../media/profile_pics/signup2.png | Bin .../media/readme_examples/Animal profile.png | Bin .../media/readme_examples/Diet note details.png | Bin .../readme_examples/Full timeline of notes.png | Bin .../media/readme_examples/User registration.png | Bin .../partials/animal_card.html | 0 176 files changed, 16 insertions(+), 20 deletions(-) rename {AHC_app/static => static}/AHC_app/base.css (100%) rename {AHC_app/static => static}/css/expanding_sections.css (100%) rename {AHC_app/static => static}/css/hide_large_description.css (100%) rename {AHC_app/static => static}/css/pico-1.5.9/.github/CONTRIBUTING.md (100%) rename {AHC_app/static => static}/css/pico-1.5.9/.github/ISSUE_TEMPLATE/bug_report.md (100%) rename {AHC_app/static => static}/css/pico-1.5.9/.github/ISSUE_TEMPLATE/config.yml (100%) rename {AHC_app/static => static}/css/pico-1.5.9/.github/examples.jpg (100%) rename {AHC_app/static => static}/css/pico-1.5.9/.github/logo.svg (100%) rename {AHC_app/static => static}/css/pico-1.5.9/.gitignore (100%) rename {AHC_app/static => static}/css/pico-1.5.9/LICENSE.md (100%) rename {AHC_app/static => static}/css/pico-1.5.9/README.md (100%) rename {AHC_app/static => static}/css/pico-1.5.9/composer.json (100%) rename {AHC_app/static => static}/css/pico-1.5.9/css/pico.classless.css (100%) rename {AHC_app/static => static}/css/pico-1.5.9/css/pico.classless.css.map (100%) rename {AHC_app/static => static}/css/pico-1.5.9/css/pico.classless.min.css (100%) rename {AHC_app/static => static}/css/pico-1.5.9/css/pico.classless.min.css.map (100%) rename {AHC_app/static => static}/css/pico-1.5.9/css/pico.css (100%) rename {AHC_app/static => static}/css/pico-1.5.9/css/pico.css.map (100%) rename {AHC_app/static => static}/css/pico-1.5.9/css/pico.fluid.classless.css (100%) rename {AHC_app/static => static}/css/pico-1.5.9/css/pico.fluid.classless.css.map (100%) rename {AHC_app/static => static}/css/pico-1.5.9/css/pico.fluid.classless.min.css (100%) rename {AHC_app/static => static}/css/pico-1.5.9/css/pico.fluid.classless.min.css.map (100%) rename {AHC_app/static => static}/css/pico-1.5.9/css/pico.min.css (100%) rename {AHC_app/static => static}/css/pico-1.5.9/css/pico.min.css.map (100%) rename {AHC_app/static => static}/css/pico-1.5.9/css/pico.slim.css (100%) rename {AHC_app/static => static}/css/pico-1.5.9/css/pico.slim.css.map (100%) rename {AHC_app/static => static}/css/pico-1.5.9/css/pico.slim.min.css (100%) rename {AHC_app/static => static}/css/pico-1.5.9/css/pico.slim.min.css.map (100%) rename {AHC_app/static => static}/css/pico-1.5.9/css/postcss.config.js (100%) rename {AHC_app/static => static}/css/pico-1.5.9/css/themes/default.css (100%) rename {AHC_app/static => static}/css/pico-1.5.9/css/themes/default.css.map (100%) rename {AHC_app/static => static}/css/pico-1.5.9/css/themes/default.min.css (100%) rename {AHC_app/static => static}/css/pico-1.5.9/css/themes/default.min.css.map (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/accordions.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/buttons.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/cards.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/classless.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/containers.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/css/pico.docs.css (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/css/pico.docs.css.map (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/css/pico.docs.min.css (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/css/pico.docs.min.css.map (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/customization.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/dropdowns.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/forms.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/grid.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/index.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/js/commons.js (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/js/commons.min.js (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/js/customization.js (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/js/customization.min.js (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/js/grid.js (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/js/grid.min.js (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/js/modal.js (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/js/modal.min.js (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/js/src/color-picker.js (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/js/src/material-design-colors.js (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/js/src/theme-switcher.js (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/js/src/toggle-navigation.js (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/loading.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/modal.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/navs.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/progress.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/rtl.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/scroller.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/scss/components/_modal.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/scss/components/_nav.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/scss/components/_theme-switcher.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/scss/content/_code.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/scss/content/_typography.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/scss/layout/_aside.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/scss/layout/_document.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/scss/layout/_documentation.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/scss/layout/_main.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/scss/pico.docs.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/scss/themes/_docs.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/scss/themes/docs/_dark.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/scss/themes/docs/_icons.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/scss/themes/docs/_light.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/_footer.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/_head.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/_nav.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/_sidebar.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/accordions.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/buttons.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/cards.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/classless.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/containers.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/customization.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/dropdowns.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/forms.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/grid.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/index.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/loading.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/modal.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/navs.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/progress.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/rtl.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/scroller.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/tables.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/themes.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/tooltips.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/typography.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/src/we-love-classes.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/tables.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/themes.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/tooltips.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/typography.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/docs/we-love-classes.html (100%) rename {AHC_app/static => static}/css/pico-1.5.9/package-lock.json (100%) rename {AHC_app/static => static}/css/pico-1.5.9/package.json (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/_functions.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/_variables.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/components/_accordion.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/components/_card.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/components/_dropdown.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/components/_modal.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/components/_nav.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/components/_progress.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/content/_button.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/content/_code.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/content/_embedded.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/content/_form-alt-input-types.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/content/_form-checkbox-radio.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/content/_form.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/content/_miscs.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/content/_table.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/content/_typography.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/layout/_container.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/layout/_document.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/layout/_grid.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/layout/_scroller.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/layout/_section.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/layout/_sectioning.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/pico.classless.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/pico.fluid.classless.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/pico.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/pico.slim.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/postcss.config.js (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/themes/default.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/themes/default/_colors.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/themes/default/_dark.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/themes/default/_light.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/themes/default/_styles.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/utilities/_accessibility.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/utilities/_loading.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/utilities/_reduce-motion.scss (100%) rename {AHC_app/static => static}/css/pico-1.5.9/scss/utilities/_tooltip.scss (100%) rename {AHC_app/static => static}/css/stable_grid.css (100%) rename {AHC_app/static => static}/css/timeline.css (100%) rename {AHC_app/static => static}/custom_pico.scss (100%) rename {AHC_app/static => static}/js/expanding_sections.js (100%) rename {AHC_app/static => static}/js/hiding_note_fields_in_form.js (100%) rename {AHC_app/static => static}/js/hiding_note_fields_in_measurement_form.js (100%) rename {AHC_app/static => static}/js/pin_animal.js (100%) rename {AHC_app/static => static}/js/timeline.js (100%) rename {AHC_app/static => static}/media/background/background-1169534_1920.png (100%) rename {AHC_app/static => static}/media/background/black.jpg (100%) rename {AHC_app/static => static}/media/background/default_title.jpg (100%) rename {AHC_app/static => static}/media/background/lizard2.jpg (100%) rename {AHC_app/static => static}/media/icons/chinchilla.png (100%) rename {AHC_app/static => static}/media/profile_pics/pet-care-icon.png (100%) rename {AHC_app/static => static}/media/profile_pics/pet-care.png (100%) rename {AHC_app/static => static}/media/profile_pics/signup.png (100%) rename {AHC_app/static => static}/media/profile_pics/signup2.png (100%) rename {AHC_app/static => static}/media/readme_examples/Animal profile.png (100%) rename {AHC_app/static => static}/media/readme_examples/Diet note details.png (100%) rename {AHC_app/static => static}/media/readme_examples/Full timeline of notes.png (100%) rename {AHC_app/static => static}/media/readme_examples/User registration.png (100%) rename {AHC_app/templates => templates}/partials/animal_card.html (100%) diff --git a/.gitattributes b/.gitattributes index 287d346..6915582 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,5 +2,5 @@ * text=auto # Vendor static files — preserve LF line endings as published -AHC_app/static/**/* text eol=lf -AHC_app/static_collected/**/* text eol=lf +static/**/* text eol=lf +static_collected/**/* text eol=lf diff --git a/.gitignore b/.gitignore index 60345ef..afebe7a 100644 --- a/.gitignore +++ b/.gitignore @@ -50,12 +50,12 @@ CLAUDE.md .idea/ # Project-specific -/AHC_app/static_collected/ -/AHC_app/static/media/profile_pics/animals/ -/AHC_app/static/media/attachments/ +/static_collected/ +/static/media/profile_pics/animals/ +/static/media/attachments/ # Kubernetes -/AHC_app/tars/ +/tars/ /kubernetes/**/*.tar secret.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 682aad7..4cfcfde 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,4 +1,4 @@ -exclude: 'AHC_app/static/|AHC_app/static_collected/' +exclude: 'static/|static_collected/' repos: - repo: local diff --git a/README.md b/README.md index 68d1c1e..8bc0102 100644 --- a/README.md +++ b/README.md @@ -22,12 +22,12 @@
- - + + - - + +

Animal profile

Full timeline of notes

Animal profile

Full timeline of notes

Diet note details

User registration

Diet note details

User registration

@@ -50,7 +50,7 @@ - Docker & Docker Compose - PostgreSQL 15 (instance for volumes) - Apache CouchDB 3.3.3 (instance for volumes) -- [Packages](AHC_app/pyproject.toml) +- [Packages](pyproject.toml) - [pico-1.5.10](https://github.com/picocss/pico/archive/refs/tags/v1.5.10.zip) --- @@ -71,7 +71,6 @@ 4. Install uv and sync dependencies: ``` pip install uv - cd AHC_app uv sync ``` 5. Install pre-commit hooks: @@ -85,7 +84,6 @@ With `just` installed, steps 4–6 simplify to: ``` -cd AHC_app just install just precommit just docker-up @@ -137,7 +135,6 @@ just docker-up ### Test running: ```bash # pytest (recommended) -cd AHC_app uv run pytest -m integration # or with just diff --git a/pyproject.toml b/pyproject.toml index afd39e3..f2bdd19 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -82,7 +82,7 @@ markers = [ python-version = "3.14" [tool.codespell] -skip = "uv.lock,./AHC_app/static,./AHC_app/static_collected,./static,./static_collected" +skip = "uv.lock,./static,./static_collected" [tool.bandit] exclude_dirs = [".venv"] diff --git a/src/ahc/settings.py b/src/ahc/settings.py index bf3b365..077c99b 100644 --- a/src/ahc/settings.py +++ b/src/ahc/settings.py @@ -10,7 +10,6 @@ https://docs.djangoproject.com/en/4.2/ref/settings/ """ -import os import sys from pathlib import Path @@ -98,7 +97,7 @@ def _skip_external_services() -> bool: { "BACKEND": "django.template.backends.django.DjangoTemplates", # 'DIRS': [], - "DIRS": [BASE_DIR / "AHC_app" / "templates"], + "DIRS": [BASE_DIR / "templates"], "APP_DIRS": True, "OPTIONS": { "context_processors": [ @@ -194,7 +193,7 @@ def _skip_external_services() -> bool: STATIC_URL = "/static/" STATIC_ROOT = "static_collected" STATICFILES_DIRS = [ - os.path.join(BASE_DIR, "AHC_app/static/"), + BASE_DIR / "static", ] STATICFILES_FINDERS = [ @@ -232,7 +231,7 @@ def _skip_external_services() -> bool: """ MEDIA_URL = "/media/" -MEDIA_ROOT = os.path.join(BASE_DIR, "AHC_app/static/media") +MEDIA_ROOT = BASE_DIR / "static" / "media" # Default primary key field type # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field diff --git a/AHC_app/static/AHC_app/base.css b/static/AHC_app/base.css similarity index 100% rename from AHC_app/static/AHC_app/base.css rename to static/AHC_app/base.css diff --git a/AHC_app/static/css/expanding_sections.css b/static/css/expanding_sections.css similarity index 100% rename from AHC_app/static/css/expanding_sections.css rename to static/css/expanding_sections.css diff --git a/AHC_app/static/css/hide_large_description.css b/static/css/hide_large_description.css similarity index 100% rename from AHC_app/static/css/hide_large_description.css rename to static/css/hide_large_description.css diff --git a/AHC_app/static/css/pico-1.5.9/.github/CONTRIBUTING.md b/static/css/pico-1.5.9/.github/CONTRIBUTING.md similarity index 100% rename from AHC_app/static/css/pico-1.5.9/.github/CONTRIBUTING.md rename to static/css/pico-1.5.9/.github/CONTRIBUTING.md diff --git a/AHC_app/static/css/pico-1.5.9/.github/ISSUE_TEMPLATE/bug_report.md b/static/css/pico-1.5.9/.github/ISSUE_TEMPLATE/bug_report.md similarity index 100% rename from AHC_app/static/css/pico-1.5.9/.github/ISSUE_TEMPLATE/bug_report.md rename to static/css/pico-1.5.9/.github/ISSUE_TEMPLATE/bug_report.md diff --git a/AHC_app/static/css/pico-1.5.9/.github/ISSUE_TEMPLATE/config.yml b/static/css/pico-1.5.9/.github/ISSUE_TEMPLATE/config.yml similarity index 100% rename from AHC_app/static/css/pico-1.5.9/.github/ISSUE_TEMPLATE/config.yml rename to static/css/pico-1.5.9/.github/ISSUE_TEMPLATE/config.yml diff --git a/AHC_app/static/css/pico-1.5.9/.github/examples.jpg b/static/css/pico-1.5.9/.github/examples.jpg similarity index 100% rename from AHC_app/static/css/pico-1.5.9/.github/examples.jpg rename to static/css/pico-1.5.9/.github/examples.jpg diff --git a/AHC_app/static/css/pico-1.5.9/.github/logo.svg b/static/css/pico-1.5.9/.github/logo.svg similarity index 100% rename from AHC_app/static/css/pico-1.5.9/.github/logo.svg rename to static/css/pico-1.5.9/.github/logo.svg diff --git a/AHC_app/static/css/pico-1.5.9/.gitignore b/static/css/pico-1.5.9/.gitignore similarity index 100% rename from AHC_app/static/css/pico-1.5.9/.gitignore rename to static/css/pico-1.5.9/.gitignore diff --git a/AHC_app/static/css/pico-1.5.9/LICENSE.md b/static/css/pico-1.5.9/LICENSE.md similarity index 100% rename from AHC_app/static/css/pico-1.5.9/LICENSE.md rename to static/css/pico-1.5.9/LICENSE.md diff --git a/AHC_app/static/css/pico-1.5.9/README.md b/static/css/pico-1.5.9/README.md similarity index 100% rename from AHC_app/static/css/pico-1.5.9/README.md rename to static/css/pico-1.5.9/README.md diff --git a/AHC_app/static/css/pico-1.5.9/composer.json b/static/css/pico-1.5.9/composer.json similarity index 100% rename from AHC_app/static/css/pico-1.5.9/composer.json rename to static/css/pico-1.5.9/composer.json diff --git a/AHC_app/static/css/pico-1.5.9/css/pico.classless.css b/static/css/pico-1.5.9/css/pico.classless.css similarity index 100% rename from AHC_app/static/css/pico-1.5.9/css/pico.classless.css rename to static/css/pico-1.5.9/css/pico.classless.css diff --git a/AHC_app/static/css/pico-1.5.9/css/pico.classless.css.map b/static/css/pico-1.5.9/css/pico.classless.css.map similarity index 100% rename from AHC_app/static/css/pico-1.5.9/css/pico.classless.css.map rename to static/css/pico-1.5.9/css/pico.classless.css.map diff --git a/AHC_app/static/css/pico-1.5.9/css/pico.classless.min.css b/static/css/pico-1.5.9/css/pico.classless.min.css similarity index 100% rename from AHC_app/static/css/pico-1.5.9/css/pico.classless.min.css rename to static/css/pico-1.5.9/css/pico.classless.min.css diff --git a/AHC_app/static/css/pico-1.5.9/css/pico.classless.min.css.map b/static/css/pico-1.5.9/css/pico.classless.min.css.map similarity index 100% rename from AHC_app/static/css/pico-1.5.9/css/pico.classless.min.css.map rename to static/css/pico-1.5.9/css/pico.classless.min.css.map diff --git a/AHC_app/static/css/pico-1.5.9/css/pico.css b/static/css/pico-1.5.9/css/pico.css similarity index 100% rename from AHC_app/static/css/pico-1.5.9/css/pico.css rename to static/css/pico-1.5.9/css/pico.css diff --git a/AHC_app/static/css/pico-1.5.9/css/pico.css.map b/static/css/pico-1.5.9/css/pico.css.map similarity index 100% rename from AHC_app/static/css/pico-1.5.9/css/pico.css.map rename to static/css/pico-1.5.9/css/pico.css.map diff --git a/AHC_app/static/css/pico-1.5.9/css/pico.fluid.classless.css b/static/css/pico-1.5.9/css/pico.fluid.classless.css similarity index 100% rename from AHC_app/static/css/pico-1.5.9/css/pico.fluid.classless.css rename to static/css/pico-1.5.9/css/pico.fluid.classless.css diff --git a/AHC_app/static/css/pico-1.5.9/css/pico.fluid.classless.css.map b/static/css/pico-1.5.9/css/pico.fluid.classless.css.map similarity index 100% rename from AHC_app/static/css/pico-1.5.9/css/pico.fluid.classless.css.map rename to static/css/pico-1.5.9/css/pico.fluid.classless.css.map diff --git a/AHC_app/static/css/pico-1.5.9/css/pico.fluid.classless.min.css b/static/css/pico-1.5.9/css/pico.fluid.classless.min.css similarity index 100% rename from AHC_app/static/css/pico-1.5.9/css/pico.fluid.classless.min.css rename to static/css/pico-1.5.9/css/pico.fluid.classless.min.css diff --git a/AHC_app/static/css/pico-1.5.9/css/pico.fluid.classless.min.css.map b/static/css/pico-1.5.9/css/pico.fluid.classless.min.css.map similarity index 100% rename from AHC_app/static/css/pico-1.5.9/css/pico.fluid.classless.min.css.map rename to static/css/pico-1.5.9/css/pico.fluid.classless.min.css.map diff --git a/AHC_app/static/css/pico-1.5.9/css/pico.min.css b/static/css/pico-1.5.9/css/pico.min.css similarity index 100% rename from AHC_app/static/css/pico-1.5.9/css/pico.min.css rename to static/css/pico-1.5.9/css/pico.min.css diff --git a/AHC_app/static/css/pico-1.5.9/css/pico.min.css.map b/static/css/pico-1.5.9/css/pico.min.css.map similarity index 100% rename from AHC_app/static/css/pico-1.5.9/css/pico.min.css.map rename to static/css/pico-1.5.9/css/pico.min.css.map diff --git a/AHC_app/static/css/pico-1.5.9/css/pico.slim.css b/static/css/pico-1.5.9/css/pico.slim.css similarity index 100% rename from AHC_app/static/css/pico-1.5.9/css/pico.slim.css rename to static/css/pico-1.5.9/css/pico.slim.css diff --git a/AHC_app/static/css/pico-1.5.9/css/pico.slim.css.map b/static/css/pico-1.5.9/css/pico.slim.css.map similarity index 100% rename from AHC_app/static/css/pico-1.5.9/css/pico.slim.css.map rename to static/css/pico-1.5.9/css/pico.slim.css.map diff --git a/AHC_app/static/css/pico-1.5.9/css/pico.slim.min.css b/static/css/pico-1.5.9/css/pico.slim.min.css similarity index 100% rename from AHC_app/static/css/pico-1.5.9/css/pico.slim.min.css rename to static/css/pico-1.5.9/css/pico.slim.min.css diff --git a/AHC_app/static/css/pico-1.5.9/css/pico.slim.min.css.map b/static/css/pico-1.5.9/css/pico.slim.min.css.map similarity index 100% rename from AHC_app/static/css/pico-1.5.9/css/pico.slim.min.css.map rename to static/css/pico-1.5.9/css/pico.slim.min.css.map diff --git a/AHC_app/static/css/pico-1.5.9/css/postcss.config.js b/static/css/pico-1.5.9/css/postcss.config.js similarity index 100% rename from AHC_app/static/css/pico-1.5.9/css/postcss.config.js rename to static/css/pico-1.5.9/css/postcss.config.js diff --git a/AHC_app/static/css/pico-1.5.9/css/themes/default.css b/static/css/pico-1.5.9/css/themes/default.css similarity index 100% rename from AHC_app/static/css/pico-1.5.9/css/themes/default.css rename to static/css/pico-1.5.9/css/themes/default.css diff --git a/AHC_app/static/css/pico-1.5.9/css/themes/default.css.map b/static/css/pico-1.5.9/css/themes/default.css.map similarity index 100% rename from AHC_app/static/css/pico-1.5.9/css/themes/default.css.map rename to static/css/pico-1.5.9/css/themes/default.css.map diff --git a/AHC_app/static/css/pico-1.5.9/css/themes/default.min.css b/static/css/pico-1.5.9/css/themes/default.min.css similarity index 100% rename from AHC_app/static/css/pico-1.5.9/css/themes/default.min.css rename to static/css/pico-1.5.9/css/themes/default.min.css diff --git a/AHC_app/static/css/pico-1.5.9/css/themes/default.min.css.map b/static/css/pico-1.5.9/css/themes/default.min.css.map similarity index 100% rename from AHC_app/static/css/pico-1.5.9/css/themes/default.min.css.map rename to static/css/pico-1.5.9/css/themes/default.min.css.map diff --git a/AHC_app/static/css/pico-1.5.9/docs/accordions.html b/static/css/pico-1.5.9/docs/accordions.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/accordions.html rename to static/css/pico-1.5.9/docs/accordions.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/buttons.html b/static/css/pico-1.5.9/docs/buttons.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/buttons.html rename to static/css/pico-1.5.9/docs/buttons.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/cards.html b/static/css/pico-1.5.9/docs/cards.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/cards.html rename to static/css/pico-1.5.9/docs/cards.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/classless.html b/static/css/pico-1.5.9/docs/classless.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/classless.html rename to static/css/pico-1.5.9/docs/classless.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/containers.html b/static/css/pico-1.5.9/docs/containers.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/containers.html rename to static/css/pico-1.5.9/docs/containers.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/css/pico.docs.css b/static/css/pico-1.5.9/docs/css/pico.docs.css similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/css/pico.docs.css rename to static/css/pico-1.5.9/docs/css/pico.docs.css diff --git a/AHC_app/static/css/pico-1.5.9/docs/css/pico.docs.css.map b/static/css/pico-1.5.9/docs/css/pico.docs.css.map similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/css/pico.docs.css.map rename to static/css/pico-1.5.9/docs/css/pico.docs.css.map diff --git a/AHC_app/static/css/pico-1.5.9/docs/css/pico.docs.min.css b/static/css/pico-1.5.9/docs/css/pico.docs.min.css similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/css/pico.docs.min.css rename to static/css/pico-1.5.9/docs/css/pico.docs.min.css diff --git a/AHC_app/static/css/pico-1.5.9/docs/css/pico.docs.min.css.map b/static/css/pico-1.5.9/docs/css/pico.docs.min.css.map similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/css/pico.docs.min.css.map rename to static/css/pico-1.5.9/docs/css/pico.docs.min.css.map diff --git a/AHC_app/static/css/pico-1.5.9/docs/customization.html b/static/css/pico-1.5.9/docs/customization.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/customization.html rename to static/css/pico-1.5.9/docs/customization.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/dropdowns.html b/static/css/pico-1.5.9/docs/dropdowns.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/dropdowns.html rename to static/css/pico-1.5.9/docs/dropdowns.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/forms.html b/static/css/pico-1.5.9/docs/forms.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/forms.html rename to static/css/pico-1.5.9/docs/forms.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/grid.html b/static/css/pico-1.5.9/docs/grid.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/grid.html rename to static/css/pico-1.5.9/docs/grid.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/index.html b/static/css/pico-1.5.9/docs/index.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/index.html rename to static/css/pico-1.5.9/docs/index.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/js/commons.js b/static/css/pico-1.5.9/docs/js/commons.js similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/js/commons.js rename to static/css/pico-1.5.9/docs/js/commons.js diff --git a/AHC_app/static/css/pico-1.5.9/docs/js/commons.min.js b/static/css/pico-1.5.9/docs/js/commons.min.js similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/js/commons.min.js rename to static/css/pico-1.5.9/docs/js/commons.min.js diff --git a/AHC_app/static/css/pico-1.5.9/docs/js/customization.js b/static/css/pico-1.5.9/docs/js/customization.js similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/js/customization.js rename to static/css/pico-1.5.9/docs/js/customization.js diff --git a/AHC_app/static/css/pico-1.5.9/docs/js/customization.min.js b/static/css/pico-1.5.9/docs/js/customization.min.js similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/js/customization.min.js rename to static/css/pico-1.5.9/docs/js/customization.min.js diff --git a/AHC_app/static/css/pico-1.5.9/docs/js/grid.js b/static/css/pico-1.5.9/docs/js/grid.js similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/js/grid.js rename to static/css/pico-1.5.9/docs/js/grid.js diff --git a/AHC_app/static/css/pico-1.5.9/docs/js/grid.min.js b/static/css/pico-1.5.9/docs/js/grid.min.js similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/js/grid.min.js rename to static/css/pico-1.5.9/docs/js/grid.min.js diff --git a/AHC_app/static/css/pico-1.5.9/docs/js/modal.js b/static/css/pico-1.5.9/docs/js/modal.js similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/js/modal.js rename to static/css/pico-1.5.9/docs/js/modal.js diff --git a/AHC_app/static/css/pico-1.5.9/docs/js/modal.min.js b/static/css/pico-1.5.9/docs/js/modal.min.js similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/js/modal.min.js rename to static/css/pico-1.5.9/docs/js/modal.min.js diff --git a/AHC_app/static/css/pico-1.5.9/docs/js/src/color-picker.js b/static/css/pico-1.5.9/docs/js/src/color-picker.js similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/js/src/color-picker.js rename to static/css/pico-1.5.9/docs/js/src/color-picker.js diff --git a/AHC_app/static/css/pico-1.5.9/docs/js/src/material-design-colors.js b/static/css/pico-1.5.9/docs/js/src/material-design-colors.js similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/js/src/material-design-colors.js rename to static/css/pico-1.5.9/docs/js/src/material-design-colors.js diff --git a/AHC_app/static/css/pico-1.5.9/docs/js/src/theme-switcher.js b/static/css/pico-1.5.9/docs/js/src/theme-switcher.js similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/js/src/theme-switcher.js rename to static/css/pico-1.5.9/docs/js/src/theme-switcher.js diff --git a/AHC_app/static/css/pico-1.5.9/docs/js/src/toggle-navigation.js b/static/css/pico-1.5.9/docs/js/src/toggle-navigation.js similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/js/src/toggle-navigation.js rename to static/css/pico-1.5.9/docs/js/src/toggle-navigation.js diff --git a/AHC_app/static/css/pico-1.5.9/docs/loading.html b/static/css/pico-1.5.9/docs/loading.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/loading.html rename to static/css/pico-1.5.9/docs/loading.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/modal.html b/static/css/pico-1.5.9/docs/modal.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/modal.html rename to static/css/pico-1.5.9/docs/modal.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/navs.html b/static/css/pico-1.5.9/docs/navs.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/navs.html rename to static/css/pico-1.5.9/docs/navs.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/progress.html b/static/css/pico-1.5.9/docs/progress.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/progress.html rename to static/css/pico-1.5.9/docs/progress.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/rtl.html b/static/css/pico-1.5.9/docs/rtl.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/rtl.html rename to static/css/pico-1.5.9/docs/rtl.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/scroller.html b/static/css/pico-1.5.9/docs/scroller.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/scroller.html rename to static/css/pico-1.5.9/docs/scroller.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/scss/components/_modal.scss b/static/css/pico-1.5.9/docs/scss/components/_modal.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/scss/components/_modal.scss rename to static/css/pico-1.5.9/docs/scss/components/_modal.scss diff --git a/AHC_app/static/css/pico-1.5.9/docs/scss/components/_nav.scss b/static/css/pico-1.5.9/docs/scss/components/_nav.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/scss/components/_nav.scss rename to static/css/pico-1.5.9/docs/scss/components/_nav.scss diff --git a/AHC_app/static/css/pico-1.5.9/docs/scss/components/_theme-switcher.scss b/static/css/pico-1.5.9/docs/scss/components/_theme-switcher.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/scss/components/_theme-switcher.scss rename to static/css/pico-1.5.9/docs/scss/components/_theme-switcher.scss diff --git a/AHC_app/static/css/pico-1.5.9/docs/scss/content/_code.scss b/static/css/pico-1.5.9/docs/scss/content/_code.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/scss/content/_code.scss rename to static/css/pico-1.5.9/docs/scss/content/_code.scss diff --git a/AHC_app/static/css/pico-1.5.9/docs/scss/content/_typography.scss b/static/css/pico-1.5.9/docs/scss/content/_typography.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/scss/content/_typography.scss rename to static/css/pico-1.5.9/docs/scss/content/_typography.scss diff --git a/AHC_app/static/css/pico-1.5.9/docs/scss/layout/_aside.scss b/static/css/pico-1.5.9/docs/scss/layout/_aside.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/scss/layout/_aside.scss rename to static/css/pico-1.5.9/docs/scss/layout/_aside.scss diff --git a/AHC_app/static/css/pico-1.5.9/docs/scss/layout/_document.scss b/static/css/pico-1.5.9/docs/scss/layout/_document.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/scss/layout/_document.scss rename to static/css/pico-1.5.9/docs/scss/layout/_document.scss diff --git a/AHC_app/static/css/pico-1.5.9/docs/scss/layout/_documentation.scss b/static/css/pico-1.5.9/docs/scss/layout/_documentation.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/scss/layout/_documentation.scss rename to static/css/pico-1.5.9/docs/scss/layout/_documentation.scss diff --git a/AHC_app/static/css/pico-1.5.9/docs/scss/layout/_main.scss b/static/css/pico-1.5.9/docs/scss/layout/_main.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/scss/layout/_main.scss rename to static/css/pico-1.5.9/docs/scss/layout/_main.scss diff --git a/AHC_app/static/css/pico-1.5.9/docs/scss/pico.docs.scss b/static/css/pico-1.5.9/docs/scss/pico.docs.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/scss/pico.docs.scss rename to static/css/pico-1.5.9/docs/scss/pico.docs.scss diff --git a/AHC_app/static/css/pico-1.5.9/docs/scss/themes/_docs.scss b/static/css/pico-1.5.9/docs/scss/themes/_docs.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/scss/themes/_docs.scss rename to static/css/pico-1.5.9/docs/scss/themes/_docs.scss diff --git a/AHC_app/static/css/pico-1.5.9/docs/scss/themes/docs/_dark.scss b/static/css/pico-1.5.9/docs/scss/themes/docs/_dark.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/scss/themes/docs/_dark.scss rename to static/css/pico-1.5.9/docs/scss/themes/docs/_dark.scss diff --git a/AHC_app/static/css/pico-1.5.9/docs/scss/themes/docs/_icons.scss b/static/css/pico-1.5.9/docs/scss/themes/docs/_icons.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/scss/themes/docs/_icons.scss rename to static/css/pico-1.5.9/docs/scss/themes/docs/_icons.scss diff --git a/AHC_app/static/css/pico-1.5.9/docs/scss/themes/docs/_light.scss b/static/css/pico-1.5.9/docs/scss/themes/docs/_light.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/scss/themes/docs/_light.scss rename to static/css/pico-1.5.9/docs/scss/themes/docs/_light.scss diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/_footer.html b/static/css/pico-1.5.9/docs/src/_footer.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/_footer.html rename to static/css/pico-1.5.9/docs/src/_footer.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/_head.html b/static/css/pico-1.5.9/docs/src/_head.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/_head.html rename to static/css/pico-1.5.9/docs/src/_head.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/_nav.html b/static/css/pico-1.5.9/docs/src/_nav.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/_nav.html rename to static/css/pico-1.5.9/docs/src/_nav.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/_sidebar.html b/static/css/pico-1.5.9/docs/src/_sidebar.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/_sidebar.html rename to static/css/pico-1.5.9/docs/src/_sidebar.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/accordions.html b/static/css/pico-1.5.9/docs/src/accordions.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/accordions.html rename to static/css/pico-1.5.9/docs/src/accordions.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/buttons.html b/static/css/pico-1.5.9/docs/src/buttons.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/buttons.html rename to static/css/pico-1.5.9/docs/src/buttons.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/cards.html b/static/css/pico-1.5.9/docs/src/cards.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/cards.html rename to static/css/pico-1.5.9/docs/src/cards.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/classless.html b/static/css/pico-1.5.9/docs/src/classless.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/classless.html rename to static/css/pico-1.5.9/docs/src/classless.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/containers.html b/static/css/pico-1.5.9/docs/src/containers.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/containers.html rename to static/css/pico-1.5.9/docs/src/containers.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/customization.html b/static/css/pico-1.5.9/docs/src/customization.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/customization.html rename to static/css/pico-1.5.9/docs/src/customization.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/dropdowns.html b/static/css/pico-1.5.9/docs/src/dropdowns.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/dropdowns.html rename to static/css/pico-1.5.9/docs/src/dropdowns.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/forms.html b/static/css/pico-1.5.9/docs/src/forms.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/forms.html rename to static/css/pico-1.5.9/docs/src/forms.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/grid.html b/static/css/pico-1.5.9/docs/src/grid.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/grid.html rename to static/css/pico-1.5.9/docs/src/grid.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/index.html b/static/css/pico-1.5.9/docs/src/index.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/index.html rename to static/css/pico-1.5.9/docs/src/index.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/loading.html b/static/css/pico-1.5.9/docs/src/loading.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/loading.html rename to static/css/pico-1.5.9/docs/src/loading.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/modal.html b/static/css/pico-1.5.9/docs/src/modal.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/modal.html rename to static/css/pico-1.5.9/docs/src/modal.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/navs.html b/static/css/pico-1.5.9/docs/src/navs.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/navs.html rename to static/css/pico-1.5.9/docs/src/navs.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/progress.html b/static/css/pico-1.5.9/docs/src/progress.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/progress.html rename to static/css/pico-1.5.9/docs/src/progress.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/rtl.html b/static/css/pico-1.5.9/docs/src/rtl.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/rtl.html rename to static/css/pico-1.5.9/docs/src/rtl.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/scroller.html b/static/css/pico-1.5.9/docs/src/scroller.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/scroller.html rename to static/css/pico-1.5.9/docs/src/scroller.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/tables.html b/static/css/pico-1.5.9/docs/src/tables.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/tables.html rename to static/css/pico-1.5.9/docs/src/tables.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/themes.html b/static/css/pico-1.5.9/docs/src/themes.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/themes.html rename to static/css/pico-1.5.9/docs/src/themes.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/tooltips.html b/static/css/pico-1.5.9/docs/src/tooltips.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/tooltips.html rename to static/css/pico-1.5.9/docs/src/tooltips.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/typography.html b/static/css/pico-1.5.9/docs/src/typography.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/typography.html rename to static/css/pico-1.5.9/docs/src/typography.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/src/we-love-classes.html b/static/css/pico-1.5.9/docs/src/we-love-classes.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/src/we-love-classes.html rename to static/css/pico-1.5.9/docs/src/we-love-classes.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/tables.html b/static/css/pico-1.5.9/docs/tables.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/tables.html rename to static/css/pico-1.5.9/docs/tables.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/themes.html b/static/css/pico-1.5.9/docs/themes.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/themes.html rename to static/css/pico-1.5.9/docs/themes.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/tooltips.html b/static/css/pico-1.5.9/docs/tooltips.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/tooltips.html rename to static/css/pico-1.5.9/docs/tooltips.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/typography.html b/static/css/pico-1.5.9/docs/typography.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/typography.html rename to static/css/pico-1.5.9/docs/typography.html diff --git a/AHC_app/static/css/pico-1.5.9/docs/we-love-classes.html b/static/css/pico-1.5.9/docs/we-love-classes.html similarity index 100% rename from AHC_app/static/css/pico-1.5.9/docs/we-love-classes.html rename to static/css/pico-1.5.9/docs/we-love-classes.html diff --git a/AHC_app/static/css/pico-1.5.9/package-lock.json b/static/css/pico-1.5.9/package-lock.json similarity index 100% rename from AHC_app/static/css/pico-1.5.9/package-lock.json rename to static/css/pico-1.5.9/package-lock.json diff --git a/AHC_app/static/css/pico-1.5.9/package.json b/static/css/pico-1.5.9/package.json similarity index 100% rename from AHC_app/static/css/pico-1.5.9/package.json rename to static/css/pico-1.5.9/package.json diff --git a/AHC_app/static/css/pico-1.5.9/scss/_functions.scss b/static/css/pico-1.5.9/scss/_functions.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/_functions.scss rename to static/css/pico-1.5.9/scss/_functions.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/_variables.scss b/static/css/pico-1.5.9/scss/_variables.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/_variables.scss rename to static/css/pico-1.5.9/scss/_variables.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/components/_accordion.scss b/static/css/pico-1.5.9/scss/components/_accordion.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/components/_accordion.scss rename to static/css/pico-1.5.9/scss/components/_accordion.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/components/_card.scss b/static/css/pico-1.5.9/scss/components/_card.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/components/_card.scss rename to static/css/pico-1.5.9/scss/components/_card.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/components/_dropdown.scss b/static/css/pico-1.5.9/scss/components/_dropdown.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/components/_dropdown.scss rename to static/css/pico-1.5.9/scss/components/_dropdown.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/components/_modal.scss b/static/css/pico-1.5.9/scss/components/_modal.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/components/_modal.scss rename to static/css/pico-1.5.9/scss/components/_modal.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/components/_nav.scss b/static/css/pico-1.5.9/scss/components/_nav.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/components/_nav.scss rename to static/css/pico-1.5.9/scss/components/_nav.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/components/_progress.scss b/static/css/pico-1.5.9/scss/components/_progress.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/components/_progress.scss rename to static/css/pico-1.5.9/scss/components/_progress.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/content/_button.scss b/static/css/pico-1.5.9/scss/content/_button.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/content/_button.scss rename to static/css/pico-1.5.9/scss/content/_button.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/content/_code.scss b/static/css/pico-1.5.9/scss/content/_code.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/content/_code.scss rename to static/css/pico-1.5.9/scss/content/_code.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/content/_embedded.scss b/static/css/pico-1.5.9/scss/content/_embedded.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/content/_embedded.scss rename to static/css/pico-1.5.9/scss/content/_embedded.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/content/_form-alt-input-types.scss b/static/css/pico-1.5.9/scss/content/_form-alt-input-types.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/content/_form-alt-input-types.scss rename to static/css/pico-1.5.9/scss/content/_form-alt-input-types.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/content/_form-checkbox-radio.scss b/static/css/pico-1.5.9/scss/content/_form-checkbox-radio.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/content/_form-checkbox-radio.scss rename to static/css/pico-1.5.9/scss/content/_form-checkbox-radio.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/content/_form.scss b/static/css/pico-1.5.9/scss/content/_form.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/content/_form.scss rename to static/css/pico-1.5.9/scss/content/_form.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/content/_miscs.scss b/static/css/pico-1.5.9/scss/content/_miscs.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/content/_miscs.scss rename to static/css/pico-1.5.9/scss/content/_miscs.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/content/_table.scss b/static/css/pico-1.5.9/scss/content/_table.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/content/_table.scss rename to static/css/pico-1.5.9/scss/content/_table.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/content/_typography.scss b/static/css/pico-1.5.9/scss/content/_typography.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/content/_typography.scss rename to static/css/pico-1.5.9/scss/content/_typography.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/layout/_container.scss b/static/css/pico-1.5.9/scss/layout/_container.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/layout/_container.scss rename to static/css/pico-1.5.9/scss/layout/_container.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/layout/_document.scss b/static/css/pico-1.5.9/scss/layout/_document.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/layout/_document.scss rename to static/css/pico-1.5.9/scss/layout/_document.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/layout/_grid.scss b/static/css/pico-1.5.9/scss/layout/_grid.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/layout/_grid.scss rename to static/css/pico-1.5.9/scss/layout/_grid.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/layout/_scroller.scss b/static/css/pico-1.5.9/scss/layout/_scroller.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/layout/_scroller.scss rename to static/css/pico-1.5.9/scss/layout/_scroller.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/layout/_section.scss b/static/css/pico-1.5.9/scss/layout/_section.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/layout/_section.scss rename to static/css/pico-1.5.9/scss/layout/_section.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/layout/_sectioning.scss b/static/css/pico-1.5.9/scss/layout/_sectioning.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/layout/_sectioning.scss rename to static/css/pico-1.5.9/scss/layout/_sectioning.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/pico.classless.scss b/static/css/pico-1.5.9/scss/pico.classless.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/pico.classless.scss rename to static/css/pico-1.5.9/scss/pico.classless.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/pico.fluid.classless.scss b/static/css/pico-1.5.9/scss/pico.fluid.classless.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/pico.fluid.classless.scss rename to static/css/pico-1.5.9/scss/pico.fluid.classless.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/pico.scss b/static/css/pico-1.5.9/scss/pico.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/pico.scss rename to static/css/pico-1.5.9/scss/pico.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/pico.slim.scss b/static/css/pico-1.5.9/scss/pico.slim.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/pico.slim.scss rename to static/css/pico-1.5.9/scss/pico.slim.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/postcss.config.js b/static/css/pico-1.5.9/scss/postcss.config.js similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/postcss.config.js rename to static/css/pico-1.5.9/scss/postcss.config.js diff --git a/AHC_app/static/css/pico-1.5.9/scss/themes/default.scss b/static/css/pico-1.5.9/scss/themes/default.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/themes/default.scss rename to static/css/pico-1.5.9/scss/themes/default.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/themes/default/_colors.scss b/static/css/pico-1.5.9/scss/themes/default/_colors.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/themes/default/_colors.scss rename to static/css/pico-1.5.9/scss/themes/default/_colors.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/themes/default/_dark.scss b/static/css/pico-1.5.9/scss/themes/default/_dark.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/themes/default/_dark.scss rename to static/css/pico-1.5.9/scss/themes/default/_dark.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/themes/default/_light.scss b/static/css/pico-1.5.9/scss/themes/default/_light.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/themes/default/_light.scss rename to static/css/pico-1.5.9/scss/themes/default/_light.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/themes/default/_styles.scss b/static/css/pico-1.5.9/scss/themes/default/_styles.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/themes/default/_styles.scss rename to static/css/pico-1.5.9/scss/themes/default/_styles.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/utilities/_accessibility.scss b/static/css/pico-1.5.9/scss/utilities/_accessibility.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/utilities/_accessibility.scss rename to static/css/pico-1.5.9/scss/utilities/_accessibility.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/utilities/_loading.scss b/static/css/pico-1.5.9/scss/utilities/_loading.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/utilities/_loading.scss rename to static/css/pico-1.5.9/scss/utilities/_loading.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/utilities/_reduce-motion.scss b/static/css/pico-1.5.9/scss/utilities/_reduce-motion.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/utilities/_reduce-motion.scss rename to static/css/pico-1.5.9/scss/utilities/_reduce-motion.scss diff --git a/AHC_app/static/css/pico-1.5.9/scss/utilities/_tooltip.scss b/static/css/pico-1.5.9/scss/utilities/_tooltip.scss similarity index 100% rename from AHC_app/static/css/pico-1.5.9/scss/utilities/_tooltip.scss rename to static/css/pico-1.5.9/scss/utilities/_tooltip.scss diff --git a/AHC_app/static/css/stable_grid.css b/static/css/stable_grid.css similarity index 100% rename from AHC_app/static/css/stable_grid.css rename to static/css/stable_grid.css diff --git a/AHC_app/static/css/timeline.css b/static/css/timeline.css similarity index 100% rename from AHC_app/static/css/timeline.css rename to static/css/timeline.css diff --git a/AHC_app/static/custom_pico.scss b/static/custom_pico.scss similarity index 100% rename from AHC_app/static/custom_pico.scss rename to static/custom_pico.scss diff --git a/AHC_app/static/js/expanding_sections.js b/static/js/expanding_sections.js similarity index 100% rename from AHC_app/static/js/expanding_sections.js rename to static/js/expanding_sections.js diff --git a/AHC_app/static/js/hiding_note_fields_in_form.js b/static/js/hiding_note_fields_in_form.js similarity index 100% rename from AHC_app/static/js/hiding_note_fields_in_form.js rename to static/js/hiding_note_fields_in_form.js diff --git a/AHC_app/static/js/hiding_note_fields_in_measurement_form.js b/static/js/hiding_note_fields_in_measurement_form.js similarity index 100% rename from AHC_app/static/js/hiding_note_fields_in_measurement_form.js rename to static/js/hiding_note_fields_in_measurement_form.js diff --git a/AHC_app/static/js/pin_animal.js b/static/js/pin_animal.js similarity index 100% rename from AHC_app/static/js/pin_animal.js rename to static/js/pin_animal.js diff --git a/AHC_app/static/js/timeline.js b/static/js/timeline.js similarity index 100% rename from AHC_app/static/js/timeline.js rename to static/js/timeline.js diff --git a/AHC_app/static/media/background/background-1169534_1920.png b/static/media/background/background-1169534_1920.png similarity index 100% rename from AHC_app/static/media/background/background-1169534_1920.png rename to static/media/background/background-1169534_1920.png diff --git a/AHC_app/static/media/background/black.jpg b/static/media/background/black.jpg similarity index 100% rename from AHC_app/static/media/background/black.jpg rename to static/media/background/black.jpg diff --git a/AHC_app/static/media/background/default_title.jpg b/static/media/background/default_title.jpg similarity index 100% rename from AHC_app/static/media/background/default_title.jpg rename to static/media/background/default_title.jpg diff --git a/AHC_app/static/media/background/lizard2.jpg b/static/media/background/lizard2.jpg similarity index 100% rename from AHC_app/static/media/background/lizard2.jpg rename to static/media/background/lizard2.jpg diff --git a/AHC_app/static/media/icons/chinchilla.png b/static/media/icons/chinchilla.png similarity index 100% rename from AHC_app/static/media/icons/chinchilla.png rename to static/media/icons/chinchilla.png diff --git a/AHC_app/static/media/profile_pics/pet-care-icon.png b/static/media/profile_pics/pet-care-icon.png similarity index 100% rename from AHC_app/static/media/profile_pics/pet-care-icon.png rename to static/media/profile_pics/pet-care-icon.png diff --git a/AHC_app/static/media/profile_pics/pet-care.png b/static/media/profile_pics/pet-care.png similarity index 100% rename from AHC_app/static/media/profile_pics/pet-care.png rename to static/media/profile_pics/pet-care.png diff --git a/AHC_app/static/media/profile_pics/signup.png b/static/media/profile_pics/signup.png similarity index 100% rename from AHC_app/static/media/profile_pics/signup.png rename to static/media/profile_pics/signup.png diff --git a/AHC_app/static/media/profile_pics/signup2.png b/static/media/profile_pics/signup2.png similarity index 100% rename from AHC_app/static/media/profile_pics/signup2.png rename to static/media/profile_pics/signup2.png diff --git a/AHC_app/static/media/readme_examples/Animal profile.png b/static/media/readme_examples/Animal profile.png similarity index 100% rename from AHC_app/static/media/readme_examples/Animal profile.png rename to static/media/readme_examples/Animal profile.png diff --git a/AHC_app/static/media/readme_examples/Diet note details.png b/static/media/readme_examples/Diet note details.png similarity index 100% rename from AHC_app/static/media/readme_examples/Diet note details.png rename to static/media/readme_examples/Diet note details.png diff --git a/AHC_app/static/media/readme_examples/Full timeline of notes.png b/static/media/readme_examples/Full timeline of notes.png similarity index 100% rename from AHC_app/static/media/readme_examples/Full timeline of notes.png rename to static/media/readme_examples/Full timeline of notes.png diff --git a/AHC_app/static/media/readme_examples/User registration.png b/static/media/readme_examples/User registration.png similarity index 100% rename from AHC_app/static/media/readme_examples/User registration.png rename to static/media/readme_examples/User registration.png diff --git a/AHC_app/templates/partials/animal_card.html b/templates/partials/animal_card.html similarity index 100% rename from AHC_app/templates/partials/animal_card.html rename to templates/partials/animal_card.html From d93179208a5009db6a98e5eabefc497a9df59757 Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Sat, 30 May 2026 12:02:11 +0200 Subject: [PATCH 20/27] feat(security): remove hardcoded SECRET_KEY and DEBUG from settings --- .env.template | 5 +++++ .github/workflows/django.yml | 1 + src/ahc/settings.py | 16 ++++++++-------- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/.env.template b/.env.template index 6fe5166..fcf11b7 100644 --- a/.env.template +++ b/.env.template @@ -1,3 +1,8 @@ +# Django core +SECRET_KEY= +DEBUG=True +ALLOWED_HOSTS=localhost,127.0.0.1 + # PostgresDB for docker-compose.yml - dev POSTGRES_DB= POSTGRES_USER= diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml index 65986f7..d210048 100644 --- a/.github/workflows/django.yml +++ b/.github/workflows/django.yml @@ -34,6 +34,7 @@ jobs: EMAIL_HOST_PASSWORD: ${{ secrets.EMAIL_HOST_PASSWORD }} DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }} PYTHONUNBUFFERED: "1" + SECRET_KEY: ${{ secrets.SECRET_KEY }} steps: - name: Checkout diff --git a/src/ahc/settings.py b/src/ahc/settings.py index 077c99b..ee12b9c 100644 --- a/src/ahc/settings.py +++ b/src/ahc/settings.py @@ -14,7 +14,7 @@ from pathlib import Path import pycouchdb -from decouple import config +from decouple import Csv, config _OFFLINE_COMMANDS = { "check", @@ -50,13 +50,13 @@ def _skip_external_services() -> bool: # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = "django-insecure-x#q0@altnjw2yrhh)edi)co2)n3p8q&0qmz7m8oxu-*jhd8d9-" # nosec B105 - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True - -ALLOWED_HOSTS = [] +if _is_test_run(): + SECRET_KEY = config("SECRET_KEY", default="django-insecure-test-only-not-for-production") # nosec B105 + DEBUG = True +else: + SECRET_KEY = config("SECRET_KEY") + DEBUG = config("DEBUG", default=False, cast=bool) +ALLOWED_HOSTS = config("ALLOWED_HOSTS", default="localhost,127.0.0.1", cast=Csv()) # Application definition From d5b212b5d0590118bf9e0920a6cc62b300b52997 Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Sat, 30 May 2026 12:04:45 +0200 Subject: [PATCH 21/27] fix(cd): rename hook alias --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4cfcfde..c3e1185 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,7 +20,7 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.15.14 hooks: - - id: ruff + - id: ruff-check args: [--fix] - id: ruff-format From 0332817560104d83252294a81d53116c1f4560f9 Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Sat, 30 May 2026 12:22:08 +0200 Subject: [PATCH 22/27] chore(toolchain): rename ruff hook, add just help --- justfile | 4 ++++ src/ahc/settings.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/justfile b/justfile index ccaa8dc..7cebea3 100644 --- a/justfile +++ b/justfile @@ -1,5 +1,9 @@ set shell := ["pwsh", "-NoLogo", "-Command"] +# List all available recipes +help: + @just --list + # Install all dependencies including dev group install: uv sync diff --git a/src/ahc/settings.py b/src/ahc/settings.py index ee12b9c..c5664ea 100644 --- a/src/ahc/settings.py +++ b/src/ahc/settings.py @@ -51,7 +51,7 @@ def _skip_external_services() -> bool: # See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ if _is_test_run(): - SECRET_KEY = config("SECRET_KEY", default="django-insecure-test-only-not-for-production") # nosec B105 + SECRET_KEY = config("SECRET_KEY", default="django-insecure-test-only-not-for-production") DEBUG = True else: SECRET_KEY = config("SECRET_KEY") From 4cfa477e8ed85388fda9fe253903c00850eafa2f Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Sat, 30 May 2026 12:25:12 +0200 Subject: [PATCH 23/27] refactor(homepage): drop orphaned CronJob model --- src/ahc/apps/homepage/admin.py | 24 +------------------ .../migrations/0004_delete_cronjob.py | 11 +++++++++ src/ahc/apps/homepage/models.py | 12 ---------- 3 files changed, 12 insertions(+), 35 deletions(-) create mode 100644 src/ahc/apps/homepage/migrations/0004_delete_cronjob.py diff --git a/src/ahc/apps/homepage/admin.py b/src/ahc/apps/homepage/admin.py index 1307303..73a2081 100644 --- a/src/ahc/apps/homepage/admin.py +++ b/src/ahc/apps/homepage/admin.py @@ -1,27 +1,5 @@ from django.contrib import admin -from ahc.apps.homepage.models import AnimalTitle, CronJob +from ahc.apps.homepage.models import AnimalTitle admin.site.register(AnimalTitle) - - -class CronJobAdmin(admin.ModelAdmin): - list_display = ("name", "schedule", "last_execution", "next_execution") - readonly_fields = ( - "name", - "command", - "schedule", - "last_execution", - "next_execution", - ) - - def changelist_view(self, request, extra_context=None): - extra_context = extra_context or {} - extra_context["cronjobs"] = CronJob.objects.all() - return super().changelist_view(request, extra_context=extra_context) - - def has_add_permission(self, request): - return False - - -admin.site.register(CronJob, CronJobAdmin) diff --git a/src/ahc/apps/homepage/migrations/0004_delete_cronjob.py b/src/ahc/apps/homepage/migrations/0004_delete_cronjob.py new file mode 100644 index 0000000..200dd96 --- /dev/null +++ b/src/ahc/apps/homepage/migrations/0004_delete_cronjob.py @@ -0,0 +1,11 @@ +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("homepage", "0003_cronjob"), + ] + + operations = [ + migrations.DeleteModel(name="CronJob"), + ] diff --git a/src/ahc/apps/homepage/models.py b/src/ahc/apps/homepage/models.py index 43cc191..213acd7 100644 --- a/src/ahc/apps/homepage/models.py +++ b/src/ahc/apps/homepage/models.py @@ -42,15 +42,3 @@ def __str__(self): def get_absolute_url(self): return reverse("article-detail", kwargs={"pk": self.pk}) - - -# TODO: implement to allow set cronjobs from admin panel, must run shell command -class CronJob(models.Model): - name = models.CharField(max_length=255) - command = models.CharField(max_length=255) - schedule = models.CharField(max_length=255) - last_execution = models.DateTimeField(null=True, blank=True) - next_execution = models.DateTimeField(null=True, blank=True) - - def __str__(self): - return self.name From 715031b126225c3991393977ca86430bc2f42a6b Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Sat, 30 May 2026 12:42:15 +0200 Subject: [PATCH 24/27] test(apps): add tests for animals, users, medical_notes; fix signal bug and migration --- .github/workflows/django.yml | 1 - conftest.py | 34 +++++++++++ src/ahc/apps/animals/tests.py | 58 ++++++++++++++++++- ...notification_last_modification_and_more.py | 6 +- .../signals/type_measurement_notes.py | 22 +++---- src/ahc/apps/medical_notes/tests.py | 55 +++++++++++++++++- src/ahc/apps/users/tests.py | 28 ++++++++- 7 files changed, 184 insertions(+), 20 deletions(-) diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml index d210048..65986f7 100644 --- a/.github/workflows/django.yml +++ b/.github/workflows/django.yml @@ -34,7 +34,6 @@ jobs: EMAIL_HOST_PASSWORD: ${{ secrets.EMAIL_HOST_PASSWORD }} DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }} PYTHONUNBUFFERED: "1" - SECRET_KEY: ${{ secrets.SECRET_KEY }} steps: - name: Checkout diff --git a/conftest.py b/conftest.py index e69de29..72922e2 100644 --- a/conftest.py +++ b/conftest.py @@ -0,0 +1,34 @@ +from unittest.mock import MagicMock, patch + +import pytest +from django.contrib.auth.models import User + + +@pytest.fixture +def user_profile(db): + """Create a User + Profile pair, mocking image processing in Profile.save().""" + from ahc.apps.users.models import Profile + + user = User.objects.create_user(username="testuser", password="testpass123") + with patch("ahc.apps.users.models.Image.open") as mock_open: + mock_img = MagicMock() + mock_img.height = 100 + mock_img.width = 100 + mock_open.return_value = mock_img + profile = Profile.objects.create(user=user) + return user, profile + + +@pytest.fixture +def second_user_profile(db): + """A second User + Profile for multi-user permission tests.""" + from ahc.apps.users.models import Profile + + user = User.objects.create_user(username="otheruser", password="testpass123") + with patch("ahc.apps.users.models.Image.open") as mock_open: + mock_img = MagicMock() + mock_img.height = 100 + mock_img.width = 100 + mock_open.return_value = mock_img + profile = Profile.objects.create(user=user) + return user, profile diff --git a/src/ahc/apps/animals/tests.py b/src/ahc/apps/animals/tests.py index a39b155..933a9c0 100644 --- a/src/ahc/apps/animals/tests.py +++ b/src/ahc/apps/animals/tests.py @@ -1 +1,57 @@ -# Create your tests here. +import pytest + +from ahc.apps.animals.models import Animal +from ahc.apps.animals.signals import update_allowed_users + + +@pytest.fixture +def animal(db, user_profile): + _, profile = user_profile + return Animal.objects.create(full_name="Whiskers", owner=profile) + + +@pytest.mark.integration +@pytest.mark.django_db +class TestAnimalModel: + def test_animal_is_created_with_uuid_pk(self, animal): + assert animal.id is not None + assert animal.full_name == "Whiskers" + + def test_owner_is_assigned(self, animal, user_profile): + _, profile = user_profile + assert animal.owner == profile + + def test_no_keepers_by_default(self, animal): + assert animal.allowed_users.count() == 0 + + def test_second_user_can_be_added_as_keeper(self, animal, second_user_profile): + _, other_profile = second_user_profile + animal.allowed_users.add(other_profile) + assert animal.allowed_users.filter(pk=other_profile.pk).exists() + + +@pytest.mark.integration +@pytest.mark.django_db +class TestUpdateAllowedUsersSignalHandler: + """update_allowed_users: owner must not appear in allowed_users.""" + + def test_owner_removed_when_present_in_allowed_users(self, animal, user_profile): + _, profile = user_profile + animal.allowed_users.add(profile) + assert animal.allowed_users.filter(pk=profile.pk).exists() + + update_allowed_users(sender=Animal, instance=animal) + + assert not animal.allowed_users.filter(pk=profile.pk).exists() + + def test_non_owner_keeper_not_affected(self, animal, second_user_profile): + _, other_profile = second_user_profile + animal.allowed_users.add(other_profile) + + update_allowed_users(sender=Animal, instance=animal) + + assert animal.allowed_users.filter(pk=other_profile.pk).exists() + + def test_no_op_when_allowed_users_is_empty(self, animal): + update_allowed_users(sender=Animal, instance=animal) + assert animal.allowed_users.count() == 0 diff --git a/src/ahc/apps/medical_notes/migrations/0009_discordnotification_last_modification_and_more.py b/src/ahc/apps/medical_notes/migrations/0009_discordnotification_last_modification_and_more.py index 29c4e8d..237bd01 100644 --- a/src/ahc/apps/medical_notes/migrations/0009_discordnotification_last_modification_and_more.py +++ b/src/ahc/apps/medical_notes/migrations/0009_discordnotification_last_modification_and_more.py @@ -14,16 +14,16 @@ class Migration(migrations.Migration): migrations.AddField( model_name="discordnotification", name="last_modification", - field=models.DateTimeField(default=datetime.datetime(2024, 2, 2, 13, 46, 49, 356514)), + field=models.DateTimeField(default=datetime.datetime(2024, 2, 2, 13, 46, 49, 356514, tzinfo=datetime.UTC)), ), migrations.AddField( model_name="emailnotification", name="last_modification", - field=models.DateTimeField(default=datetime.datetime(2024, 2, 2, 13, 46, 49, 356514)), + field=models.DateTimeField(default=datetime.datetime(2024, 2, 2, 13, 46, 49, 356514, tzinfo=datetime.UTC)), ), migrations.AddField( model_name="smsnotification", name="last_modification", - field=models.DateTimeField(default=datetime.datetime(2024, 2, 2, 13, 46, 49, 356514)), + field=models.DateTimeField(default=datetime.datetime(2024, 2, 2, 13, 46, 49, 356514, tzinfo=datetime.UTC)), ), ] diff --git a/src/ahc/apps/medical_notes/signals/type_measurement_notes.py b/src/ahc/apps/medical_notes/signals/type_measurement_notes.py index 38e3507..d3cddd6 100644 --- a/src/ahc/apps/medical_notes/signals/type_measurement_notes.py +++ b/src/ahc/apps/medical_notes/signals/type_measurement_notes.py @@ -10,20 +10,16 @@ @receiver(pre_save, sender=BiometricRecord) def validate_one_to_one_fields(sender, instance, **kwargs): - if ( - len( - { - instance - for instance in ( - instance.weight_biometric_record, - instance.height_biometric_record, - instance.custom_biometric_record, - ) - if instance is not None - } + assigned = sum( + 1 + for field in ( + instance.weight_biometric_record, + instance.height_biometric_record, + instance.custom_biometric_record, ) - > 1 - ): + if field is not None + ) + if assigned > 1: raise ValidationError("BiometricRecord can only have one of OneToOneFields assigned.") diff --git a/src/ahc/apps/medical_notes/tests.py b/src/ahc/apps/medical_notes/tests.py index a39b155..c18ca7e 100644 --- a/src/ahc/apps/medical_notes/tests.py +++ b/src/ahc/apps/medical_notes/tests.py @@ -1 +1,54 @@ -# Create your tests here. +from unittest.mock import MagicMock + +import pytest +from django.core.exceptions import ValidationError + +from ahc.apps.medical_notes.models.type_measurement_notes import ( + BiometricHeightRecords, + BiometricWeightRecords, +) +from ahc.apps.medical_notes.signals.type_measurement_notes import validate_one_to_one_fields + + +def _make_instance(weight=None, height=None, custom=None): + instance = MagicMock() + instance.weight_biometric_record = weight + instance.height_biometric_record = height + instance.custom_biometric_record = custom + return instance + + +@pytest.mark.unit +class TestBiometricRecordValidation: + """validate_one_to_one_fields: at most one measurement type per BiometricRecord.""" + + def test_two_types_raises_validation_error(self): + instance = _make_instance( + weight=BiometricWeightRecords(weight=5), + height=BiometricHeightRecords(height=30), + ) + with pytest.raises(ValidationError): + validate_one_to_one_fields(sender=None, instance=instance) + + def test_all_three_types_raises_validation_error(self): + from ahc.apps.medical_notes.models.type_measurement_notes import BiometricCustomRecords + + instance = _make_instance( + weight=BiometricWeightRecords(weight=5), + height=BiometricHeightRecords(height=30), + custom=BiometricCustomRecords(record_name="x", record_value="1", record_unit="cm"), + ) + with pytest.raises(ValidationError): + validate_one_to_one_fields(sender=None, instance=instance) + + def test_weight_only_is_valid(self): + instance = _make_instance(weight=BiometricWeightRecords(weight=5)) + validate_one_to_one_fields(sender=None, instance=instance) + + def test_height_only_is_valid(self): + instance = _make_instance(height=BiometricHeightRecords(height=30)) + validate_one_to_one_fields(sender=None, instance=instance) + + def test_all_none_is_valid(self): + instance = _make_instance() + validate_one_to_one_fields(sender=None, instance=instance) diff --git a/src/ahc/apps/users/tests.py b/src/ahc/apps/users/tests.py index a39b155..7984f3e 100644 --- a/src/ahc/apps/users/tests.py +++ b/src/ahc/apps/users/tests.py @@ -1 +1,27 @@ -# Create your tests here. +import pytest + +from ahc.apps.users.models import Profile + + +@pytest.mark.integration +@pytest.mark.django_db +class TestProfileModel: + def test_str_returns_username(self, user_profile): + _, profile = user_profile + assert str(profile) == "testuser" + + def test_profile_linked_to_user(self, user_profile): + user, profile = user_profile + assert profile.user == user + + def test_allow_recent_animals_list_defaults_to_true(self, user_profile): + _, profile = user_profile + assert profile.allow_recennt_animals_list is True + + def test_pinned_animals_empty_by_default(self, user_profile): + _, profile = user_profile + assert profile.pinned_animals.count() == 0 + + def test_profile_is_unique_per_user(self, user_profile): + user, _ = user_profile + assert Profile.objects.filter(user=user).count() == 1 From 8ce2841b4041ef2d0633b8006c514f26f562c2e4 Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Sat, 30 May 2026 17:12:48 +0200 Subject: [PATCH 25/27] fix(animals): use MEDIA_ROOT in signals, guard against missing media dir --- src/ahc/apps/animals/signals.py | 41 ++++++++++++++++----------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/ahc/apps/animals/signals.py b/src/ahc/apps/animals/signals.py index daddc0f..6ccd793 100644 --- a/src/ahc/apps/animals/signals.py +++ b/src/ahc/apps/animals/signals.py @@ -1,46 +1,45 @@ import os +from pathlib import Path +from django.conf import settings from django.db.models.signals import post_delete, post_save, pre_delete from django.dispatch import receiver from ahc.apps.animals.models import Animal from ahc.apps.users.models import Profile +_ANIMALS_MEDIA_DIR = Path(settings.MEDIA_ROOT) / "profile_pics" / "animals" + @receiver(post_save, sender=Animal) def remove_old_pictures_after_change(sender, instance, **kwargs): - animals_with_profile_images = Animal.objects.exclude(profile_image="").values_list("profile_image", flat=True) - unused_images = os.listdir("static/media/profile_pics/animals/") - - animals_with_profile_images = [str(picture).split("/")[-1] for picture in animals_with_profile_images] - - for image_name in unused_images: + if not _ANIMALS_MEDIA_DIR.is_dir(): + return + animals_with_profile_images = { + str(p).split("/")[-1] for p in Animal.objects.exclude(profile_image="").values_list("profile_image", flat=True) + } + for image_name in os.listdir(_ANIMALS_MEDIA_DIR): if image_name not in animals_with_profile_images: - image_path = os.path.join("static/media/profile_pics/animals/", image_name) - os.remove(image_path) + (_ANIMALS_MEDIA_DIR / image_name).unlink(missing_ok=True) -# is necessary to write tests for this one! @receiver(pre_delete, sender=Animal) def remove_old_pictures_after_animal_delete(sender, instance, **kwargs): if instance.profile_image: - image_name = instance.profile_image.name - image_path = os.path.join("static/media/profile_pics/animals/", image_name) - if os.path.exists(image_path): - os.remove(image_path) + image_path = _ANIMALS_MEDIA_DIR / Path(instance.profile_image.name).name + image_path.unlink(missing_ok=True) @receiver(post_delete, sender=Profile) def remove_old_pictures_after_user_delete(sender, instance, **kwargs): - animals_with_profile_images = Animal.objects.exclude(profile_image="").values_list("profile_image", flat=True) - unused_images = os.listdir("static/media/profile_pics/animals/") - - animals_with_profile_images = [str(picture).split("/")[-1] for picture in animals_with_profile_images] - - for image_name in unused_images: + if not _ANIMALS_MEDIA_DIR.is_dir(): + return + animals_with_profile_images = { + str(p).split("/")[-1] for p in Animal.objects.exclude(profile_image="").values_list("profile_image", flat=True) + } + for image_name in os.listdir(_ANIMALS_MEDIA_DIR): if image_name not in animals_with_profile_images: - image_path = os.path.join("static/media/profile_pics/animals/", image_name) - os.remove(image_path) + (_ANIMALS_MEDIA_DIR / image_name).unlink(missing_ok=True) @receiver(post_save, sender=Animal) From 0150da75b00dda819809071dc76bb310ef97f198 Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Sat, 30 May 2026 17:17:46 +0200 Subject: [PATCH 26/27] cd: remove format form precommit hooks --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c3e1185..8afd159 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,8 +21,8 @@ repos: rev: v0.15.14 hooks: - id: ruff-check - args: [--fix] - id: ruff-format + args: [--check] - repo: https://github.com/codespell-project/codespell rev: v2.4.2 From 7de838cbb169ec538f94170aa24932a5f1aa151f Mon Sep 17 00:00:00 2001 From: Cybernetic-Ransomware <71835339+Cybernetic-Ransomware@users.noreply.github.com> Date: Sat, 30 May 2026 17:19:41 +0200 Subject: [PATCH 27/27] fix(settings): use BASE_DIR / static_collected for STATIC_ROOT --- src/ahc/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ahc/settings.py b/src/ahc/settings.py index c5664ea..2db41ef 100644 --- a/src/ahc/settings.py +++ b/src/ahc/settings.py @@ -191,7 +191,7 @@ def _skip_external_services() -> bool: # https://docs.djangoproject.com/en/4.2/howto/static-files/ STATIC_URL = "/static/" -STATIC_ROOT = "static_collected" +STATIC_ROOT = BASE_DIR / "static_collected" STATICFILES_DIRS = [ BASE_DIR / "static", ]