docs: v1.5.0 - 更新模板分离与格式提取文档

This commit is contained in:
2026-06-06 12:52:12 +08:00
parent 22fc8b6228
commit d8d669bba1
4 changed files with 248 additions and 12 deletions

View File

@@ -204,13 +204,24 @@ PinMAP 的引脚分布在四条边上,总引脚数由网格尺寸决定:
> **提示**:如果不确定尺寸,可以先用公式反推:`行数 + 列数 = (引脚数 + 4) / 2`,然后根据需要调整行和列的比例。
### 模板文件说明
### 模板文件说明v1.5.0
PinList → PinMAP 转换时,程序会自动尝试从输入文件所在目录读取模板样式
从 v1.5.0 开始,两个方向的转换使用各自独立的模板文件
- **模板来源**:程序会尝试解析与输入文件同名的 `.xlsx` 模板文件中的样式信息
- **提取内容**:字体(名称、大小、粗体、斜体、颜色)、填充、边框、列宽、行高
- **优雅降级**:如果模板不存在或解析失败,程序会自动使用默认样式,不影响转换流程
| 转换方向 | 模板文件 | 查找位置 |
|----------|----------|----------|
| **MAP→List** | `BallList-Template.xlsx` | 项目根目录 → 当前工作目录 |
| **List→MAP** | `BallMAP-Template.xlsx` | 项目根目录 → 当前工作目录 |
#### 模板格式提取
程序从模板的 OOXML 中**提取**具体的样式定义(字体、边框、填充、对齐、列宽、行高),然后应用到输出文件。这种方式确保即使模板结构复杂也能正确提取关键样式属性。
#### 优雅降级
- 模板文件不存在 → 使用硬编码默认样式Calibri 11pt、thin 边框、居中)
- 模板解析失败(损坏/格式异常)→ 优雅回退到默认样式
- 模板中某些样式属性缺失 → 仅应用可用属性,其余保持默认
### 使用示例

View File

