feat!: adopt Python 3.15 and support BattlesnakeArena
- Require Python 3.15 in project metadata, runtime pin, and Docker stages. - Use lazy imports for database backends and type-only dependencies. - Defer benchmark dependencies until their code paths are used. - Rely on deferred annotations and use Path.info for file discovery. - Accept BattlesnakeArena alongside BattlesnakeEngine on game endpoints. - Advance quart_common for Python 3.15 and multi-agent validation. - Add pytest development dependencies and refresh the uv lockfile. - Test lazy backend loading, import order, and fresh file discovery. - Document the runtime requirements and locked uv workflow. BREAKING CHANGE: Python 3.15 or newer is required; earlier runtimes cannot parse the lazy import syntax.
This commit is contained in:
@@ -5,8 +5,6 @@ For outcome/win-rate tournaments use the local Battlesnake CLI. This harness is
|
||||
fast enough for CI and detects move disagreements, crashes, and latency changes.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Benchmark snake move latency against sampled states from gameplay SQLite."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
import sqlite3
|
||||
@@ -15,8 +12,8 @@ sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
from server.database.benchmark_states import (
|
||||
_build_state, is_postgresql_source, load_postgresql_states,
|
||||
)
|
||||
from server.GameBoard import GameBoard
|
||||
from snakes import SnakeBuilder
|
||||
lazy from server.GameBoard import GameBoard
|
||||
lazy from snakes import SnakeBuilder
|
||||
|
||||
def percentile(values: list[float], quantile: float) -> float:
|
||||
ordered = sorted(values)
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Delete old low-quality replay payloads while preserving game results."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from typing import Iterable
|
||||
from collections.abc import Iterable
|
||||
from urllib.parse import urlencode
|
||||
from urllib.request import urlopen
|
||||
import shutil
|
||||
@@ -84,14 +81,14 @@ def prune_output(output_root:Path, wanted_files:set[Path]) -> int:
|
||||
return 0
|
||||
|
||||
for file_path in output_root.rglob("*"):
|
||||
if not file_path.is_file():
|
||||
if not file_path.info.is_file():
|
||||
continue
|
||||
if file_path not in wanted_files:
|
||||
file_path.unlink()
|
||||
removed += 1
|
||||
|
||||
for directory in sorted(
|
||||
(p for p in output_root.rglob("*") if p.is_dir()), reverse=True
|
||||
(p for p in output_root.rglob("*") if p.info.is_dir()), reverse=True
|
||||
):
|
||||
if any(directory.iterdir()):
|
||||
continue
|
||||
|
||||
@@ -6,9 +6,6 @@ row IDs are regenerated, delta games are quality-rated, and all result rows are
|
||||
kept even when their replay is excluded. The base can be replaced only after
|
||||
verification and a timestamped backup.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from collections import Counter
|
||||
from datetime import datetime, timezone
|
||||
|
||||
@@ -5,9 +5,6 @@ The source is always opened read-only. The destination is written separately,
|
||||
verified, and can optionally replace the source after a timestamped backup is
|
||||
created. No in-place schema rewrite is performed.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from datetime import datetime, timezone
|
||||
import json
|
||||
|
||||
@@ -5,9 +5,6 @@ The source is opened read-only. Rows are copied in bounded batches through
|
||||
temporary PostgreSQL tables, then inserted idempotently with ON CONFLICT. The
|
||||
script verifies source/inserted row counts and never modifies the SQLite file.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Run paired seeded games through the official local Battlesnake rules engine."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
"""Deterministic scenario corpus for the local snake arena."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from copy import deepcopy
|
||||
|
||||
from tests.bench_best_battle_snake import build_game_state
|
||||
|
||||
Reference in New Issue
Block a user