Skip to content

Commit

Permalink
Set oicompare language to user's language (#403)
Browse files Browse the repository at this point in the history
* Set oicompare language to user's language

* Remove debug

* Fix bug

* Allow changing oicompare format

* Change test for oicompare
  • Loading branch information
MasloMaslane authored Sep 23, 2024
1 parent 9d763fb commit b82ae56
Show file tree
Hide file tree
Showing 10 changed files with 189 additions and 4 deletions.
1 change: 1 addition & 0 deletions oioioi/contestexcl/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ def _modify_contestexcl(
('contestlogo', 0, 0, 0, 1),
('programs_config', 0, 0, 0, 1),
('contestcompiler_set', 0, 0, 0, 1000),
('checkerformatforcontest', 0, 0, 0, 1),
)
data = dict()
for (name, total, initial, min_num, max_num) in formsets:
Expand Down
12 changes: 12 additions & 0 deletions oioioi/problems/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from oioioi.evalmgr.tasks import create_environ, delay_environ
from oioioi.problems.models import ProblemStatistics, UserStatistics
from oioioi.problems.utils import can_admin_problem
from oioioi.programs.utils import get_checker_format

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -148,6 +149,17 @@ def judge(self, submission, extra_args=None, is_rejudge=False):
environ = create_environ()
environ['extra_args'] = extra_args or {}
environ['is_rejudge'] = is_rejudge
if hasattr(submission, 'programsubmission'):
user_lang = None
for code, lang in settings.LANGUAGES:
if code == submission.programsubmission.user_language_code:
user_lang = lang.lower()
break
if user_lang:
environ['user_language'] = user_lang
else:
environ['user_language'] = 'english'
environ['checker_format'] = environ['user_language'] + '_' + get_checker_format(submission.problem_instance)
picontroller = submission.problem_instance.controller

picontroller.fill_evaluation_environ(environ, submission)
Expand Down
37 changes: 37 additions & 0 deletions oioioi/programs/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
ProgramsConfig,
ReportActionsConfig,
Test,
CheckerFormatForContest,
CheckerFormatForProblem,
)


Expand Down Expand Up @@ -447,3 +449,38 @@ def queryset(self, request, queryset):
return queryset.filter(condition)
else:
return queryset


class CheckerFormatForContestInline(admin.StackedInline):
model = CheckerFormatForContest
category = _("Advanced")


class CheckerFormatForProblemInline(admin.StackedInline):
model = CheckerFormatForProblem
category = _("Advanced")


class CheckerFormatOverrideContestAdminMixin(object):
"""Adds :class:`~oioioi.programs.models.CheckerFormatForContest` to an admin
panel.
"""
def __init__(self, *args, **kwargs):
super(CheckerFormatOverrideContestAdminMixin, self).__init__(*args, **kwargs)
self.inlines = tuple(self.inlines) + (CheckerFormatForContestInline,)


ContestAdmin.mix_in(CheckerFormatOverrideContestAdminMixin)


class CheckerFormatOverrideProblemAdminMixin(object):
"""Adds :class:`~oioioi.programs.models.CheckerFormatForProblem` to an admin
panel.
"""

def __init__(self, *args, **kwargs):
super(CheckerFormatOverrideProblemAdminMixin, self).__init__(*args, **kwargs)
self.inlines = tuple(self.inlines) + (CheckerFormatForProblemInline,)


ProblemInstanceAdmin.mix_in(CheckerFormatOverrideProblemAdminMixin)
3 changes: 2 additions & 1 deletion oioioi/programs/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from django.template.loader import render_to_string
from django.urls import reverse
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
from django.utils.translation import gettext_lazy as _, get_language_from_request

from oioioi.base.preferences import ensure_preferences_exist_for_user
from oioioi.base.utils.inputs import narrow_input_field
Expand Down Expand Up @@ -529,6 +529,7 @@ def create_submission(
),
),
date=request.timestamp,
user_language_code=get_language_from_request(request),
)

file = form_data['file']
Expand Down
1 change: 1 addition & 0 deletions oioioi/programs/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ def run_tests(env, kind=None, **kwargs):
job['check_output'] = env.get('check_outputs', True)
if env.get('checker'):
job['chk_file'] = env['checker']
job['checker_format'] = env.get('checker_format', 'english_abbreviated')
if env.get('save_outputs'):
job.setdefault('out_file', _make_filename(env, test_name + '.out'))
job['upload_out'] = True
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Generated by Django 4.2.16 on 2024-09-15 21:27

from django.db import migrations, models
import django.db.models.deletion
import oioioi.base.fields


class Migration(migrations.Migration):

dependencies = [
('contests', '0018_contest_show_contest_rules'),
('programs', '0019_add_limits_override'),
]

