refactor: enforce BasedPyright strict type checking (#5158)

This commit is contained in:
chengyongru
2026-07-29 21:37:11 +08:00
committed by GitHub
parent e703481755
commit 757ad9c764
166 changed files with 4728 additions and 2621 deletions
+32 -35
View File
@@ -13,12 +13,12 @@ import string
import threading
import time
from pathlib import Path
from typing import Any
from typing import Any, cast
from loguru import logger
from nanobot.config.paths import get_data_dir
from nanobot.utils.helpers import _write_text_atomic
from nanobot.utils.helpers import _write_text_atomic # pyright: ignore[reportPrivateUsage]
# threading.Lock is used so store functions remain callable from both sync CLI
# and async channel handlers. At private-assistant scale (small JSON file,
@@ -47,21 +47,20 @@ def _load() -> dict[str, Any]:
logger.warning("Corrupted pairing store, resetting")
return {"approved": {}, "pending": {}}
# JSON stores may contain null maps after partial edits; treat like {}.
approved = data.get("approved") or {}
if not isinstance(approved, dict):
approved = {}
# JSON stores may contain null or malformed maps after partial edits; treat like {}.
data = cast(dict[str, Any], data)
raw_approved = data.get("approved")
approved = cast(dict[str, Any], raw_approved) if isinstance(raw_approved, dict) else {}
data["approved"] = approved
pending = data.get("pending") or {}
if not isinstance(pending, dict):
pending = {}
raw_pending = data.get("pending")
pending = cast(dict[str, Any], raw_pending) if isinstance(raw_pending, dict) else {}
data["pending"] = pending
# Convert approved lists to str sets for O(1) lookup.
for channel, users in approved.items():
if not isinstance(users, list):
users = []
data["approved"][channel] = {str(u) for u in users}
data["approved"][channel] = {str(user) for user in cast(list[object], users)}
return data
@@ -69,14 +68,12 @@ def _save(data: dict[str, Any]) -> None:
path = _store_path()
path.parent.mkdir(parents=True, exist_ok=True)
# Convert sets back to lists for JSON serialization
approved = data.get("approved") or {}
pending = data.get("pending") or {}
if not isinstance(approved, dict):
approved = {}
if not isinstance(pending, dict):
pending = {}
payload = {
"approved": {ch: sorted(list(users)) for ch, users in approved.items()},
raw_approved = data.get("approved")
approved = cast(dict[str, Any], raw_approved) if isinstance(raw_approved, dict) else {}
raw_pending = data.get("pending")
pending = cast(dict[str, Any], raw_pending) if isinstance(raw_pending, dict) else {}
payload: dict[str, Any] = {
"approved": {ch: sorted(list(cast(set[str], users))) for ch, users in approved.items()},
"pending": dict(pending),
}
_write_text_atomic(path, json.dumps(payload, indent=2, ensure_ascii=False))
@@ -86,22 +83,22 @@ def _gc_pending(data: dict[str, Any]) -> None:
"""Remove expired pending entries in-place."""
now = time.time()
pending: dict[str, Any] = data.get("pending") or {}
if not isinstance(pending, dict):
data["pending"] = {}
return
expired = [
code
for code, info in pending.items()
expired: list[str] = []
for code, info in pending.items():
if not isinstance(info, dict):
expired.append(code)
continue
entry = cast(dict[str, Any], info)
expires_at = entry.get("expires_at")
if (
not isinstance(info, dict)
or not isinstance(info.get("channel"), str)
or not info.get("channel")
or info.get("sender_id") is None
or isinstance(info.get("expires_at"), bool)
or not isinstance(info.get("expires_at"), (int, float))
or info["expires_at"] < now
)
]
not isinstance(entry.get("channel"), str)
or not entry["channel"]
or entry.get("sender_id") is None
or isinstance(expires_at, bool)
or not isinstance(expires_at, (int, float))
or expires_at < now
):
expired.append(code)
for code in expired:
del pending[code]
data["pending"] = pending
@@ -322,13 +319,13 @@ def handle_pairing_command(channel: str, subcommand_text: str) -> str:
if len(parts) == 2:
return (
f"Revoked {arg} from {channel}"
if revoke(channel, arg)
if revoke(channel, parts[1])
else f"{arg} was not in the approved list for {channel}"
)
if len(parts) == 3:
return (
f"Revoked {parts[2]} from {arg}"
if revoke(arg, parts[2])
if revoke(parts[1], parts[2])
else f"{parts[2]} was not in the approved list for {arg}"
)
return "Usage: `/pairing revoke <user_id>` or `/pairing revoke <channel> <user_id>`"