cp.nvim/scrapers/models.py
Barrett Ruth cc279166cb
feat(commands): implement :CP open [problem|contest|standings]
Problem: There was no way to open a problem or contest page in the
browser from within the plugin; users had to manually navigate to
the platform URL.

Solution: Add `contest_url` and `standings_url` to `MetadataResult`
and persist them via `cache.set_contest_data`. Add `cache.get_open_urls`
to assemble all three URLs from cache. Wire up `:CP open` in
`commands/init.lua` to call `vim.ui.open` on the resolved URL,
warning when none is available (e.g. CSES standings).
2026-03-05 19:13:06 -05:00

88 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)
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")