CSV 导入任务说明:覆盖边界情况,不只考虑顺利路径

使用 AI 辅助编写与复核。

本文目录

向 Agent 说明 CSV 导入任务时,应分别定义可接受的文件格式与数据规则,再提供小文件及其确切的接受或拒绝结果。“读取这份 CSV”会把编码、重复项、空值和失败处理留给猜测。

下面的虚构目录导入器校验一批候选记录,不写入数据库。九份小样例的既有本地运行使用 Python 3.12.14;它们演示一份选定的契约,不代表支持所有 CSV 方言。

先定义字段字典与文件边界

这个导入器接受不含字节顺序标记的 UTF-8,文件最多 65,536 字节,包含 1 到 100 条数据记录。它使用逗号分隔、双引号包围字段,并在引号字段内用连续两个双引号表示一个双引号。表头必须精确为:

sku,title,quantity,note
字段 可接受值 转换或失败
sku 1 到 20 个 ASCII 大写字母、数字或连字符 原样保留;拒绝批次内重复项
title 1 到 80 个 Python 字符串字符 原样保留,不去除首尾空白
quantity 1 到 99 的规范十进制整数 转为整数;拒绝 01、-1 和 1.0
note 0 到 200 个 Python 字符串字符 空值转为 None,其他情况原样保留

这些都是应用选择。尤其是,拒绝 UTF-8 BOM 是本例的策略,不是 CSV 的通用属性。真实导入器可以有意使用合适的解码器接受它。应先决定行为,而不是等用户失败后才发现。

在这个解析器下,带引号与不带引号的空字段都会变成同一个空字符串,因此这份契约不能用它们区分 null 与有意留空的备注。如果应用需要这项区分,应选择明确的表示方式。

Python 3.12 CSV 文档介绍了可配置方言、换行处理和解析选项,但不会定义你的 SKU 或重复项策略。这里使用带明确方言和严格模式的 csv.reader 解析,再由独立校验器检查字段数量与取值。

给 Agent 一份包含复杂语法的有效文件

下面是编写出来的目录示例数据:

sku,title,quantity,note
KIT-01,"Desk, small",2,"Said ""hello"""
KIT-02,Lamp,1,"Line one
Line two"

它有两条数据记录,尽管第二条备注跨了两个物理行。既有本地练习得到以下候选记录:

[
  {"sku":"KIT-01","title":"Desk, small","quantity":2,"note":"Said \"hello\""},
  {"sku":"KIT-02","title":"Lamp","quantity":1,"note":"Line one\nLine two"}
]

不要先把输入拆成行,再按逗号拆每一行。这样会同时破坏引号内逗号与内嵌换行。样例文件保留实际字节,包括记录间的 CRLF 分隔,以及第二条备注内的 LF。

为失败附上确切原因

以下结果来自既有本地教学校验器。每份被拒绝的文件都没有返回候选记录。

样例 有意设置的情况 已有实际结果
01-quoted-fields.csv 逗号、转义引号与内嵌换行 接受,两条记录
02-empty-note.csv 最后字段为空 接受,备注变为 None
03-duplicate.csv DUP-01 出现两次 逻辑记录 3 出现 DUPLICATE_SKU
04-bad-quantity.csv 数量为 -1 INVALID_QUANTITY
05-extra-column.csv 五个字段,而不是四个 COLUMN_COUNT
06-unclosed-quote.csv 引号字段没有闭合 MALFORMED_CSV
07-invalid-utf8.csv 包含字节 0xff INVALID_UTF8
08-bom.csv 以 UTF-8 BOM 字节开头 UNSUPPORTED_BOM
09-wrong-header.csv 表头以 title,sku 开始 INVALID_HEADER

记录编号把表头计为记录 1,统计的是逻辑 CSV 记录,不是物理行。解析器层面的失败可能没有可靠的记录号;本例返回 null,不作猜测。

重复项样例的完整结果为:

{
  "accepted": false,
  "records": [],
  "errors": [{"record": 3, "code": "DUPLICATE_SKU"}]
}

这是一次校验拒绝,不能把它描述成“已导入两行”或数据库事务回滚,因为没有连接数据库。

选择整批拒绝还是部分接受

决策 本例选用的整批拒绝 另一种选择:部分接受
一条记录无效 拒绝整个批次 接受有效记录,并报告拒绝项
用户修正 修复文件后重新提交 决定如何只重交失败项而不产生重复
结果计数 失败时接受的候选记录数为零 分别统计接受、拒绝和跳过数量
持久化 先校验,另外定义事务行为 定义逐记录写入失败与重试语义
重复项策略 拒绝本文件内重复项 仍然需要明确的重复与冲突策略

部分接受可能有用,但悄悄丢弃格式错误的行不是完整策略。它需要可审阅的错误结果与重试方案。本练习采用整批校验更简单,因为用户可以修正一份文件后重试。

既有数据库记录冲突不在这个校验器范围内。加入持久化前,应明确已知 SKU 是错误、更新还是另一项操作,以及如何处理并发改动。通过这些样例不能证明具备上述行为。

复制导入任务说明

为附带的虚构目录 CSV 实现候选记录校验器。
使用 Python 3.12 csv.reader,明确保留选定方言。

文件契约:
- 严格 UTF-8,不带 BOM,最多 65,536 字节。
- 逗号分隔,双引号包围,用连续双引号转义。
- 打开文本文件或构造 StringIO 时,使用 newline=""。
- 表头精确为 sku,title,quantity,note;1 到 100 条数据记录。
- 额外空记录无效,不要悄悄跳过。

数据契约:
- sku 匹配 [A-Z0-9-]{1,20},保持不变且在本文件内唯一。
- title 为 1-80 个 Python 字符串字符,保持不变。
- quantity 匹配 [1-9][0-9]?,并转为整数。
- note 最多 200 个字符;空值映射为 None。
- 不去除首尾空白、不转换大小写、不推断分隔符,也不强制转换其他值。

失败契约:
- 任何失败都拒绝批次,并返回 records: []。
- 返回稳定错误码,以及可确定时的逻辑记录号。
- 表头是逻辑记录 1;解析或编码错误可以使用 null。
- 格式错误与字段校验错误分开。

交付:
- 校验器、九份样例及其确切预期结果。
- 实际运行了哪些检查、所用运行时版本的记录。
- 提出现有记录冲突问题,不编造处理行为。

范围仅限候选记录校验。不要增加数据库写入、upsert、
上传、后台任务或电子表格导出行为。

可以从这组样例开始,再加入与你自己契约相关的示例。如果准备依赖文件大小边界或非 ASCII 标题,就应为其另设检查。九份已执行样例只为所列情况提供证据,不代表完整覆盖导入器。