From d700bc1dfd0542fe51ede7c5c690660a28b39136 Mon Sep 17 00:00:00 2001 From: aszerW Date: Wed, 3 Jun 2026 09:14:53 +0800 Subject: [PATCH] =?UTF-8?q?fix(rotation):=20=E5=9B=9E=E6=B5=8B=E5=AF=BC?= =?UTF-8?q?=E5=87=BAJSON=E5=BA=8F=E5=88=97=E5=8C=96NaN/Inf=E6=B8=85?= =?UTF-8?q?=E6=B4=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - simple_rotation.py: 新增 _sanitize_json() 递归替换 NaN/Inf 为 None, 确保 json.dump 生成合法 JSON(避免前端解析失败) - .env: 注释掉群2钉钉配置(暂不使用) --- .env | 4 ++-- rotation/simple_rotation.py | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/.env b/.env index 8c0d9f0..63f0545 100644 --- a/.env +++ b/.env @@ -8,8 +8,8 @@ DINGTALK_WEBHOOK_1=https://oapi.dingtalk.com/robot/send?access_token=fb70c1561d8 DINGTALK_SECRET_1=SEC1ae7cd2f1a6f9da3611af37da3e7d954c1e8533fc073c6c8cc5e5af3b6e5926b # 钉钉机器人配置 - 群2 -DINGTALK_WEBHOOK_2=https://oapi.dingtalk.com/robot/send?access_token=87c7abfcdd69b699c32da4e4f5981cd2ca6b0445474fc6ffb36f2ed0f6262fbb -DINGTALK_SECRET_2=SECf3d6b43f2f8a87ab91feffd052e71ec314fbf57a1842e483fe07af3c0a0e5aa6 +# DINGTALK_WEBHOOK_2=https://oapi.dingtalk.com/robot/send?access_token=87c7abfcdd69b699c32da4e4f5981cd2ca6b0445474fc6ffb36f2ed0f6262fbb +# DINGTALK_SECRET_2=SECf3d6b43f2f8a87ab91feffd052e71ec314fbf57a1842e483fe07af3c0a0e5aa6 diff --git a/rotation/simple_rotation.py b/rotation/simple_rotation.py index 6e70df3..50bf7bc 100644 --- a/rotation/simple_rotation.py +++ b/rotation/simple_rotation.py @@ -40,6 +40,22 @@ def _http_get(url: str, params: dict = None, timeout: int = 120) -> requests.Res return _session.get(url, params=params, timeout=timeout) +def _sanitize_json(obj): + """Recursively replace NaN/Inf with None in-place so json.dump produces valid JSON""" + if isinstance(obj, dict): + for k, v in obj.items(): + if isinstance(v, float) and (math.isnan(v) or math.isinf(v)): + obj[k] = None + elif isinstance(v, (dict, list)): + _sanitize_json(v) + elif isinstance(obj, list): + for i, v in enumerate(obj): + if isinstance(v, float) and (math.isnan(v) or math.isinf(v)): + obj[i] = None + elif isinstance(v, (dict, list)): + _sanitize_json(v) + + # ============================================================ # Pure functions: momentum # ============================================================ @@ -888,6 +904,7 @@ class SimpleRotationStrategy: }, 'days': days_out, } + _sanitize_json(detail) with open(detail_path, 'w', encoding='utf-8') as f: json.dump(detail, f, ensure_ascii=False, indent=2) print(f" + Detail: {detail_path} ({len(days_out)} days)") @@ -895,6 +912,7 @@ class SimpleRotationStrategy: # Metrics JSON metrics = self._compute_metrics(sum(1 for r in self.daily_records if r['is_rebalance'])) metrics_path = output_dir / 'simple_rotation_metrics.json' + _sanitize_json(metrics) with open(metrics_path, 'w', encoding='utf-8') as f: json.dump(metrics, f, ensure_ascii=False, indent=2) print(f" + Metrics: {metrics_path}")