fix(data): 校验早于副作用,补空行;经验写入 pitfalls
save_table 的两处收尾(用户授权代改): - 后缀校验原先藏在 if/else 分支的 else 里,排在 path.parent.mkdir(...) 之后, 传 sub/x.txt 会先把 sub\ 建出来再抛 ValueError。改成守卫子句,集中在 mkdir 之前, 校验段结束后才产生副作用;此时 else 分支自然消失,用回 if/else 两路分派 - __all__ 与下一个 def 之间补回第二个空行(PEP 8 / E302) 测试: - 新增 test_save_table_validates_before_touching_disk, 断言参数非法时 tmp_path 下一个条目都不留(ValueError 与 TypeError 两条路径) - 40 passed / 44 skipped,两套环境一致;ruff All checks passed 文档: - docs/dev/personal-pitfalls.md 追加条目 5(参数校验排在副作用之后) 与条目 6(把 lint 的"没报错"当成"没问题"),索引表同步加行 - STATUS:io.py 收尾,L0 第 3 项完成;测试计数 40 - CHANGELOG:Fixed 段补两条
This commit is contained in:
1 parent
19f4a15107
commit
6758e81c9d
5 files changed
+61
-9
No files matched your search
@@ -26,6 +26,8 @@
|
||||
| 2 | 以为 `# TODO(L0)` 只是普通注释 | 2026-10-01 |
|
||||
| 3 | 签名里的类型注解和 docstring 说的不一致 | 2026-10-01 |
|
||||
| 4 | 只覆盖自己的状态,忘了第三方库还在用 numpy 旧全局 | 2026-10-01 |
|
||||
| 5 | 参数校验排在副作用(建目录 / 写文件)之后 | 2026-10-01 |
|
||||
| 6 | 把 lint 的"没报错"当成"没问题" | 2026-10-01 |
|
||||
|
||||
---
|
||||
|
||||
@@ -66,3 +68,33 @@
|
||||
- 以后怎么防:凡是"设全局状态"的函数,先列清单——自己的、numpy 旧的、标准库 `random` 的、
|
||||
第三方框架的,逐个决定要不要一起设,并在 docstring 里写清到底覆盖了哪几个。
|
||||
- 首次:2026-10-01|复发:0
|
||||
|
||||
|
||||
### 5. 参数校验排在副作用(建目录 / 写文件)之后
|
||||
|
||||
- 现象:`save_table` 先 `path.parent.mkdir(parents=True, exist_ok=True)`,再在
|
||||
`if suffix == '.csv' ... else: raise ValueError` 里判断后缀。传 `sub/x.txt` 时,
|
||||
空目录 `sub\` 已经建出来了,函数才抛 `ValueError`——错误路径上留下垃圾。
|
||||
- 为什么会错:函数体是照着"顺利流程"顺着写下来的——先建目录、再按分支干活;
|
||||
校验顺手塞进分支的 `else` 里,于是校验自动排到了最后。分支越多,越会有路径漏掉。
|
||||
会传染:`isinstance` 校验改到 `mkdir` 前面之后,后缀校验**还是**留在原地,
|
||||
因为它藏在分支里,看起来"已经检查过了"。
|
||||
- 以后怎么防:函数体分三段写——**① 所有校验 → ② 所有副作用(建目录 / 写文件 /
|
||||
联网 / 改全局状态)→ ③ 主逻辑**。校验用守卫子句集中在开头,不要塞进分支里;
|
||||
凡是 `raise` 的行,位置必须在校验段内,不能出现在副作用段之后。
|
||||
写完自问一句:"这个参数不合法时,磁盘 / 网络 / 全局状态会不会已经动过了?"
|
||||
- 首次:2026-10-01|复发:0
|
||||
|
||||
### 6. 把 lint 的"没报错"当成"没问题"
|
||||
|
||||
- 现象:`__all__` 与下一个 `def` 之间只留了 1 个空行(PEP 8 要求 2 个),
|
||||
`ruff check src tests` 照样打印 "All checks passed!"。
|
||||
- 为什么会错:版本号看着一样,覆盖的规则却是两回事。ruff 0.16 里 `E302`
|
||||
(函数间空行)属于 **preview 规则**,不在 `select = ["E"]` 的默认集合里——
|
||||
加了也会被"because preview is not enabled"忽略掉,安安静静不报。
|
||||
根本问题是:**lint 只检查你 select 的那部分**,而默认规则集本来就不是 PEP 8 全集。
|
||||
把"我配的检查全过了"读成"这份代码符合规范",是把自己没开的检查当成了已经通过的检查。
|
||||
- 以后怎么防:把 lint 结论限定成"我 select 的规则里没问题",别说成"没问题"。
|
||||
想看全貌就偶尔跑一次 `ruff check --select ALL --preview`(只当参考,别直接开进 CI,
|
||||
会淹没在噪声里);纯格式问题交给 `ruff format`,它是 formatter,不受 `select` 影响。
|
||||
- 首次:2026-10-01|复发:0
|
||||
Reference in new issue
Block a user