def post(self, task_id): fallback_page = self.url("task", task_id, "attachments", "add") task = self.safe_get_item(Task, task_id) attachment = self.request.files["attachment"][0] task_name = task.name self.sql_session.close() try: digest = self.service.file_cacher.put_file_content( attachment["body"], "Task attachment for %s" % task_name) except Exception as error: self.service.add_notification(make_datetime(), "Attachment storage failed", repr(error)) self.redirect(fallback_page) return # TODO verify that there's no other Attachment with that filename # otherwise we'd trigger an IntegrityError for constraint violation self.sql_session = Session() task = self.safe_get_item(Task, task_id) attachment = Attachment(attachment["filename"], digest, task=task) self.sql_session.add(attachment) if self.try_commit(): self.redirect(self.url("task", task_id)) else: self.redirect(fallback_page)
def put_attachments(self, args): """ Create Attachment objects and put them in the given args. """ args["attachments"] = [] attachment_paths = self.processor.get_attachments() for path in attachment_paths: base_name = os.path.basename(path) description = "Attachment %s for task %s" % \ (base_name, self.short_name) digest = self.file_cacher.put_file_from_path(path, description) args["attachments"] += [Attachment(base_name, digest)]
def add_testcases_dir(folder): if os.path.isdir(folder): for filename in sorted(os.listdir(folder)): nombre, ext = os.path.splitext(filename) if ext == ".in": input_digest = self.file_cacher.put_file_from_path( os.path.join(folder, filename), "Input %s for task %s" % (nombre, task.name)) output_digest = self.file_cacher.put_file_from_path( os.path.join(folder, nombre + ".dat"), "Output %s for task %s" % (nombre, task.name)) args["testcases"] += [ Testcase(nombre, False, input_digest, output_digest) ] if args["task_type"] == "OutputOnly": task.attachments += [ Attachment(filename, input_digest) ]
def get_task(self, name): """See docstring in class Loader. """ try: num = self.tasks_order[name] # Here we expose an undocumented behavior, so that cmsMake can # import a task even without the whole contest; this is not to # be relied upon in general except AttributeError: num = 1 task_path = os.path.join(self.path, name) # We first look for the yaml file inside the task folder, # and eventually fallback to a yaml file in its parent folder. try: conf = yaml.safe_load( io.open(os.path.join(task_path, "task.yaml"), "rt", encoding="utf-8")) except IOError: conf = yaml.safe_load( io.open(os.path.join(self.path, name + ".yaml"), "rt", encoding="utf-8")) logger.info("Loading parameters for task %s." % name) # Here we update the time of the last import touch(os.path.join(task_path, ".itime")) # If this file is not deleted, then the import failed touch(os.path.join(task_path, ".import_error")) args = {} args["num"] = num load(conf, args, ["name", "nome_breve"]) load(conf, args, ["title", "nome"]) assert name == args["name"] if args["name"] == args["title"]: logger.warning("Short name equals long name (title). " "Please check.") primary_language = load(conf, None, "primary_language") if primary_language is None: primary_language = 'it' paths = [os.path.join(task_path, "statement", "statement.pdf"), os.path.join(task_path, "testo", "testo.pdf")] for path in paths: if os.path.exists(path): digest = self.file_cacher.put_file_from_path( path, "Statement for task %s (lang: %s)" % (name, primary_language)) break else: logger.critical("Couldn't find any task statement, aborting...") sys.exit(1) args["statements"] = [Statement(primary_language, digest)] args["primary_statements"] = '["%s"]' % (primary_language) args["attachments"] = [] # FIXME Use auxiliary args["submission_format"] = [ SubmissionFormatElement("%s.%%l" % name)] # Use the new token settings format if detected. if "token_mode" in conf: load(conf, args, "token_mode") load(conf, args, "token_max_number") load(conf, args, "token_min_interval", conv=make_timedelta) load(conf, args, "token_gen_initial") load(conf, args, "token_gen_number") load(conf, args, "token_gen_interval", conv=make_timedelta) load(conf, args, "token_gen_max") # Otherwise fall back on the old one. else: logger.warning( "%s.yaml uses a deprecated format for token settings which " "will soon stop being supported, you're advised to update it.", name) # Determine the mode. if conf.get("token_initial", None) is None: args["token_mode"] = "disabled" elif conf.get("token_gen_number", 0) > 0 and \ conf.get("token_gen_time", 0) == 0: args["token_mode"] = "infinite" else: args["token_mode"] = "finite" # Set the old default values. args["token_gen_initial"] = 0 args["token_gen_number"] = 0 args["token_gen_interval"] = timedelta() # Copy the parameters to their new names. load(conf, args, "token_total", "token_max_number") load(conf, args, "token_min_interval", conv=make_timedelta) load(conf, args, "token_initial", "token_gen_initial") load(conf, args, "token_gen_number") load(conf, args, "token_gen_time", "token_gen_interval", conv=make_timedelta) load(conf, args, "token_max", "token_gen_max") # Remove some corner cases. if args["token_gen_initial"] is None: args["token_gen_initial"] = 0 if args["token_gen_interval"].total_seconds() == 0: args["token_gen_interval"] = timedelta(minutes=1) load(conf, args, "max_submission_number") load(conf, args, "max_user_test_number") load(conf, args, "min_submission_interval", conv=make_timedelta) load(conf, args, "min_user_test_interval", conv=make_timedelta) # Attachments args["attachments"] = [] if os.path.exists(os.path.join(task_path, "att")): for filename in os.listdir(os.path.join(task_path, "att")): digest = self.file_cacher.put_file_from_path( os.path.join(task_path, "att", filename), "Attachment %s for task %s" % (filename, name)) args["attachments"] += [Attachment(filename, digest)] task = Task(**args) args = {} args["task"] = task args["description"] = conf.get("version", "Default") args["autojudge"] = False load(conf, args, ["time_limit", "timeout"], conv=float) load(conf, args, ["memory_limit", "memlimit"]) # Builds the parameters that depend on the task type args["managers"] = [] infile_param = conf.get("infile", "input.txt") outfile_param = conf.get("outfile", "output.txt") # If there is sol/grader.%l for some language %l, then, # presuming that the task type is Batch, we retrieve graders # in the form sol/grader.%l graders = False for lang in LANGUAGES: if os.path.exists(os.path.join( task_path, "sol", "grader.%s" % lang)): graders = True break if graders: # Read grader for each language for lang in LANGUAGES: grader_filename = os.path.join( task_path, "sol", "grader.%s" % lang) if os.path.exists(grader_filename): digest = self.file_cacher.put_file_from_path( grader_filename, "Grader for task %s and language %s" % (name, lang)) args["managers"] += [ Manager("grader.%s" % lang, digest)] else: logger.warning("Grader for language %s not found " % lang) # Read managers with other known file extensions for other_filename in os.listdir(os.path.join(task_path, "sol")): if other_filename.endswith('.h') or \ other_filename.endswith('lib.pas'): digest = self.file_cacher.put_file_from_path( os.path.join(task_path, "sol", other_filename), "Manager %s for task %s" % (other_filename, name)) args["managers"] += [ Manager(other_filename, digest)] compilation_param = "grader" else: compilation_param = "alone" # If there is check/checker (or equivalent), then, presuming # that the task type is Batch or OutputOnly, we retrieve the # comparator paths = [os.path.join(task_path, "check", "checker"), os.path.join(task_path, "cor", "correttore")] for path in paths: if os.path.exists(path): digest = self.file_cacher.put_file_from_path( path, "Manager for task %s" % name) args["managers"] += [ Manager("checker", digest)] evaluation_param = "comparator" break else: evaluation_param = "diff" # Detect subtasks by checking GEN gen_filename = os.path.join(task_path, 'gen', 'GEN') try: with io.open(gen_filename, "rt", encoding="utf-8") as gen_file: subtasks = [] testcases = 0 points = None for line in gen_file: line = line.strip() splitted = line.split('#', 1) if len(splitted) == 1: # This line represents a testcase, otherwise it's # just a blank if splitted[0] != '': testcases += 1 else: testcase, comment = splitted testcase_detected = False subtask_detected = False if testcase.strip() != '': testcase_detected = True comment = comment.strip() if comment.startswith('ST:'): subtask_detected = True if testcase_detected and subtask_detected: raise Exception("No testcase and subtask in the" " same line allowed") # This line represents a testcase and contains a # comment, but the comment doesn't start a new # subtask if testcase_detected: testcases += 1 # This line starts a new subtask if subtask_detected: # Close the previous subtask if points is None: assert(testcases == 0) else: subtasks.append([points, testcases]) # Open the new one testcases = 0 points = int(comment[3:].strip()) # Close last subtask (if no subtasks were defined, just # fallback to Sum) if points is None: args["score_type"] = "Sum" total_value = float(conf.get("total_value", 100.0)) input_value = 0.0 n_input = testcases if n_input != 0: input_value = total_value / n_input args["score_type_parameters"] = "%s" % input_value else: subtasks.append([points, testcases]) assert(100 == sum([int(st[0]) for st in subtasks])) n_input = sum([int(st[1]) for st in subtasks]) args["score_type"] = "GroupMin" args["score_type_parameters"] = "%s" % subtasks if "n_input" in conf: assert int(conf['n_input']) == n_input # If gen/GEN doesn't exist, just fallback to Sum except IOError: args["score_type"] = "Sum" total_value = float(conf.get("total_value", 100.0)) input_value = 0.0 n_input = int(conf['n_input']) if n_input != 0: input_value = total_value / n_input args["score_type_parameters"] = "%s" % input_value # If output_only is set, then the task type is OutputOnly if conf.get('output_only', False): args["task_type"] = "OutputOnly" args["time_limit"] = None args["memory_limit"] = None args["task_type_parameters"] = '["%s"]' % evaluation_param task.submission_format = [ SubmissionFormatElement("output_%03d.txt" % i) for i in xrange(n_input)] # If there is check/manager (or equivalent), then the task # type is Communication else: paths = [os.path.join(task_path, "check", "manager"), os.path.join(task_path, "cor", "manager")] for path in paths: if os.path.exists(path): args["task_type"] = "Communication" args["task_type_parameters"] = '[]' digest = self.file_cacher.put_file_from_path( path, "Manager for task %s" % name) args["managers"] += [ Manager("manager", digest)] for lang in LANGUAGES: stub_name = os.path.join( task_path, "sol", "stub.%s" % lang) if os.path.exists(stub_name): digest = self.file_cacher.put_file_from_path( stub_name, "Stub for task %s and language %s" % (name, lang)) args["managers"] += [ Manager("stub.%s" % lang, digest)] else: logger.warning("Stub for language %s not " "found." % lang) break # Otherwise, the task type is Batch else: args["task_type"] = "Batch" args["task_type_parameters"] = \ '["%s", ["%s", "%s"], "%s"]' % \ (compilation_param, infile_param, outfile_param, evaluation_param) args["testcases"] = [] for i in xrange(n_input): input_digest = self.file_cacher.put_file_from_path( os.path.join(task_path, "input", "input%d.txt" % i), "Input %d for task %s" % (i, name)) output_digest = self.file_cacher.put_file_from_path( os.path.join(task_path, "output", "output%d.txt" % i), "Output %d for task %s" % (i, name)) args["testcases"] += [ Testcase("%03d" % i, False, input_digest, output_digest)] if args["task_type"] == "OutputOnly": task.attachments += [ Attachment("input_%03d.txt" % i, input_digest)] public_testcases = load(conf, None, ["public_testcases", "risultati"], conv=lambda x: "" if x is None else x) if public_testcases != "": for x in public_testcases.split(","): args["testcases"][int(x.strip())].public = True dataset = Dataset(**args) task.active_dataset = dataset # Import was successful os.remove(os.path.join(task_path, ".import_error")) logger.info("Task parameters loaded.") return task
def get_task(self, get_statement=True): """See docstring in class Loader. """ json_src = os.path.join(self.path, 'problem.json') if not os.path.exists(json_src): logger.error('No task found.') with open(json_src) as json_file: data = json.load(json_file) name = data['code'] logger.info("Loading parameters for task %s.", name) args = {} # Here we update the time of the last import. touch(os.path.join(self.path, ".itime")) # If this file is not deleted, then the import failed. touch(os.path.join(self.path, ".import_error")) args["name"] = name args["title"] = data['name'] # Statements if get_statement: statements_dir = os.path.join(self.path, 'statements') if os.path.exists(statements_dir): statements = [ filename for filename in os.listdir(statements_dir) if filename[-4:] == ".pdf" ] if len(statements) > 0: args['statements'] = dict() logger.info('Statements found') for statement in statements: language = statement[:-4] if language == "en_US": args["primary_statements"] = '["en_US"]' digest = self.file_cacher.put_file_from_path( os.path.join(statements_dir, statement), "Statement for task %s (lang: %s)" % (name, language)) args['statements'][language] = Statement(language, digest) # Attachments args["attachments"] = dict() attachments_dir = os.path.join(self.path, 'attachments') if os.path.exists(attachments_dir): logger.info("Attachments found") for filename in os.listdir(attachments_dir): digest = self.file_cacher.put_file_from_path( os.path.join(attachments_dir, filename), "Attachment %s for task %s" % (filename, name)) args["attachments"][filename] = Attachment(filename, digest) data["task_type"] = data["task_type"][0].upper( ) + data["task_type"][1:] # Setting the submission format # Obtaining testcases' codename testcases_dir = os.path.join(self.path, 'tests') if not os.path.exists(testcases_dir): logger.warning('Testcase folder was not found') testcase_codenames = [] else: testcase_codenames = sorted([ filename[:-3] for filename in os.listdir(testcases_dir) if filename[-3:] == '.in' ]) if data["task_type"] == 'OutputOnly': args["submission_format"] = list() for codename in testcase_codenames: args["submission_format"].append( SubmissionFormatElement("%s.out" % codename)) elif data["task_type"] == 'Notice': args["submission_format"] = list() else: args["submission_format"] = [ SubmissionFormatElement("%s.%%l" % name) ] # These options cannot be configured in the CPS format. # Uncomment the following to set specific values for them. # args['max_submission_number'] = 100 # args['max_user_test_number'] = 100 # args['min_submission_interval'] = make_timedelta(60) # args['min_user_test_interval'] = make_timedelta(60) # args['max_user_test_number'] = 10 # args['min_user_test_interval'] = make_timedelta(60) # args['token_mode'] = 'infinite' # args['token_max_number'] = 100 # args['token_min_interval'] = make_timedelta(60) # args['token_gen_initial'] = 1 # args['token_gen_number'] = 1 # args['token_gen_interval'] = make_timedelta(1800) # args['token_gen_max'] = 2 if "score_precision" in data: args['score_precision'] = int(data["score_precision"]) else: args['score_precision'] = 2 args['max_submission_number'] = 50 args['max_user_test_number'] = 50 if data["task_type"] == 'OutputOnly': args['max_submission_number'] = 100 args['max_user_test_number'] = 100 args['min_submission_interval'] = make_timedelta(60) args['min_user_test_interval'] = make_timedelta(60) task = Task(**args) args = dict() args["task"] = task args["description"] = "Default" args["autojudge"] = True if data['task_type'] != 'OutputOnly' and data['task_type'] != 'Notice': args["time_limit"] = float(data['time_limit']) args["memory_limit"] = int(data['memory_limit']) args["managers"] = {} # Checker checker_dir = os.path.join(self.path, "checker") checker_src = os.path.join(checker_dir, "checker.cpp") if os.path.exists(checker_src): logger.info("Checker found, compiling") checker_exe = os.path.join(checker_dir, "checker") os.system("g++ -x c++ -std=gnu++14 -O2 -static -o %s %s" % (checker_exe, checker_src)) digest = self.file_cacher.put_file_from_path( checker_exe, "Manager for task %s" % name) args["managers"]['checker'] = Manager("checker", digest) evaluation_param = "comparator" else: logger.info("Checker not found, using diff if neccessary") evaluation_param = "diff" args["task_type"] = data['task_type'] if data['task_type'] != 'Notice': args["task_type"] += '2017' args["task_type_parameters"] = \ self._get_task_type_parameters(data, data['task_type'], evaluation_param) # Graders graders_dir = os.path.join(self.path, 'graders') if data['task_type'] == 'TwoSteps': pas_manager = name + 'lib.pas' pas_manager_path = os.path.join(graders_dir, pas_manager) if not os.path.exists(pas_manager_path): digest = self.file_cacher.put_file_content( ''.encode('utf-8'), 'Pascal manager for task %s' % name) args["managers"][pas_manager] = Manager(pas_manager, digest) if not os.path.exists(graders_dir): logger.warning('Grader folder was not found') graders_list = [] else: graders_list = \ [filename for filename in os.listdir(graders_dir) if filename != 'manager.cpp'] for grader_name in graders_list: grader_src = os.path.join(graders_dir, grader_name) digest = self.file_cacher.put_file_from_path( grader_src, "Manager for task %s" % name) args["managers"][grader_name] = Manager(grader_name, digest) # Manager manager_src = os.path.join(graders_dir, 'manager.cpp') if os.path.exists(manager_src): logger.info("Manager found, compiling") manager_exe = os.path.join(graders_dir, "manager") os.system("cat %s | \ g++ -x c++ -O2 -static -o %s -" % (manager_src, manager_exe)) digest = self.file_cacher.put_file_from_path( manager_exe, "Manager for task %s" % name) args["managers"]["manager"] = Manager("manager", digest) # Testcases args["testcases"] = {} for codename in testcase_codenames: infile = os.path.join(testcases_dir, "%s.in" % codename) outfile = os.path.join(testcases_dir, "%s.out" % codename) if not os.path.exists(outfile): logger.critical( 'Could not file the output file for testcase %s' % codename) logger.critical('Aborting...') return input_digest = self.file_cacher.put_file_from_path( infile, "Input %s for task %s" % (codename, name)) output_digest = self.file_cacher.put_file_from_path( outfile, "Output %s for task %s" % (codename, name)) testcase = Testcase(codename, True, input_digest, output_digest) args["testcases"][codename] = testcase # Score Type subtasks_dir = os.path.join(self.path, 'subtasks') if not os.path.exists(subtasks_dir): logger.warning('Subtask folder was not found') subtasks = [] else: subtasks = sorted(os.listdir(subtasks_dir)) if len(subtasks) == 0: number_tests = max(len(testcase_codenames), 1) args["score_type"] = "Sum" args["score_type_parameters"] = str(100 / number_tests) else: args["score_type"] = "GroupMinWithMaxScore" parsed_data = [ 100, ] subtask_no = -1 add_optional_name = False for subtask in subtasks: subtask_no += 1 with open(os.path.join(subtasks_dir, subtask)) as subtask_json: subtask_data = json.load(subtask_json) score = int(subtask_data["score"]) testcases = "|".join( re.escape(testcase) for testcase in subtask_data["testcases"]) optional_name = "Subtask %d" % subtask_no if subtask_no == 0 and score == 0: add_optional_name = True optional_name = "Samples" if add_optional_name: parsed_data.append([score, testcases, optional_name]) else: parsed_data.append([score, testcases]) args["score_type_parameters"] = json.dumps(parsed_data) args["description"] = datetime.utcnow()\ .strftime("%Y-%m-%d %H:%M:%S %Z%z") dataset = Dataset(**args) task.active_dataset = dataset os.remove(os.path.join(self.path, ".import_error")) logger.info("Task parameters loaded.") return task
def get_task(self, get_statement=True): """See docstring in class TaskLoader.""" name = os.path.split(self.path)[1] if (not os.path.exists(os.path.join(self.path, "task.yaml"))) and \ (not os.path.exists(os.path.join(self.path, "..", name + ".yaml"))): logger.critical("File missing: \"task.yaml\"") return None # We first look for the yaml file inside the task folder, # and eventually fallback to a yaml file in its parent folder. try: conf = load_yaml_from_path(os.path.join(self.path, "task.yaml")) except OSError as err: try: deprecated_path = os.path.join(self.path, "..", name + ".yaml") conf = load_yaml_from_path(deprecated_path) logger.warning("You're using a deprecated location for the " "task.yaml file. You're advised to move %s to " "%s.", deprecated_path, os.path.join(self.path, "task.yaml")) except OSError: # Since both task.yaml and the (deprecated) "../taskname.yaml" # are missing, we will only warn the user that task.yaml is # missing (to avoid encouraging the use of the deprecated one) raise err # Here we update the time of the last import touch(os.path.join(self.path, ".itime")) # If this file is not deleted, then the import failed touch(os.path.join(self.path, ".import_error")) args = {} load(conf, args, ["name", "nome_breve"]) load(conf, args, ["title", "nome"]) if name != args["name"]: logger.info("The task name (%s) and the directory name (%s) are " "different. The former will be used.", args["name"], name) if args["name"] == args["title"]: logger.warning("Short name equals long name (title). " "Please check.") name = args["name"] logger.info("Loading parameters for task %s.", name) if get_statement: primary_language = load(conf, None, "primary_language") if primary_language is None: primary_language = 'it' paths = [os.path.join(self.path, "statement", "statement.pdf"), os.path.join(self.path, "testo", "testo.pdf")] for path in paths: if os.path.exists(path): digest = self.file_cacher.put_file_from_path( path, "Statement for task %s (lang: %s)" % (name, primary_language)) break else: logger.critical("Couldn't find any task statement, aborting.") sys.exit(1) args["statements"] = { primary_language: Statement(primary_language, digest) } args["primary_statements"] = [primary_language] args["submission_format"] = ["%s.%%l" % name] # Import the feedback level when explicitly set to full # (default behaviour is restricted) if conf.get("feedback_level", None) == FEEDBACK_LEVEL_FULL: args["feedback_level"] = FEEDBACK_LEVEL_FULL elif conf.get("feedback_level", None) == FEEDBACK_LEVEL_RESTRICTED: args["feedback_level"] = FEEDBACK_LEVEL_RESTRICTED if conf.get("score_mode", None) == SCORE_MODE_MAX: args["score_mode"] = SCORE_MODE_MAX elif conf.get("score_mode", None) == SCORE_MODE_MAX_SUBTASK: args["score_mode"] = SCORE_MODE_MAX_SUBTASK elif conf.get("score_mode", None) == SCORE_MODE_MAX_TOKENED_LAST: args["score_mode"] = SCORE_MODE_MAX_TOKENED_LAST # Use the new token settings format if detected. if "token_mode" in conf: load(conf, args, "token_mode") load(conf, args, "token_max_number") load(conf, args, "token_min_interval", conv=make_timedelta) load(conf, args, "token_gen_initial") load(conf, args, "token_gen_number") load(conf, args, "token_gen_interval", conv=make_timedelta) load(conf, args, "token_gen_max") # Otherwise fall back on the old one. else: logger.warning( "task.yaml uses a deprecated format for token settings which " "will soon stop being supported, you're advised to update it.") # Determine the mode. if conf.get("token_initial", None) is None: args["token_mode"] = TOKEN_MODE_DISABLED elif conf.get("token_gen_number", 0) > 0 and \ conf.get("token_gen_time", 0) == 0: args["token_mode"] = TOKEN_MODE_INFINITE else: args["token_mode"] = TOKEN_MODE_FINITE # Set the old default values. args["token_gen_initial"] = 0 args["token_gen_number"] = 0 args["token_gen_interval"] = timedelta() # Copy the parameters to their new names. load(conf, args, "token_total", "token_max_number") load(conf, args, "token_min_interval", conv=make_timedelta) load(conf, args, "token_initial", "token_gen_initial") load(conf, args, "token_gen_number") load(conf, args, "token_gen_time", "token_gen_interval", conv=make_timedelta) load(conf, args, "token_max", "token_gen_max") # Remove some corner cases. if args["token_gen_initial"] is None: args["token_gen_initial"] = 0 if args["token_gen_interval"].total_seconds() == 0: args["token_gen_interval"] = timedelta(minutes=1) load(conf, args, "max_submission_number") load(conf, args, "max_user_test_number") load(conf, args, "min_submission_interval", conv=make_timedelta) load(conf, args, "min_user_test_interval", conv=make_timedelta) # Attachments args["attachments"] = dict() if os.path.exists(os.path.join(self.path, "att")): for filename in os.listdir(os.path.join(self.path, "att")): digest = self.file_cacher.put_file_from_path( os.path.join(self.path, "att", filename), "Attachment %s for task %s" % (filename, name)) args["attachments"][filename] = Attachment(filename, digest) task = Task(**args) args = {} args["task"] = task args["description"] = conf.get("version", "Default") args["autojudge"] = False load(conf, args, ["time_limit", "timeout"], conv=float) # The Italian YAML format specifies memory limits in MiB. load(conf, args, ["memory_limit", "memlimit"], conv=lambda mb: mb * 1024 * 1024) # Builds the parameters that depend on the task type args["managers"] = [] infile_param = conf.get("infile", "input.txt") outfile_param = conf.get("outfile", "output.txt") # If there is sol/grader.%l for some language %l, then, # presuming that the task type is Batch, we retrieve graders # in the form sol/grader.%l graders = False for lang in LANGUAGES: if os.path.exists(os.path.join( self.path, "sol", "grader%s" % lang.source_extension)): graders = True break if graders: # Read grader for each language for lang in LANGUAGES: extension = lang.source_extension grader_filename = os.path.join( self.path, "sol", "grader%s" % extension) if os.path.exists(grader_filename): digest = self.file_cacher.put_file_from_path( grader_filename, "Grader for task %s and language %s" % (task.name, lang)) args["managers"] += [ Manager("grader%s" % extension, digest)] else: logger.warning("Grader for language %s not found ", lang) # Read managers with other known file extensions for other_filename in os.listdir(os.path.join(self.path, "sol")): if any(other_filename.endswith(header) for header in HEADER_EXTS): digest = self.file_cacher.put_file_from_path( os.path.join(self.path, "sol", other_filename), "Manager %s for task %s" % (other_filename, task.name)) args["managers"] += [ Manager(other_filename, digest)] compilation_param = "grader" else: compilation_param = "alone" # If there is check/checker (or equivalent), then, presuming # that the task type is Batch or OutputOnly, we retrieve the # comparator paths = [os.path.join(self.path, "check", "checker"), os.path.join(self.path, "cor", "correttore")] for path in paths: if os.path.exists(path): digest = self.file_cacher.put_file_from_path( path, "Manager for task %s" % task.name) args["managers"] += [ Manager("checker", digest)] evaluation_param = "comparator" break else: evaluation_param = "diff" # Detect subtasks by checking GEN gen_filename = os.path.join(self.path, 'gen', 'GEN') try: with open(gen_filename, "rt", encoding="utf-8") as gen_file: subtasks = [] testcases = 0 points = None for line in gen_file: line = line.strip() splitted = line.split('#', 1) if len(splitted) == 1: # This line represents a testcase, otherwise # it's just a blank if splitted[0] != '': testcases += 1 else: testcase, comment = splitted testcase = testcase.strip() comment = comment.strip() testcase_detected = len(testcase) > 0 copy_testcase_detected = comment.startswith("COPY:") subtask_detected = comment.startswith('ST:') flags = [testcase_detected, copy_testcase_detected, subtask_detected] if len([x for x in flags if x]) > 1: raise Exception("No testcase and command in" " the same line allowed") # This line represents a testcase and contains a # comment, but the comment doesn't start a new # subtask if testcase_detected or copy_testcase_detected: testcases += 1 # This line starts a new subtask if subtask_detected: # Close the previous subtask if points is None: assert(testcases == 0) else: subtasks.append([points, testcases]) # Open the new one testcases = 0 points = int(comment[3:].strip()) # Close last subtask (if no subtasks were defined, just # fallback to Sum) if points is None: args["score_type"] = "Sum" total_value = float(conf.get("total_value", 100.0)) input_value = 0.0 n_input = testcases if n_input != 0: input_value = total_value / n_input args["score_type_parameters"] = input_value else: subtasks.append([points, testcases]) assert(100 == sum([int(st[0]) for st in subtasks])) n_input = sum([int(st[1]) for st in subtasks]) args["score_type"] = "GroupMin" args["score_type_parameters"] = subtasks if "n_input" in conf: assert int(conf['n_input']) == n_input # If gen/GEN doesn't exist, just fallback to Sum except OSError: args["score_type"] = "Sum" total_value = float(conf.get("total_value", 100.0)) input_value = 0.0 n_input = int(conf['n_input']) if n_input != 0: input_value = total_value / n_input args["score_type_parameters"] = input_value # Override score_type if explicitly specified if "score_type" in conf and "score_type_parameters" in conf: logger.info("Overriding 'score_type' and 'score_type_parameters' " "as per task.yaml") load(conf, args, "score_type") load(conf, args, "score_type_parameters") elif "score_type" in conf or "score_type_parameters" in conf: logger.warning("To override score type data, task.yaml must " "specify both 'score_type' and " "'score_type_parameters'.") # If output_only is set, then the task type is OutputOnly if conf.get('output_only', False): args["task_type"] = "OutputOnly" args["time_limit"] = None args["memory_limit"] = None args["task_type_parameters"] = [evaluation_param] task.submission_format = \ ["output_%03d.txt" % i for i in range(n_input)] # If there is check/manager (or equivalent), then the task # type is Communication else: paths = [os.path.join(self.path, "check", "manager"), os.path.join(self.path, "cor", "manager")] for path in paths: if os.path.exists(path): num_processes = load(conf, None, "num_processes") if num_processes is None: num_processes = 1 logger.info("Task type Communication") args["task_type"] = "Communication" args["task_type_parameters"] = \ [num_processes, "stub", "fifo_io"] digest = self.file_cacher.put_file_from_path( path, "Manager for task %s" % task.name) args["managers"] += [ Manager("manager", digest)] for lang in LANGUAGES: stub_name = os.path.join( self.path, "sol", "stub%s" % lang.source_extension) if os.path.exists(stub_name): digest = self.file_cacher.put_file_from_path( stub_name, "Stub for task %s and language %s" % ( task.name, lang.name)) args["managers"] += [ Manager( "stub%s" % lang.source_extension, digest)] else: logger.warning("Stub for language %s not " "found.", lang.name) for other_filename in os.listdir(os.path.join(self.path, "sol")): if any(other_filename.endswith(header) for header in HEADER_EXTS): digest = self.file_cacher.put_file_from_path( os.path.join(self.path, "sol", other_filename), "Stub %s for task %s" % (other_filename, task.name)) args["managers"] += [ Manager(other_filename, digest)] break # Otherwise, the task type is Batch else: args["task_type"] = "Batch" args["task_type_parameters"] = \ [compilation_param, [infile_param, outfile_param], evaluation_param] args["testcases"] = [] for i in range(n_input): input_digest = self.file_cacher.put_file_from_path( os.path.join(self.path, "input", "input%d.txt" % i), "Input %d for task %s" % (i, task.name)) output_digest = self.file_cacher.put_file_from_path( os.path.join(self.path, "output", "output%d.txt" % i), "Output %d for task %s" % (i, task.name)) args["testcases"] += [ Testcase("%03d" % i, False, input_digest, output_digest)] if args["task_type"] == "OutputOnly": task.attachments.set( Attachment("input_%03d.txt" % i, input_digest)) public_testcases = load(conf, None, ["public_testcases", "risultati"], conv=lambda x: "" if x is None else x) if public_testcases == "all": for t in args["testcases"]: t.public = True elif len(public_testcases) > 0: for x in public_testcases.split(","): args["testcases"][int(x.strip())].public = True args["testcases"] = dict((tc.codename, tc) for tc in args["testcases"]) args["managers"] = dict((mg.filename, mg) for mg in args["managers"]) dataset = Dataset(**args) task.active_dataset = dataset # Import was successful os.remove(os.path.join(self.path, ".import_error")) logger.info("Task parameters loaded.") return task
def get_task(self, get_statement=True): """See docstring in class Loader. """ json_src = os.path.join(self.path, 'problem.json') if not os.path.exists(json_src): logger.critical('No task found.') raise OSError('No task found at path %s' % json_src) with open(json_src, 'rt', encoding='utf-8') as json_file: data = json.load(json_file) name = data['code'] logger.info("Loading parameters for task %s.", name) args = {} args["name"] = name args["title"] = data['name'] # Statements if get_statement: statements_dir = os.path.join(self.path, 'statements') if os.path.exists(statements_dir): statements = [ filename for filename in os.listdir(statements_dir) if filename[-4:] == ".pdf"] if len(statements) > 0: args['statements'] = dict() logger.info('Statements found') for statement in statements: language = statement[:-4] if language == "en_US": args["primary_statements"] = ["en_US"] digest = self.file_cacher.put_file_from_path( os.path.join(statements_dir, statement), "Statement for task %s (lang: %s)" % (name, language)) args['statements'][language] = Statement(language, digest) # Attachments args["attachments"] = dict() attachments_dir = os.path.join(self.path, 'attachments') if os.path.exists(attachments_dir): logger.info("Attachments found") for filename in os.listdir(attachments_dir): digest = self.file_cacher.put_file_from_path( os.path.join(attachments_dir, filename), "Attachment %s for task %s" % (filename, name)) args["attachments"][filename] = Attachment(filename, digest) data["task_type"] = \ data["task_type"][0].upper() + data["task_type"][1:] # Setting the submission format # Obtaining testcases' codename testcases_dir = os.path.join(self.path, 'tests') if not os.path.exists(testcases_dir): logger.warning('Testcase folder was not found') testcase_codenames = [] else: testcase_codenames = sorted([ filename[:-3] for filename in os.listdir(testcases_dir) if filename[-3:] == '.in']) if data["task_type"] == 'OutputOnly': args["submission_format"] = list() for codename in testcase_codenames: args["submission_format"].append("%s.out" % codename) elif data["task_type"] == 'Notice': args["submission_format"] = list() else: args["submission_format"] = ["%s.%%l" % name] # These options cannot be configured in the TPS format. # Uncomment the following to set specific values for them. # args['max_user_test_number'] = 10 # args['min_user_test_interval'] = make_timedelta(60) # args['token_mode'] = 'infinite' # args['token_max_number'] = 100 # args['token_min_interval'] = make_timedelta(60) # args['token_gen_initial'] = 1 # args['token_gen_number'] = 1 # args['token_gen_interval'] = make_timedelta(1800) # args['token_gen_max'] = 2 if "score_precision" in data: args['score_precision'] = int(data["score_precision"]) else: args['score_precision'] = 2 args['max_submission_number'] = 50 args['max_user_test_number'] = 50 if data["task_type"] == 'OutputOnly': args['max_submission_number'] = 100 args['max_user_test_number'] = 100 args['min_submission_interval'] = make_timedelta(60) args['min_user_test_interval'] = make_timedelta(60) task = Task(**args) args = dict() args["task"] = task args["description"] = "Default" args["autojudge"] = True if data['task_type'] != 'OutputOnly' \ and data['task_type'] != 'Notice': args["time_limit"] = float(data['time_limit']) args["memory_limit"] = int(data['memory_limit']) args["managers"] = {} # Checker checker_dir = os.path.join(self.path, "checker") checker_src = os.path.join(checker_dir, "checker.cpp") if os.path.exists(checker_src): logger.info("Checker found, compiling") checker_exe = os.path.join(checker_dir, "checker") subprocess.call([ "g++", "-x", "c++", "-std=gnu++14", "-O2", "-static", "-o", checker_exe, checker_src ]) digest = self.file_cacher.put_file_from_path( checker_exe, "Manager for task %s" % name) args["managers"]['checker'] = Manager("checker", digest) evaluation_param = "comparator" else: logger.info("Checker not found, using diff if necessary") evaluation_param = "diff" # Note that the original TPS worked with custom task type Batch2017 # and Communication2017 instead of Batch and Communication. args["task_type"] = data['task_type'] args["task_type_parameters"] = \ self._get_task_type_parameters( data, data['task_type'], evaluation_param) # Graders graders_dir = os.path.join(self.path, 'graders') if data['task_type'] == 'TwoSteps': pas_manager = name + 'lib.pas' pas_manager_path = os.path.join(graders_dir, pas_manager) if not os.path.exists(pas_manager_path): digest = self.file_cacher.put_file_content( ''.encode('utf-8'), 'Pascal manager for task %s' % name) args["managers"][pas_manager] = Manager(pas_manager, digest) if not os.path.exists(graders_dir): logger.warning('Grader folder was not found') graders_list = [] else: graders_list = \ [filename for filename in os.listdir(graders_dir) if filename != 'manager.cpp'] for grader_name in graders_list: grader_src = os.path.join(graders_dir, grader_name) digest = self.file_cacher.put_file_from_path( grader_src, "Manager for task %s" % name) if data['task_type'] == 'Communication' \ and os.path.splitext(grader_name)[0] == 'grader': grader_name = 'stub' + os.path.splitext(grader_name)[1] args["managers"][grader_name] = Manager(grader_name, digest) # Manager manager_src = os.path.join(graders_dir, 'manager.cpp') if os.path.exists(manager_src): logger.info("Manager found, compiling") manager_exe = os.path.join(graders_dir, "manager") subprocess.call([ "g++", "-x", "c++", "-O2", "-static", "-o", manager_exe, manager_src ]) digest = self.file_cacher.put_file_from_path( manager_exe, "Manager for task %s" % name) args["managers"]["manager"] = Manager("manager", digest) # Testcases args["testcases"] = {} for codename in testcase_codenames: infile = os.path.join(testcases_dir, "%s.in" % codename) outfile = os.path.join(testcases_dir, "%s.out" % codename) if not os.path.exists(outfile): logger.critical( 'Could not find the output file for testcase %s', codename) logger.critical('Aborting...') return input_digest = self.file_cacher.put_file_from_path( infile, "Input %s for task %s" % (codename, name)) output_digest = self.file_cacher.put_file_from_path( outfile, "Output %s for task %s" % (codename, name)) testcase = Testcase(codename, True, input_digest, output_digest) args["testcases"][codename] = testcase # Score Type subtasks_dir = os.path.join(self.path, 'subtasks') if not os.path.exists(subtasks_dir): logger.warning('Subtask folder was not found') subtasks = [] else: subtasks = sorted(os.listdir(subtasks_dir)) if len(subtasks) == 0: number_tests = max(len(testcase_codenames), 1) args["score_type"] = "Sum" args["score_type_parameters"] = 100 / number_tests else: args["score_type"] = "GroupMin" parsed_data = [] subtask_no = -1 add_optional_name = False for subtask in subtasks: subtask_no += 1 with open(os.path.join(subtasks_dir, subtask), 'rt', encoding='utf-8') as subtask_json: subtask_data = json.load(subtask_json) score = int(subtask_data["score"]) testcases = "|".join( re.escape(testcase) for testcase in subtask_data["testcases"] ) optional_name = "Subtask %d" % subtask_no if subtask_no == 0 and score == 0: add_optional_name = True optional_name = "Samples" if add_optional_name: parsed_data.append([score, testcases, optional_name]) else: parsed_data.append([score, testcases]) args["score_type_parameters"] = parsed_data dataset = Dataset(**args) task.active_dataset = dataset logger.info("Task parameters loaded.") return task
def get_task(self, get_statement=True): """See docstring in class TaskLoader.""" name = os.path.split(self.path)[1] if (not os.path.exists(os.path.join(self.path, "task.yaml"))) and \ (not os.path.exists(os.path.join(self.path, "problema.yaml"))) and \ (not os.path.exists(os.path.join(self.path, "..", name + ".yaml"))): logger.critical("File missing: \"task.yaml\"") return None # We first look for the yaml file inside the task folder, # and eventually fallback to a yaml file in its parent folder. try: conf = yaml.safe_load( io.open(os.path.join(self.path, "task.yaml"), "rt", encoding="utf-8")) except IOError as err: try: conf = yaml.safe_load( io.open(os.path.join(self.path, "problema.yaml"), "rt", encoding="utf-8")) except: try: deprecated_path = os.path.join(self.path, "..", name + ".yaml") conf = yaml.safe_load( io.open(deprecated_path, "rt", encoding="utf-8")) logger.warning( "You're using a deprecated location for the " "task.yaml file. You're advised to move %s to " "%s.", deprecated_path, os.path.join(self.path, "task.yaml")) except IOError: # Since both task.yaml and the (deprecated) "../taskname.yaml" # are missing, we will only warn the user that task.yaml is # missing (to avoid encouraging the use of the deprecated one) raise err # Here we update the time of the last import touch(os.path.join(self.path, ".itime")) # If this file is not deleted, then the import failed touch(os.path.join(self.path, ".import_error")) args = {} load(conf, args, ["name", "nome_breve"]) load(conf, args, ["title", "nome"]) load(conf, args, "hide_task_prefix") load(conf, args, "category") load(conf, args, "level") if "level" in args: args["level"] = unicode(args["level"]) if name != args["name"]: logger.info( "The task name (%s) and the directory name (%s) are " "different. The former will be used.", args["name"], name) if args["name"] == args["title"]: logger.warning("Short name equals long name (title). " "Please check.") name = args["name"] logger.info("Loading parameters for task %s.", name) if get_statement: primary_language = load(conf, None, "primary_language") if primary_language is None: primary_language = 'it' paths = [ os.path.join(self.path, "statement", "statement.pdf"), os.path.join(self.path, "statement.pdf"), os.path.join(self.path, "enunciado.pdf"), os.path.join(self.path, args["name"] + ".pdf"), os.path.join(self.path, "testo", "testo.pdf") ] for path in paths: if os.path.exists(path): digest = self.file_cacher.put_file_from_path( path, "Statement for task %s (lang: %s)" % (name, primary_language)) break else: logger.critical("Couldn't find any task statement, aborting.") sys.exit(1) args["statements"] = [Statement(primary_language, digest)] args["primary_statements"] = '["%s"]' % (primary_language) args["attachments"] = [] # FIXME Use auxiliary args["submission_format"] = [SubmissionFormatElement("%s.%%l" % name)] if conf.get("score_mode", None) == SCORE_MODE_MAX: args["score_mode"] = SCORE_MODE_MAX elif conf.get("score_mode", None) == SCORE_MODE_MAX_TOKENED_LAST: args["score_mode"] = SCORE_MODE_MAX_TOKENED_LAST # Use the new token settings format if detected. if "token_mode" in conf: load(conf, args, "token_mode") load(conf, args, "token_max_number") load(conf, args, "token_min_interval", conv=make_timedelta) load(conf, args, "token_gen_initial") load(conf, args, "token_gen_number") load(conf, args, "token_gen_interval", conv=make_timedelta) load(conf, args, "token_gen_max") # Otherwise fall back on the old one. else: logger.warning( "task.yaml uses a deprecated format for token settings which " "will soon stop being supported, you're advised to update it.") # Determine the mode. if conf.get("token_initial", None) is None: args["token_mode"] = "disabled" elif conf.get("token_gen_number", 0) > 0 and \ conf.get("token_gen_time", 0) == 0: args["token_mode"] = "infinite" else: args["token_mode"] = "finite" # Set the old default values. args["token_gen_initial"] = 0 args["token_gen_number"] = 0 args["token_gen_interval"] = timedelta() # Copy the parameters to their new names. load(conf, args, "token_total", "token_max_number") load(conf, args, "token_min_interval", conv=make_timedelta) load(conf, args, "token_initial", "token_gen_initial") load(conf, args, "token_gen_number") load(conf, args, "token_gen_time", "token_gen_interval", conv=make_timedelta) load(conf, args, "token_max", "token_gen_max") # Remove some corner cases. if args["token_gen_initial"] is None: args["token_gen_initial"] = 0 if args["token_gen_interval"].total_seconds() == 0: args["token_gen_interval"] = timedelta(minutes=1) load(conf, args, "max_submission_number") load(conf, args, "max_user_test_number") load(conf, args, "min_submission_interval", conv=make_timedelta) load(conf, args, "min_user_test_interval", conv=make_timedelta) # Attachments args["attachments"] = [] if os.path.exists(os.path.join(self.path, "att")): for filename in os.listdir(os.path.join(self.path, "att")): digest = self.file_cacher.put_file_from_path( os.path.join(self.path, "att", filename), "Attachment %s for task %s" % (filename, name)) args["attachments"] += [Attachment(filename, digest)] task = Task(**args) args = {} args["task"] = task args["description"] = conf.get("version", "Default") args["autojudge"] = False load(conf, args, ["time_limit", "timeout"], conv=float) load(conf, args, ["memory_limit", "memlimit"]) # Builds the parameters that depend on the task type args["managers"] = [] infile_param = conf.get("infile", "input.txt") outfile_param = conf.get("outfile", "output.txt") # If there is sol/grader.%l for some language %l, then, # presuming that the task type is Batch, we retrieve graders # in the form sol/grader.%l graders = False for lang in LANGUAGES: if os.path.exists( os.path.join(self.path, "sol", "grader%s" % lang.source_extension)): graders = True break if graders: # Read grader for each language for lang in LANGUAGES: extension = lang.source_extension grader_filename = os.path.join(self.path, "sol", "grader%s" % extension) if os.path.exists(grader_filename): digest = self.file_cacher.put_file_from_path( grader_filename, "Grader for task %s and language %s" % (task.name, lang)) args["managers"] += [ Manager("grader%s" % extension, digest) ] else: logger.warning("Grader for language %s not found ", lang) # Read managers with other known file extensions for other_filename in os.listdir(os.path.join(self.path, "sol")): if any( other_filename.endswith(header) for header in HEADER_EXTS): digest = self.file_cacher.put_file_from_path( os.path.join(self.path, "sol", other_filename), "Manager %s for task %s" % (other_filename, task.name)) args["managers"] += [Manager(other_filename, digest)] compilation_param = "grader" else: compilation_param = "alone" # If there is check/checker (or equivalent), then, presuming # that the task type is Batch or OutputOnly, we retrieve the # comparator paths = [ os.path.join(self.path, "check", "checker"), os.path.join(self.path, "corrector.exe"), os.path.join(self.path, "cor", "correttore") ] for path in paths: if os.path.exists(path): digest = self.file_cacher.put_file_from_path( path, "Manager for task %s" % task.name) args["managers"] += [Manager("checker", digest)] evaluation_param = "comparator" break else: evaluation_param = "diff" # Detect subtasks by checking GEN gen_filename = os.path.join(self.path, 'gen', 'GEN') try: with io.open(gen_filename, "rt", encoding="utf-8") as gen_file: subtasks = [] testcases = 0 points = None for line in gen_file: line = line.strip() splitted = line.split('#', 1) if len(splitted) == 1: # This line represents a testcase, otherwise # it's just a blank if splitted[0] != '': testcases += 1 else: testcase, comment = splitted testcase = testcase.strip() comment = comment.strip() testcase_detected = testcase != '' copy_testcase_detected = comment.startswith("COPY:") subtask_detected = comment.startswith('ST:') flags = [ testcase_detected, copy_testcase_detected, subtask_detected ] if len([x for x in flags if x]) > 1: raise Exception("No testcase and command in" " the same line allowed") # This line represents a testcase and contains a # comment, but the comment doesn't start a new # subtask if testcase_detected or copy_testcase_detected: testcases += 1 # This line starts a new subtask if subtask_detected: # Close the previous subtask if points is None: assert (testcases == 0) else: subtasks.append([points, testcases]) # Open the new one testcases = 0 points = int(comment[3:].strip()) # Close last subtask (if no subtasks were defined, just # fallback to Sum) if points is None: args["score_type"] = "Sum" total_value = float(conf.get("total_value", 100.0)) input_value = 0.0 n_input = testcases if n_input != 0: input_value = total_value / n_input args["score_type_parameters"] = "%s" % input_value else: subtasks.append([points, testcases]) assert (100 == sum([int(st[0]) for st in subtasks])) n_input = sum([int(st[1]) for st in subtasks]) args["score_type"] = "GroupMin" args["score_type_parameters"] = "%s" % subtasks if "n_input" in conf: assert int(conf['n_input']) == n_input # If gen/GEN doesn't exist, just fallback to Sum except IOError: if 'n_input' not in conf: conf['n_input'] = 0 n_input = int(conf['n_input']) if "score_type" in conf: args["score_type"] = conf["score_type"] if "score_type_parameters" in conf: args["score_type_parameters"] = ( "%s" % conf["score_type_parameters"]) args["score_type_parameters"] = re.sub( r'u\'([^\']+)\'', '\"\g<1>\"', args["score_type_parameters"]) else: args["score_type"] = "Sum" total_value = float(conf.get("total_value", 100.0)) input_value = 0.0 def count_testcases(folder): c = 0 if os.path.isdir(folder): for filename in sorted(os.listdir(folder)): nombre, ext = os.path.splitext(filename) if ext == ".in": c += 1 return c casos = n_input + count_testcases( os.path.join(self.path, "casos")) + count_testcases( os.path.join(self.path, "casos", "generados")) if casos != 0: input_value = total_value / casos args["score_type_parameters"] = "%s" % input_value # If output_only is set, then the task type is OutputOnly if conf.get('output_only', False): args["task_type"] = "OutputOnly" args["time_limit"] = None args["memory_limit"] = None args["task_type_parameters"] = '["%s"]' % evaluation_param task.submission_format = [ SubmissionFormatElement("output_%03d.txt" % i) for i in xrange(n_input) ] # If there is check/manager (or equivalent), then the task # type is Communication else: paths = [ os.path.join(self.path, "check", "manager"), os.path.join(self.path, "cor", "manager") ] for path in paths: if os.path.exists(path): num_processes = load(conf, None, "num_processes") if num_processes is None: num_processes = 1 logger.info("Task type Communication") args["task_type"] = "Communication" args["task_type_parameters"] = '[%d]' % num_processes digest = self.file_cacher.put_file_from_path( path, "Manager for task %s" % task.name) args["managers"] += [Manager("manager", digest)] for lang in LANGUAGES: stub_name = os.path.join( self.path, "sol", "stub%s" % lang.source_extension) if os.path.exists(stub_name): digest = self.file_cacher.put_file_from_path( stub_name, "Stub for task %s and language %s" % (task.name, lang.name)) args["managers"] += [ Manager("stub%s" % lang.source_extension, digest) ] else: logger.warning( "Stub for language %s not " "found.", lang.name) for other_filename in os.listdir( os.path.join(self.path, "sol")): if any( other_filename.endswith(header) for header in HEADER_EXTS): digest = self.file_cacher.put_file_from_path( os.path.join(self.path, "sol", other_filename), "Stub %s for task %s" % (other_filename, task.name)) args["managers"] += [ Manager(other_filename, digest) ] break # Otherwise, the task type is Batch else: args["task_type"] = "Batch" args["task_type_parameters"] = \ '["%s", ["%s", "%s"], "%s"]' % \ (compilation_param, infile_param, outfile_param, evaluation_param) args["testcases"] = [] for i in xrange(n_input): input_digest = self.file_cacher.put_file_from_path( os.path.join(self.path, "input", "input%d.txt" % i), "Input %d for task %s" % (i, task.name)) output_digest = self.file_cacher.put_file_from_path( os.path.join(self.path, "output", "output%d.txt" % i), "Output %d for task %s" % (i, task.name)) args["testcases"] += [ Testcase("%03d" % i, False, input_digest, output_digest) ] if args["task_type"] == "OutputOnly": task.attachments += [ Attachment("input_%03d.txt" % i, input_digest) ] def add_testcases_dir(folder): if os.path.isdir(folder): for filename in sorted(os.listdir(folder)): nombre, ext = os.path.splitext(filename) if ext == ".in": input_digest = self.file_cacher.put_file_from_path( os.path.join(folder, filename), "Input %s for task %s" % (nombre, task.name)) output_digest = self.file_cacher.put_file_from_path( os.path.join(folder, nombre + ".dat"), "Output %s for task %s" % (nombre, task.name)) args["testcases"] += [ Testcase(nombre, False, input_digest, output_digest) ] if args["task_type"] == "OutputOnly": task.attachments += [ Attachment(filename, input_digest) ] add_testcases_dir(os.path.join(self.path, "casos")) add_testcases_dir(os.path.join(self.path, "casos", "generados")) public_testcases = load(conf, None, ["public_testcases", "risultati"], conv=lambda x: "" if x is None else x) if public_testcases == "all": for t in args["testcases"]: t.public = True elif public_testcases != "": for x in public_testcases.split(","): args["testcases"][int(x.strip())].public = True dataset = Dataset(**args) task.active_dataset = dataset # Import was successful os.remove(os.path.join(self.path, ".import_error")) logger.info("Task parameters loaded.") return task
def get_task(self, get_statement=True): """See docstring in class Loader. """ json_src = os.path.join(self.path, 'problem.json') if not os.path.exists(json_src): logger.critical('No task found.') raise IOError('No task found at path %s' % json_src) with io.open(json_src, 'rt', encoding='utf-8') as json_file: data = json.load(json_file) name = data['code'] logger.info("Loading parameters for task %s.", name) args = {} args["name"] = name args["title"] = data['name'] # Statements if get_statement: statements_dir = os.path.join(self.path, 'statements') if os.path.exists(statements_dir): statements = [ filename for filename in os.listdir(statements_dir) if filename[-4:] == ".pdf"] if len(statements) > 0: args['statements'] = dict() logger.info('Statements found') for statement in statements: language = statement[:-4] if language == "en_US": args["primary_statements"] = ["en_US"] digest = self.file_cacher.put_file_from_path( os.path.join(statements_dir, statement), "Statement for task %s (lang: %s)" % (name, language)) args['statements'][language] = Statement(language, digest) # Attachments args["attachments"] = dict() attachments_dir = os.path.join(self.path, 'attachments') if os.path.exists(attachments_dir): logger.info("Attachments found") for filename in os.listdir(attachments_dir): digest = self.file_cacher.put_file_from_path( os.path.join(attachments_dir, filename), "Attachment %s for task %s" % (filename, name)) args["attachments"][filename] = Attachment(filename, digest) data["task_type"] = \ data["task_type"][0].upper() + data["task_type"][1:] # Setting the submission format # Obtaining testcases' codename testcases_dir = os.path.join(self.path, 'tests') if not os.path.exists(testcases_dir): logger.warning('Testcase folder was not found') testcase_codenames = [] else: testcase_codenames = sorted([ filename[:-3] for filename in os.listdir(testcases_dir) if filename[-3:] == '.in']) if data["task_type"] == 'OutputOnly': args["submission_format"] = list() for codename in testcase_codenames: args["submission_format"].append("%s.out" % codename) elif data["task_type"] == 'Notice': args["submission_format"] = list() else: args["submission_format"] = ["%s.%%l" % name] # These options cannot be configured in the TPS format. # Uncomment the following to set specific values for them. # args['max_user_test_number'] = 10 # args['min_user_test_interval'] = make_timedelta(60) # args['token_mode'] = 'infinite' # args['token_max_number'] = 100 # args['token_min_interval'] = make_timedelta(60) # args['token_gen_initial'] = 1 # args['token_gen_number'] = 1 # args['token_gen_interval'] = make_timedelta(1800) # args['token_gen_max'] = 2 if "score_precision" in data: args['score_precision'] = int(data["score_precision"]) else: args['score_precision'] = 2 args['max_submission_number'] = 50 args['max_user_test_number'] = 50 if data["task_type"] == 'OutputOnly': args['max_submission_number'] = 100 args['max_user_test_number'] = 100 args['min_submission_interval'] = make_timedelta(60) args['min_user_test_interval'] = make_timedelta(60) task = Task(**args) args = dict() args["task"] = task args["description"] = "Default" args["autojudge"] = True if data['task_type'] != 'OutputOnly' \ and data['task_type'] != 'Notice': args["time_limit"] = float(data['time_limit']) args["memory_limit"] = int(data['memory_limit']) args["managers"] = {} # Checker checker_dir = os.path.join(self.path, "checker") checker_src = os.path.join(checker_dir, "checker.cpp") if os.path.exists(checker_src): logger.info("Checker found, compiling") checker_exe = os.path.join(checker_dir, "checker") subprocess.call([ "g++", "-x", "c++", "-std=gnu++14", "-O2", "-static", "-o", checker_exe, checker_src ]) digest = self.file_cacher.put_file_from_path( checker_exe, "Manager for task %s" % name) args["managers"]['checker'] = Manager("checker", digest) evaluation_param = "comparator" else: logger.info("Checker not found, using diff if necessary") evaluation_param = "diff" # Note that the original TPS worked with custom task type Batch2017 # and Communication2017 instead of Batch and Communication. args["task_type"] = data['task_type'] args["task_type_parameters"] = \ self._get_task_type_parameters( data, data['task_type'], evaluation_param)
def get_task(self, get_statement=True): """See docstring in class Loader. """ json_src = os.path.join(self.path, 'problem.json') if not os.path.exists(json_src): logger.critical('No task found.') raise IOError('No task found at path %s' % json_src) with io.open(json_src, 'rt', encoding='utf-8') as json_file: data = json.load(json_file) name = data['name'] logger.info("Loading parameters for task %s.", name) args = {} args["name"] = name if 'problem_label' in data: args['title'] = '{}. {}'.format(data['problem_label'], data['title']) else: args['title'] = data['title'] # Statements if get_statement: statements_dir = os.path.join(self.path, 'statement') if os.path.exists(statements_dir): statements = [ filename for filename in os.listdir(statements_dir) if filename[-4:] == ".pdf" ] if len(statements) > 0: args['statements'] = dict() logger.info('Statements found') for statement in statements: language = statement[:-4] if language == "en_US": args["primary_statements"] = ["en_US"] digest = self.file_cacher.put_file_from_path( os.path.join(statements_dir, statement), "Statement for task %s (lang: %s)" % (name, language)) args['statements'][language] = Statement(language, digest) # Attachments if get_statement: args["attachments"] = dict() attachments_dir = os.path.join(self.path, 'attachments') if os.path.exists(attachments_dir): logger.info("Attachments found") for filename in os.listdir(attachments_dir): digest = self.file_cacher.put_file_from_path( os.path.join(attachments_dir, filename), "Attachment %s for task %s" % (filename, name)) args["attachments"][filename] = Attachment( filename, digest) data["task_type"] = \ data["task_type"][0].upper() + data["task_type"][1:] # Setting the submission format # Obtaining testcases' codename testcases_dir = os.path.join(self.path, 'tests') if not os.path.exists(testcases_dir): logger.warning('Testcase folder was not found') testcase_codenames = [] else: testcase_codenames = sorted([ filename[:-3] for filename in os.listdir(testcases_dir) if filename[-3:] == '.in' ]) if data["task_type"] == 'OutputOnly': args["submission_format"] = list() for codename in testcase_codenames: args["submission_format"].append("%s.out" % codename) elif data["task_type"] == 'Notice': args["submission_format"] = list() else: args["submission_format"] = ["%s.%%l" % name] # Task information if 'feedback_level' in data: args['feedback_level'] = data['feedback_level'] # Tokens parameters # Limits if 'max_submission_number' in data: args['max_submission_number'] = data['max_submission_number'] if 'max_user_test_number' in data: args['max_user_test_number'] = data['max_user_test_number'] if 'min_submission_interval' in data: if data['min_submission_interval'] is None: args['min_submission_interval'] = None else: args['min_submission_interval'] = make_timedelta( data['min_submission_interval']) if 'min_user_test_interval' in data: if data['min_user_test_interval'] is None: args['min_user_test_interval'] = None else: args['min_user_test_interval'] = make_timedelta( data['min_user_test_interval']) # Score options if 'score_precision' in data: args['score_precision'] = int(data['score_precision']) if 'score_mode' in data: args['score_mode'] = data['score_mode'] task = Task(**args) ignore_datasets = data[ 'ignore_datasets'] if 'ignore_datasets' in data else False if ignore_datasets: logger.info("Task parameters loaded.") logger.info("Dataset loading skipped.") return task args = dict() args["task"] = task args["description"] = "Default" args["autojudge"] = True if data['task_type'] != 'OutputOnly' \ and data['task_type'] != 'Notice': args["time_limit"] = float(data['time_limit']) args["memory_limit"] = int(data['memory_limit']) args["managers"] = {} # Checker checker_dir = os.path.join(self.path, "checker") checker_src = os.path.join(checker_dir, "checker.cpp") checker_py = os.path.join(checker_dir, "checker.py") has_checker = data['has_checker'] if 'has_checker' in data else False if not has_checker: logger.info("Checker is ignored, using diff if necessary") evaluation_param = "diff" elif os.path.exists(checker_src): logger.info("Checker found, compiling") checker_exe = os.path.join(checker_dir, "checker") subprocess.call([ "g++", "-x", "c++", "-std=gnu++14", "-O2", "-static", "-o", checker_exe, checker_src ]) digest = self.file_cacher.put_file_from_path( checker_exe, "Manager for task %s" % name) args["managers"]['checker'] = Manager("checker", digest) evaluation_param = "comparator" elif os.path.exists(checker_py): logger.info("Checker found, compiling") checker_exe = os.path.join(checker_dir, "checker") subprocess.call(["cp", checker_py, checker_exe]) subprocess.call(["chmod", "+x", checker_exe]) digest = self.file_cacher.put_file_from_path( checker_exe, "Manager for task %s" % name) args["managers"]['checker'] = Manager("checker", digest) evaluation_param = "comparator" else: logger.info("Checker not found, using diff if necessary") evaluation_param = "diff" # Note that the original TPS worked with custom task type Batch2017 # and Communication2017 instead of Batch and Communication. args["task_type"] = data['task_type'] args["task_type_parameters"] = \ self._get_task_type_parameters( data, data['task_type'], evaluation_param) # Graders graders_dir = os.path.join(self.path, 'graders') if data['task_type'] == 'TwoSteps': pas_manager = name + 'lib.pas' pas_manager_path = os.path.join(graders_dir, pas_manager) if not os.path.exists(pas_manager_path): digest = self.file_cacher.put_file_content( ''.encode('utf-8'), 'Pascal manager for task %s' % name) args["managers"][pas_manager] = Manager(pas_manager, digest) if not os.path.exists(graders_dir): logger.warning('Grader folder was not found') graders_list = [] else: graders_list = \ [filename for filename in os.listdir(graders_dir) if filename != 'manager.cpp'] for grader_name in graders_list: grader_src = os.path.join(graders_dir, grader_name) digest = self.file_cacher.put_file_from_path( grader_src, "Manager for task %s" % name) if data['task_type'] == 'Communication' \ and os.path.splitext(grader_name)[0] == 'grader': grader_name = 'stub' + os.path.splitext(grader_name)[1] args["managers"][grader_name] = Manager(grader_name, digest) # Manager manager_src = os.path.join(graders_dir, 'manager.cpp') if os.path.exists(manager_src): logger.info("Manager found, compiling") manager_exe = os.path.join(graders_dir, "manager") subprocess.call([ "g++", "-x", "c++", "-O2", "-static", "-o", manager_exe, manager_src ]) digest = self.file_cacher.put_file_from_path( manager_exe, "Manager for task %s" % name) args["managers"]["manager"] = Manager("manager", digest) # Testcases args["testcases"] = {} for codename in testcase_codenames: infile = os.path.join(testcases_dir, "%s.in" % codename) outfile = os.path.join(testcases_dir, "%s.out" % codename) if not os.path.exists(outfile): logger.critical( 'Could not find the output file for testcase %s', codename) logger.critical('Aborting...') return input_digest = self.file_cacher.put_file_from_path( infile, "Input %s for task %s" % (codename, name)) output_digest = self.file_cacher.put_file_from_path( outfile, "Output %s for task %s" % (codename, name)) testcase = Testcase(codename, True, input_digest, output_digest) args["testcases"][codename] = testcase # Score Type subtasks_json_src = os.path.join(self.path, 'subtasks.json') if not os.path.exists(subtasks_json_src): number_tests = max(len(testcase_codenames), 1) args["score_type"] = "Sum" args["score_type_parameters"] = 100 / number_tests else: args["score_type"] = "GroupMin" parsed_data = [] subtask_no = -1 mapping_src = os.path.join(self.path, 'tests', 'mapping') with open(subtasks_json_src, 'rt', encoding='utf-8') as json_file: subtasks_data = json.load(json_file) use_mapping = os.path.exists(mapping_src) if use_mapping: mapping_data = {} for subtask in subtasks_data['subtasks']: mapping_data[subtask] = [] with open(mapping_src, 'rt', encoding='utf-8') as mapping_file: for row in mapping_file: row = row.strip().split(' ') if len(row) == 2: mapping_data[row[0]].append(row[1]) add_optional_name = data[ 'add_optional_name'] if 'add_optional_name' in data else False for subtask, subtask_data in subtasks_data['subtasks'].items(): subtask_no += 1 score = int(subtask_data["score"]) if use_mapping: testcases = "|".join( re.escape(testcase) for testcase in mapping_data[subtask]) if testcases == '': testcases = '|NO_TESTCASES_AVAILABLE' else: testcases = subtask_data["regex"] optional_name = "Subtask %d" % subtask_no if subtask_no == 0 and score == 0: optional_name = "Samples" if add_optional_name: parsed_data.append([score, testcases, optional_name]) else: parsed_data.append([score, testcases]) args["score_type_parameters"] = parsed_data dataset = Dataset(**args) task.active_dataset = dataset logger.info("Task parameters loaded.") return task
def get_task(self, get_statement=True): base_path = self.path cms_path = os.path.join(base_path, 'cms') conf_path = os.path.join(base_path, 'cms', 'task-iif.yaml') if not exists(conf_path): logger.critical("cannot find \"task-iif.yaml\"") return None conf = load_yaml(conf_path) name = conf['name'] logger.info("loading parameters for task \"%s\"", name) # inherited default default_conf_paths = DEFAULT_CONF_PATHS.copy() env_default_conf_path = os.environ.get(ENVVAR_NAME_DEFAULT_CONF_PATH) if env_default_conf_path is not None: default_conf_paths = [env_default_conf_path] default_found = False for def_path in default_conf_paths: if exists(def_path): default_conf = load_yaml(def_path) default_assign(conf, default_conf, 'primary_language') default_assign(conf, default_conf, 'max_submission_number') default_assign(conf, default_conf, 'min_submission_interval') default_found = True break if not default_found: search_paths = ', '.join(default_conf_paths) logging.warning("cannot find default config file (search path: {})".format(search_paths)) # default conf.setdefault('score_mode', SCORE_MODE_MAX_SUBTASK) conf.setdefault('primary_language', 'ja') conf.setdefault('samples', ['sample-*']) conf.setdefault('feedback', ['*']) conf.setdefault('version', 'default-dataset') # override conf['token_mode'] = TOKEN_MODE_DISABLED task = {} task_type = conf.get('task_type', 'batch').lower() score_type = conf.get('score_type', 'normal').lower() # general task config assign(task, conf, 'name') assign(task, conf, 'title') task['primary_statements'] = [conf['primary_language']] assign(task, conf, 'score_mode') assign(task, conf, 'token_mode') try_assign(task, conf, 'max_submission_number') try_assign(task, conf, 'max_user_test_number') try_assign(task, conf, 'min_submission_interval', make_timedelta) try_assign(task, conf, 'min_user_test_interval', make_timedelta) try_assign(task, conf, 'score_precision') sample_regexp = globlist_to_regexp(conf['samples']) feedback_regexp = globlist_to_regexp(conf['feedback']) # testcases detection testcases = {} missing_out_testcases = [] old_input_dir = os.path.join(base_path, 'in') new_input_dir = os.path.join(base_path, 'gen', 'in') for input_dir in [old_input_dir, new_input_dir]: if not os.path.isdir(input_dir): continue for fname in os.listdir(input_dir): m = re.match(r'\A(.+)\.txt\Z', fname) if not m: logger.warning("ignored input file: \"%s\"", fname) continue codename = m.group(1) in_path = os.path.join(input_dir, fname) out_path = os.path.join(input_dir, '..', 'out', fname) if not exists(out_path): missing_out_testcases.append(codename) out_path = None if codename in testcases: logger.warning("duplicated testcase name: \"%s\"", codename) testcases[codename] = { 'in_path': in_path, 'out_path': out_path, 'sample': sample_regexp.match(codename) is not None, 'feedback': feedback_regexp.match(codename) is not None, } # additional files detection headers = [] stubs, graders, manager, checker, stub_preload = [], [], None, None, None manager_src, checker_src, stub_preload_src = None, None, None for fname in os.listdir(cms_path): path = os.path.join(cms_path, fname) if any(fname.endswith(ext) for ext in HEADER_EXTS): headers.append((fname, path)) for src_ext in SOURCE_EXTS: if fname == ('stub%s' % src_ext): stubs.append((fname, path)) if fname == ('grader%s' % src_ext): graders.append((fname, path)) if fname == 'manager.cpp': manager_src = path if fname == 'checker.cpp': checker_src = path if fname == 'stub_preload.cpp': stub_preload_src = path # auto compilation if manager_src: logger.info("manager auto compilation") manager = compile_judge_program('manager', os.path.join(cms_path, 'manager'), manager_src) if manager is None: logger.critical("manager compilation failed") return None if checker_src: logger.info("checker auto compilation") checker = compile_judge_program('checker', os.path.join(cms_path, 'checker'), checker_src) if checker is None: logger.critical("checker compilation failed") return None if stub_preload_src: logger.info("stub_preload auto compilation") stub_preload = compile_judge_program('stub_preload', os.path.join(cms_path, 'stub_preload'), stub_preload_src) if stub_preload is None: logger.critical("stub_preload compilation failed") return None # statements detection & registration if get_statement: statements = {} primary_language = conf['primary_language'] pdf_dir = os.path.join(base_path, 'task') pdf_files = [ ('statement.pdf', primary_language), ('statement-ja.pdf', 'ja'), ('statement-en.pdf', 'en'), ] for fname, lang in pdf_files: path = os.path.join(pdf_dir, fname) if exists(path): digest = self.file_cacher.put_file_from_path(path, "statement (%s) for task \"%s\"" % (lang, name)) statements[lang] = Statement(lang, digest) task['statements'] = statements if len(statements) == 0: logger.warning("cannot find any task statements") # attachments detection dist_path = os.path.join(base_path, 'dist') zipping_files = [] dist_files = [] if exists(dist_path): for base, dirs, files in os.walk(dist_path): for fname in files: path = os.path.join(base, fname) arc_name = os.path.relpath(path, dist_path) safe_arc_name = arc_name.replace(os.sep, '-') if fname.endswith('.zip'): dist_files.append((path, safe_arc_name)) else: zipping_files.append((path, arc_name)) for codename, testcase in testcases.items(): in_path = testcase['in_path'] out_path = testcase['out_path'] if testcase['sample']: zipping_files.append((in_path, "%s-in.txt" % codename)) if out_path: zipping_files.append((out_path, "%s-out.txt" % codename)) elif task_type == 'outputonly': zipping_files.append((in_path, "input_%s.txt" % codename)) dataset = {} dataset['description'] = conf['version'] dataset['autojudge'] = False # score type parameters if score_type == 'normal': dataset['score_type_parameters'] = [ [st['point'], globlist_to_text(st['targets'])] for st in conf['subtasks'] ] dataset['score_type'] = 'GroupMin' elif score_type == 'truncation': score_params = [] for st in conf['subtasks']: opt = st['score_option'] opt.setdefault('power', 1.0) if 'threshold' not in opt: logger.critical("truncation score type requires \"threshold\" parameter") return None param = [ st['point'], globlist_to_text(st['targets']), opt['threshold'][0], opt['threshold'][1], opt['power'], ] score_params.append(param) dataset['score_type_parameters'] = score_params dataset['score_type'] = 'GroupMinTruncation' else: logger.critical("unknown score type \"%s\"", score_type) return None # task_type grader_param = 'grader' if graders else 'alone' eval_param = 'comparator' if checker else 'diff' if task_type == 'batch': assign(dataset, conf, 'time_limit', float) assign(dataset, conf, 'memory_limit', int) task['submission_format'] = ["%s.%%l" % name] dataset['task_type'] = 'Batch' dataset['task_type_parameters'] = \ [grader_param, ['', ''], eval_param] elif task_type == 'outputonly': task['submission_format'] = [ 'output_%s.txt' % codename for codename in sorted(testcases.keys())] dataset['task_type'] = 'OutputOnly' dataset['task_type_parameters'] = [eval_param] elif task_type == 'communication': assign(dataset, conf, 'time_limit', float) assign(dataset, conf, 'memory_limit', int) if not stubs: logger.critical("stub is required for communication task") return None if not manager: logger.critical("manager is required for communication task") return None task_params = [1] submission_format = ["%s.%%l" % name] if 'task_option' in conf: opt = conf['task_option'] if 'processes' not in opt: logger.critical("task_option/processes is required") return None if 'formats' not in opt: logger.critical("task_option/formats is required") return None task_params = [opt['processes']] submission_format = [ fname for fname in opt['formats'] ] task['submission_format'] = submission_format dataset['task_type'] = 'Communication' dataset['task_type_parameters'] = task_params else: logger.critical("unknown task type \"%s\"", task_type) return None # attachments registration attachments = {} for path, arc_name in dist_files: digest = self.file_cacher.put_file_from_path( path, "distribution file for task \"%s\"" % name) attachments[arc_name] = Attachment(arc_name, digest) # zipfile registration if zipping_files: zip_archive = tempfile.mkstemp('cms-iimoj-loader-', '.zip') zip_path = zip_archive[1] with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_STORED) as fp: for path, arc_name in zipping_files: new_arc_name = os.path.join(name, arc_name) fp.write(path, new_arc_name) zip_digest = self.file_cacher.put_file_from_path(zip_path, "distribution archive for task \"%s\"" % name) zip_fname = name + '.zip' attachments[zip_fname] = Attachment(zip_fname, zip_digest) os.remove(zip_path) task['attachments'] = attachments # additional files registration extra_managers = {} extra_files = headers + stubs + graders if manager: extra_files.append(manager) if checker: extra_files.append(checker) if stub_preload: extra_files.append(stub_preload) for fname, path in extra_files: digest = self.file_cacher.put_file_from_path(path, "extra file \"%s\" for task \"%s\"" % (fname, name)) logger.info("extra file: \"%s\"", fname) extra_managers[fname] = Manager(fname, digest) dataset['managers'] = extra_managers # testcases registration logger.info("registering testcases") registered_testcases = {} for codename, testcase in testcases.items(): in_path = testcase['in_path'] out_path = testcase['out_path'] feedback = testcase['feedback'] in_digest = self.file_cacher.put_file_from_path(in_path, "input \"%s\" for task \"%s\"" % (codename, name)) out_digest = None if out_path: out_digest = self.file_cacher.put_file_from_path(out_path, "output \"%s\" for task \"%s\"" % (codename, name)) else: out_digest = self.file_cacher.put_file_content(b'', "output \"%s\" for task \"%s\"" % (codename, name)) registered_testcases[codename] = Testcase(codename, feedback, in_digest, out_digest) logger.info("testcases registration completed") dataset['testcases'] = registered_testcases # instantiation db_task = Task(**task) dataset['task'] = db_task db_dataset = Dataset(**dataset) db_task.active_dataset = db_dataset # import result logger.info("========== task \"%s\" ==========", name) logger.info("tasktype : %s", task_type) if task_type != 'batch': logger.info("headers : [%02d files]", len(headers)) for fname, _ in sorted(headers): logger.info(" * %s", fname) if task_type == 'communication': logger.info("manager : %s", "OK" if manager else "--") logger.info("stub : [%02d files]", len(stubs)) for fname, _ in sorted(stubs): logger.info(" * %s", fname) if task_type != 'communication': logger.info("comparator: %s", "OK" if checker else "--") if task_type == 'batch': logger.info("grader : [%02d files]", len(graders)) for fname, _ in sorted(graders): logger.info(" * %s", fname) logger.info("zipped : [%02d files]", len(zipping_files)) for _, arc_name in sorted(zipping_files): logger.info(" * %s", arc_name) logger.info("direct : [%02d files]", len(dist_files)) for _, arc_name in sorted(dist_files): logger.info(" * %s", arc_name) if missing_out_testcases and task_type != 'communication': pretty = ", ".join(sorted(missing_out_testcases)[:4]) remain = len(missing_out_testcases) - 4 if remain > 0: pretty += (", (%d more files)" % remain) logger.warning("missing output: %s", pretty) logger.info("=================%s============", "=" * len(name)) logger.info("task parameters loaded") return db_task