Repository navigation
Expand file tree
/
Copy pathstats.py
More file actions
58 lines (51 loc) · 1.65 KB
/
Copy pathstats.py
File metadata and controls
58 lines (51 loc) · 1.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
"""关键词命中统计共享模块。"""
import json
import logging
import os
import tempfile
from pathlib import Path
logger = logging.getLogger(__name__)
STATS_FILE = Path(os.getenv("STATS_FILE", "stats.json"))
def load_stats() -> dict[str, int]:
"""从 STATS_FILE 加载统计,文件缺失返回空字典。"""
if not STATS_FILE.exists():
return {}
try:
raw = STATS_FILE.read_text(encoding="utf-8")
data = json.loads(raw)
except (json.JSONDecodeError, OSError) as exc:
logger.warning("Failed to load stats from %s: %s", STATS_FILE, exc)
return {}
stats = data.get("stats", {})
if not isinstance(stats, dict):
logger.warning("Invalid stats format in %s, expected dict", STATS_FILE)
return {}
result: dict[str, int] = {}
for k, v in stats.items():
try:
result[str(k)] = int(v)
except (ValueError, TypeError):
logger.warning("Skipping invalid stats entry: %s=%s", k, v)
return result
def save_stats(stats: dict[str, int]) -> None:
"""原子写入统计到 STATS_FILE(临时文件 + rename)。"""
content = json.dumps({"stats": stats}, ensure_ascii=False, indent=2) + "\n"
fd, tmp_path = tempfile.mkstemp(
dir=str(STATS_FILE.parent),
prefix=f".{STATS_FILE.name}.tmp.",
)
try:
try:
os.write(fd, content.encode("utf-8"))
except OSError:
os.close(fd)
raise
else:
os.close(fd)
os.replace(tmp_path, STATS_FILE)
except OSError:
try:
os.unlink(tmp_path)
except OSError:
pass
raise