## Problem Two gaps in the plugin: (1) contest pickers have no way to know whether a contest supports countdown (race), so the UI can't surface that affordance; (2) `:CP submit` hardcodes a single language ID per platform with no way to choose C++ standard or override the platform ID. ## Solution **Race countdown** (`4e709c8`): Add `supports_countdown` boolean to `ContestListResult` and wire it through CSES/USACO scrapers, cache, race module, and pickers. **Language version selection** (`b90ac67`): Add `LANGUAGE_VERSIONS` and `DEFAULT_VERSIONS` tables in `constants.lua`. Config gains `version` and `submit_id` fields validated at setup time. `submit.lua` resolves the effective config to a platform ID (priority: `submit_id` > `version` > default). Helpdocs add `*cp-submit-language*` section. Tests cover `LANGUAGE_IDS` completeness.
89 lines
1.8 KiB
Python
89 lines
1.8 KiB
Python
from pydantic import BaseModel, ConfigDict, Field
|
|
|
|
|
|
class TestCase(BaseModel):
|
|
input: str
|
|
expected: str
|
|
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
|
|
class CombinedTest(BaseModel):
|
|
input: str
|
|
expected: str
|
|
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
|
|
class ProblemSummary(BaseModel):
|
|
id: str
|
|
name: str
|
|
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
|
|
class ContestSummary(BaseModel):
|
|
id: str
|
|
name: str
|
|
display_name: str | None = None
|
|
start_time: int | None = None
|
|
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
|
|
class ScrapingResult(BaseModel):
|
|
success: bool
|
|
error: str
|
|
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
|
|
class MetadataResult(ScrapingResult):
|
|
contest_id: str = ""
|
|
problems: list[ProblemSummary] = Field(default_factory=list)
|
|
url: str
|
|
contest_url: str = ""
|
|
standings_url: str = ""
|
|
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
|
|
class ContestListResult(ScrapingResult):
|
|
contests: list[ContestSummary] = Field(default_factory=list)
|
|
supports_countdown: bool = True
|
|
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
|
|
class TestsResult(ScrapingResult):
|
|
problem_id: str
|
|
combined: CombinedTest
|
|
tests: list[TestCase] = Field(default_factory=list)
|
|
timeout_ms: int
|
|
memory_mb: float
|
|
interactive: bool = False
|
|
multi_test: bool = False
|
|
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
|
|
class LoginResult(ScrapingResult):
|
|
credentials: dict[str, str] = Field(default_factory=dict)
|
|
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
|
|
class SubmitResult(ScrapingResult):
|
|
submission_id: str = ""
|
|
verdict: str = ""
|
|
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
|
|
class ScraperConfig(BaseModel):
|
|
timeout_seconds: int = 30
|
|
max_retries: int = 3
|
|
backoff_base: float = 2.0
|
|
rate_limit_delay: float = 1.0
|
|
|
|
model_config = ConfigDict(extra="forbid")
|