NDOJ/judge/models/problem_data.py

126 lines
6.1 KiB
Python
Raw Normal View History

2020-01-21 06:35:58 +00:00
import errno
import os
2021-06-01 20:34:42 +00:00
from zipfile import BadZipFile, ZipFile
2020-01-21 06:35:58 +00:00
2020-01-24 02:32:46 +00:00
from django.core.validators import FileExtensionValidator
2021-06-01 20:34:42 +00:00
from django.core.cache import cache
2020-01-21 06:35:58 +00:00
from django.db import models
from django.utils.translation import gettext_lazy as _
2021-06-01 20:34:42 +00:00
from judge.utils.problem_data import ProblemDataStorage, get_file_cachekey
2020-01-21 06:35:58 +00:00
__all__ = ['problem_data_storage', 'problem_directory_file', 'ProblemData', 'ProblemTestCase', 'CHECKERS']
problem_data_storage = ProblemDataStorage()
def _problem_directory_file(code, filename):
return os.path.join(code, os.path.basename(filename))
def problem_directory_file(data, filename):
return _problem_directory_file(data.problem.code, filename)
CHECKERS = (
('standard', _('Standard')),
('floats', _('Floats')),
('floatsabs', _('Floats (absolute)')),
('floatsrel', _('Floats (relative)')),
('rstripped', _('Non-trailing spaces')),
('sorted', _('Unordered')),
('identical', _('Byte identical')),
('linecount', _('Line-by-line')),
2020-03-18 02:41:09 +00:00
('custom', _('Custom checker (PY)')),
('customval', _('Custom validator (CPP)')),
2020-01-21 06:35:58 +00:00
)
class ProblemData(models.Model):
problem = models.OneToOneField('Problem', verbose_name=_('problem'), related_name='data_files',
on_delete=models.CASCADE)
zipfile = models.FileField(verbose_name=_('data zip file'), storage=problem_data_storage, null=True, blank=True,
upload_to=problem_directory_file)
generator = models.FileField(verbose_name=_('generator file'), storage=problem_data_storage, null=True, blank=True,
upload_to=problem_directory_file)
output_prefix = models.IntegerField(verbose_name=_('output prefix length'), blank=True, null=True)
output_limit = models.IntegerField(verbose_name=_('output limit length'), blank=True, null=True)
feedback = models.TextField(verbose_name=_('init.yml generation feedback'), blank=True)
checker = models.CharField(max_length=10, verbose_name=_('checker'), choices=CHECKERS, blank=True)
checker_args = models.TextField(verbose_name=_('checker arguments'), blank=True,
help_text=_('checker arguments as a JSON object'))
2020-01-24 02:39:19 +00:00
custom_checker = models.FileField(verbose_name=_('custom checker file'),
storage=problem_data_storage,
null=True,
blank=True,
2020-01-24 02:32:46 +00:00
upload_to=problem_directory_file,
validators=[FileExtensionValidator(allowed_extensions=['py'])])
custom_validator = models.FileField(verbose_name=_('custom validator file'),
storage=problem_data_storage,
null=True,
blank=True,
upload_to=problem_directory_file,
validators=[FileExtensionValidator(allowed_extensions=['cpp'])])
2020-01-21 06:35:58 +00:00
__original_zipfile = None
def __init__(self, *args, **kwargs):
super(ProblemData, self).__init__(*args, **kwargs)
self.__original_zipfile = self.zipfile
def save(self, *args, **kwargs):
2021-06-01 20:34:42 +00:00
if self.zipfile != self.__original_zipfile and self.__original_zipfile:
# Delete caches
try:
files = ZipFile(self.__original_zipfile.path).namelist()
for file in files:
cache_key = 'problem_archive:%s:%s' % (self.problem.code, get_file_cachekey(file))
cache.delete(cache_key)
except BadZipFile:
pass
2020-01-21 06:35:58 +00:00
self.__original_zipfile.delete(save=False)
return super(ProblemData, self).save(*args, **kwargs)
def has_yml(self):
return problem_data_storage.exists('%s/init.yml' % self.problem.code)
def _update_code(self, original, new):
try:
problem_data_storage.rename(original, new)
except OSError as e:
if e.errno != errno.ENOENT:
raise
if self.zipfile:
self.zipfile.name = _problem_directory_file(new, self.zipfile.name)
if self.generator:
self.generator.name = _problem_directory_file(new, self.generator.name)
2020-01-24 02:32:46 +00:00
if self.custom_checker:
self.custom_checker.name = _problem_directory_file(new, self.custom_checker.name)
if self.custom_checker:
self.custom_checker.name = _problem_directory_file(new, self.custom_checker.name)
if self.custom_validator:
self.custom_validator.name = _problem_directory_file(new, self.custom_validator.name)
2020-01-21 06:35:58 +00:00
self.save()
_update_code.alters_data = True
class ProblemTestCase(models.Model):
dataset = models.ForeignKey('Problem', verbose_name=_('problem data set'), related_name='cases',
on_delete=models.CASCADE)
order = models.IntegerField(verbose_name=_('case position'))
type = models.CharField(max_length=1, verbose_name=_('case type'),
choices=(('C', _('Normal case')),
('S', _('Batch start')),
('E', _('Batch end'))),
default='C')
input_file = models.CharField(max_length=100, verbose_name=_('input file name'), blank=True)
output_file = models.CharField(max_length=100, verbose_name=_('output file name'), blank=True)
generator_args = models.TextField(verbose_name=_('generator arguments'), blank=True)
points = models.IntegerField(verbose_name=_('point value'), blank=True, null=True)
is_pretest = models.BooleanField(verbose_name=_('case is pretest?'))
output_prefix = models.IntegerField(verbose_name=_('output prefix length'), blank=True, null=True)
output_limit = models.IntegerField(verbose_name=_('output limit length'), blank=True, null=True)
checker = models.CharField(max_length=10, verbose_name=_('checker'), choices=CHECKERS, blank=True)
checker_args = models.TextField(verbose_name=_('checker arguments'), blank=True,
help_text=_('checker arguments as a JSON object'))