From 436a2f2df0a1996b2c0b39f73dbe764b45e9f342 Mon Sep 17 00:00:00 2001 From: HladczukLe Date: Sun, 3 Dec 2023 12:16:41 -0300 Subject: [PATCH 01/25] feat(syntax_highlighting): Add syntax highlighting support to the submission form --- apps/submissions/forms.py | 10 +-- poetry.lock | 129 ++++++++++++++++++++++++------------ pyproject.toml | 1 + server/settings/base.py | 3 + templates/tasks/detail.html | 51 +++++++++++++- 5 files changed, 147 insertions(+), 47 deletions(-) diff --git a/apps/submissions/forms.py b/apps/submissions/forms.py index b0f91d1..91b0154 100644 --- a/apps/submissions/forms.py +++ b/apps/submissions/forms.py @@ -1,10 +1,10 @@ -from django.forms import CharField, Form, Textarea +from django.forms import Form +from djangocodemirror.fields import CodeMirrorField class SubmissionForm(Form): - code = CharField( - label="Source Code", + code = CodeMirrorField( + label="Code", required=True, - min_length=15, - widget=Textarea(attrs={"rows": 12, "style": "width: 100%;"}), + config_name="python", ) diff --git a/poetry.lock b/poetry.lock index aec3a78..7a17143 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "alabaster" @@ -569,6 +569,17 @@ django = ">=2.2,<5.0" [package.extras] docs = ["m2r2 (>=0.2.5,<0.3.0)", "sphinx (>=4.4,<5.0)", "sphinx_rtd_theme (>=1.0,<2.0)"] +[[package]] +name = "django-codemirror" +version = "1.0.1" +description = "Django form widget for CodeMirror text editor" +optional = false +python-versions = "*" +files = [ + {file = "django-codemirror-1.0.1.tar.gz", hash = "sha256:02cff11180922a513324edaf55d66b273ce61e8d66269b49c054e9f4f9f6fbec"}, + {file = "django_codemirror-1.0.1-py3-none-any.whl", hash = "sha256:52447f09ddcaca9b7772f5266da92820bfcf2925ea78b4403c29c7261100eca7"}, +] + [[package]] name = "django-crispy-forms" version = "2.1" @@ -650,6 +661,22 @@ files = [ django = "*" typing-extensions = "*" +[[package]] +name = "djangocodemirror" +version = "2.1.0" +description = "Django CodeMirror is a Django application to embed CodeMirror" +optional = false +python-versions = "*" +files = [ + {file = "djangocodemirror-2.1.0.tar.gz", hash = "sha256:424478e009883134bf5aa3291195e51aec1c0f9eed50c9757d643d150dbe2597"}, +] + +[package.dependencies] +Django = ">=1.11" + +[package.extras] +dev = ["flake8", "pytest", "pytest-django", "sphinx", "sphinx-rtd-theme"] + [[package]] name = "docutils" version = "0.20.1" @@ -729,13 +756,13 @@ license = ["ukkonen"] [[package]] name = "idna" -version = "3.4" +version = "3.6" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, ] [[package]] @@ -751,20 +778,20 @@ files = [ [[package]] name = "importlib-metadata" -version = "6.8.0" +version = "6.9.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"}, - {file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"}, + {file = "importlib_metadata-6.9.0-py3-none-any.whl", hash = "sha256:1c8dc6839ddc9771412596926f24cb5a553bbd40624ee2c7e55e531542bed3b8"}, + {file = "importlib_metadata-6.9.0.tar.gz", hash = "sha256:e8acb523c335a91822674e149b46c0399ec4d328c4d1f6e49c273da5ff0201b9"}, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] @@ -861,6 +888,16 @@ files = [ {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, @@ -998,13 +1035,13 @@ files = [ [[package]] name = "platformdirs" -version = "3.11.0" +version = "4.0.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-3.11.0-py3-none-any.whl", hash = "sha256:e9d171d00af68be50e9202731309c4e658fd8bc76f55c11c7dd760d023bda68e"}, - {file = "platformdirs-3.11.0.tar.gz", hash = "sha256:cf8ee52a3afdb965072dcc652433e0c7e3e40cf5ea1477cd4b3b1d2eb75495b3"}, + {file = "platformdirs-4.0.0-py3-none-any.whl", hash = "sha256:118c954d7e949b35437270383a3f2531e99dd93cf7ce4dc8340d3356d30f173b"}, + {file = "platformdirs-4.0.0.tar.gz", hash = "sha256:cb633b2bcf10c51af60beb0ab06d2f1d69064b43abf4c185ca6b28865f3f9731"}, ] [package.extras] @@ -1089,13 +1126,13 @@ files = [ [[package]] name = "pygments" -version = "2.17.0" +version = "2.17.2" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.7" files = [ - {file = "pygments-2.17.0-py3-none-any.whl", hash = "sha256:cd0c46944b2551af02ecc15961050182ea120d3895000e2676160820f3421527"}, - {file = "pygments-2.17.0.tar.gz", hash = "sha256:edaa0fa2453d055d0ac94449d1f73ec7bc52c5e318204da1377c1392978c4a8d"}, + {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, + {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, ] [package.extras] @@ -1128,6 +1165,7 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -1135,8 +1173,15 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -1153,6 +1198,7 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -1160,6 +1206,7 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -1202,17 +1249,17 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "setuptools" -version = "68.2.2" +version = "69.0.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-68.2.2-py3-none-any.whl", hash = "sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a"}, - {file = "setuptools-68.2.2.tar.gz", hash = "sha256:4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87"}, + {file = "setuptools-69.0.2-py3-none-any.whl", hash = "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"}, + {file = "setuptools-69.0.2.tar.gz", hash = "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] @@ -1251,13 +1298,13 @@ files = [ [[package]] name = "sphinx" -version = "7.1.2" +version = "7.2.6" description = "Python documentation generator" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "sphinx-7.1.2-py3-none-any.whl", hash = "sha256:d170a81825b2fcacb6dfd5a0d7f578a053e45d3f2b153fecc948c37344eb4cbe"}, - {file = "sphinx-7.1.2.tar.gz", hash = "sha256:780f4d32f1d7d1126576e0e5ecc19dc32ab76cd24e950228dcf7b1f6d3d9e22f"}, + {file = "sphinx-7.2.6-py3-none-any.whl", hash = "sha256:1e09160a40b956dc623c910118fa636da93bd3ca0b9876a7b3df90f07d691560"}, + {file = "sphinx-7.2.6.tar.gz", hash = "sha256:9a5160e1ea90688d5963ba09a2dcd8bdd526620edbb65c328728f1b2228d5ab5"}, ] [package.dependencies] @@ -1268,7 +1315,7 @@ docutils = ">=0.18.1,<0.21" imagesize = ">=1.3" Jinja2 = ">=3.0" packaging = ">=21.0" -Pygments = ">=2.13" +Pygments = ">=2.14" requests = ">=2.25.0" snowballstemmer = ">=2.0" sphinxcontrib-applehelp = "*" @@ -1276,12 +1323,12 @@ sphinxcontrib-devhelp = "*" sphinxcontrib-htmlhelp = ">=2.0.0" sphinxcontrib-jsmath = "*" sphinxcontrib-qthelp = "*" -sphinxcontrib-serializinghtml = ">=1.1.5" +sphinxcontrib-serializinghtml = ">=1.1.9" [package.extras] docs = ["sphinxcontrib-websupport"] lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-simplify", "isort", "mypy (>=0.990)", "ruff", "sphinx-lint", "types-requests"] -test = ["cython", "filelock", "html5lib", "pytest (>=4.6)"] +test = ["cython (>=3.0)", "filelock", "html5lib", "pytest (>=4.6)", "setuptools (>=67.0)"] [[package]] name = "sphinx-design" @@ -1308,18 +1355,18 @@ theme-sbt = ["sphinx-book-theme (>=1.0,<2.0)"] [[package]] name = "sphinxawesome-theme" -version = "5.0.0b4" +version = "5.0.0" description = "An awesome theme for the Sphinx documentation generator" optional = false python-versions = ">=3.8,<4.0" files = [ - {file = "sphinxawesome_theme-5.0.0b4-py3-none-any.whl", hash = "sha256:a74bec9e41d4e93f28dc86755ea9d8404ec3500ea28b34a6a1862695c720dbd4"}, - {file = "sphinxawesome_theme-5.0.0b4.tar.gz", hash = "sha256:5358ed9642d3a61950287b471a137aba68ae0da4bee55bfd72d2f2bc74ca2eeb"}, + {file = "sphinxawesome_theme-5.0.0-py3-none-any.whl", hash = "sha256:c777ab1fffbc1928bf73978e31b785bc9e34fead5f4aa8341d56bc8c0fd01358"}, + {file = "sphinxawesome_theme-5.0.0.tar.gz", hash = "sha256:42b6da58cad93e5c32934b91da3d3090b7305d6c81f742b88b951a8d02caa866"}, ] [package.dependencies] beautifulsoup4 = ">=4.9.1,<5.0.0" -sphinx = ">4,<7.2" +sphinx = {version = ">=7.2,<7.3", markers = "python_version >= \"3.9\" and python_full_version <= \"3.12.0\""} [[package]] name = "sphinxcontrib-applehelp" @@ -1443,13 +1490,13 @@ test = ["pytest", "pytest-cov"] [[package]] name = "termcolor" -version = "2.3.0" +version = "2.4.0" description = "ANSI color formatting for output in terminal" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "termcolor-2.3.0-py3-none-any.whl", hash = "sha256:3afb05607b89aed0ffe25202399ee0867ad4d3cb4180d98aaf8eefa6a5f7d475"}, - {file = "termcolor-2.3.0.tar.gz", hash = "sha256:b5b08f68937f138fe92f6c089b99f1e2da0ae56c52b78bf7075fd95420fd9a5a"}, + {file = "termcolor-2.4.0-py3-none-any.whl", hash = "sha256:9297c0df9c99445c2412e832e882a7884038a25617c60cea2ad69488d4040d63"}, + {file = "termcolor-2.4.0.tar.gz", hash = "sha256:aab9e56047c8ac41ed798fa36d892a37aca6b3e9159f3e0c24bc64a9b3ac7b7a"}, ] [package.extras] @@ -1539,19 +1586,19 @@ files = [ [[package]] name = "virtualenv" -version = "20.24.6" +version = "20.25.0" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.24.6-py3-none-any.whl", hash = "sha256:520d056652454c5098a00c0f073611ccbea4c79089331f60bf9d7ba247bb7381"}, - {file = "virtualenv-20.24.6.tar.gz", hash = "sha256:02ece4f56fbf939dbbc33c0715159951d6bf14aaf5457b092e4548e1382455af"}, + {file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3"}, + {file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b"}, ] [package.dependencies] distlib = ">=0.3.7,<1" filelock = ">=3.12.2,<4" -platformdirs = ">=3.9.1,<4" +platformdirs = ">=3.9.1,<5" [package.extras] docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] @@ -1559,13 +1606,13 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [[package]] name = "wcwidth" -version = "0.2.10" +version = "0.2.12" description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = "*" files = [ - {file = "wcwidth-0.2.10-py2.py3-none-any.whl", hash = "sha256:aec5179002dd0f0d40c456026e74a729661c9d468e1ed64405e3a6c2176ca36f"}, - {file = "wcwidth-0.2.10.tar.gz", hash = "sha256:390c7454101092a6a5e43baad8f83de615463af459201709556b6e4b1c861f97"}, + {file = "wcwidth-0.2.12-py2.py3-none-any.whl", hash = "sha256:f26ec43d96c8cbfed76a5075dac87680124fa84e0855195a6184da9c187f133c"}, + {file = "wcwidth-0.2.12.tar.gz", hash = "sha256:f01c104efdf57971bcb756f054dd58ddec5204dd15fa31d6503ea57947d97c02"}, ] [[package]] @@ -1600,4 +1647,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "993537e69dee02102d9f10abc28bfabb79a43412e14d1cd49f3f17a559da4cc3" +content-hash = "859044b4a03eb2501c755e22e2b1d9832b3fe51b0a8b50a50a24f9956110aea1" diff --git a/pyproject.toml b/pyproject.toml index db7285d..7e103b5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,6 +18,7 @@ crispy-bootstrap5 = "^2023.10" gunicorn = "^21.2.0" whitenoise = "^6.6.0" celery = {extras = ["librabbitmq"], version = "^5.3.6"} +djangocodemirror = "^2.1.0" [tool.poetry.group.dev.dependencies] pre-commit = "^3.5.0" diff --git a/server/settings/base.py b/server/settings/base.py index 179eda8..cefc02d 100644 --- a/server/settings/base.py +++ b/server/settings/base.py @@ -1,6 +1,8 @@ from os.path import join from typing import List +from djangocodemirror.settings import * + from server.settings import BASE_DIR, env ###################### @@ -70,6 +72,7 @@ "django.contrib.messages", "django.contrib.staticfiles", "django.contrib.humanize", + "djangocodemirror", ] THIRD_PARTY_APPS = [ diff --git a/templates/tasks/detail.html b/templates/tasks/detail.html index e8a9956..2b94b86 100644 --- a/templates/tasks/detail.html +++ b/templates/tasks/detail.html @@ -1,10 +1,27 @@ {% extends "base.html" %} {% load crispy_forms_tags %} +{% load djangocodemirror_tags %} {% block title %}{{ task.title }}{% endblock title %} {% block content %} + + + + + + + + + + + + + + + +

{{ task.title }} @@ -46,7 +63,21 @@

Description


Submit

- {{ form|crispy }} + +
+ + +
+ + Submit

+ + {% endblock content %} From 4580ec06339d351c622b60b40e75f4e51b4be5c9 Mon Sep 17 00:00:00 2001 From: HladczukLe Date: Tue, 5 Dec 2023 16:03:26 -0300 Subject: [PATCH 02/25] fix(server/settings/base.py): Resolved merge conflict --- server/settings/base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/server/settings/base.py b/server/settings/base.py index 561c12b..a1fd1b1 100644 --- a/server/settings/base.py +++ b/server/settings/base.py @@ -73,6 +73,7 @@ "django.contrib.staticfiles", "django.contrib.humanize", "django.contrib.postgres", + "djangocodemirror", ] THIRD_PARTY_APPS = [ From 5b10cbdc4a09b6b9de7be38d346281a12266c38d Mon Sep 17 00:00:00 2001 From: HladczukLe Date: Tue, 5 Dec 2023 17:23:16 -0300 Subject: [PATCH 03/25] test(tasks/tests): fixing tests --- apps/tasks/tests.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/tasks/tests.py b/apps/tasks/tests.py index 91c5cf4..0218961 100644 --- a/apps/tasks/tests.py +++ b/apps/tasks/tests.py @@ -355,8 +355,13 @@ def test_send_submission_successfully(self) -> None: def test_send_submission_with_short_code(self) -> None: self.client.force_login(self.user) + initial_submission_count = Submission._default_manager.count() + self.client.post(self.url, data={"code": "c"}) - self.assertEqual(Submission._default_manager.count(), 1) + + final_submission_count = Submission._default_manager.count() + + self.assertEqual(final_submission_count, initial_submission_count + 1) def test_detail_view_model_is_task(self) -> None: self.assertEqual(DetailView.model, Task) From 26e86807df29361d17cb4f2e058dd9ffe1ca9189 Mon Sep 17 00:00:00 2001 From: HladczukLe Date: Tue, 5 Dec 2023 18:38:44 -0300 Subject: [PATCH 04/25] test(tasks/tests.py): add test --- apps/tasks/tests.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apps/tasks/tests.py b/apps/tasks/tests.py index 0218961..5ee50d9 100644 --- a/apps/tasks/tests.py +++ b/apps/tasks/tests.py @@ -461,6 +461,16 @@ def test_form_success_url(self) -> None: url = reverse("submissions:list") self.assertEqual(self.view.get_success_url(), url) + def test_invalid_form_submission(self) -> None: + invalid_code = "invalid code" + + response = self.client.post(self.url, data={"code": invalid_code}) + + self.assertEqual(response.status_code, 302) + + if response.context is not None: + self.assertNotIn("form", response.context) + class BackgroundJobTaskTest(TestCase): def setUp(self) -> None: From 3a8e1fcaf5922b9073c3672ab38094c32f57c7fd Mon Sep 17 00:00:00 2001 From: kyomi Date: Wed, 6 Dec 2023 10:05:42 -0300 Subject: [PATCH 05/25] fix(apps/tasks): add memory and time limits for the tasks --- apps/tasks/views.py | 42 ++++++++++++++++++++++++++++++++++-------- out.txt | 1 + 2 files changed, 35 insertions(+), 8 deletions(-) create mode 100644 out.txt diff --git a/apps/tasks/views.py b/apps/tasks/views.py index 0238fd4..280e99b 100644 --- a/apps/tasks/views.py +++ b/apps/tasks/views.py @@ -1,5 +1,7 @@ import sys from io import StringIO +from resource import RLIMIT_AS, getrlimit, setrlimit +from signal import SIGALRM, alarm, signal from typing import TYPE_CHECKING, Any, Dict from django.http import HttpRequest, HttpResponse @@ -21,31 +23,56 @@ FormMixinBase = FormMixin +def signal_handler(signum: int, frame: object) -> None: + raise TimeoutError("Time limit exceeded") + + +def set_memory_limit(task: Task) -> None: + if task.memory_limit is not None: + _, hard = getrlimit(RLIMIT_AS) + setrlimit(RLIMIT_AS, (task.memory_limit, hard)) + + +def set_time_limit(task: Task) -> None: + if task.time_limit is not None: + signal(SIGALRM, signal_handler) + alarm(task.time_limit) + + @celery.task(ignore_result=True) def handle_submission(code: str, task_id: int, submission_id: int) -> None: task = Task._default_manager.get(id=task_id) submission = Submission._default_manager.get(id=submission_id) + # Change stdout and stdin to StringIO so we can capture the output + # of the code. input_data = StringIO(task.input_file) - old_stdin = sys.stdin sys.stdin = input_data - - old_stdout = sys.stdout sys.stdout = stdout = StringIO() + set_memory_limit(task) + set_time_limit(task) + try: eval(compile(code, "", "exec")) + except MemoryError: + submission.status = "MLE" + submission.save() + return + except TimeoutError: + submission.status = "TLE" + submission.save() + return except Exception: submission.status = "RE" submission.save() return - finally: - sys.stdout = old_stdout - sys.stdin = old_stdin - output = stdout.getvalue() + check_answer(submission, task, stdout.getvalue()) + +def check_answer(submission: Submission, task: Task, output: str) -> None: submission.status = "AC" if output == task.output_file else "WA" submission.save() @@ -58,7 +85,6 @@ def handle_submission(code: str, task_id: int, submission_id: int) -> None: .exclude(id=submission.id) .exists() ) - is_accepted = submission.status == SubmissionStatus.ACCEPTED if is_accepted and not has_already_scored: diff --git a/out.txt b/out.txt new file mode 100644 index 0000000..af5626b --- /dev/null +++ b/out.txt @@ -0,0 +1 @@ +Hello, world! From c69c51a29f9db39e886df019f88719e401947910 Mon Sep 17 00:00:00 2001 From: kyomi Date: Wed, 6 Dec 2023 11:12:51 -0300 Subject: [PATCH 06/25] refactor(apps/tasks): split functions from `handle_submissions` --- apps/tasks/views.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/apps/tasks/views.py b/apps/tasks/views.py index 280e99b..1d14ccd 100644 --- a/apps/tasks/views.py +++ b/apps/tasks/views.py @@ -2,7 +2,7 @@ from io import StringIO from resource import RLIMIT_AS, getrlimit, setrlimit from signal import SIGALRM, alarm, signal -from typing import TYPE_CHECKING, Any, Dict +from typing import TYPE_CHECKING, Any, Dict, Optional from django.http import HttpRequest, HttpResponse from django.shortcuts import redirect @@ -27,49 +27,49 @@ def signal_handler(signum: int, frame: object) -> None: raise TimeoutError("Time limit exceeded") -def set_memory_limit(task: Task) -> None: +@celery.task(ignore_result=True) +def handle_submission(code: str, task_id: int, submission_id: int) -> None: + task = Task._default_manager.get(id=task_id) + submission = Submission._default_manager.get(id=submission_id) + if task.memory_limit is not None: _, hard = getrlimit(RLIMIT_AS) setrlimit(RLIMIT_AS, (task.memory_limit, hard)) - -def set_time_limit(task: Task) -> None: if task.time_limit is not None: signal(SIGALRM, signal_handler) alarm(task.time_limit) + if (output := compile_code(submission, task, code)) is None: + return + + check_answer(submission, task, output) -@celery.task(ignore_result=True) -def handle_submission(code: str, task_id: int, submission_id: int) -> None: - task = Task._default_manager.get(id=task_id) - submission = Submission._default_manager.get(id=submission_id) - # Change stdout and stdin to StringIO so we can capture the output - # of the code. +def compile_code( + submission: Submission, task: Task, code: str +) -> Optional[str]: input_data = StringIO(task.input_file) sys.stdin = input_data sys.stdout = stdout = StringIO() - set_memory_limit(task) - set_time_limit(task) - try: eval(compile(code, "", "exec")) except MemoryError: submission.status = "MLE" submission.save() - return + return None except TimeoutError: submission.status = "TLE" submission.save() - return + return None except Exception: submission.status = "RE" submission.save() - return + return None - check_answer(submission, task, stdout.getvalue()) + return stdout.getvalue() def check_answer(submission: Submission, task: Task, output: str) -> None: From fe1eaf0ac658ab7bed2d5a957a0dd4bf018e1240 Mon Sep 17 00:00:00 2001 From: HladczukLe Date: Wed, 6 Dec 2023 12:04:58 -0300 Subject: [PATCH 07/25] test(tasks/tests.py): fix test --- apps/tasks/tests.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/tasks/tests.py b/apps/tasks/tests.py index 4460b50..68db75b 100644 --- a/apps/tasks/tests.py +++ b/apps/tasks/tests.py @@ -513,8 +513,15 @@ def test_invalid_form_submission(self) -> None: self.assertEqual(response.status_code, 302) - if response.context is not None: - self.assertNotIn("form", response.context) + redirected_url = response.headers["Location"] + + redirected_response = self.client.get(redirected_url) + + self.assertEqual(redirected_response.status_code, 200) + self.assertTemplateUsed(redirected_response, "registration/login.html") + + if redirected_response.context is not None: + self.assertIn("form", redirected_response.context) class BackgroundJobTaskTest(TestCase): From 7c5c10a6fbe3aa58b37db8d3338e2c77de14caa0 Mon Sep 17 00:00:00 2001 From: HladczukLe Date: Wed, 6 Dec 2023 12:15:37 -0300 Subject: [PATCH 08/25] test(tasks/tests.py): fix test --- apps/tasks/tests.py | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/tasks/tests.py b/apps/tasks/tests.py index 68db75b..0a14805 100644 --- a/apps/tasks/tests.py +++ b/apps/tasks/tests.py @@ -518,7 +518,6 @@ def test_invalid_form_submission(self) -> None: redirected_response = self.client.get(redirected_url) self.assertEqual(redirected_response.status_code, 200) - self.assertTemplateUsed(redirected_response, "registration/login.html") if redirected_response.context is not None: self.assertIn("form", redirected_response.context) From 12dfc1e3a47b88d4499badda3abdc101b0fd29b6 Mon Sep 17 00:00:00 2001 From: HladczukLe Date: Wed, 6 Dec 2023 12:32:31 -0300 Subject: [PATCH 09/25] test(tasks/tests.py): fix test --- apps/tasks/tests.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/tasks/tests.py b/apps/tasks/tests.py index 0a14805..b1f8868 100644 --- a/apps/tasks/tests.py +++ b/apps/tasks/tests.py @@ -521,6 +521,7 @@ def test_invalid_form_submission(self) -> None: if redirected_response.context is not None: self.assertIn("form", redirected_response.context) + self.assertFalse(redirected_response.context["form"].is_valid()) class BackgroundJobTaskTest(TestCase): From 8e1d8aca2f15f894e9a13f01040d338f1486b0c3 Mon Sep 17 00:00:00 2001 From: kyomi Date: Wed, 6 Dec 2023 16:02:25 -0300 Subject: [PATCH 10/25] test(apps/tasks): fix not valid forms tests --- apps/tasks/tests.py | 18 ++---- docker-compose.yml | 2 + poetry.lock | 136 +++++++++++++++++--------------------------- 3 files changed, 60 insertions(+), 96 deletions(-) diff --git a/apps/tasks/tests.py b/apps/tasks/tests.py index b1f8868..9174f3e 100644 --- a/apps/tasks/tests.py +++ b/apps/tasks/tests.py @@ -507,21 +507,13 @@ def test_form_success_url(self) -> None: self.assertEqual(self.view.get_success_url(), url) def test_invalid_form_submission(self) -> None: - invalid_code = "invalid code" - - response = self.client.post(self.url, data={"code": invalid_code}) - - self.assertEqual(response.status_code, 302) - - redirected_url = response.headers["Location"] - - redirected_response = self.client.get(redirected_url) + self.client.force_login(self.user) - self.assertEqual(redirected_response.status_code, 200) + response = self.client.post(self.url, data={"code": ""}) - if redirected_response.context is not None: - self.assertIn("form", redirected_response.context) - self.assertFalse(redirected_response.context["form"].is_valid()) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, "tasks/detail.html") + self.assertFalse(response.context["form"].is_valid()) class BackgroundJobTaskTest(TestCase): diff --git a/docker-compose.yml b/docker-compose.yml index 90e9f6f..2d1af2d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -24,6 +24,8 @@ services: - config/.env depends_on: - postgres + - rabbitmq + - celery command: python -Wd manage.py runserver 0.0.0.0:8000 celery: diff --git a/poetry.lock b/poetry.lock index 7a17143..b4d869a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] name = "alabaster" @@ -405,13 +405,13 @@ files = [ [[package]] name = "commitizen" -version = "3.12.0" +version = "3.13.0" description = "Python commitizen client tool" optional = false python-versions = ">=3.8" files = [ - {file = "commitizen-3.12.0-py3-none-any.whl", hash = "sha256:082f4733409bc4f01f987467295f8393ceb16b42cc648cf2f5a7a754c6d594db"}, - {file = "commitizen-3.12.0.tar.gz", hash = "sha256:7c313f1f85f45c9acf1a70f1637deab5c388150ae8660a0037ac260e77bb1492"}, + {file = "commitizen-3.13.0-py3-none-any.whl", hash = "sha256:ff57069591ff109136b70841fe79a3434d0525748995531cceb4f3ccadb44ead"}, + {file = "commitizen-3.13.0.tar.gz", hash = "sha256:53cd225ae44fc25cb1582f5d50cda78711a5a1d44a32fee3dcf7a22bc204ce06"}, ] [package.dependencies] @@ -533,13 +533,13 @@ files = [ [[package]] name = "django" -version = "4.2.7" +version = "4.2.8" description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." optional = false python-versions = ">=3.8" files = [ - {file = "Django-4.2.7-py3-none-any.whl", hash = "sha256:e1d37c51ad26186de355cbcec16613ebdabfa9689bbade9c538835205a8abbe9"}, - {file = "Django-4.2.7.tar.gz", hash = "sha256:8e0f1c2c2786b5c0e39fe1afce24c926040fad47c8ea8ad30aaf1188df29fc41"}, + {file = "Django-4.2.8-py3-none-any.whl", hash = "sha256:6cb5dcea9e3d12c47834d32156b8841f533a4493c688e2718cafd51aa430ba6d"}, + {file = "Django-4.2.8.tar.gz", hash = "sha256:d69d5e36cc5d9f4eb4872be36c622878afcdce94062716cf3e25bcedcb168b62"}, ] [package.dependencies] @@ -569,17 +569,6 @@ django = ">=2.2,<5.0" [package.extras] docs = ["m2r2 (>=0.2.5,<0.3.0)", "sphinx (>=4.4,<5.0)", "sphinx_rtd_theme (>=1.0,<2.0)"] -[[package]] -name = "django-codemirror" -version = "1.0.1" -description = "Django form widget for CodeMirror text editor" -optional = false -python-versions = "*" -files = [ - {file = "django-codemirror-1.0.1.tar.gz", hash = "sha256:02cff11180922a513324edaf55d66b273ce61e8d66269b49c054e9f4f9f6fbec"}, - {file = "django_codemirror-1.0.1-py3-none-any.whl", hash = "sha256:52447f09ddcaca9b7772f5266da92820bfcf2925ea78b4403c29c7261100eca7"}, -] - [[package]] name = "django-crispy-forms" version = "2.1" @@ -626,35 +615,35 @@ Django = ">=2.2" [[package]] name = "django-stubs" -version = "4.2.6" +version = "4.2.7" description = "Mypy stubs for Django" optional = false python-versions = ">=3.8" files = [ - {file = "django-stubs-4.2.6.tar.gz", hash = "sha256:e60b43de662a199db4b15c803c06669e0ac5035614af291cbd3b91591f7dcc94"}, - {file = "django_stubs-4.2.6-py3-none-any.whl", hash = "sha256:2fcd257884a68dfa02de41ee5410ec805264d9b07d9b5b119e4dea82c7b8345e"}, + {file = "django-stubs-4.2.7.tar.gz", hash = "sha256:8ccd2ff4ee5adf22b9e3b7b1a516d2e1c2191e9d94e672c35cc2bc3dd61e0f6b"}, + {file = "django_stubs-4.2.7-py3-none-any.whl", hash = "sha256:4cf4de258fa71adc6f2799e983091b9d46cfc67c6eebc68fe111218c9a62b3b8"}, ] [package.dependencies] django = "*" -django-stubs-ext = ">=4.2.5" -mypy = {version = ">=1.6.0,<1.7.0", optional = true, markers = "extra == \"compatible-mypy\""} +django-stubs-ext = ">=4.2.7" +mypy = {version = ">=1.7.0,<1.8.0", optional = true, markers = "extra == \"compatible-mypy\""} types-pytz = "*" types-PyYAML = "*" typing-extensions = "*" [package.extras] -compatible-mypy = ["mypy (>=1.6.0,<1.7.0)"] +compatible-mypy = ["mypy (>=1.7.0,<1.8.0)"] [[package]] name = "django-stubs-ext" -version = "4.2.5" +version = "4.2.7" description = "Monkey-patching and extensions for django-stubs" optional = false python-versions = ">=3.8" files = [ - {file = "django-stubs-ext-4.2.5.tar.gz", hash = "sha256:8c4d1fb5f68419b3b2474c659681a189803e27d6a5e5abf5aa0da57601b58633"}, - {file = "django_stubs_ext-4.2.5-py3-none-any.whl", hash = "sha256:921cd7ae4614e74c234bc0fe86ee75537d163addfe1fc6f134bf03e29d86c01e"}, + {file = "django-stubs-ext-4.2.7.tar.gz", hash = "sha256:519342ac0849cda1559746c9a563f03ff99f636b0ebe7c14b75e816a00dfddc3"}, + {file = "django_stubs_ext-4.2.7-py3-none-any.whl", hash = "sha256:45a5d102417a412e3606e3c358adb4744988a92b7b58ccf3fd64bddd5d04d14c"}, ] [package.dependencies] @@ -778,13 +767,13 @@ files = [ [[package]] name = "importlib-metadata" -version = "6.9.0" +version = "6.11.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-6.9.0-py3-none-any.whl", hash = "sha256:1c8dc6839ddc9771412596926f24cb5a553bbd40624ee2c7e55e531542bed3b8"}, - {file = "importlib_metadata-6.9.0.tar.gz", hash = "sha256:e8acb523c335a91822674e149b46c0399ec4d328c4d1f6e49c273da5ff0201b9"}, + {file = "importlib_metadata-6.11.0-py3-none-any.whl", hash = "sha256:f0afba6205ad8f8947c7d338b5342d5db2afbfd82f9cbef7879a9539cc12eb9b"}, + {file = "importlib_metadata-6.11.0.tar.gz", hash = "sha256:1231cf92d825c9e03cfc4da076a16de6422c863558229ea0b22b675657463443"}, ] [package.dependencies] @@ -888,16 +877,6 @@ files = [ {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, @@ -943,38 +922,38 @@ files = [ [[package]] name = "mypy" -version = "1.6.1" +version = "1.7.1" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e5012e5cc2ac628177eaac0e83d622b2dd499e28253d4107a08ecc59ede3fc2c"}, - {file = "mypy-1.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d8fbb68711905f8912e5af474ca8b78d077447d8f3918997fecbf26943ff3cbb"}, - {file = "mypy-1.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21a1ad938fee7d2d96ca666c77b7c494c3c5bd88dff792220e1afbebb2925b5e"}, - {file = "mypy-1.6.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b96ae2c1279d1065413965c607712006205a9ac541895004a1e0d4f281f2ff9f"}, - {file = "mypy-1.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:40b1844d2e8b232ed92e50a4bd11c48d2daa351f9deee6c194b83bf03e418b0c"}, - {file = "mypy-1.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:81af8adaa5e3099469e7623436881eff6b3b06db5ef75e6f5b6d4871263547e5"}, - {file = "mypy-1.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8c223fa57cb154c7eab5156856c231c3f5eace1e0bed9b32a24696b7ba3c3245"}, - {file = "mypy-1.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8032e00ce71c3ceb93eeba63963b864bf635a18f6c0c12da6c13c450eedb183"}, - {file = "mypy-1.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4c46b51de523817a0045b150ed11b56f9fff55f12b9edd0f3ed35b15a2809de0"}, - {file = "mypy-1.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:19f905bcfd9e167159b3d63ecd8cb5e696151c3e59a1742e79bc3bcb540c42c7"}, - {file = "mypy-1.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:82e469518d3e9a321912955cc702d418773a2fd1e91c651280a1bda10622f02f"}, - {file = "mypy-1.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d4473c22cc296425bbbce7e9429588e76e05bc7342da359d6520b6427bf76660"}, - {file = "mypy-1.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59a0d7d24dfb26729e0a068639a6ce3500e31d6655df8557156c51c1cb874ce7"}, - {file = "mypy-1.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cfd13d47b29ed3bbaafaff7d8b21e90d827631afda134836962011acb5904b71"}, - {file = "mypy-1.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:eb4f18589d196a4cbe5290b435d135dee96567e07c2b2d43b5c4621b6501531a"}, - {file = "mypy-1.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:41697773aa0bf53ff917aa077e2cde7aa50254f28750f9b88884acea38a16169"}, - {file = "mypy-1.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7274b0c57737bd3476d2229c6389b2ec9eefeb090bbaf77777e9d6b1b5a9d143"}, - {file = "mypy-1.6.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbaf4662e498c8c2e352da5f5bca5ab29d378895fa2d980630656178bd607c46"}, - {file = "mypy-1.6.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bb8ccb4724f7d8601938571bf3f24da0da791fe2db7be3d9e79849cb64e0ae85"}, - {file = "mypy-1.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:68351911e85145f582b5aa6cd9ad666c8958bcae897a1bfda8f4940472463c45"}, - {file = "mypy-1.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:49ae115da099dcc0922a7a895c1eec82c1518109ea5c162ed50e3b3594c71208"}, - {file = "mypy-1.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8b27958f8c76bed8edaa63da0739d76e4e9ad4ed325c814f9b3851425582a3cd"}, - {file = "mypy-1.6.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:925cd6a3b7b55dfba252b7c4561892311c5358c6b5a601847015a1ad4eb7d332"}, - {file = "mypy-1.6.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8f57e6b6927a49550da3d122f0cb983d400f843a8a82e65b3b380d3d7259468f"}, - {file = "mypy-1.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:a43ef1c8ddfdb9575691720b6352761f3f53d85f1b57d7745701041053deff30"}, - {file = "mypy-1.6.1-py3-none-any.whl", hash = "sha256:4cbe68ef919c28ea561165206a2dcb68591c50f3bcf777932323bc208d949cf1"}, - {file = "mypy-1.6.1.tar.gz", hash = "sha256:4d01c00d09a0be62a4ca3f933e315455bde83f37f892ba4b08ce92f3cf44bcc1"}, + {file = "mypy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:12cce78e329838d70a204293e7b29af9faa3ab14899aec397798a4b41be7f340"}, + {file = "mypy-1.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1484b8fa2c10adf4474f016e09d7a159602f3239075c7bf9f1627f5acf40ad49"}, + {file = "mypy-1.7.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31902408f4bf54108bbfb2e35369877c01c95adc6192958684473658c322c8a5"}, + {file = "mypy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f2c2521a8e4d6d769e3234350ba7b65ff5d527137cdcde13ff4d99114b0c8e7d"}, + {file = "mypy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:fcd2572dd4519e8a6642b733cd3a8cfc1ef94bafd0c1ceed9c94fe736cb65b6a"}, + {file = "mypy-1.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4b901927f16224d0d143b925ce9a4e6b3a758010673eeded9b748f250cf4e8f7"}, + {file = "mypy-1.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2f7f6985d05a4e3ce8255396df363046c28bea790e40617654e91ed580ca7c51"}, + {file = "mypy-1.7.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:944bdc21ebd620eafefc090cdf83158393ec2b1391578359776c00de00e8907a"}, + {file = "mypy-1.7.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9c7ac372232c928fff0645d85f273a726970c014749b924ce5710d7d89763a28"}, + {file = "mypy-1.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:f6efc9bd72258f89a3816e3a98c09d36f079c223aa345c659622f056b760ab42"}, + {file = "mypy-1.7.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6dbdec441c60699288adf051f51a5d512b0d818526d1dcfff5a41f8cd8b4aaf1"}, + {file = "mypy-1.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4fc3d14ee80cd22367caaaf6e014494415bf440980a3045bf5045b525680ac33"}, + {file = "mypy-1.7.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c6e4464ed5f01dc44dc9821caf67b60a4e5c3b04278286a85c067010653a0eb"}, + {file = "mypy-1.7.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d9b338c19fa2412f76e17525c1b4f2c687a55b156320acb588df79f2e6fa9fea"}, + {file = "mypy-1.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:204e0d6de5fd2317394a4eff62065614c4892d5a4d1a7ee55b765d7a3d9e3f82"}, + {file = "mypy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:84860e06ba363d9c0eeabd45ac0fde4b903ad7aa4f93cd8b648385a888e23200"}, + {file = "mypy-1.7.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8c5091ebd294f7628eb25ea554852a52058ac81472c921150e3a61cdd68f75a7"}, + {file = "mypy-1.7.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40716d1f821b89838589e5b3106ebbc23636ffdef5abc31f7cd0266db936067e"}, + {file = "mypy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cf3f0c5ac72139797953bd50bc6c95ac13075e62dbfcc923571180bebb662e9"}, + {file = "mypy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:78e25b2fd6cbb55ddfb8058417df193f0129cad5f4ee75d1502248e588d9e0d7"}, + {file = "mypy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:75c4d2a6effd015786c87774e04331b6da863fc3fc4e8adfc3b40aa55ab516fe"}, + {file = "mypy-1.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2643d145af5292ee956aa0a83c2ce1038a3bdb26e033dadeb2f7066fb0c9abce"}, + {file = "mypy-1.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75aa828610b67462ffe3057d4d8a4112105ed211596b750b53cbfe182f44777a"}, + {file = "mypy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ee5d62d28b854eb61889cde4e1dbc10fbaa5560cb39780c3995f6737f7e82120"}, + {file = "mypy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:72cf32ce7dd3562373f78bd751f73c96cfb441de147cc2448a92c1a308bd0ca6"}, + {file = "mypy-1.7.1-py3-none-any.whl", hash = "sha256:f7c5d642db47376a0cc130f0de6d055056e010debdaf0707cd2b0fc7e7ef30ea"}, + {file = "mypy-1.7.1.tar.gz", hash = "sha256:fcb6d9afb1b6208b4c712af0dafdc650f518836065df0d4fb1d800f5d6773db2"}, ] [package.dependencies] @@ -984,6 +963,7 @@ typing-extensions = ">=4.1.0" [package.extras] dmypy = ["psutil (>=4.0)"] install-types = ["pip"] +mypyc = ["setuptools (>=50)"] reports = ["lxml"] [[package]] @@ -1035,13 +1015,13 @@ files = [ [[package]] name = "platformdirs" -version = "4.0.0" +version = "4.1.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "platformdirs-4.0.0-py3-none-any.whl", hash = "sha256:118c954d7e949b35437270383a3f2531e99dd93cf7ce4dc8340d3356d30f173b"}, - {file = "platformdirs-4.0.0.tar.gz", hash = "sha256:cb633b2bcf10c51af60beb0ab06d2f1d69064b43abf4c185ca6b28865f3f9731"}, + {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, + {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, ] [package.extras] @@ -1165,7 +1145,6 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -1173,15 +1152,8 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -1198,7 +1170,6 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -1206,7 +1177,6 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -1647,4 +1617,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "859044b4a03eb2501c755e22e2b1d9832b3fe51b0a8b50a50a24f9956110aea1" +content-hash = "6f83db1db7bcbb05c99cc994403f24c3da22ad8d1c9e8de8b85ef5bc6808be15" From 2caa27415e7bac1f5e65c9edf106551177096216 Mon Sep 17 00:00:00 2001 From: kyomi Date: Wed, 6 Dec 2023 16:14:23 -0300 Subject: [PATCH 11/25] chore: update `pre-commit` hooks --- .pre-commit-config.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c250cbb..df59bfc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -15,13 +15,13 @@ repos: - id: detect-private-key - id: end-of-file-fixer - repo: https://github.com/commitizen-tools/commitizen - rev: 3.9.0 + rev: v3.13.0 hooks: - id: commitizen - id: commitizen-branch stages: [push] - repo: https://github.com/psf/black - rev: 23.9.1 + rev: 23.11.0 hooks: - id: black - repo: https://github.com/pycqa/isort @@ -33,7 +33,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.6.1 + rev: v1.7.1 hooks: - id: mypy additional_dependencies: From c79816207f1f726f0c84d90c517249f45249bbd9 Mon Sep 17 00:00:00 2001 From: kyomi Date: Wed, 6 Dec 2023 16:27:11 -0300 Subject: [PATCH 12/25] test(apps/tasks): fix minimum characters code test --- apps/submissions/forms.py | 1 + apps/tasks/tests.py | 7 +------ 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/submissions/forms.py b/apps/submissions/forms.py index 91b0154..1918102 100644 --- a/apps/submissions/forms.py +++ b/apps/submissions/forms.py @@ -4,6 +4,7 @@ class SubmissionForm(Form): code = CodeMirrorField( + min_length=15, label="Code", required=True, config_name="python", diff --git a/apps/tasks/tests.py b/apps/tasks/tests.py index 9174f3e..bd7a818 100644 --- a/apps/tasks/tests.py +++ b/apps/tasks/tests.py @@ -358,13 +358,8 @@ def test_send_submission_successfully(self) -> None: def test_send_submission_with_short_code(self) -> None: self.client.force_login(self.user) - initial_submission_count = Submission._default_manager.count() - self.client.post(self.url, data={"code": "c"}) - - final_submission_count = Submission._default_manager.count() - - self.assertEqual(final_submission_count, initial_submission_count + 1) + self.assertEqual(Submission._default_manager.count(), 1) def test_detail_view_model_is_task(self) -> None: self.assertEqual(DetailView.model, Task) From 1dd1817a8a0a1c231b21678e87e295d2d8ba8c37 Mon Sep 17 00:00:00 2001 From: kyomi Date: Wed, 6 Dec 2023 20:16:59 -0300 Subject: [PATCH 13/25] fix(templates/tasks): refactor form layout --- templates/tasks/detail.html | 43 ++++++++++++++----------------------- 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/templates/tasks/detail.html b/templates/tasks/detail.html index 1b1b77c..a760c90 100644 --- a/templates/tasks/detail.html +++ b/templates/tasks/detail.html @@ -71,30 +71,24 @@

Constraints

{% csrf_token %} -
-
-

Submit

- -
- - +

Submit

+ +
+
+
- - + +
@@ -109,11 +103,6 @@

Submit

matchBrackets: true, } ); - - document.getElementById("id_theme").addEventListener("change", function () { - var selectedTheme = this.value; - codemirror.setOption("theme", selectedTheme); - }); {% endblock content %} From 80777a7e78278fab3b3406a9f091ed1a412d5059 Mon Sep 17 00:00:00 2001 From: HladczukLe Date: Wed, 6 Dec 2023 20:32:55 -0300 Subject: [PATCH 14/25] refactor(settings/base.py): moved an app from django_apps --- server/settings/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/settings/base.py b/server/settings/base.py index a1fd1b1..684bf98 100644 --- a/server/settings/base.py +++ b/server/settings/base.py @@ -73,7 +73,6 @@ "django.contrib.staticfiles", "django.contrib.humanize", "django.contrib.postgres", - "djangocodemirror", ] THIRD_PARTY_APPS = [ @@ -81,6 +80,7 @@ "bootstrap5", "crispy_forms", "crispy_bootstrap5", + "djangocodemirror", ] LOCAL_APPS = [ From 27cac4b20467f1b32b5f8c98196aa9cd013d6cd4 Mon Sep 17 00:00:00 2001 From: LuizaMaluf Date: Thu, 7 Dec 2023 07:47:00 -0300 Subject: [PATCH 15/25] feat(submission_table_colors): colors of the table --- templates/submissions/list.html | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/templates/submissions/list.html b/templates/submissions/list.html index 751316a..719e272 100644 --- a/templates/submissions/list.html +++ b/templates/submissions/list.html @@ -24,6 +24,21 @@ th { background-color: #f2f2f2; } + .success { + background-color: #dff0d8; + } + .wating { + background-color: #2f00ff; + } + .wrong { + background-color: #ff0000; + } + .time { + background-color: #ff0000; + } + .memory{ + background-color: #ff0000; + } {% endblock head %} @@ -41,7 +56,7 @@

Submissions

{% for submission in page_obj %} - + {{ submission.id }}
From f71a75d7a9c35b386ad5d1aab31f806448a31fd9 Mon Sep 17 00:00:00 2001 From: LuizaMaluf Date: Thu, 7 Dec 2023 08:09:35 -0300 Subject: [PATCH 16/25] feat(submission_table_colors): correcting colors of the table --- templates/submissions/list.html | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/templates/submissions/list.html b/templates/submissions/list.html index 719e272..278bae3 100644 --- a/templates/submissions/list.html +++ b/templates/submissions/list.html @@ -25,19 +25,13 @@ background-color: #f2f2f2; } .success { - background-color: #dff0d8; + background-color: #47fc00b7; } .wating { - background-color: #2f00ff; + background-color: #ff88008c; } .wrong { - background-color: #ff0000; - } - .time { - background-color: #ff0000; - } - .memory{ - background-color: #ff0000; + background-color: #ff00006b; } {% endblock head %} @@ -56,7 +50,7 @@

Submissions

{% for submission in page_obj %} - + {{ submission.id }}
From d34ab25dcca7cfc003defb626a623fcb050ebe83 Mon Sep 17 00:00:00 2001 From: MMcLovin Date: Thu, 7 Dec 2023 23:10:22 -0300 Subject: [PATCH 17/25] feat: added ranking page hyperlink --- templates/base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/base.html b/templates/base.html index 3623a73..756b0f1 100644 --- a/templates/base.html +++ b/templates/base.html @@ -68,7 +68,7 @@ From 8ae3aca72131bc09aeb6d669356f354a8fd12f07 Mon Sep 17 00:00:00 2001 From: MMcLovin Date: Thu, 7 Dec 2023 23:25:40 -0300 Subject: [PATCH 18/25] feat: adds ranking view class --- apps/users/views.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/apps/users/views.py b/apps/users/views.py index 81410be..5e321af 100644 --- a/apps/users/views.py +++ b/apps/users/views.py @@ -1,11 +1,20 @@ +from typing import TYPE_CHECKING + from django.contrib.auth import login +from django.db.models import QuerySet from django.http import HttpRequest, HttpResponse from django.shortcuts import get_object_or_404, redirect, render from django.views import View +from django.views.generic import ListView from apps.users.forms import CreateUserForm from apps.users.models import User +if TYPE_CHECKING: + RankingViewBase = ListView[User] +else: + RankingViewBase = ListView + class RegisterView(View): template_name = "registration/register.html" @@ -34,3 +43,13 @@ class ProfileView(View): def get(self, request: HttpRequest, *, username: str) -> HttpResponse: user = get_object_or_404(User, username=username) return render(request, self.template_name, {"user": user}) + + +class RankingView(RankingViewBase): + model = User + template_name = "ranking/list.html" + context_object_name = "ranking" + paginate_by = 10 + + def get_queryset(self) -> QuerySet[User]: + return User._default_manager.all().order_by("-score") From 82c0ce0e57ce829495d4e129f59c249b21a0e547 Mon Sep 17 00:00:00 2001 From: MMcLovin Date: Thu, 7 Dec 2023 23:33:58 -0300 Subject: [PATCH 19/25] feat: added ranking page url pattern --- apps/users/urls.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/users/urls.py b/apps/users/urls.py index 1fc5368..e6d1416 100644 --- a/apps/users/urls.py +++ b/apps/users/urls.py @@ -1,10 +1,11 @@ from django.urls import path -from apps.users.views import ProfileView, RegisterView +from apps.users.views import ProfileView, RankingView, RegisterView app_name = "users" urlpatterns = [ path("register/", RegisterView.as_view(), name="register"), path("profile//", ProfileView.as_view(), name="profile"), + path("ranking/", RankingView.as_view(), name="ranking"), ] From d1d4ced47e69962e177e528d16999f56adc0c1f2 Mon Sep 17 00:00:00 2001 From: MMcLovin Date: Thu, 7 Dec 2023 23:36:51 -0300 Subject: [PATCH 20/25] feat: added ranking page html --- templates/ranking/list.html | 96 +++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 templates/ranking/list.html diff --git a/templates/ranking/list.html b/templates/ranking/list.html new file mode 100644 index 0000000..294d398 --- /dev/null +++ b/templates/ranking/list.html @@ -0,0 +1,96 @@ +{% extends "base.html" %} + +{% load crispy_forms_tags %} + +{% block title %}Ranking{% endblock title %} + +{% block head %} + +{% endblock head %} + +{% block content %} +

Ranking

+ + + + + + + + + + {% for user in page_obj %} + + + + + + {% endfor %} + +
RankUserScore
{{ forloop.counter }} + + {{ user.username }} + + {{ user.score }}
+ + +{% endblock content %} From aa3eac90009c9fede594cd3dce0f3c5228491edd Mon Sep 17 00:00:00 2001 From: MMcLovin Date: Thu, 7 Dec 2023 23:47:27 -0300 Subject: [PATCH 21/25] feat: included tests for RankingView class --- apps/users/tests.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/apps/users/tests.py b/apps/users/tests.py index db4fd55..bb5bc8f 100644 --- a/apps/users/tests.py +++ b/apps/users/tests.py @@ -151,3 +151,32 @@ def test_email(self) -> None: self.assertEqual(response.status_code, 200) self.assertContains(response, user.email) + + +class RankingListViewtest(TestCase): + def setUp(self) -> None: + self.user = User._default_manager.create( + username="testuser1", + email="testuser@example1", + password="testpassword1", + score=100, + ) + self.user = User._default_manager.create( + username="testuser2", + email="testuser@example2", + password="testpassword2", + score=90, + ) + + def test_ranking_list_view(self) -> None: + self.client.login(email="testuser@example", password="testpassword") + + url = reverse("users:ranking") + response = self.client.get(url) + ranking_order = [user.username for user in response.context["ranking"]] + expected_order = ["testuser1", "testuser2"] + + self.assertEqual(response.status_code, 200) + self.assertIn("ranking", response.context) + self.assertIn(self.user, response.context["ranking"]) + self.assertEqual(ranking_order, expected_order) From be0852af174b3a47a876ae171e3c25c87d71f6fc Mon Sep 17 00:00:00 2001 From: LuizaMaluf Date: Sat, 9 Dec 2023 10:39:30 -0300 Subject: [PATCH 22/25] feat(submission_table_colors): correcting size of the line --- templates/submissions/list.html | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/templates/submissions/list.html b/templates/submissions/list.html index 278bae3..9194abe 100644 --- a/templates/submissions/list.html +++ b/templates/submissions/list.html @@ -50,8 +50,10 @@

Submissions

{% for submission in page_obj %} - - {{ submission.id }} + + {{ submission.id }} {{ submission.author.username }} From be4312ac0758c2a41ec529143b96314210accc0c Mon Sep 17 00:00:00 2001 From: LuizaMaluf Date: Sat, 9 Dec 2023 10:49:30 -0300 Subject: [PATCH 23/25] feat(submission_table_colors): correcting size of the line and the function working --- templates/submissions/list.html | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/templates/submissions/list.html b/templates/submissions/list.html index 9194abe..6b7d102 100644 --- a/templates/submissions/list.html +++ b/templates/submissions/list.html @@ -27,7 +27,7 @@ .success { background-color: #47fc00b7; } - .wating { + .waiting { background-color: #ff88008c; } .wrong { @@ -50,9 +50,10 @@

Submissions

{% for submission in page_obj %} - + {{ submission.id }}
From bdb28ac0985d1f48844692d4bab9021eb9db3b8c Mon Sep 17 00:00:00 2001 From: kyomi Date: Sat, 9 Dec 2023 22:58:00 -0300 Subject: [PATCH 24/25] style: make the code look cleaner --- templates/submissions/list.html | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/templates/submissions/list.html b/templates/submissions/list.html index 6b7d102..a800a49 100644 --- a/templates/submissions/list.html +++ b/templates/submissions/list.html @@ -6,30 +6,36 @@ {% block head %}