feat: LLM generated convert function
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				build / build (push) Successful in 1m3s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	build / build (push) Successful in 1m3s
				
			This commit is contained in:
		
							parent
							
								
									228488cbf2
								
							
						
					
					
						commit
						8bf0f7cfff
					
				
							
								
								
									
										61
									
								
								joj3_config_generator/convert.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								joj3_config_generator/convert.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,61 @@ | |||
| from joj3_config_generator.models import ( | ||||
|     Cmd, | ||||
|     CmdFile, | ||||
|     ExecutorConfig, | ||||
|     ExecutorWithConfig, | ||||
|     ParserConfig, | ||||
|     Repo, | ||||
|     ResultConfig, | ||||
|     Stage, | ||||
|     StageConfig, | ||||
|     Task, | ||||
|     TeapotConfig, | ||||
| ) | ||||
| 
 | ||||
| 
 | ||||
| # FIXME: LLM generated convert function, only for demostration | ||||
| def convert(repo_conf: Repo, task_conf: Task) -> ResultConfig: | ||||
|     # Create the base ResultConf object | ||||
|     result_conf = ResultConfig( | ||||
|         name=task_conf.task, | ||||
|         log_path=f"{task_conf.task.replace(' ', '_')}.log", | ||||
|         expire_unix_timestamp=( | ||||
|             int(task_conf.release.deadline.timestamp()) | ||||
|             if task_conf.release.deadline | ||||
|             else -1 | ||||
|         ), | ||||
|         stage=StageConfig(stages=[], sandbox_token=repo_conf.sandbox_token), | ||||
|         teapot=TeapotConfig(), | ||||
|     ) | ||||
| 
 | ||||
|     # Convert each stage in the task configuration | ||||
|     for task_stage in task_conf.stages: | ||||
|         executor_with_config = ExecutorWithConfig( | ||||
|             default=Cmd( | ||||
|                 args=task_stage.command.split(), | ||||
|                 copy_in={file: CmdFile(src=file) for file in task_stage.files.import_}, | ||||
|                 copy_out_cached=task_stage.files.export, | ||||
|             ), | ||||
|             cases=[],  # You can add cases if needed | ||||
|         ) | ||||
|         conf_stage = Stage( | ||||
|             name=task_stage.name, | ||||
|             group=task_conf.task, | ||||
|             executor=ExecutorConfig( | ||||
|                 name="sandbox", | ||||
|                 with_=executor_with_config, | ||||
|             ), | ||||
|             parsers=[ | ||||
|                 ParserConfig(name=parser, with_={}) for parser in task_stage.parsers | ||||
|             ], | ||||
|         ) | ||||
| 
 | ||||
|         if "result-detail" in task_stage.parsers: | ||||
|             result_detail_parser = next( | ||||
|                 p for p in conf_stage.parsers if p.name == "result-detail" | ||||
|             ) | ||||
|             result_detail_parser.with_.update(task_stage.result_detail) | ||||
| 
 | ||||
|         result_conf.stage.stages.append(conf_stage) | ||||
| 
 | ||||
|     return result_conf | ||||
|  | @ -1,3 +1,5 @@ | |||
| from pathlib import Path | ||||
| 
 | ||||
| import inquirer | ||||
| import typer | ||||
| 
 | ||||
|  | @ -7,9 +9,9 @@ app = typer.Typer(add_completion=False) | |||
| 
 | ||||
| 
 | ||||
