多规格换图一对一映射要处理的不是商品效果,而是一类可以由程序明确判断的输入问题。CSV采用old、new两列,先把旧文件映射定义检查清楚,再报告输入集合中没有映射的项以及没有被使用的映射。重复旧键必须拒绝。
多规格换图一对一映射要处理的不是商品效果,而是一类可以由程序明确判断的输入问题。CSV采用old、new两列,先把旧文件映射定义检查清楚,再报告输入集合中没有映射的项以及没有被使用的映射。重复旧键必须拒绝。
输入契约与实现
CSV采用old、new两列,先把旧文件映射定义检查清楚,再报告输入集合中没有映射的项以及没有被使用的映射。重复旧键必须拒绝。

代码把一对一文件映射限定成小范围任务,刻意不增加网络请求、文件覆盖和发布动作。
运行结果与排错
完整输入返回两组pairs;部分输入报告c.png未匹配和b.png未使用;重复旧键抛出duplicate_old:a.png。
代码只生成映射报告,不移动文件、不改数据库、不执行平台换图。若业务允许多对一,需另外制定规则,不静默绕过当前一对一约束。如果要扩大范围,先添加对应失败夹具,再修改实现。
成功分支同样要验证结果含义。
放在图片制作链路的哪里
这个工具适合放在映射工具相关的本地资料整理环节,和图像制作保持解耦。
实际交接至少保留输入版本、代码版本和完整报告。
本例的覆盖范围是:完整输入返回两组pairs;部分输入报告c.png未匹配和b.png未使用;重复旧键抛出duplicate_old:a.png。未覆盖的边界是:代码只生成映射报告,不移动文件、不改数据库、不执行平台换图。若业务允许多对一,需另外制定规则,不静默绕过当前一对一约束。
import csv, io, json
def mapping(text, inputs):
reader = csv.DictReader(io.StringIO(text))
if not {'old', 'new'} <= set(reader.fieldnames or []):
raise ValueError('missing_columns')
result, targets = {}, set()
for row in reader:
old, new = row['old'].strip(), row['new'].strip()
if not old or not new:
raise ValueError('blank_path')
if old in result:
raise ValueError('duplicate_old:' + old)
if new in targets:
raise ValueError('duplicate_target:' + new)
result[old] = new
targets.add(new)
present = set(inputs)
return {'pairs': [[x, result[x]] for x in inputs if x in result],
'unmatched': sorted(present - result.keys()),
'unused': sorted(result.keys() - present)}
good = 'old,new\na.png,a-v2.png\nb.png,b-v2.png\n'
success = mapping(good, ['a.png', 'b.png'])
assert len(success['pairs']) == 2 and not success['unmatched']
partial = mapping(good, ['a.png', 'c.png'])
assert partial['unmatched'] == ['c.png'] and partial['unused'] == ['b.png']
try:
mapping('old,new\na.png,x.png\na.png,y.png\n', ['a.png'])
except ValueError as exc:
assert str(exc) == 'duplicate_old:a.png'
else:
raise AssertionError('expected rejection')
print(json.dumps({'success': success, 'partial': partial}))
编辑复核与下一组测试
这份映射报告应按定义是否有歧义、输入是否覆盖、规则是否闲置三个层次阅读。CSV的old与new先建立对应关系,duplicate_old:a.png意味着旧文件a.png被重复定义,此时即使两行指向同一个new,也不能用字典覆盖的方式跳过拒绝分支;应回到映射来源确认哪一行有效,避免一对多意图被压成表面上的单一结果。完整输入返回两组pairs时,接收者仍要逐对核对旧文件与新文件承担的规格角色,因为名称能匹配不代表商品颜色或角度对应正确。部分输入中c.png未匹配,说明输入集合包含这个旧文件却没有相应映射;b.png未使用,则说明映射表中存在该旧键,但本次输入没有用到它。这两项不是同一种缺失:前者需要补充映射或排除不应参与的输入,后者需要确认映射是否为其他批次预留、文件是否漏入本批,不能把未使用条目直接当成错误删除。交接时可把pairs作为待核对配对表,把未匹配项交给素材整理人员,把未使用项交给映射表维护者,以免一位处理者通过删掉两边条目获得一个空报告,却同时丢掉本来要换图的规格。下一组测试可先用空输入集合配合非空映射,确认闲置规则的表现,再用非空输入配合空映射,确认缺口能被完整呈现;另可让同一个old分别指向两个不同new,直接验证重复旧键的拒绝目标。标题中的一对一还应落实到业务解释:不同old指向同一个new属于多对一需求,是否接受需另外制定规则,不能仅凭没有duplicate_old提示就推断所有目标都唯一。对于文件名的大小写、目录前缀或空格差异,可补充对照输入以明确匹配口径,不能在修复报告时擅自改名并使另一批映射失效。这份工具适合放在新图清单已确认、换图动作尚未实施的交接点,产物是对应关系与差异诊断,不是文件移动结果或平台换图回执。若随后由其他流程执行替换,应以已经确认的pairs为依据并另记执行状态;不能把映射检查通过写成旧图已被替换,也不能根据未匹配报告自动删除原文件。