Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

checker comments #261

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions pynformatics/model/problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

from pynformatics.model.meta import Base
from pynformatics.utils.run import read_file_unknown_encoding
from pynformatics.utils.json_type import JsonType


class Problem(Base):
Expand All @@ -30,6 +31,8 @@ class Problem(Base):
show_limits = Column(Boolean)
output_only = Column(Boolean)
pr_id = Column(Integer, ForeignKey('moodle.mdl_ejudge_problem.id'))
settings = Column(JsonType)

# ejudge_users = relation('EjudgeUser', backref="moodle.mdl_user", uselist=False)
# ejudge_user = relation('EjudgeUser', backref = backref('moodle.mdl_user'), uselist=False, primaryjoin = "EjudgeUser.user_id == User.id")
def __init__(self, name, timelimit, memorylimit, output_only, content='', review='', description='', analysis='', sample_tests='', sample_tests_html='', pr_id=None):
Expand Down Expand Up @@ -61,7 +64,7 @@ class EjudgeProblemDummy(Base):
short_id = Column(String(100))
ejudgeName = Column('name', String(100))
# runs = relation('Run', backref='runs', uselist=True)

def __init__(self, name, contest_id, problem_id, short_id, ejudge_contest_id):
self.contest_id = contest_id
self.ejudge_contest_id = ejudge_contest_id
Expand All @@ -84,7 +87,7 @@ class EjudgeProblem(Problem):
short_id = Column(String(100))
ejudgeName = Column('name', String(100))
runs = relation('Run', backref='runs', uselist=True)

def __init__(self, name, timelimit, memorylimit, output_only, contest_id, problem_id, short_id, ejudge_contest_id, content='', review='', description='', analysis='', sample_tests='', sample_tests_html=''):
self.name = name
self.content = content
Expand Down Expand Up @@ -119,7 +122,7 @@ def get_test_size(self, test_num):

test_file_name = (prob.tests_dir + prob.test_pat) % int(test_num)
return os.stat(test_file_name).st_size

def get_corr(self, test_num, size=255):
conf = EjudgeContestCfg(number = self.ejudge_contest_id)
prob = conf.getProblem(self.problem_id)
Expand All @@ -138,7 +141,7 @@ def get_corr_size(self, test_num):

corr_file_name = (prob.tests_dir + prob.corr_pat) % int(test_num)
return os.stat(corr_file_name).st_size

def get_checker(self):
conf = EjudgeContestCfg(number = self.ejudge_contest_id)
prob = conf.getProblem(self.problem_id)
Expand All @@ -157,7 +160,7 @@ def get_checker(self):
if find_res:
check_src = open(find_res[0], "r").read()
checker_ext = os.path.splitext(find_res[0])[1]

#if checker not found then try polygon package
downloads_dir = os.path.join(conf.contest_path, "download")
if check_src is None and os.path.exists(downloads_dir):
Expand Down Expand Up @@ -188,7 +191,7 @@ def generateSamples(self):
res = ""
if self.sample_tests != '':
res = "<div class='problem-statement'><div class='sample-tests'><div class='section-title'>Примеры</div>"

for i in self.sample_tests.split(","):
inp = self.get_test(i, 4096)
if inp[-1] == '\n':
Expand All @@ -202,8 +205,8 @@ def generateSamples(self):
res += "</pre></div><div class='output'><div class='title'>Выходные данные</div><pre class='content'>"
res += corr
res += "</pre></div></div>"

res += "</div></div>"

self.sample_tests_html = res
self.sample_tests_html = res
return self.sample_tests
47 changes: 26 additions & 21 deletions pynformatics/model/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class Run(Base):
{'schema':'ejudge'}
)


run_id = Column(Integer, primary_key=True)
size = Column(Integer)
create_time = Column(DateTime)
Expand All @@ -35,7 +35,7 @@ class Run(Base):
status = Column(Integer)
score = Column(Integer)
test_num = Column(Integer)

def __init__(self, run_id, contest_id, size, create_time, user_id, prob_id, lang_id, status, score, test_num):
self.run_id = run_id
self.contest_id = contest_id
Expand Down Expand Up @@ -63,7 +63,7 @@ def get_sources(self):

