Merge pull request #179 from barrett-ruth/feat/codechef
add codechef platform
This commit is contained in:
commit
8fd4ce9651
29 changed files with 5401 additions and 54 deletions
13
.busted
13
.busted
|
|
@ -1,13 +0,0 @@
|
|||
return {
|
||||
_all = {
|
||||
coverage = false,
|
||||
lpath = 'lua/?.lua;lua/?/init.lua',
|
||||
lua = 'nlua',
|
||||
},
|
||||
default = {
|
||||
verbose = true,
|
||||
},
|
||||
tests = {
|
||||
verbose = true,
|
||||
},
|
||||
}
|
||||
15
.github/workflows/test.yaml
vendored
15
.github/workflows/test.yaml
vendored
|
|
@ -35,21 +35,6 @@ jobs:
|
|||
- 'pyproject.toml'
|
||||
- 'uv.lock'
|
||||
|
||||
lua-test:
|
||||
name: Lua Tests (${{ matrix.neovim_version }})
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: ${{ needs.changes.outputs.lua == 'true' }}
|
||||
strategy:
|
||||
matrix:
|
||||
neovim_version: ['stable', 'nightly']
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Run Lua tests
|
||||
uses: nvim-neorocks/nvim-busted-action@v1
|
||||
with:
|
||||
nvim_version: ${{ matrix.neovim_version }}
|
||||
|
||||
python-test:
|
||||
name: Python Tests
|
||||
runs-on: ubuntu-latest
|
||||
|
|
|
|||
|
|
@ -9,8 +9,7 @@ https://github.com/user-attachments/assets/956ec4c4-5ef1-4391-abea-3a51fa771809
|
|||
|
||||
## Features
|
||||
|
||||
- **Multi-platform support**: AtCoder, Codeforces, CSES with consistent
|
||||
interface
|
||||
- **Multi-platform support**: AtCoder, CodeChef, Codeforces, and CSES
|
||||
- **Automatic problem setup**: Scrape test cases and metadata in seconds
|
||||
- **Dual view modes**: Lightweight I/O view for quick feedback, full panel for
|
||||
detailed analysis
|
||||
|
|
|
|||
|
|
@ -139,6 +139,10 @@ M.defaults = {
|
|||
enabled_languages = { 'cpp', 'python' },
|
||||
default_language = 'cpp',
|
||||
},
|
||||
codechef = {
|
||||
enabled_languages = { 'cpp', 'python' },
|
||||
default_language = 'cpp',
|
||||
},
|
||||
cses = {
|
||||
enabled_languages = { 'cpp', 'python' },
|
||||
default_language = 'cpp',
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
local M = {}
|
||||
|
||||
M.PLATFORMS = { 'atcoder', 'codeforces', 'cses' }
|
||||
M.PLATFORMS = { 'atcoder', 'codechef', 'codeforces', 'cses' }
|
||||
M.ACTIONS = { 'run', 'panel', 'next', 'prev', 'pick', 'cache', 'interact', 'edit' }
|
||||
|
||||
M.PLATFORM_DISPLAY_NAMES = {
|
||||
atcoder = 'AtCoder',
|
||||
codechef = 'CodeChef',
|
||||
codeforces = 'CodeForces',
|
||||
cses = 'CSES',
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ dev = [
|
|||
"pytest-mock>=3.12.0",
|
||||
"pre-commit>=4.3.0",
|
||||
"basedpyright>=1.31.6",
|
||||
"ruff>=0.14.2",
|
||||
]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
|
|
|
|||
317
scrapers/codechef.py
Normal file
317
scrapers/codechef.py
Normal file
|
|
@ -0,0 +1,317 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
from scrapling.fetchers import StealthyFetcher
|
||||
|
||||
from .base import BaseScraper
|
||||
from .models import (
|
||||
ContestListResult,
|
||||
ContestSummary,
|
||||
MetadataResult,
|
||||
ProblemSummary,
|
||||
TestCase,
|
||||
TestsResult,
|
||||
)
|
||||
|
||||
BASE_URL = "https://www.codechef.com"
|
||||
API_CONTESTS_ALL = "/api/list/contests/all"
|
||||
API_CONTEST = "/api/contests/{contest_id}"
|
||||
API_PROBLEM = "/api/contests/{contest_id}/problems/{problem_id}"
|
||||
PROBLEM_URL = "https://www.codechef.com/problems/{problem_id}"
|
||||
|
||||
HEADERS = {
|
||||
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
||||
}
|
||||
TIMEOUT_S = 15.0
|
||||
CONNECTIONS = 8
|
||||
|
||||
MEMORY_LIMIT_RE = re.compile(
|
||||
r"Memory\s+[Ll]imit.*?([0-9.]+)\s*(MB|GB)", re.IGNORECASE | re.DOTALL
|
||||
)
|
||||
|
||||
|
||||
async def fetch_json(client: httpx.AsyncClient, path: str) -> dict:
|
||||
r = await client.get(BASE_URL + path, headers=HEADERS, timeout=TIMEOUT_S)
|
||||
r.raise_for_status()
|
||||
return r.json()
|
||||
|
||||
|
||||
def _extract_memory_limit(html: str) -> float:
|
||||
m = MEMORY_LIMIT_RE.search(html)
|
||||
if not m:
|
||||
return 256.0
|
||||
value = float(m.group(1))
|
||||
unit = m.group(2).upper()
|
||||
if unit == "GB":
|
||||
return value * 1024.0
|
||||
return value
|
||||
|
||||
|
||||
def _fetch_html_sync(url: str) -> str:
|
||||
response = StealthyFetcher.fetch(url, headless=True, network_idle=True)
|
||||
return str(response.body)
|
||||
|
||||
|
||||
class CodeChefScraper(BaseScraper):
|
||||
@property
|
||||
def platform_name(self) -> str:
|
||||
return "codechef"
|
||||
|
||||
async def scrape_contest_metadata(self, contest_id: str) -> MetadataResult:
|
||||
async with httpx.AsyncClient() as client:
|
||||
try:
|
||||
data = await fetch_json(
|
||||
client, API_CONTEST.format(contest_id=contest_id)
|
||||
)
|
||||
except httpx.HTTPStatusError as e:
|
||||
return self._create_metadata_error(
|
||||
f"Failed to fetch contest {contest_id}: {e}", contest_id
|
||||
)
|
||||
|
||||
if not data.get("problems"):
|
||||
return self._create_metadata_error(
|
||||
f"No problems found for contest {contest_id}", contest_id
|
||||
)
|
||||
|
||||
problems = []
|
||||
for problem_code, problem_data in data["problems"].items():
|
||||
if problem_data.get("category_name") == "main":
|
||||
problems.append(
|
||||
ProblemSummary(
|
||||
id=problem_code,
|
||||
name=problem_data.get("name", problem_code),
|
||||
)
|
||||
)
|
||||
|
||||
return MetadataResult(
|
||||
success=True,
|
||||
error="",
|
||||
contest_id=contest_id,
|
||||
problems=problems,
|
||||
url=f"{BASE_URL}/{contest_id}",
|
||||
)
|
||||
|
||||
async def scrape_contest_list(self) -> ContestListResult:
|
||||
async with httpx.AsyncClient() as client:
|
||||
try:
|
||||
data = await fetch_json(client, API_CONTESTS_ALL)
|
||||
except httpx.HTTPStatusError as e:
|
||||
return self._create_contests_error(f"Failed to fetch contests: {e}")
|
||||
|
||||
all_contests = data.get("future_contests", []) + data.get(
|
||||
"past_contests", []
|
||||
)
|
||||
|
||||
max_num = 0
|
||||
for contest in all_contests:
|
||||
contest_code = contest.get("contest_code", "")
|
||||
if contest_code.startswith("START"):
|
||||
match = re.match(r"START(\d+)", contest_code)
|
||||
if match:
|
||||
num = int(match.group(1))
|
||||
max_num = max(max_num, num)
|
||||
|
||||
if max_num == 0:
|
||||
return self._create_contests_error("No Starters contests found")
|
||||
|
||||
contests = []
|
||||
sem = asyncio.Semaphore(CONNECTIONS)
|
||||
|
||||
async def fetch_divisions(i: int) -> list[ContestSummary]:
|
||||
parent_id = f"START{i}"
|
||||
async with sem:
|
||||
try:
|
||||
parent_data = await fetch_json(
|
||||
client, API_CONTEST.format(contest_id=parent_id)
|
||||
)
|
||||
except Exception as e:
|
||||
import sys
|
||||
|
||||
print(f"Error fetching {parent_id}: {e}", file=sys.stderr)
|
||||
return []
|
||||
|
||||
child_contests = parent_data.get("child_contests", {})
|
||||
if not child_contests:
|
||||
return []
|
||||
|
||||
base_name = f"Starters {i}"
|
||||
divisions = []
|
||||
|
||||
for div_key, div_data in child_contests.items():
|
||||
div_code = div_data.get("contest_code", "")
|
||||
div_num = div_data.get("div", {}).get("div_number", "")
|
||||
if div_code and div_num:
|
||||
divisions.append(
|
||||
ContestSummary(
|
||||
id=div_code,
|
||||
name=base_name,
|
||||
display_name=f"{base_name} (Div. {div_num})",
|
||||
)
|
||||
)
|
||||
|
||||
return divisions
|
||||
|
||||
tasks = [fetch_divisions(i) for i in range(1, max_num + 1)]
|
||||
for coro in asyncio.as_completed(tasks):
|
||||
divisions = await coro
|
||||
contests.extend(divisions)
|
||||
|
||||
return ContestListResult(success=True, error="", contests=contests)
|
||||
|
||||
async def stream_tests_for_category_async(self, contest_id: str) -> None:
|
||||
async with httpx.AsyncClient(
|
||||
limits=httpx.Limits(max_connections=CONNECTIONS)
|
||||
) as client:
|
||||
try:
|
||||
contest_data = await fetch_json(
|
||||
client, API_CONTEST.format(contest_id=contest_id)
|
||||
)
|
||||
except Exception:
|
||||
return
|
||||
|
||||
all_problems = contest_data.get("problems", {})
|
||||
if not all_problems:
|
||||
return
|
||||
|
||||
problems = {
|
||||
code: data
|
||||
for code, data in all_problems.items()
|
||||
if data.get("category_name") == "main"
|
||||
}
|
||||
|
||||
sem = asyncio.Semaphore(CONNECTIONS)
|
||||
|
||||
async def run_one(problem_code: str) -> dict[str, Any]:
|
||||
async with sem:
|
||||
try:
|
||||
problem_data = await fetch_json(
|
||||
client,
|
||||
API_PROBLEM.format(
|
||||
contest_id=contest_id, problem_id=problem_code
|
||||
),
|
||||
)
|
||||
|
||||
sample_tests = (
|
||||
problem_data.get("problemComponents", {}).get(
|
||||
"sampleTestCases", []
|
||||
)
|
||||
or []
|
||||
)
|
||||
tests = [
|
||||
TestCase(
|
||||
input=t.get("input", "").strip(),
|
||||
expected=t.get("output", "").strip(),
|
||||
)
|
||||
for t in sample_tests
|
||||
if not t.get("isDeleted", False)
|
||||
]
|
||||
|
||||
time_limit_str = problem_data.get("max_timelimit", "1")
|
||||
timeout_ms = int(float(time_limit_str) * 1000)
|
||||
|
||||
problem_url = PROBLEM_URL.format(problem_id=problem_code)
|
||||
loop = asyncio.get_event_loop()
|
||||
html = await loop.run_in_executor(
|
||||
None, _fetch_html_sync, problem_url
|
||||
)
|
||||
memory_mb = _extract_memory_limit(html)
|
||||
|
||||
interactive = False
|
||||
|
||||
except Exception:
|
||||
tests = []
|
||||
timeout_ms = 1000
|
||||
memory_mb = 256.0
|
||||
interactive = False
|
||||
|
||||
return {
|
||||
"problem_id": problem_code,
|
||||
"tests": [
|
||||
{"input": t.input, "expected": t.expected} for t in tests
|
||||
],
|
||||
"timeout_ms": timeout_ms,
|
||||
"memory_mb": memory_mb,
|
||||
"interactive": interactive,
|
||||
}
|
||||
|
||||
tasks = [run_one(problem_code) for problem_code in problems.keys()]
|
||||
for coro in asyncio.as_completed(tasks):
|
||||
payload = await coro
|
||||
print(json.dumps(payload), flush=True)
|
||||
|
||||
|
||||
async def main_async() -> int:
|
||||
if len(sys.argv) < 2:
|
||||
result = MetadataResult(
|
||||
success=False,
|
||||
error="Usage: codechef.py metadata <contest_id> OR codechef.py tests <contest_id> OR codechef.py contests",
|
||||
url="",
|
||||
)
|
||||
print(result.model_dump_json())
|
||||
return 1
|
||||
|
||||
mode: str = sys.argv[1]
|
||||
scraper = CodeChefScraper()
|
||||
|
||||
if mode == "metadata":
|
||||
if len(sys.argv) != 3:
|
||||
result = MetadataResult(
|
||||
success=False,
|
||||
error="Usage: codechef.py metadata <contest_id>",
|
||||
url="",
|
||||
)
|
||||
print(result.model_dump_json())
|
||||
return 1
|
||||
contest_id = sys.argv[2]
|
||||
result = await scraper.scrape_contest_metadata(contest_id)
|
||||
print(result.model_dump_json())
|
||||
return 0 if result.success else 1
|
||||
|
||||
if mode == "tests":
|
||||
if len(sys.argv) != 3:
|
||||
tests_result = TestsResult(
|
||||
success=False,
|
||||
error="Usage: codechef.py tests <contest_id>",
|
||||
problem_id="",
|
||||
tests=[],
|
||||
timeout_ms=0,
|
||||
memory_mb=0,
|
||||
)
|
||||
print(tests_result.model_dump_json())
|
||||
return 1
|
||||
contest_id = sys.argv[2]
|
||||
await scraper.stream_tests_for_category_async(contest_id)
|
||||
return 0
|
||||
|
||||
if mode == "contests":
|
||||
if len(sys.argv) != 2:
|
||||
contest_result = ContestListResult(
|
||||
success=False, error="Usage: codechef.py contests"
|
||||
)
|
||||
print(contest_result.model_dump_json())
|
||||
return 1
|
||||
contest_result = await scraper.scrape_contest_list()
|
||||
print(contest_result.model_dump_json())
|
||||
return 0 if contest_result.success else 1
|
||||
|
||||
result = MetadataResult(
|
||||
success=False,
|
||||
error=f"Unknown mode: {mode}. Use 'metadata <contest_id>', 'tests <contest_id>', or 'contests'",
|
||||
url="",
|
||||
)
|
||||
print(result.model_dump_json())
|
||||
return 1
|
||||
|
||||
|
||||
def main() -> None:
|
||||
sys.exit(asyncio.run(main_async()))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
describe('run module', function()
|
||||
local run = require('cp.runner.run')
|
||||
|
||||
describe('basic functionality', function()
|
||||
it('can get panel state', function()
|
||||
local state = run.get_panel_state()
|
||||
assert.is_table(state)
|
||||
assert.is_table(state.test_cases)
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
|
@ -63,13 +63,13 @@ def run_scraper_offline(fixture_text):
|
|||
target = target.removeprefix("https://cses.fi")
|
||||
|
||||
if target.strip("/") == "problemset":
|
||||
return fixture_text("cses_contests.html")
|
||||
return fixture_text("cses/contests.html")
|
||||
|
||||
if target.startswith("/problemset/task/") or target.startswith(
|
||||
"problemset/task/"
|
||||
):
|
||||
pid = target.rstrip("/").split("/")[-1]
|
||||
return fixture_text(f"cses_task_{pid}.html")
|
||||
return fixture_text(f"cses/task_{pid}.html")
|
||||
|
||||
raise AssertionError(f"No fixture for CSES path={path!r} url={url!r}")
|
||||
|
||||
|
|
@ -77,12 +77,12 @@ def run_scraper_offline(fixture_text):
|
|||
if not url:
|
||||
raise AssertionError("AtCoder expects url routing")
|
||||
if "/contests/archive" in url:
|
||||
return fixture_text("atcoder_contests.html")
|
||||
return fixture_text("atcoder/contests.html")
|
||||
if url.endswith("/tasks"):
|
||||
return fixture_text("atcoder_abc100_tasks.html")
|
||||
return fixture_text("atcoder/abc100_tasks.html")
|
||||
if "/tasks/" in url:
|
||||
slug = url.rsplit("/", 1)[-1]
|
||||
return fixture_text(f"atcoder_task_{slug}.html")
|
||||
return fixture_text(f"atcoder/task_{slug}.html")
|
||||
raise AssertionError(f"No fixture for AtCoder url={url!r}")
|
||||
|
||||
def _router_codeforces(*, path: str | None = None, url: str | None = None) -> str:
|
||||
|
|
@ -90,17 +90,17 @@ def run_scraper_offline(fixture_text):
|
|||
raise AssertionError("Codeforces expects url routing")
|
||||
if "/contest/" in url and url.endswith("/problems"):
|
||||
contest_id = url.rstrip("/").split("/")[-2]
|
||||
return fixture_text(f"codeforces_{contest_id}_problems.html")
|
||||
return fixture_text(f"codeforces/{contest_id}_problems.html")
|
||||
if "/contests" in url and "/problem/" not in url:
|
||||
return fixture_text("codeforces_contests.html")
|
||||
return fixture_text("codeforces/contests.html")
|
||||
if "/problem/" in url:
|
||||
parts = url.rstrip("/").split("/")
|
||||
contest_id, index = parts[-3], parts[-1]
|
||||
return fixture_text(f"codeforces_{contest_id}_{index}.html")
|
||||
return fixture_text(f"codeforces/{contest_id}_{index}.html")
|
||||
if "/problemset/problem/" in url:
|
||||
parts = url.rstrip("/").split("/")
|
||||
contest_id, index = parts[-2], parts[-1]
|
||||
return fixture_text(f"codeforces_{contest_id}_{index}.html")
|
||||
return fixture_text(f"codeforces/{contest_id}_{index}.html")
|
||||
|
||||
raise AssertionError(f"No fixture for Codeforces url={url!r}")
|
||||
|
||||
|
|
@ -136,12 +136,12 @@ def run_scraper_offline(fixture_text):
|
|||
|
||||
case "codeforces":
|
||||
|
||||
class MockPage:
|
||||
class MockCodeForcesPage:
|
||||
def __init__(self, html: str):
|
||||
self.html_content = html
|
||||
|
||||
def _mock_stealthy_fetch(url: str, **kwargs):
|
||||
return MockPage(_router_codeforces(url=url))
|
||||
return MockCodeForcesPage(_router_codeforces(url=url))
|
||||
|
||||
def _mock_requests_get(url: str, **kwargs):
|
||||
if "api/contest.list" in url:
|
||||
|
|
@ -176,6 +176,59 @@ def run_scraper_offline(fixture_text):
|
|||
"requests.get": _mock_requests_get,
|
||||
}
|
||||
|
||||
case "codechef":
|
||||
|
||||
class MockResponse:
|
||||
def __init__(self, json_data):
|
||||
self._json_data = json_data
|
||||
self.status_code = 200
|
||||
|
||||
def json(self):
|
||||
return self._json_data
|
||||
|
||||
def raise_for_status(self):
|
||||
pass
|
||||
|
||||
async def __offline_get_async(client, url: str, **kwargs):
|
||||
if "/api/list/contests/all" in url:
|
||||
data = json.loads(fixture_text("codechef/contests.json"))
|
||||
return MockResponse(data)
|
||||
if "/api/contests/START" in url and "/problems/" not in url:
|
||||
contest_id = url.rstrip("/").split("/")[-1]
|
||||
try:
|
||||
data = json.loads(
|
||||
fixture_text(f"codechef/{contest_id}.json")
|
||||
)
|
||||
return MockResponse(data)
|
||||
except FileNotFoundError:
|
||||
raise AssertionError(f"No fixture for CodeChef url={url!r}")
|
||||
if "/api/contests/START" in url and "/problems/" in url:
|
||||
parts = url.rstrip("/").split("/")
|
||||
contest_id = parts[-3]
|
||||
problem_id = parts[-1]
|
||||
data = json.loads(
|
||||
fixture_text(f"codechef/{contest_id}_{problem_id}.json")
|
||||
)
|
||||
return MockResponse(data)
|
||||
raise AssertionError(f"No fixture for CodeChef url={url!r}")
|
||||
|
||||
class MockCodeChefPage:
|
||||
def __init__(self, html: str):
|
||||
self.body = html
|
||||
self.status = 200
|
||||
|
||||
def _mock_stealthy_fetch(url: str, **kwargs):
|
||||
if "/problems/" in url:
|
||||
problem_id = url.rstrip("/").split("/")[-1]
|
||||
html = fixture_text(f"codechef/{problem_id}.html")
|
||||
return MockCodeChefPage(html)
|
||||
raise AssertionError(f"No fixture for CodeChef url={url!r}")
|
||||
|
||||
return {
|
||||
"__offline_get_async": __offline_get_async,
|
||||
"StealthyFetcher.fetch": _mock_stealthy_fetch,
|
||||
}
|
||||
|
||||
case _:
|
||||
raise AssertionError(f"Unknown scraper: {scraper_name}")
|
||||
|
||||
|
|
@ -192,6 +245,9 @@ def run_scraper_offline(fixture_text):
|
|||
ns._get_async = offline_fetches["_get_async"]
|
||||
elif scraper_name == "cses":
|
||||
httpx.AsyncClient.get = offline_fetches["__offline_fetch_text"] # type: ignore[assignment]
|
||||
elif scraper_name == "codechef":
|
||||
httpx.AsyncClient.get = offline_fetches["__offline_get_async"] # type: ignore[assignment]
|
||||
fetchers.StealthyFetcher.fetch = offline_fetches["StealthyFetcher.fetch"] # type: ignore[assignment]
|
||||
|
||||
main_async = getattr(ns, "main_async")
|
||||
assert callable(main_async), f"main_async not found in {scraper_name}"
|
||||
|
|
|
|||
4343
tests/fixtures/codechef/P1209.html
vendored
Normal file
4343
tests/fixtures/codechef/P1209.html
vendored
Normal file
File diff suppressed because it is too large
Load diff
1
tests/fixtures/codechef/START209.json
vendored
Normal file
1
tests/fixtures/codechef/START209.json
vendored
Normal file
File diff suppressed because one or more lines are too long
202
tests/fixtures/codechef/START209D.json
vendored
Normal file
202
tests/fixtures/codechef/START209D.json
vendored
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
{
|
||||
"status": "success",
|
||||
"user": { "username": null },
|
||||
"code": "START209D",
|
||||
"isRatedContest": "1",
|
||||
"isParentContestRated": "1",
|
||||
"name": "Starters 209 (Rated)",
|
||||
"problems": {
|
||||
"P1209": {
|
||||
"code": "P1209",
|
||||
"name": "Bitcoin Market",
|
||||
"type": "3",
|
||||
"successful_submissions": "25131",
|
||||
"allow_submission": false,
|
||||
"accuracy": 85.680000000000007,
|
||||
"problem_url": "\/problems\/P1209",
|
||||
"submit_url": "\/problems\/P1209",
|
||||
"status_url": "\/status\/P1209",
|
||||
"is_added_to_practice": true,
|
||||
"total_submissions": "33093",
|
||||
"category_name": "main",
|
||||
"is_direct_submittable": false
|
||||
},
|
||||
"P2209": {
|
||||
"code": "P2209",
|
||||
"name": "Divisible Duel",
|
||||
"type": "3",
|
||||
"successful_submissions": "21888",
|
||||
"allow_submission": false,
|
||||
"accuracy": 64.159999999999997,
|
||||
"problem_url": "\/problems\/P2209",
|
||||
"submit_url": "\/problems\/P2209",
|
||||
"status_url": "\/status\/P2209",
|
||||
"is_added_to_practice": true,
|
||||
"total_submissions": "37437",
|
||||
"category_name": "main",
|
||||
"is_direct_submittable": false
|
||||
},
|
||||
"P3209": {
|
||||
"code": "P3209",
|
||||
"name": "Small GCD Sort",
|
||||
"type": "3",
|
||||
"successful_submissions": "13450",
|
||||
"allow_submission": false,
|
||||
"accuracy": 76.239999999999995,
|
||||
"problem_url": "\/problems\/P3209",
|
||||
"submit_url": "\/problems\/P3209",
|
||||
"status_url": "\/status\/P3209",
|
||||
"is_added_to_practice": true,
|
||||
"total_submissions": "19164",
|
||||
"category_name": "main",
|
||||
"is_direct_submittable": false
|
||||
},
|
||||
"P4209": {
|
||||
"code": "P4209",
|
||||
"name": "Tactical Conversion",
|
||||
"type": "3",
|
||||
"successful_submissions": "1567",
|
||||
"allow_submission": false,
|
||||
"accuracy": 8.4499999999999993,
|
||||
"problem_url": "\/problems\/P4209",
|
||||
"submit_url": "\/problems\/P4209",
|
||||
"status_url": "\/status\/P4209",
|
||||
"is_added_to_practice": true,
|
||||
"total_submissions": "20535",
|
||||
"category_name": "main",
|
||||
"is_direct_submittable": false
|
||||
},
|
||||
"P5209": {
|
||||
"code": "P5209",
|
||||
"name": "Binary Love",
|
||||
"type": "3",
|
||||
"successful_submissions": "3271",
|
||||
"allow_submission": false,
|
||||
"accuracy": 33.530000000000001,
|
||||
"problem_url": "\/problems\/P5209",
|
||||
"submit_url": "\/problems\/P5209",
|
||||
"status_url": "\/status\/P5209",
|
||||
"is_added_to_practice": true,
|
||||
"total_submissions": "11128",
|
||||
"category_name": "main",
|
||||
"is_direct_submittable": false
|
||||
},
|
||||
"P6209E": {
|
||||
"code": "P6209E",
|
||||
"name": "High Score (Easy Version)",
|
||||
"type": "3",
|
||||
"successful_submissions": "285",
|
||||
"allow_submission": false,
|
||||
"accuracy": 7.2800000000000002,
|
||||
"problem_url": "\/problems\/P6209E",
|
||||
"submit_url": "\/problems\/P6209E",
|
||||
"status_url": "\/status\/P6209E",
|
||||
"is_added_to_practice": true,
|
||||
"total_submissions": "4535",
|
||||
"category_name": "main",
|
||||
"is_direct_submittable": false
|
||||
},
|
||||
"P6209": {
|
||||
"code": "P6209",
|
||||
"name": "High Score (Hard Version)",
|
||||
"type": "3",
|
||||
"successful_submissions": "34",
|
||||
"allow_submission": false,
|
||||
"accuracy": 3.1899999999999999,
|
||||
"problem_url": "\/problems\/P6209",
|
||||
"submit_url": "\/problems\/P6209",
|
||||
"status_url": "\/status\/P6209",
|
||||
"is_added_to_practice": true,
|
||||
"total_submissions": "1159",
|
||||
"category_name": "main",
|
||||
"is_direct_submittable": false
|
||||
},
|
||||
"P7209": {
|
||||
"code": "P7209",
|
||||
"name": "Easy Grid Game",
|
||||
"type": "3",
|
||||
"successful_submissions": "80",
|
||||
"allow_submission": false,
|
||||
"accuracy": 5.1100000000000003,
|
||||
"problem_url": "\/problems\/P7209",
|
||||
"submit_url": "\/problems\/P7209",
|
||||
"status_url": "\/status\/P7209",
|
||||
"is_added_to_practice": true,
|
||||
"total_submissions": "1740",
|
||||
"category_name": "main",
|
||||
"is_direct_submittable": false
|
||||
},
|
||||
"P8209": {
|
||||
"code": "P8209",
|
||||
"name": "Counting Is Fun",
|
||||
"type": "3",
|
||||
"successful_submissions": "22",
|
||||
"allow_submission": false,
|
||||
"accuracy": 1.8200000000000001,
|
||||
"problem_url": "\/problems\/P8209",
|
||||
"submit_url": "\/problems\/P8209",
|
||||
"status_url": "\/status\/P8209",
|
||||
"is_added_to_practice": true,
|
||||
"total_submissions": "1261",
|
||||
"category_name": "main",
|
||||
"is_direct_submittable": false
|
||||
}
|
||||
},
|
||||
"banner": "https:\/\/cdn.codechef.com\/download\/small-banner\/START209D\/1760933097.png",
|
||||
"rules": "<h4>CodeChef: A Platform for Aspiring Programmers<\/h4>\n<p class=\"last\">CodeChef was created as a platform to help programmers make it big in the world of algorithms, computer programming, and programming contests. At CodeChef, our dedicated efforts are aimed at reviving the inner geek within you, as we proudly host a thrilling programming (coding) contest every Wednesday.<\/p>\n<h4>About CodeChef Starters:<\/h4>\n<p>CodeChef Starters is a short programming contest which takes place on every Wednesday\u00a0<\/p>\n<h4>Contest Details:<\/h4>\n<ul class=\"last\">\n<li><strong>D<\/strong><strong>uration: <\/strong>\u00a02.00 hours\u00a0<\/li>\n<li><strong>Start Date: <\/strong>Wednesday, 22nd October , 2025 at 20:00 HRS (IST)<\/li>\n<li><strong>End Date: <\/strong>Wednesday, 22nd October, 2025 at 22:00 HRS (IST)<\/li>\n<li>Check your timezone <a href=\"https:\/\/www.timeanddate.com\/worldclock\/fixedtime.html?msg=CodeChef+Starters+209&iso=20251022T20&p1=44&ah=2\" target=\"_blank\" rel=\"nofollow noreferrer noopener\">here<\/a>.<\/li>\n<\/ul>\n<h4>Eligibility Criteria: Anyone with a knack for programming<\/h4>\n<p class=\"last\">Our contests are open to all programmers across the globe.<\/p>\n<h4>What's in it for you?<\/h4>\n<p>The idea behind these programming contests is that we want you to learn while competing. Also, we believe that it is alright to refer to tutorials, books, and other materials, learn a concept, and then apply the same to solve a problem during a contest. But it is <strong>not alright to copy other people's solutions or seek other people's help to solve a problem. <\/strong>All the participants are expected to abide to <a class=\"button blue\" href=\"..\/codeofconduct\">CodeChef's Code Of Conduct<\/a>.<\/p>\n<h4>Rules and Regulations:<\/h4>\n<ul>\n<li>This is an IOI-style contest. This means that the problems will be partially graded. You will get the score for passing certain test data.<\/li>\n<li>The details of the failed test cases will also be visible on your solution page.<\/li>\n<li>You can submit solutions as many times as you'd like, there are no penalties for incorrect submissions. Only your best correct submission will be considered.<\/li>\n<li>Those who achieve the score first will be placed higher in the ranklist in case of a tie.<\/li>\n<li><strong>We have removed all the Institutions that we could not identify from our database. We request you to update your institutions once again by going to your profile page.<\/strong><\/li>\n<li>You can also send in your queries in an email to <a href=\"mailto:help@codechef.com\" target=\"_blank\" rel=\"noreferrer noopener\">help@codechef.com<\/a>, during the contest.<\/li>\n<li>Please do not discuss strategy, suggestions, or tips in the comments during a live contest. Posting questions clarifying the problem statement is ok. If you are unsure, email us at <a href=\"mailto:feedback@codechef.com\" target=\"_blank\" rel=\"noreferrer noopener\"> feedback@codechef.com<\/a>.<\/li>\n<li>Discussing CodeChef's problems or any aspect of a problem, on any other platform on the web, on identification, could lead to the disabling of the respective account and banning from the community.<\/li>\n<\/ul>\n<p><strong>Note: You can now \"Code, Compile, and Run\" your codes on our <a href=\"..\/ide\">Online IDE<\/a>.<\/strong><\/p>\n<p>However, if you are using any other online development environment, make sure that other contestants don't have access to your code. As a contestant, you are responsible for making sure others don't access the code that you submit. If you use Ideone, make sure to mark your submission \"private\" (not secret)\".<\/p>",
|
||||
"time": {
|
||||
"start": 1761143406,
|
||||
"end": 1761150606,
|
||||
"freezing": 0,
|
||||
"current": 1761365589
|
||||
},
|
||||
"ip": "2603:7000:3900:1358:3959:b692:6cf3:cb03",
|
||||
"announcements": "<p><strong>CodeChef \u00d7 Coding Club League (2025-26)<\/strong><br \/><br \/>Partner with CodeChef to build a strong coding culture on campus!<\/p>\n<p><strong>Benefits for Clubs:<\/strong><\/p>\n<ul>\n<li>Platform access and support for Annual Technical events \/ hackathons<\/li>\n<li>Pro access for winners<\/li>\n<li>Dashboard to track member progress<\/li>\n<li>Discounts on CodeChef Pro for all members<\/li>\n<li>Co-branding & promotion on CodeChef channels<br \/><br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<strong style=\"text-align:center;\"><a class=\"button blue\" href=\"codechef-coding-club\" target=\"_blank\" rel=\"noreferrer noopener\">\u00a0Click Here To Know More<\/a><\/strong><\/li>\n<\/ul>\n<p><strong>\u00a0<\/strong><\/p>\n<p>\u00a0<\/p>",
|
||||
"problemsstats": {
|
||||
"attempted": [],
|
||||
"partially_solved": [],
|
||||
"solved": [],
|
||||
"locked": []
|
||||
},
|
||||
"todos": [],
|
||||
"stats": null,
|
||||
"partial_scores": {
|
||||
"P7209": [{ "score": "100", "count": "80" }],
|
||||
"P5209": [{ "score": "100", "count": "3271" }],
|
||||
"P4209": [{ "score": "100", "count": "1567" }],
|
||||
"P1209": [{ "score": "100", "count": "25131" }],
|
||||
"P3209": [{ "score": "100", "count": "13450" }],
|
||||
"P2209": [{ "score": "100", "count": "21888" }],
|
||||
"P8209": [{ "score": "100", "count": "22" }],
|
||||
"P6209": [{ "score": "100", "count": "34" }],
|
||||
"P6209E": [{ "score": "100", "count": "285" }]
|
||||
},
|
||||
"isRanklistFrozen": false,
|
||||
"rank_and_score": { "score": "NA", "rank": "NA" },
|
||||
"is_a_parent_contest": false,
|
||||
"is_contest_elements_visible": true,
|
||||
"is_OTP_required": false,
|
||||
"is_linked_problems_contest": "0",
|
||||
"custom_contest_page_title": "",
|
||||
"custom_contest_page_meta_desc": "",
|
||||
"contest_introduction": "https:\/\/discuss.codechef.com\/t\/invitation-to-codechef-starters-209-rated-upto-5-stars-22nd-october\/124401",
|
||||
"contest_editorials": "https:\/\/discuss.codechef.com\/tag\/start209",
|
||||
"contest_video_editorials": "",
|
||||
"is_older_rating_based_division_system": false,
|
||||
"division_generation": 3,
|
||||
"isAssessmentContest": false,
|
||||
"penalisedUsersCount": 0,
|
||||
"ttl": 60,
|
||||
"scorable_heading": "Scorable Problems for Division 4",
|
||||
"scorable_message": "",
|
||||
"division": "Division 4",
|
||||
"non_scorable_heading": "Non Scorable Problems for Practice",
|
||||
"non_scorable_message": "<p>The following problems are <b>NOT part of the contest<\/b>, and will not be counted towards your rankings and ratings. These are problems from the other Division(s), made available for you to practice. Click <a href='\/blogs\/how-does-codechef-rating-system-work'>here<\/a> to know more. They will be considered for plagiarism though.<\/p>",
|
||||
"is_registration_enabled_contest": false,
|
||||
"is_flexi_time_contest": false,
|
||||
"duration": "120",
|
||||
"is_proctored": false,
|
||||
"autoRefresh": true,
|
||||
"visitedContests": [],
|
||||
"user_live_ratings_update_frequency": 15
|
||||
}
|
||||
99
tests/fixtures/codechef/START209D_P1209.json
vendored
Normal file
99
tests/fixtures/codechef/START209D_P1209.json
vendored
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
{
|
||||
"category_name": "main",
|
||||
"contest_code": "START209D",
|
||||
"contest_name": "Starters 209 (Rated)",
|
||||
"status": "success",
|
||||
"submit_error": "You need to login to submit.",
|
||||
"is_verified": false,
|
||||
"problem_code": "P1209",
|
||||
"contest_category": "9",
|
||||
"problem_name": "Bitcoin Market",
|
||||
"intended_contest_code": "START209",
|
||||
"body": "This is an example problem statement in markdown, and a mini guide on writing statements. Please make sure to remove everything here before publishing your problem.\n\n- Codechef uses markdown for its problem statements. Markdown syntax can be found [here](https:\/\/github.com\/showdownjs\/showdown\/wiki\/Showdown's-Markdown-syntax). Note the `[text](link)` syntax to insert a hyperlink.\n- Codechef also uses $\\LaTeX$ to render mathematical expressions, and you are advised to make liberal use of it to make your statement look good.\n- Text can be made **bold** or *italicized*.\n- **Do not** use HTML tags (p, ul, li, pre, br, ...) in the statement.\n- To insert an image, first upload it to an online hosting service (for an official contest, ask a Codechef admin to do this for you \u2014 this is important) and then use the following syntax: ``.\n- If your problem doesn't contain subtasks, ensure that the Subtasks section below is disabled and **all content is deleted from it**.\n\nIf you face any issues, either contact a Codechef admin directly or send us an email at help@codechef.com.\n\nBelow is an example problem statement that uses some of the above-mentioned features.\n\n---------\n\nChef has a simple undirected graph $G$ with $N$ vertices and $M$ edges. A [subgraph](https:\/\/mathworld.wolfram.com\/Subgraph.html) $H$ of $G$ is called *good* if:\n- $H$ is connected\n- $H$ contains all $N$ vertices of $G$\n- There is a unique path between any two vertices in $H$, using only edges in $H$\n\nCount the number of *good* subgraphs of $G$. Since this number might be large, report it modulo $10^9 + 7$.\n\nIn other news, here's a completely unrelated image:\n\n.\n\n\n<aside style='background: #f8f8f8;padding: 10px 15px;'><div>All submissions for this problem are available.<\/div><\/aside>",
|
||||
"problemComponents": {
|
||||
"constraints": "- $1 \\leq R \\leq 10$",
|
||||
"constraintsState": true,
|
||||
"subtasks": "- **Subtask 1 (10 points):** $1 \\leq M \\leq 10$\n- **Subtask 2 (20 points):** The sum of $N$ across all test cases won't exceed $20$.\n- **Subtask 3 (70 points):** No further constraints.",
|
||||
"subtasksState": false,
|
||||
"statement": "Chef has recently started investing in **Bitcoin**. \nHe assigns a **market risk level** $R$ (from $1$ to $10$), where: \n\n- $1$ means the market is *very safe*, \n- $10$ means the market is *very risky*. \n\nChef will **buy Bitcoin** only if the risk level is **$4$ or less**. \n\nGiven the current risk level $R$, determine whether Chef should buy Bitcoin.\n\nPrint **\"YES\"** if Chef should buy, otherwise print **\"NO\"**.",
|
||||
"inputFormat": "- The first and only line of input contains a single integer $R$ \u2014 the current market risk level.",
|
||||
"inputFormatState": true,
|
||||
"outputFormat": "Print `YES` if Chef should buy Bitcoin, Otherwise, print `NO`.\n\nYou may print each character of the string in uppercase or lowercase (for example, the strings `YES`, `yEs`, `yes`, and `yeS` will all be treated as identical).\n",
|
||||
"outputFormatState": true,
|
||||
"sampleTestCases": [
|
||||
{
|
||||
"id": "1",
|
||||
"input": "2",
|
||||
"output": "YES",
|
||||
"explanation": "The current market risk is $2$. \nSince $2$ is not larger than $4$, the risk is small enough, and Chef will buy Bitcoin.",
|
||||
"isDeleted": false
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"input": "4",
|
||||
"output": "YES",
|
||||
"explanation": "The current market risk is $4$. \nSince $4$ is not larger than $4$, the risk is small enough, and Chef will buy Bitcoin.",
|
||||
"isDeleted": false
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"input": "5",
|
||||
"output": "NO",
|
||||
"explanation": "The current market risk is $5$. \nSince $5$ is larger than $4$, the risk is too much, and Chef will **not** buy Bitcoin.",
|
||||
"isDeleted": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"gumlet_video_url": "",
|
||||
"video_editorial_url": "https:\/\/youtu.be\/tjUCV9Ld1Kw?si=minop9943wecj1bh",
|
||||
"text_editorial_body": "<h1><a name=\"problem-link-1\" class=\"anchor\" href=\"#problem-link-1\"><\/a>PROBLEM LINK:<\/h1>\n<p><a href=\"https:\/\/www.codechef.com\/problems\/P1209\">Practice<\/a><br>\n<a href=\"https:\/\/www.codechef.com\/START209A\/problems\/P1209\">Contest: Division 1<\/a><br>\n<a href=\"https:\/\/www.codechef.com\/START209B\/problems\/P1209\">Contest: Division 2<\/a><br>\n<a href=\"https:\/\/www.codechef.com\/START209C\/problems\/P1209\">Contest: Division 3<\/a><br>\n<a href=\"https:\/\/www.codechef.com\/START209D\/problems\/P1209\">Contest: Division 4<\/a><\/p>\n<p><em><strong>Author:<\/strong><\/em> <a href=\"https:\/\/www.codechef.com\/users\/pols_agyi_pols\">pols_agyi_pols<\/a><br>\n<em><strong>Tester:<\/strong><\/em> <a href=\"https:\/\/www.codechef.com\/users\/kingmessi\">kingmessi<\/a><br>\n<em><strong>Editorialist:<\/strong><\/em> <a href=\"https:\/\/www.codechef.com\/users\/iceknight1093\">iceknight1093<\/a><\/p>\n<h1><a name=\"difficulty-2\" class=\"anchor\" href=\"#difficulty-2\"><\/a>DIFFICULTY:<\/h1>\n<p>Cakewalk<\/p>\n<h1><a name=\"prerequisites-3\" class=\"anchor\" href=\"#prerequisites-3\"><\/a>PREREQUISITES:<\/h1>\n<p>None<\/p>\n<h1><a name=\"problem-4\" class=\"anchor\" href=\"#problem-4\"><\/a>PROBLEM:<\/h1>\n<p>Chef will buy bitcoin if the market risk level is no more than <span class=\"math\">4<\/span>.<br>\nThe current market risk level is <span class=\"math\">R<\/span>.<br>\nWill Chef buy bitcoin?<\/p>\n<h1><a name=\"explanation-5\" class=\"anchor\" href=\"#explanation-5\"><\/a>EXPLANATION:<\/h1>\n<p>The answer is <code>Yes<\/code> if <span class=\"math\">R \\le 4<\/span> and <code>No<\/code> otherwise.<br>\nThis can be checked using an <code>if<\/code> condition.<\/p>\n<h1><a name=\"time-complexity-6\" class=\"anchor\" href=\"#time-complexity-6\"><\/a>TIME COMPLEXITY:<\/h1>\n<p><span class=\"math\">\\mathcal{O}(1)<\/span> per testcase.<\/p>\n<h1><a name=\"code-7\" class=\"anchor\" href=\"#code-7\"><\/a>CODE:<\/h1>\n<details>\n<summary>\nEditorialist's code (PyPy3)<\/summary>\n<pre><code class=\"lang-python\">r = int(input())\nprint('Yes' if r <= 4 else 'No')\n<\/code><\/pre>\n<\/details>",
|
||||
"text_editorial_is_markdown": 0,
|
||||
"text_editorial_topic_id": 124410,
|
||||
"languages_supported": "CPP20, PYTH 3, C, JAVA, PYP3, CS2, NODEJS, GO, TS, PHP, kotlin, rust, R",
|
||||
"max_timelimit": "1",
|
||||
"source_sizelimit": "50000",
|
||||
"problem_author": "archit_adm",
|
||||
"problem_display_authors": ["archit_adm"],
|
||||
"problem_display_authors_html_handle": "<div class=\"multiple-usernames-container\"><a href='\/users\/archit_adm'>archit_adm<\/a><\/div>",
|
||||
"problem_tester": null,
|
||||
"problem_testers_usernames": ["kingmessi"],
|
||||
"problem_tester_html_handle": "<div class=\"multiple-usernames-container\"><a href='\/users\/kingmessi'><span \n class='rating' \n style='display: inline-block; \n font-size: 10px; \n background: #D0011B;\n padding: 0 3px; \n line-height: 1.3; \n color: white;\n margin-right: 2px;'>7★<\/span><span class='m-username--link'>kingmessi<\/span><\/a><\/div>",
|
||||
"problem_editorialist": "iceknight1093",
|
||||
"date_added": "20-10-2025",
|
||||
"ready_for_debug": false,
|
||||
"problem_stats": {
|
||||
"accuracy": 85.780000000000001,
|
||||
"successful_submissions": "25325",
|
||||
"total_submissions": "33327"
|
||||
},
|
||||
"user_tags": ["archit_adm", "cakewalk", "start209"],
|
||||
"computed_tags": [],
|
||||
"difficulty_rating": "172",
|
||||
"best_tag": "",
|
||||
"editorial_url": "",
|
||||
"time": {
|
||||
"view_start_date": 1761143406,
|
||||
"submit_start_date": 1761143406,
|
||||
"visible_start_date": 1761150606,
|
||||
"end_date": 1761150606,
|
||||
"current": 1761365589,
|
||||
"practice_submission_allowed": false
|
||||
},
|
||||
"user": { "username": null, "access": "default", "isPremiumUser": false },
|
||||
"bookmark_status": false,
|
||||
"contest_problem_status": "unattempted",
|
||||
"problem_status": "unattempted",
|
||||
"is_direct_submittable": false,
|
||||
"problemDiscussURL": "https:\/\/discuss.codechef.com\/search?q=P1209",
|
||||
"is_a_practice_or_college_contest": false,
|
||||
"votes_data": {
|
||||
"SolutionVoteData": { "upvote_count": 0, "user_vote": 0 },
|
||||
"HintsVoteData": { "upvote_count": 0, "user_vote": 0 },
|
||||
"ProblemStatementVoteData": { "upvote_count": 26, "user_vote": 0 },
|
||||
"DoubtSupportVoteData": { "upvote_count": 0, "user_vote": 0 }
|
||||
},
|
||||
"is_proctored": false,
|
||||
"is_user_verified_for_proctoring": false,
|
||||
"visitedContests": [],
|
||||
"isSupportedByJudge": true
|
||||
}
|
||||
330
tests/fixtures/codechef/contests.json
vendored
Normal file
330
tests/fixtures/codechef/contests.json
vendored
Normal file
|
|
@ -0,0 +1,330 @@
|
|||
{
|
||||
"status": "success",
|
||||
"message": "All contests list",
|
||||
"present_contests": [
|
||||
{
|
||||
"contest_code": "DEVWEEKEND21",
|
||||
"contest_name": "Weekend Dev Challenge 21: Full Stack Projects using MERN",
|
||||
"contest_start_date": "25 Oct 2025 00:00:00",
|
||||
"contest_end_date": "27 Oct 2025 00:00:00",
|
||||
"contest_start_date_iso": "2025-10-25T00:00:00+05:30",
|
||||
"contest_end_date_iso": "2025-10-27T00:00:00+05:30",
|
||||
"contest_duration": "2880",
|
||||
"distinct_users": 8
|
||||
}
|
||||
],
|
||||
"future_contests": [
|
||||
{
|
||||
"contest_code": "START210",
|
||||
"contest_name": "Starters 210",
|
||||
"contest_start_date": "29 Oct 2025 20:00:00",
|
||||
"contest_end_date": "29 Oct 2025 22:00:00",
|
||||
"contest_start_date_iso": "2025-10-29T20:00:00+05:30",
|
||||
"contest_end_date_iso": "2025-10-29T22:00:00+05:30",
|
||||
"contest_duration": "120",
|
||||
"distinct_users": 0
|
||||
},
|
||||
{
|
||||
"contest_code": "START211",
|
||||
"contest_name": "Starters 211",
|
||||
"contest_start_date": "05 Nov 2025 20:00:00",
|
||||
"contest_end_date": "05 Nov 2025 22:00:00",
|
||||
"contest_start_date_iso": "2025-11-05T20:00:00+05:30",
|
||||
"contest_end_date_iso": "2025-11-05T22:00:00+05:30",
|
||||
"contest_duration": "120",
|
||||
"distinct_users": 0
|
||||
}
|
||||
],
|
||||
"practice_contests": [],
|
||||
"past_contests": [
|
||||
{
|
||||
"contest_code": "START209",
|
||||
"contest_name": "Starters 209 (Rated till 5 star)",
|
||||
"contest_start_date": "22 Oct 2025 20:00:00",
|
||||
"contest_end_date": "22 Oct 2025 22:00:00",
|
||||
"contest_start_date_iso": "2025-10-22T20:00:00+05:30",
|
||||
"contest_end_date_iso": "2025-10-22T22:00:00+05:30",
|
||||
"contest_duration": "120",
|
||||
"distinct_users": 30408
|
||||
},
|
||||
{
|
||||
"contest_code": "DSAMONDAY08",
|
||||
"contest_name": "Monday Munch - DSA Challenge 08",
|
||||
"contest_start_date": "20 Oct 2025 18:00:31",
|
||||
"contest_end_date": "20 Oct 2025 21:00:31",
|
||||
"contest_start_date_iso": "2025-10-20T18:00:31+05:30",
|
||||
"contest_end_date_iso": "2025-10-20T21:00:31+05:30",
|
||||
"contest_duration": "180",
|
||||
"distinct_users": 653
|
||||
},
|
||||
{
|
||||
"contest_code": "DEVWEEKEND20",
|
||||
"contest_name": "Weekend Dev Challenge 20: Full Stack Projects using MERN",
|
||||
"contest_start_date": "18 Oct 2025 00:00:00",
|
||||
"contest_end_date": "20 Oct 2025 00:00:00",
|
||||
"contest_start_date_iso": "2025-10-18T00:00:00+05:30",
|
||||
"contest_end_date_iso": "2025-10-20T00:00:00+05:30",
|
||||
"contest_duration": "2880",
|
||||
"distinct_users": 318
|
||||
},
|
||||
{
|
||||
"contest_code": "START208",
|
||||
"contest_name": "Starters 208 (Rated till 6 star)",
|
||||
"contest_start_date": "15 Oct 2025 20:00:00",
|
||||
"contest_end_date": "15 Oct 2025 22:00:00",
|
||||
"contest_start_date_iso": "2025-10-15T20:00:00+05:30",
|
||||
"contest_end_date_iso": "2025-10-15T22:00:00+05:30",
|
||||
"contest_duration": "120",
|
||||
"distinct_users": 37727
|
||||
},
|
||||
{
|
||||
"contest_code": "DSAMONDAY07",
|
||||
"contest_name": "Monday Munch - DSA Challenge 07",
|
||||
"contest_start_date": "13 Oct 2025 18:00:00",
|
||||
"contest_end_date": "13 Oct 2025 21:00:00",
|
||||
"contest_start_date_iso": "2025-10-13T18:00:00+05:30",
|
||||
"contest_end_date_iso": "2025-10-13T21:00:00+05:30",
|
||||
"contest_duration": "180",
|
||||
"distinct_users": 4934
|
||||
},
|
||||
{
|
||||
"contest_code": "DEVWEEKEND19",
|
||||
"contest_name": "Weekend Dev Challenge 19: Full Stack Projects using MERN",
|
||||
"contest_start_date": "11 Oct 2025 00:00:00",
|
||||
"contest_end_date": "13 Oct 2025 00:00:00",
|
||||
"contest_start_date_iso": "2025-10-11T00:00:00+05:30",
|
||||
"contest_end_date_iso": "2025-10-13T00:00:00+05:30",
|
||||
"contest_duration": "2880",
|
||||
"distinct_users": 5376
|
||||
},
|
||||
{
|
||||
"contest_code": "START207",
|
||||
"contest_name": "Starters 207 (Rated till 5 star)",
|
||||
"contest_start_date": "08 Oct 2025 20:00:00",
|
||||
"contest_end_date": "08 Oct 2025 22:00:00",
|
||||
"contest_start_date_iso": "2025-10-08T20:00:00+05:30",
|
||||
"contest_end_date_iso": "2025-10-08T22:00:00+05:30",
|
||||
"contest_duration": "120",
|
||||
"distinct_users": 32785
|
||||
},
|
||||
{
|
||||
"contest_code": "DSAMONDAY06",
|
||||
"contest_name": "Monday Munch - DSA Challenge 06",
|
||||
"contest_start_date": "06 Oct 2025 18:00:02",
|
||||
"contest_end_date": "06 Oct 2025 21:00:02",
|
||||
"contest_start_date_iso": "2025-10-06T18:00:02+05:30",
|
||||
"contest_end_date_iso": "2025-10-06T21:00:02+05:30",
|
||||
"contest_duration": "180",
|
||||
"distinct_users": 892
|
||||
},
|
||||
{
|
||||
"contest_code": "DEVWEEKEND18",
|
||||
"contest_name": "Weekend Dev Challenge 18: Full Stack Projects using MERN",
|
||||
"contest_start_date": "04 Oct 2025 00:00:00",
|
||||
"contest_end_date": "06 Oct 2025 00:00:00",
|
||||
"contest_start_date_iso": "2025-10-04T00:00:00+05:30",
|
||||
"contest_end_date_iso": "2025-10-06T00:00:00+05:30",
|
||||
"contest_duration": "2880",
|
||||
"distinct_users": 223
|
||||
},
|
||||
{
|
||||
"contest_code": "START206",
|
||||
"contest_name": "Starters 206 (Rated till 5 star)",
|
||||
"contest_start_date": "01 Oct 2025 20:00:00",
|
||||
"contest_end_date": "01 Oct 2025 22:00:00",
|
||||
"contest_start_date_iso": "2025-10-01T20:00:00+05:30",
|
||||
"contest_end_date_iso": "2025-10-01T22:00:00+05:30",
|
||||
"contest_duration": "120",
|
||||
"distinct_users": 23977
|
||||
},
|
||||
{
|
||||
"contest_code": "DSAMONDAY05",
|
||||
"contest_name": "Monday Munch - DSA Challenge 05",
|
||||
"contest_start_date": "29 Sep 2025 18:00:00",
|
||||
"contest_end_date": "29 Sep 2025 21:00:00",
|
||||
"contest_start_date_iso": "2025-09-29T18:00:00+05:30",
|
||||
"contest_end_date_iso": "2025-09-29T21:00:00+05:30",
|
||||
"contest_duration": "180",
|
||||
"distinct_users": 1160
|
||||
},
|
||||
{
|
||||
"contest_code": "DEVWEEKEND17",
|
||||
"contest_name": "Weekend Dev Challenge 17: GenAI Projects using LLM",
|
||||
"contest_start_date": "27 Sep 2025 00:00:00",
|
||||
"contest_end_date": "29 Sep 2025 00:00:00",
|
||||
"contest_start_date_iso": "2025-09-27T00:00:00+05:30",
|
||||
"contest_end_date_iso": "2025-09-29T00:00:00+05:30",
|
||||
"contest_duration": "2880",
|
||||
"distinct_users": 130
|
||||
},
|
||||
{
|
||||
"contest_code": "START205",
|
||||
"contest_name": "Starters 205 (Rated till 6 star)",
|
||||
"contest_start_date": "24 Sep 2025 20:00:00",
|
||||
"contest_end_date": "24 Sep 2025 22:00:00",
|
||||
"contest_start_date_iso": "2025-09-24T20:00:00+05:30",
|
||||
"contest_end_date_iso": "2025-09-24T22:00:00+05:30",
|
||||
"contest_duration": "120",
|
||||
"distinct_users": 32552
|
||||
},
|
||||
{
|
||||
"contest_code": "DSAMONDAY04",
|
||||
"contest_name": "Monday Munch - DSA Challenge 04",
|
||||
"contest_start_date": "22 Sep 2025 18:00:00",
|
||||
"contest_end_date": "22 Sep 2025 21:00:00",
|
||||
"contest_start_date_iso": "2025-09-22T18:00:00+05:30",
|
||||
"contest_end_date_iso": "2025-09-22T21:00:00+05:30",
|
||||
"contest_duration": "180",
|
||||
"distinct_users": 759
|
||||
},
|
||||
{
|
||||
"contest_code": "DEVWEEKEND16",
|
||||
"contest_name": "Weekend Dev Challenge 16: GenAI Projects using LLM",
|
||||
"contest_start_date": "20 Sep 2025 00:00:00",
|
||||
"contest_end_date": "22 Sep 2025 00:00:00",
|
||||
"contest_start_date_iso": "2025-09-20T00:00:00+05:30",
|
||||
"contest_end_date_iso": "2025-09-22T00:00:00+05:30",
|
||||
"contest_duration": "2880",
|
||||
"distinct_users": 171
|
||||
},
|
||||
{
|
||||
"contest_code": "START204",
|
||||
"contest_name": "Starters 204 (Rated till 5 star)",
|
||||
"contest_start_date": "17 Sep 2025 20:00:00",
|
||||
"contest_end_date": "17 Sep 2025 22:00:00",
|
||||
"contest_start_date_iso": "2025-09-17T20:00:00+05:30",
|
||||
"contest_end_date_iso": "2025-09-17T22:00:00+05:30",
|
||||
"contest_duration": "120",
|
||||
"distinct_users": 36282
|
||||
},
|
||||
{
|
||||
"contest_code": "DSAMONDAY03",
|
||||
"contest_name": "Monday Munch - DSA Challenge 03",
|
||||
"contest_start_date": "15 Sep 2025 18:00:00",
|
||||
"contest_end_date": "15 Sep 2025 21:00:00",
|
||||
"contest_start_date_iso": "2025-09-15T18:00:00+05:30",
|
||||
"contest_end_date_iso": "2025-09-15T21:00:00+05:30",
|
||||
"contest_duration": "180",
|
||||
"distinct_users": 657
|
||||
},
|
||||
{
|
||||
"contest_code": "DEVWEEKEND15",
|
||||
"contest_name": "Weekend Dev Challenge 15: Classify images using Deep Learning",
|
||||
"contest_start_date": "13 Sep 2025 00:00:00",
|
||||
"contest_end_date": "14 Sep 2025 00:00:00",
|
||||
"contest_start_date_iso": "2025-09-13T00:00:00+05:30",
|
||||
"contest_end_date_iso": "2025-09-14T00:00:00+05:30",
|
||||
"contest_duration": "1440",
|
||||
"distinct_users": 112
|
||||
},
|
||||
{
|
||||
"contest_code": "START203",
|
||||
"contest_name": "Starters 203 (Rated till 5 star)",
|
||||
"contest_start_date": "10 Sep 2025 20:00:00",
|
||||
"contest_end_date": "10 Sep 2025 22:00:00",
|
||||
"contest_start_date_iso": "2025-09-10T20:00:00+05:30",
|
||||
"contest_end_date_iso": "2025-09-10T22:00:00+05:30",
|
||||
"contest_duration": "120",
|
||||
"distinct_users": 36512
|
||||
},
|
||||
{
|
||||
"contest_code": "DSAMONDAY02",
|
||||
"contest_name": "Monday Munch - DSA Challenge 02",
|
||||
"contest_start_date": "08 Sep 2025 18:00:00",
|
||||
"contest_end_date": "08 Sep 2025 21:00:00",
|
||||
"contest_start_date_iso": "2025-09-08T18:00:00+05:30",
|
||||
"contest_end_date_iso": "2025-09-08T21:00:00+05:30",
|
||||
"contest_duration": "180",
|
||||
"distinct_users": 737
|
||||
}
|
||||
],
|
||||
"skill_tests": [
|
||||
{
|
||||
"contest_code": "basic-python",
|
||||
"contest_name": "Python Online Test & Quiz",
|
||||
"contest_start_date": "27 Mar 2024 15:00:00",
|
||||
"contest_end_date": "01 Jan 2027 01:30:00",
|
||||
"contest_start_date_iso": "2024-03-27T15:00:00+05:30",
|
||||
"contest_end_date_iso": "2027-01-01T01:30:00+05:30",
|
||||
"contest_duration": "90",
|
||||
"problem_count": 30,
|
||||
"distinct_users": 61244
|
||||
},
|
||||
{
|
||||
"contest_code": "basic-java",
|
||||
"contest_name": "Java Online Test & Quiz",
|
||||
"contest_start_date": "28 Mar 2024 00:00:00",
|
||||
"contest_end_date": "01 Jan 2027 01:30:00",
|
||||
"contest_start_date_iso": "2024-03-28T00:00:00+05:30",
|
||||
"contest_end_date_iso": "2027-01-01T01:30:00+05:30",
|
||||
"contest_duration": "90",
|
||||
"problem_count": 30,
|
||||
"distinct_users": 49993
|
||||
},
|
||||
{
|
||||
"contest_code": "basic-c-language",
|
||||
"contest_name": "C language online test",
|
||||
"contest_start_date": "28 Mar 2024 00:00:00",
|
||||
"contest_end_date": "01 Jan 2027 01:30:00",
|
||||
"contest_start_date_iso": "2024-03-28T00:00:00+05:30",
|
||||
"contest_end_date_iso": "2027-01-01T01:30:00+05:30",
|
||||
"contest_duration": "90",
|
||||
"problem_count": 30,
|
||||
"distinct_users": 41373
|
||||
},
|
||||
{
|
||||
"contest_code": "basic-c-plus-plus",
|
||||
"contest_name": "C++ Online Test and Quiz",
|
||||
"contest_start_date": "28 Mar 2024 00:00:00",
|
||||
"contest_end_date": "01 Jan 2027 01:30:00",
|
||||
"contest_start_date_iso": "2024-03-28T00:00:00+05:30",
|
||||
"contest_end_date_iso": "2027-01-01T01:30:00+05:30",
|
||||
"contest_duration": "90",
|
||||
"problem_count": 30,
|
||||
"distinct_users": 32507
|
||||
},
|
||||
{
|
||||
"contest_code": "basic-sql",
|
||||
"contest_name": "SQL Online Test and Quiz",
|
||||
"contest_start_date": "01 Jun 2024 00:00:00",
|
||||
"contest_end_date": "01 Jan 2027 01:00:00",
|
||||
"contest_start_date_iso": "2024-06-01T00:00:00+05:30",
|
||||
"contest_end_date_iso": "2027-01-01T01:00:00+05:30",
|
||||
"contest_duration": "60",
|
||||
"problem_count": 17,
|
||||
"distinct_users": 17426
|
||||
},
|
||||
{
|
||||
"contest_code": "operating-systems",
|
||||
"contest_name": "Operating Systems Skill Test",
|
||||
"contest_start_date": "01 Jun 2024 00:00:00",
|
||||
"contest_end_date": "01 Jan 2027 00:45:00",
|
||||
"contest_start_date_iso": "2024-06-01T00:00:00+05:30",
|
||||
"contest_end_date_iso": "2027-01-01T00:45:00+05:30",
|
||||
"contest_duration": "45",
|
||||
"problem_count": 30,
|
||||
"distinct_users": 8751
|
||||
},
|
||||
{
|
||||
"contest_code": "c-language-dsa",
|
||||
"contest_name": "Data structures and Algorithms in C test",
|
||||
"contest_start_date": "01 Apr 2024 12:00:00",
|
||||
"contest_end_date": "01 Jan 2027 02:00:00",
|
||||
"contest_start_date_iso": "2024-04-01T12:00:00+05:30",
|
||||
"contest_end_date_iso": "2027-01-01T02:00:00+05:30",
|
||||
"contest_duration": "120",
|
||||
"problem_count": 28,
|
||||
"distinct_users": 6611
|
||||
}
|
||||
],
|
||||
"banners": [
|
||||
{
|
||||
"image": "1760933050.png",
|
||||
"link": "https:\/\/www.codechef.com\/START209"
|
||||
},
|
||||
{
|
||||
"image": "1719492535.png",
|
||||
"link": "https:\/\/www.codechef.com\/roadmap\/data-structures-and-algorithms"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -27,6 +27,11 @@ MATRIX = {
|
|||
"tests": ("1550",),
|
||||
"contests": tuple(),
|
||||
},
|
||||
"codechef": {
|
||||
"metadata": ("START209D",),
|
||||
"tests": ("START209D",),
|
||||
"contests": tuple(),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
30
uv.lock
generated
30
uv.lock
generated
|
|
@ -1,5 +1,5 @@
|
|||
version = 1
|
||||
revision = 3
|
||||
revision = 2
|
||||
requires-python = ">=3.11"
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1539,6 +1539,32 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/d7/25/dd878a121fcfdf38f52850f11c512e13ec87c2ea72385933818e5b6c15ce/requests_file-2.1.0-py2.py3-none-any.whl", hash = "sha256:cf270de5a4c5874e84599fc5778303d496c10ae5e870bfa378818f35d21bda5c", size = 4244, upload-time = "2024-05-21T16:27:57.733Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.14.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ee/34/8218a19b2055b80601e8fd201ec723c74c7fe1ca06d525a43ed07b6d8e85/ruff-0.14.2.tar.gz", hash = "sha256:98da787668f239313d9c902ca7c523fe11b8ec3f39345553a51b25abc4629c96", size = 5539663, upload-time = "2025-10-23T19:37:00.956Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/16/dd/23eb2db5ad9acae7c845700493b72d3ae214dce0b226f27df89216110f2b/ruff-0.14.2-py3-none-linux_armv6l.whl", hash = "sha256:7cbe4e593505bdec5884c2d0a4d791a90301bc23e49a6b1eb642dd85ef9c64f1", size = 12533390, upload-time = "2025-10-23T19:36:18.044Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/8c/5f9acff43ddcf3f85130d0146d0477e28ccecc495f9f684f8f7119b74c0d/ruff-0.14.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:8d54b561729cee92f8d89c316ad7a3f9705533f5903b042399b6ae0ddfc62e11", size = 12887187, upload-time = "2025-10-23T19:36:22.664Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/fa/047646491479074029665022e9f3dc6f0515797f40a4b6014ea8474c539d/ruff-0.14.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5c8753dfa44ebb2cde10ce5b4d2ef55a41fb9d9b16732a2c5df64620dbda44a3", size = 11925177, upload-time = "2025-10-23T19:36:24.778Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/15/8b/c44cf7fe6e59ab24a9d939493a11030b503bdc2a16622cede8b7b1df0114/ruff-0.14.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d0bbeffb8d9f4fccf7b5198d566d0bad99a9cb622f1fc3467af96cb8773c9e3", size = 12358285, upload-time = "2025-10-23T19:36:26.979Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/45/01/47701b26254267ef40369aea3acb62a7b23e921c27372d127e0f3af48092/ruff-0.14.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7047f0c5a713a401e43a88d36843d9c83a19c584e63d664474675620aaa634a8", size = 12303832, upload-time = "2025-10-23T19:36:29.192Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2d/5c/ae7244ca4fbdf2bee9d6405dcd5bc6ae51ee1df66eb7a9884b77b8af856d/ruff-0.14.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bf8d2f9aa1602599217d82e8e0af7fd33e5878c4d98f37906b7c93f46f9a839", size = 13036995, upload-time = "2025-10-23T19:36:31.861Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/27/4c/0860a79ce6fd4c709ac01173f76f929d53f59748d0dcdd662519835dae43/ruff-0.14.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:1c505b389e19c57a317cf4b42db824e2fca96ffb3d86766c1c9f8b96d32048a7", size = 14512649, upload-time = "2025-10-23T19:36:33.915Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/7f/d365de998069720a3abfc250ddd876fc4b81a403a766c74ff9bde15b5378/ruff-0.14.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a307fc45ebd887b3f26b36d9326bb70bf69b01561950cdcc6c0bdf7bb8e0f7cc", size = 14088182, upload-time = "2025-10-23T19:36:36.983Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6c/ea/d8e3e6b209162000a7be1faa41b0a0c16a133010311edc3329753cc6596a/ruff-0.14.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:61ae91a32c853172f832c2f40bd05fd69f491db7289fb85a9b941ebdd549781a", size = 13599516, upload-time = "2025-10-23T19:36:39.208Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fa/ea/c7810322086db68989fb20a8d5221dd3b79e49e396b01badca07b433ab45/ruff-0.14.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1967e40286f63ee23c615e8e7e98098dedc7301568bd88991f6e544d8ae096", size = 13272690, upload-time = "2025-10-23T19:36:41.453Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a9/39/10b05acf8c45786ef501d454e00937e1b97964f846bf28883d1f9619928a/ruff-0.14.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:2877f02119cdebf52a632d743a2e302dea422bfae152ebe2f193d3285a3a65df", size = 13496497, upload-time = "2025-10-23T19:36:43.61Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/59/a1/1f25f8301e13751c30895092485fada29076e5e14264bdacc37202e85d24/ruff-0.14.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e681c5bc777de5af898decdcb6ba3321d0d466f4cb43c3e7cc2c3b4e7b843a05", size = 12266116, upload-time = "2025-10-23T19:36:45.625Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/fa/0029bfc9ce16ae78164e6923ef392e5f173b793b26cc39aa1d8b366cf9dc/ruff-0.14.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e21be42d72e224736f0c992cdb9959a2fa53c7e943b97ef5d081e13170e3ffc5", size = 12281345, upload-time = "2025-10-23T19:36:47.618Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/ab/ece7baa3c0f29b7683be868c024f0838770c16607bea6852e46b202f1ff6/ruff-0.14.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:b8264016f6f209fac16262882dbebf3f8be1629777cf0f37e7aff071b3e9b92e", size = 12629296, upload-time = "2025-10-23T19:36:49.789Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/7f/638f54b43f3d4e48c6a68062794e5b367ddac778051806b9e235dfb7aa81/ruff-0.14.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5ca36b4cb4db3067a3b24444463ceea5565ea78b95fe9a07ca7cb7fd16948770", size = 13371610, upload-time = "2025-10-23T19:36:51.882Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8d/35/3654a973ebe5b32e1fd4a08ed2d46755af7267da7ac710d97420d7b8657d/ruff-0.14.2-py3-none-win32.whl", hash = "sha256:41775927d287685e08f48d8eb3f765625ab0b7042cc9377e20e64f4eb0056ee9", size = 12415318, upload-time = "2025-10-23T19:36:53.961Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/71/30/3758bcf9e0b6a4193a6f51abf84254aba00887dfa8c20aba18aa366c5f57/ruff-0.14.2-py3-none-win_amd64.whl", hash = "sha256:0df3424aa5c3c08b34ed8ce099df1021e3adaca6e90229273496b839e5a7e1af", size = 13565279, upload-time = "2025-10-23T19:36:56.578Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/5d/aa883766f8ef9ffbe6aa24f7192fb71632f31a30e77eb39aa2b0dc4290ac/ruff-0.14.2-py3-none-win_arm64.whl", hash = "sha256:ea9d635e83ba21569fbacda7e78afbfeb94911c9434aff06192d9bc23fd5495a", size = 12554956, upload-time = "2025-10-23T19:36:58.714Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scrapers"
|
||||
version = "0.1.0"
|
||||
|
|
@ -1561,6 +1587,7 @@ dev = [
|
|||
{ name = "pre-commit" },
|
||||
{ name = "pytest" },
|
||||
{ name = "pytest-mock" },
|
||||
{ name = "ruff" },
|
||||
{ name = "types-beautifulsoup4" },
|
||||
{ name = "types-requests" },
|
||||
]
|
||||
|
|
@ -1584,6 +1611,7 @@ dev = [
|
|||
{ name = "pre-commit", specifier = ">=4.3.0" },
|
||||
{ name = "pytest", specifier = ">=8.0.0" },
|
||||
{ name = "pytest-mock", specifier = ">=3.12.0" },
|
||||
{ name = "ruff", specifier = ">=0.14.2" },
|
||||
{ name = "types-beautifulsoup4", specifier = ">=4.12.0.20250516" },
|
||||
{ name = "types-requests", specifier = ">=2.32.4.20250913" },
|
||||
]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue