diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml new file mode 100644 index 000000000..16a1a716b --- /dev/null +++ b/.github/workflows/ruff.yml @@ -0,0 +1,18 @@ +name: Ruff + +on: + push: + branches: + - master + pull_request: + workflow_dispatch: + +jobs: + ruff: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: chartboost/ruff-action@v1 + with: + src: "./oioioi" + version: 0.0.265 \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..46bcd7b83 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,7 @@ +repos: +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.0.269 + hooks: + - id: ruff + files: ^oioioi/ + args: [ --fix, --exit-non-zero-on-fix ] diff --git a/easy_toolbox.py b/easy_toolbox.py index f617208eb..3cf04823f 100755 --- a/easy_toolbox.py +++ b/easy_toolbox.py @@ -3,7 +3,7 @@ # pip requirements: # python ^3.6 # inquirer (only for GUI) -# +# # system: # docker # docker-compose @@ -19,8 +19,9 @@ import os -BASE_DOCKER_COMMAND = "OIOIOI_UID=$(id -u) docker-compose" + \ - " -f docker-compose-dev.yml" +BASE_DOCKER_COMMAND = ( + "OIOIOI_UID=$(id -u) docker-compose" + " -f docker-compose-dev.yml" +) RAW_COMMANDS = [ ("build", "Build OIOIOI container from source.", "build", True), @@ -31,17 +32,38 @@ ("bash", "Open command prompt on web container.", "{exec} web bash"), ("bash-db", "Open command prompt on database container.", "{exec} db bash"), # This one CLEARS the database. Use wisely. - ("flush-db", "Clear database.", "{exec} web python manage.py flush --noinput", True), - ("add-superuser", "Create admin_admin.", - "{exec} web python manage.py loaddata ../oioioi/oioioi_cypress/cypress/fixtures/admin_admin.json"), + ( + "flush-db", + "Clear database.", + "{exec} web python manage.py flush --noinput", + True, + ), + ( + "add-superuser", + "Create admin_admin.", + "{exec} web python manage.py loaddata ../oioioi/oioioi_cypress/cypress/fixtures/admin_admin.json", + ), ("test", "Run unit tests.", "{exec} web ../oioioi/test.sh"), - ("test-slow", "Run unit tests. (--runslow)", "{exec} web ../oioioi/test.sh --runslow"), - ("test-abc", "Run specific test file. (edit the toolbox)", - "{exec} web ../oioioi/test.sh -v oioioi/problems/tests/test_task_archive.py"), - ("test-coverage", "Run coverage tests.", - "{exec} 'web' ../oioioi/test.sh oioioi/problems --cov-report term --cov-report xml:coverage.xml --cov=oioioi"), - ("cypress-apply-settings", "Apply settings for CyPress.", - "{exec} web bash -c \"echo CAPTCHA_TEST_MODE=True >> settings.py\""), + ( + "test-slow", + "Run unit tests. (--runslow)", + "{exec} web ../oioioi/test.sh --runslow", + ), + ( + "test-abc", + "Run specific test file. (edit the toolbox)", + "{exec} web ../oioioi/test.sh -v oioioi/problems/tests/test_task_archive.py", + ), + ( + "test-coverage", + "Run coverage tests.", + "{exec} 'web' ../oioioi/test.sh oioioi/problems --cov-report term --cov-report xml:coverage.xml --cov=oioioi", + ), + ( + "cypress-apply-settings", + "Apply settings for CyPress.", + "{exec} web bash -c \"echo CAPTCHA_TEST_MODE=True >> settings.py\"", + ), ] longest_command_arg = max([len(command[0]) for command in RAW_COMMANDS]) @@ -63,7 +85,9 @@ def fill_tty(self, disable=False): self.command = self.command.format(exec="exec -T" if disable else "exec") def long_str(self) -> str: - return f"Option({self.arg}, Description='{self.help}', Command='{self.command}')" + return ( + f"Option({self.arg}, Description='{self.help}', Command='{self.command}')" + ) def __str__(self) -> str: spaces = longest_command_arg - len(self.arg) @@ -75,7 +99,9 @@ def __str__(self) -> str: def check_commands() -> None: if len(set([opt.arg for opt in COMMANDS])) != len(COMMANDS): - raise Exception("Error in COMMANDS. Same name was declared for more then one command.") + raise Exception( + "Error in COMMANDS. Same name was declared for more then one command." + ) NO_INPUT = False @@ -110,12 +136,9 @@ def get_action_from_args() -> Option: def get_action_from_gui() -> Option: import inquirer + questions = [ - inquirer.List( - "action", - message="Select OIOIOI action", - choices=COMMANDS - ) + inquirer.List("action", message="Select OIOIOI action", choices=COMMANDS) ] answers = inquirer.prompt(questions) return answers["action"] @@ -130,7 +153,9 @@ def run_command(command) -> None: def warn_user(action: Option) -> bool: - print(f"You are going to execute command [{action.command}] marked as `dangerous`. Are you sure? [y/N]") + print( + f"You are going to execute command [{action.command}] marked as `dangerous`. Are you sure? [y/N]" + ) while True: choice = input().lower() if not choice or "no".startswith(choice): @@ -152,10 +177,19 @@ def run() -> None: def print_help() -> None: - print("OIOIOI helper toolbox", "", "This script allows to control OIOIOI with Docker commands.", - f"Commands are always being run with '{BASE_DOCKER_COMMAND}' prefix.", - f"Aveliable commands are: ", "", - *COMMANDS, "", "Example `build`:", f"{sys.argv[0]} build", sep="\n") + print( + "OIOIOI helper toolbox", + "", + "This script allows to control OIOIOI with Docker commands.", + f"Commands are always being run with '{BASE_DOCKER_COMMAND}' prefix.", + f"Aveliable commands are: ", + "", + *COMMANDS, + "", + "Example `build`:", + f"{sys.argv[0]} build", + sep="\n", + ) def main() -> None: diff --git a/oioioi/__init__.py b/oioioi/__init__.py index a8063f0ac..b7974eefd 100644 --- a/oioioi/__init__.py +++ b/oioioi/__init__.py @@ -1,2 +1,2 @@ # apply monkey patch -from oioioi.contests import current_contest +from oioioi.contests import current_contest # noqa diff --git a/oioioi/_locale/apps.py b/oioioi/_locale/apps.py index 1b82a1f64..060073e68 100644 --- a/oioioi/_locale/apps.py +++ b/oioioi/_locale/apps.py @@ -4,4 +4,3 @@ class LocaleConfig(AppConfig): default_auto_field = 'django.db.models.AutoField' name = 'oioioi._locale' - \ No newline at end of file diff --git a/oioioi/acm/controllers.py b/oioioi/acm/controllers.py index 52e2d1fc8..93d842d42 100644 --- a/oioioi/acm/controllers.py +++ b/oioioi/acm/controllers.py @@ -58,8 +58,9 @@ def fill_evaluation_environ(self, environ, submission): def update_report_statuses(self, submission, queryset): if submission.kind == 'TESTRUN': - self._activate_newest_report(submission, queryset, - kind=['TESTRUN', 'FAILURE']) + self._activate_newest_report( + submission, queryset, kind=['TESTRUN', 'FAILURE'] + ) return self._activate_newest_report(submission, queryset, kind=['FULL', 'FAILURE']) diff --git a/oioioi/acm/score.py b/oioioi/acm/score.py index f116ba2e0..9cadf4f96 100644 --- a/oioioi/acm/score.py +++ b/oioioi/acm/score.py @@ -163,7 +163,7 @@ def _to_repr(self): ``penalties_count`` is number of unsuccessful submissions. """ - ordering = 10 ** 10 * (self.problems_solved + 1) - self.total_time + ordering = 10**10 * (self.problems_solved + 1) - self.total_time return '%020d:%010d:%010d:%010d' % ( ordering, self.problems_solved, diff --git a/oioioi/acm/utils.py b/oioioi/acm/utils.py index 78012e957..dd7b54256 100644 --- a/oioioi/acm/utils.py +++ b/oioioi/acm/utils.py @@ -8,16 +8,12 @@ def acm_test_scorer(test, result): def acm_group_scorer(test_results): - status = aggregate_statuses( - [result['status'] for result in test_results.values()] - ) + status = aggregate_statuses([result['status'] for result in test_results.values()]) return None, None, status def acm_score_aggregator(group_results): if not group_results: return None, None, 'OK' - status = aggregate_statuses( - [result['status'] for result in group_results.values()] - ) + status = aggregate_statuses([result['status'] for result in group_results.values()]) return BinaryScore(status == 'OK'), BinaryScore(True), status diff --git a/oioioi/balloons/management/commands/import_balloons_displays.py b/oioioi/balloons/management/commands/import_balloons_displays.py index b25b78eb9..bcd05feb4 100644 --- a/oioioi/balloons/management/commands/import_balloons_displays.py +++ b/oioioi/balloons/management/commands/import_balloons_displays.py @@ -1,7 +1,7 @@ import csv import os - import urllib.request + from django.contrib.auth.models import User from django.core.exceptions import ValidationError from django.core.management.base import BaseCommand, CommandError @@ -111,6 +111,4 @@ def handle(self, *args, **options): if ok: self.stdout.write(_("Processed %d entries") % (all_count)) else: - raise CommandError( - _("There were some errors. Database not changed.\n") - ) + raise CommandError(_("There were some errors. Database not changed.\n")) diff --git a/oioioi/balloons/models.py b/oioioi/balloons/models.py index 6ff399918..d655b1fff 100644 --- a/oioioi/balloons/models.py +++ b/oioioi/balloons/models.py @@ -1,6 +1,5 @@ from django.contrib.auth.models import User from django.db import models - from django.utils.translation import gettext_lazy as _ from oioioi.base.utils import generate_key @@ -11,7 +10,6 @@ check_django_app_dependencies(__name__, ['oioioi.participants', 'oioioi.acm']) - class ProblemBalloonsConfig(models.Model): problem_instance = models.OneToOneField( ProblemInstance, @@ -27,13 +25,7 @@ class Meta(object): verbose_name_plural = _("balloons colors") def __str__(self): - return ( - str(self.problem_instance) - + u' (' - + str(self.color) - + u')' - ) - + return str(self.problem_instance) + u' (' + str(self.color) + u')' class BalloonsDisplay(models.Model): @@ -55,7 +47,6 @@ def __str__(self): return str(self.ip_addr) - class BalloonDelivery(models.Model): user = models.ForeignKey(User, verbose_name=_("user"), on_delete=models.CASCADE) problem_instance = models.ForeignKey( diff --git a/oioioi/base/admin.py b/oioioi/base/admin.py index 3edb300e0..98c2c04a1 100644 --- a/oioioi/base/admin.py +++ b/oioioi/base/admin.py @@ -1,4 +1,5 @@ import urllib.parse + from django.contrib import admin, messages from django.contrib.admin import helpers from django.contrib.admin.sites import AdminSite as DjangoAdminSite @@ -62,10 +63,7 @@ class ModelAdminMeta(admin.ModelAdmin.__class__, ClassInitMeta): pass -class ModelAdmin( - admin.ModelAdmin, ObjectWithMixins, metaclass=ModelAdminMeta -): - +class ModelAdmin(admin.ModelAdmin, ObjectWithMixins, metaclass=ModelAdminMeta): # This is handled by AdminSite._reinit_model_admins allow_too_late_mixins = True @@ -332,11 +330,7 @@ def get_urls(self): def login(self, request, extra_context=None): next_url = request.GET.get('next', None) - suffix = ( - '?' + urllib.parse.urlencode({'next': next_url}) - if next_url - else '' - ) + suffix = '?' + urllib.parse.urlencode({'next': next_url}) if next_url else '' return HttpResponseRedirect(reverse('auth_login') + suffix) diff --git a/oioioi/base/api.py b/oioioi/base/api.py index 06de8b364..8889be91f 100644 --- a/oioioi/base/api.py +++ b/oioioi/base/api.py @@ -12,14 +12,14 @@ @api_view() def ping(request): - """ Test endpoint for unauthorized user. """ + """Test endpoint for unauthorized user.""" return Response("pong") @api_view() @enforce_condition(not_anonymous, login_redirect=False) def auth_ping(request): - """ Test endpoint for authorized user. """ + """Test endpoint for authorized user.""" return Response("pong " + str(request.user)) diff --git a/oioioi/base/captcha_check.py b/oioioi/base/captcha_check.py index 72ed76cd5..cd2fa396e 100644 --- a/oioioi/base/captcha_check.py +++ b/oioioi/base/captcha_check.py @@ -13,7 +13,6 @@ class CaptchaAudioWarning(Warning): def _check_executable(setting_name, path, expected_code=0): - if not os.path.isfile(path): raise ImproperlyConfigured( '{}: {} is not a valid path.'.format(setting_name, path) diff --git a/oioioi/base/fields.py b/oioioi/base/fields.py index 48158afc5..abc5c0686 100644 --- a/oioioi/base/fields.py +++ b/oioioi/base/fields.py @@ -178,7 +178,7 @@ def __iter__(self): return self.entries.__iter__() def __getitem__(self, key): - for (val, desc) in self: + for val, desc in self: if val == key: return desc raise KeyError(key) @@ -194,7 +194,7 @@ def register(self, value, description): def get(self, value, fallback): """Return description for a given value, or fallback if value not in registry""" - for (val, desc) in self: + for val, desc in self: if val == value: return desc return fallback diff --git a/oioioi/base/forms.py b/oioioi/base/forms.py index c331ef54c..47717f373 100644 --- a/oioioi/base/forms.py +++ b/oioioi/base/forms.py @@ -7,18 +7,19 @@ from django.contrib.auth import get_user_model from django.contrib.auth.forms import ( PasswordResetForm, - UserChangeForm, UserCreationForm, ) from django.contrib.auth.models import User from django.core.validators import RegexValidator from django.forms import BooleanField, ChoiceField -from django.forms import ChoiceField from django.utils.translation import gettext_lazy as _ from registration.forms import RegistrationForm from oioioi.base.models import Consents, PreferencesSaved -from oioioi.base.preferences import PreferencesFactory, ensure_preferences_exist_for_user +from oioioi.base.preferences import ( + PreferencesFactory, + ensure_preferences_exist_for_user, +) from oioioi.base.utils.user import UNICODE_CATEGORY_LIST, USERNAME_REGEX from oioioi.base.utils.validators import UnicodeValidator, ValidationError @@ -68,6 +69,7 @@ def _maybe_add_field(label, *args, **kwargs): kwargs.setdefault('label', label) PreferencesFactory.add_field(*args, **kwargs) + def adjust_preferences_factory_fields(): choices_not_translated = [("", "None")] + list(settings.LANGUAGES) choices = [(k, _(v)) for k, v in choices_not_translated] @@ -84,7 +86,7 @@ def handle_preferred_language(user): lambda name, user: handle_preferred_language(user), label=_("Preferred language"), choices=choices, - required=False + required=False, ) def handle_enable_editor(user): @@ -100,9 +102,10 @@ def handle_enable_editor(user): lambda name, user: handle_enable_editor(user), label=_("Enable editor"), order=0, - required=False + required=False, ) + def handle_new_preference_fields(request, user): changed = False ensure_preferences_exist_for_user(user) @@ -127,6 +130,7 @@ def handle_new_preference_fields(request, user): if changed: user.userpreferences.save() + _maybe_add_field( settings.REGISTRATION_RULES_CONSENT, 'terms_accepted', @@ -153,6 +157,7 @@ def handle_new_preference_fields(request, user): adjust_preferences_factory_fields() + def save_consents(sender, user, **kwargs): form = sender consents = None @@ -232,14 +237,14 @@ def save(self, *args, **kwargs): PreferencesSaved.send(self, user=instance) return instance + class UserChangeForm(UserForm): confirm_password = forms.CharField(widget=forms.PasswordInput(), required=False) class Media(object): js = ('js/email-change.js',) - def __init__(self, *args, **kwargs): - + def __init__(self, *args, **kwargs): super(UserChangeForm, self).__init__(*args, **kwargs) self.user = kwargs.pop('instance', None) @@ -253,7 +258,10 @@ def clean_confirm_password(self): return confirm_password if not self.user.check_password(confirm_password): - raise forms.ValidationError(_("Password incorrect."), code='password_incorrect', ) + raise forms.ValidationError( + _("Password incorrect."), + code='password_incorrect', + ) return confirm_password diff --git a/oioioi/base/main_page.py b/oioioi/base/main_page.py index 2947977f7..a8d69c324 100644 --- a/oioioi/base/main_page.py +++ b/oioioi/base/main_page.py @@ -54,7 +54,6 @@ def unregister_main_page_view(view): def main_page_view(request): - for entry in _main_page_registry: if entry.condition(request): return entry.view(request) diff --git a/oioioi/base/management/commands/import_users.py b/oioioi/base/management/commands/import_users.py index 2b9582c21..91ac6cd01 100644 --- a/oioioi/base/management/commands/import_users.py +++ b/oioioi/base/management/commands/import_users.py @@ -1,7 +1,7 @@ import csv import os - import urllib.request + from django.contrib.auth.models import User from django.core.exceptions import ValidationError from django.core.management.base import BaseCommand, CommandError @@ -100,6 +100,4 @@ def handle(self, *args, **options): if ok: self.stdout.write(_("Processed %d entries") % (all_count)) else: - raise CommandError( - _("There were some errors. Database not changed.\n") - ) + raise CommandError(_("There were some errors. Database not changed.\n")) diff --git a/oioioi/base/menu.py b/oioioi/base/menu.py index 9ac7d5717..8f9314abc 100644 --- a/oioioi/base/menu.py +++ b/oioioi/base/menu.py @@ -59,7 +59,6 @@ class MenuItem(object): def __init__( self, name, text, url_generator, condition=None, attrs=None, order=sys.maxsize ): - if condition is None: condition = Condition(lambda request: True) @@ -96,7 +95,8 @@ def _get_all_registered_items(self, request): def __init__(self, text=None, condition=None, show_icons=False): self.text = text if condition is None: - condition = lambda request: True + def condition(request): + return True self.condition = condition self.show_icons = show_icons self._registry = [] diff --git a/oioioi/base/middleware.py b/oioioi/base/middleware.py index 19a44dd17..e1c1da8fb 100644 --- a/oioioi/base/middleware.py +++ b/oioioi/base/middleware.py @@ -1,15 +1,14 @@ from dateutil.parser import parse as parse_date +from django.conf import settings from django.contrib import messages from django.contrib.auth import BACKEND_SESSION_KEY from django.core.exceptions import ImproperlyConfigured from django.http import HttpResponseNotAllowed from django.template.loader import render_to_string from django.urls import reverse -from django.utils import timezone +from django.utils import timezone, translation from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy as _ -from django.conf import settings -from django.utils import translation from oioioi.base.preferences import ensure_preferences_exist_for_user from oioioi.base.utils.middleware import was_response_generated_by_exception @@ -185,8 +184,9 @@ def __call__(self, request): def _process_request(self, request): # checking data set by set_first_view_after_logging_flag signal handler: - just_logged_in = ('first_view_after_logging' in request.session) and \ - request.session['first_view_after_logging'] is True + just_logged_in = ( + 'first_view_after_logging' in request.session + ) and request.session['first_view_after_logging'] is True ensure_preferences_exist_for_user(request.user) @@ -196,8 +196,9 @@ def _process_request(self, request): if just_logged_in and pref_lang != "": self.lang = pref_lang - if ((not just_logged_in) or pref_lang == "") and \ - settings.LANGUAGE_COOKIE_NAME in request.COOKIES.keys(): + if ( + (not just_logged_in) or pref_lang == "" + ) and settings.LANGUAGE_COOKIE_NAME in request.COOKIES.keys(): self.lang = request.COOKIES[settings.LANGUAGE_COOKIE_NAME] translation.activate(self.lang) @@ -205,8 +206,13 @@ def _process_request(self, request): def _process_response(self, request, response): if settings.LANGUAGE_COOKIE_NAME in request.COOKIES: - response.set_cookie(settings.LANGUAGE_COOKIE_NAME, - request.COOKIES[settings.LANGUAGE_COOKIE_NAME], samesite='lax') + response.set_cookie( + settings.LANGUAGE_COOKIE_NAME, + request.COOKIES[settings.LANGUAGE_COOKIE_NAME], + samesite='lax', + ) else: - response.set_cookie(settings.LANGUAGE_COOKIE_NAME, self.lang, samesite='lax') + response.set_cookie( + settings.LANGUAGE_COOKIE_NAME, self.lang, samesite='lax' + ) return response diff --git a/oioioi/base/models.py b/oioioi/base/models.py index cc56182ec..61c3e3de4 100644 --- a/oioioi/base/models.py +++ b/oioioi/base/models.py @@ -1,12 +1,18 @@ # coding: utf-8 +import logging from importlib import import_module import django.dispatch from django.conf import settings +from django.contrib.auth.models import User +from django.db import models +from django.db.models.signals import post_save +from django.dispatch import receiver +from django.utils.translation import gettext_lazy as _ # pylint: disable=unused-import # Important. This import is to register signal handlers. Do not remove it. -import oioioi.base.signal_handlers +import oioioi.base.signal_handlers # noqa: F401 from oioioi.base.captcha_check import captcha_check from oioioi.base.setup_check import setup_check @@ -24,14 +30,6 @@ except ImportError: pass -import logging - -from django.contrib.auth.models import User -from django.db import models -from django.db.models.signals import post_save -from django.dispatch import receiver -from django.utils.translation import gettext_lazy as _ - auditLogger = logging.getLogger(__name__ + ".audit") # Sender will be equal to the form that was completed @@ -60,7 +58,7 @@ class UserPreferences(models.Model): _("preferred_language"), max_length=2, choices=list(settings.LANGUAGES) + [("", _("None"))], - default="" + default="", ) enable_editor = models.BooleanField( diff --git a/oioioi/base/notification.py b/oioioi/base/notification.py index 9f919bca5..c2a2c8516 100644 --- a/oioioi/base/notification.py +++ b/oioioi/base/notification.py @@ -2,9 +2,9 @@ import logging import threading import time +import urllib.parse import uuid -import urllib.parse from django.conf import settings from pika import BlockingConnection, ConnectionParameters, PlainCredentials from pika.exceptions import AMQPChannelError, AMQPConnectionError diff --git a/oioioi/base/permissions.py b/oioioi/base/permissions.py index 01328945b..5a8749358 100644 --- a/oioioi/base/permissions.py +++ b/oioioi/base/permissions.py @@ -44,21 +44,20 @@ def __call__(self, *args, **kwargs): def __or__(self, other): if not isinstance(other, Condition): return NotImplemented - condition_or = lambda *args, **kwargs: self(*args, **kwargs) or other( - *args, **kwargs - ) + def condition_or(*args, **kwargs): + return self(*args, **kwargs) or other(*args, **kwargs) return Condition(condition_or) def __and__(self, other): if not isinstance(other, Condition): return NotImplemented - condition_and = lambda *args, **kwargs: self(*args, **kwargs) and other( - *args, **kwargs - ) + def condition_and(*args, **kwargs): + return self(*args, **kwargs) and other(*args, **kwargs) return Condition(condition_and) def __invert__(self): - condition_inverted = lambda *args, **kwargs: not self(*args, **kwargs) + def condition_inverted(*args, **kwargs): + return not self(*args, **kwargs) return Condition(condition_inverted) diff --git a/oioioi/base/preferences.py b/oioioi/base/preferences.py index 281c74b57..739f420e5 100644 --- a/oioioi/base/preferences.py +++ b/oioioi/base/preferences.py @@ -1,6 +1,8 @@ from collections import OrderedDict + from oioioi.base.models import UserPreferences + # Huge thanks to: http://jacobian.org/writing/dynamic-form-generation/ class PreferencesFactory(object): """Since each app might want to add new options for the user to edit in his diff --git a/oioioi/base/registration_backend.py b/oioioi/base/registration_backend.py index 9d482c1a7..9a93241e9 100644 --- a/oioioi/base/registration_backend.py +++ b/oioioi/base/registration_backend.py @@ -1,10 +1,9 @@ import logging -import registration.backends.default.urls -import registration.views +import registration.backends.default.urls as default_urls from django.conf import settings from django.contrib.auth.models import User -from django.contrib.auth.views import PasswordResetView, PasswordResetDoneView +from django.contrib.auth.views import PasswordResetView from django.contrib.sites.requests import RequestSite from django.urls import re_path, reverse_lazy from django.views.generic import TemplateView @@ -14,8 +13,7 @@ ) from registration.models import RegistrationProfile -from oioioi.base.forms import OioioiPasswordResetForm, RegistrationFormWithNames -from oioioi.base.forms import handle_new_preference_fields +from oioioi.base.forms import OioioiPasswordResetForm, RegistrationFormWithNames, handle_new_preference_fields from oioioi.base.models import PreferencesSaved from oioioi.base.preferences import PreferencesFactory @@ -89,4 +87,4 @@ def register(self, form): ), ] -urlpatterns += registration.backends.default.urls.urlpatterns +urlpatterns += default_urls.urlpatterns diff --git a/oioioi/base/signal_handlers.py b/oioioi/base/signal_handlers.py index a159beb26..558b3aa01 100644 --- a/oioioi/base/signal_handlers.py +++ b/oioioi/base/signal_handlers.py @@ -1,4 +1,3 @@ -import django from django.contrib.auth.signals import user_logged_in from django.db.backends.signals import connection_created from django.dispatch import receiver diff --git a/oioioi/base/tests/__init__.py b/oioioi/base/tests/__init__.py index 3968debcd..ad7f6f733 100644 --- a/oioioi/base/tests/__init__.py +++ b/oioioi/base/tests/__init__.py @@ -1,14 +1,13 @@ import sys import threading +import urllib.parse from contextlib import contextmanager import pytest -import urllib.parse -from django.contrib.auth.models import AnonymousUser, User +from django.contrib.auth.models import User from django.core.cache import cache from django.core.exceptions import ImproperlyConfigured from django.db import DEFAULT_DB_ALIAS, connections -from django.template.loaders.cached import Loader as CachedLoader from django.test import TestCase as DjangoTestCase from django.test.utils import CaptureQueriesContext from django.urls import reverse @@ -42,7 +41,6 @@ def __exit__(self, exc_type, exc_value, traceback): class TestCase(DjangoTestCase): - # Based on: https://github.com/revsys/django-test-plus/blob/master/test_plus/test.py#L236 def assertNumQueriesLessThan(self, num, *args, **kwargs): func = kwargs.pop('func', None) diff --git a/oioioi/base/tests/tests.py b/oioioi/base/tests/tests.py index 310a23605..d5e0bc75f 100644 --- a/oioioi/base/tests/tests.py +++ b/oioioi/base/tests/tests.py @@ -723,7 +723,7 @@ def test_registration_form_fields(self): self.assertIn('last_name', form.fields) def _register_user(self, terms_accepted=True, pass_captcha=True): - response = self.client.get(reverse('registration_register')) + self.client.get(reverse('registration_register')) captcha_count = CaptchaStore.objects.count() self.assertEqual(captcha_count, 1) captcha = CaptchaStore.objects.all()[0] @@ -778,7 +778,6 @@ def test_registration_captcha_not_passed(self): self.assertEqual(User.objects.filter(username='test_foo').count(), 0) - class TestArchive(TestCase): good_files = ['archive.tgz', 'archive.zip'] bad_files = ['archive-with-symlink.tgz', 'archive-with-hardlink.tgz'] @@ -884,7 +883,7 @@ def test_edit_profile_view(self): self.assertEqual(user.last_name, 'ln') def test_edit_email(self): - #Trying to use incorrect email. + # Trying to use incorrect email. self.data['email'] = 'a@a' self.data['first_name'] = 'fn_new' self.data['last_name'] = 'ln_new' @@ -905,7 +904,6 @@ def test_edit_email(self): self.assertEqual(self.user.first_name, self.first_name) self.assertEqual(self.user.last_name, self.last_name) - # Trying to change email with wrong password. self.data['confirm_password'] = 'not-the-password' response = self.client.post(self.url_edit_profile, self.data, follow=True) @@ -940,7 +938,6 @@ def test_terms_not_accepted(self): # and that the user sees an error self.assertContains(response, 'field is required') - self.data.pop('terms_accepted') response = self.client.post(self.url_edit_profile, self.data, follow=True) self.assertEqual(response.status_code, 200) @@ -978,8 +975,8 @@ def test_unicode_wrong_last_name(self): self.assertEqual(self.user.last_name, self.last_name) def test_names_with_valid_spaces(self): - self.data['first_name'] = u'Jan Maria', - self.data['last_name'] = u'Le Guien', + self.data['first_name'] = (u'Jan Maria',) + self.data['last_name'] = (u'Le Guien',) response = self.client.post(self.url_edit_profile, self.data, follow=True) self.assertEqual(response.status_code, 200) self.user.refresh_from_db() @@ -1032,12 +1029,14 @@ def callback_func(sender, **kwargs): for text in ['Doggy', 'Andrzej', '72', 'The answer to everything']: self.assertContains(response, text) - self.data.update({ - 'first_name': 'fn', - 'last_name': 'ln', - 'dog': 'Janusz', - 'answer': '42', - }) + self.data.update( + { + 'first_name': 'fn', + 'last_name': 'ln', + 'dog': 'Janusz', + 'answer': '42', + } + ) self.client.post(self.url_edit_profile, self.data, follow=True) # callback_func should be called already @@ -1211,23 +1210,23 @@ def setUp(self): self.url_edit_profile = reverse('edit_profile') def test_message(self): - for l in self.invalid_logins: - self.user.username = l + for valid_login in self.invalid_logins: + self.user.username = valid_login self.user.save() response = self.client.get(self.url_index, follow=True) self.assertContains(response, 'contains forbidden characters') - for l in self.valid_logins: - self.user.username = l + for valid_login in self.valid_logins: + self.user.username = valid_login self.user.save() response = self.client.get(self.url_index, follow=True) self.assertNotContains(response, 'contains forbidden characters') def test_can_change_login_from_invalid(self): - for l in self.invalid_logins: - self.user.username = l + for invalid_login in self.invalid_logins: + self.user.username = invalid_login self.user.save() response = self.client.get(self.url_edit_profile) @@ -1236,16 +1235,20 @@ def test_can_change_login_from_invalid(self): response, '' % l, + 'maxlength="150" required />' % invalid_login, html=True, ) self.client.post( self.url_edit_profile, - {'username': 'valid_user', 'terms_accepted': True, 'email': "test_user@example.com"}, + { + 'username': 'valid_user', + 'terms_accepted': True, + 'email': "test_user@example.com", + }, follow=True, ) - self.assertEqual(self.user.username, l) + self.assertEqual(self.user.username, invalid_login) response = self.client.post(self.url_index, follow=True) self.assertNotContains(response, 'contains not allowed characters') @@ -1260,8 +1263,8 @@ def test_can_change_login_from_invalid(self): ) def test_login_cannot_change_from_valid(self): - for l in self.valid_logins: - self.user.username = l + for valid_login in self.valid_logins: + self.user.username = valid_login self.user.save() response = self.client.get(self.url_edit_profile) @@ -1269,7 +1272,7 @@ def test_login_cannot_change_from_valid(self): response, '' % l, + 'maxlength="150" readonly required />' % valid_login, html=True, ) @@ -1278,7 +1281,7 @@ def test_login_cannot_change_from_valid(self): {'username': 'valid_user', 'terms_accepted': True}, follow=True, ) - self.assertEqual(self.user.username, l) + self.assertEqual(self.user.username, valid_login) self.assertContains(response, 'You cannot change your username.') response = self.client.get(self.url_index, follow=True) @@ -1293,9 +1296,9 @@ def test_failed_login_change(self): self.user.username = self.invalid_logins[0] self.user.save() - for l in self.invalid_logins: + for invalid_login in self.invalid_logins: self.client.post( - url_edit_profile, {'username': l, 'terms_accepted': True}, follow=True + url_edit_profile, {'username': invalid_login, 'terms_accepted': True}, follow=True ) self.assertEqual(self.user.username, self.invalid_logins[0]) @@ -1395,7 +1398,7 @@ def test_strip_num_or_hash(self): 'a_1_2.pdf': 'a_1.pdf', } - for (before, after) in cases.items(): + for before, after in cases.items(): self.assertEqual(strip_num_or_hash(before), after) @@ -1461,7 +1464,6 @@ def test_api_token_regeneration(self): class TestDocsEndpoints(APITestCase): - def test_docs(self): response = self.client.get('/api/docs', follow=True) self.assertContains(response, "OIOIOI API") @@ -1508,15 +1510,16 @@ class TestPasswordReset(TestCase): fixtures = ['test_users'] def setUp(self): - self.user = User.objects.create_user('test_email_user', 'test@test.com', 'test1234') + self.user = User.objects.create_user( + 'test_email_user', 'test@test.com', 'test1234' + ) def test_reset_password_email_send_existing(self): - response = self.client.post(reverse('auth_password_reset'), data={'email': self.user.email}) - self.assertEqual(len(mail.outbox), 1) - self.assertRedirects( - response, - reverse('auth_password_reset_done') + response = self.client.post( + reverse('auth_password_reset'), data={'email': self.user.email} ) + self.assertEqual(len(mail.outbox), 1) + self.assertRedirects(response, reverse('auth_password_reset_done')) class TestAccountDeletion(TestCase): @@ -1551,7 +1554,6 @@ def test_account_deletion_no_password(self): class TestJsCatalog(TestCase): - def test_javascript_catalog(self): response = self.client.get(reverse('javascript_catalog')) self.assertContains(response, 'jsi18n_initialized') diff --git a/oioioi/base/urls.py b/oioioi/base/urls.py index 50b2a2907..bbe3f8d56 100644 --- a/oioioi/base/urls.py +++ b/oioioi/base/urls.py @@ -1,10 +1,11 @@ from django.conf import settings from django.urls import include, re_path -from oioioi.base import admin, api, views -from oioioi.base.main_page import main_page_view from rest_framework.documentation import include_docs_urls from two_factor.urls import urlpatterns as tf_urls +from oioioi.base import admin, api, views +from oioioi.base.main_page import main_page_view + app_name = 'base' urlpatterns = [ @@ -37,7 +38,9 @@ if settings.USE_API: urlpatterns += [ re_path(r'^api/token', api.api_token, name='api_token'), - re_path(r'^api/regenerate_token', api.regenerate_token, name='api_regenerate_key'), + re_path( + r'^api/regenerate_token', api.regenerate_token, name='api_regenerate_key' + ), ] noncontest_patterns += [ # the c prefix doesn't make sense for non contest related endpoints as diff --git a/oioioi/base/utils/__init__.py b/oioioi/base/utils/__init__.py index b87165070..f3fb112b5 100644 --- a/oioioi/base/utils/__init__.py +++ b/oioioi/base/utils/__init__.py @@ -7,15 +7,13 @@ import shutil import sys import tempfile +import urllib.parse from contextlib import contextmanager from importlib import import_module import six -import urllib.parse from django.forms.utils import flatatt from django.http import Http404, HttpResponse, HttpResponseRedirect -from django.shortcuts import render -from django.template import Template from django.template.loader import render_to_string from django.template.response import TemplateResponse from django.utils.encoding import force_str @@ -438,9 +436,7 @@ def tabbed_view(request, template, context, tabs, tab_kwargs, link_builder): raise Http404 qs = request.GET.dict() qs['key'] = next(iter(tabs)).key - return HttpResponseRedirect( - request.path + '?' + urllib.parse.urlencode(qs) - ) + return HttpResponseRedirect(request.path + '?' + urllib.parse.urlencode(qs)) key = request.GET['key'] for tab in tabs: if tab.key == key: @@ -510,7 +506,8 @@ def strip_num_or_hash(filename): def naturalsort_key(key): - convert = lambda text: int(text) if text.isdigit() else text + def convert(text): + return int(text) if text.isdigit() else text return [convert(c) for c in re.split('([0-9]+)', key)] diff --git a/oioioi/base/utils/archive.py b/oioioi/base/utils/archive.py index 8715cf543..2445d5500 100644 --- a/oioioi/base/utils/archive.py +++ b/oioioi/base/utils/archive.py @@ -22,7 +22,6 @@ # THE SOFTWARE. import os -import sys import tarfile import tempfile import zipfile @@ -77,11 +76,7 @@ def __del__(self): @staticmethod def _resolve_streamed_files(file, ext): - if ( - isinstance(file, str) - or hasattr(file, 'seek') - or hasattr(file, 'tell') - ): + if isinstance(file, str) or hasattr(file, 'seek') or hasattr(file, 'tell'): return file, False lookup_filename = file.name + ext base, tail_ext = os.path.splitext(lookup_filename.lower()) diff --git a/oioioi/base/utils/color.py b/oioioi/base/utils/color.py index 4fc8ca853..59ddd9d65 100644 --- a/oioioi/base/utils/color.py +++ b/oioioi/base/utils/color.py @@ -1,6 +1,5 @@ import re -import django from django import forms from django.core.validators import RegexValidator from django.db import models diff --git a/oioioi/base/utils/filters.py b/oioioi/base/utils/filters.py index b60f3179c..6d8bb97fa 100644 --- a/oioioi/base/utils/filters.py +++ b/oioioi/base/utils/filters.py @@ -2,6 +2,7 @@ from django.db.models import Case, F, Subquery, When from django.utils.translation import get_language from django.utils.translation import gettext_lazy as _ + from oioioi.problems.models import ProblemName diff --git a/oioioi/base/utils/finders.py b/oioioi/base/utils/finders.py index 14352bb89..adc71cd86 100644 --- a/oioioi/base/utils/finders.py +++ b/oioioi/base/utils/finders.py @@ -1,5 +1,4 @@ import shutil -from distutils import spawn def find_executable_path(name): diff --git a/oioioi/base/utils/input_with_generate.py b/oioioi/base/utils/input_with_generate.py index aafd0a4f4..28a59a80c 100644 --- a/oioioi/base/utils/input_with_generate.py +++ b/oioioi/base/utils/input_with_generate.py @@ -1,4 +1,3 @@ -import django from django import forms from django.utils.safestring import mark_safe diff --git a/oioioi/base/utils/middleware.py b/oioioi/base/utils/middleware.py index 5be135924..35c5da7fa 100644 --- a/oioioi/base/utils/middleware.py +++ b/oioioi/base/utils/middleware.py @@ -1,5 +1,6 @@ EXCEPTION_GENERATED_STATUS_CODES = [400, 403, 404, 500] + # Django converts exceptions from middlewares to HttpResponses with above # status codes. Overridable method of middleware factory process_exception() # processes only exceptions generated by the view itself, but sometimes we want diff --git a/oioioi/base/utils/redirect.py b/oioioi/base/utils/redirect.py index 47230d687..725a30c3b 100644 --- a/oioioi/base/utils/redirect.py +++ b/oioioi/base/utils/redirect.py @@ -4,7 +4,9 @@ def safe_redirect(request, url, fallback='index'): - if url and url_has_allowed_host_and_scheme(url=url, allowed_hosts=request.get_host()): + if url and url_has_allowed_host_and_scheme( + url=url, allowed_hosts=request.get_host() + ): next_page = url else: next_page = reverse(fallback) diff --git a/oioioi/base/utils/test_migrations.py b/oioioi/base/utils/test_migrations.py index 940a0c6e3..6f6a0156c 100644 --- a/oioioi/base/utils/test_migrations.py +++ b/oioioi/base/utils/test_migrations.py @@ -3,6 +3,7 @@ from django.db import connection from django.db.migrations.executor import MigrationExecutor + class TestCaseMigrations(test.TestCase): """TestCase for Django Migrations diff --git a/oioioi/base/utils/user.py b/oioioi/base/utils/user.py index 8ae7ed798..32f8ad75c 100644 --- a/oioioi/base/utils/user.py +++ b/oioioi/base/utils/user.py @@ -1,5 +1,4 @@ import re -from unicodedata import category from django.core.exceptions import ValidationError diff --git a/oioioi/base/utils/user_selection.py b/oioioi/base/utils/user_selection.py index f2c0bb6da..bbd5690d6 100644 --- a/oioioi/base/utils/user_selection.py +++ b/oioioi/base/utils/user_selection.py @@ -1,4 +1,3 @@ -import django from django import forms from django.conf import settings from django.contrib.auth.models import User @@ -7,6 +6,7 @@ from django.http import Http404 from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy as _ + from oioioi.base.utils import jsonify INVALID_USER_SELECTION = '__invalid_user_selection__' @@ -95,7 +95,6 @@ def _parse_user_hint(value, queryset=None, user_field_name=None): if len(value) == 1 or ( len(value) > 1 and value[1].startswith('(') and value[-1].endswith(')') ): - value = value[0] try: @@ -110,9 +109,7 @@ def _parse_user_hint(value, queryset=None, user_field_name=None): class UserSelectionWidget(forms.TextInput): - html_template = ( - "" - ) + html_template = "" def __init__(self, attrs=None): if attrs is None: diff --git a/oioioi/base/views.py b/oioioi/base/views.py index 592b88c9f..6a2de60f7 100644 --- a/oioioi/base/views.py +++ b/oioioi/base/views.py @@ -1,5 +1,4 @@ import traceback -from django.conf import settings from django.contrib.auth import REDIRECT_FIELD_NAME from django.contrib.auth.views import LogoutView as AuthLogoutView @@ -20,7 +19,10 @@ from oioioi.base.forms import handle_new_preference_fields from oioioi.base.menu import account_menu_registry from oioioi.base.permissions import enforce_condition, not_anonymous -from oioioi.base.preferences import PreferencesFactory, ensure_preferences_exist_for_user +from oioioi.base.preferences import ( + PreferencesFactory, + ensure_preferences_exist_for_user, +) from oioioi.base.processors import site_name from oioioi.base.utils import generate_key, is_ajax, jsonify from oioioi.base.utils.redirect import safe_redirect diff --git a/oioioi/base/widgets.py b/oioioi/base/widgets.py index 49941cac4..e5ce8079d 100644 --- a/oioioi/base/widgets.py +++ b/oioioi/base/widgets.py @@ -33,16 +33,22 @@ def render(self, name, value, attrs=None, renderer=None): {'name': name, 'value': value, 'attrs': flatatt(self.build_attrs(attrs))}, ) + class AceEditorWidget(forms.widgets.Textarea): def __init__(self, attrs, default_state=False): super(AceEditorWidget, self).__init__(attrs={'rows': 10, 'class': 'monospace'}) self.default_state = default_state def render(self, name, value, attrs=None, renderer=None): - return super(AceEditorWidget, self).render(name, value, attrs=attrs, renderer=renderer) + \ - render_to_string('widgets/aceeditor.html', - {'editor_id': 'editor', - 'inner_code': '', - 'replace_code_area': 'textarea[name="code"]', - 'toggle_checkbox_id': 'id_toggle_editor', - 'default_state': 'true' if self.default_state else 'false'},) + return super(AceEditorWidget, self).render( + name, value, attrs=attrs, renderer=renderer + ) + render_to_string( + 'widgets/aceeditor.html', + { + 'editor_id': 'editor', + 'inner_code': '', + 'replace_code_area': 'textarea[name="code"]', + 'toggle_checkbox_id': 'id_toggle_editor', + 'default_state': 'true' if self.default_state else 'false', + }, + ) diff --git a/oioioi/complaints/views.py b/oioioi/complaints/views.py index d2c04d809..3c63a06ea 100644 --- a/oioioi/complaints/views.py +++ b/oioioi/complaints/views.py @@ -1,7 +1,7 @@ import urllib +import urllib.parse from uuid import uuid4 -import urllib.parse from django.conf import settings from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist from django.core.mail import EmailMessage @@ -63,9 +63,7 @@ def email_template_context(request, message): 'submissions_link': request.build_absolute_uri( reverse('oioioiadmin:contests_submission_changelist') + '?' - + urllib.parse.urlencode( - {'user__username': request.user.username} - ) + + urllib.parse.urlencode({'user__username': request.user.username}) ), } diff --git a/oioioi/confirmations/utils.py b/oioioi/confirmations/utils.py index 078f9e499..9150f5f61 100644 --- a/oioioi/confirmations/utils.py +++ b/oioioi/confirmations/utils.py @@ -1,13 +1,12 @@ import hashlib -import itertools import logging import sys +from itertools import zip_longest import dateutil.parser from django.conf import settings from django.core import signing from django.template.loader import render_to_string -from itertools import zip_longest from oioioi.programs.models import ProgramSubmission @@ -110,7 +109,7 @@ def send_submission_receipt_confirmation(request, submission): 'problem_shortname': proof_data['problem_name'], 'size': proof_data['size'], 'full_name': submission.user.get_full_name(), - 'user_login': submission.user.username + 'user_login': submission.user.username, } subject = render_to_string('confirmations/email_subject.txt', context) diff --git a/oioioi/contestexcl/forms.py b/oioioi/contestexcl/forms.py index e1b11bbb3..1435fd03c 100644 --- a/oioioi/contestexcl/forms.py +++ b/oioioi/contestexcl/forms.py @@ -1,5 +1,5 @@ from django import forms -from django.forms import BooleanField, ValidationError +from django.forms import ValidationError from django.utils.translation import gettext_lazy as _ from oioioi.base.forms import AlwaysChangedModelForm diff --git a/oioioi/contestexcl/middleware.py b/oioioi/contestexcl/middleware.py index 9ea9079cb..430225ea4 100644 --- a/oioioi/contestexcl/middleware.py +++ b/oioioi/contestexcl/middleware.py @@ -47,7 +47,6 @@ def __call__(self, request): return self.get_response(request) def process_view(self, request, view_func, view_args, view_kwargs, selector=None): - if not self._check_requirements(request): return @@ -57,9 +56,8 @@ def _default_selector(user, contest): if selector is None: final_selector = _default_selector else: - final_selector = lambda user, contest: _default_selector( - user, contest - ) and selector(user, contest) + def final_selector(user, contest): + return _default_selector(user, contest) and selector(user, contest) if settings.ONLY_DEFAULT_CONTEST: qs = [Contest.objects.get(id=settings.DEFAULT_CONTEST)] diff --git a/oioioi/contestexcl/models.py b/oioioi/contestexcl/models.py index 4dd1e8d41..a3d1c802c 100644 --- a/oioioi/contestexcl/models.py +++ b/oioioi/contestexcl/models.py @@ -3,7 +3,6 @@ from django.db import models from django.db.models import Q from django.utils import timezone - from django.utils.translation import gettext_lazy as _ from oioioi.contests.date_registration import date_registry @@ -45,7 +44,6 @@ def get_active_between(self, start, end): @date_registry.register( 'end_date', name_generator=(lambda obj: _("Disable exclusiveness")) ) - class ExclusivenessConfig(models.Model): """Represents an exclusiveness config for a contest. diff --git a/oioioi/contestexcl/tests.py b/oioioi/contestexcl/tests.py index bb690f7ac..695c37d8b 100644 --- a/oioioi/contestexcl/tests.py +++ b/oioioi/contestexcl/tests.py @@ -192,7 +192,7 @@ def _modify_contestexcl( ('contestcompiler_set', 0, 0, 0, 1000), ) data = dict() - for (name, total, initial, min_num, max_num) in formsets: + for name, total, initial, min_num, max_num in formsets: data.update( { '{}-TOTAL_FORMS'.format(name): total, diff --git a/oioioi/contestlogo/urls.py b/oioioi/contestlogo/urls.py index 3e43e7f2d..92355e618 100644 --- a/oioioi/contestlogo/urls.py +++ b/oioioi/contestlogo/urls.py @@ -6,5 +6,7 @@ contest_patterns = [ re_path(r'^logo/$', views.logo_image_view, name='logo_image_view'), - re_path(r'^icons/(?P\d+)/$', views.icon_image_view, name='icon_image_view'), + re_path( + r'^icons/(?P\d+)/$', views.icon_image_view, name='icon_image_view' + ), ] diff --git a/oioioi/contests/admin.py b/oioioi/contests/admin.py index c4c64cc4b..c12b5f208 100644 --- a/oioioi/contests/admin.py +++ b/oioioi/contests/admin.py @@ -1,9 +1,8 @@ import threading -from functools import partial -from django.conf import settings - import urllib.parse +from functools import partial +from django.conf import settings from django.contrib.admin import AllValuesFieldListFilter, SimpleListFilter from django.contrib.admin.sites import NotRegistered from django.contrib.admin.utils import quote, unquote @@ -16,9 +15,9 @@ from django.urls import re_path, reverse from django.utils.encoding import force_str from django.utils.html import format_html -from django.utils.translation import get_language +from django.utils.translation import get_language, ngettext_lazy from django.utils.translation import gettext_lazy as _ -from django.utils.translation import ngettext_lazy + from oioioi.base import admin from oioioi.base.admin import NO_CATEGORY, delete_selected from oioioi.base.utils import make_html_link, make_html_links @@ -398,9 +397,7 @@ def _add_or_update_href(self, instance): return ( reverse('problemset_add_or_update') + '?' - + urllib.parse.urlencode( - {'problem': instance.problem_id, 'key': 'upload'} - ) + + urllib.parse.urlencode({'problem': instance.problem_id, 'key': 'upload'}) ) def _replace_statement_href(self, instance): diff --git a/oioioi/contests/api.py b/oioioi/contests/api.py index 6af22f277..29c13f644 100644 --- a/oioioi/contests/api.py +++ b/oioioi/contests/api.py @@ -1,16 +1,17 @@ from django.http import Http404 from django.shortcuts import get_object_or_404 +from rest_framework import permissions, status, views +from rest_framework.parsers import MultiPartParser +from rest_framework.permissions import IsAuthenticated +from rest_framework.response import Response +from rest_framework.schemas import AutoSchema + from oioioi.base.utils.api import make_path_coreapi_schema from oioioi.contests.forms import SubmissionFormForProblemInstance from oioioi.contests.models import Contest, ProblemInstance from oioioi.contests.serializers import SubmissionSerializer from oioioi.contests.utils import can_enter_contest from oioioi.problems.models import Problem -from rest_framework import permissions, status, views -from rest_framework.parsers import MultiPartParser -from rest_framework.permissions import IsAuthenticated -from rest_framework.response import Response -from rest_framework.schemas import AutoSchema class CanEnterContest(permissions.BasePermission): @@ -65,7 +66,7 @@ class SubmitSolutionView(views.APIView): parser_classes = (MultiPartParser,) def get_problem_instance(self, **kwargs): - raise NotImplemented + raise NotImplementedError def post(self, request, **kwargs): """This endpoint allows you to submit solution for selected problem.""" diff --git a/oioioi/contests/controllers.py b/oioioi/contests/controllers.py index f5c2e6c63..17fd69823 100644 --- a/oioioi/contests/controllers.py +++ b/oioioi/contests/controllers.py @@ -6,7 +6,6 @@ from django.core.exceptions import PermissionDenied from django.core.mail import EmailMessage from django.db import transaction -from django.db.models import Q from django.template.loader import render_to_string from django.urls import reverse from django.utils.safestring import mark_safe diff --git a/oioioi/contests/date_registration.py b/oioioi/contests/date_registration.py index e4355f633..3df3d01e2 100644 --- a/oioioi/contests/date_registration.py +++ b/oioioi/contests/date_registration.py @@ -53,21 +53,24 @@ def decorator(original_class): ) return original_class + def none_returner(obj): + return None + + def default_name_generator(obj): + return str(model._meta.verbose_name) + " " + str(model._meta.get_field(date_field).verbose_name) + if model is None: return decorator if name_generator is None: - name_generator = ( - lambda obj: str(model._meta.verbose_name) - + " " - + str(model._meta.get_field(date_field).verbose_name) - ) + name_generator = default_name_generator if round_chooser is None: - round_chooser = lambda obj: None + round_chooser = none_returner if qs_filter is None: - qs_filter = lambda qs, contest_id: qs.filter(contest=contest_id) + def qs_filter(qs, contest_id): + return qs.filter(contest=contest_id) date_item = self.DateItem( date_field, name_generator, round_chooser, qs_filter, model diff --git a/oioioi/contests/forms.py b/oioioi/contests/forms.py index 64357e963..3f5286a4c 100644 --- a/oioioi/contests/forms.py +++ b/oioioi/contests/forms.py @@ -117,7 +117,9 @@ class SubmissionForm(forms.Form): problem_instance_id = forms.ChoiceField(label=_("Problem")) - _js = ['common/submit.js',] + _js = [ + 'common/submit.js', + ] @property def media(self): @@ -289,8 +291,7 @@ def clean(self, check_submission_limit=True, check_round_times=True): self.request, pi, kind ): raise ValidationError( - _("Submission limit for the problem '%s' exceeded.") - % pi.problem.name + _("Submission limit for the problem '%s' exceeded.") % pi.problem.name ) decision = pi.controller.can_submit(self.request, pi, check_round_times) diff --git a/oioioi/contests/handlers.py b/oioioi/contests/handlers.py index e0c14e2e0..976c8825e 100644 --- a/oioioi/contests/handlers.py +++ b/oioioi/contests/handlers.py @@ -147,7 +147,6 @@ def call_submission_judged(env, submission, **kwargs): assert contest.id == env['contest_id'] contest.controller.submission_judged(submission, rejudged=env['is_rejudge']) - if submission.user is not None and not env['is_rejudge']: logger.info( "Submission %(submission_id)d by user %(username)s" diff --git a/oioioi/contests/management/commands/find_all_se_submissions.py b/oioioi/contests/management/commands/find_all_se_submissions.py index 90686b410..78b776860 100644 --- a/oioioi/contests/management/commands/find_all_se_submissions.py +++ b/oioioi/contests/management/commands/find_all_se_submissions.py @@ -1,36 +1,40 @@ from __future__ import print_function -import six import time +from datetime import datetime, timedelta from django.core.management.base import BaseCommand +from django.db import transaction from django.db.models import Q from django.utils.translation import ugettext as _ -from django.db import transaction -from oioioi.contests.models import Contest, Round, Submission, SubmissionReport -from datetime import datetime, timedelta + +from oioioi.contests.models import Submission, SubmissionReport + class Command(BaseCommand): help = _("Display all submissions that got System Error in the past N days") def add_arguments(self, parser): - parser.add_argument('-n', '--numdays', - action='store', - type=int, - dest='numdays', - help="How many past days of reports to check", - default=10) + parser.add_argument( + '-n', + '--numdays', + action='store', + type=int, + dest='numdays', + help="How many past days of reports to check", + default=10, + ) def handle(self, *args, **options): numdays = options["numdays"] - subs = Submission.objects.filter(date__gte=datetime.now()-timedelta(days=numdays)) + subs = Submission.objects.filter( + date__gte=datetime.now() - timedelta(days=numdays) + ) raporty = SubmissionReport.objects.filter(submission__in=subs) # problem_instance.controller.judge(submission, is_rejudge=True) q = Q( failurereport__isnull=False, - ) | Q( - testreport__status='SE' - ) + ) | Q(testreport__status='SE') raporty_z_se = raporty.filter(q).distinct() for r in raporty_z_se: pi = r.submission.problem_instance @@ -40,6 +44,4 @@ def handle(self, *args, **options): time.sleep(1) print(r.submission.id, end=",") print(r.submission, end=",") - print(pi.contest, ",", pi.problem, ",", pi.short_name) - - + print(pi.contest, ",", pi.problem, ",", pi.short_name) diff --git a/oioioi/contests/management/commands/stats_all_submissions.py b/oioioi/contests/management/commands/stats_all_submissions.py index 08aea0645..733449e9e 100644 --- a/oioioi/contests/management/commands/stats_all_submissions.py +++ b/oioioi/contests/management/commands/stats_all_submissions.py @@ -1,34 +1,39 @@ from __future__ import print_function -import six -import time +from datetime import datetime, timedelta from django.core.management.base import BaseCommand from django.db.models import Q from django.utils.translation import ugettext as _ -from django.db import transaction -from oioioi.contests.models import Contest, Round, Submission, SubmissionReport -from datetime import datetime, timedelta + +from oioioi.contests.models import Submission + class Command(BaseCommand): help = _("Count submissions in the past N days") def add_arguments(self, parser): - parser.add_argument('-n', '--numdays', - action='store', - type=int, - dest='numdays', - help="How many past days of reports to check", - default=10) + parser.add_argument( + '-n', + '--numdays', + action='store', + type=int, + dest='numdays', + help="How many past days of reports to check", + default=10, + ) def handle(self, *args, **options): numdays = options["numdays"] - subs_all = Submission.objects.filter(date__gte=datetime.now() - timedelta(days=numdays)) - #raporty = SubmissionReport.objects.filter(submission__in=subs) + subs_all = Submission.objects.filter( + date__gte=datetime.now() - timedelta(days=numdays) + ) + # raporty = SubmissionReport.objects.filter(submission__in=subs) # problem_instance.controller.judge(submission, is_rejudge=True) for iteration in range(numdays): data = (datetime.now() - timedelta(days=iteration)).date() - q = Q(date__gte=datetime.now() - timedelta(days=iteration)) & Q(date__lte=datetime.now() - timedelta(days=(iteration-1))) + q = Q(date__gte=datetime.now() - timedelta(days=iteration)) & Q( + date__lte=datetime.now() - timedelta(days=(iteration - 1)) + ) subs = subs_all.filter(q).count() print(str(data) + "," + str(subs)) - diff --git a/oioioi/contests/models.py b/oioioi/contests/models.py index 2fa55a25c..f6307c814 100644 --- a/oioioi/contests/models.py +++ b/oioioi/contests/models.py @@ -10,7 +10,6 @@ from django.db.models.signals import post_save, pre_save from django.dispatch import receiver from django.utils import timezone - from django.utils.module_loading import import_string from django.utils.text import get_valid_filename from django.utils.translation import gettext_lazy as _ @@ -95,17 +94,16 @@ class Contest(models.Model): "their weights." ), ) - enable_editor = models.BooleanField( - verbose_name=_("enable editor"), - default=False - ) + enable_editor = models.BooleanField(verbose_name=_("enable editor"), default=False) # Part of szkopul backporting. - # This is a hack for situation where contest controller is empty, + # This is a hack for situation where contest controller is empty, # which is very uncommon in normal usage. def save(self, *args, **kwargs): if not self.controller_name: - self.controller_name = 'oioioi.teachers.controllers.TeacherContestController' + self.controller_name = ( + 'oioioi.teachers.controllers.TeacherContestController' + ) super(Contest, self).save(*args, **kwargs) @property @@ -351,10 +349,12 @@ class Meta(object): @date_registry.register( - 'registration_available_from', name_generator=(lambda obj: _("Make registration available")) + 'registration_available_from', + name_generator=(lambda obj: _("Make registration available")), ) @date_registry.register( - 'registration_available_to', name_generator=(lambda obj: _("Make registration unavailable")) + 'registration_available_to', + name_generator=(lambda obj: _("Make registration unavailable")), ) class RegistrationAvailabilityConfig(models.Model): contest = models.OneToOneField('contests.Contest', on_delete=models.CASCADE) @@ -394,16 +394,29 @@ def is_registration_open(self, timestamp): if self.enabled == 'YES': return True if self.enabled == 'CONFIG': - return self.registration_available_from <= timestamp <= self.registration_available_to + return ( + self.registration_available_from + <= timestamp + <= self.registration_available_to + ) return False def clean(self): if self.enabled == 'CONFIG': - if self.registration_available_from is None or self.registration_available_to is None: - raise ValidationError(_("If registration availability is set to Configuration, then " - "'Available from' and 'Available to' must be set.")) + if ( + self.registration_available_from is None + or self.registration_available_to is None + ): + raise ValidationError( + _( + "If registration availability is set to Configuration, then " + "'Available from' and 'Available to' must be set." + ) + ) if self.available_from > self.registration_available_to: - raise ValidationError(_("'Available from' must be before 'available to'.")) + raise ValidationError( + _("'Available from' must be before 'available to'.") + ) class ProblemInstance(models.Model): @@ -725,7 +738,7 @@ def contest_links_generator(request): for link in links: # pylint: disable=cell-var-from-loop # http://docs.python-guide.org/en/latest/writing/gotchas/#late-binding-closures - url_generator = lambda request, url=link.url: url + url_generator = lambda request, url=link.url: url # noqa: E731 item = MenuItem( name='contest_link_%d' % link.id, text=link.description, diff --git a/oioioi/contests/tests/__init__.py b/oioioi/contests/tests/__init__.py index dc757aff0..7576743de 100644 --- a/oioioi/contests/tests/__init__.py +++ b/oioioi/contests/tests/__init__.py @@ -1,5 +1,3 @@ -from django.core.files.base import ContentFile -from django.db.models import Q from django.urls import reverse from oioioi.base.utils.query_helpers import Q_always_false @@ -80,7 +78,7 @@ def make_empty_contest_formset(): ('contestcompiler_set', 0, 0, 0, 1000), ) data = dict() - for (name, total, initial, min_num, max_num) in formsets: + for name, total, initial, min_num, max_num in formsets: data['{}-TOTAL_FORMS'.format(name)] = total data['{}-INITIAL_FORMS'.format(name)] = initial data['{}-MIN_NUM_FORMS'.format(name)] = min_num diff --git a/oioioi/contests/tests/tests.py b/oioioi/contests/tests/tests.py index 0c7433f40..2be5971b8 100644 --- a/oioioi/contests/tests/tests.py +++ b/oioioi/contests/tests/tests.py @@ -7,7 +7,6 @@ import pytest import pytz - from django.conf import settings from django.contrib.admin.utils import quote from django.contrib.auth.models import AnonymousUser, User @@ -21,6 +20,8 @@ from django.urls import NoReverseMatch, reverse from django.utils import timezone from django.utils.timezone import utc +from rest_framework.test import APITestCase + from oioioi.base.tests import TestCase, TestsUtilsMixin, check_not_accessible, fake_time from oioioi.contests.current_contest import ContestMode from oioioi.contests.date_registration import date_registry @@ -69,7 +70,6 @@ from oioioi.teachers.views import ( contest_dashboard_redirect as teachers_contest_dashboard, ) -from rest_framework.test import APITestCase class TestModels(TestCase): @@ -195,7 +195,6 @@ def check_id_order_in_response(self, response, ids): @pytest.mark.skip(reason="TODO: Repair the ordering platform-wide.") def test_score_order(self): - # 7 is the number of score column. # Order by score ascending, null score should be below OK. response = self.client.get(self.url + "?o=-7") @@ -266,14 +265,17 @@ def setUp(self): ) def test_all_filters(self): - response = self.client.get(self.url, { - 'has_active_system_error': 'yes', - 'kind': 'NORMAL', - 'status__exact': 'INI_OK', - 'revealed': '1', - 'round': 'Round 1', - 'lang': 'Pascal', - }) + response = self.client.get( + self.url, + { + 'has_active_system_error': 'yes', + 'kind': 'NORMAL', + 'status__exact': 'INI_OK', + 'revealed': '1', + 'round': 'Round 1', + 'lang': 'Pascal', + }, + ) self.assertEqual(response.status_code, 200) self.assertContains(response, '0 submissions') @@ -1528,7 +1530,7 @@ def check_visibility(*should_be_visible): self.assertNotContains(response, name) def check_accessibility(should_be_accesible, should_not_be_accesible): - for (id, content) in should_be_accesible: + for id, content in should_be_accesible: response = self.client.get( reverse( 'contest_attachment', @@ -1893,7 +1895,6 @@ def test_probleminstance_admin(self): self.assertTrue(self.client.login(username='test_contest_basicadmin')) self.client.get('/c/c/') for pi in ProblemInstance.objects.all(): - url = reverse( 'oioioiadmin:contests_probleminstance_change', kwargs={'contest_id': 'c'}, @@ -3137,7 +3138,7 @@ def contest_submit(self, contest, pi, *args, **kwargs): 'api_contest_submit', {'contest_name': contest.id, 'problem_short_name': pi.short_name}, *args, - **kwargs + **kwargs, ) def test_simple_submission(self): @@ -3258,7 +3259,6 @@ def test_not_sorting(self): # checks ranking visibility without RankingVisibilityConfig, # with it set to default and with it set to 'YES' def check_ranking_visibility(self, url, rvc): - # test without RankingVisibilityConfig response = self.client.get(url) self.assertContains(response, 'Test User') @@ -3348,7 +3348,9 @@ def set_registration_availability(rvc, enabled, available_from=None, available_t rvc.save() -def check_registration(self, expected_status_code, availability, available_from=None, available_to=None): +def check_registration( + self, expected_status_code, availability, available_from=None, available_to=None +): contest = Contest.objects.get() contest.controller_name = 'oioioi.oi.controllers.OIContestController' contest.save() @@ -3364,10 +3366,7 @@ def check_registration(self, expected_status_code, availability, available_from= class TestOpenRegistration(TestCase): - fixtures = [ - 'test_users', - 'test_contest' - ] + fixtures = ['test_users', 'test_contest'] def test_open_registration(self): check_registration(self, 200, 'YES') @@ -3391,4 +3390,4 @@ def test_configured_registration_closed_after(self): now = timezone.now() available_from = now - timedelta(hours=1) available_to = now - timedelta(minutes=5) - check_registration(self, 403, 'CONFIG', available_from, available_to) \ No newline at end of file + check_registration(self, 403, 'CONFIG', available_from, available_to) diff --git a/oioioi/contests/urls.py b/oioioi/contests/urls.py index 609c4864f..6a6d5e2a3 100644 --- a/oioioi/contests/urls.py +++ b/oioioi/contests/urls.py @@ -59,8 +59,8 @@ def make_patterns(neutrals=None, contests=None, noncontests=None, globs=None): # namespaced with 'contest' or 'noncontest', we have to extract # and add them to our patterns so they are taken into account. def glob_namespaced_patterns(namespace): - pattern_lists = [l for l in globs if getattr(l, 'namespace', None) == namespace] - return [pattern for l in pattern_lists for pattern in l.url_patterns] + pattern_lists = [glob for glob in globs if getattr(glob, 'namespace', None) == namespace] + return [pattern for pattern_list in pattern_lists for pattern in pattern_list.url_patterns] neutrals = neutrals or [] contests = (contests or []) + neutrals + glob_namespaced_patterns('contest') diff --git a/oioioi/contests/utils.py b/oioioi/contests/utils.py index 3a2b0faab..1ce0a56a5 100644 --- a/oioioi/contests/utils.py +++ b/oioioi/contests/utils.py @@ -408,17 +408,13 @@ def best_round_to_display(request, allow_past_rounds=False): (round, contest.controller.get_round_times(request, round)) for round in Round.objects.filter(contest=contest) ) - next_rtimes = [ - (r, rt) for r, rt in rtimes.items() if rt.is_future(timestamp) - ] + next_rtimes = [(r, rt) for r, rt in rtimes.items() if rt.is_future(timestamp)] next_rtimes.sort(key=lambda r_rt: r_rt[1].get_start()) current_rtimes = [ (r, rt) for r, rt in rtimes if rt.is_active(timestamp) and rt.get_end() ] current_rtimes.sort(key=lambda r_rt1: r_rt1[1].get_end()) - past_rtimes = [ - (r, rt) for r, rt in rtimes.items() if rt.is_past(timestamp) - ] + past_rtimes = [(r, rt) for r, rt in rtimes.items() if rt.is_past(timestamp)] past_rtimes.sort(key=lambda r_rt2: r_rt2[1].get_end()) if current_rtimes: diff --git a/oioioi/contests/views.py b/oioioi/contests/views.py index b30997570..60c73a101 100644 --- a/oioioi/contests/views.py +++ b/oioioi/contests/views.py @@ -1,8 +1,6 @@ from operator import itemgetter # pylint: disable=E0611 import six - -import django from django.conf import settings from django.contrib import messages from django.contrib.auth.models import User @@ -16,6 +14,7 @@ from django.utils.translation import gettext_lazy as _ from django.utils.translation import ngettext_lazy from django.views.decorators.http import require_POST + from oioioi.base.main_page import register_main_page_view from oioioi.base.menu import menu_registry from oioioi.base.permissions import enforce_condition, not_anonymous @@ -196,7 +195,6 @@ def problem_statement_view(request, problem_instance): @enforce_condition(contest_exists & can_enter_contest) def problem_statement_zip_index_view(request, problem_instance, statement_id): - response = problem_statement_zip_view( request, problem_instance, statement_id, 'index.html' ) diff --git a/oioioi/cypress_settings.py b/oioioi/cypress_settings.py index 7279051bc..dcbb3e4ba 100644 --- a/oioioi/cypress_settings.py +++ b/oioioi/cypress_settings.py @@ -1,4 +1,4 @@ -# pylint: disable=wildcard-import +# ruff: noqa from settings import * # Enable optional modules. diff --git a/oioioi/dashboard/views.py b/oioioi/dashboard/views.py index 4984ca3ca..d41a9410a 100644 --- a/oioioi/dashboard/views.py +++ b/oioioi/dashboard/views.py @@ -1,5 +1,3 @@ -import itertools - from django.conf import settings from django.shortcuts import redirect from django.template.loader import render_to_string diff --git a/oioioi/default_settings.py b/oioioi/default_settings.py index 6efb48141..727bf69a8 100755 --- a/oioioi/default_settings.py +++ b/oioioi/default_settings.py @@ -12,6 +12,7 @@ from django.utils.translation import gettext_lazy as _ import oioioi +from oioioi.contests.current_contest import ContestMode INSTALLATION_CONFIG_VERSION = 49 @@ -43,8 +44,8 @@ 'NAME': os.getenv('OIOIOI_DB_NAME', 'oioioi'), # Or path to database file if using sqlite3. 'USER': os.getenv('OIOIOI_DB_USER', 'oioioi'), # Not used with sqlite3. 'PASSWORD': os.getenv('OIOIOI_DB_PASSWORD', 'password'), # Not used with sqlite3. - 'HOST': os.getenv('OIOIOI_DB_HOST', 'db'), # Set to empty string for localhost. Not used with sqlite3. - 'PORT': os.getenv('OIOIOI_DB_PORT', ''), # Set to empty string for default. Not used with sqlite3. + 'HOST': os.getenv('OIOIOI_DB_HOST', 'db'), # Set to empty string for localhost. Not used with sqlite3. + 'PORT': os.getenv('OIOIOI_DB_PORT', ''), # Set to empty string for default. Not used with sqlite3. 'ATOMIC_REQUESTS': True, # Don't touch unless you know what you're doing. } } @@ -591,7 +592,6 @@ # # Some features may depend on this setting, e.g. the "portals" app requires # that either the "neutral" or the "contest_if_possible" option is picked. -from oioioi.contests.current_contest import ContestMode CONTEST_MODE = ContestMode.contest_if_possible # A sample logging configuration. The only tangible logging diff --git a/oioioi/deployment/create_config.py b/oioioi/deployment/create_config.py index 027324522..4f8d26e18 100644 --- a/oioioi/deployment/create_config.py +++ b/oioioi/deployment/create_config.py @@ -66,9 +66,7 @@ def generate_all(dir, verbose): settings = {} settings_py = os.path.join(dir, 'settings.py') - exec( - compile(open(settings_py).read(), settings_py, 'exec'), globals(), settings - ) + exec(compile(open(settings_py).read(), settings_py, 'exec'), globals(), settings) media_root = settings['MEDIA_ROOT'] os.mkdir(media_root) diff --git a/oioioi/disqualification/controllers.py b/oioioi/disqualification/controllers.py index 50377aee6..89c88fa85 100644 --- a/oioioi/disqualification/controllers.py +++ b/oioioi/disqualification/controllers.py @@ -5,7 +5,7 @@ from oioioi.contests.controllers import ContestController, submission_template_context from oioioi.contests.models import Submission -from oioioi.contests.utils import is_contest_admin, is_contest_observer +from oioioi.contests.utils import is_contest_admin from oioioi.disqualification.models import Disqualification, DisqualificationsConfig from oioioi.programs.controllers import ProgrammingContestController from oioioi.rankings.controllers import DefaultRankingController diff --git a/oioioi/disqualification/tests.py b/oioioi/disqualification/tests.py index 6c708a0fa..b1866c3e9 100644 --- a/oioioi/disqualification/tests.py +++ b/oioioi/disqualification/tests.py @@ -169,26 +169,31 @@ def _assert_submission(self, submission_id, disqualified): self.assertContains(response, "Submission " + str(submission.id)) def test_dashboard(self): + def response_cb(): + return self.client.get( + reverse("contest_dashboard", kwargs=self.contest_kwargs), follow=True + ) + self.assertTrue(self.client.login(username="test_user")) - response_cb = lambda: self.client.get( - reverse("contest_dashboard", kwargs=self.contest_kwargs), follow=True - ) self._assert_disqualification_box(response_cb) def test_my_submissions(self): + def response_cb(): + return self.client.get( + reverse("my_submissions", kwargs=self.contest_kwargs) + ) self.assertTrue(self.client.login(username="test_user")) - response_cb = lambda: self.client.get( - reverse("my_submissions", kwargs=self.contest_kwargs) - ) self._assert_disqualification_box(response_cb) def test_user_info_page(self): + def response_callback(): + return self.client.get( + reverse('user_info', kwargs={'contest_id': contest.id, 'user_id': user.id}) + ) + self.assertTrue(self.client.login(username='test_admin')) user = User.objects.get(username="test_user") contest = Contest.objects.get() - response_callback = lambda: self.client.get( - reverse('user_info', kwargs={'contest_id': contest.id, 'user_id': user.id}) - ) self._assert_disqualification_box(response_callback) diff --git a/oioioi/disqualification/urls.py b/oioioi/disqualification/urls.py index 2a1f557b8..7f518834a 100644 --- a/oioioi/disqualification/urls.py +++ b/oioioi/disqualification/urls.py @@ -1,5 +1,5 @@ # Force loading views -from oioioi.disqualification.views import disqualification_fragment +from oioioi.disqualification.views import disqualification_fragment # noqa: F401 app_name = 'disqualification' diff --git a/oioioi/evalmgr/admin.py b/oioioi/evalmgr/admin.py index b6a6890e0..68ec43983 100644 --- a/oioioi/evalmgr/admin.py +++ b/oioioi/evalmgr/admin.py @@ -6,6 +6,7 @@ from django.urls import reverse from django.utils.html import format_html from django.utils.translation import gettext_lazy as _ + from oioioi.base import admin from oioioi.base.admin import system_admin_menu_registry from oioioi.base.utils import make_html_link diff --git a/oioioi/evalmgr/tasks.py b/oioioi/evalmgr/tasks.py index acf5cb5e0..f02a59088 100644 --- a/oioioi/evalmgr/tasks.py +++ b/oioioi/evalmgr/tasks.py @@ -4,11 +4,11 @@ from uuid import uuid4 import six -from celery.exceptions import Ignore -from celery.task import task from django.db import transaction from django.utils.module_loading import import_string +from celery.exceptions import Ignore +from celery.task import task from oioioi.base.utils.db import require_transaction from oioioi.base.utils.loaders import load_modules from oioioi.evalmgr import logger diff --git a/oioioi/evalmgr/tests/tests.py b/oioioi/evalmgr/tests/tests.py index c15d47929..3884da519 100644 --- a/oioioi/evalmgr/tests/tests.py +++ b/oioioi/evalmgr/tests/tests.py @@ -134,7 +134,6 @@ def _uuid(): class TestRemoteJobs(TestCase): - base_dir = os.path.dirname(__file__) local_source_file = os.path.join(base_dir, 'files/solution.c') remote_source_file = '/test_worker_manager/' + _uuid() + 'add_solution.c' diff --git a/oioioi/exportszu/tests.py b/oioioi/exportszu/tests.py index 061cba3a7..f4be9b70c 100644 --- a/oioioi/exportszu/tests.py +++ b/oioioi/exportszu/tests.py @@ -2,9 +2,9 @@ import shutil import tarfile import tempfile +from io import BytesIO from django.core.management import call_command -from io import BytesIO from oioioi.base.tests import TestCase from oioioi.contests.models import Contest, Round diff --git a/oioioi/exportszu/utils.py b/oioioi/exportszu/utils.py index 79997326c..ff726a2a9 100644 --- a/oioioi/exportszu/utils.py +++ b/oioioi/exportszu/utils.py @@ -31,6 +31,10 @@ class SubmissionData(object): source_file = None +class InvalidValue(Exception): + pass + + class SubmissionsWithUserDataCollector(object): """ Collects submissions with some associated data in specific contest with @@ -63,7 +67,6 @@ def get_contest_id(self): return self.contest.id def collect_list(self): - ccontroller = self.contest.controller q_expressions = Q(user__isnull=False) if self.round: diff --git a/oioioi/filetracker/client.py b/oioioi/filetracker/client.py index cbf56a25c..21eac4ca1 100644 --- a/oioioi/filetracker/client.py +++ b/oioioi/filetracker/client.py @@ -3,8 +3,8 @@ from django.dispatch import receiver from django.test.signals import setting_changed from django.utils.module_loading import import_string -from filetracker.client import Client as FiletrackerClient +from filetracker.client import Client as FiletrackerClient from oioioi.base.utils import memoized, reset_memoized diff --git a/oioioi/filetracker/management/commands/collectgarbage.py b/oioioi/filetracker/management/commands/collectgarbage.py index a25138cf7..052e0c162 100644 --- a/oioioi/filetracker/management/commands/collectgarbage.py +++ b/oioioi/filetracker/management/commands/collectgarbage.py @@ -7,8 +7,8 @@ from django.db.models.loading import cache from django.utils.translation import gettext as _ from django.utils.translation import ngettext -from filetracker.utils import split_name +from filetracker.utils import split_name from oioioi.filetracker.client import get_client @@ -35,9 +35,7 @@ def add_arguments(self, parser): action='store_true', dest='pretend', default=False, - help=_( - "If set, the orphaned files will only be displayed, not deleted." - ), + help=_("If set, the orphaned files will only be displayed, not deleted."), ) def _get_needed_files(self): diff --git a/oioioi/filetracker/storage.py b/oioioi/filetracker/storage.py index 14d3785ea..50e9921ed 100644 --- a/oioioi/filetracker/storage.py +++ b/oioioi/filetracker/storage.py @@ -9,6 +9,7 @@ from django.core.files.storage import Storage from django.urls import reverse from django.utils import timezone + from oioioi.filetracker.client import get_client from oioioi.filetracker.filename import FiletrackerFilename from oioioi.filetracker.utils import FileInFiletracker @@ -123,7 +124,8 @@ def size(self, name): def modified_time(self, name): warnings.warn( - """The old, non-timezone-aware methods accessed_time(), created_time(), and modified_time() are deprecated in favor of the new get_*_time() methods. + """The old, non-timezone-aware methods accessed_time(), created_time(), and modified_time() + are deprecated in favor of the new get_*_time() methods. https://docs.djangoproject.com/en/1.10/releases/1.10/#non-timezone-aware-storage-api""", category=DeprecationWarning, stacklevel=2, @@ -154,9 +156,7 @@ def url(self, name): return reverse('raw_file', kwargs={'filename': name}) def path(self, name): - raise NotImplementedError( - "File is in Filetracker, cannot get its local path" - ) + raise NotImplementedError("File is in Filetracker, cannot get its local path") def listdir(self, path): raise NotImplementedError("Filetracker doesn't provide path listing") diff --git a/oioioi/filetracker/tests.py b/oioioi/filetracker/tests.py index 066ae544f..e09a6a1a1 100644 --- a/oioioi/filetracker/tests.py +++ b/oioioi/filetracker/tests.py @@ -9,6 +9,7 @@ from django.db.models.fields.files import FieldFile, FileField from django.urls import reverse from django.utils import timezone + from filetracker.client import Client as FiletrackerClient from filetracker.client.dummy import DummyClient from oioioi.base.tests import TestCase diff --git a/oioioi/filetracker/utils.py b/oioioi/filetracker/utils.py index 68930bdc5..1ab187a73 100644 --- a/oioioi/filetracker/utils.py +++ b/oioioi/filetracker/utils.py @@ -1,8 +1,8 @@ import mimetypes import urllib +import urllib.parse from wsgiref.util import FileWrapper -import urllib.parse from django.core.files import File from django.core.files.storage import default_storage from django.http import StreamingHttpResponse diff --git a/oioioi/forum/admin.py b/oioioi/forum/admin.py index 806a71020..cc2dad601 100644 --- a/oioioi/forum/admin.py +++ b/oioioi/forum/admin.py @@ -12,10 +12,12 @@ from oioioi.contests.utils import is_contest_admin from oioioi.forum.models import Ban, Category, Forum, Post, Thread + def string_concat(*strings): """https://docs.djangoproject.com/en/3.2/releases/1.11/#deprecated-features-1-11""" return format_lazy('{}' * len(strings), *strings) + def make_list_elem(elem, text=None): if not text: text = elem.name diff --git a/oioioi/forum/models.py b/oioioi/forum/models.py index 0d517d060..95403aa44 100644 --- a/oioioi/forum/models.py +++ b/oioioi/forum/models.py @@ -6,7 +6,6 @@ from django.dispatch import receiver from django.urls import reverse from django.utils import timezone - from django.utils.translation import gettext_lazy as _ from oioioi.base.fields import EnumField, EnumRegistry @@ -18,7 +17,6 @@ @date_registry.register( 'unlock_date', name_generator=(lambda obj: _("Unlock the forum")) ) - class Forum(models.Model): """Forum is connected with contest""" @@ -57,9 +55,8 @@ def is_locked(self, now=None): return bool(self.is_autolocked(now) and not self.is_autounlocked(now)) - class Category(models.Model): - """Category model """ + """Category model""" forum = models.ForeignKey(Forum, verbose_name=_("forum"), on_delete=models.CASCADE) name = models.CharField(max_length=255, verbose_name=_("category")) @@ -114,7 +111,6 @@ def save(self, **kwargs): super(Category, self).save(**kwargs) - class Thread(models.Model): """Thread model - topic in a category""" @@ -157,9 +153,8 @@ def get_admin_url(self): return reverse('oioioiadmin:forum_thread_change', args=(self.id,)) - class Post(models.Model): - """Post - the basic part of the forum """ + """Post - the basic part of the forum""" thread = models.ForeignKey( Thread, verbose_name=_("thread"), on_delete=models.CASCADE @@ -274,7 +269,6 @@ class PostReaction(models.Model): type_of_reaction = EnumField(post_reaction_types) - class Ban(models.Model): """Ban model - represents a ban on a forum. Banned person should not be allowed any 'write' interaction with forum. This includes reporting diff --git a/oioioi/forum/tests.py b/oioioi/forum/tests.py index a7a8e5895..c39cca43c 100644 --- a/oioioi/forum/tests.py +++ b/oioioi/forum/tests.py @@ -10,7 +10,7 @@ from oioioi.base.tests import TestCase, fake_time from oioioi.contests.models import Contest from oioioi.forum.forms import PostForm -from oioioi.forum.models import Ban, Category, Post, PostReaction, Thread +from oioioi.forum.models import Ban, Category, Post, Thread from oioioi.participants.models import Participant diff --git a/oioioi/forum/urls.py b/oioioi/forum/urls.py index d09b2c395..363fa9c73 100644 --- a/oioioi/forum/urls.py +++ b/oioioi/forum/urls.py @@ -8,7 +8,9 @@ re_path(r'^$', views.forum_view, name='forum'), re_path(r'^lock/$', views.lock_forum_view, name='forum_lock'), re_path(r'^unlock/$', views.unlock_forum_view, name='forum_unlock'), - re_path(r'^latest_posts/$', views.latest_posts_forum_view, name='forum_latest_posts'), + re_path( + r'^latest_posts/$', views.latest_posts_forum_view, name='forum_latest_posts' + ), re_path(r'^(?P\d+)/$', views.category_view, name='forum_category'), re_path( r'^(?P\d+)/delete/$', @@ -86,7 +88,9 @@ views.post_toggle_reaction, name='forum_post_toggle_reaction', ), - re_path(r'^user/(?P\d+)/ban/$', views.ban_user_view, name='forum_user_ban'), + re_path( + r'^user/(?P\d+)/ban/$', views.ban_user_view, name='forum_user_ban' + ), ] contest_patterns = [ diff --git a/oioioi/globalmessage/admin.py b/oioioi/globalmessage/admin.py index 4234ca94a..8d6eaf38a 100644 --- a/oioioi/globalmessage/admin.py +++ b/oioioi/globalmessage/admin.py @@ -28,7 +28,9 @@ def get_urls(self): urls = super(GlobalMessageAdmin, self).get_urls() custom_urls = [ - re_path(r'^$', self.admin_site.admin_view(self.change_view), {'object_id': pk}), + re_path( + r'^$', self.admin_site.admin_view(self.change_view), {'object_id': pk} + ), ] return custom_urls + urls diff --git a/oioioi/globalmessage/models.py b/oioioi/globalmessage/models.py index 8a3523f46..ac1dc3841 100644 --- a/oioioi/globalmessage/models.py +++ b/oioioi/globalmessage/models.py @@ -1,9 +1,7 @@ from django.db import models - from django.utils.translation import gettext_lazy as _ - class GlobalMessage(models.Model): message = models.TextField(verbose_name=_("message")) enabled = models.BooleanField(default=False, verbose_name=_("enabled")) diff --git a/oioioi/ipauthsync/models.py b/oioioi/ipauthsync/models.py index 22c194cc1..4d98ffb22 100644 --- a/oioioi/ipauthsync/models.py +++ b/oioioi/ipauthsync/models.py @@ -1,7 +1,6 @@ from django.core.exceptions import ValidationError from django.db import models from django.utils import timezone - from django.utils.translation import gettext_lazy as _ from oioioi.base.utils.deps import check_django_app_dependencies @@ -26,7 +25,6 @@ def get_active(self, timestamp): @date_registry.register( 'end_date', name_generator=(lambda obj: _("Disable IP authentication sync")) ) - class IpAuthSyncConfig(models.Model): contest = models.OneToOneField(Contest, on_delete=models.CASCADE) enabled = models.BooleanField(default=True, verbose_name=_("enabled")) diff --git a/oioioi/ipdnsauth/management/commands/ipauth-dnsserver.py b/oioioi/ipdnsauth/management/commands/ipauth-dnsserver.py index aa1b6e2ca..35dae502c 100644 --- a/oioioi/ipdnsauth/management/commands/ipauth-dnsserver.py +++ b/oioioi/ipdnsauth/management/commands/ipauth-dnsserver.py @@ -1,9 +1,9 @@ import datetime import logging +import socketserver import threading import time -import socketserver from django.conf import settings from django.contrib.auth.models import User from django.core.management.base import BaseCommand, CommandError diff --git a/oioioi/ipdnsauth/models.py b/oioioi/ipdnsauth/models.py index 0a9ec65c6..014c80a29 100644 --- a/oioioi/ipdnsauth/models.py +++ b/oioioi/ipdnsauth/models.py @@ -1,6 +1,5 @@ from django.contrib.auth.models import User from django.db import models - from django.utils.translation import gettext_lazy as _ from oioioi.base.utils.deps import check_django_app_dependencies @@ -8,7 +7,6 @@ check_django_app_dependencies(__name__, ['oioioi.contestexcl']) - class IpToUser(models.Model): """Represents mapping for automatic authorization based on IP address.""" @@ -25,7 +23,6 @@ def __str__(self): return str(self.ip_addr) - class DnsToUser(models.Model): """Represents mapping for automatic authorization based on DNS hostname.""" diff --git a/oioioi/livedata/views.py b/oioioi/livedata/views.py index 1fc67ff2c..22bec0c42 100644 --- a/oioioi/livedata/views.py +++ b/oioioi/livedata/views.py @@ -9,6 +9,7 @@ from django.utils import dateformat from django.utils.timezone import utc from django.utils.translation import get_language + from oioioi.base.permissions import enforce_condition from oioioi.base.utils import allow_cross_origin, jsonify from oioioi.contests.models import SubmissionReport diff --git a/oioioi/liveranking/views.py b/oioioi/liveranking/views.py index 75828b678..454fb9815 100644 --- a/oioioi/liveranking/views.py +++ b/oioioi/liveranking/views.py @@ -3,7 +3,7 @@ from django.template.response import TemplateResponse from oioioi.base.permissions import enforce_condition -from oioioi.contests.models import Contest, Round +from oioioi.contests.models import Round from oioioi.contests.utils import contest_exists from oioioi.livedata.utils import can_see_livedata diff --git a/oioioi/mailsubmit/admin.py b/oioioi/mailsubmit/admin.py index 59fce43ff..5ac1adf14 100644 --- a/oioioi/mailsubmit/admin.py +++ b/oioioi/mailsubmit/admin.py @@ -1,5 +1,6 @@ from django.urls import reverse from django.utils.translation import gettext_lazy as _ + from oioioi.base import admin from oioioi.base.utils import make_html_link from oioioi.contests.admin import ( diff --git a/oioioi/mailsubmit/forms.py b/oioioi/mailsubmit/forms.py index fea5a9210..ecb441cb4 100644 --- a/oioioi/mailsubmit/forms.py +++ b/oioioi/mailsubmit/forms.py @@ -3,7 +3,6 @@ from django.utils.translation import gettext_lazy as _ from oioioi.contests.forms import SubmissionForm -from oioioi.contests.models import ProblemInstance from oioioi.contests.utils import visible_problem_instances from oioioi.default_settings import MAILSUBMIT_CONFIRMATION_HASH_LENGTH from oioioi.mailsubmit.models import MailSubmission @@ -64,8 +63,7 @@ def clean(self): mailsubmission = MailSubmission.objects.get(id=mailsubmission_id) except MailSubmission.DoesNotExist: raise ValidationError( - _("Postal submission number %s does not exist") - % (mailsubmission_id,) + _("Postal submission number %s does not exist") % (mailsubmission_id,) ) if mailsubmission.problem_instance.contest != self.request.contest: diff --git a/oioioi/mailsubmit/utils.py b/oioioi/mailsubmit/utils.py index 29b77b7a4..60cfb51c3 100644 --- a/oioioi/mailsubmit/utils.py +++ b/oioioi/mailsubmit/utils.py @@ -13,7 +13,6 @@ @make_request_condition def is_mailsubmit_used(request): try: - _msc = request.contest.mail_submission_config return True except MailSubmissionConfig.DoesNotExist: @@ -87,7 +86,7 @@ def mail_submission_hashes(mailsubmission): submission_hash = hmac.new( settings.SECRET_KEY.encode('utf-8'), msg, - 'sha256' # Name of the hashing algorithm is required from Python3.8. + 'sha256', # Name of the hashing algorithm is required from Python3.8. ).hexdigest()[:MAILSUBMIT_CONFIRMATION_HASH_LENGTH] return source_hash, submission_hash diff --git a/oioioi/maintenancemode/management/commands/maintenance_mode.py b/oioioi/maintenancemode/management/commands/maintenance_mode.py index d9cd749dd..1697b8558 100644 --- a/oioioi/maintenancemode/management/commands/maintenance_mode.py +++ b/oioioi/maintenancemode/management/commands/maintenance_mode.py @@ -1,6 +1,6 @@ from __future__ import absolute_import -from django.core.management.base import BaseCommand, CommandError +from django.core.management.base import BaseCommand from django.utils.translation import gettext_lazy as _ from oioioi.maintenancemode.models import set_maintenance_mode diff --git a/oioioi/mp/models.py b/oioioi/mp/models.py index 3e14c89d4..87bb551bc 100644 --- a/oioioi/mp/models.py +++ b/oioioi/mp/models.py @@ -3,9 +3,8 @@ from django.utils.translation import gettext_lazy as _ from oioioi.base.utils.deps import check_django_app_dependencies - -from oioioi.participants.models import RegistrationModel from oioioi.contests.models import Contest +from oioioi.participants.models import RegistrationModel check_django_app_dependencies(__name__, ['oioioi.participants']) check_django_app_dependencies(__name__, ['oioioi.contests']) @@ -20,12 +19,13 @@ def erase_data(self): class SubmissionScoreMultiplier(models.Model): - """ If SubmissionScoreMultiplier exists, users can submit problems + """If SubmissionScoreMultiplier exists, users can submit problems even after round ends, until end_date - + Result score for submission after round's end is multiplied by given multiplier value """ + contest = models.OneToOneField( Contest, verbose_name=_("contest"), on_delete=models.CASCADE ) diff --git a/oioioi/mp/tests.py b/oioioi/mp/tests.py index 3514a507b..38f40b610 100644 --- a/oioioi/mp/tests.py +++ b/oioioi/mp/tests.py @@ -1,5 +1,5 @@ -from datetime import datetime import re +from datetime import datetime from django.urls import reverse from django.utils.timezone import utc @@ -24,7 +24,7 @@ class TestMPRanking(TestCase): def _ranking_url(self, key='c'): contest = Contest.objects.get(name='contest1') return reverse('ranking', kwargs={'contest_id': contest.id, 'key': key}) - + def _check_order(self, response, expected): prev_pos = 0 for round_name in expected: @@ -49,12 +49,15 @@ def test_columns_order(self): self.assertTrue(self.client.login(username='test_user1')) with fake_time(datetime(2023, 1, 6, 0, 0, tzinfo=utc)): response = self.client.get(self._ranking_url()) - self._check_order(response, [ - b'User', - b']*>Sum', - b']*>\s*(]*>)*\s*squ1\s*()*\s*', - b']*>\s*(]*>)*\s*squ\s*()*\s*' - ]) + self._check_order( + response, + [ + b'User', + b']*>Sum', + b']*>\s*(]*>)*\s*squ1\s*()*\s*', + b']*>\s*(]*>)*\s*squ\s*()*\s*', + ], + ) def test_no_zero_scores_in_ranking(self): self.assertTrue(self.client.login(username='test_user1')) diff --git a/oioioi/newsfeed/tests.py b/oioioi/newsfeed/tests.py index dcf5f3d55..da4a2221a 100644 --- a/oioioi/newsfeed/tests.py +++ b/oioioi/newsfeed/tests.py @@ -1,4 +1,4 @@ -from django.urls import reverse, resolve +from django.urls import resolve, reverse from oioioi.base.tests import TestCase @@ -85,10 +85,7 @@ class TestNewsfeedOptions(TestCase): def _assert_redirect_to_newsfeed(self, response): self.assertEqual(response.status_code, 200) - self.assertEqual( - resolve(response.redirect_chain[-1][0]).view_name, - 'newsfeed' - ) + self.assertEqual(resolve(response.redirect_chain[-1][0]).view_name, 'newsfeed') def test_news_add(self): url_newsfeed = reverse('newsfeed') diff --git a/oioioi/newsfeed/urls.py b/oioioi/newsfeed/urls.py index 10fc84d8d..4e7fbbe2f 100644 --- a/oioioi/newsfeed/urls.py +++ b/oioioi/newsfeed/urls.py @@ -6,7 +6,9 @@ urlpatterns = [ re_path(r'^news/add/$', views.add_news_view, name='add_news'), - re_path(r'^news/delete/(?P\d+)/$', views.delete_news_view, name='delete_news'), + re_path( + r'^news/delete/(?P\d+)/$', views.delete_news_view, name='delete_news' + ), re_path(r'^news/edit/(?P\d+)/$', views.edit_news_view, name='edit_news'), re_path(r'^news/newsfeed/$', views.newsfeed_view, name='newsfeed'), ] diff --git a/oioioi/oi/admin.py b/oioioi/oi/admin.py index 72137e4a7..62213a18b 100644 --- a/oioioi/oi/admin.py +++ b/oioioi/oi/admin.py @@ -1,13 +1,11 @@ import urllib.parse + from django.contrib import messages from django.urls import reverse from django.utils.translation import gettext_lazy as _ from oioioi.base import admin -from oioioi.base.permissions import make_request_condition from oioioi.base.utils import make_html_link -from oioioi.contests.menu import contest_admin_menu_registry -from oioioi.contests.utils import is_contest_admin from oioioi.oi.forms import OIRegistrationForm from oioioi.oi.models import OIRegistration, School from oioioi.participants.admin import ParticipantAdmin diff --git a/oioioi/oi/controllers.py b/oioioi/oi/controllers.py index 19446a3f8..a2bb67b7f 100644 --- a/oioioi/oi/controllers.py +++ b/oioioi/oi/controllers.py @@ -1,7 +1,6 @@ import logging from django.conf import settings -from django.db.models import Q from django.shortcuts import redirect from django.template.loader import render_to_string from django.template.response import TemplateResponse diff --git a/oioioi/oi/forms.py b/oioioi/oi/forms.py index 03f78dc61..3a2bd627b 100644 --- a/oioioi/oi/forms.py +++ b/oioioi/oi/forms.py @@ -1,7 +1,6 @@ import datetime from django import forms -from django.forms import ValidationError from django.forms.widgets import SelectDateWidget from django.template.loader import render_to_string from django.utils.safestring import mark_safe diff --git a/oioioi/oi/management/commands/export_schools.py b/oioioi/oi/management/commands/export_schools.py index e9d95bb61..4f4ffaf68 100644 --- a/oioioi/oi/management/commands/export_schools.py +++ b/oioioi/oi/management/commands/export_schools.py @@ -16,8 +16,5 @@ def handle(self, *args, **options): writer = csv.writer(self.stdout) writer.writerow(COLUMNS) for school in School.objects.order_by('postal_code'): - row = [ - str(getattr(school, column)).encode('utf-8') - for column in COLUMNS - ] + row = [str(getattr(school, column)).encode('utf-8') for column in COLUMNS] writer.writerow(row) diff --git a/oioioi/oi/management/commands/export_schools_id.py b/oioioi/oi/management/commands/export_schools_id.py index 48ca801c4..7182aafbb 100644 --- a/oioioi/oi/management/commands/export_schools_id.py +++ b/oioioi/oi/management/commands/export_schools_id.py @@ -1,6 +1,6 @@ import csv - import sys + from django.core.management.base import BaseCommand from django.utils.translation import gettext as _ @@ -9,6 +9,7 @@ COLUMNS = ['id'] + COLUMNS + class Command(BaseCommand): help = _("Exports schools list to a CSV file") @@ -19,6 +20,5 @@ def handle(self, *args, **options): writer.writerow(COLUMNS) schools = School.objects.filter(is_approved=True, is_active=True) for school in schools.order_by('postal_code'): - row = [str(getattr(school, column)).encode('utf-8') - for column in COLUMNS] + row = [str(getattr(school, column)).encode('utf-8') for column in COLUMNS] writer.writerow(row) diff --git a/oioioi/oi/management/commands/import_schools.py b/oioioi/oi/management/commands/import_schools.py index 8513f8c0d..92c6f2708 100644 --- a/oioioi/oi/management/commands/import_schools.py +++ b/oioioi/oi/management/commands/import_schools.py @@ -1,8 +1,8 @@ # ~*~ coding: utf-8 ~*~ import os import string - import urllib.request + import unicodecsv from django.core.exceptions import ValidationError from django.core.management.base import BaseCommand, CommandError @@ -117,6 +117,4 @@ def handle(self, *args, **options): % {'all_count': all_count, 'new_count': created_count} ) else: - raise CommandError( - _("There were some errors. Database not changed\n") - ) + raise CommandError(_("There were some errors. Database not changed\n")) diff --git a/oioioi/oi/management/commands/oi_export_emails.py b/oioioi/oi/management/commands/oi_export_emails.py index 12e782537..59b7ad393 100644 --- a/oioioi/oi/management/commands/oi_export_emails.py +++ b/oioioi/oi/management/commands/oi_export_emails.py @@ -13,20 +13,19 @@ class Command(BaseCommand): help = _("Export personal data.") def add_arguments(self, parser): - parser.add_argument('contest_id', - type=str, - help="Contest to export from") - parser.add_argument('out_file', - type=str, - help="File path to export to") + parser.add_argument('contest_id', type=str, help="Contest to export from") + parser.add_argument('out_file', type=str, help="File path to export to") def gen_csv_header(self): def render_sublist(sublist, prefix): result = [] for field in sublist: if isinstance(field, tuple): - result.extend(render_sublist(field[2], - prefix + field[1] + '_' if field[1] else prefix)) + result.extend( + render_sublist( + field[2], prefix + field[1] + '_' if field[1] else prefix + ) + ) else: result.append(prefix + field) return result @@ -37,7 +36,9 @@ def collect_personal_data(self, contest_id): participants_data = [] participants = Participant.objects.filter(contest=contest_id) for p in participants: - participants_data.append((p.user.first_name, p.user.last_name, p.user.email)) + participants_data.append( + (p.user.first_name, p.user.last_name, p.user.email) + ) return participants_data def handle(self, *args, **options): @@ -45,7 +46,7 @@ def handle(self, *args, **options): out_file = options['out_file'] csv_header = self.gen_csv_header() - + personal_data = self.collect_personal_data(contest_id) with open(out_file, 'w') as f: diff --git a/oioioi/oi/management/commands/oi_generate_dnsauth.py b/oioioi/oi/management/commands/oi_generate_dnsauth.py index f36e9b3e7..2b3ad86da 100644 --- a/oioioi/oi/management/commands/oi_generate_dnsauth.py +++ b/oioioi/oi/management/commands/oi_generate_dnsauth.py @@ -1,5 +1,3 @@ -import re - from django.core.management.base import BaseCommand, CommandError from django.db import transaction from django.utils.translation import gettext as _ diff --git a/oioioi/oi/models.py b/oioioi/oi/models.py index b390e0d33..a9ce7f3d3 100644 --- a/oioioi/oi/models.py +++ b/oioioi/oi/models.py @@ -1,17 +1,15 @@ # coding: utf-8 import difflib import urllib - import urllib.parse + from django.core.validators import RegexValidator from django.db import models from django.urls import reverse - from django.utils.translation import gettext_lazy as _ from oioioi.base.utils.deps import check_django_app_dependencies from oioioi.base.utils.validators import validate_whitespaces -from oioioi.contests.models import Contest from oioioi.participants.models import RegistrationModel check_django_app_dependencies(__name__, ['oioioi.participants']) @@ -61,7 +59,6 @@ ] - class School(models.Model): name = models.CharField( max_length=255, validators=[validate_whitespaces], verbose_name=_("name") @@ -113,7 +110,6 @@ def is_similar(self, instance): return ratio > 0.75 - class OIRegistration(RegistrationModel): address = models.CharField(max_length=255, verbose_name=_("address")) postal_code = models.CharField( diff --git a/oioioi/oi/tests.py b/oioioi/oi/tests.py index e93c69b5d..53bc4433a 100644 --- a/oioioi/oi/tests.py +++ b/oioioi/oi/tests.py @@ -607,7 +607,7 @@ def test_user_info_page(self): ('test_personal_data_user', True), ] - for (username, can_see) in can_see_list: + for username, can_see in can_see_list: self.assertTrue(self.client.login(username=username)) response = self.client.get(url) self.client.logout() diff --git a/oioioi/oi/urls.py b/oioioi/oi/urls.py index 37c6af7b1..2c35fc8f2 100644 --- a/oioioi/oi/urls.py +++ b/oioioi/oi/urls.py @@ -7,7 +7,9 @@ urlpatterns = [ re_path(r'^oi/cities/$', views.cities_view), re_path(r'^oi/schools/$', views.schools_view), - re_path(r'^oi/schools/similar/$', views.schools_similar_view, name='schools_similar'), + re_path( + r'^oi/schools/similar/$', views.schools_similar_view, name='schools_similar' + ), re_path(r'^oi/schools/add/$', views.add_school_view, name='add_school'), re_path( r'^oi/schools/choose/(?P[0-9]+)/$', diff --git a/oioioi/oireports/tests.py b/oioioi/oireports/tests.py index ffbf209df..eaee2fd81 100644 --- a/oioioi/oireports/tests.py +++ b/oioioi/oireports/tests.py @@ -1,10 +1,10 @@ from datetime import datetime # pylint: disable=E0611 - from io import BytesIO from django.contrib.auth.models import User from django.urls import reverse from django.utils.timezone import utc + from oioioi.base.tests import TestCase, fake_time from oioioi.base.utils.pdf import extract_text_from_pdf from oioioi.contests.models import Contest diff --git a/oioioi/oireports/urls.py b/oioioi/oireports/urls.py index a9c3effbb..f99116d6c 100644 --- a/oioioi/oireports/urls.py +++ b/oioioi/oireports/urls.py @@ -6,5 +6,7 @@ contest_patterns = [ re_path(r'^oireports/$', views.oireports_view, name='oireports'), - re_path(r'^get_report_users/$', views.get_report_users_view, name='get_report_users'), + re_path( + r'^get_report_users/$', views.get_report_users_view, name='get_report_users' + ), ] diff --git a/oioioi/pa/admin.py b/oioioi/pa/admin.py index 6c6aff29d..90b3884d0 100644 --- a/oioioi/pa/admin.py +++ b/oioioi/pa/admin.py @@ -1,5 +1,3 @@ -from django.utils.translation import gettext_lazy as _ - from oioioi.base import admin from oioioi.contests.admin import ProblemInstanceAdmin from oioioi.contests.utils import is_contest_admin diff --git a/oioioi/pa/controllers.py b/oioioi/pa/controllers.py index ad2417b1e..577db5518 100644 --- a/oioioi/pa/controllers.py +++ b/oioioi/pa/controllers.py @@ -2,7 +2,6 @@ import logging from django import forms -from django.db.models import Q from django.shortcuts import redirect from django.template.response import TemplateResponse from django.utils.translation import gettext_lazy as _ @@ -266,8 +265,10 @@ class PADivCRankingController(PARankingController): description = _("PA style ranking (with division C)") def available_rankings(self, request): - rankings = [(A_PLUS_B_RANKING_KEY, _("Division A + B + C")), - (B_RANKING_KEY, _("Division B + C"))] + rankings = [ + (A_PLUS_B_RANKING_KEY, _("Division A + B + C")), + (B_RANKING_KEY, _("Division B + C")), + ] for round in self._rounds_for_ranking(request): if round.is_trial: rankings.append((str(round.id), round.name)) @@ -275,8 +276,7 @@ def available_rankings(self, request): def _filter_pis_for_ranking(self, partial_key, queryset): if partial_key == A_PLUS_B_RANKING_KEY: - return queryset.filter( - paprobleminstancedata__division__in=['A', 'B', 'C']) + return queryset.filter(paprobleminstancedata__division__in=['A', 'B', 'C']) elif partial_key == B_RANKING_KEY: return queryset.filter(paprobleminstancedata__division__in=['B', 'C']) else: @@ -317,6 +317,7 @@ def get_safe_exec_mode(self): PAFinalsContestController.mix_in(OnsiteContestControllerMixin) + class PADivCContestController(PAContestController): description = _("Algorithmic Engagements with Division C") diff --git a/oioioi/pa/models.py b/oioioi/pa/models.py index 5774a3c4b..217576493 100644 --- a/oioioi/pa/models.py +++ b/oioioi/pa/models.py @@ -6,8 +6,8 @@ from oioioi.base.utils.deps import check_django_app_dependencies from oioioi.contests.models import ProblemInstance -# pylint: disable=unused-import -from oioioi.pa.score import PAScore # Registers the PA score type +# Registers the PA score type +from oioioi.pa.score import PAScore # noqa: F401 from oioioi.participants.models import RegistrationModel check_django_app_dependencies(__name__, ['oioioi.participants']) diff --git a/oioioi/pa/tests.py b/oioioi/pa/tests.py index 8e17ff21a..6f438b0bc 100644 --- a/oioioi/pa/tests.py +++ b/oioioi/pa/tests.py @@ -1,7 +1,6 @@ import re -from datetime import datetime # pylint: disable=E0611 - import urllib.parse +from datetime import datetime # pylint: disable=E0611 from django.contrib.admin.utils import quote from django.contrib.auth.models import User @@ -10,6 +9,7 @@ from django.test.utils import override_settings from django.urls import reverse from django.utils.timezone import utc + from oioioi.base.tests import TestCase, fake_time, fake_timezone_now from oioioi.contests.models import ( Contest, diff --git a/oioioi/participants/controllers.py b/oioioi/participants/controllers.py index f31653c83..feefd2b7d 100644 --- a/oioioi/participants/controllers.py +++ b/oioioi/participants/controllers.py @@ -1,5 +1,6 @@ import logging import urllib.parse + from django import forms from django.core.exceptions import ObjectDoesNotExist, PermissionDenied from django.db.models import Q @@ -25,6 +26,7 @@ auditLogger = logging.getLogger(__name__ + ".audit") + class ParticipantsController(RegistrationController): registration_template = 'participants/registration.html' @@ -79,9 +81,7 @@ def no_entry_view(self, request): url = ( reverse('participants_register', kwargs={'contest_id': self.contest.id}) + '?' - + urllib.parse.urlencode( - {'next': request.build_absolute_uri()} - ) + + urllib.parse.urlencode({'next': request.build_absolute_uri()}) ) return HttpResponseRedirect(url) return super(ParticipantsController, self).no_entry_view(request) @@ -202,7 +202,10 @@ def is_registration_open(self, request): rvc = RegistrationAvailabilityConfig.objects.get(contest=request.contest) return rvc.is_registration_open(request.timestamp) except RegistrationAvailabilityConfig.DoesNotExist: - auditLogger.warning("RegistrationAvailabilityConfig does not exist for contest %s", request.contest) + auditLogger.warning( + "RegistrationAvailabilityConfig does not exist for contest %s", + request.contest, + ) return True diff --git a/oioioi/participants/management/commands/import_onsite_participants.py b/oioioi/participants/management/commands/import_onsite_participants.py index 6821a1922..73b076dee 100644 --- a/oioioi/participants/management/commands/import_onsite_participants.py +++ b/oioioi/participants/management/commands/import_onsite_participants.py @@ -2,8 +2,8 @@ import csv import os - import urllib.request + from django.contrib.auth.models import User from django.core.exceptions import ValidationError from django.core.management.base import BaseCommand, CommandError @@ -142,6 +142,4 @@ def handle(self, *args, **options): if ok: self.stdout.write(_("Processed %d entries") % (all_count)) else: - raise CommandError( - _("There were some errors. Database not changed.\n") - ) + raise CommandError(_("There were some errors. Database not changed.\n")) diff --git a/oioioi/participants/management/commands/import_participants.py b/oioioi/participants/management/commands/import_participants.py index 9e69e8ae2..e13dfc1d0 100644 --- a/oioioi/participants/management/commands/import_participants.py +++ b/oioioi/participants/management/commands/import_participants.py @@ -1,6 +1,6 @@ import os - import urllib.request + from django.contrib.auth.models import User from django.core.management.base import BaseCommand, CommandError from django.db import DatabaseError, transaction @@ -84,6 +84,4 @@ def handle(self, *args, **options): if ok: self.stdout.write(_("Processed %d entries") % (all_count)) else: - raise CommandError( - _("There were some errors. Database not changed.\n") - ) + raise CommandError(_("There were some errors. Database not changed.\n")) diff --git a/oioioi/participants/middleware.py b/oioioi/participants/middleware.py index 4caf22569..292db85b7 100644 --- a/oioioi/participants/middleware.py +++ b/oioioi/participants/middleware.py @@ -19,7 +19,6 @@ class ExclusiveContestsWithParticipantsMiddlewareMixin(object): """ def process_view(self, request, view_func, view_args, view_kwargs, selector=None): - if not self._check_requirements(request): return @@ -36,12 +35,15 @@ def _participants_selector(user, contest): return rcontroller.filter_participants(qs).exists() return True + def _extended_selector(user, contest): + return _participants_selector( + user, contest + ) and selector(user, contest) + if selector is None: final_selector = _participants_selector else: - final_selector = lambda user, contest: _participants_selector( - user, contest - ) and selector(user, contest) + final_selector = _extended_selector return super( ExclusiveContestsWithParticipantsMiddlewareMixin, self diff --git a/oioioi/participants/models.py b/oioioi/participants/models.py index 9680e7700..5ef4233ae 100644 --- a/oioioi/participants/models.py +++ b/oioioi/participants/models.py @@ -1,7 +1,6 @@ from django.contrib.auth.models import User from django.core.exceptions import ObjectDoesNotExist from django.db import models - from django.utils.translation import gettext_lazy as _ from oioioi.base.fields import EnumField, EnumRegistry @@ -19,7 +18,6 @@ participant_statuses.register('DELETED', _("Account deleted")) - class Participant(models.Model): contest = models.ForeignKey(Contest, on_delete=models.CASCADE) user = models.ForeignKey(User, on_delete=models.CASCADE) @@ -62,7 +60,6 @@ def erase_data(self): self.save() - class Region(models.Model): short_name = models.CharField(max_length=10, validators=[validate_db_string_id]) name = models.CharField(max_length=255) @@ -112,7 +109,6 @@ def erase_data(self): self.save() - class OnsiteRegistration(RegistrationModel): number = models.IntegerField(verbose_name=_("number")) region = models.ForeignKey( diff --git a/oioioi/participants/urls.py b/oioioi/participants/urls.py index 33d3d7542..6715d297b 100644 --- a/oioioi/participants/urls.py +++ b/oioioi/participants/urls.py @@ -6,7 +6,9 @@ contest_patterns = [ re_path(r'^register/$', views.registration_view, name='participants_register'), - re_path(r'^unregister/$', views.unregistration_view, name='participants_unregister'), + re_path( + r'^unregister/$', views.unregistration_view, name='participants_unregister' + ), re_path(r'^participants_data/$', views.participants_data, name='participants_data'), re_path( r'^participants_data_csv/$', diff --git a/oioioi/plagiarism/forms.py b/oioioi/plagiarism/forms.py index 70c0f0dd8..9b5cfc84a 100644 --- a/oioioi/plagiarism/forms.py +++ b/oioioi/plagiarism/forms.py @@ -28,7 +28,7 @@ class MossSubmitForm(forms.Form): label=_("MOSS user ID"), required=True, min_value=0, - max_value=2 ** 32, + max_value=2**32, ) def __init__(self, problem_instances, *args, **kwargs): diff --git a/oioioi/plagiarism/tests.py b/oioioi/plagiarism/tests.py index 807bcda6f..7fc8bfc3b 100644 --- a/oioioi/plagiarism/tests.py +++ b/oioioi/plagiarism/tests.py @@ -1,6 +1,7 @@ import six from django.core.management import call_command from django.core.management.base import CommandError + try: from mock import Mock, patch except ImportError: diff --git a/oioioi/portals/handlers.py b/oioioi/portals/handlers.py index 6991ae761..084a24a13 100644 --- a/oioioi/portals/handlers.py +++ b/oioioi/portals/handlers.py @@ -1,4 +1,4 @@ -from django.db.models.signals import post_migrate, post_save +from django.db.models.signals import post_migrate from django.dispatch import receiver from oioioi.portals.models import Node diff --git a/oioioi/portals/models.py b/oioioi/portals/models.py index 9105f01c1..3bdc15425 100644 --- a/oioioi/portals/models.py +++ b/oioioi/portals/models.py @@ -2,8 +2,6 @@ from django.contrib.auth.models import User from django.core.exceptions import ImproperlyConfigured, ValidationError from django.db import models -from django.dispatch import Signal - from django.utils.translation import get_language, get_language_from_request from django.utils.translation import gettext_lazy as _ from mptt.models import MPTTModel, TreeForeignKey @@ -21,7 +19,6 @@ ) - class Node(MPTTModel): short_name = models.CharField( max_length=32, diff --git a/oioioi/portals/templatetags/breadcrumbs.py b/oioioi/portals/templatetags/breadcrumbs.py index 39f13de04..385c118ed 100644 --- a/oioioi/portals/templatetags/breadcrumbs.py +++ b/oioioi/portals/templatetags/breadcrumbs.py @@ -1,4 +1,5 @@ from django.template import Library + from oioioi.portals.utils import join_paths register = Library() diff --git a/oioioi/portals/tests.py b/oioioi/portals/tests.py index 853fbf34f..19a567b2d 100644 --- a/oioioi/portals/tests.py +++ b/oioioi/portals/tests.py @@ -1,6 +1,7 @@ from django.contrib.auth.models import AnonymousUser from django.test.utils import override_settings from django.urls import reverse + from oioioi.base.tests import TestCase from oioioi.contests.current_contest import ContestMode from oioioi.portals.actions import portal_url @@ -51,12 +52,18 @@ class TestPortalModels(TestCase): def test_get_siblings(self): node = get_portal().root self.assertQuerysetEqual(node.get_siblings(), [], transform=repr) - self.assertQuerysetEqual(node.get_siblings(include_self=True), [''], transform=repr) + self.assertQuerysetEqual( + node.get_siblings(include_self=True), [''], transform=repr + ) node = node.children.get(short_name='child1') - self.assertQuerysetEqual(node.get_siblings(), [''], transform=repr) self.assertQuerysetEqual( - node.get_siblings(include_self=True), ['', ''], transform=repr + node.get_siblings(), [''], transform=repr + ) + self.assertQuerysetEqual( + node.get_siblings(include_self=True), + ['', ''], + transform=repr, ) def test_get_path(self): @@ -336,7 +343,9 @@ def test_delete_node_view(self): self.assertRedirects(response, portal_url(portal=get_portal())) node = get_portal().root - self.assertQuerysetEqual(node.get_children(), [''], transform=repr) + self.assertQuerysetEqual( + node.get_children(), [''], transform=repr + ) def test_portal_tree_json_view(self): self.assertTrue(self.client.login(username='test_user')) @@ -403,11 +412,17 @@ def assertMoveStatus(username, node, target, position, status_code): assertMoveStatus('test_user', 2, 3, 'inside', 200) node = get_portal().root - self.assertQuerysetEqual(node.get_children(), [''], transform=repr) + self.assertQuerysetEqual( + node.get_children(), [''], transform=repr + ) node = node.children.get() - self.assertQuerysetEqual(node.get_children(), [''], transform=repr) + self.assertQuerysetEqual( + node.get_children(), [''], transform=repr + ) node = node.children.get() - self.assertQuerysetEqual(node.get_children(), [''], transform=repr) + self.assertQuerysetEqual( + node.get_children(), [''], transform=repr + ) def test_delete_portal_view(self): self.assertTrue(self.client.login(username='test_user')) @@ -569,7 +584,9 @@ def test_block_spoiler(self): ) self.assertIn("
", rendered_markdown) - self.assertIn('spoiler text', rendered_markdown) + self.assertIn( + 'spoiler text', rendered_markdown + ) self.assertIn("