| @app.command() | ||||
| def create() -> None: | ||||
| def create(toml: typer.FileTextWrite) -> None: | ||||
|     """ | ||||
|     Create a new JOJ3 config file | ||||
|     Create a new JOJ3 toml config file | ||||
|     """ | ||||
|     logger.info("Creating") | ||||
|     questions = [ | ||||
|  | @ -24,8 +26,16 @@ def create() -> None: | |||
| 
 | ||||
| 
 | ||||
| @app.command() | ||||
| def convert() -> None: | ||||
| def convert_joj1(yaml: typer.FileText, toml: typer.FileTextWrite) -> None: | ||||
|     """ | ||||
|     Convert a JOJ1 config file to JOJ3 config file | ||||
|     Convert a JOJ1 yaml config file to JOJ3 toml config file | ||||
|     """ | ||||
|     logger.info("Converting") | ||||
| 
 | ||||
| 
 | ||||
| @app.command() | ||||
| def convert(root_path: Path = Path(".")) -> None: | ||||
|     """ | ||||
|     Convert given dir of JOJ3 toml config files to JOJ3 json config files | ||||
|     """ | ||||
|     logger.info(f"Converting {root_path.absolute()}") | ||||
|  |  | |||
|  | @ -1,101 +0,0 @@ | |||
| from datetime import datetime | ||||
| from typing import List, Optional | ||||
| 
 | ||||
| import rtoml | ||||
| from pydantic import BaseModel, Field | ||||
| 
 | ||||
| 
 | ||||
| class RepoFiles(BaseModel): | ||||
|     whitelist_patterns: List[str] | ||||
|     whitelist_file: Optional[str] | ||||
|     required: List[str] | ||||
|     immutable: List[str] | ||||
| 
 | ||||
| 
 | ||||
| class Repo(BaseModel): | ||||
|     teaching_team: List[str] | ||||
|     max_size: float = Field(..., ge=0) | ||||
|     release_tags: List[str] | ||||
|     files: RepoFiles | ||||
| 
 | ||||
| 
 | ||||
| class ParserResultDetail(BaseModel): | ||||
|     time: bool = True  # Display run time | ||||
|     mem: bool = True  # Display memory usage | ||||
|     stderr: bool = False  # Display stderr messages | ||||
| 
 | ||||
| 
 | ||||
| class Files(BaseModel): | ||||
|     import_: List[str] = Field(alias="import") | ||||
|     export: List[str] | ||||
| 
 | ||||
| 
 | ||||
| class Stage(BaseModel): | ||||
|     name: str  # Stage name | ||||
|     command: str  # Command to run | ||||
|     files: Files  # Files to import and export | ||||
|     score: int  # Score for the task | ||||
|     parsers: List[str]  # List of parsers | ||||
|     result_detail: ParserResultDetail = ( | ||||
|         ParserResultDetail() | ||||
|     )  #  for result-detail parser | ||||
| 
 | ||||
| 
 | ||||
| class Release(BaseModel): | ||||
|     deadline: Optional[datetime]  # RFC 3339 formatted date-time with offset | ||||
| 
 | ||||
| 
 | ||||
| class Task(BaseModel): | ||||
|     task: str  # Task name (e.g., hw3 ex5) | ||||
|     release: Release  # Release configuration | ||||
|     stages: List[Stage]  # List of stage configurations | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     repo_toml = """ | ||||
| teaching_team = [ "prof_john", "ta_alice", "ta_bob" ] | ||||
| max_size = 50.5 | ||||
| release_tags = [ "v1.0", "v2.0", "final" ] | ||||
| 
 | ||||
| [files] | ||||
| whitelist_patterns = [ "*.py", "*.txt", "*.md" ] | ||||
| whitelist_file = ".whitelist" | ||||
| required = [ "main.py", "README.md" ] | ||||
| immutable = [ "config.yaml", "setup.py" ] | ||||
| """ | ||||
|     task_toml = """ | ||||
| task = "hw3 ex5" | ||||
| 
 | ||||
| [release] | ||||
| deadline = "2024-10-18T23:59:00+08:00" | ||||
| 
 | ||||
| [[stages]] | ||||
| name = "judge_base" | ||||
| command = "./matlab-joj ./h3/ex5.m" | ||||
| score = 100 | ||||
| parsers = [ "diff", "result-detail" ] | ||||
| 
 | ||||
| files.import = [ "tools/matlab-joj", "tools/matlab_formatter.py" ] | ||||
| files.export = [ "output/ex5_results.txt", "output/ex5_logs.txt" ] | ||||
| 
 | ||||
| result_detail.time = false | ||||
| result_detail.mem = false | ||||
| result_detail.stderr = true | ||||
| 
 | ||||
| [[stages]] | ||||
| name = "judge_base2" | ||||
| command = "./matlab-joj ./h3/ex5.m" | ||||
| score = 80 | ||||
| parsers = [ "diff", "result-detail" ] | ||||
| 
 | ||||
| files.import = [ "tools/matlab-joj", "tools/matlab_formatter.py" ] | ||||
| files.export = [ "output/ex5_results2.txt", "output/ex5_logs2.txt" ] | ||||
| 
 | ||||
| result_detail.time = true | ||||
| result_detail.mem = true | ||||
| result_detail.stderr = false | ||||
| """ | ||||
|     repo_obj = rtoml.loads(repo_toml) | ||||
|     task_obj = rtoml.loads(task_toml) | ||||
|     print(Repo(**repo_obj)) | ||||
|     print(Task(**task_obj)) | ||||
							
								
								
									
										11
									
								
								joj3_config_generator/models/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								joj3_config_generator/models/__init__.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | |||
| from joj3_config_generator.models.repo import Repo as Repo | ||||
| from joj3_config_generator.models.result import Cmd as Cmd | ||||
| from joj3_config_generator.models.result import CmdFile as CmdFile | ||||
| from joj3_config_generator.models.result import ExecutorConfig as ExecutorConfig | ||||
| from joj3_config_generator.models.result import ExecutorWithConfig as ExecutorWithConfig | ||||
| from joj3_config_generator.models.result import ParserConfig as ParserConfig | ||||
| from joj3_config_generator.models.result import ResultConfig as ResultConfig | ||||
| from joj3_config_generator.models.result import Stage as Stage | ||||
| from joj3_config_generator.models.result import StageConfig as StageConfig | ||||
| from joj3_config_generator.models.result import TeapotConfig as TeapotConfig | ||||
| from joj3_config_generator.models.task import Task as Task | ||||
							
								
								
									
										18
									
								
								joj3_config_generator/models/repo.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								joj3_config_generator/models/repo.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | |||
| from typing import Optional | ||||
| 
 | ||||
| from pydantic import BaseModel, Field | ||||
| 
 | ||||
| 
 | ||||
| class RepoFiles(BaseModel): | ||||
|     whitelist_patterns: list[str] | ||||
|     whitelist_file: Optional[str] | ||||
|     required: list[str] | ||||
|     immutable: list[str] | ||||
| 
 | ||||
| 
 | ||||
| class Repo(BaseModel): | ||||
|     teaching_team: list[str] | ||||
|     max_size: float = Field(..., ge=0) | ||||
|     release_tags: list[str] | ||||
|     files: RepoFiles | ||||
|     sandbox_token: str | ||||
							
								
								
									
										135
									
								
								joj3_config_generator/models/result.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								joj3_config_generator/models/result.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,135 @@ | |||
| from typing import Any, Optional | ||||
| 
 | ||||
| import rtoml | ||||
| from pydantic import BaseModel, Field | ||||
| 
 | ||||
| 
 | ||||
| class CmdFile(BaseModel): | ||||
|     src: Optional[str] = None | ||||
|     content: Optional[str] = None | ||||
|     file_id: Optional[str] = Field(None, serialization_alias="fileId") | ||||
|     name: Optional[str] = None | ||||
|     max: Optional[int] = None | ||||
|     symlink: Optional[str] = None | ||||
|     stream_in: bool = Field(False, serialization_alias="streamIn") | ||||
|     stream_out: bool = Field(False, serialization_alias="streamOut") | ||||
|     pipe: bool = False | ||||
| 
 | ||||
| 
 | ||||
| class Cmd(BaseModel): | ||||
|     args: list[str] | ||||
|     env: list[str] = [] | ||||
|     stdin: Optional[CmdFile] = None | ||||
|     stdout: Optional[CmdFile] = None | ||||
|     stderr: Optional[CmdFile] = None | ||||
|     cpu_limit: int = Field(0, serialization_alias="cpuLimit") | ||||
|     real_cpu_limit: int = Field(0, serialization_alias="realCpuLimit") | ||||
|     clock_limit: int = Field(0, serialization_alias="clockLimit") | ||||
|     memory_limit: int = Field(0, serialization_alias="memoryLimit") | ||||
|     stack_limit: int = Field(0, serialization_alias="stackLimit") | ||||
|     proc_limit: int = Field(0, serialization_alias="procLimit") | ||||
|     cpu_rate_limit: int = Field(0, serialization_alias="cpuRateLimit") | ||||
|     cpu_set_limit: str = Field("", serialization_alias="cpuSetLimit") | ||||
|     copy_in: dict[str, CmdFile] = Field({}, serialization_alias="copyIn") | ||||
|     copy_in_cached: dict[str, str] = Field({}, serialization_alias="copyInCached") | ||||
|     copy_in_dir: str = Field("", serialization_alias="copyInDir") | ||||
|     copy_out: list[str] = Field([], serialization_alias="copyOut") | ||||
|     copy_out_cached: list[str] = Field([], serialization_alias="copyOutCached") | ||||
|     copy_out_max: int = Field(0, serialization_alias="copyOutMax") | ||||
|     copy_out_dir: str = Field("", serialization_alias="copyOutDir") | ||||
|     tty: bool = False | ||||
|     strict_memory_limit: bool = Field(False, serialization_alias="strictMemoryLimit") | ||||
|     data_segment_limit: bool = Field(False, serialization_alias="dataSegmentLimit") | ||||
|     address_space_limit: bool = Field(False, serialization_alias="addressSpaceLimit") | ||||
| 
 | ||||
| 
 | ||||
| class OptionalCmd(BaseModel): | ||||
|     args: Optional[list[str]] = None | ||||
|     env: Optional[list[str]] = None | ||||
|     stdin: Optional[CmdFile] = None | ||||
|     stdout: Optional[CmdFile] = None | ||||
|     stderr: Optional[CmdFile] = None | ||||
|     cpu_limit: Optional[int] = Field(None, serialization_alias="cpuLimit") | ||||
|     real_cpu_limit: Optional[int] = Field(None, serialization_alias="realCpuLimit") | ||||
|     clock_limit: Optional[int] = Field(None, serialization_alias="clockLimit") | ||||
|     memory_limit: Optional[int] = Field(None, serialization_alias="memoryLimit") | ||||
|     stack_limit: Optional[int] = Field(None, serialization_alias="stackLimit") | ||||
|     proc_limit: Optional[int] = Field(None, serialization_alias="procLimit") | ||||
|     cpu_rate_limit: Optional[int] = Field(None, serialization_alias="cpuRateLimit") | ||||
|     cpu_set_limit: Optional[str] = Field(None, serialization_alias="cpuSetLimit") | ||||
|     copy_in: Optional[dict[str, CmdFile]] = Field(None, serialization_alias="copyIn") | ||||
|     copy_in_cached: Optional[dict[str, str]] = Field( | ||||
|         None, serialization_alias="copyInCached" | ||||
|     ) | ||||
|     copy_in_dir: Optional[str] = Field(None, serialization_alias="copyInDir") | ||||
|     copy_out: Optional[list[str]] = Field(None, serialization_alias="copyOut") | ||||
|     copy_out_cached: Optional[list[str]] = Field( | ||||
|         None, serialization_alias="copyOutCached" | ||||
|     ) | ||||
|     copy_out_max: Optional[int] = Field(None, serialization_alias="copyOutMax") | ||||
|     copy_out_dir: Optional[str] = Field(None, serialization_alias="copyOutDir") | ||||
|     tty: Optional[bool] = None | ||||
|     strict_memory_limit: Optional[bool] = Field( | ||||
|         None, serialization_alias="strictMemoryLimit" | ||||
|     ) | ||||
|     data_segment_limit: Optional[bool] = Field( | ||||
|         None, serialization_alias="dataSegmentLimit" | ||||
|     ) | ||||
|     address_space_limit: Optional[bool] = Field( | ||||
|         None, serialization_alias="addressSpaceLimit" | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| class Stage(BaseModel): | ||||
|     name: str | ||||
|     group: str | ||||
|     executor: "ExecutorConfig" | ||||
|     parsers: list["ParserConfig"] | ||||
| 
 | ||||
| 
 | ||||
| class ExecutorWithConfig(BaseModel): | ||||
|     default: Cmd | ||||
|     cases: list[OptionalCmd] | ||||
| 
 | ||||
| 
 | ||||
| class ExecutorConfig(BaseModel): | ||||
|     name: str | ||||
|     with_: ExecutorWithConfig = Field(..., serialization_alias="with") | ||||
| 
 | ||||
| 
 | ||||
| class ParserConfig(BaseModel): | ||||
|     name: str | ||||
|     with_: dict[str, Any] = Field(..., serialization_alias="with") | ||||
| 
 | ||||
| 
 | ||||
| class StageConfig(BaseModel): | ||||
|     sandbox_exec_server: str = Field( | ||||
|         "172.17.0.1:5051", serialization_alias="sandboxExecServer" | ||||
|     ) | ||||
|     sandbox_token: str = Field("", serialization_alias="sandboxToken") | ||||
|     output_path: str = Field( | ||||
|         "/tmp/joj3_result.json", serialization_alias="outputPath" | ||||
|     )  # nosec: B108 | ||||
|     stages: list[Stage] | ||||
| 
 | ||||
| 
 | ||||
| class TeapotConfig(BaseModel): | ||||
|     log_path: str = Field( | ||||
|         "/home/tt/.cache/joint-teapot-debug.log", serialization_alias="logPath" | ||||
|     ) | ||||
|     scoreboard_path: str = Field("scoreboard.csv", serialization_alias="scoreboardPath") | ||||
|     failed_table_path: str = Field( | ||||
|         "failed-table.md", serialization_alias="failedTablePath" | ||||
|     ) | ||||
|     grading_repo_name: str = Field("", serialization_alias="gradingRepoName") | ||||
|     skip_issue: bool = Field(False, serialization_alias="skipIssue") | ||||
|     skip_scoreboard: bool = Field(False, serialization_alias="skipScoreboard") | ||||
|     skip_failed_table: bool = Field(False, serialization_alias="skipFailedTable") | ||||
| 
 | ||||
| 
 | ||||
| class ResultConfig(BaseModel): | ||||
|     name: str = "unknown" | ||||
|     log_path: str = Field("", serialization_alias="logPath") | ||||
|     expire_unix_timestamp: int = Field(-1, serialization_alias="expireUnixTimestamp") | ||||
|     stage: StageConfig | ||||
|     teapot: TeapotConfig | ||||
							
								
								
									
										37
									
								
								joj3_config_generator/models/task.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								joj3_config_generator/models/task.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,37 @@ | |||
| from datetime import datetime | ||||
| from typing import Optional | ||||
| 
 | ||||
| from pydantic import BaseModel, Field | ||||
| 
 | ||||
| 
 | ||||
| class ParserResultDetail(BaseModel): | ||||
|     time: bool = True  # Display run time | ||||
|     mem: bool = True  # Display memory usage | ||||
|     stdout: bool = False  # Display stdout messages | ||||
|     stderr: bool = False  # Display stderr messages | ||||
| 
 | ||||
| 
 | ||||
| class Files(BaseModel): | ||||
|     import_: list[str] = Field(alias="import") | ||||
|     export: list[str] | ||||
| 
 | ||||
| 
 | ||||
| class Stage(BaseModel): | ||||
|     name: str  # Stage name | ||||
|     command: str  # Command to run | ||||
|     files: Files  # Files to import and export | ||||
|     score: int  # Score for the task | ||||
|     parsers: list[str]  # list of parsers | ||||
|     result_detail: ParserResultDetail = ( | ||||
|         ParserResultDetail() | ||||
|     )  #  for result-detail parser | ||||
| 
 | ||||
| 
 | ||||
| class Release(BaseModel): | ||||
|     deadline: Optional[datetime]  # RFC 3339 formatted date-time with offset | ||||
| 
 | ||||
| 
 | ||||
| class Task(BaseModel): | ||||
|     task: str  # Task name (e.g., hw3 ex5) | ||||
|     release: Release  # Release configuration | ||||
|     stages: list[Stage]  # list of stage configurations | ||||
							
								
								
									
										10
									
								
								tests/basic/repo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								tests/basic/repo.toml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | |||
| teaching_team = ["prof_john", "ta_alice", "ta_bob"] | ||||
| max_size = 50.5 | ||||
| release_tags = ["v1.0", "v2.0", "final"] | ||||
| sandbox_token = "test" | ||||
| 
 | ||||
| [files] | ||||
| whitelist_patterns = ["*.py", "*.txt", "*.md"] | ||||
| whitelist_file = ".whitelist" | ||||
| required = ["main.py", "README.md"] | ||||
| immutable = ["config.yaml", "setup.py"] | ||||
							
								
								
									
										181
									
								
								tests/basic/task.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								tests/basic/task.json
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,181 @@ | |||
| { | ||||
|     "name": "hw3 ex5", | ||||
|     "logPath": "hw3_ex5.log", | ||||
|     "expireUnixTimestamp": 1729267140, | ||||
|     "stage": { | ||||
|         "sandboxExecServer": "172.17.0.1:5051", | ||||
|         "sandboxToken": "test", | ||||
|         "outputPath": "/tmp/joj3_result.json", | ||||
|         "stages": [ | ||||
|             { | ||||
|                 "name": "judge_base", | ||||
|                 "group": "hw3 ex5", | ||||
|                 "executor": { | ||||
|                     "name": "sandbox", | ||||
|                     "with": { | ||||
|                         "default": { | ||||
|                             "args": [ | ||||
|                                 "./matlab-joj", | ||||
|                                 "./h3/ex5.m" | ||||
|                             ], | ||||
|                             "env": [], | ||||
|                             "stdin": null, | ||||
|                             "stdout": null, | ||||
|                             "stderr": null, | ||||
|                             "cpuLimit": 0, | ||||
|                             "realCpuLimit": 0, | ||||
|                             "clockLimit": 0, | ||||
|                             "memoryLimit": 0, | ||||
|                             "stackLimit": 0, | ||||
|                             "procLimit": 0, | ||||
|                             "cpuRateLimit": 0, | ||||
|                             "cpuSetLimit": "", | ||||
|                             "copyIn": { | ||||
|                                 "tools/matlab-joj": { | ||||
|                                     "src": "tools/matlab-joj", | ||||
|                                     "content": null, | ||||
|                                     "fileId": null, | ||||
|                                     "name": null, | ||||
|                                     "max": null, | ||||
|                                     "symlink": null, | ||||
|                                     "streamIn": false, | ||||
|                                     "streamOut": false, | ||||
|                                     "pipe": false | ||||
|                                 }, | ||||
|                                 "tools/matlab_formatter.py": { | ||||
|                                     "src": "tools/matlab_formatter.py", | ||||
|                                     "content": null, | ||||
|                                     "fileId": null, | ||||
|                                     "name": null, | ||||
|                                     "max": null, | ||||
|                                     "symlink": null, | ||||
|                                     "streamIn": false, | ||||
|                                     "streamOut": false, | ||||
|                                     "pipe": false | ||||
|                                 } | ||||
|                             }, | ||||
|                             "copyInCached": {}, | ||||
|                             "copyInDir": "", | ||||
|                             "copyOut": [], | ||||
|                             "copyOutCached": [ | ||||
|                                 "output/ex5_results.txt", | ||||
|                                 "output/ex5_logs.txt" | ||||
|                             ], | ||||
|                             "copyOutMax": 0, | ||||
|                             "copyOutDir": "", | ||||
|                             "tty": false, | ||||
|                             "strictMemoryLimit": false, | ||||
|                             "dataSegmentLimit": false, | ||||
|                             "addressSpaceLimit": false | ||||
|                         }, | ||||
|                         "cases": [] | ||||
|                     } | ||||
|                 }, | ||||
|                 "parsers": [ | ||||
|                     { | ||||
|                         "name": "diff", | ||||
|                         "with": {} | ||||
|                     }, | ||||
|                     { | ||||
|                         "name": "result-detail", | ||||
|                         "with": { | ||||
|                             "time": false, | ||||
|                             "mem": false, | ||||
|                             "stdout": false, | ||||
|                             "stderr": true | ||||
|                         } | ||||
|                     } | ||||
|                 ] | ||||
|             }, | ||||
|             { | ||||
|                 "name": "judge_base2", | ||||
|                 "group": "hw3 ex5", | ||||
|                 "executor": { | ||||
|                     "name": "sandbox", | ||||
|                     "with": { | ||||
|                         "default": { | ||||
|                             "args": [ | ||||
|                                 "./matlab-joj", | ||||
|                                 "./h3/ex5.m" | ||||
|                             ], | ||||
|                             "env": [], | ||||
|                             "stdin": null, | ||||
|                             "stdout": null, | ||||
|                             "stderr": null, | ||||
|                             "cpuLimit": 0, | ||||
|                             "realCpuLimit": 0, | ||||
|                             "clockLimit": 0, | ||||
|                             "memoryLimit": 0, | ||||
|                             "stackLimit": 0, | ||||
|                             "procLimit": 0, | ||||
|                             "cpuRateLimit": 0, | ||||
|                             "cpuSetLimit": "", | ||||
|                             "copyIn": { | ||||
|                                 "tools/matlab-joj": { | ||||
|                                     "src": "tools/matlab-joj", | ||||
|                                     "content": null, | ||||
|                                     "fileId": null, | ||||
|                                     "name": null, | ||||
|                                     "max": null, | ||||
|                                     "symlink": null, | ||||
|                                     "streamIn": false, | ||||
|                                     "streamOut": false, | ||||
|                                     "pipe": false | ||||
|                                 }, | ||||
|                                 "tools/matlab_formatter.py": { | ||||
|                                     "src": "tools/matlab_formatter.py", | ||||
|                                     "content": null, | ||||
|                                     "fileId": null, | ||||
|                                     "name": null, | ||||
|                                     "max": null, | ||||
|                                     "symlink": null, | ||||
|                                     "streamIn": false, | ||||
|                                     "streamOut": false, | ||||
|                                     "pipe": false | ||||
|                                 } | ||||
|                             }, | ||||
|                             "copyInCached": {}, | ||||
|                             "copyInDir": "", | ||||
|                             "copyOut": [], | ||||
|                             "copyOutCached": [ | ||||
|                                 "output/ex5_results2.txt", | ||||
|                                 "output/ex5_logs2.txt" | ||||
|                             ], | ||||
|                             "copyOutMax": 0, | ||||
|                             "copyOutDir": "", | ||||
|                             "tty": false, | ||||
|                             "strictMemoryLimit": false, | ||||
|                             "dataSegmentLimit": false, | ||||
|                             "addressSpaceLimit": false | ||||
|                         }, | ||||
|                         "cases": [] | ||||
|                     } | ||||
|                 }, | ||||
|                 "parsers": [ | ||||
|                     { | ||||
|                         "name": "diff", | ||||
|                         "with": {} | ||||
|                     }, | ||||
|                     { | ||||
|                         "name": "result-detail", | ||||
|                         "with": { | ||||
|                             "time": true, | ||||
|                             "mem": true, | ||||
|                             "stdout": false, | ||||
|                             "stderr": false | ||||
|                         } | ||||
|                     } | ||||
|                 ] | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     "teapot": { | ||||
|         "logPath": "/home/tt/.cache/joint-teapot-debug.log", | ||||
|         "scoreboardPath": "scoreboard.csv", | ||||
|         "failedTablePath": "failed-table.md", | ||||
|         "gradingRepoName": "", | ||||
|         "skipIssue": false, | ||||
|         "skipScoreboard": false, | ||||
|         "skipFailedTable": false | ||||
|     } | ||||
| } | ||||
							
								
								
									
										30
									
								
								tests/basic/task.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								tests/basic/task.toml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | |||
| task = "hw3 ex5" | ||||
| 
 | ||||
| [release] | ||||
| deadline = "2024-10-18T23:59:00+08:00" | ||||
| 
 | ||||
| [[stages]] | ||||
| name = "judge_base" | ||||
| command = "./matlab-joj ./h3/ex5.m" | ||||
| score = 100 | ||||
| parsers = ["diff", "result-detail"] | ||||
| 
 | ||||
| files.import = ["tools/matlab-joj", "tools/matlab_formatter.py"] | ||||
| files.export = ["output/ex5_results.txt", "output/ex5_logs.txt"] | ||||
| 
 | ||||
| result_detail.time = false | ||||
| result_detail.mem = false | ||||
| result_detail.stderr = true | ||||
| 
 | ||||
| [[stages]] | ||||
| name = "judge_base2" | ||||
| command = "./matlab-joj ./h3/ex5.m" | ||||
| score = 80 | ||||
| parsers = ["diff", "result-detail"] | ||||
| 
 | ||||
| files.import = ["tools/matlab-joj", "tools/matlab_formatter.py"] | ||||
| files.export = ["output/ex5_results2.txt", "output/ex5_logs2.txt"] | ||||
| 
 | ||||
| result_detail.time = true | ||||
| result_detail.mem = true | ||||
| result_detail.stderr = false | ||||
							
								
								
									
										23
									
								
								tests/conftest.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								tests/conftest.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,23 @@ | |||
| import os | ||||
| from typing import Any | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
| from joj3_config_generator.models import Repo, Task | ||||
| from tests.utils import read_convert_files | ||||
| 
 | ||||
| 
 | ||||
| def get_test_cases() -> list[tuple[str, Repo, Task, dict[str, Any]]]: | ||||
|     test_cases = [] | ||||
|     tests_dir = os.path.dirname(os.path.realpath(__file__)) | ||||
|     for dir_name in os.listdir(tests_dir): | ||||
|         dir_path = os.path.join(tests_dir, dir_name) | ||||
|         if os.path.isdir(dir_path) and dir_name != "__pycache__": | ||||
|             repo, task, expected_result = read_convert_files(dir_path) | ||||
|             test_cases.append((dir_name, repo, task, expected_result)) | ||||
|     return test_cases | ||||
| 
 | ||||
| 
 | ||||
| @pytest.fixture(params=get_test_cases(), ids=lambda x: x[0]) | ||||
| def test_case(request: pytest.FixtureRequest) -> tuple[Repo, Task, dict[str, Any]]: | ||||
|     return request.param[1:]  # return repo, task, expected_result | ||||
|  | @ -1,17 +0,0 @@ | |||
| # from xxx import generate | ||||
| 
 | ||||
| 
 | ||||
| from typing import Any | ||||
| 
 | ||||
| import pytest | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.xfail(strict=True) | ||||
| def test_generate() -> None: | ||||
|     generate = lambda x: x  # TODO: real generate function imported | ||||
|     data_input: dict[Any, Any] = {}  # TODO: load real input from some file | ||||
|     data_output: dict[Any, Any] = generate(data_input) | ||||
|     expected_output: dict[Any, Any] = { | ||||
|         "a": "b" | ||||
|     }  # TODO: load real output from some file | ||||
|     assert data_output == expected_output | ||||
							
								
								
									
										10
									
								
								tests/test_all_cases.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								tests/test_all_cases.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | |||
| from typing import Any | ||||
| 
 | ||||
| from joj3_config_generator.convert import convert | ||||
| from joj3_config_generator.models import Repo, Task | ||||
| 
 | ||||
| 
 | ||||
| def test_convert(test_case: tuple[Repo, Task, dict[str, Any]]) -> None: | ||||
|     repo, task, expected_result = test_case | ||||
|     result = convert(repo, task).model_dump(by_alias=True) | ||||
|     assert result == expected_result | ||||
							
								
								
									
										22
									
								
								tests/utils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								tests/utils.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | |||
| import json | ||||
| import os | ||||
| from typing import Any | ||||
| 
 | ||||
| import rtoml | ||||
| 
 | ||||
| from joj3_config_generator.models import Repo, Task | ||||
| 
 | ||||
| 
 | ||||
| def read_convert_files(root: str) -> tuple[Repo, Task, dict[str, Any]]: | ||||
|     repo_toml_path = os.path.join(root, "repo.toml") | ||||
|     task_toml_path = os.path.join(root, "task.toml") | ||||
|     result_json_path = os.path.join(root, "task.json") | ||||
|     with open(repo_toml_path) as repo_file: | ||||
|         repo_toml = repo_file.read() | ||||
|     with open(task_toml_path) as task_file: | ||||
|         task_toml = task_file.read() | ||||
|     with open(result_json_path) as result_file: | ||||
|         expected_result: dict[str, Any] = json.load(result_file) | ||||
|     repo_obj = rtoml.loads(repo_toml) | ||||
|     task_obj = rtoml.loads(task_toml) | ||||
|     return Repo(**repo_obj), Task(**task_obj), expected_result | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user