Skip to content

Latest commit

 

History

History
377 lines (267 loc) · 12.8 KB

File metadata and controls

377 lines (267 loc) · 12.8 KB

ExcelAlchemy

English README · 项目说明 · 快速开始 · 接入路线图 · 结果对象 · 架构文档 · Locale Policy · Changelog · 迁移说明

ExcelAlchemy 是一个面向 Excel 导入导出的 schema-first Python 库。 它的核心思路不是“读写表格文件”,而是“把 Excel 当成一种带约束的业务契约”。

当前稳定发布版本是 2.2.8,它在稳定的 ExcelAlchemy 2.x 线上继续加强了接入路线图、失败导入 API 载荷的 smoke 校验,以及对 FastAPI 参考应用的安装后真实可用验证。

你用 Pydantic 模型定义结构,用 FieldMeta 定义 Excel 元数据,用显式的导入/导出流程去完成模板生成、数据校验、错误回写和后端集成。

截图

这些截图由仓库内的 scripts/generate_portfolio_assets.py 生成。

模板 导入结果
Excel 模板截图 Excel 导入结果截图

这个项目适合什么

  • 需要给业务方发 Excel 模板并回收数据
  • 需要把 Excel 输入和后端模型保持一致
  • 需要在失败结果中明确指出哪一格有问题
  • 想要一个可以接自定义存储的 Excel 工作流库

这个项目不打算做什么

  • 不做通用表格分析库
  • 不做 pandas 风格的数据处理框架
  • 不做桌面表格编辑器
  • 不追求“魔法式自动推断一切”

核心特点

  • 基于 Pydantic v2 的 schema 驱动设计
  • 支持 locale='zh-CN' | 'en' 的 Excel 展示文案
  • 支持可插拔存储后端 ExcelStorage
  • 运行时不依赖 pandas
  • 支持 Python 3.12-3.14,主支持版本是 3.14
  • 使用 uv 管理开发与 CI

项目定位

这个仓库不只是“一个能用的库”,也是一个展示工程思考的作品:

  • 为什么要从 Pydantic v1 迁到 v2
  • 为什么要去掉 pandas
  • 为什么要做 storage abstraction
  • 为什么 facade 外面要简洁,里面要分层
  • 为什么国际化先从消息层和 workbook display text 开始

详细设计思路见 ABOUT.md

架构概览

flowchart TD
    A[ExcelAlchemy 门面]
    A --> B[ExcelSchemaLayout]
    A --> C[ExcelHeaderParser / Validator]
    A --> D[RowAggregator]
    A --> E[ImportExecutor]
    A --> F[ExcelRenderer / writer.py]
    A --> G[ExcelStorage 协议]

    G --> H[MinioStorageGateway]
    G --> I[自定义存储实现]

    B --> J[FieldMeta / FieldMetaInfo]
    E --> K[Pydantic Adapter]
    F --> L[i18n Display Messages]
    E --> M[Runtime Error Messages]
Loading

完整分层说明见 docs/architecture.md

工作流概览

flowchart LR
    A[Pydantic 模型 + FieldMeta] --> B[ExcelAlchemy 门面]
    B --> C[模板渲染]
    B --> D[Worksheet 解析]
    D --> E[表头校验]
    D --> F[行聚合]
    F --> G[导入执行器]
    G --> H[导入结果工作簿]
    C --> I[给用户的工作簿]
    H --> I
Loading

安装

pip install ExcelAlchemy

如果你要使用内置的 Minio 后端:

pip install "ExcelAlchemy[minio]"

示例

仓库里有一组更贴近实际接入的示例:

如果你想按推荐顺序来阅读,建议先看 examples/README.md

如果你想看一页汇总好的展示页,里面同时包含截图、代表性工作流和固定输出, 可以直接看 docs/examples-showcase.md

这些固定输出素材由 scripts/generate_example_output_assets.py 生成。

示例输出

导入工作流输出:

Employee import workflow completed
Result: SUCCESS
Success rows: 1
Failed rows: 0
Result workbook URL: None
Created rows: 1
Uploaded artifacts: []

导出工作流输出:

Export workflow completed
Artifact filename: employees-export.xlsx
Artifact bytes: 6893
Upload URL: memory://employees-export-upload.xlsx
Uploaded objects: ['employees-export-upload.xlsx']

完整输出:

快速开始

from pydantic import BaseModel

from excelalchemy import ExcelAlchemy, FieldMeta, ImporterConfig, Number, String


class Importer(BaseModel):
    age: Number = FieldMeta(label='年龄', order=1)
    name: String = FieldMeta(label='姓名', order=2)


alchemy = ExcelAlchemy(ImporterConfig(Importer))
template = alchemy.download_template_artifact(filename='people-template.xlsx')

excel_bytes = template.as_bytes()
template_data_url = template.as_data_url()  # 兼容旧的浏览器集成方式

浏览器下载时,优先使用 excel_bytes 构造 Blob,或者让后端直接返回二进制并带上 Content-Disposition: attachment。现代浏览器对超长 data: URL 的顶层导航并不稳定。

选择模板 / 结果语言

locale 会影响 Excel 里真正给用户看的文案,例如:

  • 第一行填写须知
  • 表头批注
  • 结果列标题
  • “校验通过 / 校验不通过” 文本

