From 39ef90b3fdc5b62c7feee4c204edb612ffbf42bd Mon Sep 17 00:00:00 2001 From: NotSoToothless <67082114+FURRO404@users.noreply.github.com> Date: Wed, 13 May 2026 23:42:47 -0700 Subject: [PATCH] =?UTF-8?q?Auto=20merge=20dev=20=E2=86=92=20main=20(#1225)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix BOT.data_parser import in render_recap.py render_recap.py runs as a subprocess (Path(__file__).parent.parent on sys.path) and used `from BOT.data_parser import ...`. After the SHARED move, data_parser is no longer in the BOT package. Add BOTS/SHARED to sys.path and switch to the absolute `from data_parser import ...`. Co-Authored-By: Claude Opus 4.7 (1M context) * centralize SHARED sys.path bootstrap in BOT/__init__.py Drop per-file `sys.path.insert(SHARED)` bandaids from BOT/scoreboard.py, gob.py, utils.py, and game_api.py. The bootstrap now happens exactly once when the BOT package is imported (via BOT/__init__.py), which is implicit for any `from BOT.X import …` / `import BOT.X` and any `python -m BOT.x` invocation. `SHARED_DIR` is exposed as a public name on the BOT package; siblings import it via `from . import SHARED_DIR` for building asset paths (MAPS, ICONS, FONTS, vromfs) instead of recomputing the location. render_recap.py is the one subprocess entry point that runs as __main__, so it keeps a minimal bootstrap: add SREBOT to sys.path then `import BOT` to fire the package init once. Also move pyrightconfig.json to the BOTS monorepo root so pyright resolves data_parser and third-party imports regardless of which subproject the editor opens from. Co-Authored-By: Claude Opus 4.7 (1M context) --------- Co-authored-by: Claude Opus 4.7 (1M context) --- BOT/__init__.py | 18 ++++++++++++------ BOT/game_api.py | 7 +------ BOT/gob.py | 14 +++++--------- BOT/render_recap.py | 10 ++++++---- BOT/scoreboard.py | 14 +++++--------- BOT/utils.py | 14 ++++++-------- pyrightconfig.json | 14 -------------- 7 files changed, 35 insertions(+), 56 deletions(-) delete mode 100644 pyrightconfig.json diff --git a/BOT/__init__.py b/BOT/__init__.py index 693a8a3..6e7a51f 100644 --- a/BOT/__init__.py +++ b/BOT/__init__.py @@ -1,12 +1,18 @@ """SREBOT bot package. -Bootstraps the sibling BOTS/SHARED directory onto sys.path so that -`from data_parser import ...` (and other SHARED-only modules) resolve -regardless of which submodule gets imported first. +Single source of truth for the BOTS/SHARED bootstrap. Importing this +package (which happens automatically for any `from BOT.X import ...` +or `import BOT.X`) puts the sibling `BOTS/SHARED/` directory on +sys.path, so submodules can simply `from data_parser import ...` etc. + +`SHARED_DIR` is also re-exported so consumers can compute asset paths +(MAPS, ICONS, FONTS, vromfs) without re-deriving the location. """ import sys from pathlib import Path -_SHARED_DIR = Path(__file__).resolve().parents[2] / "SHARED" -if str(_SHARED_DIR) not in sys.path: - sys.path.insert(0, str(_SHARED_DIR)) +SHARED_DIR: Path = Path(__file__).resolve().parents[2] / "SHARED" +if str(SHARED_DIR) not in sys.path: + sys.path.insert(0, str(SHARED_DIR)) + +__all__ = ["SHARED_DIR"] diff --git a/BOT/game_api.py b/BOT/game_api.py index f4eb74e..dc768b1 100644 --- a/BOT/game_api.py +++ b/BOT/game_api.py @@ -12,7 +12,6 @@ import json import logging import os import sqlite3 -import sys import time from pathlib import Path from typing import Any, Dict, Tuple @@ -23,11 +22,7 @@ import aiohttp import aiosqlite from dotenv import load_dotenv -# Ensure project root is in path for DAGOR_FILES imports -_project_root = Path(__file__).resolve().parent.parent -if str(_project_root) not in sys.path: - sys.path.insert(0, str(_project_root)) - +# DAGOR_FILES lives in BOTS/SHARED; BOT/__init__.py already put it on sys.path. from DAGOR_FILES.WtFileUtils.blk.BlkParser import BlkDecoder # Local Module Imports diff --git a/BOT/gob.py b/BOT/gob.py index 08d79c5..1c8d7f3 100644 --- a/BOT/gob.py +++ b/BOT/gob.py @@ -33,14 +33,10 @@ import numpy as np import pygob import zstandard as zstd +from . import SHARED_DIR from .utils import REPLAYS_DIR from PIL import Image, ImageDraw, ImageFilter, ImageFont -# Make SHARED (sibling of SREBOT under BOTS/) importable -_SHARED_DIR = Path(__file__).resolve().parents[2] / "SHARED" -if str(_SHARED_DIR) not in sys.path: - sys.path.insert(0, str(_SHARED_DIR)) - try: from data_parser import ( LangTableReader as _LangTableReader, @@ -114,9 +110,9 @@ N_WORKERS = min(8, os.cpu_count() or 4) # Thread pool size for parallel frame WIN_COLOR = (0, 200, 0) # green LOSE_COLOR = (220, 30, 30) # red -MINIMAPS_DIR = _SHARED_DIR / "MAPS" / "MINIMAPS" -LEVELS_DIR = _SHARED_DIR / "MAPS" / "LEVELS" -ICONS_DIR = _SHARED_DIR / "ICONS" +MINIMAPS_DIR = SHARED_DIR / "MAPS" / "MINIMAPS" +LEVELS_DIR = SHARED_DIR / "MAPS" / "LEVELS" +ICONS_DIR = SHARED_DIR / "ICONS" _tl = threading.local() @@ -221,7 +217,7 @@ def _get_unit_tags(internal_name: str) -> list[str] | None: return UnitTags.get()._get_tags(internal_name) -MINIS_DIR = _SHARED_DIR / "ICONS" / "MINIS" +MINIS_DIR = SHARED_DIR / "ICONS" / "MINIS" _AIRCRAFT_TAGS = {"air", "aircraft", "helicopter"} diff --git a/BOT/render_recap.py b/BOT/render_recap.py index b4515e7..5bfa7bd 100644 --- a/BOT/render_recap.py +++ b/BOT/render_recap.py @@ -69,11 +69,13 @@ def _sanitize_render_text(s: str) -> str: ) -_repo_root = Path(__file__).resolve().parent.parent -if str(_repo_root) not in sys.path: - sys.path.insert(0, str(_repo_root)) +# This script runs as a subprocess entry point (python BOT/render_recap.py …), +# so BOT/__init__.py is not invoked automatically. Put SREBOT on sys.path, +# then `import BOT` to trigger the package's SHARED bootstrap once. +sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) +import BOT # noqa: F401, E402 — side effect: adds BOTS/SHARED to sys.path -from BOT.data_parser import apply_vehicle_name_filters # noqa: E402 +from data_parser import apply_vehicle_name_filters # noqa: E402 LOCALES_DIR = Path(__file__).resolve().parent.parent / "web" / "locales" DEFAULT_LANG = "en" diff --git a/BOT/scoreboard.py b/BOT/scoreboard.py index 3b16417..226e5fa 100644 --- a/BOT/scoreboard.py +++ b/BOT/scoreboard.py @@ -14,7 +14,6 @@ import logging import os import pstats import re -import sys from datetime import datetime, timezone from functools import lru_cache from pathlib import Path @@ -24,12 +23,9 @@ import numpy as np from PIL import Image, ImageDraw, ImageFilter, ImageFont from PIL.Image import Resampling -# Make SHARED (sibling of SREBOT under BOTS/) importable -_SHARED_DIR = Path(__file__).resolve().parents[2] / "SHARED" -if str(_SHARED_DIR) not in sys.path: - sys.path.insert(0, str(_SHARED_DIR)) - # Local Module Imports +from . import SHARED_DIR + # Toggle for data_parser dependency # Set to False to avoid importing data_parser and show all vehicles as "?" in team composition USE_DATA_PARSER = True @@ -45,9 +41,9 @@ else: return name BASE_DIR = Path(__file__).resolve().parent -MAPS_DIR = _SHARED_DIR / "MAPS" -ICON_BASE_DIR = _SHARED_DIR / "ICONS" -TEXT_FONT_PATH = _SHARED_DIR / "FONTS" / "arial_unicode_ms.otf" +MAPS_DIR = SHARED_DIR / "MAPS" +ICON_BASE_DIR = SHARED_DIR / "ICONS" +TEXT_FONT_PATH = SHARED_DIR / "FONTS" / "arial_unicode_ms.otf" def _normalize_squad_key(value: str | None) -> str: diff --git a/BOT/utils.py b/BOT/utils.py index 781d34a..3a95c9d 100644 --- a/BOT/utils.py +++ b/BOT/utils.py @@ -30,12 +30,10 @@ from discord.utils import escape_markdown, escape_mentions from dotenv import load_dotenv from wcwidth import wcswidth -# Make SHARED (sibling of SREBOT under BOTS/) importable -_SHARED_DIR = Path(__file__).resolve().parents[2] / "SHARED" -if str(_SHARED_DIR) not in sys.path: - sys.path.insert(0, str(_SHARED_DIR)) - # Local Module Imports +# BOT/__init__.py has already put BOTS/SHARED on sys.path; re-export it +# under a public name so peer modules can use it for asset paths. +from . import SHARED_DIR # noqa: F401 — re-exported for siblings from data_parser import ( LangTableReader, UnitTags, @@ -64,7 +62,7 @@ def esc(text: str) -> str: # Base storage paths STORAGE_DIR = require_storage_dir() -ICONS_DIR = _SHARED_DIR / "ICONS" +ICONS_DIR = SHARED_DIR / "ICONS" # Cache and Auth directories CACHE_DIR = STORAGE_DIR / "CACHE" @@ -1411,7 +1409,7 @@ async def init_game_cache(): all_names = unit_tags.all_names logging.info(f"[GAMES] TOTAL VEHICLES: {len(all_names)}") - icons_dir = _SHARED_DIR / "ICONS" / "VEHICLES" + icons_dir = SHARED_DIR / "ICONS" / "VEHICLES" # Case-insensitive lookup: unittags.blk uses CDKs like "ussr_su_122P" while the # icon file on disk is "ussr_su_122p.png". On case-sensitive filesystems an exact # match silently drops these vehicles from the cache. @@ -1445,7 +1443,7 @@ async def init_game_cache_all(): all_names = unit_tags.all_names logging.info(f"[GAMES] TOTAL VEHICLES (ALL): {len(all_names)}") - icons_dir = _SHARED_DIR / "ICONS" / "VEHICLES" + icons_dir = SHARED_DIR / "ICONS" / "VEHICLES" icons_on_disk = {p.name.lower(): p.name for p in icons_dir.iterdir() if p.suffix == ".png"} if icons_dir.is_dir() else {} translate = LangTableReader("English") diff --git a/pyrightconfig.json b/pyrightconfig.json deleted file mode 100644 index 731c0c8..0000000 --- a/pyrightconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "pythonVersion": "3.14", - "extraPaths": [ - ".venv/lib/python3.14/site-packages", - "../SHARED" - ], - "exclude": [ - ".venv", - "../SHARED/DAGOR_FILES", - "web/node_modules", - "node_modules", - "**/__pycache__" - ] -}