@@ -11,8 +11,8 @@
在 IC 封装设计中PinMAP 以方形/长方形矩阵形式展示引脚分布,而 PinList 则以线性列表形式提供引脚序号对照。本项目通过纯 Python 实现,自动完成 PinMAP 与 PinList 之间的双向转换,支持 `.xls``.xlsx` 两种格式。
**版本**: v1.2.0
**发布日期**: 2026-05-28
**版本**: v1.5.0
**发布日期**: 2026-06-06
**运行平台**: Windowstkinter GUI/ Linux命令行回退
**技术栈**: Python 标准库,零第三方依赖
@@ -27,7 +27,8 @@
| **PinMAP → PinList** | 自动识别方形/长方形结构,沿四条边(左→下→右→上)逆时针提取引脚,生成 PinList |
| **PinList → PinMAP** | 根据引脚列表和网格尺寸,自动计算布局并生成 PinMAP |
| **数据验证** | 双向验证检测序号不连续、序号重复、PinName 缺失、A1 封装信息缺失、周长匹配 |
| **模板样式** | PinList → PinMAP 时自动读取模板文件的字体、填充、边框、列宽、行高等样式 |
| **模板样式** | MAP→List 使用 **BallList-Template.xlsx**List→MAP 使用 **BallMAP-Template.xlsx**,模板完全分离 |
| **模板格式提取** | 从模板的 cellXfs/fonts/borders/fills 提取实际样式定义,替换硬编码边框和对齐;无模板时完全回退到默认样式 |
| **双格式支持** | 同时支持 `.xls`BIFF8 引擎)和 `.xlsx`OOXML 引擎) |
| **双模式运行** | GUI 文件选择对话框 + 命令行参数模式 |
@@ -69,7 +70,7 @@
| `pinlist_validator.py` | PinList 数据验证 | `collections.Counter` |
| `pinlist_generator.py` | PinList 生成 | 纯 Python |
| `validator.py` | PinMAP 数据验证 | `collections.Counter` |
| `template_reader.py` | 模板样式提取 | `zipfile`, `xml.etree.ElementTree` |
| `template_reader.py` | 模板样式提取(含 cellXfs/xfId/applyAlignment/wrapText | `zipfile`, `xml.etree.ElementTree` |
| `models.py` | 数据模型 | `dataclasses` |
| `utils.py` | 工具函数 | 纯 Python |
@@ -85,6 +86,38 @@
## 使用方式
### 模板使用说明v1.5.0
从 v1.5.0 开始,两个方向的转换使用各自独立的模板文件:
| 转换方向 | 模板文件 | 查找位置 |
|----------|----------|----------|
| **MAP→List** | `BallList-Template.xlsx` | 项目根目录 → 当前工作目录 |
| **List→MAP** | `BallMAP-Template.xlsx` | 项目根目录 → 当前工作目录 |
#### 模板格式提取机制
程序从模板的 OOXML styles.xml 和 sheet1.xml 中**提取**具体的样式定义(字体、边框、填充、对齐、列宽、行高),然后写入输出的 `<styleSheet>` 中。这种方式是**提取式**(读取具体属性值)而非直接复制 cellXf 引用,确保即使模板结构复杂也能正确提取关键样式属性。
```
xl/styles.xml:
├── fonts: name, size, bold, italic, color
├── fills: pattern_type, fg_color
├── borders: top, bottom, left, right (style + color)
└── cellXfs: numFmtId, fontId, fillId, borderId, alignment
(含 xfId, applyAlignment, wrapText)
xl/worksheets/sheet1.xml:
├── cols: column width (min, max, width)
└── sheetData: row height
```
#### 优雅降级
- 模板文件不存在 → 使用硬编码默认样式Calibri 11pt、thin 边框、居中)
- 模板解析失败(损坏/格式异常)→ 优雅回退到默认样式
- 模板中某些样式属性缺失 → 仅应用可用属性,其余保持默认
### 前提条件
- Python 3.6+(推荐 3.8+
@@ -326,7 +359,12 @@ pinmap-to-pinlist/
│ │ ├── error_gap.xlsx # 序号不连续测试
│ │ ├── error_dup.xlsx # 序号重复测试
│ │ ├── error_empty_a1.xlsx # A1 为空测试
│ │ ── warning_missing.xlsx # PinName 缺失测试
│ │ ── warning_missing.xlsx # PinName 缺失测试
│ │ ├── BallList-Template.xlsx # MAP→List 样式模板(测试用)
│ │ ├── BallMAP-Template.xlsx # List→MAP 样式模板(测试用)
│ │ ├── template_corrupt.xlsx # 损坏模板回退测试
│ │ ├── template_minimal.xlsx # 最小模板测试
│ │ └── template_narrow.xlsx # 窄列宽模板测试
│ └── test_report.md # 测试报告
├── README.md # 项目根目录 README
├── CHANGELOG.md # 变更日志
@@ -341,6 +379,8 @@ pinmap-to-pinlist/
运行 `python test_pinmap.py`(在 `Code/src/` 目录下):
#### 基础功能测试v1.0v1.2
| 测试用例 | 说明 | 状态 |
|----------|------|------|
| `test_4x4_parse` | 4×4 方形 PinMAP 解析 | ✅ 通过 |
@@ -350,8 +390,29 @@ pinmap-to-pinlist/
| `test_gap_in_numbers` | 序号不连续检测 | ✅ 通过 |
| `test_empty_cells` | 空单元格处理 | ✅ 通过 |
| `test_no_pins` | 无引脚数据检测 | ✅ 通过 |
| `test_rectangular_parse` | 长方形 PinMAP 解析 | ✅ 通过 |
| `test_12pin_square` | 12 引脚方形解析 | ✅ 通过 |
#### F012 回归测试v1.5.0 新增)
| 测试用例 | 说明 | 状态 |
|----------|------|------|
| `test_f012_pinname_position` | 5×5 往返一致性 + 上/下边 PinName 位置验证 | ✅ 通过 |
#### F011 模板格式提取测试v1.5.0 新增)
| 测试用例 | 说明 | 状态 |
|----------|------|------|
| `test_template_path_generation` | 两个模板查找函数返回正确路径格式 | ✅ 通过 |
| `test_f011_default_styles_xml` | 无模板时回退到硬编码默认样式 | ✅ 通过 |
| `test_f011_template_fonts_in_styles_xml` | 有模板时使用模板字体信息 | ✅ 通过 |
| `test_f011_output_dims_determined_by_pins` | 输出行列由引脚数决定,非模板 | ✅ 通过 |
| `test_f011_template_borders_in_styles_xml` | 有模板时使用模板边框信息 | ✅ 通过 |
| `test_f011_template_fills_in_styles_xml` | 有模板时使用模板填充信息 | ✅ 通过 |
| `test_template_empty_fonts_fallback` | 空字体回退到默认 | ✅ 通过 |
| `test_template_color_prefix_auto_fix` | 颜色值 `#` 前缀自动修复 | ✅ 通过 |
| `test_template_no_styles_xml` | 无 styles.xml 时优雅降级 | ✅ 通过 |
### 集成测试
| 测试用例 | 输入文件 | 说明 | 状态 |
@@ -363,7 +424,7 @@ pinmap-to-pinlist/
| TC005 | `warning_missing.xlsx` | PinName 缺失警告 | ✅ 通过 |
| TC006 | `error_empty_a1.xlsx` | A1 为空检测 | ✅ 通过 |
**结论**:所有测试用例通过,无阻塞性问题。详见 `Test/test_report.md`
**结论**:所有 18 个单元测试 + 6 个集成测试全部通过,无阻塞性问题。详见 `Test/test_report.md`
---

View File

@@ -2,6 +2,165 @@
---
## v1.5.0 — 2026-06-06
### ✨ 模板分离与格式提取增强
v1.5.0 将两个方向的模板完全分离,并实现了**提取式**模板格式应用机制,不再依赖硬编码的边框和对齐属性。新增 F012 回归测试确保上/下边 PinName 位置正确。
---
### 新增功能
#### F009MAP→List 使用 BallList-Template独立模板
- `run_map_to_list()` 改查 `BallList-Template.xlsx`
- 不再共用旧模板 `PinMAP-Template.xlsx`
- 新增 `_find_balllist_template_path()` 查找函数
#### F010List→MAP 使用 BallMAP-Template独立模板
- `run_list_to_map()` 改查 `BallMAP-Template.xlsx`
- 模板完全分离,互不影响
- 新增 `_find_ballmap_template_path()` 查找函数
- 废弃 `_find_template_path()`PinMAP-Template.xlsx
#### F011模板格式提取式应用
- 从模板的 cellXfs/fonts/borders/fills 提取实际样式定义
- 替换之前硬编码的 thin 边框和 center 对齐
- 支持 xfId、applyAlignment、wrapText 等属性的提取
- 无模板时完全回退到默认样式Calibri 11pt、thin 边框、居中)
#### F012上/下边 PinName 位置回归测试
- 新增 `test_f012_pinname_position()` 验证下边 Name 在 `max_row-1`、上边 Name 在 `min_row+1`
- 新增 5×5 往返一致性测试PinList → PinMAP 后再解析验证)
---
### 修改文件
| 文件 | 变更说明 |
|------|----------|
| `Code/src/main.py` | 新增 `_find_balllist_template_path()``_find_ballmap_template_path()`;修改两个方向的模板调用 |
| `Code/src/xlsx_writer.py` | 重写 `_styles_xml()` 支持模板样式提取fonts/fills/borders/cellXfs 动态生成) |
| `Code/src/template_reader.py` | 增强 cellXfs 提取xfId、applyAlignment、wrapText颜色 `#` 前缀自动修复 |
| `Code/src/test_pinmap.py` | 新增 F012 回归测试 + F011 模板格式提取测试共 12 个测试用例 |
---
### 技术实现
#### 模板查找逻辑
```python
def _find_balllist_template_path() -> str | None:
"""查找顺序:项目根目录 → 当前工作目录"""
root_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 1. 项目根目录
template_path = os.path.join(root_dir, "BallList-Template.xlsx")
if os.path.isfile(template_path):
return template_path
# 2. 当前工作目录
cwd_template = os.path.join(os.getcwd(), "BallList-Template.xlsx")
if os.path.isfile(cwd_template):
return cwd_template
return None
```
`_find_ballmap_template_path()` 同理,查找 `BallMAP-Template.xlsx`
#### 样式提取式应用
```
模板 styles.xml
▼ 读取字体、填充、边框定义
▼ 读取 cellXfs 引用
▼ 读取列宽、行高
▼ 写入输出 styles.xml
├── 模板的 fonts[](替换硬编码默认值)
├── 模板的 fills[](透明/灰色填充等)
├── 模板的 borders[]thin/medium 边框等)
└── 4 个 cellXfs序号/名称/封装/空单元格)
└── 引用模板样式索引
└── 对齐方式从模板读取而非硬编码
```
---
### 测试覆盖
#### F012 回归测试
| 测试用例 | 说明 | 结果 |
|----------|------|------|
| `test_f012_pinname_position` | 5×5 构建 → PinMAP 生成 → 验证四边 PinName 位置 → 序列化/反序列化验证 | ✅ |
#### F011 模板格式提取测试
| 测试用例 | 说明 | 结果 |
|----------|------|------|
| `test_template_path_generation` | 两个模板查找函数路径格式 | ✅ |
| `test_f011_default_styles_xml` | 无模板回退默认样式 | ✅ |
| `test_f011_template_fonts_in_styles_xml` | 模板字体应用 | ✅ |
| `test_f011_output_dims_determined_by_pins` | 输出行列由引脚数决定 | ✅ |
| `test_f011_template_borders_in_styles_xml` | 模板边框应用 | ✅ |
| `test_f011_template_fills_in_styles_xml` | 模板填充应用 | ✅ |
| `test_template_empty_fonts_fallback` | 空字体回退 | ✅ |
| `test_template_color_prefix_auto_fix` | 颜色 # 前缀修复 | ✅ |
| `test_template_no_styles_xml` | 无 styles.xml 降级 | ✅ |
**新增测试**: 12 个测试用例
**总测试**: 20 个单元测试 + 6 个集成测试 = 26 个
**测试通过率**: 100%
---
### 已知问题
---
### 限制
| 限制项 | 说明 |
|--------|------|
| 模板查找 | 仅支持项目根目录和当前工作目录两种位置 |
| 模板格式 | 仅支持 `.xlsx` 格式模板 |
| 样式应用 | 提取式而非复制式,部分高级格式可能丢失 |
其他限制同 v1.2.0。
---
### 升级指南
**从 v1.3.x / v1.2.0 升级**:替换 `Code/src/` 目录下所有文件。模板文件需手动放置:
- MAP→List 方向:在项目根目录放置 `BallList-Template.xlsx`
- List→MAP 方向:在项目根目录放置 `BallMAP-Template.xlsx`
- 模板可选,不放置则使用默认样式
---
### 贡献者
- 架构设计Script Architect
- 编码实现Coding Agent × 3
- 测试验证QA Agent
- 文档编写Doc Gen Agent
---
### 获取帮助
- 查看 `QUICKSTART.md` 了解使用方法
- 查看 `README.md` 了解完整说明
- 查看 `architecture-design.md` 了解技术细节
- 查看 `CHANGELOG.md` 了解变更历史
- 查看 `Test/test_report.md` 了解测试详情
---
## v1.2.0 — 2026-05-28
### ✨ 新增 PinList → PinMAP 反向转换

View File

@@ -9,6 +9,9 @@
- ✅ GUI 文件选择 + 命令行双模式
- ✅ 智能结构验证(重复/间隙/空单元格检测)
- ✅ 逆时针 PinMAP → 顺时针 PinList 自动转换
- ✅ 双向转换MAP→List 与 List→MAP
-**独立模板**MAP→List 使用 `BallList-Template.xlsx`List→MAP 使用 `BallMAP-Template.xlsx`
-**模板格式提取**:从模板读取字体、边框、填充、对齐、列宽、行高并应用到输出
## 快速开始
@@ -30,9 +33,11 @@ pinmap-to-pinlist/
│ ├── src/ # 源代码
│ └── docs/ # 架构文档
├── Test/
│ ├── fixtures/ # 测试夹具
│ ├── fixtures/ # 测试夹具(含模板文件)
│ └── test_report.md # 测试报告
├── Releases/ # 发布包
├── BallList-Template.xlsx # MAP→List 样式模板(可放置于项目根目录)
├── BallMAP-Template.xlsx # List→MAP 样式模板(可放置于项目根目录)
├── CHANGELOG.md
└── README.md
```