JOJ3-config-generator/joj3_config_generator/models/task.py
李衍志523370910113 9213e57ca3
All checks were successful
build / build (push) Successful in 2m32s
dev (#10)
## What I have done:

- basic generation of json files
  - supported parsers:
    - healthcheck
    - result-detail
    - result-status
    - file
    - log
    - dummy
    - keyword (keyword, clangtidy, cppcheck, cpplint)
    - diff
- `convert` functions is mature, tested in engr151-24fa last two homeworks and engr151-24fa p3
- teapot and healthcheck should be up to date

## TODO

- update all new comming parsers in future.

@bomingzh Could you please help me do a code review first then I shall fix all things and rebase? I checked the source code of JOJ3 currently, and find we have more parsers, such as plugin and tierscore, I haven''t added them yet, and some of the keys might have changed such as clang-tidy, can you help me take a look if current version is still up to date? I ll redo the fix tomorrow

Co-authored-by: Boming Zhang <bomingzh@sjtu.edu.cn>
Reviewed-on: #10
Reviewed-by: 张泊明518370910136 <bomingzh@sjtu.edu.cn>
Co-authored-by: jon-lee <jon-lee@sjtu.edu.cn>
Co-committed-by: jon-lee <jon-lee@sjtu.edu.cn>
2025-03-05 16:20:38 +08:00

154 lines
4.0 KiB
Python

from datetime import datetime, timedelta
from enum import Enum
from pathlib import Path
from typing import Any, Dict, List, Type
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
from joj3_config_generator.models.common import Memory, Time
from joj3_config_generator.models.const import (
DEFAULT_CPU_LIMIT,
DEFAULT_FILE_LIMIT,
DEFAULT_MEMORY_LIMIT,
)
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
exit_status: bool = True
class ParserFile(BaseModel):
name: str = ""
class ParserLog(BaseModel):
filename: str
msg: str = ""
level: str = ""
class ParserDummy(BaseModel):
comment: str = ""
score: int = 0
force_quit: bool = False
class ParserKeyword(BaseModel):
keyword: List[str] = []
weight: List[int] = []
class Outputs(BaseModel):
score: int = 0
ignore_spaces: bool = True
hide: bool = False
force_quit: bool = False
class ParserDiff(BaseModel):
output: Outputs = Outputs()
class Files(BaseModel):
import_: List[str] = Field([], alias="import")
export: List[str] = []
class Limit(BaseModel):
mem: int = DEFAULT_MEMORY_LIMIT
cpu: int = DEFAULT_CPU_LIMIT
stdout: int = DEFAULT_FILE_LIMIT
stderr: int = DEFAULT_FILE_LIMIT
model_config = ConfigDict(validate_assignment=True)
@field_validator("cpu", mode="before")
@classmethod
def ensure_time(cls, v: Any) -> Time:
if isinstance(v, str):
return Time(v)
raise ValueError("Must be a string")
@field_validator("mem", "stdout", "stderr", mode="before")
@classmethod
def ensure_mem(cls, v: Any) -> Memory:
if isinstance(v, str):
return Memory(v)
raise ValueError("Must be a string")
class Parser(str, Enum):
CLANG_TIDY = "clangtidy"
CPPCHECK = "cppcheck"
CPPLINT = "cpplint"
KEYWORD = "keyword"
RESULT_STATUS = "result-status"
RESULT_DETAIL = "result-detail"
DUMMY = "dummy"
FILE = "file"
DIFF = "diff"
class Stage(BaseModel):
name: str = "" # Stage name
env: List[str] = []
command: str = "" # Command to run
files: Files = Files()
in_: str = Field("", alias="in")
out_: str = Field("", alias="out")
score: int = 0
parsers: List[Parser] = [] # list of parsers
limit: Limit = Limit()
dummy: ParserDummy = ParserDummy()
result_status: ParserDummy = Field(ParserDummy(), alias="result-status")
keyword: ParserKeyword = ParserKeyword()
clangtidy: ParserKeyword = ParserKeyword()
cppcheck: ParserKeyword = ParserKeyword()
cpplint: ParserKeyword = ParserKeyword()
result_detail: ParserResultDetail = Field(
ParserResultDetail(), alias="result-detail"
)
file: ParserFile = ParserFile()
skip: List[str] = []
# cases related
cases: Dict[str, "Stage"] = {}
diff: ParserDiff = ParserDiff()
model_config = ConfigDict(extra="allow")
@model_validator(mode="before")
@classmethod
def gather_cases(cls: Type["Stage"], values: Dict[str, Any]) -> Dict[str, Any]:
cases = {k: v for k, v in values.items() if k.startswith("case")}
for key in cases:
values.pop(key)
values["cases"] = {k: v for k, v in cases.items()}
return values
class Release(BaseModel):
end_time: datetime = datetime.now() + timedelta(
days=365
) # RFC 3339 formatted date-time with offset
begin_time: datetime = datetime.fromtimestamp(
0
) # RFC 3339 formatted date-time with offset
class Task(BaseModel):
type_: str = Field("unknown", serialization_alias="type", validation_alias="type")
name: str = "unknown"
class Config(BaseModel):
root: Path = Path(".")
path: Path = Path("task.toml")
task: Task = Task() # Task name (e.g., hw3 ex5)
release: Release = Release() # Release configuration
stages: List[Stage] = [] # list of stage configurations