Skip to content

Commit ec77eca

Browse files
committed
feat(v2.2.5): Error UX polish
1 parent c7c3f14 commit ec77eca

47 files changed

Lines changed: 1584 additions & 134 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@ jobs:
107107
run: |
108108
uv run pytest --cov=excelalchemy --cov-report=term-missing:skip-covered --cov-report=xml:coverage.xml --junitxml=pytest.xml tests
109109
110+
- name: Run smoke scripts
111+
if: matrix.python-version == '3.14'
112+
run: |
113+
uv run python scripts/smoke_package.py
114+
uv run python scripts/smoke_examples.py
115+
uv run python scripts/generate_example_output_assets.py
116+
110117
- name: Upload coverage artifact
111118
if: always() && matrix.python-version == '3.14'
112119
uses: actions/upload-artifact@v7

.github/workflows/python-publish.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,17 @@ jobs:
5858
uv pip install --python .pkg-smoke-wheel/bin/python dist/*.whl
5959
.pkg-smoke-wheel/bin/python -c "import excelalchemy; print(excelalchemy.__version__)"
6060
.pkg-smoke-wheel/bin/python scripts/smoke_package.py
61+
.pkg-smoke-wheel/bin/python scripts/smoke_examples.py
62+
.pkg-smoke-wheel/bin/python scripts/generate_example_output_assets.py
6163
6264
- name: Smoke test source distribution installation
6365
run: |
6466
uv venv .pkg-smoke-sdist --python 3.14
6567
uv pip install --python .pkg-smoke-sdist/bin/python dist/*.tar.gz
6668
.pkg-smoke-sdist/bin/python -c "import excelalchemy; print(excelalchemy.__version__)"
6769
.pkg-smoke-sdist/bin/python scripts/smoke_package.py
70+
.pkg-smoke-sdist/bin/python scripts/smoke_examples.py
71+
.pkg-smoke-sdist/bin/python scripts/generate_example_output_assets.py
6872
6973
- name: Set artifact metadata
7074
id: artifact-meta

CHANGELOG.md

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,83 @@ All notable changes to this project will be documented in this file.
44

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

7-
## [2.2.3] - Unreleased
7+
## [2.2.5] - 2026-04-04
8+
9+
This release continues the stable 2.x line with error UX polish, clearer
10+
documentation boundaries, stronger examples and smoke coverage, and continued
11+
typing cleanup across the runtime path.
12+
13+
### Added
14+
15+
- Added `CellErrorMap` and `RowIssueMap` as richer workbook-facing error access
16+
containers while preserving 2.x dict-like compatibility
17+
- Added `docs/getting-started.md` to give new users one clear entry point for
18+
installation, schema declaration, workflow setup, and backend configuration
19+
- Added `docs/examples-showcase.md` and example-output assets so examples can
20+
be browsed as a lightweight showcase instead of only as source code
21+
- Added more business-oriented examples, including employee import,
22+
create-or-update import, export workflow, selection-heavy forms, and
23+
date/range field workflows
24+
- Added stronger smoke scripts and release checks for installed packages,
25+
repository examples, and generated example-output assets
26+
27+
### Changed
28+
29+
- Polished error UX so row and cell issues are easier to inspect through
30+
dedicated result-map helpers such as `at(...)`, `messages_at(...)`,
31+
`messages_for_row(...)`, and `flatten()`
32+
- Unified exception boundaries around `ProgrammaticError`, `ConfigError`,
33+
`ExcelCellError`, and `ExcelRowError`, including structured `to_dict()`
34+
output and clearer equality semantics
35+
- Normalized common validation messages into more natural, workbook-facing
36+
English such as `This field is required`
37+
- Clarified `FieldMetaInfo` as a compatibility facade over layered metadata
38+
objects and moved more internal consumers and codecs onto `declared`,
39+
`runtime`, `presentation`, and `constraints`
40+
- Continued shrinking typing gray areas outside `metadata.py` and
41+
`helper/pydantic.py` by removing or consolidating low-value `cast(...)`
42+
usage where concrete runtime behavior was already clear
43+
- Strengthened documentation boundaries by cross-linking getting-started,
44+
public API, migrations, examples, showcase, and PyPI-facing README content
45+
- Expanded `examples/README.md` into a recommended reading order with expected
46+
outputs and captured example artifacts
47+
48+
### Fixed
49+
50+
- Restored explicit `ProgrammaticError` handling for unsupported
51+
`Annotated[..., Field(...), ExcelMeta(...)]` declarations that use native
52+
Python types instead of `ExcelFieldCodec` subclasses
53+
- Tightened codec resolution in the Pydantic adapter so unsupported
54+
declarations fail at the codec resolution boundary instead of being treated
55+
as valid runtime metadata
56+
- Added regression coverage for the unsupported-annotation path and for error
57+
message quality in the Pydantic adapter
58+
59+
### Compatibility Notes
60+
61+
- No public import or export workflow API was removed in this release
62+
- Valid `ExcelFieldCodec` and `CompositeExcelFieldCodec` declarations continue
63+
to work unchanged
64+
- Unsupported native annotations with `ExcelMeta(...)` now fail early with the
65+
intended `ProgrammaticError`
66+
- `storage=...` remains the recommended 2.x backend configuration path, while
67+
legacy built-in Minio fields continue to exist only as compatibility surface
68+
- `FieldMeta(...)` and `ExcelMeta(...)` remain the stable public metadata entry
69+
points while internal metadata continues to consolidate behind them
70+
71+
### Release Summary
72+
73+
- import failures are easier to inspect and present through richer error maps
74+
- validation messages are more consistent, more natural, and better suited for
75+
workbook feedback
76+
- examples now read more like real integration guides and are protected by
77+
direct smoke coverage
78+
- getting-started, public API, migrations, examples, and showcase docs now
79+
form a clearer documentation path
80+
- runtime typing boundaries are a little tighter without sacrificing
81+
readability or 2.x compatibility
82+
83+
## [2.2.3] - Unpublished draft history
884

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

97-
## [2.2.1] - Unreleased
173+
## [2.2.1] - 2026-04-03
98174

99175
This release continues the stable 2.x line with deeper metadata layering,
100176
stronger internal immutability, and tighter type boundaries around the

MIGRATIONS.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@ If your application is still pinned to Pydantic v1, upgrade that dependency befo
2929
- Storage is now modeled as the `ExcelStorage` protocol
3030
- The built-in Minio backend is still available, but as an optional extra
3131

32+
### The 2.x recommendation in one sentence
33+
34+
For all new 2.x application code, prefer:
35+
36+
```python
37+
storage=...
38+
```
39+
40+
Treat the older built-in Minio fields as compatibility-only API surface.
41+
3242
### New install patterns
3343

3444
Base install:
@@ -59,7 +69,14 @@ config = ExporterConfig.for_storage(
5969

6070
### Legacy compatibility
6171

62-
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.
72+
The older `minio=..., bucket_name=..., url_expires=...` configuration style is
73+
still accepted for compatibility, but:
74+
75+
- it is not the recommended 2.x path
76+
- it emits a deprecation warning
77+
- it should be treated as a migration bridge rather than a long-term API choice
78+
79+
If you are writing new code in the 2.x line, use `storage=...` instead.
6380

6481
### Recommended importer constructors
6582

@@ -84,6 +101,15 @@ config = ImporterConfig.for_create_or_update(
84101
)
85102
```
86103

104+
### Examples and docs
105+
106+
If you want concrete examples of the recommended 2.x API shape, see:
107+
108+
- [`docs/getting-started.md`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/getting-started.md)
109+
- [`docs/public-api.md`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/public-api.md)
110+
- [`examples/README.md`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/examples/README.md)
111+
- [`docs/examples-showcase.md`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/examples-showcase.md)
112+
87113
## pandas
88114

89115
- ExcelAlchemy no longer uses or installs `pandas` at runtime

README-pypi.md

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ ExcelAlchemy turns Pydantic models into typed workbook contracts:
1010
- render workbook-facing output in `zh-CN` or `en`
1111
- keep storage pluggable through `ExcelStorage`
1212

13-
[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)
13+
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.
14+
15+
[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)
1416

1517
## Screenshots
1618

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

80+
## Example Outputs
81+
82+
These fixed outputs are generated from the repository examples by
83+
[`scripts/generate_example_output_assets.py`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/scripts/generate_example_output_assets.py).
84+
85+
Import workflow:
86+
87+
```text
88+
Employee import workflow completed
89+
Result: SUCCESS
90+
Success rows: 1
91+
Failed rows: 0
92+
Result workbook URL: None
93+
Created rows: 1
94+
Uploaded artifacts: []
95+
```
96+
97+
Export workflow:
98+
99+
```text
100+
Export workflow completed
101+
Artifact filename: employees-export.xlsx
102+
Artifact bytes: 6893
103+
Upload URL: memory://employees-export-upload.xlsx
104+
Uploaded objects: ['employees-export-upload.xlsx']
105+
```
106+
107+
Full captured outputs:
108+
109+
- [employee-import-workflow.txt](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/employee-import-workflow.txt)
110+
- [create-or-update-import.txt](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/create-or-update-import.txt)
111+
- [export-workflow.txt](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/export-workflow.txt)
112+
- [date-and-range-fields.txt](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/date-and-range-fields.txt)
113+
- [selection-fields.txt](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/selection-fields.txt)
114+
115+
For a single GitHub page that combines screenshots, representative workflows,
116+
and captured outputs, see the
117+
[Examples Showcase](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/examples-showcase.md).
118+
78119
## Why ExcelAlchemy
79120

80121
- Pydantic v2-based schema extraction and validation

README.md

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
![Lint](https://img.shields.io/badge/lint-ruff-D7FF64)
77
![Typing](https://img.shields.io/badge/typing-pyright-2C6BED)
88

9-
[中文 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)
9+
[中文 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)
1010

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

19-
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.
19+
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.
2020

2121
## At a Glance
2222

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

194+
If you want a single page that combines screenshots, representative workflows,
195+
and captured outputs, see
196+
[`docs/examples-showcase.md`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/examples-showcase.md).
197+
198+
Selected fixed outputs from the examples are generated by
199+
[`scripts/generate_example_output_assets.py`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/scripts/generate_example_output_assets.py).
200+
201+
### Example Outputs
202+
203+
Import workflow output:
204+
205+
```text
206+
Employee import workflow completed
207+
Result: SUCCESS
208+
Success rows: 1
209+
Failed rows: 0
210+
Result workbook URL: None
211+
Created rows: 1
212+
Uploaded artifacts: []
213+
```
214+
215+
Export workflow output:
216+
217+
```text
218+
Export workflow completed
219+
Artifact filename: employees-export.xlsx
220+
Artifact bytes: 6893
221+
Upload URL: memory://employees-export-upload.xlsx
222+
Uploaded objects: ['employees-export-upload.xlsx']
223+
```
224+
225+
Full captured outputs:
226+
227+
- [`files/example-outputs/employee-import-workflow.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/employee-import-workflow.txt)
228+
- [`files/example-outputs/create-or-update-import.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/create-or-update-import.txt)
229+
- [`files/example-outputs/export-workflow.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/export-workflow.txt)
230+
- [`files/example-outputs/date-and-range-fields.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/date-and-range-fields.txt)
231+
- [`files/example-outputs/selection-fields.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/selection-fields.txt)
232+
- [`files/example-outputs/custom-storage.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/custom-storage.txt)
233+
- [`files/example-outputs/annotated-schema.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/annotated-schema.txt)
234+
194235
## Public API Boundaries
195236

196237
If you want to know which modules are stable public entry points versus

README_cn.md

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
ExcelAlchemy 是一个面向 Excel 导入导出的 schema-first Python 库。
66
它的核心思路不是“读写表格文件”,而是“把 Excel 当成一种带约束的业务契约”。
77

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

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

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

123+
如果你想看一页汇总好的展示页,里面同时包含截图、代表性工作流和固定输出,
124+
可以直接看
125+
[`docs/examples-showcase.md`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/examples-showcase.md)
126+
127+
这些固定输出素材由
128+
[`scripts/generate_example_output_assets.py`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/scripts/generate_example_output_assets.py)
129+
生成。
130+
131+
### 示例输出
132+
133+
导入工作流输出:
134+
135+
```text
136+
Employee import workflow completed
137+
Result: SUCCESS
138+
Success rows: 1
139+
Failed rows: 0
140+
Result workbook URL: None
141+
Created rows: 1
142+
Uploaded artifacts: []
143+
```
144+
145+
导出工作流输出:
146+
147+
```text
148+
Export workflow completed
149+
Artifact filename: employees-export.xlsx
150+
Artifact bytes: 6893
151+
Upload URL: memory://employees-export-upload.xlsx
152+
Uploaded objects: ['employees-export-upload.xlsx']
153+
```
154+
155+
完整输出:
156+
157+
- [`files/example-outputs/employee-import-workflow.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/employee-import-workflow.txt)
158+
- [`files/example-outputs/create-or-update-import.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/create-or-update-import.txt)
159+
- [`files/example-outputs/export-workflow.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/export-workflow.txt)
160+
- [`files/example-outputs/date-and-range-fields.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/date-and-range-fields.txt)
161+
- [`files/example-outputs/selection-fields.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/selection-fields.txt)
162+
- [`files/example-outputs/custom-storage.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/custom-storage.txt)
163+
- [`files/example-outputs/annotated-schema.txt`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/files/example-outputs/annotated-schema.txt)
164+
123165
## 快速开始
124166

125167
```python

0 commit comments

Comments
 (0)