spoiler body

", rendered_markdown) self.assertIn("
", rendered_markdown) @@ -586,15 +603,23 @@ def test_block_spoiler_nested(self): rendered_markdown = render_panel( self.request, '>![first]\n>!>![nested]\n>!>!nested text\n>!first text\n' ) - self.assertIn('first', rendered_markdown) - self.assertIn('nested', rendered_markdown) + self.assertIn( + 'first', rendered_markdown + ) + self.assertIn( + 'nested', rendered_markdown + ) def test_block_spoiler_in_sequence(self): rendered_markdown = render_panel( self.request, '>![first]\n>!first text\n\n>![second]\n>!second text\n' ) - self.assertIn('first', rendered_markdown) - self.assertIn('second', rendered_markdown) + self.assertIn( + 'first', rendered_markdown + ) + self.assertIn( + 'second', rendered_markdown + ) def test_table_element(self): rendered_markdown = render_panel(self.request, '|a|b|\n|-|-|\n|1|2|\n') diff --git a/oioioi/portals/utils.py b/oioioi/portals/utils.py index 845a171b9..b3335bc82 100644 --- a/oioioi/portals/utils.py +++ b/oioioi/portals/utils.py @@ -1,8 +1,6 @@ -from django.contrib.auth.models import User -from django.core.exceptions import ObjectDoesNotExist, PermissionDenied +from django.core.exceptions import ObjectDoesNotExist from django.http import Http404 -from oioioi.base.permissions import make_request_condition from oioioi.problems.models import Problem diff --git a/oioioi/portals/views.py b/oioioi/portals/views.py index 893d9ae28..dedd88db9 100644 --- a/oioioi/portals/views.py +++ b/oioioi/portals/views.py @@ -1,7 +1,6 @@ import json from django.conf import settings -from django.contrib.auth.models import User from django.core.exceptions import SuspiciousOperation from django.db import IntegrityError from django.db.models import Q @@ -15,8 +14,7 @@ from django.utils.translation import gettext_lazy as _ from mptt.exceptions import InvalidMove -# pylint: disable=W0611 -import oioioi.portals.handlers +import oioioi.portals.handlers # noqa: F401 from oioioi.base.main_page import register_main_page_view from oioioi.base.menu import account_menu_registry from oioioi.base.permissions import enforce_condition, is_superuser, not_anonymous @@ -41,11 +39,10 @@ PortalShortDescForm, PortalsSearchForm, ) +from oioioi.portals.handlers import update_task_information_cache from oioioi.portals.models import Node, NodeLanguageVersion, Portal from oioioi.portals.utils import resolve_path from oioioi.portals.widgets import render_panel -from oioioi.portals.handlers import update_task_information_cache - from oioioi.problems.problem_site import problem_site_tab diff --git a/oioioi/portals/widgets.py b/oioioi/portals/widgets.py index 111aeda3b..7d53fc7f4 100644 --- a/oioioi/portals/widgets.py +++ b/oioioi/portals/widgets.py @@ -1,7 +1,6 @@ import re - import urllib.parse -from django.conf import settings + from django.http import Http404 from django.template.loader import render_to_string from django.urls import resolve, reverse diff --git a/oioioi/printing/forms.py b/oioioi/printing/forms.py index 269546931..c6b878eb2 100644 --- a/oioioi/printing/forms.py +++ b/oioioi/printing/forms.py @@ -34,9 +34,7 @@ def clean_file(self): try: cleaned_data['file'] = generator( source=orig.expandtabs(4), - header=str( - '%s (%s)' % (self.user.get_full_name(), self.user) - ), + header=str('%s (%s)' % (self.user.get_full_name(), self.user)), ) except PageLimitExceeded: raise ValidationError(_("The page limit exceeded.")) diff --git a/oioioi/printing/tests.py b/oioioi/printing/tests.py index 64b29d17a..3ea9fc2c4 100644 --- a/oioioi/printing/tests.py +++ b/oioioi/printing/tests.py @@ -1,7 +1,8 @@ +from io import BytesIO + from django.core.files.base import ContentFile from django.test.utils import override_settings from django.urls import reverse -from io import BytesIO from oioioi.base.tests import TestCase from oioioi.base.utils.pdf import extract_text_from_pdf diff --git a/oioioi/problems/admin.py b/oioioi/problems/admin.py index 356c66b83..6714f9886 100644 --- a/oioioi/problems/admin.py +++ b/oioioi/problems/admin.py @@ -1,5 +1,4 @@ import logging - import urllib.parse from django.contrib import messages @@ -12,6 +11,7 @@ from django.urls import re_path, reverse from django.utils.html import escape, format_html, mark_safe from django.utils.translation import gettext_lazy as _ + from oioioi.base import admin from oioioi.base.admin import NO_CATEGORY, system_admin_menu_registry from oioioi.base.permissions import is_superuser, make_request_condition @@ -21,7 +21,8 @@ from oioioi.contests.models import ( ProblemInstance, ProblemStatementConfig, - RankingVisibilityConfig, RegistrationAvailabilityConfig, + RankingVisibilityConfig, + RegistrationAvailabilityConfig, ) from oioioi.contests.utils import is_contest_admin, is_contest_basicadmin from oioioi.problems.forms import ( @@ -34,7 +35,8 @@ ProblemNameInlineFormSet, ProblemSiteForm, ProblemStatementConfigForm, - RankingVisibilityConfigForm, RegistrationAvailabilityConfigForm, + RankingVisibilityConfigForm, + RegistrationAvailabilityConfigForm, ) from oioioi.problems.models import ( AlgorithmTag, diff --git a/oioioi/problems/api.py b/oioioi/problems/api.py index b68225d29..2d2b693b9 100644 --- a/oioioi/problems/api.py +++ b/oioioi/problems/api.py @@ -2,6 +2,13 @@ from django.shortcuts import get_object_or_404 from django.utils.decorators import method_decorator from django.utils.translation import gettext as _ +from rest_framework import status +from rest_framework.parsers import MultiPartParser +from rest_framework.permissions import IsAuthenticated +from rest_framework.response import Response +from rest_framework.schemas import AutoSchema +from rest_framework.views import APIView + from oioioi.base.utils.api import make_path_coreapi_schema from oioioi.contests.models import Contest from oioioi.contests.utils import can_admin_contest @@ -13,12 +20,6 @@ PackageUploadSerializer, ) from oioioi.problems.utils import can_admin_problem -from rest_framework import status -from rest_framework.parsers import MultiPartParser -from rest_framework.permissions import IsAuthenticated -from rest_framework.response import Response -from rest_framework.schemas import AutoSchema -from rest_framework.views import APIView def _check_permissions(request, contest=None, existing_problem=None): diff --git a/oioioi/problems/controllers.py b/oioioi/problems/controllers.py index d6c365a45..ad04273e7 100644 --- a/oioioi/problems/controllers.py +++ b/oioioi/problems/controllers.py @@ -11,7 +11,9 @@ from django.template.loader import render_to_string from django.utils import timezone from django.utils.safestring import mark_safe -from django.utils.translation import gettext_lazy as _, gettext_noop +from django.utils.translation import gettext_lazy as _ +from django.utils.translation import gettext_noop + from oioioi.base.utils import ObjectWithMixins, RegisteredSubclassesBase from oioioi.contests.models import ( FailureReport, @@ -707,7 +709,6 @@ def supports_problem_statement(self): """ return True - def get_notification_message_submission_judged(self, submission): """Returns a message to show in a notification when a submission has been judged. It doesn't validate any permissions. diff --git a/oioioi/problems/forms.py b/oioioi/problems/forms.py index 8b1216c78..60e099a68 100644 --- a/oioioi/problems/forms.py +++ b/oioioi/problems/forms.py @@ -4,9 +4,14 @@ from django.conf import settings from django.db import transaction from django.utils.translation import gettext_lazy as _ + from oioioi.base.utils.input_with_generate import TextInputWithGenerate from oioioi.base.utils.inputs import narrow_input_field -from oioioi.contests.models import ProblemStatementConfig, RankingVisibilityConfig, RegistrationAvailabilityConfig +from oioioi.contests.models import ( + ProblemStatementConfig, + RankingVisibilityConfig, + RegistrationAvailabilityConfig, +) from oioioi.problems.models import OriginInfoValue, Problem, ProblemSite diff --git a/oioioi/problems/management/commands/addproblem.py b/oioioi/problems/management/commands/addproblem.py index fdc01a03b..9e325b149 100644 --- a/oioioi/problems/management/commands/addproblem.py +++ b/oioioi/problems/management/commands/addproblem.py @@ -4,6 +4,7 @@ from django.db import transaction from django.utils.module_loading import import_string from django.utils.translation import gettext as _ + from oioioi.problems.package import NoBackend, backend_for_package diff --git a/oioioi/problems/management/commands/recalculate_statistics.py b/oioioi/problems/management/commands/recalculate_statistics.py index a4358a8f4..e2bb35842 100644 --- a/oioioi/problems/management/commands/recalculate_statistics.py +++ b/oioioi/problems/management/commands/recalculate_statistics.py @@ -1,10 +1,10 @@ from __future__ import print_function -from django.conf import settings from django.core.management.base import BaseCommand from django.db import transaction from django.utils.translation import gettext as _ from django.utils.translation import ngettext + from oioioi.contests.models import Submission from oioioi.problems.models import Problem, ProblemStatistics, UserStatistics diff --git a/oioioi/problems/management/commands/showbrokensolutions.py b/oioioi/problems/management/commands/showbrokensolutions.py index 5092a2b3f..4d5751fda 100755 --- a/oioioi/problems/management/commands/showbrokensolutions.py +++ b/oioioi/problems/management/commands/showbrokensolutions.py @@ -1,6 +1,7 @@ from django.core.management.base import BaseCommand from django.db.models import F from django.utils.translation import gettext as _ + from oioioi.problems.models import Problem from oioioi.programs.models import ModelProgramSubmission diff --git a/oioioi/problems/management/commands/updateproblem.py b/oioioi/problems/management/commands/updateproblem.py index 7e8d9dc8b..7fb1107bd 100644 --- a/oioioi/problems/management/commands/updateproblem.py +++ b/oioioi/problems/management/commands/updateproblem.py @@ -4,6 +4,7 @@ from django.db import transaction from django.utils.module_loading import import_string from django.utils.translation import gettext as _ + from oioioi.problems.models import Problem from oioioi.problems.package import NoBackend, backend_for_package diff --git a/oioioi/problems/menu.py b/oioioi/problems/menu.py index a37aef0c3..41263ebb0 100644 --- a/oioioi/problems/menu.py +++ b/oioioi/problems/menu.py @@ -1,4 +1,5 @@ from django.utils.translation import gettext_lazy as _ + from oioioi.base.menu import MenuRegistry navbar_links_registry = MenuRegistry(_("Navigation Bar Menu")) diff --git a/oioioi/problems/models.py b/oioioi/problems/models.py index 9c09a0bee..23673ed20 100644 --- a/oioioi/problems/models.py +++ b/oioioi/problems/models.py @@ -18,12 +18,13 @@ from django.utils.text import get_valid_filename from django.utils.translation import get_language, pgettext_lazy from django.utils.translation import gettext_lazy as _ +from unidecode import unidecode + from oioioi.base.fields import DottedNameField, EnumField, EnumRegistry from oioioi.base.utils import split_extension, strip_num_or_hash from oioioi.contests.models import ProblemInstance from oioioi.filetracker.fields import FileField from oioioi.problems.validators import validate_origintag -from unidecode import unidecode logger = logging.getLogger(__name__) @@ -43,7 +44,6 @@ def make_problem_filename(instance, filename): ) - class Problem(models.Model): """Represents a problem in the problems database. @@ -248,7 +248,6 @@ def __str__(self): return u'%s / %s' % (self.problem.name, self.filename) - class ProblemAttachment(models.Model): """Represents an additional file visible to the contestant, linked to a problem. @@ -299,7 +298,7 @@ def _make_package_filename(instance, filename): def truncate_unicode(string, length, encoding='utf-8'): - """ Truncates string to be `length` bytes long. """ + """Truncates string to be `length` bytes long.""" encoded = string.encode(encoding)[:length] return encoded.decode(encoding, 'ignore') @@ -453,7 +452,6 @@ def manager(): return manager() - class ProblemSite(models.Model): """Represents a global problem site. @@ -547,7 +545,6 @@ def __getattr__(self, key): @_localized('short_name', 'full_name', 'description') - class OriginTag(models.Model): """OriginTags are used along with OriginInfoCategories and OriginInfoValue to give information about the problem's origin. OriginTags themselves @@ -587,7 +584,6 @@ def __str__(self): return str(self.name) - class OriginTagLocalization(models.Model): origin_tag = models.ForeignKey( OriginTag, related_name='localizations', on_delete=models.CASCADE @@ -628,7 +624,6 @@ def __str__(self): @_localized('full_name') - class OriginInfoCategory(models.Model): """This class represents a category of information, which further specifies what its parent_tag is already telling about the origin. It doesn't do @@ -683,7 +678,6 @@ def __str__(self): return str("{}_{}".format(self.parent_tag, self.name)) - class OriginInfoCategoryLocalization(models.Model): origin_info_category = models.ForeignKey( OriginInfoCategory, related_name='localizations', on_delete=models.CASCADE @@ -707,7 +701,6 @@ def __str__(self): @_localized('full_value') - class OriginInfoValue(models.Model): """This class represents additional information, further specifying what its parent_tag is already telling about the origin. Each @@ -777,9 +770,7 @@ def name(self): @property def full_name(self): - return str( - u'{} {}'.format(self.parent_tag.full_name, self.full_value) - ) + return str(u'{} {}'.format(self.parent_tag.full_name, self.full_value)) class Meta(object): unique_together = ('parent_tag', 'value') @@ -790,7 +781,6 @@ def __str__(self): return str(self.name) - class OriginInfoValueLocalization(models.Model): origin_info_value = models.ForeignKey( OriginInfoValue, related_name='localizations', on_delete=models.CASCADE @@ -814,7 +804,6 @@ def __str__(self): @_localized('full_name') - class DifficultyTag(models.Model): name = models.CharField( max_length=20, @@ -838,7 +827,6 @@ def __str__(self): return str(self.name) - class DifficultyTagThrough(models.Model): problem = models.OneToOneField(Problem, on_delete=models.CASCADE) tag = models.ForeignKey(DifficultyTag, on_delete=models.CASCADE) @@ -848,7 +836,6 @@ def __str__(self): return str(self.tag.name) - class DifficultyTagLocalization(models.Model): difficulty_tag = models.ForeignKey( DifficultyTag, related_name='localizations', on_delete=models.CASCADE @@ -871,7 +858,6 @@ def __str__(self): return str("{} - {}".format(self.difficulty_tag, self.language)) - class DifficultyTagProposal(models.Model): problem = models.ForeignKey(Problem, on_delete=models.CASCADE) tag = models.ForeignKey(DifficultyTag, on_delete=models.CASCADE, null=True) @@ -886,7 +872,6 @@ class Meta(object): @_localized('full_name') - class AlgorithmTag(models.Model): name = models.CharField( max_length=20, @@ -910,7 +895,6 @@ def __str__(self): return str(self.name) - class AlgorithmTagThrough(models.Model): problem = models.ForeignKey(Problem, on_delete=models.CASCADE) tag = models.ForeignKey(AlgorithmTag, on_delete=models.CASCADE) @@ -923,7 +907,6 @@ class Meta(object): unique_together = ('problem', 'tag') - class AlgorithmTagLocalization(models.Model): algorithm_tag = models.ForeignKey( AlgorithmTag, related_name='localizations', on_delete=models.CASCADE @@ -946,7 +929,6 @@ def __str__(self): return str("{} - {}".format(self.algorithm_tag, self.language)) - class AlgorithmTagProposal(models.Model): problem = models.ForeignKey(Problem, on_delete=models.CASCADE) tag = models.ForeignKey(AlgorithmTag, on_delete=models.CASCADE) diff --git a/oioioi/problems/package.py b/oioioi/problems/package.py index 5370f5e57..0060c03d0 100644 --- a/oioioi/problems/package.py +++ b/oioioi/problems/package.py @@ -11,6 +11,7 @@ from django.conf import settings from django.core.files import File from django.utils.module_loading import import_string + from oioioi.base.utils import ObjectWithMixins, RegisteredSubclassesBase from oioioi.problems.models import Problem, ProblemPackage diff --git a/oioioi/problems/problem_site.py b/oioioi/problems/problem_site.py index c567e825a..1e78a09ef 100644 --- a/oioioi/problems/problem_site.py +++ b/oioioi/problems/problem_site.py @@ -16,6 +16,7 @@ from django.utils.encoding import smart_str from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy as _ + from oioioi.base.menu import OrderedRegistry from oioioi.base.utils import uploaded_file_name from oioioi.base.utils.archive import Archive @@ -64,10 +65,13 @@ def problem_site_tab(title, key, order=sys.maxsize, condition=None): if the tab should be accessible for this request """ + def default_condition(request, problem): + return True + Tab = namedtuple('Tab', ['view', 'title', 'key', 'condition']) if condition is None: - condition = lambda request, problem: True + condition = default_condition def decorator(func): problem_site_tab_registry.register(Tab(func, title, key, condition), order) @@ -97,8 +101,10 @@ def problem_site_statement(request, problem): if not statement: statement_html = render_to_string( 'problems/no-problem-statement.html', - {'problem': problem, - 'can_admin_problem': can_admin_problem(request, problem)} + { + 'problem': problem, + 'can_admin_problem': can_admin_problem(request, problem), + }, ) elif statement.extension == '.zip': response = problem_site_statement_zip_view( @@ -106,9 +112,11 @@ def problem_site_statement(request, problem): ) statement_html = render_to_string( 'problems/from-zip-statement.html', - {'problem': problem, - 'statement': mark_safe(response.content.decode(errors="replace")), - 'can_admin_problem': can_admin_problem(request, problem)} + { + 'problem': problem, + 'statement': mark_safe(response.content.decode(errors="replace")), + 'can_admin_problem': can_admin_problem(request, problem), + }, ) else: statement_url = reverse( @@ -117,9 +125,11 @@ def problem_site_statement(request, problem): ) statement_html = render_to_string( 'problems/external-statement.html', - {'problem': problem, - 'statement_url': statement_url, - 'can_admin_problem': can_admin_problem(request, problem)}, + { + 'problem': problem, + 'statement_url': statement_url, + 'can_admin_problem': can_admin_problem(request, problem), + }, ) return statement_html diff --git a/oioioi/problems/problem_sources.py b/oioioi/problems/problem_sources.py index 0887755ac..98f54547a 100644 --- a/oioioi/problems/problem_sources.py +++ b/oioioi/problems/problem_sources.py @@ -1,5 +1,4 @@ import logging -import sys from django.conf import settings from django.contrib import messages @@ -12,6 +11,7 @@ from django.utils.http import urlencode from django.utils.module_loading import import_string from django.utils.translation import gettext_lazy as _ + from oioioi.base.utils import uploaded_file_name from oioioi.base.utils.redirect import safe_redirect from oioioi.contests.utils import is_contest_basicadmin diff --git a/oioioi/problems/processors.py b/oioioi/problems/processors.py index c50893431..4a89aaabf 100644 --- a/oioioi/problems/processors.py +++ b/oioioi/problems/processors.py @@ -2,6 +2,7 @@ from django.urls import reverse from django.utils.functional import lazy from django.utils.translation import ngettext + from oioioi.base.utils import make_navbar_badge from oioioi.contests.models import ProblemInstance from oioioi.contests.utils import is_contest_basicadmin @@ -70,9 +71,7 @@ def generator(): text = text % {'count': count} return make_navbar_badge(link, text) - return { - 'extra_navbar_right_not_rejudged_problems': lazy(generator, str)() - } + return {'extra_navbar_right_not_rejudged_problems': lazy(generator, str)()} def can_add_to_problemset_processor(request): diff --git a/oioioi/problems/serializers.py b/oioioi/problems/serializers.py index eabd772d7..c71fc175b 100644 --- a/oioioi/problems/serializers.py +++ b/oioioi/problems/serializers.py @@ -1,6 +1,7 @@ -from oioioi.base.utils.validators import validate_db_string_id, validate_whitespaces from rest_framework import serializers +from oioioi.base.utils.validators import validate_db_string_id, validate_whitespaces + class PackageSerializer(serializers.Serializer): package_file = serializers.FileField( diff --git a/oioioi/problems/templatetags/tag.py b/oioioi/problems/templatetags/tag.py index 4812d67bb..d18a32b21 100644 --- a/oioioi/problems/templatetags/tag.py +++ b/oioioi/problems/templatetags/tag.py @@ -1,6 +1,7 @@ from django.db.models import prefetch_related_objects from django.template import Library from django.utils.html import format_html + from oioioi.base.utils.tags import get_tag_name, get_tag_prefix register = Library() diff --git a/oioioi/problems/tests/__init__.py b/oioioi/problems/tests/__init__.py index 237ba32d3..285fc73fc 100644 --- a/oioioi/problems/tests/__init__.py +++ b/oioioi/problems/tests/__init__.py @@ -1,7 +1,7 @@ -from .utilities import ( - DummyContestController, - DummyPackageBackend, - DummySource, - TestProblemController, - dummy_handler, -) +from . import utilities + +DummyContestController = utilities.DummyContestController +DummyPackageBackend = utilities.DummyPackageBackend +DummySource = utilities.DummySource +TestProblemController = utilities.TestProblemController +dummy_handler = utilities.dummy_handler diff --git a/oioioi/problems/tests/test_problem.py b/oioioi/problems/tests/test_problem.py index 3cab5ef7d..5617f862b 100644 --- a/oioioi/problems/tests/test_problem.py +++ b/oioioi/problems/tests/test_problem.py @@ -3,7 +3,6 @@ import io import six -import urllib.parse from django.contrib.auth.models import AnonymousUser, Permission, User from django.contrib.contenttypes.models import ContentType from django.core.files.base import ContentFile diff --git a/oioioi/problems/tests/test_tags.py b/oioioi/problems/tests/test_tags.py index 5541112a9..a50ccd122 100644 --- a/oioioi/problems/tests/test_tags.py +++ b/oioioi/problems/tests/test_tags.py @@ -5,6 +5,7 @@ from django.contrib.auth.models import User from django.test.utils import override_settings from django.urls import reverse + from oioioi.base.tests import TestCase from oioioi.problems.models import ( AlgorithmTag, diff --git a/oioioi/problems/tests/test_task_archive.py b/oioioi/problems/tests/test_task_archive.py index 35e127e40..2f8d2c6f0 100644 --- a/oioioi/problems/tests/test_task_archive.py +++ b/oioioi/problems/tests/test_task_archive.py @@ -16,6 +16,7 @@ from oioioi.problems.models import OriginInfoCategory, OriginInfoValue, Problem from oioioi.problems.utils import get_prefetched_value + @override_settings(LANGUAGE_CODE='pl') class TestTaskArchive(TestCase): fixtures = [ @@ -267,4 +268,3 @@ def test_can_access_with_result(score, max_score): test_can_access_with_result(IntegerScore(50), IntegerScore(100)) test_can_access_with_result(None, IntegerScore(100)) test_can_access_with_result(IntegerScore(50), None) - diff --git a/oioioi/problems/tests/test_upload.py b/oioioi/problems/tests/test_upload.py index 59c85fcc4..c848195d0 100644 --- a/oioioi/problems/tests/test_upload.py +++ b/oioioi/problems/tests/test_upload.py @@ -1,5 +1,6 @@ -import pytest import urllib.parse + +import pytest from django.core.files.base import ContentFile from django.db import transaction from django.test import TransactionTestCase diff --git a/oioioi/problems/unpackmgr.py b/oioioi/problems/unpackmgr.py index 9a825f1b3..5593735e5 100644 --- a/oioioi/problems/unpackmgr.py +++ b/oioioi/problems/unpackmgr.py @@ -1,7 +1,8 @@ import logging -from celery.task import task from django.utils.module_loading import import_string + +from celery.task import task from oioioi.problems.models import Problem, ProblemPackage logger = logging.getLogger(__name__) diff --git a/oioioi/problems/urls.py b/oioioi/problems/urls.py index b60407098..62f3deb9a 100644 --- a/oioioi/problems/urls.py +++ b/oioioi/problems/urls.py @@ -1,6 +1,8 @@ from django.conf import settings from django.urls import include, re_path + from oioioi.problems import api, views +from oioioi.problems.problem_site import problem_site_statement_zip_view app_name = 'problems' @@ -8,7 +10,7 @@ re_path(r'^site/$', views.problem_site_view, name='problem_site'), re_path( r'^site/(?P.+)$', - views.problem_site_statement_zip_view, + problem_site_statement_zip_view, name='problem_site_statement_zip', ), re_path( @@ -137,8 +139,7 @@ views.get_algorithm_tag_label_view, name='get_algorithm_tag_label', ), - re_path(r'^save_proposals/', views.save_proposals_view, - name='save_proposals'), + re_path(r'^save_proposals/', views.save_proposals_view, name='save_proposals'), ] noncontest_patterns = [ diff --git a/oioioi/problems/utils.py b/oioioi/problems/utils.py index 6459c14af..cdbd1c3c0 100644 --- a/oioioi/problems/utils.py +++ b/oioioi/problems/utils.py @@ -3,11 +3,11 @@ import zipfile from collections import defaultdict -import django from django.conf import settings from django.core.exceptions import SuspiciousOperation from django.http import Http404, HttpResponse from django.utils import translation + from oioioi.base.utils import request_cached from oioioi.contests.models import ProblemInstance, Submission from oioioi.contests.processors import recent_contests @@ -26,9 +26,9 @@ ) from oioioi.programs.models import ( GroupReport, + LanguageOverrideForTest, ModelProgramSubmission, TestReport, - LanguageOverrideForTest, ) @@ -125,7 +125,7 @@ def query_statement(problem_id): return None lang_prefs = ( - [translation.get_language()] + ['', None] + [l[0] for l in settings.LANGUAGES] + [translation.get_language()] + ['', None] + [lang[0] for lang in settings.LANGUAGES] ) ext_prefs = ['.zip', '.pdf', '.ps', '.html', '.txt'] @@ -296,7 +296,7 @@ def generate_model_solutions_context(request, problem_instance): percentage_statuses[s.id] = '25' elif time_ratio <= 0.50: percentage_statuses[s.id] = '50' - if submissions_percentage_statuses[s.id] is not '100': + if submissions_percentage_statuses[s.id] != '100': submissions_percentage_statuses[s.id] = '50' else: percentage_statuses[s.id] = '100' diff --git a/oioioi/problems/views.py b/oioioi/problems/views.py index 9e86d844c..3646c610f 100644 --- a/oioioi/problems/views.py +++ b/oioioi/problems/views.py @@ -1,17 +1,16 @@ # coding: utf-8 +import json import os import shutil import tempfile +import urllib.parse from functools import wraps from itertools import groupby from operator import attrgetter -import json - -import urllib.parse -from django.contrib.auth.decorators import login_required from django.conf import settings from django.contrib import messages +from django.contrib.auth.decorators import login_required from django.contrib.auth.models import User from django.core.exceptions import PermissionDenied from django.core.files.base import File @@ -37,6 +36,8 @@ from django.utils.translation import get_language from django.utils.translation import gettext_lazy as _ from django.views.decorators.http import require_http_methods +from unidecode import unidecode + from oioioi.base.permissions import enforce_condition, not_anonymous from oioioi.base.utils import jsonify, tabbed_view from oioioi.base.utils.archive import Archive @@ -77,10 +78,7 @@ # in problem_site.py. We placed the view in problem_site.py # instead of views.py to avoid circular imports. We still import # it here to use it in urls.py. -from oioioi.problems.problem_site import ( - problem_site_statement_zip_view, - problem_site_tab_registry, -) +from oioioi.problems.problem_site import problem_site_tab_registry from oioioi.problems.problem_sources import problem_sources from oioioi.problems.utils import ( can_add_to_problemset, @@ -94,7 +92,6 @@ show_proposal_form, ) from oioioi.programs.models import ModelSolution -from unidecode import unidecode if settings.CONTEST_MODE == ContestMode.neutral: navbar_links_registry.register( @@ -695,16 +692,21 @@ def get_report_row_begin_HTML_view(request, submission_id): return TemplateResponse( request, 'contests/my_submission_table_base_row_begin.html', - { + { 'record': submission_template_context(request, submission), 'show_scores': json.loads(request.POST.get('show_scores', "false")), - 'can_admin': can_admin_problem_instance(request, submission.problem_instance) and - json.loads(request.POST.get('can_admin', "false")), + 'can_admin': can_admin_problem_instance( + request, submission.problem_instance + ) + and json.loads(request.POST.get('can_admin', "false")), 'shortened': json.loads(request.POST.get('shortened', "false")), - 'inside_problem_view': json.loads(request.POST.get('inside_problem_view', "false")), - } + 'inside_problem_view': json.loads( + request.POST.get('inside_problem_view', "false") + ), + }, ) + @transaction.non_atomic_requests def problemset_add_or_update_problem_view(request): if not can_add_to_problemset(request): @@ -992,7 +994,12 @@ def get_last_submissions(request): return TemplateResponse( request, "contests/my_submissions_table.html", - {'submissions': submissions, 'show_scores': True, 'hide_reports': True, 'status': True}, + { + 'submissions': submissions, + 'show_scores': True, + 'hide_reports': True, + 'status': True, + }, ) diff --git a/oioioi/problemsharing/urls.py b/oioioi/problemsharing/urls.py index b368aa31c..b879aa2d6 100644 --- a/oioioi/problemsharing/urls.py +++ b/oioioi/problemsharing/urls.py @@ -5,7 +5,9 @@ app_name = "problemsharing" urlpatterns = [ - re_path(r'^friends/$', views.FriendshipsView.as_view(), name='problemsharing_friends'), + re_path( + r'^friends/$', views.FriendshipsView.as_view(), name='problemsharing_friends' + ), re_path( r'^friends/hints/$', views.friend_hints_view, name='problemsharing_friend_hints' ), diff --git a/oioioi/programs/admin.py b/oioioi/programs/admin.py index 9f81a662c..82239ead8 100644 --- a/oioioi/programs/admin.py +++ b/oioioi/programs/admin.py @@ -14,7 +14,6 @@ from oioioi.contests.admin import ContestAdmin, ProblemInstanceAdmin, SubmissionAdmin from oioioi.contests.models import ProblemInstance from oioioi.contests.utils import is_contest_admin -from oioioi.programs.utils import get_submittable_languages from oioioi.problems.admin import MainProblemInstanceAdmin, ProblemPackageAdmin from oioioi.programs.forms import ( CompilerInlineForm, @@ -32,6 +31,7 @@ ReportActionsConfig, Test, ) +from oioioi.programs.utils import get_submittable_languages class ProgramsConfigInline(admin.TabularInline): diff --git a/oioioi/programs/controllers.py b/oioioi/programs/controllers.py index 8ed54ab30..76b9228b6 100644 --- a/oioioi/programs/controllers.py +++ b/oioioi/programs/controllers.py @@ -7,7 +7,6 @@ from django.conf import settings from django.core.exceptions import SuspiciousOperation, ValidationError from django.core.files.base import ContentFile -from django.forms.widgets import Media from django.template.loader import render_to_string from django.urls import reverse from django.utils.safestring import mark_safe @@ -54,15 +53,15 @@ form_field_id_for_langs, get_extension, get_problem_link_or_name, + get_submittable_languages, has_report_actions_config, is_model_submission, - get_submittable_languages, ) from oioioi.programs.widgets import CancellableFileInput - logger = logging.getLogger(__name__) + def get_report_display_type(request, test_report): if test_report.status == 'INI_OK' or test_report.status == 'OK': try: @@ -98,6 +97,7 @@ def get_report_display_type(request, test_report): return display_type + class ProgrammingProblemController(ProblemController): description = _("Simple programming problem") @@ -179,7 +179,6 @@ def generate_initial_evaluation_environ(self, environ, submission, **kwargs): ) def generate_base_environ(self, environ, submission, **kwargs): - contest = submission.problem_instance.contest self.generate_initial_evaluation_environ(environ, submission) environ.setdefault('recipe', []).extend( [ @@ -582,7 +581,7 @@ def validate_language(file): def parse_problem(problem): available_problems = form.fields['problem_instance_id'].choices problem_id = None - for (id, name) in available_problems: + for id, name in available_problems: if name.find(problem) != -1: if problem_id is None: problem_id = id @@ -622,7 +621,10 @@ def parse_problem(problem): if not request.user.is_anonymous: ensure_preferences_exist_for_user(request.user) default_state = request.user.userpreferences.enable_editor - receipt_types = ((False, "no editor"), (True, "editor"), ) + receipt_types = ( + (False, "no editor"), + (True, "editor"), + ) form.fields["toggle_editor"] = forms.ChoiceField( required=False, choices=receipt_types, @@ -642,7 +644,7 @@ def parse_problem(problem): required=False, label=_("Code"), validators=[validate_code_length], - widget=code_widget + widget=code_widget, ) self._add_langs_to_form(request, form, problem_instance) diff --git a/oioioi/programs/handlers.py b/oioioi/programs/handlers.py index c7849e2c0..98d57804a 100755 --- a/oioioi/programs/handlers.py +++ b/oioioi/programs/handlers.py @@ -12,7 +12,7 @@ from oioioi.base.utils import make_html_link from oioioi.contests.handlers import _get_submission_or_skip from oioioi.contests.models import ScoreReport, SubmissionReport -from oioioi.contests.scores import IntegerScore, ScoreValue +from oioioi.contests.scores import ScoreValue from oioioi.evalmgr.tasks import transfer_job from oioioi.filetracker.client import get_client from oioioi.filetracker.utils import ( @@ -22,10 +22,10 @@ from oioioi.programs.models import ( CompilationReport, GroupReport, + LanguageOverrideForTest, Test, TestReport, UserOutGenStatus, - LanguageOverrideForTest, ) logger = logging.getLogger(__name__) @@ -118,7 +118,7 @@ def compile_end(env, **kwargs): def _override_tests_limits(language, tests): - """ Given language and list of Test objects, returns + """Given language and list of Test objects, returns the dictionary of memory and time limits. The key is test's pk. In case language overriding is defined in the database, @@ -411,8 +411,7 @@ def grade_groups(env, **kwargs): group_result['status'] = status one_of_tests = env['tests'][next(iter(results.keys()))] if not all( - env['tests'][key]['kind'] == one_of_tests['kind'] - for key in results.keys() + env['tests'][key]['kind'] == one_of_tests['kind'] for key in results.keys() ): raise ValueError( "Tests in group '%s' have different kinds. " diff --git a/oioioi/programs/models.py b/oioioi/programs/models.py index b7bddb62f..f801dcc89 100644 --- a/oioioi/programs/models.py +++ b/oioioi/programs/models.py @@ -5,7 +5,6 @@ from django.db import models, transaction from django.db.models.signals import post_save, pre_save from django.dispatch import receiver - from django.utils.translation import gettext_lazy as _ from oioioi.base.fields import EnumField, EnumRegistry @@ -70,7 +69,6 @@ def validate_memory_limit(value): ) - class Test(models.Model): __test__ = False problem_instance = models.ForeignKey(ProblemInstance, on_delete=models.CASCADE) diff --git a/oioioi/programs/notifications.py b/oioioi/programs/notifications.py index 3e2e253ef..af83cc8fa 100644 --- a/oioioi/programs/notifications.py +++ b/oioioi/programs/notifications.py @@ -37,7 +37,11 @@ def notification_function_initial_results(arguments): url = '' message = gettext_noop("Initial result for task %(short_name)s is ready") - message_arguments = {'short_name': pi.short_name, 'address': url, 'submission_id': arguments.submission.pk} + message_arguments = { + 'short_name': pi.short_name, + 'address': url, + 'submission_id': arguments.submission.pk, + } NotificationHandler.send_notification( arguments.user, 'initial_results', message, message_arguments @@ -58,9 +62,7 @@ def notification_function_submission_judged(arguments): request.timestamp = datetime.now().replace(tzinfo=utc) # Check if the final report is visible to the user - if not pi.controller.can_see_submission_score( - request, arguments.submission - ): + if not pi.controller.can_see_submission_score(request, arguments.submission): return if pi.contest: @@ -92,7 +94,7 @@ def notification_function_submission_judged(arguments): } if pi.contest: message_arguments['contest_name'] = pi.contest.name - + NotificationHandler.send_notification( arguments.user, 'submission_judged', message, message_arguments ) diff --git a/oioioi/programs/tests.py b/oioioi/programs/tests.py index e41889096..a53f1cb02 100644 --- a/oioioi/programs/tests.py +++ b/oioioi/programs/tests.py @@ -1,12 +1,11 @@ import os import re +import urllib from collections import defaultdict from datetime import datetime # pylint: disable=E0611 import pytest import six -import urllib - from django.conf import settings from django.contrib.admin.utils import quote from django.contrib.auth.models import User @@ -18,6 +17,7 @@ from django.utils.html import escape, strip_tags from django.utils.http import urlencode from django.utils.timezone import utc + from oioioi.base.notification import NotificationHandler from oioioi.base.tests import ( TestCase, @@ -27,22 +27,23 @@ ) from oioioi.base.utils import memoized_property from oioioi.base.utils.test_migrations import TestCaseMigrations +from oioioi.contests.handlers import call_submission_judged from oioioi.contests.models import Contest, ProblemInstance, Round, Submission from oioioi.contests.scores import IntegerScore -from oioioi.contests.handlers import call_submission_judged from oioioi.contests.tests import PrivateRegistrationController, SubmitMixin +from oioioi.evalmgr.tasks import create_environ from oioioi.filetracker.tests import TestStreamingMixin from oioioi.problems.models import Problem from oioioi.programs import utils from oioioi.programs.controllers import ProgrammingContestController -from oioioi.programs.handlers import make_report, collect_tests +from oioioi.programs.handlers import collect_tests, make_report from oioioi.programs.models import ( + LanguageOverrideForTest, ModelSolution, ProblemAllowedLanguage, ProgramSubmission, ReportActionsConfig, Test, - LanguageOverrideForTest, TestReport, check_compilers_config, ) @@ -50,7 +51,6 @@ from oioioi.programs.utils import form_field_id_for_langs from oioioi.programs.views import _testreports_to_generate_outs from oioioi.sinolpack.tests import get_test_filename -from oioioi.evalmgr.tasks import create_environ def extract_code(show_response): @@ -541,7 +541,7 @@ def fake_send_notification( NotificationHandler.send_notification = fake_send_notification submission = Submission.objects.get(pk=1) - + environ = create_environ() environ['extra_args'] = {} environ['is_rejudge'] = False @@ -1027,7 +1027,7 @@ def test_discrete_test_scorer(self): results = list( map( utils.discrete_test_scorer, - *list(zip(*self.t_results_unequal_max_scores)) + *list(zip(*self.t_results_unequal_max_scores)), ) ) self.assertEqual(self.t_expected_unequal_max_scores, results) @@ -1069,7 +1069,7 @@ def test_threshold_linear_test_scorer(self): results = list( map( utils.threshold_linear_test_scorer, - *list(zip(*self.t_results_unequal_max_scores)) + *list(zip(*self.t_results_unequal_max_scores)), ) ) self.assertEqual(self.t_expected_unequal_max_scores, results) @@ -1108,7 +1108,7 @@ def g_results_unequal_max_scores(self): results = list( map( utils.threshold_linear_test_scorer, - *list(zip(*self.t_results_unequal_max_scores)) + *list(zip(*self.t_results_unequal_max_scores)), ) ) dicts = list(self.g_results_wrong.values()) diff --git a/oioioi/programs/utils.py b/oioioi/programs/utils.py index 6163ddb54..95ee534bb 100644 --- a/oioioi/programs/utils.py +++ b/oioioi/programs/utils.py @@ -8,7 +8,6 @@ from django.urls import reverse from oioioi.base.utils import make_html_link -from oioioi.contests.models import Submission from oioioi.contests.scores import IntegerScore, ScoreValue from oioioi.contests.utils import aggregate_statuses from oioioi.programs.models import ( @@ -24,21 +23,17 @@ def sum_score_aggregator(group_results): return None, None, 'OK' scores = [ - ScoreValue.deserialize(result['score']) - for result in group_results.values() + ScoreValue.deserialize(result['score']) for result in group_results.values() ] max_scores = [ - ScoreValue.deserialize(result['max_score']) - for result in group_results.values() + ScoreValue.deserialize(result['max_score']) for result in group_results.values() ] # the sum below needs a start value of an appropriate type, # the default zero is not suitable score = sum(scores[1:], scores[0]) max_score = sum(max_scores[1:], max_scores[0]) - status = aggregate_statuses( - [result['status'] for result in group_results.values()] - ) + status = aggregate_statuses([result['status'] for result in group_results.values()]) return score, max_score, status @@ -50,19 +45,15 @@ def sum_group_scorer(test_results): return None, None, 'OK' scores = [ - ScoreValue.deserialize(result['score']) - for result in test_results.values() + ScoreValue.deserialize(result['score']) for result in test_results.values() ] max_scores = [ - ScoreValue.deserialize(result['max_score']) - for result in test_results.values() + ScoreValue.deserialize(result['max_score']) for result in test_results.values() ] score = sum(scores[1:], scores[0]) max_score = sum(max_scores[1:], max_scores[0]) - status = aggregate_statuses( - [result['status'] for result in test_results.values()] - ) + status = aggregate_statuses([result['status'] for result in test_results.values()]) return score, max_score, status @@ -75,20 +66,16 @@ def min_group_scorer(test_results): """Gets minimal result of all tests inside a test group.""" scores = [ - ScoreValue.deserialize(result['score']) - for result in test_results.values() + ScoreValue.deserialize(result['score']) for result in test_results.values() ] max_scores = [ - ScoreValue.deserialize(result['max_score']) - for result in test_results.values() + ScoreValue.deserialize(result['max_score']) for result in test_results.values() ] score = min(scores) max_score = min(max_scores) if max_score != max(max_scores): - raise UnequalMaxScores( - "Tests in one group cannot have different max scores." - ) + raise UnequalMaxScores("Tests in one group cannot have different max scores.") sorted_results = sorted(list(test_results.values()), key=itemgetter('order')) status = aggregate_statuses([result['status'] for result in sorted_results]) @@ -99,7 +86,7 @@ def min_group_scorer(test_results): def discrete_test_scorer(test, result): status = result['result_code'] percentage = result.get('result_percentage', 100) - max_score = int(ceil(percentage * test['max_score'] / 100.)) + max_score = int(ceil(percentage * test['max_score'] / 100.0)) score = max_score if status == 'OK' else 0 return IntegerScore(score), IntegerScore(test['max_score']), status diff --git a/oioioi/programs/views.py b/oioioi/programs/views.py index 586ccc265..fab1a52aa 100644 --- a/oioioi/programs/views.py +++ b/oioioi/programs/views.py @@ -205,7 +205,7 @@ def download_output_file_view(request, test_id): def download_checker_exe_view(request, checker_id): checker = get_object_or_404(OutputChecker, id=checker_id) - if not test.problem_instance.controller.can_see_checker_exe(request, test): + if not checker.problem_instance.controller.can_see_checker_exe(request, checker): raise PermissionDenied if not checker.exe_file: raise Http404 diff --git a/oioioi/questions/management/commands/mailnotifyd.py b/oioioi/questions/management/commands/mailnotifyd.py index 45cd08f81..934287567 100644 --- a/oioioi/questions/management/commands/mailnotifyd.py +++ b/oioioi/questions/management/commands/mailnotifyd.py @@ -50,7 +50,7 @@ def mailnotify(instance): mails = [(sub.user, sub.user.email) for sub in subscriptions if sub.user.email] # if there are any users with e-mails - for (user, mail) in mails: + for user, mail in mails: try_sending(instance, user, mail) elif instance.kind == 'PRIVATE': diff --git a/oioioi/questions/models.py b/oioioi/questions/models.py index afd6acff9..fed119d5c 100644 --- a/oioioi/questions/models.py +++ b/oioioi/questions/models.py @@ -9,7 +9,6 @@ from django.dispatch import receiver from django.urls import reverse from django.utils import timezone - from django.utils.text import Truncator from django.utils.translation import gettext_lazy as _ @@ -30,7 +29,6 @@ logger = logging.getLogger('oioioi') - class Message(models.Model): contest = models.ForeignKey( Contest, null=True, blank=True, on_delete=models.CASCADE @@ -99,7 +97,7 @@ def __str__(self): @property def to_quote(self): lines = self.content.strip().split('\n') - return ''.join('> ' + l for l in lines) + return ''.join('> ' + line for line in lines) def get_absolute_url(self): link = reverse( @@ -114,14 +112,13 @@ def get_absolute_url(self): return link def get_user_date(self): - """ returns date visible by a user """ + """returns date visible by a user""" return self.pub_date if self.pub_date is not None else self.date def get_kind_label(self): return message_kind_labels[self.kind] - class ReplyTemplate(models.Model): contest = models.ForeignKey( Contest, null=True, blank=True, on_delete=models.CASCADE diff --git a/oioioi/questions/notifications.py b/oioioi/questions/notifications.py index fce8b5266..02e8f7d28 100644 --- a/oioioi/questions/notifications.py +++ b/oioioi/questions/notifications.py @@ -36,9 +36,9 @@ def notification_function_answer(arguments): def notification_function_public(arguments): - assert hasattr(arguments, 'contest') and hasattr(arguments, 'message_instance'), ( - "The log doesn't have contest or message_instance value in the extra map" - ) + assert hasattr(arguments, 'contest') and hasattr( + arguments, 'message_instance' + ), "The log doesn't have contest or message_instance value in the extra map" message_details = ( arguments.message_instance.topic + ': ' + arguments.message_instance.content diff --git a/oioioi/questions/views.py b/oioioi/questions/views.py index 8d5a1f1b5..c68383666 100644 --- a/oioioi/questions/views.py +++ b/oioioi/questions/views.py @@ -216,6 +216,13 @@ def make_entry(m): 'needs_reply': m in unanswered, } + def sort_key_basicadmin(entry): + return entry['needs_reply'], entry['has_new_message'], entry['timestamp'] + + + def sort_key_default(entry): + return entry['has_new_message'], entry['needs_reply'], entry['timestamp'] + vmsg_kwargs, template_kwargs = process_filter_form(request) vmessages = visible_messages(request, **vmsg_kwargs) new_msgs = frozenset(new_messages(request, vmessages)) @@ -237,9 +244,9 @@ def make_entry(m): tree[m.id] = entry if is_contest_basicadmin(request): - sort_key = lambda x: (x['needs_reply'], x['has_new_message'], x['timestamp']) + sort_key = sort_key_basicadmin else: - sort_key = lambda x: (x['has_new_message'], x['needs_reply'], x['timestamp']) + sort_key = sort_key_default tree_list = sorted(list(tree.values()), key=sort_key, reverse=True) for entry in tree_list: entry['replies'].sort(key=sort_key, reverse=True) diff --git a/oioioi/quizzes/admin.py b/oioioi/quizzes/admin.py index c770f6b7f..2b4a3ee5f 100644 --- a/oioioi/quizzes/admin.py +++ b/oioioi/quizzes/admin.py @@ -2,7 +2,6 @@ from django.core.exceptions import ValidationError from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy as _ - from nested_admin import nested from nested_admin.formsets import NestedInlineFormSet diff --git a/oioioi/quizzes/controllers.py b/oioioi/quizzes/controllers.py index 774602a85..477c80ecd 100644 --- a/oioioi/quizzes/controllers.py +++ b/oioioi/quizzes/controllers.py @@ -63,21 +63,25 @@ def validate_submission_form(self, request, problem_instance, form, cleaned_data return cleaned_data def render_pictures(self, pictures): - return format_html( - u'''
+ return ( + format_html( + u'''
{}
''', - format_html_join( - u'\n', - u''' + format_html_join( + u'\n', + u'''
{} ''', - ((p.get_absolute_url(), p.caption) for p in pictures), - ), - ) if pictures else u'' + ((p.get_absolute_url(), p.caption) for p in pictures), + ), + ) + if pictures + else u'' + ) def render_question(self, request, question): pictures = question.quizquestionpicture_set.all() @@ -173,7 +177,6 @@ def create_submission(self, request, problem_instance, form_data, **kwargs): return submission def _submit_answers(self, selected_answers, question, submission): - if question.is_text_input: sub = QuizSubmissionTextAnswer.objects.create( quiz_submission=submission, diff --git a/oioioi/quizzes/problem_sources.py b/oioioi/quizzes/problem_sources.py index 027eca268..b469397c0 100644 --- a/oioioi/quizzes/problem_sources.py +++ b/oioioi/quizzes/problem_sources.py @@ -3,6 +3,7 @@ from django.template.response import TemplateResponse from django.urls import reverse from django.utils.translation import gettext_lazy as _ + from oioioi.base.utils import generate_key from oioioi.base.utils.redirect import safe_redirect from oioioi.contests.models import ProblemInstance diff --git a/oioioi/quizzes/tests.py b/oioioi/quizzes/tests.py index b5d6038dd..82ef0645f 100644 --- a/oioioi/quizzes/tests.py +++ b/oioioi/quizzes/tests.py @@ -443,7 +443,7 @@ def test_quiz_tab_visibility(self): url = reverse('problem_site', kwargs={'site_key': quiz.problemsite.url_key}) response = self.client.get(url, follow=True) - for (allowed_tab, disabled_tab) in zip( + for allowed_tab, disabled_tab in zip( self.allowed_quiz_tabs, self.disabled_quiz_tabs ): self.assertContains(response, allowed_tab) diff --git a/oioioi/rankings/models.py b/oioioi/rankings/models.py index 663a6526b..fa9281a8b 100644 --- a/oioioi/rankings/models.py +++ b/oioioi/rankings/models.py @@ -176,9 +176,7 @@ def save_recalc_results(recalc, date_before, date_after, serialized, pages_list) r = Ranking.objects.filter(recalc_in_progress=recalc).select_for_update().get() except Ranking.DoesNotExist: return - r.serialized_data = pickle.dumps( - serialized - ) + r.serialized_data = pickle.dumps(serialized) save_pages(r, pages_list) r.last_recalculation_date = date_before r.last_recalculation_duration = date_after - date_before diff --git a/oioioi/rankings/tests.py b/oioioi/rankings/tests.py index fb4923c4b..c1e3500e4 100644 --- a/oioioi/rankings/tests.py +++ b/oioioi/rankings/tests.py @@ -307,7 +307,7 @@ def test_invalidate_view(self): self.assertTrue(ranking.is_up_to_date()) recalc = choose_for_recalculation() self.assertIsNone(recalc) - response = self.client.post(url, key='key') + self.client.post(url, key='key') ranking.refresh_from_db() self.assertFalse(ranking.is_up_to_date()) recalc = choose_for_recalculation() diff --git a/oioioi/scoresreveal/admin.py b/oioioi/scoresreveal/admin.py index 9deaa78d1..c2c2b7465 100644 --- a/oioioi/scoresreveal/admin.py +++ b/oioioi/scoresreveal/admin.py @@ -2,10 +2,8 @@ from django.utils.translation import gettext_lazy as _ from oioioi.base import admin -from oioioi.base.admin import NO_CATEGORY from oioioi.base.forms import AlwaysChangedModelForm from oioioi.contests.admin import ProblemInstanceAdmin, SubmissionAdmin -from oioioi.contests.utils import is_contest_admin from oioioi.scoresreveal.models import ScoreRevealConfig from oioioi.scoresreveal.utils import is_revealed diff --git a/oioioi/scoresreveal/controllers.py b/oioioi/scoresreveal/controllers.py index f7c9d333e..7dccd6bb2 100644 --- a/oioioi/scoresreveal/controllers.py +++ b/oioioi/scoresreveal/controllers.py @@ -170,9 +170,7 @@ def render_submission_footer(self, request, submission): 'scoresreveal/submission-footer.html', request=request, context={ - 'submission': submission_template_context( - request, submission - ), + 'submission': submission_template_context(request, submission), 'scores_reveals': scores_reveals, 'scores_reveals_limit': scores_reveals_limit, 'scores_reveals_disable_time': scores_reveals_disable_time, diff --git a/oioioi/scoresreveal/tests.py b/oioioi/scoresreveal/tests.py index aef2881f2..06f2997f9 100644 --- a/oioioi/scoresreveal/tests.py +++ b/oioioi/scoresreveal/tests.py @@ -13,8 +13,8 @@ RoundTimeExtension, Submission, ) -from oioioi.scoresreveal.models import ScoreRevealConfig from oioioi.quizzes.models import QuizSubmission +from oioioi.scoresreveal.models import ScoreRevealConfig class TestScoresManualReveal(TestCase): diff --git a/oioioi/selenium_settings.py b/oioioi/selenium_settings.py index c4c583efb..874b3b6c7 100644 --- a/oioioi/selenium_settings.py +++ b/oioioi/selenium_settings.py @@ -1,4 +1,4 @@ -# pylint: disable=wildcard-import +# ruff: noqa from settings import * # Enable optional modules. diff --git a/oioioi/similarsubmits/tests.py b/oioioi/similarsubmits/tests.py index 8db741e32..899450d32 100644 --- a/oioioi/similarsubmits/tests.py +++ b/oioioi/similarsubmits/tests.py @@ -7,6 +7,10 @@ from oioioi.similarsubmits.models import SubmissionsSimilarityGroup +def none_returner(): + return None + + class TestSimilarSubmitViews(TestCase): fixtures = [ 'test_users', @@ -48,7 +52,7 @@ def test_bulk_add_similar_submits_view(self): def test_invalid_bulk_form(self): invalid_bulks = ['1:user:test.cpp', '1:usertestcpp 1:user:test.cpp'] - mock_request = lambda: None + mock_request = none_returner mock_request.contest = None for bulk in invalid_bulks: form_data = {'similar_groups': bulk} diff --git a/oioioi/similarsubmits/urls.py b/oioioi/similarsubmits/urls.py index 1f55cb59f..cef2404cf 100644 --- a/oioioi/similarsubmits/urls.py +++ b/oioioi/similarsubmits/urls.py @@ -13,5 +13,7 @@ views.mark_not_guilty_view, name='mark_not_guilty', ), - re_path(r'^bulk_add/$', views.bulk_add_similarities_view, name='bulk_add_similarities'), + re_path( + r'^bulk_add/$', views.bulk_add_similarities_view, name='bulk_add_similarities' + ), ] diff --git a/oioioi/simpleui/forms.py b/oioioi/simpleui/forms.py index 6a1fd3ac2..b28d23a03 100644 --- a/oioioi/simpleui/forms.py +++ b/oioioi/simpleui/forms.py @@ -1,6 +1,7 @@ from django import forms from django.urls import reverse from django.utils.translation import gettext_lazy as _ + from oioioi.base.utils import make_html_link from oioioi.contests.models import ProblemInstance, Round from oioioi.programs.models import Test diff --git a/oioioi/simpleui/urls.py b/oioioi/simpleui/urls.py index 8a884208f..edb9ade28 100644 --- a/oioioi/simpleui/urls.py +++ b/oioioi/simpleui/urls.py @@ -1,10 +1,13 @@ from django.urls import re_path + from oioioi.simpleui import views app_name = 'simpleui' noncontest_patterns = [ - re_path(r'^user-dashboard/$', views.user_dashboard_view, name='simpleui_user_dashboard') + re_path( + r'^user-dashboard/$', views.user_dashboard_view, name='simpleui_user_dashboard' + ) ] contest_patterns = [ diff --git a/oioioi/sinolpack/package.py b/oioioi/sinolpack/package.py index 8805d8675..aa2322428 100644 --- a/oioioi/sinolpack/package.py +++ b/oioioi/sinolpack/package.py @@ -11,13 +11,13 @@ import chardet import six - from django.conf import settings from django.contrib.auth.models import User from django.core.exceptions import ValidationError from django.core.files import File from django.core.validators import slug_re from django.utils.translation import gettext as _ + from oioioi.base.utils import generate_key, naturalsort_key from oioioi.base.utils.archive import Archive from oioioi.base.utils.execute import ExecuteError, execute @@ -251,7 +251,7 @@ def _override_compiler(self, prefix, lang, compilation_job): 'cpp': 'C++', 'pas': 'Pascal', 'java': 'Java', - 'py': 'Python' + 'py': 'Python', } if lang in name_map and lang in settings.OVERRIDE_COMPILER_LANGS: @@ -271,7 +271,7 @@ def _run_compilation_job(self, ext, ft_source_name, out_name): prefix = 'system' compilation_job['compiler'] = prefix + '-' + lang self._override_compiler(prefix, lang, compilation_job) - + if not self.use_make and self.prog_archive: compilation_job['additional_archive'] = self.prog_archive add_extra_files( @@ -320,7 +320,7 @@ def _make_ins(self, re_string): renv = run_sioworkers_job(env) if renv['return_code'] != 0: - raise ProblemPackageError(_("Ingen failed: %r") % renv) + raise ProblemPackageError(_("Ingen failed: %r") % renv) get_client().delete_file(env['compiled_file']) return renv['collected_files'] @@ -574,7 +574,7 @@ def _process_statements(self): # pylint: disable=maybe-no-member self.problem.statements.all().delete() - lang_prefs = [''] + ['-' + l[0] for l in settings.STATEMENT_LANGUAGES] + lang_prefs = [''] + ['-' + lang[0] for lang in settings.STATEMENT_LANGUAGES] if self.use_make: self._compile_latex_docs(docdir) @@ -618,7 +618,6 @@ def _force_index_encoding(self, htmlzipfile): with zipfile.ZipFile(htmlzipfile, 'r') as archive, archive.open( 'index.html' ) as index: - data = index.read() # First, we check if index.html is utf-8 encoded. # If it is - nothing to do. diff --git a/oioioi/sinolpack/tests.py b/oioioi/sinolpack/tests.py index c45ab1373..eb35f408b 100644 --- a/oioioi/sinolpack/tests.py +++ b/oioioi/sinolpack/tests.py @@ -1,11 +1,11 @@ # coding: utf-8 import os.path +import urllib.parse import zipfile +from io import BytesIO import pytest -import urllib.parse -from io import BytesIO from django.conf import settings from django.core.files import File from django.core.management import call_command @@ -15,6 +15,7 @@ from django.urls import reverse from django.utils.html import escape from django.utils.module_loading import import_string + from oioioi.base.tests import TestCase, needs_linux from oioioi.contests.current_contest import ContestMode from oioioi.contests.models import ( @@ -67,6 +68,7 @@ def no_makefiles(fn): # both_configurations will be run twice. Once in safe and once in unsafe unpack # mode. + # Unfortunately, you won't be able run such a decorated method as a single # test, that is: # ./test.sh oioioi.sinolpack.tests:TestSinolPackage.test_huge_unpack_update diff --git a/oioioi/sioworkers/backends.py b/oioioi/sioworkers/backends.py index 1dba4f49a..e040faab4 100644 --- a/oioioi/sioworkers/backends.py +++ b/oioioi/sioworkers/backends.py @@ -5,11 +5,11 @@ # this assumption, even a single call to LocalClient.build would break that # code. from threading import Lock +from xmlrpc.client import Server import sio.workers.runner from django.conf import settings from django.db import transaction -from xmlrpc.client import Server from oioioi.evalmgr.tasks import delay_environ diff --git a/oioioi/sioworkers/management/commands/download_sandboxes.py b/oioioi/sioworkers/management/commands/download_sandboxes.py index d061d1f8b..f3d68ec18 100644 --- a/oioioi/sioworkers/management/commands/download_sandboxes.py +++ b/oioioi/sioworkers/management/commands/download_sandboxes.py @@ -2,10 +2,10 @@ import os import os.path - import urllib.error import urllib.parse import urllib.request + from django.conf import settings from django.core.management.base import BaseCommand, CommandError @@ -95,9 +95,7 @@ def handle(self, *args, **options): print("--- Downloading Manifest ...", file=self.stdout) try: manifest_url = options['manifest_url'] - manifest = ( - urllib.request.urlopen(manifest_url).read().decode('utf-8') - ) + manifest = urllib.request.urlopen(manifest_url).read().decode('utf-8') manifest = manifest.strip().splitlines() except Exception as e: raise CommandError("Error downloading manifest: %s" % (e,)) @@ -105,9 +103,7 @@ def handle(self, *args, **options): print("--- Looking for license ...", file=self.stdout) try: license_url = urllib.parse.urljoin(manifest_url, 'LICENSE') - license = ( - urllib.request.urlopen(license_url).read().decode('utf-8') - ) + license = urllib.request.urlopen(license_url).read().decode('utf-8') if not options['license_agreement']: self.display_license(license) except urllib.error.HTTPError as e: @@ -153,7 +149,8 @@ def handle(self, *args, **options): quiet_flag = ['-nv'] if options['quiet'] else [] execute( - [options['wget'], '-N', '--no-check-certificate', '-i', '-'] + quiet_flag, + [options['wget'], '-N', '--no-check-certificate', '-i', '-'] + + quiet_flag, stdin='\n'.join(urls).encode('utf-8'), capture_output=False, cwd=download_dir, diff --git a/oioioi/sioworkers/management/commands/worker.py b/oioioi/sioworkers/management/commands/worker.py index c4630d44d..43c4c690d 100644 --- a/oioioi/sioworkers/management/commands/worker.py +++ b/oioioi/sioworkers/management/commands/worker.py @@ -1,8 +1,8 @@ import json +from xmlrpc.client import Server from django.conf import settings from django.core.management.base import BaseCommand, CommandError -from xmlrpc.client import Server class Command(BaseCommand): @@ -19,9 +19,9 @@ def add_arguments(self, parser): parser.add_argument('args', type=str, nargs='*', help='Command\' arguments') def cmd_list(self, **kwargs): - l = self.server.get_workers() - if l: - self.stdout.write('\n'.join(map(str, l))) + workers = self.server.get_workers() + if workers: + self.stdout.write('\n'.join(map(str, workers))) else: self.stdout.write('No workers connected.\n') diff --git a/oioioi/statistics/plotfunctions.py b/oioioi/statistics/plotfunctions.py index cabe00a19..d2966c8a8 100644 --- a/oioioi/statistics/plotfunctions.py +++ b/oioioi/statistics/plotfunctions.py @@ -212,7 +212,7 @@ def test_scores(request, problem): # Why .order_by()? Just in case. More in the following link: # https://docs.djangoproject.com/en/dev/topics/db/ # aggregation/#interaction-with-default-ordering-or-order-by - # Testreports for deleted tests remain in the database, + # Testreports for deleted tests remain in the database, # we can't show them here. agg = ( TestReport.objects.filter( diff --git a/oioioi/statistics/plottypes.py b/oioioi/statistics/plottypes.py index 65bff871a..fc1bea941 100644 --- a/oioioi/statistics/plottypes.py +++ b/oioioi/statistics/plottypes.py @@ -88,7 +88,7 @@ def highcharts_options(self, data): options['%sAxis' % a][b] = data[key] # Setting axes titles if 'titles' in data: - for (key, title) in data['titles'].items(): + for key, title in data['titles'].items(): options.setdefault(key, {}).update({'title': {'text': title}}) return options diff --git a/oioioi/statistics/views.py b/oioioi/statistics/views.py index 584738aa8..9598b943e 100644 --- a/oioioi/statistics/views.py +++ b/oioioi/statistics/views.py @@ -23,7 +23,7 @@ def links(request): links_list = [] plot_groups = controller.statistics_available_plot_groups(request) - for (category, object_name, description) in plot_groups: + for category, object_name, description in plot_groups: category_name, link = statistics_categories[category] links_list.append( { @@ -62,7 +62,7 @@ def statistics_view( controller = request.contest.controller category_key = '' - for (key, desc) in statistics_categories: + for key, desc in statistics_categories: if desc[1] == category: category_key = key category = category_key @@ -79,7 +79,7 @@ def statistics_view( else: raise Http404 - if not (category, object_name) in set( + if (category, object_name) not in set( (c, o) for (c, o, d) in controller.statistics_available_plot_groups(request) ): raise PermissionDenied(_("You have no access to those charts")) diff --git a/oioioi/submitservice/static/submitservice/submit.py b/oioioi/submitservice/static/submitservice/submit.py index 63374275e..863dc0914 100755 --- a/oioioi/submitservice/static/submitservice/submit.py +++ b/oioioi/submitservice/static/submitservice/submit.py @@ -11,13 +11,12 @@ import random import string import sys +import urllib.parse +import urllib.request import webbrowser from argparse import ArgumentParser from os.path import expanduser, splitext -import urllib.parse -import urllib.request - class MultiPartForm(object): """Accumulate the data to be used when posting a form.""" @@ -204,9 +203,7 @@ def submit(filename, task_name, token, contest_url, open_webbrowser): form.add_field('task', task_name) form.add_file('file', solution_file.name, filehandle=solution_file) body = str(form) - request = urllib.request.Request( - '%ssubmitservice/submit/' % contest_url - ) + request = urllib.request.Request('%ssubmitservice/submit/' % contest_url) request.add_header('Content-Type', form.get_content_type()) request.add_header('Content-Length', str(len(body))) request.add_data(body) diff --git a/oioioi/suspendjudge/handlers.py b/oioioi/suspendjudge/handlers.py index ae8cbbed2..4ba26b772 100644 --- a/oioioi/suspendjudge/handlers.py +++ b/oioioi/suspendjudge/handlers.py @@ -1,6 +1,6 @@ -from celery.exceptions import Ignore from django.db import transaction +from celery.exceptions import Ignore from oioioi.contests.handlers import _get_submission_or_skip from oioioi.evalmgr.utils import mark_job_state from oioioi.programs.models import ModelProgramSubmission diff --git a/oioioi/suspendjudge/models.py b/oioioi/suspendjudge/models.py index d6686c85f..6d8aab569 100644 --- a/oioioi/suspendjudge/models.py +++ b/oioioi/suspendjudge/models.py @@ -1,7 +1,6 @@ from django.db import models from django.utils.translation import gettext_lazy as _ -from oioioi.base.utils.deps import check_django_app_dependencies from oioioi.contests.models import ProblemInstance from oioioi.evalmgr.models import job_states diff --git a/oioioi/suspendjudge/tests.py b/oioioi/suspendjudge/tests.py index 579313596..558e9acba 100644 --- a/oioioi/suspendjudge/tests.py +++ b/oioioi/suspendjudge/tests.py @@ -1,6 +1,6 @@ -from celery.exceptions import Ignore from django.urls import reverse +from celery.exceptions import Ignore from oioioi.base.tests import TestCase from oioioi.contests.models import Contest, ProblemInstance, Submission from oioioi.evalmgr.tasks import create_environ diff --git a/oioioi/szkopul/settings.py b/oioioi/szkopul/settings.py index e51943f65..c2196514b 100644 --- a/oioioi/szkopul/settings.py +++ b/oioioi/szkopul/settings.py @@ -1,9 +1,18 @@ # -*- coding: utf-8 -*- from datetime import datetime + import pytz from django.utils.safestring import mark_safe -from oioioi.default_settings import * + from oioioi.contests.current_contest import ContestMode +from oioioi.default_settings import ( + AUTHENTICATION_BACKENDS, + CACHED_TEMPLATE_LOADERS, + INSTALLED_APPS, + PROBLEM_SOURCES, + TEMPLATES, + UNCACHED_TEMPLATE_LOADERS, +) # This should match INSTALLATION_CONFIG_VERSION in # "oioioi/default_settings.py". @@ -57,9 +66,7 @@ # Email addresses to send communication from users (for example requests for # teacher accounts). -MANAGERS = ( - ('Szkopul Admin', 'sio2@sio2project.mimuw.edu.pl'), -) +MANAGERS = (('Szkopul Admin', 'sio2@sio2project.mimuw.edu.pl'),) # Registration checkbox descriptions @@ -70,11 +77,19 @@ " zgodę na przetwarzanie moich ww. danych osobowych" " oraz oświadczam," " że zapoznałam/zapoznałem się z " - "klauzulą informacyjną") + "klauzulą informacyjną" +) # See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts -ALLOWED_HOSTS = ['szkopul.edu.pl', 'szk.oioioi.edu.pl', - 'snag.dasie.mimuw.edu.pl', 'snag', 'szkopul', 'szkopul2', 'localhost'] +ALLOWED_HOSTS = [ + 'szkopul.edu.pl', + 'szk.oioioi.edu.pl', + 'snag.dasie.mimuw.edu.pl', + 'snag', + 'szkopul', + 'szkopul2', + 'localhost', +] # Local time zone for this installation. Choices can be found here: # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name @@ -175,21 +190,13 @@ RUN_SIOWORKERSD = False SUBMITTABLE_LANGUAGES = { - 'C': { - 'display_name': 'C' - }, - 'C++': { - 'display_name': 'C++' - }, - 'Pascal': { - 'display_name': 'Pascal' - }, + 'C': {'display_name': 'C'}, + 'C++': {'display_name': 'C++'}, + 'Pascal': {'display_name': 'Pascal'}, # 'Java': { # 'display_name': 'Java' # }, - 'Python': { - 'display_name': 'Python' - }, + 'Python': {'display_name': 'Python'}, } SUBMITTABLE_EXTENSIONS = { @@ -204,25 +211,21 @@ # By default that means ones defined here: # https://github.com/sio2project/sioworkers/blob/master/setup.py#L71 AVAILABLE_COMPILERS = { - 'C': { - 'gcc4_8_2_c99': {'display_name': 'gcc:4.8.2 std=gnu99'} - }, + 'C': {'gcc4_8_2_c99': {'display_name': 'gcc:4.8.2 std=gnu99'}}, 'C++': { 'g++4_8_2_cpp11': {'display_name': 'g++:4.8.2 std=c++11'}, 'g++8_3_cpp17': {'display_name': 'g++:8.3 std=c++17'}, 'g++8_3_cpp17_amd64': {'display_name': 'g++:8.3 std=c++17 x64'}, - 'g++10_2_cpp17_amd64': {'display_name': 'g++:10.2 std=c++17 x64'} - }, - 'Pascal': { - 'fpc2_6_2': {'display_name': 'fpc:2.6.2'} + 'g++10_2_cpp17_amd64': {'display_name': 'g++:10.2 std=c++17 x64'}, }, + 'Pascal': {'fpc2_6_2': {'display_name': 'fpc:2.6.2'}}, # 'Java': { # 'java1_8': {'display_name': 'java:1.8'} # }, 'Python': { 'python_3_4_numpy': {'display_name': 'python:3.4 + numpy'}, 'python_3_7_numpy': {'display_name': 'python:3.7 + numpy'}, - 'python_3_9_numpy': {'display_name': 'python:3.9 + numpy'} + 'python_3_9_numpy': {'display_name': 'python:3.9 + numpy'}, }, } @@ -362,7 +365,7 @@ 'oioioi.problemsharing', 'oioioi.usergroups', 'oioioi.usercontests', - 'oioioi.plagiarism' + 'oioioi.plagiarism', ) + INSTALLED_APPS PROBLEM_TAGS_VISIBLE = True @@ -385,13 +388,21 @@ ] # VERY STUPID WORKAROUND FOR SZKOPUL-FK -if 'oioioi.problems.processors.dangling_problems_processor' in TEMPLATES[0]['OPTIONS']['context_processors']: +if ( + 'oioioi.problems.processors.dangling_problems_processor' + in TEMPLATES[0]['OPTIONS']['context_processors'] +): TEMPLATES[0]['OPTIONS']['context_processors'].remove( - 'oioioi.problems.processors.dangling_problems_processor') + 'oioioi.problems.processors.dangling_problems_processor' + ) # AND FOR SZKOPUL-FJ -if 'oioioi.problems.processors.problems_need_rejudge_processor' in TEMPLATES[0]['OPTIONS']['context_processors']: +if ( + 'oioioi.problems.processors.problems_need_rejudge_processor' + in TEMPLATES[0]['OPTIONS']['context_processors'] +): TEMPLATES[0]['OPTIONS']['context_processors'].remove( - 'oioioi.problems.processors.problems_need_rejudge_processor') + 'oioioi.problems.processors.problems_need_rejudge_processor' + ) AUTHENTICATION_BACKENDS += ( 'oioioi.teachers.auth.TeacherAuthBackend', @@ -459,9 +470,7 @@ 'handlers': ['console'], }, 'filters': { - 'require_debug_false': { - '()': 'django.utils.log.RequireDebugFalse' - }, + 'require_debug_false': {'()': 'django.utils.log.RequireDebugFalse'}, }, 'formatters': { 'date_and_level': { @@ -483,17 +492,17 @@ 'mail_admins': { 'level': 'ERROR', 'filters': ['require_debug_false'], - 'class': 'django.utils.log.AdminEmailHandler' + 'class': 'django.utils.log.AdminEmailHandler', }, 'audit': { 'level': 'INFO', 'class': 'logging.FileHandler', 'formatter': 'date_and_level', - 'filename': '/sio2/deployment/logs/audit.log' + 'filename': '/sio2/deployment/logs/audit.log', }, 'emit_notification': { 'level': 'DEBUG', - 'class': 'oioioi.base.notification.NotificationHandler' + 'class': 'oioioi.base.notification.NotificationHandler', }, }, 'loggers': { @@ -510,7 +519,7 @@ 'django.security': { 'handlers': ['console'], 'level': 'ERROR', - 'propagate': False + 'propagate': False, }, 'oioioi': { 'handlers': ['console', 'emit_notification'], @@ -532,7 +541,7 @@ 'level': 'INFO', 'propagate': False, }, - } + }, } # If set to True, usercontests will become read-only: it will be impossible to diff --git a/oioioi/szkopul/tests.py b/oioioi/szkopul/tests.py index 3186492f1..47af01633 100644 --- a/oioioi/szkopul/tests.py +++ b/oioioi/szkopul/tests.py @@ -14,7 +14,6 @@ class TestMainPageView(TestCase): - fixtures = [ 'test_users', 'test_contest', diff --git a/oioioi/szkopul/views.py b/oioioi/szkopul/views.py index fe1c3cf17..091abcd48 100644 --- a/oioioi/szkopul/views.py +++ b/oioioi/szkopul/views.py @@ -1,8 +1,8 @@ -import django from django.conf import settings from django.template.response import TemplateResponse from django.urls import reverse from django.utils.translation import gettext_lazy as _ + from oioioi.base.main_page import register_main_page_view from oioioi.contests.controllers import submission_template_context from oioioi.contests.models import Submission diff --git a/oioioi/teachers/admin.py b/oioioi/teachers/admin.py index 3a405ab6e..e061cdc12 100644 --- a/oioioi/teachers/admin.py +++ b/oioioi/teachers/admin.py @@ -11,15 +11,30 @@ from oioioi.base.menu import personal_menu_registry from oioioi.base.permissions import is_superuser from oioioi.contests.admin import ContestAdmin -from oioioi.teachers.forms import TeacherContestForm, AddTeacherForm +from oioioi.teachers.forms import AddTeacherForm, TeacherContestForm from oioioi.teachers.models import ContestTeacher, RegistrationConfig, Teacher class TeacherAdmin(admin.ModelAdmin): - list_display = ['teacher_login', 'teacher_email', 'teacher_first_name', 'teacher_last_name', 'school', 'is_active', 'join_date'] - list_editable = ['is_active'] - - search_fields = ['school', 'user__username', 'user__first_name', 'user__last_name', 'user__email', 'join_date'] + list_display = [ + 'teacher_login', + 'teacher_email', + 'teacher_first_name', + 'teacher_last_name', + 'school', + 'is_active', + 'join_date', + ] + list_editable = ['is_active'] + + search_fields = [ + 'school', + 'user__username', + 'user__first_name', + 'user__last_name', + 'user__email', + 'join_date', + ] form = AddTeacherForm diff --git a/oioioi/teachers/forms.py b/oioioi/teachers/forms.py index 5382eefb0..e1433ad48 100644 --- a/oioioi/teachers/forms.py +++ b/oioioi/teachers/forms.py @@ -3,10 +3,9 @@ from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy as _ +from oioioi.base.utils.user_selection import UserSelectionField from oioioi.contests.forms import SimpleContestForm from oioioi.teachers.models import Teacher -from oioioi.base.utils.user_selection import UserSelectionField - class TeacherContestForm(SimpleContestForm): diff --git a/oioioi/teachers/models.py b/oioioi/teachers/models.py index 232c4d4e9..262cf63b0 100644 --- a/oioioi/teachers/models.py +++ b/oioioi/teachers/models.py @@ -2,7 +2,6 @@ from django.contrib.auth.models import User from django.core.exceptions import ImproperlyConfigured from django.db import models - from django.utils.translation import gettext_lazy as _ from oioioi.base.utils import generate_key @@ -17,7 +16,6 @@ ) - class Teacher(models.Model): user = models.OneToOneField( User, primary_key=True, verbose_name=_("user"), on_delete=models.CASCADE @@ -33,7 +31,6 @@ def __str__(self): return str(self.user) - class ContestTeacher(models.Model): contest = models.ForeignKey(Contest, on_delete=models.CASCADE) teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE) diff --git a/oioioi/teachers/views.py b/oioioi/teachers/views.py index cc45a9c62..758182de9 100644 --- a/oioioi/teachers/views.py +++ b/oioioi/teachers/views.py @@ -4,7 +4,6 @@ from django.core.exceptions import PermissionDenied, SuspiciousOperation from django.core.mail import EmailMessage from django.http import Http404 -from django.http import JsonResponse from django.shortcuts import get_object_or_404, redirect from django.template.loader import render_to_string from django.template.response import TemplateResponse @@ -52,11 +51,13 @@ def is_teacher(request): def is_not_teacher(request): return not_anonymous(request) and not request.user.has_perm('teachers.teacher') + @enforce_condition(is_superuser) def get_non_teacher_names(request): queryset = User.objects.filter(teacher__isnull=True) return get_user_hints_view(request, 'substr', queryset) + def send_request_email(request, teacher, message): context = { 'teacher': teacher, diff --git a/oioioi/test_settings.py b/oioioi/test_settings.py index 03b7b5008..4c0a74f51 100644 --- a/oioioi/test_settings.py +++ b/oioioi/test_settings.py @@ -1,4 +1,4 @@ -# pylint: disable=wildcard-import +# ruff: noqa from oioioi.default_settings import * TIME_ZONE = 'UTC' diff --git a/oioioi/testrun/controllers.py b/oioioi/testrun/controllers.py index be4ba4346..bc75971bc 100644 --- a/oioioi/testrun/controllers.py +++ b/oioioi/testrun/controllers.py @@ -14,7 +14,7 @@ from oioioi.base.utils import is_ajax from oioioi.base.utils.archive import Archive from oioioi.contests.controllers import submission_template_context -from oioioi.contests.models import ScoreReport, Submission, SubmissionReport +from oioioi.contests.models import ScoreReport, SubmissionReport from oioioi.evalmgr.tasks import extend_after_placeholder from oioioi.problems.utils import can_admin_problem from oioioi.programs.controllers import ( @@ -127,10 +127,7 @@ def adjust_submission_form(self, request, form, problem_instance): # Otherwise one could bypass checks and limits for example by # uploading a zipfile without the '.zip' extension. def validate_file_size(file): - if ( - is_zipfile(file) - and file.size > self.get_testrun_zipped_input_limit() - ): + if is_zipfile(file) and file.size > self.get_testrun_zipped_input_limit(): raise ValidationError(_("Zipped input file size limit exceeded.")) elif file.size > self.get_testrun_input_limit(): raise ValidationError(_("Input file size limit exceeded.")) diff --git a/oioioi/testrun/models.py b/oioioi/testrun/models.py index cf9d30623..033cde5ae 100644 --- a/oioioi/testrun/models.py +++ b/oioioi/testrun/models.py @@ -10,7 +10,7 @@ submission_statuses, ) from oioioi.filetracker.fields import FileField -from oioioi.problems.models import Problem, ProblemInstance +from oioioi.problems.models import ProblemInstance from oioioi.programs.models import ProgramSubmission submission_statuses.register('TESTRUN_OK', _("No error")) diff --git a/oioioi/testspackages/views.py b/oioioi/testspackages/views.py index 4708c1c48..37ce4c6b1 100644 --- a/oioioi/testspackages/views.py +++ b/oioioi/testspackages/views.py @@ -1,9 +1,9 @@ import os from django.core.exceptions import PermissionDenied +from django.http import Http404 from django.shortcuts import get_object_or_404 from django.urls import reverse -from django.http import Http404 from oioioi.base.permissions import enforce_condition, not_anonymous from oioioi.base.utils import request_cached @@ -11,13 +11,13 @@ attachment_registry, attachment_registry_problemset, ) +from oioioi.contests.models import ProblemInstance from oioioi.contests.utils import ( can_enter_contest, contest_exists, is_contest_admin, visible_problem_instances, ) -from oioioi.contests.models import ProblemInstance from oioioi.filetracker.utils import stream_file from oioioi.problems.utils import can_admin_problem from oioioi.testspackages.models import TestsPackage diff --git a/oioioi/timeline/views.py b/oioioi/timeline/views.py index 61cab5799..9e769648d 100644 --- a/oioioi/timeline/views.py +++ b/oioioi/timeline/views.py @@ -90,7 +90,6 @@ def timeline_view(request): if obj_str in tosave: setattr(tosave[obj_str], item['date_field'], parsed_date) else: - setattr(obj, item['date_field'], parsed_date) tosave[obj_str] = obj diff --git a/oioioi/urls.py b/oioioi/urls.py index a8f5920a8..577e71a1e 100644 --- a/oioioi/urls.py +++ b/oioioi/urls.py @@ -2,8 +2,8 @@ from django.conf import settings from django.contrib import admin as django_admin -from django.views import i18n from django.urls import include, re_path +from django.views import i18n from oioioi.base import registration_backend from oioioi.filetracker.views import raw_file_view diff --git a/oioioi/usercontests/admin.py b/oioioi/usercontests/admin.py index e3ffee267..cfbe61a89 100755 --- a/oioioi/usercontests/admin.py +++ b/oioioi/usercontests/admin.py @@ -9,8 +9,6 @@ from oioioi.base.menu import personal_menu_registry from oioioi.base.permissions import make_request_condition from oioioi.contests.admin import ContestAdmin, RoundInline -from oioioi.contests.permissions import can_create_contest -from oioioi.contests.utils import has_any_contest from oioioi.usercontests.forms import UserContestForm from oioioi.usercontests.models import UserContest @@ -50,13 +48,12 @@ def use_usercontest_admin_form(request): class UserRoundInlineFormset(RoundInline.formset): def clean(self): - super(UserRoundInlineFormset, self).clean() if not hasattr(settings, 'USER_CONTEST_TIMEOUT'): return for form in self.forms: - if not 'end_date' in form.cleaned_data.keys(): + if 'end_date' not in form.cleaned_data.keys(): continue if form.cleaned_data['end_date'] is None: raise forms.ValidationError( diff --git a/oioioi/usercontests/tests.py b/oioioi/usercontests/tests.py index 4fb3f8b8a..d5015809a 100644 --- a/oioioi/usercontests/tests.py +++ b/oioioi/usercontests/tests.py @@ -100,7 +100,7 @@ class TestUserContestCreationForm(TestCase): fixtures = ['test_users'] def _get_future_date(self): - date = '2037-04-19' # far in the future and in 32bit timestamp range. + date = '2037-04-19' # far in the future and in 32bit timestamp range. assert datetime.strptime(date, '%Y-%M-%d') > datetime.now() return date diff --git a/oioioi/usergroups/admin.py b/oioioi/usergroups/admin.py index 1c6bc371f..a11ce96e6 100644 --- a/oioioi/usergroups/admin.py +++ b/oioioi/usergroups/admin.py @@ -8,8 +8,8 @@ from oioioi.base import admin from oioioi.base.menu import personal_menu_registry from oioioi.base.permissions import is_superuser +from oioioi.contests.admin import NO_CATEGORY, ContestAdmin from oioioi.usergroups.models import UserGroup, UserGroupRanking -from oioioi.contests.admin import ContestAdmin, NO_CATEGORY def get_user_name_and_login_bounded(self, user): @@ -65,9 +65,7 @@ class UserGroupRankingInline(admin.StackedInline): def formfield_for_foreignkey(self, db_field, request, **kwargs): if db_field.name == 'user_group': - kwargs['queryset'] = UserGroup.objects.filter( - contests=request.contest - ) + kwargs['queryset'] = UserGroup.objects.filter(contests=request.contest) return super(UserGroupRankingInline, self).formfield_for_foreignkey( db_field, request, **kwargs ) diff --git a/oioioi/usergroups/controllers.py b/oioioi/usergroups/controllers.py index df876fd29..31c352bfd 100644 --- a/oioioi/usergroups/controllers.py +++ b/oioioi/usergroups/controllers.py @@ -1,11 +1,10 @@ from django.db.models import Q from django.utils import timezone -from oioioi.rankings.controllers import CONTEST_RANKING_KEY +from oioioi.contests.utils import is_contest_basicadmin, is_contest_observer +from oioioi.rankings.controllers import CONTEST_RANKING_KEY, DefaultRankingController from oioioi.teachers.controllers import TeacherRegistrationController from oioioi.usergroups.models import UserGroup, UserGroupRanking -from oioioi.contests.utils import is_contest_basicadmin, is_contest_observer -from oioioi.rankings.controllers import DefaultRankingController USER_GROUP_RANKING_PREFIX = 'g' diff --git a/oioioi/usergroups/management/commands/remove_user_group_rankings.py b/oioioi/usergroups/management/commands/remove_user_group_rankings.py index 58bd7a008..e0210d25f 100644 --- a/oioioi/usergroups/management/commands/remove_user_group_rankings.py +++ b/oioioi/usergroups/management/commands/remove_user_group_rankings.py @@ -2,9 +2,9 @@ from django.db import transaction from django.utils.translation import gettext as _ -from oioioi.usergroups.models import UserGroupRanking from oioioi.rankings.models import Ranking from oioioi.usergroups.controllers import USER_GROUP_RANKING_PREFIX +from oioioi.usergroups.models import UserGroupRanking class Command(BaseCommand): diff --git a/oioioi/usergroups/models.py b/oioioi/usergroups/models.py index 7dc02d3c4..d3346dbdc 100644 --- a/oioioi/usergroups/models.py +++ b/oioioi/usergroups/models.py @@ -4,7 +4,6 @@ from django.db import models from django.db.models import ProtectedError from django.db.models.signals import post_delete, pre_save - from django.utils.translation import gettext_lazy as _ from oioioi.base.utils import generate_key @@ -14,7 +13,6 @@ check_django_app_dependencies(__name__, ['oioioi.teachers']) - class UserGroup(models.Model): """Group of user which can be moved around contests by teachers""" diff --git a/oioioi/usergroups/tests.py b/oioioi/usergroups/tests.py index 8300e9f1d..42144abe4 100644 --- a/oioioi/usergroups/tests.py +++ b/oioioi/usergroups/tests.py @@ -1,19 +1,18 @@ from django.contrib.auth.models import User +from django.core.management import call_command from django.test import RequestFactory +from django.test.utils import override_settings from django.urls import reverse from django.urls.exceptions import NoReverseMatch -from django.test.utils import override_settings -from django.core.management import call_command - from oioioi.base.tests import TestCase from oioioi.contests.models import Contest from oioioi.contests.tests.utils import make_user_contest_admin from oioioi.participants.models import Participant +from oioioi.rankings.models import Ranking from oioioi.teachers.tests import change_contest_type from oioioi.usergroups import utils from oioioi.usergroups.models import ActionConfig, UserGroup -from oioioi.rankings.models import Ranking class TestAdmin(TestCase): diff --git a/oioioi/workers/management/commands/start_receive_from_workers.py b/oioioi/workers/management/commands/start_receive_from_workers.py index 74f29462f..ecbecf7f7 100644 --- a/oioioi/workers/management/commands/start_receive_from_workers.py +++ b/oioioi/workers/management/commands/start_receive_from_workers.py @@ -1,9 +1,9 @@ import cgi +import http.server import json import logging - -import http.server import socketserver + from django.conf import settings from django.core.management.base import BaseCommand from django.db import transaction diff --git a/oioioi/workers/views.py b/oioioi/workers/views.py index b1012866a..9b0b328cf 100644 --- a/oioioi/workers/views.py +++ b/oioioi/workers/views.py @@ -1,7 +1,6 @@ -import json +import xmlrpc.client from operator import itemgetter # pylint: disable=E0611 -import xmlrpc.client from django.conf import settings from django.http import JsonResponse from django.shortcuts import render @@ -22,8 +21,8 @@ def get_all_names(): return [i['name'] for i in get_info_about_workers()] -def del_worker(l): - for i in l: +def del_worker(workers): + for i in workers: server.forget_worker(i) diff --git a/oioioi/zeus/backends.py b/oioioi/zeus/backends.py index 5d7b2fc92..53d0e68e6 100644 --- a/oioioi/zeus/backends.py +++ b/oioioi/zeus/backends.py @@ -1,15 +1,15 @@ from __future__ import print_function import base64 +import http.client import json import logging import pprint import time - -import http.client import urllib.error import urllib.parse import urllib.request + from django.conf import settings from django.utils.module_loading import import_string diff --git a/oioioi/zeus/controllers.py b/oioioi/zeus/controllers.py index 2e552eb8e..dc0d83c6c 100644 --- a/oioioi/zeus/controllers.py +++ b/oioioi/zeus/controllers.py @@ -1,4 +1,3 @@ -from django.conf import settings from django.utils.translation import gettext_lazy as _ from oioioi.evalmgr.tasks import recipe_placeholder diff --git a/oioioi/zeus/handlers.py b/oioioi/zeus/handlers.py index c105feb52..f46797cca 100644 --- a/oioioi/zeus/handlers.py +++ b/oioioi/zeus/handlers.py @@ -239,9 +239,7 @@ def update_problem_tests_set(env, kind, **kwargs): problem = data.problem env_tests = { - key: value - for key, value in env['tests'].items() - if value['kind'] == kind + key: value for key, value in env['tests'].items() if value['kind'] == kind } test_names = list(env_tests.keys()) diff --git a/oioioi/zeus/tests.py b/oioioi/zeus/tests.py index 256f73862..f3bdbfbb8 100644 --- a/oioioi/zeus/tests.py +++ b/oioioi/zeus/tests.py @@ -1,7 +1,7 @@ import json +import urllib.parse import pytest -import urllib.parse from django.urls import reverse from oioioi.base.tests import TestCase, TestsUtilsMixin @@ -111,7 +111,7 @@ def _get_base_test_info(self, metadata=''): 'metadata': metadata, 'runtime': 100, 'time_limit_ms': 1000, - 'memory_limit_byte': 2 ** 24, + 'memory_limit_byte': 2**24, } def _assert_dict_contains_subset(self, subset, dictionary): @@ -182,7 +182,7 @@ def test_importing(self): 'group': '1', 'max_score': 2, 'exec_time_limit': 1000, - 'exec_memory_limit': 2 ** 14, + 'exec_memory_limit': 2**14, 'zeus_metadata': '1a,1,2', }, tests['1a'], diff --git a/oioioi_cypress/cypress/fixtures/sum.py b/oioioi_cypress/cypress/fixtures/sum.py index 392a942c8..b8dc7af99 100644 --- a/oioioi_cypress/cypress/fixtures/sum.py +++ b/oioioi_cypress/cypress/fixtures/sum.py @@ -1 +1 @@ -print(sum(list(map(int, input().split())))) \ No newline at end of file +print(sum(list(map(int, input().split())))) diff --git a/oioioi_selenium/__init__.py b/oioioi_selenium/__init__.py index 13c49d745..dd66cc073 100644 --- a/oioioi_selenium/__init__.py +++ b/oioioi_selenium/__init__.py @@ -96,9 +96,7 @@ def __new__(mcs, class_name, class_parents, class_attrs): return type.__new__(mcs, class_name, class_parents, new_attrs) -class OIOIOISeleniumTestCaseBase( - unittest.TestCase, metaclass=WrapTestsWithScreenshots -): +class OIOIOISeleniumTestCaseBase(unittest.TestCase, metaclass=WrapTestsWithScreenshots): def setUp(self): self.driver = WebDriver() diff --git a/pyproject.toml b/pyproject.toml index a2c34cd01..a97dbe40e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,3 +26,17 @@ exclude = ''' )/ ''' force-exclude = '((.*)?default_settings.py|(.*)migrations(.*))' + +# Linter +ruff = "^0.265.0" +[tool.ruff] +line-length = 120 +select = [ + "E", # pycodestyle + "F", # pyflakes + "I" # isort +] +src = ["oioioi"] +exclude = [ + "migrations" +] \ No newline at end of file diff --git a/requirements_static.txt b/requirements_static.txt index a2bd3344d..825abcb7a 100644 --- a/requirements_static.txt +++ b/requirements_static.txt @@ -1,4 +1,6 @@ black==22.3 isort==5.6.4 +ruff==0.0.269 elastic-apm python-memcached +pre-commit==3.3.2 diff --git a/rst/gendoc.py b/rst/gendoc.py index e9a603113..9b8b40196 100644 --- a/rst/gendoc.py +++ b/rst/gendoc.py @@ -16,7 +16,8 @@ sections_suff = '../rst/source/sections/' sections_dist = len(sections_suff.split(os.sep)) -entries = [""" +entries = [ + """ .. Autogenerated by the /rst/gendoc.py script @@ -31,7 +32,8 @@ * - Module - Implements -"""] +""" +] missing = [] oioioi_dirname = os.path.dirname(oioioi.__file__) @@ -39,7 +41,7 @@ for root, dirs, files in os.walk(oioioi_dirname): dirs.sort() rel_root = os.path.relpath(root, sections_dirname) - module_name = '.'.join(rel_root.split(os.sep)[sections_dist - 1:]) + module_name = '.'.join(rel_root.split(os.sep)[sections_dist - 1 :]) if "." in module_name or module_name.startswith("_") or not module_name: continue @@ -49,10 +51,7 @@ include_readme = "*README.rst missing*" missing.append(module_name) - entries.append( - f" * - {module_name}\n" - f" - {include_readme}\n" - ) + entries.append(f" * - {module_name}\n" f" - {include_readme}\n") content = ''.join(entries) @@ -60,7 +59,6 @@ print(sys.stderr, "Some README.rst for modules are missing:", missing) - if len(sys.argv) > 1 and (sys.argv[1] == '--verbose' or sys.argv[1] == '-v'): print(content) diff --git a/rst/source/conf.py b/rst/source/conf.py index cc75880b2..07efcb3e3 100644 --- a/rst/source/conf.py +++ b/rst/source/conf.py @@ -18,6 +18,7 @@ # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. import django + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'oioioi.test_settings') django.setup()