aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Hassan Abouelela <[email protected]>2022-07-12 07:50:51 +0400
committerGravatar GitHub <[email protected]>2022-07-12 07:50:51 +0400
commit7511c6d4aff6f3ad31ccb43c00226a9187d7ece1 (patch)
tree0c26ec6aa690ce4c62c5cf9b56f4944066cc319e
parentMerge #722 - resources: add The Algorithms and remove Atom (diff)
parentBump Django To 4.0 (diff)
Merge pull request #740 from python-discord/update-django
Update Django Version To 4.0
-rw-r--r--poetry.lock426
-rw-r--r--pydis_site/apps/api/pagination.py5
-rw-r--r--pydis_site/apps/api/tests/migrations/__init__.py1
-rw-r--r--pydis_site/apps/api/tests/migrations/base.py102
-rw-r--r--pydis_site/apps/api/tests/migrations/test_active_infraction_migration.py496
-rw-r--r--pydis_site/apps/api/tests/migrations/test_base.py135
-rw-r--r--pydis_site/apps/api/tests/test_models.py12
-rw-r--r--pydis_site/apps/content/apps.py2
-rw-r--r--pydis_site/apps/content/views/page_category.py4
-rw-r--r--pydis_site/apps/events/apps.py2
-rw-r--r--pydis_site/apps/home/tests/test_repodata_helpers.py12
-rw-r--r--pydis_site/apps/home/views/home.py6
-rw-r--r--pydis_site/apps/redirect/apps.py2
-rw-r--r--pydis_site/apps/resources/apps.py2
-rw-r--r--pydis_site/apps/staff/apps.py2
-rw-r--r--pydis_site/settings.py3
-rw-r--r--pyproject.toml8
17 files changed, 268 insertions, 952 deletions
diff --git a/poetry.lock b/poetry.lock
index 3b26c275..f6576fba 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,6 +1,23 @@
[[package]]
+name = "anyio"
+version = "3.6.1"
+description = "High level compatibility layer for multiple asynchronous event loop implementations"
+category = "main"
+optional = false
+python-versions = ">=3.6.2"
+
+[package.dependencies]
+idna = ">=2.8"
+sniffio = ">=1.1"
+
+[package.extras]
+doc = ["packaging", "sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"]
+test = ["coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "contextlib2", "uvloop (<0.15)", "mock (>=4)", "uvloop (>=0.15)"]
+trio = ["trio (>=0.16)"]
+
+[[package]]
name = "asgiref"
-version = "3.5.0"
+version = "3.5.2"
description = "ASGI specs, helper code, and adapters"
category = "main"
optional = false
@@ -25,7 +42,7 @@ tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>
[[package]]
name = "bandit"
-version = "1.7.2"
+version = "1.7.4"
description = "Security oriented static analyser for python code."
category = "dev"
optional = false
@@ -38,17 +55,17 @@ PyYAML = ">=5.3.1"
stevedore = ">=1.20.0"
[package.extras]
-test = ["beautifulsoup4 (>=4.8.0)", "coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "pylint (==1.9.4)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)", "toml"]
+test = ["coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)", "toml", "beautifulsoup4 (>=4.8.0)", "pylint (==1.9.4)"]
toml = ["toml"]
yaml = ["pyyaml"]
[[package]]
name = "certifi"
-version = "2021.10.8"
+version = "2022.6.15"
description = "Python package for providing Mozilla's CA Bundle."
category = "main"
optional = false
-python-versions = "*"
+python-versions = ">=3.6"
[[package]]
name = "cfgv"
@@ -60,18 +77,18 @@ python-versions = ">=3.6.1"
[[package]]
name = "charset-normalizer"
-version = "2.0.11"
+version = "2.1.0"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
category = "main"
optional = false
-python-versions = ">=3.5.0"
+python-versions = ">=3.6.0"
[package.extras]
unicode_backport = ["unicodedata2"]
[[package]]
name = "colorama"
-version = "0.4.4"
+version = "0.4.5"
description = "Cross-platform colored terminal text."
category = "dev"
optional = false
@@ -114,19 +131,19 @@ python-versions = "*"
[[package]]
name = "django"
-version = "3.1.14"
-description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design."
+version = "4.0.6"
+description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design."
category = "main"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.8"
[package.dependencies]
-asgiref = ">=3.2.10,<4"
-pytz = "*"
+asgiref = ">=3.4.1,<4"
sqlparse = ">=0.2.2"
+tzdata = {version = "*", markers = "sys_platform == \"win32\""}
[package.extras]
-argon2 = ["argon2-cffi (>=16.1.0)"]
+argon2 = ["argon2-cffi (>=19.1.0)"]
bcrypt = ["bcrypt"]
[[package]]
@@ -173,7 +190,7 @@ prometheus-client = ">=0.7"
[[package]]
name = "django-simple-bulma"
-version = "2.4.0"
+version = "2.5.0"
description = "Django application to add the Bulma CSS framework and its extensions"
category = "main"
optional = false
@@ -188,14 +205,15 @@ dev = ["flake8 (>=3.8,<4.0)", "flake8-annotations (>=2.0,<3.0)", "flake8-bugbear
[[package]]
name = "djangorestframework"
-version = "3.12.4"
+version = "3.13.1"
description = "Web APIs for Django, made easy."
category = "main"
optional = false
-python-versions = ">=3.5"
+python-versions = ">=3.6"
[package.dependencies]
django = ">=2.2"
+pytz = "*"
[[package]]
name = "docopt"
@@ -207,7 +225,7 @@ python-versions = "*"
[[package]]
name = "filelock"
-version = "3.4.2"
+version = "3.7.1"
description = "A platform independent file lock."
category = "dev"
optional = false
@@ -232,25 +250,26 @@ pyflakes = ">=2.3.0,<2.4.0"
[[package]]
name = "flake8-annotations"
-version = "2.7.0"
+version = "2.9.0"
description = "Flake8 Type Annotation Checks"
category = "dev"
optional = false
-python-versions = ">=3.6.2,<4.0.0"
+python-versions = ">=3.7,<4.0"
[package.dependencies]
-flake8 = ">=3.7,<5.0"
+attrs = ">=21.4,<22.0"
+flake8 = ">=3.7"
[[package]]
name = "flake8-bandit"
-version = "2.1.2"
+version = "3.0.0"
description = "Automated security testing with bandit and flake8."
category = "dev"
optional = false
-python-versions = "*"
+python-versions = ">=3.6"
[package.dependencies]
-bandit = "*"
+bandit = ">=1.7.3"
flake8 = "*"
flake8-polyfill = "*"
pycodestyle = "*"
@@ -317,7 +336,7 @@ flake8 = "*"
[[package]]
name = "flake8-tidy-imports"
-version = "4.6.0"
+version = "4.8.0"
description = "A flake8 plugin that helps you write tidier imports."
category = "dev"
optional = false
@@ -350,7 +369,7 @@ smmap = ">=3.0.1,<6"
[[package]]
name = "gitpython"
-version = "3.1.26"
+version = "3.1.27"
description = "GitPython is a python library used to interact with Git repositories"
category = "dev"
optional = false
@@ -374,8 +393,54 @@ setproctitle = ["setproctitle"]
tornado = ["tornado (>=0.2)"]
[[package]]
+name = "h11"
+version = "0.12.0"
+description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
+category = "main"
+optional = false
+python-versions = ">=3.6"
+
+[[package]]
+name = "httpcore"
+version = "0.15.0"
+description = "A minimal low-level HTTP client."
+category = "main"
+optional = false
+python-versions = ">=3.7"
+
+[package.dependencies]
+anyio = ">=3.0.0,<4.0.0"
+certifi = "*"
+h11 = ">=0.11,<0.13"
+sniffio = ">=1.0.0,<2.0.0"
+
+[package.extras]
+http2 = ["h2 (>=3,<5)"]
+socks = ["socksio (>=1.0.0,<2.0.0)"]
+
+[[package]]
+name = "httpx"
+version = "0.23.0"
+description = "The next generation HTTP client."
+category = "main"
+optional = false
+python-versions = ">=3.7"
+
+[package.dependencies]
+certifi = "*"
+httpcore = ">=0.15.0,<0.16.0"
+rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]}
+sniffio = "*"
+
+[package.extras]
+brotli = ["brotlicffi", "brotli"]
+cli = ["click (>=8.0.0,<9.0.0)", "rich (>=10,<13)", "pygments (>=2.0.0,<3.0.0)"]
+http2 = ["h2 (>=3,<5)"]
+socks = ["socksio (>=1.0.0,<2.0.0)"]
+
+[[package]]
name = "identify"
-version = "2.4.6"
+version = "2.5.1"
description = "File identification library for Python"
category = "dev"
optional = false
@@ -394,7 +459,7 @@ python-versions = ">=3.5"
[[package]]
name = "importlib-metadata"
-version = "4.10.1"
+version = "4.12.0"
description = "Read metadata from Python packages"
category = "main"
optional = false
@@ -404,9 +469,9 @@ python-versions = ">=3.7"
zipp = ">=0.5"
[package.extras]
-docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
+docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"]
perf = ["ipython"]
-testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
+testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"]
[[package]]
name = "libsass"
@@ -421,7 +486,7 @@ six = "*"
[[package]]
name = "markdown"
-version = "3.3.6"
+version = "3.3.7"
description = "Python implementation of Markdown."
category = "main"
optional = false
@@ -451,15 +516,15 @@ python-versions = ">=3.5"
[[package]]
name = "nodeenv"
-version = "1.6.0"
+version = "1.7.0"
description = "Node.js virtual environment builder"
category = "dev"
optional = false
-python-versions = "*"
+python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*"
[[package]]
name = "pbr"
-version = "5.8.0"
+version = "5.9.0"
description = "Python Build Reasonableness"
category = "dev"
optional = false
@@ -467,7 +532,7 @@ python-versions = ">=2.6"
[[package]]
name = "pep8-naming"
-version = "0.12.1"
+version = "0.13.0"
description = "Check PEP-8 naming conventions, plugin for flake8"
category = "dev"
optional = false
@@ -475,27 +540,26 @@ python-versions = "*"
[package.dependencies]
flake8 = ">=3.9.1"
-flake8-polyfill = ">=1.0.2,<2"
[[package]]
name = "platformdirs"
-version = "2.4.1"
+version = "2.5.2"
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
category = "dev"
optional = false
python-versions = ">=3.7"
[package.extras]
-docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"]
-test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"]
+docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"]
+test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"]
[[package]]
name = "pre-commit"
-version = "2.17.0"
+version = "2.20.0"
description = "A framework for managing and maintaining multi-language pre-commit hooks."
category = "dev"
optional = false
-python-versions = ">=3.6.1"
+python-versions = ">=3.7"
[package.dependencies]
cfgv = ">=2.0.0"
@@ -507,7 +571,7 @@ virtualenv = ">=20.0.8"
[[package]]
name = "prometheus-client"
-version = "0.13.1"
+version = "0.14.1"
description = "Python client for the Prometheus monitoring system."
category = "main"
optional = false
@@ -518,14 +582,14 @@ twisted = ["twisted"]
[[package]]
name = "psutil"
-version = "5.9.0"
+version = "5.9.1"
description = "Cross-platform lib for process and system monitoring in Python."
category = "dev"
optional = false
-python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[package.extras]
-test = ["ipaddress", "mock", "unittest2", "enum34", "pywin32", "wmi"]
+test = ["ipaddress", "mock", "enum34", "pywin32", "wmi"]
[[package]]
name = "psycopg2-binary"
@@ -559,7 +623,7 @@ toml = ["toml"]
[[package]]
name = "pyfakefs"
-version = "4.5.4"
+version = "4.5.6"
description = "pyfakefs implements a fake file system that mocks the Python file system modules."
category = "dev"
optional = false
@@ -601,7 +665,7 @@ test = ["pytest", "toml", "pyaml"]
[[package]]
name = "pytz"
-version = "2021.3"
+version = "2022.1"
description = "World timezone definitions, modern and historical"
category = "main"
optional = false
@@ -617,21 +681,35 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
[[package]]
name = "requests"
-version = "2.27.1"
+version = "2.28.1"
description = "Python HTTP for Humans."
category = "main"
optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
+python-versions = ">=3.7, <4"
[package.dependencies]
certifi = ">=2017.4.17"
-charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""}
-idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""}
+charset-normalizer = ">=2,<3"
+idna = ">=2.5,<4"
urllib3 = ">=1.21.1,<1.27"
[package.extras]
-socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
-use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"]
+socks = ["PySocks (>=1.5.6,!=1.5.7)"]
+use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"]
+
+[[package]]
+name = "rfc3986"
+version = "1.5.0"
+description = "Validating URI References per RFC 3986"
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+idna = {version = "*", optional = true, markers = "extra == \"idna2008\""}
+
+[package.extras]
+idna2008 = ["idna"]
[[package]]
name = "sentry-sdk"
@@ -678,6 +756,14 @@ optional = false
python-versions = ">=3.6"
[[package]]
+name = "sniffio"
+version = "1.2.0"
+description = "Sniff out which async library your code is running under"
+category = "main"
+optional = false
+python-versions = ">=3.5"
+
+[[package]]
name = "snowballstemmer"
version = "2.2.0"
description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms."
@@ -726,21 +812,29 @@ optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]]
+name = "tzdata"
+version = "2022.1"
+description = "Provider of IANA time zone data"
+category = "main"
+optional = false
+python-versions = ">=2"
+
+[[package]]
name = "urllib3"
-version = "1.26.8"
+version = "1.26.10"
description = "HTTP library with thread-safe connection pooling, file post, and more."
category = "main"
optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4"
[package.extras]
-brotli = ["brotlipy (>=0.6.0)"]
+brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"]
secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
[[package]]
name = "virtualenv"
-version = "20.13.0"
+version = "20.15.1"
description = "Virtual Python Environment builder"
category = "dev"
optional = false
@@ -769,49 +863,47 @@ brotli = ["brotli"]
[[package]]
name = "zipp"
-version = "3.7.0"
+version = "3.8.0"
description = "Backport of pathlib-compatible object wrapper for zip files"
category = "main"
optional = false
python-versions = ">=3.7"
[package.extras]
-docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
-testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
+docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"]
+testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"]
[metadata]
lock-version = "1.1"
python-versions = "3.9.*"
-content-hash = "fc9b20c33c65a289122d710844285ac20d7598e65c7f8237f8903509f5b2dea4"
+content-hash = "e71d10c3d478c5d99e842f4c449a093caa1d4b2d255eb0dfb19843c5265d4aca"
[metadata.files]
+anyio = [
+ {file = "anyio-3.6.1-py3-none-any.whl", hash = "sha256:cb29b9c70620506a9a8f87a309591713446953302d7d995344d0d7c6c0c9a7be"},
+ {file = "anyio-3.6.1.tar.gz", hash = "sha256:413adf95f93886e442aea925f3ee43baa5a765a64a0f52c6081894f9992fdd0b"},
+]
asgiref = [
- {file = "asgiref-3.5.0-py3-none-any.whl", hash = "sha256:88d59c13d634dcffe0510be048210188edd79aeccb6a6c9028cdad6f31d730a9"},
- {file = "asgiref-3.5.0.tar.gz", hash = "sha256:2f8abc20f7248433085eda803936d98992f1343ddb022065779f37c5da0181d0"},
+ {file = "asgiref-3.5.2-py3-none-any.whl", hash = "sha256:1d2880b792ae8757289136f1db2b7b99100ce959b2aa57fd69dab783d05afac4"},
+ {file = "asgiref-3.5.2.tar.gz", hash = "sha256:4a29362a6acebe09bf1d6640db38c1dc3d9217c68e6f9f6204d72667fc19a424"},
]
attrs = [
{file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"},
{file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"},
]
-bandit = [
- {file = "bandit-1.7.2-py3-none-any.whl", hash = "sha256:e20402cadfd126d85b68ed4c8862959663c8c372dbbb1fca8f8e2c9f55a067ec"},
- {file = "bandit-1.7.2.tar.gz", hash = "sha256:6d11adea0214a43813887bfe71a377b5a9955e4c826c8ffd341b494e3ab25260"},
-]
+bandit = []
certifi = [
- {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"},
- {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"},
+ {file = "certifi-2022.6.15-py3-none-any.whl", hash = "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412"},
+ {file = "certifi-2022.6.15.tar.gz", hash = "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d"},
]
cfgv = [
{file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"},
{file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"},
]
-charset-normalizer = [
- {file = "charset-normalizer-2.0.11.tar.gz", hash = "sha256:98398a9d69ee80548c762ba991a4728bfc3836768ed226b3945908d1a688371c"},
- {file = "charset_normalizer-2.0.11-py3-none-any.whl", hash = "sha256:2842d8f5e82a1f6aa437380934d5e1cd4fcf2003b06fed6940769c164a480a45"},
-]
+charset-normalizer = []
colorama = [
- {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
- {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
+ {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"},
+ {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"},
]
coverage = [
{file = "coverage-5.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b6d534e4b2ab35c9f93f46229363e17f63c53ad01330df9f2d6bd1187e5eaacf"},
@@ -875,10 +967,7 @@ distlib = [
{file = "distlib-0.3.4-py2.py3-none-any.whl", hash = "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b"},
{file = "distlib-0.3.4.zip", hash = "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579"},
]
-django = [
- {file = "Django-3.1.14-py3-none-any.whl", hash = "sha256:0fabc786489af16ad87a8c170ba9d42bfd23f7b699bd5ef05675864e8d012859"},
- {file = "Django-3.1.14.tar.gz", hash = "sha256:72a4a5a136a214c39cf016ccdd6b69e2aa08c7479c66d93f3a9b5e4bb9d8a347"},
-]
+django = []
django-distill = [
{file = "django-distill-2.9.2.tar.gz", hash = "sha256:91d5f45c2ff78b8efd4805ff5ec17df4ba815bbf51ca12a2cea65727d2f1d42e"},
]
@@ -894,32 +983,21 @@ django-prometheus = [
{file = "django-prometheus-2.2.0.tar.gz", hash = "sha256:240378a1307c408bd5fc85614a3a57f1ce633d4a222c9e291e2bbf325173b801"},
{file = "django_prometheus-2.2.0-py2.py3-none-any.whl", hash = "sha256:e6616770d8820b8834762764bf1b76ec08e1b98e72a6f359d488a2e15fe3537c"},
]
-django-simple-bulma = [
- {file = "django-simple-bulma-2.4.0.tar.gz", hash = "sha256:99a15261b0c61062a128af3c6a45da9c066d6a4a548c9063464e0fb7a5438aa1"},
- {file = "django_simple_bulma-2.4.0-py3-none-any.whl", hash = "sha256:95d5e26bebbf6a0184e33df844a0ff534bdfd91431e413d1a844d47a75c55fff"},
-]
-djangorestframework = [
- {file = "djangorestframework-3.12.4-py3-none-any.whl", hash = "sha256:6d1d59f623a5ad0509fe0d6bfe93cbdfe17b8116ebc8eda86d45f6e16e819aaf"},
- {file = "djangorestframework-3.12.4.tar.gz", hash = "sha256:f747949a8ddac876e879190df194b925c177cdeb725a099db1460872f7c0a7f2"},
-]
+django-simple-bulma = []
+djangorestframework = []
docopt = [
{file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"},
]
-filelock = [
- {file = "filelock-3.4.2-py3-none-any.whl", hash = "sha256:cf0fc6a2f8d26bd900f19bf33915ca70ba4dd8c56903eeb14e1e7a2fd7590146"},
- {file = "filelock-3.4.2.tar.gz", hash = "sha256:38b4f4c989f9d06d44524df1b24bd19e167d851f19b50bf3e3559952dddc5b80"},
-]
+filelock = []
flake8 = [
{file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"},
{file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"},
]
flake8-annotations = [
- {file = "flake8-annotations-2.7.0.tar.gz", hash = "sha256:52e53c05b0c06cac1c2dec192ea2c36e85081238add3bd99421d56f574b9479b"},
- {file = "flake8_annotations-2.7.0-py3-none-any.whl", hash = "sha256:3edfbbfb58e404868834fe6ec3eaf49c139f64f0701259f707d043185545151e"},
-]
-flake8-bandit = [
- {file = "flake8_bandit-2.1.2.tar.gz", hash = "sha256:687fc8da2e4a239b206af2e54a90093572a60d0954f3054e23690739b0b0de3b"},
+ {file = "flake8-annotations-2.9.0.tar.gz", hash = "sha256:63fb3f538970b6a8dfd84125cf5af16f7b22e52d5032acb3b7eb23645ecbda9b"},
+ {file = "flake8_annotations-2.9.0-py3-none-any.whl", hash = "sha256:84f46de2964cb18fccea968d9eafce7cf857e34d913d515120795b9af6498d56"},
]
+flake8-bandit = []
flake8-bugbear = [
{file = "flake8-bugbear-20.11.1.tar.gz", hash = "sha256:528020129fea2dea33a466b9d64ab650aa3e5f9ffc788b70ea4bc6cf18283538"},
{file = "flake8_bugbear-20.11.1-py36.py37.py38-none-any.whl", hash = "sha256:f35b8135ece7a014bc0aee5b5d485334ac30a6da48494998cc1fabf7ec70d703"},
@@ -941,8 +1019,8 @@ flake8-string-format = [
{file = "flake8_string_format-0.3.0-py2.py3-none-any.whl", hash = "sha256:812ff431f10576a74c89be4e85b8e075a705be39bc40c4b4278b5b13e2afa9af"},
]
flake8-tidy-imports = [
- {file = "flake8-tidy-imports-4.6.0.tar.gz", hash = "sha256:3e193d8c4bb4492408a90e956d888b27eed14c698387c9b38230da3dad78058f"},
- {file = "flake8_tidy_imports-4.6.0-py3-none-any.whl", hash = "sha256:6ae9f55d628156e19d19f4c359dd5d3e95431a9bd514f5e2748c53c1398c66b2"},
+ {file = "flake8-tidy-imports-4.8.0.tar.gz", hash = "sha256:df44f9c841b5dfb3a7a1f0da8546b319d772c2a816a1afefcce43e167a593d83"},
+ {file = "flake8_tidy_imports-4.8.0-py3-none-any.whl", hash = "sha256:25bd9799358edefa0e010ce2c587b093c3aba942e96aeaa99b6d0500ae1bf09c"},
]
flake8-todo = [
{file = "flake8-todo-0.7.tar.gz", hash = "sha256:6e4c5491ff838c06fe5a771b0e95ee15fc005ca57196011011280fc834a85915"},
@@ -952,25 +1030,28 @@ gitdb = [
{file = "gitdb-4.0.9.tar.gz", hash = "sha256:bac2fd45c0a1c9cf619e63a90d62bdc63892ef92387424b855792a6cabe789aa"},
]
gitpython = [
- {file = "GitPython-3.1.26-py3-none-any.whl", hash = "sha256:26ac35c212d1f7b16036361ca5cff3ec66e11753a0d677fb6c48fa4e1a9dd8d6"},
- {file = "GitPython-3.1.26.tar.gz", hash = "sha256:fc8868f63a2e6d268fb25f481995ba185a85a66fcad126f039323ff6635669ee"},
+ {file = "GitPython-3.1.27-py3-none-any.whl", hash = "sha256:5b68b000463593e05ff2b261acff0ff0972df8ab1b70d3cdbd41b546c8b8fc3d"},
+ {file = "GitPython-3.1.27.tar.gz", hash = "sha256:1c885ce809e8ba2d88a29befeb385fcea06338d3640712b59ca623c220bb5704"},
]
gunicorn = [
{file = "gunicorn-20.0.4-py2.py3-none-any.whl", hash = "sha256:cd4a810dd51bf497552cf3f863b575dabd73d6ad6a91075b65936b151cbf4f9c"},
{file = "gunicorn-20.0.4.tar.gz", hash = "sha256:1904bb2b8a43658807108d59c3f3d56c2b6121a701161de0ddf9ad140073c626"},
]
+h11 = [
+ {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"},
+ {file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"},
+]
+httpcore = []
+httpx = []
identify = [
- {file = "identify-2.4.6-py2.py3-none-any.whl", hash = "sha256:cf06b1639e0dca0c184b1504d8b73448c99a68e004a80524c7923b95f7b6837c"},
- {file = "identify-2.4.6.tar.gz", hash = "sha256:233679e3f61a02015d4293dbccf16aa0e4996f868bd114688b8c124f18826706"},
+ {file = "identify-2.5.1-py2.py3-none-any.whl", hash = "sha256:0dca2ea3e4381c435ef9c33ba100a78a9b40c0bab11189c7cf121f75815efeaa"},
+ {file = "identify-2.5.1.tar.gz", hash = "sha256:3d11b16f3fe19f52039fb7e39c9c884b21cb1b586988114fbe42671f03de3e82"},
]
idna = [
{file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"},
{file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"},
]
-importlib-metadata = [
- {file = "importlib_metadata-4.10.1-py3-none-any.whl", hash = "sha256:899e2a40a8c4a1aec681feef45733de8a6c58f3f6a0dbed2eb6574b4387a77b6"},
- {file = "importlib_metadata-4.10.1.tar.gz", hash = "sha256:951f0d8a5b7260e9db5e41d429285b5f451e928479f19d80818878527d36e95e"},
-]
+importlib-metadata = []
libsass = [
{file = "libsass-0.21.0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:06c8776417fe930714bdc930a3d7e795ae3d72be6ac883ff72a1b8f7c49e5ffb"},
{file = "libsass-0.21.0-cp27-cp27m-win32.whl", hash = "sha256:a005f298f64624f313a3ac618ab03f844c71d84ae4f4a4aec4b68d2a4ffe75eb"},
@@ -983,10 +1064,7 @@ libsass = [
{file = "libsass-0.21.0-cp38-abi3-macosx_12_0_arm64.whl", hash = "sha256:c9ec490609752c1d81ff6290da33485aa7cb6d7365ac665b74464c1b7d97f7da"},
{file = "libsass-0.21.0.tar.gz", hash = "sha256:d5ba529d9ce668be9380563279f3ffe988f27bc5b299c5a28453df2e0b0fbaf2"},
]
-markdown = [
- {file = "Markdown-3.3.6-py3-none-any.whl", hash = "sha256:9923332318f843411e9932237530df53162e29dc7a4e2b91e35764583c46c9a3"},
- {file = "Markdown-3.3.6.tar.gz", hash = "sha256:76df8ae32294ec39dcf89340382882dfa12975f87f45c3ed1ecdb1e8cefc7006"},
-]
+markdown = []
mccabe = [
{file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
{file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
@@ -995,63 +1073,48 @@ mslex = [
{file = "mslex-0.3.0-py2.py3-none-any.whl", hash = "sha256:380cb14abf8fabf40e56df5c8b21a6d533dc5cbdcfe42406bbf08dda8f42e42a"},
{file = "mslex-0.3.0.tar.gz", hash = "sha256:4a1ac3f25025cad78ad2fe499dd16d42759f7a3801645399cce5c404415daa97"},
]
-nodeenv = [
- {file = "nodeenv-1.6.0-py2.py3-none-any.whl", hash = "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"},
- {file = "nodeenv-1.6.0.tar.gz", hash = "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b"},
-]
-pbr = [
- {file = "pbr-5.8.0-py2.py3-none-any.whl", hash = "sha256:176e8560eaf61e127817ef93d8a844803abb27a4d4637f0ff3bb783129be2e0a"},
- {file = "pbr-5.8.0.tar.gz", hash = "sha256:672d8ebee84921862110f23fcec2acea191ef58543d34dfe9ef3d9f13c31cddf"},
-]
-pep8-naming = [
- {file = "pep8-naming-0.12.1.tar.gz", hash = "sha256:bb2455947757d162aa4cad55dba4ce029005cd1692f2899a21d51d8630ca7841"},
- {file = "pep8_naming-0.12.1-py2.py3-none-any.whl", hash = "sha256:4a8daeaeb33cfcde779309fc0c9c0a68a3bbe2ad8a8308b763c5068f86eb9f37"},
-]
+nodeenv = []
+pbr = []
+pep8-naming = []
platformdirs = [
- {file = "platformdirs-2.4.1-py3-none-any.whl", hash = "sha256:1d7385c7db91728b83efd0ca99a5afb296cab9d0ed8313a45ed8ba17967ecfca"},
- {file = "platformdirs-2.4.1.tar.gz", hash = "sha256:440633ddfebcc36264232365d7840a970e75e1018d15b4327d11f91909045fda"},
-]
-pre-commit = [
- {file = "pre_commit-2.17.0-py2.py3-none-any.whl", hash = "sha256:725fa7459782d7bec5ead072810e47351de01709be838c2ce1726b9591dad616"},
- {file = "pre_commit-2.17.0.tar.gz", hash = "sha256:c1a8040ff15ad3d648c70cc3e55b93e4d2d5b687320955505587fd79bbaed06a"},
-]
-prometheus-client = [
- {file = "prometheus_client-0.13.1-py3-none-any.whl", hash = "sha256:357a447fd2359b0a1d2e9b311a0c5778c330cfbe186d880ad5a6b39884652316"},
- {file = "prometheus_client-0.13.1.tar.gz", hash = "sha256:ada41b891b79fca5638bd5cfe149efa86512eaa55987893becd2c6d8d0a5dfc5"},
+ {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"},
+ {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"},
]
+pre-commit = []
+prometheus-client = []
psutil = [
- {file = "psutil-5.9.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:55ce319452e3d139e25d6c3f85a1acf12d1607ddedea5e35fb47a552c051161b"},
- {file = "psutil-5.9.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:7336292a13a80eb93c21f36bde4328aa748a04b68c13d01dfddd67fc13fd0618"},
- {file = "psutil-5.9.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:cb8d10461c1ceee0c25a64f2dd54872b70b89c26419e147a05a10b753ad36ec2"},
- {file = "psutil-5.9.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:7641300de73e4909e5d148e90cc3142fb890079e1525a840cf0dfd39195239fd"},
- {file = "psutil-5.9.0-cp27-none-win32.whl", hash = "sha256:ea42d747c5f71b5ccaa6897b216a7dadb9f52c72a0fe2b872ef7d3e1eacf3ba3"},
- {file = "psutil-5.9.0-cp27-none-win_amd64.whl", hash = "sha256:ef216cc9feb60634bda2f341a9559ac594e2eeaadd0ba187a4c2eb5b5d40b91c"},
- {file = "psutil-5.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90a58b9fcae2dbfe4ba852b57bd4a1dded6b990a33d6428c7614b7d48eccb492"},
- {file = "psutil-5.9.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff0d41f8b3e9ebb6b6110057e40019a432e96aae2008951121ba4e56040b84f3"},
- {file = "psutil-5.9.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:742c34fff804f34f62659279ed5c5b723bb0195e9d7bd9907591de9f8f6558e2"},
- {file = "psutil-5.9.0-cp310-cp310-win32.whl", hash = "sha256:8293942e4ce0c5689821f65ce6522ce4786d02af57f13c0195b40e1edb1db61d"},
- {file = "psutil-5.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:9b51917c1af3fa35a3f2dabd7ba96a2a4f19df3dec911da73875e1edaf22a40b"},
- {file = "psutil-5.9.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e9805fed4f2a81de98ae5fe38b75a74c6e6ad2df8a5c479594c7629a1fe35f56"},
- {file = "psutil-5.9.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c51f1af02334e4b516ec221ee26b8fdf105032418ca5a5ab9737e8c87dafe203"},
- {file = "psutil-5.9.0-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32acf55cb9a8cbfb29167cd005951df81b567099295291bcfd1027365b36591d"},
- {file = "psutil-5.9.0-cp36-cp36m-win32.whl", hash = "sha256:e5c783d0b1ad6ca8a5d3e7b680468c9c926b804be83a3a8e95141b05c39c9f64"},
- {file = "psutil-5.9.0-cp36-cp36m-win_amd64.whl", hash = "sha256:d62a2796e08dd024b8179bd441cb714e0f81226c352c802fca0fd3f89eeacd94"},
- {file = "psutil-5.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3d00a664e31921009a84367266b35ba0aac04a2a6cad09c550a89041034d19a0"},
- {file = "psutil-5.9.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7779be4025c540d1d65a2de3f30caeacc49ae7a2152108adeaf42c7534a115ce"},
- {file = "psutil-5.9.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:072664401ae6e7c1bfb878c65d7282d4b4391f1bc9a56d5e03b5a490403271b5"},
- {file = "psutil-5.9.0-cp37-cp37m-win32.whl", hash = "sha256:df2c8bd48fb83a8408c8390b143c6a6fa10cb1a674ca664954de193fdcab36a9"},
- {file = "psutil-5.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1d7b433519b9a38192dfda962dd8f44446668c009833e1429a52424624f408b4"},
- {file = "psutil-5.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c3400cae15bdb449d518545cbd5b649117de54e3596ded84aacabfbb3297ead2"},
- {file = "psutil-5.9.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2237f35c4bbae932ee98902a08050a27821f8f6dfa880a47195e5993af4702d"},
- {file = "psutil-5.9.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1070a9b287846a21a5d572d6dddd369517510b68710fca56b0e9e02fd24bed9a"},
- {file = "psutil-5.9.0-cp38-cp38-win32.whl", hash = "sha256:76cebf84aac1d6da5b63df11fe0d377b46b7b500d892284068bacccf12f20666"},
- {file = "psutil-5.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:3151a58f0fbd8942ba94f7c31c7e6b310d2989f4da74fcbf28b934374e9bf841"},
- {file = "psutil-5.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:539e429da49c5d27d5a58e3563886057f8fc3868a5547b4f1876d9c0f007bccf"},
- {file = "psutil-5.9.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58c7d923dc209225600aec73aa2c4ae8ea33b1ab31bc11ef8a5933b027476f07"},
- {file = "psutil-5.9.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3611e87eea393f779a35b192b46a164b1d01167c9d323dda9b1e527ea69d697d"},
- {file = "psutil-5.9.0-cp39-cp39-win32.whl", hash = "sha256:4e2fb92e3aeae3ec3b7b66c528981fd327fb93fd906a77215200404444ec1845"},
- {file = "psutil-5.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:7d190ee2eaef7831163f254dc58f6d2e2a22e27382b936aab51c835fc080c3d3"},
- {file = "psutil-5.9.0.tar.gz", hash = "sha256:869842dbd66bb80c3217158e629d6fceaecc3a3166d3d1faee515b05dd26ca25"},
+ {file = "psutil-5.9.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:799759d809c31aab5fe4579e50addf84565e71c1dc9f1c31258f159ff70d3f87"},
+ {file = "psutil-5.9.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:9272167b5f5fbfe16945be3db475b3ce8d792386907e673a209da686176552af"},
+ {file = "psutil-5.9.1-cp27-cp27m-win32.whl", hash = "sha256:0904727e0b0a038830b019551cf3204dd48ef5c6868adc776e06e93d615fc5fc"},
+ {file = "psutil-5.9.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e7e10454cb1ab62cc6ce776e1c135a64045a11ec4c6d254d3f7689c16eb3efd2"},
+ {file = "psutil-5.9.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:56960b9e8edcca1456f8c86a196f0c3d8e3e361320071c93378d41445ffd28b0"},
+ {file = "psutil-5.9.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:44d1826150d49ffd62035785a9e2c56afcea66e55b43b8b630d7706276e87f22"},
+ {file = "psutil-5.9.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7be9d7f5b0d206f0bbc3794b8e16fb7dbc53ec9e40bbe8787c6f2d38efcf6c9"},
+ {file = "psutil-5.9.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd9246e4cdd5b554a2ddd97c157e292ac11ef3e7af25ac56b08b455c829dca8"},
+ {file = "psutil-5.9.1-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29a442e25fab1f4d05e2655bb1b8ab6887981838d22effa2396d584b740194de"},
+ {file = "psutil-5.9.1-cp310-cp310-win32.whl", hash = "sha256:20b27771b077dcaa0de1de3ad52d22538fe101f9946d6dc7869e6f694f079329"},
+ {file = "psutil-5.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:58678bbadae12e0db55186dc58f2888839228ac9f41cc7848853539b70490021"},
+ {file = "psutil-5.9.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:3a76ad658641172d9c6e593de6fe248ddde825b5866464c3b2ee26c35da9d237"},
+ {file = "psutil-5.9.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a6a11e48cb93a5fa606306493f439b4aa7c56cb03fc9ace7f6bfa21aaf07c453"},
+ {file = "psutil-5.9.1-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:068935df39055bf27a29824b95c801c7a5130f118b806eee663cad28dca97685"},
+ {file = "psutil-5.9.1-cp36-cp36m-win32.whl", hash = "sha256:0f15a19a05f39a09327345bc279c1ba4a8cfb0172cc0d3c7f7d16c813b2e7d36"},
+ {file = "psutil-5.9.1-cp36-cp36m-win_amd64.whl", hash = "sha256:db417f0865f90bdc07fa30e1aadc69b6f4cad7f86324b02aa842034efe8d8c4d"},
+ {file = "psutil-5.9.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:91c7ff2a40c373d0cc9121d54bc5f31c4fa09c346528e6a08d1845bce5771ffc"},
+ {file = "psutil-5.9.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fea896b54f3a4ae6f790ac1d017101252c93f6fe075d0e7571543510f11d2676"},
+ {file = "psutil-5.9.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3054e923204b8e9c23a55b23b6df73a8089ae1d075cb0bf711d3e9da1724ded4"},
+ {file = "psutil-5.9.1-cp37-cp37m-win32.whl", hash = "sha256:d2d006286fbcb60f0b391741f520862e9b69f4019b4d738a2a45728c7e952f1b"},
+ {file = "psutil-5.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:b14ee12da9338f5e5b3a3ef7ca58b3cba30f5b66f7662159762932e6d0b8f680"},
+ {file = "psutil-5.9.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:19f36c16012ba9cfc742604df189f2f28d2720e23ff7d1e81602dbe066be9fd1"},
+ {file = "psutil-5.9.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:944c4b4b82dc4a1b805329c980f270f170fdc9945464223f2ec8e57563139cf4"},
+ {file = "psutil-5.9.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b6750a73a9c4a4e689490ccb862d53c7b976a2a35c4e1846d049dcc3f17d83b"},
+ {file = "psutil-5.9.1-cp38-cp38-win32.whl", hash = "sha256:a8746bfe4e8f659528c5c7e9af5090c5a7d252f32b2e859c584ef7d8efb1e689"},
+ {file = "psutil-5.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:79c9108d9aa7fa6fba6e668b61b82facc067a6b81517cab34d07a84aa89f3df0"},
+ {file = "psutil-5.9.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:28976df6c64ddd6320d281128817f32c29b539a52bdae5e192537bc338a9ec81"},
+ {file = "psutil-5.9.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b88f75005586131276634027f4219d06e0561292be8bd6bc7f2f00bdabd63c4e"},
+ {file = "psutil-5.9.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:645bd4f7bb5b8633803e0b6746ff1628724668681a434482546887d22c7a9537"},
+ {file = "psutil-5.9.1-cp39-cp39-win32.whl", hash = "sha256:32c52611756096ae91f5d1499fe6c53b86f4a9ada147ee42db4991ba1520e574"},
+ {file = "psutil-5.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:f65f9a46d984b8cd9b3750c2bdb419b2996895b005aefa6cbaba9a143b1ce2c5"},
+ {file = "psutil-5.9.1.tar.gz", hash = "sha256:57f1819b5d9e95cdfb0c881a8a5b7d542ed0b7c522d575706a80bedc848c8954"},
]
psycopg2-binary = [
{file = "psycopg2-binary-2.8.6.tar.gz", hash = "sha256:11b9c0ebce097180129e422379b824ae21c8f2a6596b159c7659e2e5a00e1aa0"},
@@ -1098,10 +1161,7 @@ pydocstyle = [
{file = "pydocstyle-6.1.1-py3-none-any.whl", hash = "sha256:6987826d6775056839940041beef5c08cc7e3d71d63149b48e36727f70144dc4"},
{file = "pydocstyle-6.1.1.tar.gz", hash = "sha256:1d41b7c459ba0ee6c345f2eb9ae827cab14a7533a88c5c6f7e94923f72df92dc"},
]
-pyfakefs = [
- {file = "pyfakefs-4.5.4-py3-none-any.whl", hash = "sha256:e0cc0d22cb74badf4fb2143a112817d7aea1a58ee9dca015a68bf38c3691cb52"},
- {file = "pyfakefs-4.5.4.tar.gz", hash = "sha256:5b5951e873f73bf12e3a19d8e4470c4b7962c51df753cf8c4caaf64e24a0a323"},
-]
+pyfakefs = []
pyflakes = [
{file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"},
{file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"},
@@ -1115,8 +1175,8 @@ python-frontmatter = [
{file = "python_frontmatter-1.0.0-py3-none-any.whl", hash = "sha256:766ae75f1b301ffc5fe3494339147e0fd80bc3deff3d7590a93991978b579b08"},
]
pytz = [
- {file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"},
- {file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"},
+ {file = "pytz-2022.1-py2.py3-none-any.whl", hash = "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c"},
+ {file = "pytz-2022.1.tar.gz", hash = "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7"},
]
pyyaml = [
{file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"},
@@ -1149,9 +1209,10 @@ pyyaml = [
{file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"},
{file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"},
]
-requests = [
- {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"},
- {file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"},
+requests = []
+rfc3986 = [
+ {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"},
+ {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"},
]
sentry-sdk = [
{file = "sentry-sdk-0.20.3.tar.gz", hash = "sha256:4ae8d1ced6c67f1c8ea51d82a16721c166c489b76876c9f2c202b8a50334b237"},
@@ -1165,6 +1226,10 @@ smmap = [
{file = "smmap-5.0.0-py3-none-any.whl", hash = "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94"},
{file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"},
]
+sniffio = [
+ {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"},
+ {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"},
+]
snowballstemmer = [
{file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"},
{file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"},
@@ -1185,19 +1250,14 @@ toml = [
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
]
-urllib3 = [
- {file = "urllib3-1.26.8-py2.py3-none-any.whl", hash = "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed"},
- {file = "urllib3-1.26.8.tar.gz", hash = "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c"},
-]
-virtualenv = [
- {file = "virtualenv-20.13.0-py2.py3-none-any.whl", hash = "sha256:339f16c4a86b44240ba7223d0f93a7887c3ca04b5f9c8129da7958447d079b09"},
- {file = "virtualenv-20.13.0.tar.gz", hash = "sha256:d8458cf8d59d0ea495ad9b34c2599487f8a7772d796f9910858376d1600dd2dd"},
-]
+tzdata = []
+urllib3 = []
+virtualenv = []
whitenoise = [
{file = "whitenoise-5.3.0-py2.py3-none-any.whl", hash = "sha256:d963ef25639d1417e8a247be36e6aedd8c7c6f0a08adcb5a89146980a96b577c"},
{file = "whitenoise-5.3.0.tar.gz", hash = "sha256:d234b871b52271ae7ed6d9da47ffe857c76568f11dd30e28e18c5869dbd11e12"},
]
zipp = [
- {file = "zipp-3.7.0-py3-none-any.whl", hash = "sha256:b47250dd24f92b7dd6a0a8fc5244da14608f3ca90a5efcd37a3b1642fac9a375"},
- {file = "zipp-3.7.0.tar.gz", hash = "sha256:9f50f446828eb9d45b267433fd3e9da8d801f614129124863f9c51ebceafb87d"},
+ {file = "zipp-3.8.0-py3-none-any.whl", hash = "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099"},
+ {file = "zipp-3.8.0.tar.gz", hash = "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad"},
]
diff --git a/pydis_site/apps/api/pagination.py b/pydis_site/apps/api/pagination.py
index 2a325460..61707d33 100644
--- a/pydis_site/apps/api/pagination.py
+++ b/pydis_site/apps/api/pagination.py
@@ -1,7 +1,6 @@
-import typing
-
from rest_framework.pagination import LimitOffsetPagination
from rest_framework.response import Response
+from rest_framework.utils.serializer_helpers import ReturnList
class LimitOffsetPaginationExtended(LimitOffsetPagination):
@@ -44,6 +43,6 @@ class LimitOffsetPaginationExtended(LimitOffsetPagination):
default_limit = 100
- def get_paginated_response(self, data: typing.Any) -> Response:
+ def get_paginated_response(self, data: ReturnList) -> Response:
"""Override to skip metadata i.e. `count`, `next`, and `previous`."""
return Response(data)
diff --git a/pydis_site/apps/api/tests/migrations/__init__.py b/pydis_site/apps/api/tests/migrations/__init__.py
deleted file mode 100644
index 38e42ffc..00000000
--- a/pydis_site/apps/api/tests/migrations/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-"""This submodule contains tests for functions used in data migrations."""
diff --git a/pydis_site/apps/api/tests/migrations/base.py b/pydis_site/apps/api/tests/migrations/base.py
deleted file mode 100644
index 0c0a5bd0..00000000
--- a/pydis_site/apps/api/tests/migrations/base.py
+++ /dev/null
@@ -1,102 +0,0 @@
-"""Includes utilities for testing migrations."""
-from django.db import connection
-from django.db.migrations.executor import MigrationExecutor
-from django.test import TestCase
-
-
-class MigrationsTestCase(TestCase):
- """
- A `TestCase` subclass to test migration files.
-
- To be able to properly test a migration, we will need to inject data into the test database
- before the migrations we want to test are applied, but after the older migrations have been
- applied. This makes sure that we are testing "as if" we were actually applying this migration
- to a database in the state it was in before introducing the new migration.
-
- To set up a MigrationsTestCase, create a subclass of this class and set the following
- class-level attributes:
-
- - app: The name of the app that contains the migrations (e.g., `'api'`)
- - migration_prior: The name* of the last migration file before the migrations you want to test
- - migration_target: The name* of the last migration file we want to test
-
- *) Specify the file names without a path or the `.py` file extension.
-
- Additionally, overwrite the `setUpMigrationData` in the subclass to inject data into the
- database before the migrations we want to test are applied. Please read the docstring of the
- method for more information. An optional hook, `setUpPostMigrationData` is also provided.
- """
-
- # These class-level attributes should be set in classes that inherit from this base class.
- app = None
- migration_prior = None
- migration_target = None
-
- @classmethod
- def setUpTestData(cls):
- """
- Injects data into the test database prior to the migration we're trying to test.
-
- This class methods reverts the test database back to the state of the last migration file
- prior to the migrations we want to test. It will then allow the user to inject data into the
- test database by calling the `setUpMigrationData` hook. After the data has been injected, it
- will apply the migrations we want to test and call the `setUpPostMigrationData` hook. The
- user can now test if the migration correctly migrated the injected test data.
- """
- if not cls.app:
- raise ValueError("The `app` attribute was not set.")
-
- if not cls.migration_prior or not cls.migration_target:
- raise ValueError("Both ` migration_prior` and `migration_target` need to be set.")
-
- cls.migrate_from = [(cls.app, cls.migration_prior)]
- cls.migrate_to = [(cls.app, cls.migration_target)]
-
- # Reverse to database state prior to the migrations we want to test
- executor = MigrationExecutor(connection)
- executor.migrate(cls.migrate_from)
-
- # Call the data injection hook with the current state of the project
- old_apps = executor.loader.project_state(cls.migrate_from).apps
- cls.setUpMigrationData(old_apps)
-
- # Run the migrations we want to test
- executor = MigrationExecutor(connection)
- executor.loader.build_graph()
- executor.migrate(cls.migrate_to)
-
- # Save the project state so we're able to work with the correct model states
- cls.apps = executor.loader.project_state(cls.migrate_to).apps
-
- # Call `setUpPostMigrationData` to potentially set up post migration data used in testing
- cls.setUpPostMigrationData(cls.apps)
-
- @classmethod
- def setUpMigrationData(cls, apps):
- """
- Override this method to inject data into the test database before the migration is applied.
-
- This method will be called after setting up the database according to the migrations that
- come before the migration(s) we are trying to test, but before the to-be-tested migration(s)
- are applied. This allows us to simulate a database state just prior to the migrations we are
- trying to test.
-
- To make sure we're creating objects according to the state the models were in at this point
- in the migration history, use `apps.get_model(app_name: str, model_name: str)` to get the
- appropriate model, e.g.:
-
- >>> Infraction = apps.get_model('api', 'Infraction')
- """
- pass
-
- @classmethod
- def setUpPostMigrationData(cls, apps):
- """
- Set up additional test data after the target migration has been applied.
-
- Use `apps.get_model(app_name: str, model_name: str)` to get the correct instances of the
- model classes:
-
- >>> Infraction = apps.get_model('api', 'Infraction')
- """
- pass
diff --git a/pydis_site/apps/api/tests/migrations/test_active_infraction_migration.py b/pydis_site/apps/api/tests/migrations/test_active_infraction_migration.py
deleted file mode 100644
index 8dc29b34..00000000
--- a/pydis_site/apps/api/tests/migrations/test_active_infraction_migration.py
+++ /dev/null
@@ -1,496 +0,0 @@
-"""Tests for the data migration in `filename`."""
-import logging
-from collections import ChainMap, namedtuple
-from datetime import timedelta
-from itertools import count
-from typing import Dict, Iterable, Type, Union
-
-from django.db.models import Q
-from django.forms.models import model_to_dict
-from django.utils import timezone
-
-from pydis_site.apps.api.models import Infraction, User
-from .base import MigrationsTestCase
-
-log = logging.getLogger(__name__)
-log.setLevel(logging.DEBUG)
-
-
-InfractionHistory = namedtuple('InfractionHistory', ("user_id", "infraction_history"))
-
-
-class InfractionFactory:
- """Factory that creates infractions for a User instance."""
-
- infraction_id = count(1)
- user_id = count(1)
- default_values = {
- 'active': True,
- 'expires_at': None,
- 'hidden': False,
- }
-
- @classmethod
- def create(
- cls,
- actor: User,
- infractions: Iterable[Dict[str, Union[str, int, bool]]],
- infraction_model: Type[Infraction] = Infraction,
- user_model: Type[User] = User,
- ) -> InfractionHistory:
- """
- Creates `infractions` for the `user` with the given `actor`.
-
- The `infractions` dictionary can contain the following fields:
- - `type` (required)
- - `active` (default: True)
- - `expires_at` (default: None; i.e, permanent)
- - `hidden` (default: False).
-
- The parameters `infraction_model` and `user_model` can be used to pass in an instance of
- both model classes from a different migration/project state.
- """
- user_id = next(cls.user_id)
- user = user_model.objects.create(
- id=user_id,
- name=f"Infracted user {user_id}",
- discriminator=user_id,
- avatar_hash=None,
- )
- infraction_history = []
-
- for infraction in infractions:
- infraction = dict(infraction)
- infraction["id"] = next(cls.infraction_id)
- infraction = ChainMap(infraction, cls.default_values)
- new_infraction = infraction_model.objects.create(
- user=user,
- actor=actor,
- type=infraction["type"],
- reason=f"`{infraction['type']}` infraction (ID: {infraction['id']} of {user}",
- active=infraction['active'],
- hidden=infraction['hidden'],
- expires_at=infraction['expires_at'],
- )
- infraction_history.append(new_infraction)
-
- return InfractionHistory(user_id=user_id, infraction_history=infraction_history)
-
-
-class InfractionFactoryTests(MigrationsTestCase):
- """Tests for the InfractionFactory."""
-
- app = "api"
- migration_prior = "0046_reminder_jump_url"
- migration_target = "0046_reminder_jump_url"
-
- @classmethod
- def setUpPostMigrationData(cls, apps):
- """Create a default actor for all infractions."""
- cls.infraction_model = apps.get_model('api', 'Infraction')
- cls.user_model = apps.get_model('api', 'User')
-
- cls.actor = cls.user_model.objects.create(
- id=9999,
- name="Unknown Moderator",
- discriminator=1040,
- avatar_hash=None,
- )
-
- def test_infraction_factory_total_count(self):
- """Does the test database hold as many infractions as we tried to create?"""
- InfractionFactory.create(
- actor=self.actor,
- infractions=(
- {'type': 'kick', 'active': False, 'hidden': False},
- {'type': 'ban', 'active': True, 'hidden': False},
- {'type': 'note', 'active': False, 'hidden': True},
- ),
- infraction_model=self.infraction_model,
- user_model=self.user_model,
- )
- database_count = Infraction.objects.all().count()
- self.assertEqual(3, database_count)
-
- def test_infraction_factory_multiple_users(self):
- """Does the test database hold as many infractions as we tried to create?"""
- for _user in range(5):
- InfractionFactory.create(
- actor=self.actor,
- infractions=(
- {'type': 'kick', 'active': False, 'hidden': True},
- {'type': 'ban', 'active': True, 'hidden': False},
- ),
- infraction_model=self.infraction_model,
- user_model=self.user_model,
- )
-
- # Check if infractions and users are recorded properly in the database
- database_count = Infraction.objects.all().count()
- self.assertEqual(database_count, 10)
-
- user_count = User.objects.all().count()
- self.assertEqual(user_count, 5 + 1)
-
- def test_infraction_factory_sets_correct_fields(self):
- """Does the InfractionFactory set the correct attributes?"""
- infractions = (
- {
- 'type': 'note',
- 'active': False,
- 'hidden': True,
- 'expires_at': timezone.now()
- },
- {'type': 'warning', 'active': False, 'hidden': False, 'expires_at': None},
- {'type': 'watch', 'active': False, 'hidden': True, 'expires_at': None},
- {'type': 'mute', 'active': True, 'hidden': False, 'expires_at': None},
- {'type': 'kick', 'active': True, 'hidden': True, 'expires_at': None},
- {'type': 'ban', 'active': True, 'hidden': False, 'expires_at': None},
- {
- 'type': 'superstar',
- 'active': True,
- 'hidden': True,
- 'expires_at': timezone.now()
- },
- )
-
- InfractionFactory.create(
- actor=self.actor,
- infractions=infractions,
- infraction_model=self.infraction_model,
- user_model=self.user_model,
- )
-
- for infraction in infractions:
- with self.subTest(**infraction):
- self.assertTrue(Infraction.objects.filter(**infraction).exists())
-
-
-class ActiveInfractionMigrationTests(MigrationsTestCase):
- """
- Tests the active infraction data migration.
-
- The active infraction data migration should do the following things:
-
- 1. migrates all active notes, warnings, and kicks to an inactive status;
- 2. migrates all users with multiple active infractions of a single type to have only one active
- infraction of that type. The infraction with the longest duration stays active.
- """
-
- app = "api"
- migration_prior = "0046_reminder_jump_url"
- migration_target = "0047_active_infractions_migration"
-
- @classmethod
- def setUpMigrationData(cls, apps):
- """Sets up an initial database state that contains the relevant test cases."""
- # Fetch the Infraction and User model in the current migration state
- cls.infraction_model = apps.get_model('api', 'Infraction')
- cls.user_model = apps.get_model('api', 'User')
-
- cls.created_infractions = {}
-
- # Moderator that serves as actor for all infractions
- cls.user_moderator = cls.user_model.objects.create(
- id=9999,
- name="Olivier de Vienne",
- discriminator=1040,
- avatar_hash=None,
- )
-
- # User #1: clean user with no infractions
- cls.created_infractions["no infractions"] = InfractionFactory.create(
- actor=cls.user_moderator,
- infractions=[],
- infraction_model=cls.infraction_model,
- user_model=cls.user_model,
- )
-
- # User #2: One inactive note infraction
- cls.created_infractions["one inactive note"] = InfractionFactory.create(
- actor=cls.user_moderator,
- infractions=(
- {'type': 'note', 'active': False, 'hidden': True},
- ),
- infraction_model=cls.infraction_model,
- user_model=cls.user_model,
- )
-
- # User #3: One active note infraction
- cls.created_infractions["one active note"] = InfractionFactory.create(
- actor=cls.user_moderator,
- infractions=(
- {'type': 'note', 'active': True, 'hidden': True},
- ),
- infraction_model=cls.infraction_model,
- user_model=cls.user_model,
- )
-
- # User #4: One active and one inactive note infraction
- cls.created_infractions["one active and one inactive note"] = InfractionFactory.create(
- actor=cls.user_moderator,
- infractions=(
- {'type': 'note', 'active': False, 'hidden': True},
- {'type': 'note', 'active': True, 'hidden': True},
- ),
- infraction_model=cls.infraction_model,
- user_model=cls.user_model,
- )
-
- # User #5: Once active note, one active kick, once active warning
- cls.created_infractions["active note, kick, warning"] = InfractionFactory.create(
- actor=cls.user_moderator,
- infractions=(
- {'type': 'note', 'active': True, 'hidden': True},
- {'type': 'kick', 'active': True, 'hidden': True},
- {'type': 'warning', 'active': True, 'hidden': True},
- ),
- infraction_model=cls.infraction_model,
- user_model=cls.user_model,
- )
-
- # User #6: One inactive ban and one active ban
- cls.created_infractions["one inactive and one active ban"] = InfractionFactory.create(
- actor=cls.user_moderator,
- infractions=(
- {'type': 'ban', 'active': False, 'hidden': True},
- {'type': 'ban', 'active': True, 'hidden': True},
- ),
- infraction_model=cls.infraction_model,
- user_model=cls.user_model,
- )
-
- # User #7: Two active permanent bans
- cls.created_infractions["two active perm bans"] = InfractionFactory.create(
- actor=cls.user_moderator,
- infractions=(
- {'type': 'ban', 'active': True, 'hidden': True},
- {'type': 'ban', 'active': True, 'hidden': True},
- ),
- infraction_model=cls.infraction_model,
- user_model=cls.user_model,
- )
-
- # User #8: Multiple active temporary bans
- cls.created_infractions["multiple active temp bans"] = InfractionFactory.create(
- actor=cls.user_moderator,
- infractions=(
- {
- 'type': 'ban',
- 'active': True,
- 'hidden': True,
- 'expires_at': timezone.now() + timedelta(days=1)
- },
- {
- 'type': 'ban',
- 'active': True,
- 'hidden': True,
- 'expires_at': timezone.now() + timedelta(days=10)
- },
- {
- 'type': 'ban',
- 'active': True,
- 'hidden': True,
- 'expires_at': timezone.now() + timedelta(days=20)
- },
- {
- 'type': 'ban',
- 'active': True,
- 'hidden': True,
- 'expires_at': timezone.now() + timedelta(days=5)
- },
- ),
- infraction_model=cls.infraction_model,
- user_model=cls.user_model,
- )
-
- # User #9: One active permanent ban, two active temporary bans
- cls.created_infractions["active perm, two active temp bans"] = InfractionFactory.create(
- actor=cls.user_moderator,
- infractions=(
- {
- 'type': 'ban',
- 'active': True,
- 'hidden': True,
- 'expires_at': timezone.now() + timedelta(days=10)
- },
- {
- 'type': 'ban',
- 'active': True,
- 'hidden': True,
- 'expires_at': None,
- },
- {
- 'type': 'ban',
- 'active': True,
- 'hidden': True,
- 'expires_at': timezone.now() + timedelta(days=7)
- },
- ),
- infraction_model=cls.infraction_model,
- user_model=cls.user_model,
- )
-
- # User #10: One inactive permanent ban, two active temporary bans
- cls.created_infractions["one inactive perm ban, two active temp bans"] = (
- InfractionFactory.create(
- actor=cls.user_moderator,
- infractions=(
- {
- 'type': 'ban',
- 'active': True,
- 'hidden': True,
- 'expires_at': timezone.now() + timedelta(days=10)
- },
- {
- 'type': 'ban',
- 'active': False,
- 'hidden': True,
- 'expires_at': None,
- },
- {
- 'type': 'ban',
- 'active': True,
- 'hidden': True,
- 'expires_at': timezone.now() + timedelta(days=7)
- },
- ),
- infraction_model=cls.infraction_model,
- user_model=cls.user_model,
- )
- )
-
- # User #11: Active ban, active mute, active superstar
- cls.created_infractions["active ban, mute, and superstar"] = InfractionFactory.create(
- actor=cls.user_moderator,
- infractions=(
- {'type': 'ban', 'active': True, 'hidden': True},
- {'type': 'mute', 'active': True, 'hidden': True},
- {'type': 'superstar', 'active': True, 'hidden': True},
- {'type': 'watch', 'active': True, 'hidden': True},
- ),
- infraction_model=cls.infraction_model,
- user_model=cls.user_model,
- )
-
- # User #12: Multiple active bans, active mutes, active superstars
- cls.created_infractions["multiple active bans, mutes, stars"] = InfractionFactory.create(
- actor=cls.user_moderator,
- infractions=(
- {'type': 'ban', 'active': True, 'hidden': True},
- {'type': 'ban', 'active': True, 'hidden': True},
- {'type': 'ban', 'active': True, 'hidden': True},
- {'type': 'mute', 'active': True, 'hidden': True},
- {'type': 'mute', 'active': True, 'hidden': True},
- {'type': 'mute', 'active': True, 'hidden': True},
- {'type': 'superstar', 'active': True, 'hidden': True},
- {'type': 'superstar', 'active': True, 'hidden': True},
- {'type': 'superstar', 'active': True, 'hidden': True},
- {'type': 'watch', 'active': True, 'hidden': True},
- {'type': 'watch', 'active': True, 'hidden': True},
- {'type': 'watch', 'active': True, 'hidden': True},
- ),
- infraction_model=cls.infraction_model,
- user_model=cls.user_model,
- )
-
- def test_all_never_active_types_became_inactive(self):
- """Are all infractions of a non-active type inactive after the migration?"""
- inactive_type_query = Q(type="note") | Q(type="warning") | Q(type="kick")
- self.assertFalse(
- self.infraction_model.objects.filter(inactive_type_query, active=True).exists()
- )
-
- def test_migration_left_clean_user_without_infractions(self):
- """Do users without infractions have no infractions after the migration?"""
- user_id, infraction_history = self.created_infractions["no infractions"]
- self.assertFalse(
- self.infraction_model.objects.filter(user__id=user_id).exists()
- )
-
- def test_migration_left_user_with_inactive_note_untouched(self):
- """Did the migration leave users with only an inactive note untouched?"""
- user_id, infraction_history = self.created_infractions["one inactive note"]
- inactive_note = infraction_history[0]
- self.assertTrue(
- self.infraction_model.objects.filter(**model_to_dict(inactive_note)).exists()
- )
-
- def test_migration_only_touched_active_field_of_active_note(self):
- """Does the migration only change the `active` field?"""
- user_id, infraction_history = self.created_infractions["one active note"]
- note = model_to_dict(infraction_history[0])
- note['active'] = False
- self.assertTrue(
- self.infraction_model.objects.filter(**note).exists()
- )
-
- def test_migration_only_touched_active_field_of_active_note_left_inactive_untouched(self):
- """Does the migration only change the `active` field of active notes?"""
- user_id, infraction_history = self.created_infractions["one active and one inactive note"]
- for note in infraction_history:
- with self.subTest(active=note.active):
- note = model_to_dict(note)
- note['active'] = False
- self.assertTrue(
- self.infraction_model.objects.filter(**note).exists()
- )
-
- def test_migration_migrates_all_nonactive_types_to_inactive(self):
- """Do we set the `active` field of all non-active infractions to `False`?"""
- user_id, infraction_history = self.created_infractions["active note, kick, warning"]
- self.assertFalse(
- self.infraction_model.objects.filter(user__id=user_id, active=True).exists()
- )
-
- def test_migration_leaves_user_with_one_active_ban_untouched(self):
- """Do we leave a user with one active and one inactive ban untouched?"""
- user_id, infraction_history = self.created_infractions["one inactive and one active ban"]
- for infraction in infraction_history:
- with self.subTest(active=infraction.active):
- self.assertTrue(
- self.infraction_model.objects.filter(**model_to_dict(infraction)).exists()
- )
-
- def test_migration_turns_double_active_perm_ban_into_single_active_perm_ban(self):
- """Does the migration turn two active permanent bans into one active permanent ban?"""
- user_id, infraction_history = self.created_infractions["two active perm bans"]
- active_count = self.infraction_model.objects.filter(user__id=user_id, active=True).count()
- self.assertEqual(active_count, 1)
-
- def test_migration_leaves_temporary_ban_with_longest_duration_active(self):
- """Does the migration turn two active permanent bans into one active permanent ban?"""
- user_id, infraction_history = self.created_infractions["multiple active temp bans"]
- active_ban = self.infraction_model.objects.get(user__id=user_id, active=True)
- self.assertEqual(active_ban.expires_at, infraction_history[2].expires_at)
-
- def test_migration_leaves_permanent_ban_active(self):
- """Does the migration leave the permanent ban active?"""
- user_id, infraction_history = self.created_infractions["active perm, two active temp bans"]
- active_ban = self.infraction_model.objects.get(user__id=user_id, active=True)
- self.assertIsNone(active_ban.expires_at)
-
- def test_migration_leaves_longest_temp_ban_active_with_inactive_permanent_ban(self):
- """Does the longest temp ban stay active, even with an inactive perm ban present?"""
- user_id, infraction_history = self.created_infractions[
- "one inactive perm ban, two active temp bans"
- ]
- active_ban = self.infraction_model.objects.get(user__id=user_id, active=True)
- self.assertEqual(active_ban.expires_at, infraction_history[0].expires_at)
-
- def test_migration_leaves_all_active_types_active_if_one_of_each_exists(self):
- """Do all active infractions stay active if only one of each is present?"""
- user_id, infraction_history = self.created_infractions["active ban, mute, and superstar"]
- active_count = self.infraction_model.objects.filter(user__id=user_id, active=True).count()
- self.assertEqual(active_count, 4)
-
- def test_migration_reduces_all_active_types_to_a_single_active_infraction(self):
- """Do we reduce all of the infraction types to one active infraction?"""
- user_id, infraction_history = self.created_infractions["multiple active bans, mutes, stars"]
- active_infractions = self.infraction_model.objects.filter(user__id=user_id, active=True)
- self.assertEqual(len(active_infractions), 4)
- types_observed = [infraction.type for infraction in active_infractions]
-
- for infraction_type in ('ban', 'mute', 'superstar', 'watch'):
- with self.subTest(type=infraction_type):
- self.assertIn(infraction_type, types_observed)
diff --git a/pydis_site/apps/api/tests/migrations/test_base.py b/pydis_site/apps/api/tests/migrations/test_base.py
deleted file mode 100644
index f69bc92c..00000000
--- a/pydis_site/apps/api/tests/migrations/test_base.py
+++ /dev/null
@@ -1,135 +0,0 @@
-import logging
-from unittest.mock import call, patch
-
-from django.db.migrations.loader import MigrationLoader
-from django.test import TestCase
-
-from .base import MigrationsTestCase, connection
-
-log = logging.getLogger(__name__)
-
-
-class SpanishInquisition(MigrationsTestCase):
- app = "api"
- migration_prior = "scragly"
- migration_target = "kosa"
-
-
-@patch("pydis_site.apps.api.tests.migrations.base.MigrationExecutor")
-class MigrationsTestCaseNoSideEffectsTests(TestCase):
- """Tests the MigrationTestCase class with actual migration side effects disabled."""
-
- def setUp(self):
- """Set up an instance of MigrationsTestCase for use in tests."""
- self.test_case = SpanishInquisition()
-
- def test_missing_app_class_raises_value_error(self, _migration_executor):
- """A MigrationsTestCase subclass should set the class-attribute `app`."""
- class Spam(MigrationsTestCase):
- pass
-
- spam = Spam()
- with self.assertRaises(ValueError, msg="The `app` attribute was not set."):
- spam.setUpTestData()
-
- def test_missing_migration_class_attributes_raise_value_error(self, _migration_executor):
- """A MigrationsTestCase subclass should set both `migration_prior` and `migration_target`"""
- class Eggs(MigrationsTestCase):
- app = "api"
- migration_target = "lemon"
-
- class Bacon(MigrationsTestCase):
- app = "api"
- migration_prior = "mark"
-
- instances = (Eggs(), Bacon())
-
- exception_message = "Both ` migration_prior` and `migration_target` need to be set."
- for instance in instances:
- with self.subTest(
- migration_prior=instance.migration_prior,
- migration_target=instance.migration_target,
- ):
- with self.assertRaises(ValueError, msg=exception_message):
- instance.setUpTestData()
-
- @patch(f"{__name__}.SpanishInquisition.setUpMigrationData")
- @patch(f"{__name__}.SpanishInquisition.setUpPostMigrationData")
- def test_migration_data_hooks_are_called_once(self, pre_hook, post_hook, _migration_executor):
- """The `setUpMigrationData` and `setUpPostMigrationData` hooks should be called once."""
- self.test_case.setUpTestData()
- for hook in (pre_hook, post_hook):
- with self.subTest(hook=repr(hook)):
- hook.assert_called_once()
-
- def test_migration_executor_is_instantiated_twice(self, migration_executor):
- """The `MigrationExecutor` should be instantiated with the database connection twice."""
- self.test_case.setUpTestData()
-
- expected_args = [call(connection), call(connection)]
- self.assertEqual(migration_executor.call_args_list, expected_args)
-
- def test_project_state_is_loaded_for_correct_migration_files_twice(self, migration_executor):
- """The `project_state` should first be loaded with `migrate_from`, then `migrate_to`."""
- self.test_case.setUpTestData()
-
- expected_args = [call(self.test_case.migrate_from), call(self.test_case.migrate_to)]
- self.assertEqual(migration_executor().loader.project_state.call_args_list, expected_args)
-
- def test_loader_build_graph_gets_called_once(self, migration_executor):
- """We should rebuild the migration graph before applying the second set of migrations."""
- self.test_case.setUpTestData()
-
- migration_executor().loader.build_graph.assert_called_once()
-
- def test_migration_executor_migrate_method_is_called_correctly_twice(self, migration_executor):
- """The migrate method of the executor should be called twice with the correct arguments."""
- self.test_case.setUpTestData()
-
- self.assertEqual(migration_executor().migrate.call_count, 2)
- calls = [call([('api', 'scragly')]), call([('api', 'kosa')])]
- migration_executor().migrate.assert_has_calls(calls)
-
-
-class LifeOfBrian(MigrationsTestCase):
- app = "api"
- migration_prior = "0046_reminder_jump_url"
- migration_target = "0048_add_infractions_unique_constraints_active"
-
- @classmethod
- def log_last_migration(cls):
- """Parses the applied migrations dictionary to log the last applied migration."""
- loader = MigrationLoader(connection)
- api_migrations = [
- migration for app, migration in loader.applied_migrations if app == cls.app
- ]
- last_migration = max(api_migrations, key=lambda name: int(name[:4]))
- log.info(f"The last applied migration: {last_migration}")
-
- @classmethod
- def setUpMigrationData(cls, apps):
- """Method that logs the last applied migration at this point."""
- cls.log_last_migration()
-
- @classmethod
- def setUpPostMigrationData(cls, apps):
- """Method that logs the last applied migration at this point."""
- cls.log_last_migration()
-
-
-class MigrationsTestCaseMigrationTest(TestCase):
- """Tests if `MigrationsTestCase` travels to the right points in the migration history."""
-
- def test_migrations_test_case_travels_to_correct_migrations_in_history(self):
- """The test case should first revert to `migration_prior`, then go to `migration_target`."""
- brian = LifeOfBrian()
-
- with self.assertLogs(log, level=logging.INFO) as logs:
- brian.setUpTestData()
-
- self.assertEqual(len(logs.records), 2)
-
- for time_point, record in zip(("migration_prior", "migration_target"), logs.records):
- with self.subTest(time_point=time_point):
- message = f"The last applied migration: {getattr(brian, time_point)}"
- self.assertEqual(record.getMessage(), message)
diff --git a/pydis_site/apps/api/tests/test_models.py b/pydis_site/apps/api/tests/test_models.py
index 0fad467c..c07d59cd 100644
--- a/pydis_site/apps/api/tests/test_models.py
+++ b/pydis_site/apps/api/tests/test_models.py
@@ -7,7 +7,6 @@ from pydis_site.apps.api.models import (
DeletedMessage,
DocumentationLink,
Infraction,
- Message,
MessageDeletionContext,
Nomination,
NominationEntry,
@@ -116,17 +115,6 @@ class StringDunderMethodTests(SimpleTestCase):
colour=0x5, permissions=0,
position=10,
),
- Message(
- id=45,
- author=User(
- id=444,
- name='bill',
- discriminator=5,
- ),
- channel_id=666,
- content="wooey",
- embeds=[]
- ),
MessageDeletionContext(
actor=User(
id=5555,
diff --git a/pydis_site/apps/content/apps.py b/pydis_site/apps/content/apps.py
index 1e300a48..96019e1c 100644
--- a/pydis_site/apps/content/apps.py
+++ b/pydis_site/apps/content/apps.py
@@ -4,4 +4,4 @@ from django.apps import AppConfig
class ContentConfig(AppConfig):
"""Django AppConfig for content app."""
- name = 'content'
+ name = 'pydis_site.apps.content'
diff --git a/pydis_site/apps/content/views/page_category.py b/pydis_site/apps/content/views/page_category.py
index 5af77aff..356eb021 100644
--- a/pydis_site/apps/content/views/page_category.py
+++ b/pydis_site/apps/content/views/page_category.py
@@ -3,7 +3,7 @@ from pathlib import Path
import frontmatter
from django.conf import settings
-from django.http import Http404
+from django.http import Http404, HttpRequest, HttpResponse
from django.views.generic import TemplateView
from pydis_site.apps.content import utils
@@ -12,7 +12,7 @@ from pydis_site.apps.content import utils
class PageOrCategoryView(TemplateView):
"""Handles pages and page categories."""
- def dispatch(self, request: t.Any, *args, **kwargs) -> t.Any:
+ def dispatch(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
"""Conform URL path location to the filesystem path."""
self.location = Path(kwargs.get("location", ""))
diff --git a/pydis_site/apps/events/apps.py b/pydis_site/apps/events/apps.py
index a1cf09ef..70762bc2 100644
--- a/pydis_site/apps/events/apps.py
+++ b/pydis_site/apps/events/apps.py
@@ -4,4 +4,4 @@ from django.apps import AppConfig
class EventsConfig(AppConfig):
"""Django AppConfig for events app."""
- name = 'events'
+ name = 'pydis_site.apps.events'
diff --git a/pydis_site/apps/home/tests/test_repodata_helpers.py b/pydis_site/apps/home/tests/test_repodata_helpers.py
index d43bd28e..4007eded 100644
--- a/pydis_site/apps/home/tests/test_repodata_helpers.py
+++ b/pydis_site/apps/home/tests/test_repodata_helpers.py
@@ -36,7 +36,7 @@ class TestRepositoryMetadataHelpers(TestCase):
"""Executed before each test method."""
self.home_view = HomeView()
- @mock.patch('requests.get', side_effect=mocked_requests_get)
+ @mock.patch('httpx.get', side_effect=mocked_requests_get)
def test_returns_metadata(self, _: mock.MagicMock):
"""Test if the _get_repo_data helper actually returns what it should."""
metadata = self.home_view._get_repo_data()
@@ -59,7 +59,7 @@ class TestRepositoryMetadataHelpers(TestCase):
self.assertIsInstance(metadata[0], RepositoryMetadata)
self.assertIsInstance(str(metadata[0]), str)
- @mock.patch('requests.get', side_effect=mocked_requests_get)
+ @mock.patch('httpx.get', side_effect=mocked_requests_get)
def test_refresh_stale_metadata(self, _: mock.MagicMock):
"""Test if the _get_repo_data helper will refresh when the data is stale."""
repo_data = RepositoryMetadata(
@@ -75,7 +75,7 @@ class TestRepositoryMetadataHelpers(TestCase):
self.assertIsInstance(metadata[0], RepositoryMetadata)
- @mock.patch('requests.get', side_effect=mocked_requests_get)
+ @mock.patch('httpx.get', side_effect=mocked_requests_get)
def test_returns_api_data(self, _: mock.MagicMock):
"""Tests if the _get_api_data helper returns what it should."""
api_data = self.home_view._get_api_data()
@@ -86,7 +86,7 @@ class TestRepositoryMetadataHelpers(TestCase):
self.assertIn(repo, api_data.keys())
self.assertIn("stargazers_count", api_data[repo])
- @mock.patch('requests.get', side_effect=mocked_requests_get)
+ @mock.patch('httpx.get', side_effect=mocked_requests_get)
def test_mocked_requests_get(self, mock_get: mock.MagicMock):
"""Tests if our mocked_requests_get is returning what it should."""
success_data = mock_get(HomeView.github_api)
@@ -98,7 +98,7 @@ class TestRepositoryMetadataHelpers(TestCase):
self.assertIsNotNone(success_data.json_data)
self.assertIsNone(fail_data.json_data)
- @mock.patch('requests.get')
+ @mock.patch('httpx.get')
def test_falls_back_to_database_on_error(self, mock_get: mock.MagicMock):
"""Tests that fallback to the database is performed when we get garbage back."""
repo_data = RepositoryMetadata(
@@ -117,7 +117,7 @@ class TestRepositoryMetadataHelpers(TestCase):
[item] = metadata
self.assertEqual(item, repo_data)
- @mock.patch('requests.get')
+ @mock.patch('httpx.get')
def test_falls_back_to_database_on_error_without_entries(self, mock_get: mock.MagicMock):
"""Tests that fallback to the database is performed when we get garbage back."""
mock_get.return_value.json.return_value = ['garbage']
diff --git a/pydis_site/apps/home/views/home.py b/pydis_site/apps/home/views/home.py
index 69e706c5..9bb1f8fd 100644
--- a/pydis_site/apps/home/views/home.py
+++ b/pydis_site/apps/home/views/home.py
@@ -1,7 +1,7 @@
import logging
from typing import Dict, List
-import requests
+import httpx
from django.core.handlers.wsgi import WSGIRequest
from django.http import HttpResponse
from django.shortcuts import render
@@ -56,12 +56,12 @@ class HomeView(View):
repo_dict = {}
try:
# Fetch the data from the GitHub API
- api_data: List[dict] = requests.get(
+ api_data: List[dict] = httpx.get(
self.github_api,
headers=self.headers,
timeout=settings.TIMEOUT_PERIOD
).json()
- except requests.exceptions.Timeout:
+ except httpx.TimeoutException:
log.error("Request to fetch GitHub repository metadata for timed out!")
return repo_dict
diff --git a/pydis_site/apps/redirect/apps.py b/pydis_site/apps/redirect/apps.py
index 9b70d169..0234bc93 100644
--- a/pydis_site/apps/redirect/apps.py
+++ b/pydis_site/apps/redirect/apps.py
@@ -4,4 +4,4 @@ from django.apps import AppConfig
class RedirectConfig(AppConfig):
"""AppConfig instance for Redirect app."""
- name = 'redirect'
+ name = 'pydis_site.apps.redirect'
diff --git a/pydis_site/apps/resources/apps.py b/pydis_site/apps/resources/apps.py
index e0c235bd..93117654 100644
--- a/pydis_site/apps/resources/apps.py
+++ b/pydis_site/apps/resources/apps.py
@@ -4,4 +4,4 @@ from django.apps import AppConfig
class ResourcesConfig(AppConfig):
"""AppConfig instance for Resources app."""
- name = 'resources'
+ name = 'pydis_site.apps.resources'
diff --git a/pydis_site/apps/staff/apps.py b/pydis_site/apps/staff/apps.py
index 70a15f40..d68a80c3 100644
--- a/pydis_site/apps/staff/apps.py
+++ b/pydis_site/apps/staff/apps.py
@@ -4,4 +4,4 @@ from django.apps import AppConfig
class StaffConfig(AppConfig):
"""Django AppConfig for the staff app."""
- name = 'staff'
+ name = 'pydis_site.apps.staff'
diff --git a/pydis_site/settings.py b/pydis_site/settings.py
index 17f220f3..03c16f4b 100644
--- a/pydis_site/settings.py
+++ b/pydis_site/settings.py
@@ -219,6 +219,9 @@ if DEBUG:
else:
PARENT_HOST = env('PARENT_HOST', default='pythondiscord.com')
+# Django Model Configuration
+DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
+
# Django REST framework
# https://www.django-rest-framework.org
REST_FRAMEWORK = {
diff --git a/pyproject.toml b/pyproject.toml
index b350836e..467fc8bc 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -7,14 +7,14 @@ license = "MIT"
[tool.poetry.dependencies]
python = "3.9.*"
-django = "~=3.1.14"
+django = "~=4.0"
django-environ = "~=0.4.5"
django-filter = "~=21.1"
-djangorestframework = "~=3.12.0"
+djangorestframework = "~=3.13"
psycopg2-binary = "~=2.8.0"
django-simple-bulma = "~=2.4"
whitenoise = "~=5.0"
-requests = "~=2.21"
+httpx = "~=0.23.0"
pyyaml = "~=5.1"
gunicorn = "~=20.0.4"
sentry-sdk = "~=0.19"
@@ -27,7 +27,7 @@ django-distill = "~=2.9.0"
coverage = "~=5.0"
flake8 = "~=3.7"
flake8-annotations = "~=2.0"
-flake8-bandit = "~=2.1"
+flake8-bandit = "~=3.0"
flake8-bugbear = "~=20.1"
flake8-docstrings = "~=1.5"
flake8-import-order = "~=0.18"