operations = [
migrations.AddField(
model_name='programsubmission',
name='user_language_code',
field=models.CharField(blank=True, max_length=6, null=True, verbose_name='User language code'),
),
migrations.CreateModel(
name='CheckerFormatForProblem',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('format', oioioi.base.fields.EnumField(max_length=64, verbose_name='format')),
('problem_instance', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='contests.probleminstance', verbose_name='problem instance')),
],
options={
'verbose_name': 'checker format for problem',
'verbose_name_plural': 'checker formats for problems',
'ordering': ('problem_instance',),
'unique_together': {('problem_instance', 'format')},
},
),
migrations.CreateModel(
name='CheckerFormatForContest',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('format', oioioi.base.fields.EnumField(help_text="Format of the checker output for this contest. Abbreviated describes the output difference, while Terse doesn't give any details.", max_length=64, verbose_name='format')),
('contest', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='contests.contest', verbose_name='contest')),
],
options={
'verbose_name': 'checker format for contest',
'verbose_name_plural': 'checker formats for contests',
'ordering': ('contest',),
'unique_together': {('contest', 'format')},
},
),
]
43 changes: 43 additions & 0 deletions oioioi/programs/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@ class ProgramSubmission(Submission):
source_length = models.IntegerField(
verbose_name=_("Source code length"), blank=True, null=True
)
# Stores the language used by the user in the moment of submitting the solution
user_language_code = models.CharField(max_length=6, verbose_name=_("User language code"), blank=True, null=True)

def save(self, *args, **kwargs):
if self.source_file:
Expand Down Expand Up @@ -461,3 +463,44 @@ def check_compilers_config():


check_compilers_config()


CheckerFormat = EnumRegistry()
CheckerFormat.register('terse', _("Terse"))
CheckerFormat.register('abbreviated', _("Abbreviated"))


class CheckerFormatForContest(models.Model):
"""Overrides the default checker's format (abbreviated) for a contest."""

contest = models.OneToOneField(
Contest, verbose_name=_("contest"), on_delete=models.CASCADE
)
format = EnumField(
CheckerFormat,
verbose_name=_("format"),
help_text=_("Format of the checker output for this contest. "
"Abbreviated describes the output difference, while "
"Terse doesn't give any details.")
)

class Meta(object):
verbose_name = _("checker format for contest")
verbose_name_plural = _("checker formats for contests")
ordering = ('contest',)
unique_together = ('contest', 'format')


class CheckerFormatForProblem(models.Model):
"""Overrides the default checker's format (abbreviated) for a problem."""

problem_instance = models.OneToOneField(
ProblemInstance, verbose_name=_("problem instance"), on_delete=models.CASCADE
)
format = EnumField(CheckerFormat, verbose_name=_("format"))

class Meta(object):
verbose_name = _("checker format for problem")
verbose_name_plural = _("checker formats for problems")
ordering = ('problem_instance',)
unique_together = ('problem_instance', 'format')
30 changes: 28 additions & 2 deletions oioioi/programs/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@
LanguageOverrideForTest,
TestReport,
check_compilers_config,
CheckerFormatForContest,
CheckerFormatForProblem,
)
from oioioi.programs.problem_instance_utils import get_allowed_languages_dict
from oioioi.programs.utils import form_field_id_for_langs
from oioioi.programs.utils import form_field_id_for_langs, get_checker_format
from oioioi.programs.views import _testreports_to_generate_outs
from oioioi.sinolpack.models import ExtraConfig
from oioioi.sinolpack.tests import get_test_filename
Expand Down Expand Up @@ -544,7 +546,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
Expand Down Expand Up @@ -1986,3 +1988,27 @@ def test_proper_env_override(self):
self.assertEqual(
env_with_tests['tests']['1a']['exec_mem_limit'], tests[1].memory_limit
)


class TestOICompare(TestCase):
fixtures = ['test_contest', 'test_problem_instance', 'test_full_package']

def test_format(self):
contest = Contest.objects.get()
pi = ProblemInstance.objects.get()
for format_contest, format_problem, expected in [
(None, None, 'abbreviated'),
('terse', None, 'terse'),
('terse', 'abbreviated', 'abbreviated'),
(None, 'terse', 'terse'),
]:
CheckerFormatForContest.objects.all().delete()
CheckerFormatForProblem.objects.all().delete()
if format_problem is not None:
CheckerFormatForProblem.objects.create(
problem_instance=pi, format=format_problem
)
if format_contest is not None:
CheckerFormatForContest.objects.create(contest=contest, format=format_contest)

self.assertEqual(get_checker_format(pi), expected)
15 changes: 15 additions & 0 deletions oioioi/programs/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
ModelProgramSubmission,
ProgramSubmission,
ReportActionsConfig,
CheckerFormatForContest,
CheckerFormatForProblem,
)


Expand Down Expand Up @@ -215,3 +217,16 @@ def get_submittable_languages():
for _, lang_config in submittable_languages.items():
lang_config.setdefault('type', 'main')
return submittable_languages


def get_checker_format(problem_instance):
try:
return CheckerFormatForProblem.objects.get(problem_instance=problem_instance).format
except CheckerFormatForProblem.DoesNotExist:
if problem_instance.contest:
try:
return CheckerFormatForContest.objects.get(contest=problem_instance.contest).format
except CheckerFormatForContest.DoesNotExist:
return getattr(settings, 'DEFAULT_CHECKER_FORMAT', 'abbreviated')
else:
return getattr(settings, 'DEFAULT_CHECKER_FORMAT', 'abbreviated')
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# These dependencies need to be installed from external sources,
# therefore they must be listed here. Moreover, they cannot be listed in
# setup.py, as pip is not able to install them.
http://github.com/sio2project/sioworkers/archive/refs/tags/v1.5.2.tar.gz
http://github.com/sio2project/sioworkers/archive/refs/tags/v1.5.3.tar.gz

-e .

0 comments on commit b82ae56

Please sign in to comment.