diff --git a/src/kernelbot/api/main.py b/src/kernelbot/api/main.py index 9c5f99099..d9f98973b 100644 --- a/src/kernelbot/api/main.py +++ b/src/kernelbot/api/main.py @@ -887,55 +887,6 @@ async def get_gpus( raise HTTPException(status_code=500, detail=f"Error fetching GPU data: {e}") from e -@app.get("/leaderboard/{leaderboard_id}/rankings") -async def get_leaderboard_rankings( - leaderboard_id: int, - user_info: Annotated[Optional[Any], Depends(optional_user_header)] = None, - db_context=Depends(get_db), -) -> dict: - """Return canonical leaderboard metadata and rankings for all runners.""" - await simple_rate_limit() - try: - with db_context as db: - leaderboard = db.get_leaderboard_by_id(leaderboard_id) - enforce_leaderboard_access(db, leaderboard["name"], user_info) - - rankings = {} - for gpu_type in leaderboard["gpu_types"]: - ranked_entries = db.get_leaderboard_submissions(leaderboard["name"], gpu_type) - rankings[gpu_type] = [ - { - "user_name": entry["user_name"], - "score": entry["submission_score"], - "file_name": entry["submission_name"], - "submission_id": entry["submission_id"], - "submission_count": entry.get("submission_count", 0), - "submission_time": entry["submission_time"], - } - for entry in ranked_entries - ] - - task = leaderboard["task"] - return { - "rankings": rankings, - "leaderboard": { - "name": leaderboard["name"], - "deadline": leaderboard["deadline"], - "lang": task.lang.value, - "description": leaderboard["description"], - "reference": task.files.get("reference.py", ""), - "benchmarks": task.benchmarks, - "gpu_types": leaderboard["gpu_types"], - }, - } - except HTTPException: - raise - except KernelBotError: - raise - except Exception as e: - raise HTTPException(status_code=500, detail=f"Error fetching leaderboard rankings: {e}") from e - - @app.get("/submissions/{leaderboard_name}/{gpu_name}") async def get_submissions( leaderboard_name: str, diff --git a/src/libkernelbot/db_types.py b/src/libkernelbot/db_types.py index c28ea7bff..ee1e84a35 100644 --- a/src/libkernelbot/db_types.py +++ b/src/libkernelbot/db_types.py @@ -30,7 +30,6 @@ class LeaderboardRankedEntry(TypedDict): submission_name: str submission_time: datetime.datetime submission_score: float - submission_count: NotRequired[int] leaderboard_name: str user_id: int user_name: str diff --git a/src/libkernelbot/leaderboard_db.py b/src/libkernelbot/leaderboard_db.py index 926903323..6f1413e7c 100644 --- a/src/libkernelbot/leaderboard_db.py +++ b/src/libkernelbot/leaderboard_db.py @@ -654,35 +654,6 @@ def get_leaderboard(self, leaderboard_name: str) -> "LeaderboardItem": else: raise LeaderboardDoesNotExist(leaderboard_name) - def get_leaderboard_by_id(self, leaderboard_id: int) -> "LeaderboardItem": - self.cursor.execute( - """ - SELECT id, name, deadline, task, creator_id, forum_id, secret_seed, description, visibility - FROM leaderboard.leaderboard - WHERE id = %s - """, - (leaderboard_id,), - ) - - res = self.cursor.fetchone() - - if res: - task = LeaderboardTask.from_dict(res[3]) - return LeaderboardItem( - id=res[0], - name=res[1], - deadline=res[2], - task=task, - creator_id=res[4], - forum_id=res[5], - secret_seed=res[6], - gpu_types=self.get_leaderboard_gpu_types(res[1]), - description=res[7], - visibility=res[8], - ) - else: - raise LeaderboardDoesNotExist(str(leaderboard_id)) - def check_leaderboard_access(self, leaderboard_name: str, user_id: str) -> bool: """Returns True if leaderboard is public or user has claimed an invite covering this leaderboard.""" self.cursor.execute( @@ -894,14 +865,6 @@ def get_leaderboard_submissions( if user_id: # Query all if user_id (means called from show-personal) query = """ - WITH submission_counts AS ( - SELECT s.user_id, r.runner, COUNT(DISTINCT s.id) AS submission_count - FROM leaderboard.submission s - JOIN leaderboard.runs r ON r.submission_id = s.id - JOIN leaderboard.leaderboard l ON s.leaderboard_id = l.id - WHERE l.name = %s - GROUP BY s.user_id, r.runner - ) SELECT s.file_name, s.id, @@ -910,13 +873,11 @@ def get_leaderboard_submissions( r.score, r.runner, ui.user_name, - RANK() OVER (ORDER BY r.score ASC) as rank, - COALESCE(sc.submission_count, 0) AS submission_count + RANK() OVER (ORDER BY r.score ASC) as rank FROM leaderboard.runs r JOIN leaderboard.submission s ON r.submission_id = s.id JOIN leaderboard.leaderboard l ON s.leaderboard_id = l.id JOIN leaderboard.user_info ui ON s.user_id = ui.id - LEFT JOIN submission_counts sc ON s.user_id = sc.user_id AND r.runner = sc.runner WHERE l.name = %s AND r.runner = %s AND NOT r.secret @@ -934,19 +895,11 @@ def get_leaderboard_submissions( ORDER BY r.score ASC LIMIT %s OFFSET %s """ - args = (leaderboard_name, leaderboard_name, gpu_name, user_id, limit, offset) + args = (leaderboard_name, gpu_name, user_id, limit, offset) else: # Query best submission per user if no user_id (means called from show) query = """ - WITH submission_counts AS ( - SELECT s.user_id, r.runner, COUNT(DISTINCT s.id) AS submission_count - FROM leaderboard.submission s - JOIN leaderboard.runs r ON r.submission_id = s.id - JOIN leaderboard.leaderboard l ON s.leaderboard_id = l.id - WHERE l.name = %s - GROUP BY s.user_id, r.runner - ), - best_submissions AS ( + WITH best_submissions AS ( SELECT DISTINCT ON (s.user_id) s.id as submission_id, s.file_name, @@ -978,15 +931,13 @@ def get_leaderboard_submissions( bs.score, bs.runner, ui.user_name, - RANK() OVER (ORDER BY bs.score ASC) as rank, - COALESCE(sc.submission_count, 0) AS submission_count + RANK() OVER (ORDER BY bs.score ASC) as rank FROM best_submissions bs JOIN leaderboard.user_info ui ON bs.user_id = ui.id - LEFT JOIN submission_counts sc ON bs.user_id = sc.user_id AND bs.runner = sc.runner ORDER BY bs.score ASC LIMIT %s OFFSET %s """ - args = (leaderboard_name, leaderboard_name, gpu_name, limit, offset) + args = (leaderboard_name, gpu_name, limit, offset) self.cursor.execute(query, args) @@ -999,7 +950,6 @@ def get_leaderboard_submissions( submission_score=submission[4], user_name=submission[6], rank=submission[7], - submission_count=submission[8], leaderboard_name=leaderboard_name, gpu_type=gpu_name, ) diff --git a/tests/test_admin_api.py b/tests/test_admin_api.py index dc8263cbb..2ad3ab3dd 100644 --- a/tests/test_admin_api.py +++ b/tests/test_admin_api.py @@ -700,83 +700,6 @@ def test_public_leaderboard_submissions_no_auth(self, test_client, mock_backend) response = test_client.get("/submissions/public-lb/A100") assert response.status_code == 200 - - def test_public_leaderboard_rankings_no_auth(self, test_client, mock_backend): - """GET /leaderboard/{id}/rankings returns metadata and all GPU rankings.""" - from libkernelbot.consts import Language - from libkernelbot.task import LeaderboardTask, PythonTaskData - - self._setup_db_mock(mock_backend) - task = LeaderboardTask( - lang=Language.Python, - files={"reference.py": "def ref(): pass"}, - config=PythonTaskData(main="eval.py"), - benchmarks=[{"n": 32}], - ) - mock_backend.db.get_leaderboard_by_id = MagicMock( - return_value={ - "id": 123, - "name": "qr_v2", - "deadline": "2026-06-30T00:00:00Z", - "description": "QR", - "task": task, - "gpu_types": ["B200"], - "visibility": "public", - } - ) - mock_backend.db.get_leaderboard = MagicMock(return_value={"visibility": "public"}) - mock_backend.db.get_leaderboard_submissions = MagicMock( - return_value=[ - { - "user_name": "mark", - "submission_score": 1.5, - "submission_name": "submission.py", - "submission_id": 42, - "submission_count": 3, - "submission_time": "2026-06-17T00:00:00Z", - } - ] - ) - - response = test_client.get("/leaderboard/123/rankings") - assert response.status_code == 200 - assert response.json() == { - "rankings": { - "B200": [ - { - "user_name": "mark", - "score": 1.5, - "file_name": "submission.py", - "submission_id": 42, - "submission_count": 3, - "submission_time": "2026-06-17T00:00:00Z", - } - ] - }, - "leaderboard": { - "name": "qr_v2", - "deadline": "2026-06-30T00:00:00Z", - "lang": "py", - "description": "QR", - "reference": "def ref(): pass", - "benchmarks": [{"n": 32}], - "gpu_types": ["B200"], - }, - } - - def test_missing_leaderboard_rankings_returns_404(self, test_client, mock_backend): - """GET /leaderboard/{id}/rankings returns 404 for a missing leaderboard.""" - from libkernelbot.leaderboard_db import LeaderboardDoesNotExist - - self._setup_db_mock(mock_backend) - mock_backend.db.get_leaderboard_by_id = MagicMock( - side_effect=LeaderboardDoesNotExist("999") - ) - - response = test_client.get("/leaderboard/999/rankings") - assert response.status_code == 404 - - class TestAdminExportHF: """Test admin HF export endpoint.""" diff --git a/tests/test_leaderboard_db.py b/tests/test_leaderboard_db.py index a1ea6e89e..1da4a5223 100644 --- a/tests/test_leaderboard_db.py +++ b/tests/test_leaderboard_db.py @@ -350,7 +350,6 @@ def test_leaderboard_submission_ranked(database, submit_leaderboard): "rank": 1, "submission_id": 2, "submission_name": "submission.py", - "submission_count": 3, "submission_score": Decimal("4.5"), "submission_time": submit_time, "user_id": "5", @@ -362,7 +361,6 @@ def test_leaderboard_submission_ranked(database, submit_leaderboard): "rank": 2, "submission_id": 4, "submission_name": "submission.py", - "submission_count": 1, "submission_score": Decimal("8.0"), "submission_time": submit_time, "user_id": "6",