默认是 zh-CN,如果你想生成英文模板或英文结果工作簿,可以传 locale='en'

更完整的公共策略见 docs/locale.md

  • 运行时异常默认并稳定使用英文
  • workbook 展示文案当前支持 zh-CNen
  • 2.x 版本线默认 workbook locale 仍是 zh-CN
from excelalchemy import ExcelAlchemy, FieldMeta, ImporterConfig, Number, String
from pydantic import BaseModel


class Importer(BaseModel):
    age: Number = FieldMeta(label='Age', order=1)
    name: String = FieldMeta(label='Name', order=2)


template_zh = ExcelAlchemy(ImporterConfig(Importer, locale='zh-CN')).download_template_artifact()
template_en = ExcelAlchemy(ImporterConfig(Importer, locale='en')).download_template_artifact()

导入结果工作簿也会使用同一个 locale

alchemy = ExcelAlchemy(
    ImporterConfig(
        Importer,
        creator=create_func,
        storage=storage,
        locale='en',
    )
)
result = await alchemy.import_data("people.xlsx", "people-result.xlsx")

存储扩展点

ExcelAlchemy 接受任何实现了 ExcelStorage 协议的存储后端。

from excelalchemy import ExcelAlchemy, ExcelStorage, ExporterConfig, UrlStr
from excelalchemy.core.table import WorksheetTable


class InMemoryExcelStorage(ExcelStorage):
    def read_excel_table(self, input_excel_name: str, *, skiprows: int, sheet_name: str) -> WorksheetTable:
        ...

    def upload_excel(self, output_name: str, content_with_prefix: str) -> UrlStr:
        ...


alchemy = ExcelAlchemy(ExporterConfig(Importer, storage=InMemoryExcelStorage()))

如果你希望使用内置 Minio 实现,推荐显式传入 storage=MinioStorageGateway(...),而不是再把 Minio 配置散落到门面层。

导入结果状态查看命名

如果你需要从 facade 上查看一次导入后的中间状态,推荐使用 2.2 这套更清晰的命名:

  • alchemy.worksheet_table
  • alchemy.header_table
  • alchemy.cell_error_map
  • alchemy.row_error_map

旧别名:

  • alchemy.df
  • alchemy.header_df
  • alchemy.cell_errors
  • alchemy.row_errors

在 2.x 里仍然可用,用于兼容旧代码;但新代码建议统一使用前面这组更明确的名字。

结构化错误读取

现在导入失败不仅能回写到 workbook,也更适合被后端服务和前端界面读取。

  • alchemy.cell_error_map
  • alchemy.row_error_map

这两个对象在 2.x 中仍然保持 dict 兼容,但同时提供了更适合业务代码使用的辅助方法:

  • at(...)
  • messages_at(...)
  • messages_for_row(...)
  • numbered_messages_for_row(...)
  • flatten()
  • to_dict()
  • to_api_payload()

这意味着你可以更容易地:

  • 构造前端可直接消费的校验响应
  • 渲染按行和按单元格的失败摘要
  • 保持 workbook 提示和 API 提示的一致性

常见字段类型的错误提示也更贴近业务语义了,例如:

  • 日期字段会直接提示期望的日期格式
  • 日期区间和数值区间字段会提示期望的组合输入格式
  • 邮箱、手机号、URL 会给出更自然的示例格式
  • 选项、组织、人员类字段会明确提示“必须来自配置项”

为什么这样设计

为什么去掉 pandas

这个项目真正需要的是:

  • 读写 Excel
  • 一个稳定的中间表格抽象
  • 对表头 / 行 / 错误坐标的精确控制

并不需要 pandas 擅长的分析能力。 因此改成 openpyxl + WorksheetTable 更贴合问题域,也让安装和依赖稳定性更好。

为什么做 Pydantic adapter

Excel 元数据不应该深绑到 Pydantic 内部结构上。 所以现在的分层是:

  • FieldMetaInfo 是对外兼容 façade,内部再组合声明层、运行时绑定层、展示层和导入约束层
  • helper/pydantic.py 只做适配
  • 真正的业务校验仍然由 ExcelAlchemy 控制

这就是为什么 Pydantic v2 迁移可以做得比较稳。

为什么做 storage abstraction

这个项目不应该等于 Minio。 Minio 只是一个默认实现,真正稳定的接口应该是 ExcelStorage

这样用户可以接:

  • 对象存储
  • 本地文件系统
  • 测试替身
  • 内存存储

演进记录

这个仓库的价值,很大一部分来自它的演进过程:

  • src/ layout 迁移
  • CI / 发布链路现代化
  • Pydantic 元数据层解耦
  • Pydantic v2 迁移
  • Python 3.12-3.14 现代化
  • 核心架构拆分
  • 去 pandas 化
  • 存储抽象化
  • 国际化基础层与 workbook locale 化

这些不是零碎优化,而是整套工程判断的痕迹。

文档索引

开发

uv sync --extra development
uv run pre-commit install
uv run ruff check .
uv run pyright
uv run pytest --cov=excelalchemy --cov-report=term-missing:skip-covered tests
uv build

许可证

MIT。详见 LICENSE