Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ jobs:
run: |
uv run pytest --cov=excelalchemy --cov-report=term-missing:skip-covered --cov-report=xml:coverage.xml --junitxml=pytest.xml tests
- name: Run smoke scripts
if: matrix.python-version == '3.14'
run: |
uv run python scripts/smoke_package.py
uv run python scripts/smoke_examples.py
uv run python scripts/generate_example_output_assets.py
- name: Upload coverage artifact
if: always() && matrix.python-version == '3.14'
uses: actions/upload-artifact@v7
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,17 @@ jobs:
uv pip install --python .pkg-smoke-wheel/bin/python dist/*.whl
.pkg-smoke-wheel/bin/python -c "import excelalchemy; print(excelalchemy.__version__)"
.pkg-smoke-wheel/bin/python scripts/smoke_package.py
.pkg-smoke-wheel/bin/python scripts/smoke_examples.py
.pkg-smoke-wheel/bin/python scripts/generate_example_output_assets.py

- name: Smoke test source distribution installation
run: |
uv venv .pkg-smoke-sdist --python 3.14
uv pip install --python .pkg-smoke-sdist/bin/python dist/*.tar.gz
.pkg-smoke-sdist/bin/python -c "import excelalchemy; print(excelalchemy.__version__)"
.pkg-smoke-sdist/bin/python scripts/smoke_package.py
.pkg-smoke-sdist/bin/python scripts/smoke_examples.py
.pkg-smoke-sdist/bin/python scripts/generate_example_output_assets.py

- name: Set artifact metadata
id: artifact-meta
Expand Down
80 changes: 78 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,83 @@ All notable changes to this project will be documented in this file.

The format is inspired by Keep a Changelog and versioned according to PEP 440.

## [2.2.3] - Unreleased
## [2.2.5] - 2026-04-04

This release continues the stable 2.x line with error UX polish, clearer
documentation boundaries, stronger examples and smoke coverage, and continued
typing cleanup across the runtime path.

### Added

- Added `CellErrorMap` and `RowIssueMap` as richer workbook-facing error access
containers while preserving 2.x dict-like compatibility
- Added `docs/getting-started.md` to give new users one clear entry point for
installation, schema declaration, workflow setup, and backend configuration
- Added `docs/examples-showcase.md` and example-output assets so examples can
be browsed as a lightweight showcase instead of only as source code
- Added more business-oriented examples, including employee import,
create-or-update import, export workflow, selection-heavy forms, and
date/range field workflows
- Added stronger smoke scripts and release checks for installed packages,
repository examples, and generated example-output assets

### Changed

- Polished error UX so row and cell issues are easier to inspect through
dedicated result-map helpers such as `at(...)`, `messages_at(...)`,
`messages_for_row(...)`, and `flatten()`
- Unified exception boundaries around `ProgrammaticError`, `ConfigError`,
`ExcelCellError`, and `ExcelRowError`, including structured `to_dict()`
output and clearer equality semantics
- Normalized common validation messages into more natural, workbook-facing
English such as `This field is required`
- Clarified `FieldMetaInfo` as a compatibility facade over layered metadata
objects and moved more internal consumers and codecs onto `declared`,
`runtime`, `presentation`, and `constraints`
- Continued shrinking typing gray areas outside `metadata.py` and
`helper/pydantic.py` by removing or consolidating low-value `cast(...)`
usage where concrete runtime behavior was already clear
- Strengthened documentation boundaries by cross-linking getting-started,
public API, migrations, examples, showcase, and PyPI-facing README content
- Expanded `examples/README.md` into a recommended reading order with expected
outputs and captured example artifacts

### Fixed

- Restored explicit `ProgrammaticError` handling for unsupported
`Annotated[..., Field(...), ExcelMeta(...)]` declarations that use native
Python types instead of `ExcelFieldCodec` subclasses
- Tightened codec resolution in the Pydantic adapter so unsupported
declarations fail at the codec resolution boundary instead of being treated
as valid runtime metadata
- Added regression coverage for the unsupported-annotation path and for error
message quality in the Pydantic adapter

### Compatibility Notes

- No public import or export workflow API was removed in this release
- Valid `ExcelFieldCodec` and `CompositeExcelFieldCodec` declarations continue
to work unchanged
- Unsupported native annotations with `ExcelMeta(...)` now fail early with the
intended `ProgrammaticError`
- `storage=...` remains the recommended 2.x backend configuration path, while
legacy built-in Minio fields continue to exist only as compatibility surface
- `FieldMeta(...)` and `ExcelMeta(...)` remain the stable public metadata entry
points while internal metadata continues to consolidate behind them

### Release Summary

- import failures are easier to inspect and present through richer error maps
- validation messages are more consistent, more natural, and better suited for
workbook feedback
- examples now read more like real integration guides and are protected by
direct smoke coverage
- getting-started, public API, migrations, examples, and showcase docs now
form a clearer documentation path
- runtime typing boundaries are a little tighter without sacrificing
readability or 2.x compatibility

## [2.2.3] - Unpublished draft history

This release continues the stable 2.x line with a focused validation fix in
the Pydantic adapter layer.
Expand Down Expand Up @@ -94,7 +170,7 @@ clearer public API guidance, and better release-time smoke coverage.
- release publishing now includes stronger smoke coverage for installed
packages

## [2.2.1] - Unreleased
## [2.2.1] - 2026-04-03

This release continues the stable 2.x line with deeper metadata layering,
stronger internal immutability, and tighter type boundaries around the
Expand Down
28 changes: 27 additions & 1 deletion MIGRATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ If your application is still pinned to Pydantic v1, upgrade that dependency befo
- Storage is now modeled as the `ExcelStorage` protocol
- The built-in Minio backend is still available, but as an optional extra

### The 2.x recommendation in one sentence

For all new 2.x application code, prefer:

```python
storage=...
```

Treat the older built-in Minio fields as compatibility-only API surface.

### New install patterns

Base install:
Expand Down Expand Up @@ -59,7 +69,14 @@ config = ExporterConfig.for_storage(

### Legacy compatibility

The older `minio=..., bucket_name=..., url_expires=...` configuration style is still accepted for compatibility, but it is no longer the preferred shape of the API and now emits a deprecation warning in the 2.x line.
The older `minio=..., bucket_name=..., url_expires=...` configuration style is
still accepted for compatibility, but:

- it is not the recommended 2.x path
- it emits a deprecation warning
- it should be treated as a migration bridge rather than a long-term API choice

If you are writing new code in the 2.x line, use `storage=...` instead.

### Recommended importer constructors

Expand All @@ -84,6 +101,15 @@ config = ImporterConfig.for_create_or_update(
)
```

### Examples and docs

If you want concrete examples of the recommended 2.x API shape, see:

- [`docs/getting-started.md`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/getting-started.md)
- [`docs/public-api.md`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/public-api.md)
- [`examples/README.md`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/examples/README.md)
- [`docs/examples-showcase.md`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/examples-showcase.md)

## pandas

- ExcelAlchemy no longer uses or installs `pandas` at runtime
Expand Down
43 changes: 42 additions & 1 deletion README-pypi.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ ExcelAlchemy turns Pydantic models into typed workbook contracts:
- render workbook-facing output in `zh-CN` or `en`
- keep storage pluggable through `ExcelStorage`

[GitHub Repository](https://github.com/RayCarterLab/ExcelAlchemy) · [Full README](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/README.md) · [Architecture](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/architecture.md) · [Migration Notes](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/MIGRATIONS.md)
The current stable release is `2.2.5`, which continues the 2.x line with richer import-failure feedback, clearer documentation entry points, stronger examples, and stronger smoke coverage.

[GitHub Repository](https://github.com/RayCarterLab/ExcelAlchemy) · [Full README](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/README.md) · [Getting Started](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/getting-started.md) · [Examples Showcase](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/examples-showcase.md) · [Architecture](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/architecture.md) · [Migration Notes](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/MIGRATIONS.md)

## Screenshots

Expand Down Expand Up @@ -75,6 +77,45 @@ alchemy = ExcelAlchemy(ImporterConfig(Importer, locale='en'))
template = alchemy.download_template_artifact(filename='people-template.xlsx')
```

## Example Outputs

These fixed outputs are generated from the repository examples by
[`scripts/generate_example_output_assets.py`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/scripts/generate_example_output_assets.py).

Import workflow:

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

Export workflow:

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

Full captured outputs:

- [employee-import-workflow.txt](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/employee-import-workflow.txt)
- [create-or-update-import.txt](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/create-or-update-import.txt)
- [export-workflow.txt](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/export-workflow.txt)
- [date-and-range-fields.txt](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/date-and-range-fields.txt)
- [selection-fields.txt](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/selection-fields.txt)

For a single GitHub page that combines screenshots, representative workflows,
and captured outputs, see the
[Examples Showcase](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/examples-showcase.md).

## Why ExcelAlchemy

- Pydantic v2-based schema extraction and validation
Expand Down
45 changes: 43 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
![Lint](https://img.shields.io/badge/lint-ruff-D7FF64)
![Typing](https://img.shields.io/badge/typing-pyright-2C6BED)

[中文 README](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/README_cn.md) · [About](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/ABOUT.md) · [Architecture](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/architecture.md) · [Public API](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/public-api.md) · [Locale Policy](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/locale.md) · [Changelog](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/CHANGELOG.md) · [Migration Notes](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/MIGRATIONS.md)
[中文 README](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/README_cn.md) · [About](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/ABOUT.md) · [Getting Started](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/getting-started.md) · [Architecture](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/architecture.md) · [Examples Showcase](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/examples-showcase.md) · [Public API](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/public-api.md) · [Locale Policy](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/locale.md) · [Changelog](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/CHANGELOG.md) · [Migration Notes](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/MIGRATIONS.md)

ExcelAlchemy is a schema-driven Python library for Excel import and export workflows.
It turns Pydantic models into typed workbook contracts: generate templates, validate uploads, map failures back to rows
Expand All @@ -16,7 +16,7 @@ This repository is also a design artifact.
It documents a series of deliberate engineering choices: `src/` layout, Pydantic v2 migration, pandas removal,
pluggable storage, `uv`-based workflows, and locale-aware workbook output.

The current stable release is `2.2.0`, which continues the ExcelAlchemy 2.x line with a lighter import facade, clearer config ergonomics, and a more explicit protocol-first storage story.
The current stable release is `2.2.5`, which continues the ExcelAlchemy 2.x line with richer import-failure feedback, clearer getting-started and public-API guidance, stronger real-world examples, and stronger release smoke coverage.

## At a Glance

Expand Down Expand Up @@ -191,6 +191,47 @@ Practical examples live in the repository:
If you want the recommended reading order, start with
[`examples/README.md`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/examples/README.md).

If you want a single page that combines screenshots, representative workflows,
and captured outputs, see
[`docs/examples-showcase.md`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/examples-showcase.md).

Selected fixed outputs from the examples are generated by
[`scripts/generate_example_output_assets.py`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/scripts/generate_example_output_assets.py).

### Example Outputs

Import workflow output:

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

Export workflow output:

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

Full captured outputs:

- [`files/example-outputs/employee-import-workflow.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/employee-import-workflow.txt)
- [`files/example-outputs/create-or-update-import.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/create-or-update-import.txt)
- [`files/example-outputs/export-workflow.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/export-workflow.txt)
- [`files/example-outputs/date-and-range-fields.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/date-and-range-fields.txt)
- [`files/example-outputs/selection-fields.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/selection-fields.txt)
- [`files/example-outputs/custom-storage.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/custom-storage.txt)
- [`files/example-outputs/annotated-schema.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/annotated-schema.txt)

## Public API Boundaries

If you want to know which modules are stable public entry points versus
Expand Down
44 changes: 43 additions & 1 deletion README_cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
ExcelAlchemy 是一个面向 Excel 导入导出的 schema-first Python 库。
它的核心思路不是“读写表格文件”,而是“把 Excel 当成一种带约束的业务契约”。

当前稳定发布版本是 `2.2.0`,它在稳定的 ExcelAlchemy 2.x 线上继续推进了导入 facade 轻量化、更清晰的配置构造方式,以及更明确的 protocol-first storage 叙事
当前稳定发布版本是 `2.2.5`,它在稳定的 ExcelAlchemy 2.x 线上继续加强了导入失败反馈、更清晰的入门与 public API 文档、更贴近真实业务的示例,以及更强的 release smoke 验证

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

Expand Down Expand Up @@ -120,6 +120,48 @@ pip install "ExcelAlchemy[minio]"
如果你想按推荐顺序来阅读,建议先看
[`examples/README.md`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/examples/README.md)。

如果你想看一页汇总好的展示页,里面同时包含截图、代表性工作流和固定输出,
可以直接看
[`docs/examples-showcase.md`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/examples-showcase.md)。

这些固定输出素材由
[`scripts/generate_example_output_assets.py`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/scripts/generate_example_output_assets.py)
生成。

### 示例输出

导入工作流输出:

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

导出工作流输出:

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

完整输出:

- [`files/example-outputs/employee-import-workflow.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/employee-import-workflow.txt)
- [`files/example-outputs/create-or-update-import.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/create-or-update-import.txt)
- [`files/example-outputs/export-workflow.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/export-workflow.txt)
- [`files/example-outputs/date-and-range-fields.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/date-and-range-fields.txt)
- [`files/example-outputs/selection-fields.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/selection-fields.txt)
- [`files/example-outputs/custom-storage.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/custom-storage.txt)
- [`files/example-outputs/annotated-schema.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/annotated-schema.txt)

## 快速开始

```python
Expand Down
Loading