def get_output_file(self, test_num, tp="o", size=None): #tp: o - output, e - stderr, c - checker
data = self.get_output_archive().getfile("{0:06}.{1}".format(test_num, tp)).decode('ascii')
if size is not None:
if size is not None:
data = data[:size]
return data

Expand All @@ -83,6 +83,8 @@ def parsetests(self): #parse data from xml archive
self.judge_tests_info = {}
self.status_string = None
self.maxtime = None
self.display_checker_comments = self.problem.settings.get('display_checker_comments', False)

if self.xml:
rep = self.xml.getElementsByTagName('testing-report')[0]
self.tests_count = int(rep.getAttribute('run-tests'))
Expand All @@ -105,15 +107,18 @@ def parsetests(self): #parse data from xml archive
real_time = int(real_time)
except ValueError:
real_time = 0
test = {'status': status,
'string_status': get_string_status(status),
'real_time': real_time,

test = {'status': status,
'string_status': get_string_status(status),
'real_time': real_time,
'time': time,
'max_memory_used' : max_memory_used
'max_memory_used' : max_memory_used,
}
if self.display_checker_comments:
test['checker_comment'] = node.getAttribute('checker-comment')

judge_info = {}

for _type in ('input', 'output', 'correct', 'stderr', 'checker'):
lst = node.getElementsByTagName(_type)
if lst and lst[0].firstChild:
Expand All @@ -132,17 +137,17 @@ def parsetests(self): #parse data from xml archive
#print([test['time'] for test in self.tests.values()] + [test['real_time'] for test in self.tests.values()])
self.maxtime = max([test['time'] for test in self.tests.values()] + [test['real_time'] for test in self.tests.values()])
except ValueError:
pass
pass


def get_by(run_id, contest_id):
try:
return DBSession.query(Run).filter(Run.run_id == int(run_id)).filter(Run.contest_id == int(contest_id)).first()
return DBSession.query(Run).filter(Run.run_id == int(run_id)).filter(Run.contest_id == int(contest_id)).first()
except:
return None

@lazy
def _get_compilation_protocol(self):
@lazy
def _get_compilation_protocol(self):
filename = submit_path(protocols_path, self.contest_id, self.run_id)
if filename:
if os.path.isfile(filename):
Expand Down Expand Up @@ -173,20 +178,20 @@ def _get_compilation_protocol(self):
return e
else:
return ''
@lazy
def _get_protocol(self):

@lazy
def _get_protocol(self):
filename = submit_path(protocols_path, self.contest_id, self.run_id)
# return filename
if filename != '':
return get_protocol_from_file(filename)
else:
return '<a></a>'

protocol = property(_get_protocol)
compilation_protocol = property(_get_compilation_protocol)
@lazy

@lazy
def _get_tested_protocol_data(self):
self.xml = xml.dom.minidom.parseString(str(self.protocol))
self.parsetests()
Expand Down
48 changes: 48 additions & 0 deletions pynformatics/utils/json_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import json
from sqlalchemy.ext.mutable import Mutable
from sqlalchemy.types import TypeDecorator, Text


class JsonType(TypeDecorator):
impl = Text

def process_bind_param(self, value, dialect):
if value is None:
return None
return json.dumps(value, separators=(',', ':'))

def process_result_value(self, value, dialect):
if not value:
return None
try:
loaded = json.loads(value)
except json.JSONDecodeError:
loaded = None
return loaded


class MutableDict(Mutable, dict):
@classmethod
def coerce(cls, key, value):
"Convert plain dictionaries to MutableDict."

if not isinstance(value, MutableDict):
if isinstance(value, dict):
return MutableDict(value)

# this call will raise ValueError
return Mutable.coerce(key, value)
else:
return value

def __setitem__(self, key, value):
"Detect dictionary set events and emit change events."

dict.__setitem__(self, key, value)
self.changed()

def __delitem__(self, key):
"Detect dictionary del events and emit change events."

dict.__delitem__(self, key)
self.changed()
28 changes: 16 additions & 12 deletions pynformatics/view/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,25 @@ def get_protocol(request):
run = Run.get_by(run_id = run_id, contest_id = contest_id)
try:
run.tested_protocol
ret = {
'host': run.host,
'display_checker_comments': run.display_checker_comments,
}
if (run.user.statement.filter(Statement.olympiad == 1).filter(Statement.timestop > time.time()).filter(Statement.timestart < time.time()).count() == 0):
res = OrderedDict()
for num in range(1, len(run.tests.keys()) + 1):
res[str(num)] = run.tests[str(num)]
return {"tests": res, "host": run.host}
ret["tests"] = res
return ret
else:
try:
return {"tests":run.tests["1"], "host": run.host}
ret["tests"] = run.tests["1"]
return ret
except KeyError as e:
return {"result" : "error", "message" : e.__str__(), "stack" : traceback.format_exc()}
except Exception as e:
return {"result" : "error", "message" : run.compilation_protocol, "error" : e.__str__(), "stack" : traceback.format_exc(), "protocol": run.protocol}
except Exception as e:
except Exception as e:
return {"result" : "error", "message" : e.__str__(), "stack" : traceback.format_exc(), "protocol": run.protocol}

@view_config(route_name="protocol.get_full", renderer="json")
Expand Down Expand Up @@ -104,16 +110,16 @@ def protocol_get_full(request):
except OSError as e:
prot[test_num]["output"] = judge_info.get("output", "")
prot[test_num]["big_output"] = False


try:
if run.get_output_file_size(int(test_num), tp='c') <= 255:
prot[test_num]["checker_output"] = run.get_output_file(int(test_num), tp='c')
else:
prot[test_num]["checker_output"] = run.get_output_file(int(test_num), tp='c', size=255) + "...\n"
except OSError as e:
prot[test_num]["checker_output"] = judge_info.get("checker", "")

try:
if run.get_output_file_size(int(test_num), tp='e') <= 255:
prot[test_num]["error_output"] = run.get_output_file(int(test_num), tp='e')
Expand All @@ -128,7 +134,7 @@ def protocol_get_full(request):
if "extra" not in prot[test_num]:
prot[test_num]["extra"] = str()
prot[test_num]["extra"] = prot[test_num]["extra"] + "\n Exit code {0}. ".format(judge_info["exit-code"])


for type_ in [("o", "output"), ("c", "checker_output"), ("e", "error_output")]:
file_name = "{0:06d}.{1}".format(int(test_num), type_[0])
Expand All @@ -153,7 +159,7 @@ def protocol_get_test(request):
contest_id = int(request.matchdict['contest_id'])
run_id = int(request.matchdict['run_id'])
run = Run.get_by(run_id = run_id, contest_id = contest_id)
prob = run.problem
prob = run.problem
return prob.get_test(int(request.matchdict['test_num']), prob.get_test_size(int(request.matchdict['test_num'])))

@view_config(route_name="protocol.get_corr", renderer="string")
Expand All @@ -162,15 +168,15 @@ def protocol_get_corr(request):
contest_id = int(request.matchdict['contest_id'])
run_id = int(request.matchdict['run_id'])
run = Run.get_by(run_id = run_id, contest_id = contest_id)
prob = run.problem
prob = run.problem
return prob.get_corr(int(request.matchdict['test_num']), prob.get_corr_size(int(request.matchdict['test_num'])))

@view_config(route_name="protocol.get_outp", renderer="string")
@check_global_role(("teacher", "ejudge_teacher", "admin"))
def protocol_get_outp(request):
contest_id = int(request.matchdict['contest_id'])
run_id = int(request.matchdict['run_id'])
run = Run.get_by(run_id = run_id, contest_id = contest_id)
run = Run.get_by(run_id = run_id, contest_id = contest_id)
return run.get_output_file(int(request.matchdict['test_num']), tp='o')

@view_config(route_name="protocol.get_submit_archive", renderer="string")
Expand Down Expand Up @@ -210,5 +216,3 @@ def get_submit_archive(request):
archive.seek(0)
response = Response(content_type="application/zip", content_disposition='attachment; filename="archive_{0}_{1}.zip"'.format(contest_id, run_id), body=archive.read())
return response