fix(core): 补齐 get_rng 类型校验,set_seed 覆盖 numpy 旧全局

get_rng 的"共享单例生成器"设计由用户本人提出,本提交只在其上修 bug。

- random_state 判断从 isinstance(x, int) 放宽到 (int, np.integer):
  np.int64 不是 int 的子类,之前会静默退回全局流、种子被无声忽略
- 非预期类型改成抛 TypeError(含 bool / float / str / list),不再静默降级
- get_rng 签名补上 np.integer 与 Generator,与 docstring 的承诺一致
- set_seed 同时调用 np.random.seed:sklearn / statsmodels 走的是 numpy
  旧全局状态,不覆盖它们"提交能重跑"就有洞(带 noqa: NPY002 与理由)
- 测试:TestRandom 由 4 条增到 7 条(np.integer、非法类型、共享生成器推进)
- 新增 docs/dev/personal-pitfalls.md:个人易错点清单,只追加、不通读,
  首批记录本轮 4 个点;docs/README.md 补上 05 与该文件的索引
- STATUS.md:L0 进度说明更新,决策 24 改写(共享单例)、新增决策 25
  (src/ 实现默认由用户本人写)
This commit is contained in:
guzhujushi committed 2026-10-01 19:38:59 +08:00
1 parent 658b266614
commit c93810ffb1
6 files changed
+158 -35

No files matched your search

+25
View File
@@ -21,6 +21,31 @@ class TestRandom:
g = np.random.default_rng(0)
assert get_rng(g) is g
def test_get_rng_accepts_numpy_integer(self):
"""np.int64 不是 int 的子类,必须当成整数处理,不能静默退化成全局流。"""
from mcm_toolkit.core import get_rng, set_seed
set_seed(1)
first = get_rng(np.int64(42))
second = get_rng(np.int64(42))
assert first is not second, "传 np.integer 应当新建独立生成器"
assert first.random() == np.random.default_rng(42).random()
def test_get_rng_rejects_bad_types(self):
"""类型不对就报错。静默当成"没传种子",换来的只会是不可复现的结果。"""
from mcm_toolkit.core import get_rng
for bad in ["42", 42.0, True, [42]]:
with pytest.raises(TypeError):
get_rng(bad)
def test_get_rng_without_seed_shares_and_advances(self):
from mcm_toolkit.core import get_rng, set_seed
set_seed(3)
assert get_rng() is get_rng(), "无参调用应返回同一个共享生成器"
assert get_rng().random() != get_rng().random(), "共享生成器必须被推进"
def test_get_rng_default_follows_global_seed(self):
"""set_seed 之后,不传 random_state 也必须复现——这是"论文能重跑"的底线。"""
from mcm_toolkit.core import get_rng, set_seed