From 3f0fdd816bb455c4e1d5e29ab305a120b867325a Mon Sep 17 00:00:00 2001 From: Boming Zhang Date: Wed, 17 Sep 2025 01:13:51 -0700 Subject: [PATCH] feat: strict mode toml loader --- joj3_config_generator/models/common.py | 5 +++++ joj3_config_generator/models/repo.py | 16 ++++++++-------- joj3_config_generator/models/task.py | 12 ++++++------ 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/joj3_config_generator/models/common.py b/joj3_config_generator/models/common.py index 438f77d..4c098a1 100644 --- a/joj3_config_generator/models/common.py +++ b/joj3_config_generator/models/common.py @@ -1,6 +1,7 @@ from typing import Union import humanfriendly +from pydantic import BaseModel, ConfigDict class Memory(int): @@ -17,3 +18,7 @@ class Time(int): parsed = humanfriendly.parse_timespan(value) * 1_000_000_000 # ns return super().__new__(cls, round(parsed)) return super().__new__(cls, value) + + +class StrictBaseModel(BaseModel): + model_config = ConfigDict(extra="forbid") diff --git a/joj3_config_generator/models/repo.py b/joj3_config_generator/models/repo.py index f20ac82..67d4e41 100644 --- a/joj3_config_generator/models/repo.py +++ b/joj3_config_generator/models/repo.py @@ -2,17 +2,17 @@ import os from pathlib import Path from typing import Any, List -from pydantic import AliasChoices, BaseModel, Field, field_validator, model_validator +from pydantic import AliasChoices, Field, field_validator, model_validator -from joj3_config_generator.models.common import Memory +from joj3_config_generator.models.common import Memory, StrictBaseModel -class Files(BaseModel): +class Files(StrictBaseModel): required: List[str] = [] immutable: List[str] = [] -class Groups(BaseModel): +class Groups(StrictBaseModel): name: List[str] = [] max_count: List[int] = Field( [], validation_alias=AliasChoices("max-count", "max_count") @@ -22,20 +22,20 @@ class Groups(BaseModel): ) -class Label(BaseModel): +class Label(StrictBaseModel): name: str = "Kind/Testing" color: str = "#795548" exclusive: bool = False -class Issue(BaseModel): +class Issue(StrictBaseModel): label: Label = Label() show_submitter: bool = Field( True, validation_alias=AliasChoices("show-submitter", "show_submitter") ) -class HealthCheck(BaseModel): +class HealthCheck(StrictBaseModel): score: int = 0 max_size: int = Field( Memory("10m"), validation_alias=AliasChoices("max-size", "max_size") @@ -56,7 +56,7 @@ class HealthCheck(BaseModel): raise ValueError(f'Must be a string, e.g., "256m" or "1g", but got {v}') -class Config(BaseModel): +class Config(StrictBaseModel): root: Path = Field(Path("."), exclude=True) path: Path = Field(Path("repo.toml"), exclude=True) diff --git a/joj3_config_generator/models/task.py b/joj3_config_generator/models/task.py index 7741bfd..f02cd26 100644 --- a/joj3_config_generator/models/task.py +++ b/joj3_config_generator/models/task.py @@ -13,7 +13,7 @@ from pydantic import ( model_validator, ) -from joj3_config_generator.models.common import Memory, Time +from joj3_config_generator.models.common import Memory, StrictBaseModel, Time from joj3_config_generator.models.const import ( DEFAULT_CASE_SCORE, DEFAULT_CLOCK_LIMIT_MULTIPLIER, @@ -183,7 +183,7 @@ class Parser(str, Enum): ELF = "elf" -class Case(BaseModel): +class Case(StrictBaseModel): env: List[str] = [] command: str = "" # Command to run files: StageFiles = StageFiles() @@ -236,7 +236,7 @@ class Stage(Case): return values -class Release(BaseModel): +class Release(StrictBaseModel): end_time: datetime = Field( datetime(1970, 1, 1, 0, 0, 0, tzinfo=timezone.utc), validation_alias=AliasChoices("end-time", "end_time"), @@ -247,17 +247,17 @@ class Release(BaseModel): ) # timestamp = 0, no begin time -class SubmissionTime(BaseModel): +class SubmissionTime(StrictBaseModel): begin: Optional[datetime] = None end: Optional[datetime] = None -class Penalties(BaseModel): +class Penalties(StrictBaseModel): hours: List[float] = [] factors: List[float] = [] -class Config(BaseModel): +class Config(StrictBaseModel): root: Path = Field(Path("."), exclude=True) path: Path = Field(Path("task.toml"), exclude=True) suffix: str = Field("", exclude=True)