33import os .path
44from abc import ABC , abstractmethod
55from enum import Enum
6- from typing import List , Dict , Optional , Union , Any
7-
86from task_maker .config import Config
9- from task_maker .task_maker_frontend import Frontend
10- from task_maker .source_file import SourceFile
117from task_maker .languages import GraderInfo , LanguageManager , Dependency , \
128 Language
9+ from task_maker .source_file import SourceFile
10+ from task_maker .task_maker_frontend import Frontend
11+ from typing import List , Dict , Optional , Union , Any
1312
1413# Name of the input file on disk when doing the validation process
1514VALIDATION_INPUT_NAME = "tm_input_file"
@@ -42,6 +41,7 @@ class Constraint:
4241 """
4342 Defines a CONSTRAINT in a cases.gen file (TM-format).
4443 """
44+
4545 def __init__ (self , name : str , lower_bound : Optional [float ],
4646 upper_bound : Optional [float ], more_or_equal : bool ,
4747 less_or_equal : bool ):
@@ -88,22 +88,24 @@ class Generator:
8888 a specific SourceFile. Optionally can contain a specification about its
8989 parameters (the names of them, in order).
9090 """
91+
9192 def __init__ (self , name : str , source_file : Optional [SourceFile ],
9293 args_spec : Optional [List [str ]]):
9394 self .name = name
9495 self .args_spec = args_spec
9596 self .source_file = source_file
9697
9798 def __repr__ (self ):
98- return "<Generator %s [%s]>" % (self .name ,
99- " " . join ( self . args_spec or []))
99+ return "<Generator %s [%s]>" % (self .name , " " . join ( self . args_spec
100+ or []))
100101
101102
102103class Validator :
103104 """
104105 Defines a validator of testcases. Like Generator it's composed of a name, a
105106 SourceFile and optionally a list with the names of the parameters
106107 """
108+
107109 def __init__ (self , name : str , source_file : SourceFile ,
108110 args_spec : Optional [List [str ]]):
109111 self .name = name
@@ -140,6 +142,7 @@ class TestCase:
140142 the path of where to write the files to disk.
141143 Note that a generator and a static file cannot be specified together.
142144 """
145+
143146 def __init__ (self , generator : Optional [Generator ],
144147 validator : Optional [Validator ], generator_args : List [str ],
145148 extra_deps : List [Dependency ], input_file : Optional [str ],
@@ -169,6 +172,7 @@ class Subtask:
169172 ScoreMode is used with a max_score parameter. With TM-format it's also
170173 possible to specify some constraints for the problem variables.
171174 """
175+
172176 def __init__ (self , name : str , description : str , score_mode : ScoreMode ,
173177 max_score : float , testcases : Dict [int , TestCase ],
174178 constraints : List [Constraint ]):
@@ -188,6 +192,7 @@ class Task(ABC):
188192 Abstract class of a Task, each task format should derive from this base
189193 class.
190194 """
195+
191196 def __init__ (self , name : str , title : str ):
192197 self .name = name
193198 self .title = title
@@ -208,6 +213,7 @@ class IOITask(Task):
208213 The subtasks are 0-based numbered, the testcases as well but their numbers
209214 wont reset at each subtask. The time limit is expressed in seconds.
210215 """
216+
211217 def __init__ (self , name : str , title : str , subtasks : Dict [int , Subtask ],
212218 official_solution : Optional ["SourceFile" ],
213219 grader_map : Dict [Language , GraderInfo ],
@@ -228,6 +234,44 @@ def __init__(self, name: str, title: str, subtasks: Dict[int, Subtask],
228234 self .default_gen = None # type: Optional[Generator]
229235 self .default_val = None # type: Optional[Validator]
230236
237+ def to_dict (self ):
238+ return {
239+ "name" :
240+ self .name ,
241+ "title" :
242+ self .title ,
243+ "subtasks" : {
244+ st_num : {
245+ "name" : subtask .name ,
246+ "max_score" : subtask .max_score ,
247+ "cases" : {
248+ tc_num : {
249+ "generator" : testcase .generator .name ,
250+ "generator_path" :
251+ testcase .generator .source_file .path ,
252+ "args" : testcase .generator_args
253+ }
254+ for tc_num , testcase in subtask .testcases .items ()
255+ }
256+ }
257+ for st_num , subtask in self .subtasks .items ()
258+ },
259+ "official_solution" :
260+ self .official_solution .name if self .official_solution else None ,
261+ "checker" :
262+ self .checker .name if self .checker else None ,
263+ "time_limit" :
264+ self .time_limit ,
265+ "memory_limit" :
266+ self .memory_limit_kb ,
267+ "input_file" :
268+ self .input_file ,
269+ "output_file" :
270+ self .output_file ,
271+ "task_type" :
272+ self .task_type .name
273+ }
274+
231275 def __repr__ (self ):
232276 return "<Task name=%s title=%s>" % (self .name , self .title )
233277
@@ -241,6 +285,7 @@ class TerryTask(Task):
241285 An official solution can be provided, it will be compiled and put alongside
242286 the checker.
243287 """
288+
244289 def __init__ (self , name : str , title : str , max_score : float ):
245290 super ().__init__ (name , title )
246291 self .max_score = max_score
@@ -249,6 +294,24 @@ def __init__(self, name: str, title: str, max_score: float):
249294 self .official_solution = None # type: Optional[SourceFile]
250295 self .checker = None # type: SourceFile
251296
297+ def to_dict (self ):
298+ return {
299+ "name" :
300+ self .name ,
301+ "title" :
302+ self .title ,
303+ "max_score" :
304+ self .max_score ,
305+ "generator" :
306+ self .generator .path if self .generator else None ,
307+ "validator" :
308+ self .validator .path if self .validator else None ,
309+ "official_solution" :
310+ self .official_solution .path if self .official_solution else None ,
311+ "checker" :
312+ self .checker .path if self .checker else None ,
313+ }
314+
252315 def __repr__ (self ):
253316 return "<TerryTask name={} title={}>" .format (self .name , self .title )
254317
@@ -259,6 +322,7 @@ class TaskFormat(ABC):
259322 should derive from this class. The main function will call one of those
260323 abstract methods to do the action associated to this format.
261324 """
325+
262326 @staticmethod
263327 @abstractmethod
264328 def evaluate_task (frontend : Frontend , config : Config ):
@@ -430,8 +494,8 @@ def get_solutions(solutions: List[str], directory: str,
430494 paths .append ("{}{}*" .format (directory , sol ))
431495 solutions = list_files (paths )
432496 else :
433- solutions = list_files (
434- [ directory + "*" ], exclude = graders + [directory + "__init__.py" ])
497+ solutions = list_files ([ directory + "*" ],
498+ exclude = graders + [directory + "__init__.py" ])
435499 solutions = list (
436500 filter (lambda s : not s .startswith (directory + "." ), solutions ))
437501 return solutions
0 commit comments