docs(data): 补齐 io 两个函数的 Parameters 与 Raises
按 docs/02-architecture.md §4.7,每个公开函数都要写全 Parameters 与 Raises, 格式对齐参考实现 core/random.py 的 get_rng。 - docstring 由 Codex 代写(本轮用户明确授权);函数体逻辑由用户本人改 - load_table:返回注解 Any -> pd.DataFrame,与 docstring 的承诺对齐; 写明 FileNotFoundError / ValueError / ImportError 各自在什么情况下抛 - save_table:写明 TypeError / ValueError / ImportError; 并把 isinstance(df, pd.DataFrame) 校验挪到 mkdir 之前 - 两套环境 pytest 均 39 passed / 44 skipped,ruff All checks passed
This commit is contained in:
1 parent
49fd84a2df
commit
19f4a15107
3 files changed
+55
-11
No files matched your search
@@ -31,6 +31,9 @@
|
|||||||
`na_values` 默认吃下空串 / `NA` / `N/A` / `#N/A` / `null` / `-`。
|
`na_values` 默认吃下空串 / `NA` / `N/A` / `#N/A` / `null` / `-`。
|
||||||
- `data.save_table`:实现(原属 L1,顺手落地)。按扩展名分派,父目录不存在时自动创建,
|
- `data.save_table`:实现(原属 L1,顺手落地)。按扩展名分派,父目录不存在时自动创建,
|
||||||
返回实际写入的 `Path`。
|
返回实际写入的 `Path`。
|
||||||
|
- `data.load_table` / `data.save_table`:docstring 补 `Parameters` / `Raises`
|
||||||
|
(`docs/02-architecture.md` §4.7 对每个公开函数的硬要求)。
|
||||||
|
- `data.load_table` 的返回注解 `Any` → `pd.DataFrame`,与 docstring 的承诺对齐。
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- `docs/02-architecture.md` §4.7「类型约定」:注解要写全、numpy 标量的判断写法、
|
- `docs/02-architecture.md` §4.7「类型约定」:注解要写全、numpy 标量的判断写法、
|
||||||
|
|||||||
@@ -86,6 +86,8 @@
|
|||||||
- `na_values` 默认吃下空串 / `NA` / `N/A` / `#N/A` / `null` / `-`
|
- `na_values` 默认吃下空串 / `NA` / `N/A` / `#N/A` / `null` / `-`
|
||||||
- 不支持的扩展名抛 `ValueError`;文件不存在抛带路径的 `FileNotFoundError`
|
- 不支持的扩展名抛 `ValueError`;文件不存在抛带路径的 `FileNotFoundError`
|
||||||
- 测试:`tests/test_data.py` 由 1 条(且被模块级 skip 掉)扩到 **8 条**
|
- 测试:`tests/test_data.py` 由 1 条(且被模块级 skip 掉)扩到 **8 条**
|
||||||
|
- docstring 的 `Parameters` / `Raises` 已按 §4.7 补齐(Codex 代写,用户授权)——
|
||||||
|
numpydoc 格式,对齐参考实现 `core/random.py` 的 `get_rng`
|
||||||
- [ ] 剩余 9 项(10 个函数):`clean_missing`
|
- [ ] 剩余 9 项(10 个函数):`clean_missing`
|
||||||
`detect_outliers` `normalize` `standardize` `describe` `correlation_matrix`
|
`detect_outliers` `normalize` `standardize` `describe` `correlation_matrix`
|
||||||
`bootstrap_ci` `monte_carlo` `save_figure`
|
`bootstrap_ci` `monte_carlo` `save_figure`
|
||||||
@@ -155,17 +157,14 @@
|
|||||||
| 24 | `get_rng(None)` **复用同一个模块级生成器**(会推进),不每次新建 | **用户本人提出**,取代 Codex 原来"每次新建 `default_rng(全局种子)`"的写法——那样两个都省略 `random_state` 的函数会抽到完全相同的数。共享单例既保证重跑一致,又让流自然推进 |
|
| 24 | `get_rng(None)` **复用同一个模块级生成器**(会推进),不每次新建 | **用户本人提出**,取代 Codex 原来"每次新建 `default_rng(全局种子)`"的写法——那样两个都省略 `random_state` 的函数会抽到完全相同的数。共享单例既保证重跑一致,又让流自然推进 |
|
||||||
| 25 | `src/` 下的实现默认由**用户本人**写,Codex 只改 `tests/` 与 `docs/` | 目标是"一边学一边自己写"。曾出现 Codex 直接落盘 `random.py`、与用户编辑器缓冲区冲突导致保存失败。需要代写时用户会明说 |
|
| 25 | `src/` 下的实现默认由**用户本人**写,Codex 只改 `tests/` 与 `docs/` | 目标是"一边学一边自己写"。曾出现 Codex 直接落盘 `random.py`、与用户编辑器缓冲区冲突导致保存失败。需要代写时用户会明说 |
|
||||||
| 26 | 未实现的算法用**逐条** `@pytest.mark.skip`,禁用模块级 `pytestmark` | 模块级 skip 会把同文件里**已经写好**的函数一起跳过。本次 `test_data.py` 就这样让 `load_table` 零覆盖,直到有人手动数才被发现 |
|
| 26 | 未实现的算法用**逐条** `@pytest.mark.skip`,禁用模块级 `pytestmark` | 模块级 skip 会把同文件里**已经写好**的函数一起跳过。本次 `test_data.py` 就这样让 `load_table` 零覆盖,直到有人手动数才被发现 |
|
||||||
|
| 28 | 不启用 ruff 的 preview 规则集 | `E302`(函数间要 2 个空行)在 ruff 0.16 里是 preview 规则,`select = ["E"]` 默认**不包含**它——所以少一个空行 ruff 照样报 "All checks passed"。行数空行得自己盯,别指望 lint |
|
||||||
| 27 | base 里的 zstandard 残骸目录**改名禁用**,不删除、不重装 | 删掉不可逆;`pip install zstandard` 会给 base 塞一个 conda 记录里根本没有的包,下次 `conda update --all` 又要重新判断。改名后 `import` 变回正常 `ModuleNotFoundError`,pandas 自动跳过 |
|
| 27 | base 里的 zstandard 残骸目录**改名禁用**,不删除、不重装 | 删掉不可逆;`pip install zstandard` 会给 base 塞一个 conda 记录里根本没有的包,下次 `conda update --all` 又要重新判断。改名后 `import` 变回正常 `ModuleNotFoundError`,pandas 自动跳过 |
|
||||||
|
|
||||||
## 下一步
|
## 下一步
|
||||||
|
|
||||||
1. **`data/io.py` 待你修两处**(`src/` 归你,Codex 不代写,见决策 25):
|
1. **`data/io.py` 还剩一处**:`isinstance(df, pd.DataFrame)` 已经挪到 `mkdir` 前面了,
|
||||||
- `save_table` 把 `path.parent.mkdir(parents=True, exist_ok=True)` 放在了**后缀校验之前**,
|
但**后缀校验还留在 `else` 分支里**,仍在 `mkdir` 之后。传 `sub/x.txt` 依旧会先建出
|
||||||
传个 `.txt` 会先建出一个空目录再抛 `ValueError`。
|
`sub/` 再抛 `ValueError`(实测确认)。把后缀判断也提到 `mkdir` 前面即可。
|
||||||
把校验(后缀 + `isinstance(df, pd.DataFrame)`)挪到 `mkdir` 前面即可。
|
|
||||||
- 两个函数都缺 `Raises` 段落(`docs/02-architecture.md` §4.7 要求写全);
|
|
||||||
`load_table` 的返回注解建议从 `Any` 改成 `pd.DataFrame` —— docstring 已经承诺返回 DataFrame,
|
|
||||||
注解写 `Any` 等于同一个契约写了两遍(`docs/dev/personal-pitfalls.md` 条目 3,本次已复发一次)。
|
|
||||||
2. 继续 L0,**下一个:`data/clean.py` 的 `clean_missing`**(L0 / A 档,直接能写)。
|
2. 继续 L0,**下一个:`data/clean.py` 的 `clean_missing`**(L0 / A 档,直接能写)。
|
||||||
同文件的 `detect_outliers` 是 **S 档**,要先按 `docs/dev/function-card-template.md`
|
同文件的 `detect_outliers` 是 **S 档**,要先按 `docs/dev/function-card-template.md`
|
||||||
把函数卡片写出来再动手。
|
把函数卡片写出来再动手。
|
||||||
|
|||||||
@@ -14,8 +14,7 @@ import pandas as pd
|
|||||||
|
|
||||||
__all__ = ["load_table", "save_table"]
|
__all__ = ["load_table", "save_table"]
|
||||||
|
|
||||||
|
def load_table(path: str | Path, **kwargs: Any) -> pd.DataFrame:
|
||||||
def load_table(path: str | Path, **kwargs: Any) -> Any:
|
|
||||||
"""按扩展名自动选择读取方式,返回 DataFrame。
|
"""按扩展名自动选择读取方式,返回 DataFrame。
|
||||||
|
|
||||||
约定:
|
约定:
|
||||||
@@ -24,6 +23,27 @@ def load_table(path: str | Path, **kwargs: Any) -> Any:
|
|||||||
* `.xlsx` / `.xls` 需要 `openpyxl`(`pip install "mcm-toolkit[excel]"`);
|
* `.xlsx` / `.xls` 需要 `openpyxl`(`pip install "mcm-toolkit[excel]"`);
|
||||||
* `na_values` 默认包含空串、`"NA"`、`"N/A"`、`"#N/A"`、`"null"`、`"-"`。
|
* `na_values` 默认包含空串、`"NA"`、`"N/A"`、`"#N/A"`、`"null"`、`"-"`。
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
path:
|
||||||
|
文件路径。扩展名决定用哪个读取器,大小写不敏感。
|
||||||
|
**kwargs:
|
||||||
|
原样转交给 `pandas.read_csv` / `pandas.read_excel`。
|
||||||
|
`.csv` 传了 `encoding=` 就照办,不再探测;不传则按上面的顺序逐个试。
|
||||||
|
|
||||||
|
Raises
|
||||||
|
------
|
||||||
|
FileNotFoundError
|
||||||
|
文件不存在。`.csv` 的自动探测分支会把原始路径包进中文提示里。
|
||||||
|
ValueError
|
||||||
|
后缀不在 `.csv` / `.xlsx` / `.xls` 里;
|
||||||
|
`.csv` 在候选编码下全部解码失败;
|
||||||
|
或 pandas 自身的解析错误(`pandas.errors.ParserError` 也是 `ValueError` 的子类,
|
||||||
|
报错信息原样抛出——它比转述的更有用)。
|
||||||
|
ImportError
|
||||||
|
`.xlsx` / `.xls` 但缺可选依赖(`openpyxl`,读旧 `.xls` 另需 `xlrd`),
|
||||||
|
见 docs/02-architecture.md §4.6:可选依赖的报错必须能直接看懂。
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
>>> df = load_table("data.csv") # doctest: +SKIP
|
>>> df = load_table("data.csv") # doctest: +SKIP
|
||||||
@@ -52,14 +72,36 @@ def load_table(path: str | Path, **kwargs: Any) -> Any:
|
|||||||
|
|
||||||
|
|
||||||
def save_table(df: pd.DataFrame, path: str | Path, index: bool = False, **kwargs: Any) -> Path:
|
def save_table(df: pd.DataFrame, path: str | Path, index: bool = False, **kwargs: Any) -> Path:
|
||||||
"""保存 DataFrame,返回实际写入的路径。"""
|
"""保存 DataFrame,返回实际写入的路径。
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
df:
|
||||||
|
要写出的表。必须是 `pandas.DataFrame`——`Series` 也不行,先 `.to_frame()`。
|
||||||
|
path:
|
||||||
|
目标路径。扩展名决定用哪个写入器,大小写不敏感;父目录不存在时自动创建。
|
||||||
|
index:
|
||||||
|
是否把行索引一并写进文件,默认 `False`。
|
||||||
|
**kwargs:
|
||||||
|
原样转交给 `pandas.DataFrame.to_csv` / `to_excel`。
|
||||||
|
|
||||||
|
Raises
|
||||||
|
------
|
||||||
|
TypeError
|
||||||
|
`df` 不是 `pandas.DataFrame`。
|
||||||
|
ValueError
|
||||||
|
后缀不在 `.csv` / `.xlsx` / `.xls` 里。
|
||||||
|
ImportError
|
||||||
|
写 `.xlsx` / `.xls` 但缺 `openpyxl`。
|
||||||
|
"""
|
||||||
path = Path(path)
|
path = Path(path)
|
||||||
path.parent.mkdir(parents=True,exist_ok=True)
|
|
||||||
suffix = path.suffix.lower()
|
suffix = path.suffix.lower()
|
||||||
|
|
||||||
if not isinstance(df,pd.DataFrame):
|
if not isinstance(df,pd.DataFrame):
|
||||||
raise TypeError(f"df 必须是一个pandas DataFrame,但是你上传了{type(df)}")
|
raise TypeError(f"df 必须是一个pandas DataFrame,但是你上传了{type(df)}")
|
||||||
|
|
||||||
|
path.parent.mkdir(parents=True,exist_ok=True)
|
||||||
|
|
||||||
if suffix == '.csv':
|
if suffix == '.csv':
|
||||||
df.to_csv(path,index=index,**kwargs)
|
df.to_csv(path,index=index,**kwargs)
|
||||||
elif suffix in ['.xlsx','.xls']:
|
elif suffix in ['.xlsx','.xls']:
|
||||||
|
|||||||
Reference in new issue
Block a user