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
2 changes: 2 additions & 0 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,14 @@ jobs:
uv venv .pkg-smoke-wheel --python 3.14
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

- 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

- name: Set artifact metadata
id: artifact-meta
Expand Down
37 changes: 37 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,43 @@ 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.2] - Unreleased

This release continues the stable 2.x line with stronger developer ergonomics,
clearer public API guidance, and better release-time smoke coverage.

### Added

- Added repository examples for:
`Annotated` schema declarations, custom storage integration, and FastAPI
upload flows
- Added `docs/public-api.md` to document stable public modules, compatibility
modules, and internal modules
- Added `scripts/smoke_package.py` so release workflows can smoke-test template
generation, import execution, and export generation from an installed package

### Changed

- Updated the release workflow to run package-level smoke tests after wheel and
source-distribution installation
- Updated `README.md`, `README_cn.md`, and `MIGRATIONS.md` to point users
toward examples, public API guidance, and the recommended config/storage
patterns

### Compatibility Notes

- No public import or export workflow API was removed in this release
- The new examples and docs clarify recommended public paths without changing
existing 2.x compatibility behavior

### Release Summary

- the repository now includes real integration examples instead of relying only
on README snippets
- public API boundaries are documented explicitly
- release publishing now includes stronger smoke coverage for installed
packages

## [2.2.1] - Unreleased

This release continues the stable 2.x line with deeper metadata layering,
Expand Down
28 changes: 26 additions & 2 deletions MIGRATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,38 @@ Prefer explicit storage objects:
from excelalchemy import ExporterConfig
from excelalchemy.core.storage_minio import MinioStorageGateway

config = ExporterConfig(
config = ExporterConfig.for_storage(
ExporterModel,
storage=MinioStorageGateway(minio_client, bucket_name='excel-files'),
)
```

### 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.
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.

### Recommended importer constructors

The 2.2 line also adds more explicit constructors for common importer modes:

```python
config = ImporterConfig.for_create(ImporterModel, creator=create_func, storage=storage)
```

```python
config = ImporterConfig.for_update(ImporterModel, updater=update_func, storage=storage)
```

```python
config = ImporterConfig.for_create_or_update(
create_importer_model=CreateModel,
update_importer_model=UpdateModel,
is_data_exist=is_data_exist,
creator=create_func,
updater=update_func,
storage=storage,
)
```

## pandas

Expand Down Expand Up @@ -99,6 +122,7 @@ Additional top-level module guidance:
- `excelalchemy.exceptions` is the stable replacement for `excelalchemy.exc`
- `excelalchemy.identity` is now a compatibility import; prefer `from excelalchemy import Label, Key, UrlStr, ...`
- `excelalchemy.header_models` is internal and should not be imported in application code
- `docs/public-api.md` summarizes stable public modules, compatibility modules, and internal modules

## Recommended Upgrade Checklist

Expand Down
18 changes: 16 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) · [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) · [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)

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.1.0`, which continues the ExcelAlchemy 2.x line with a lighter import facade, clearer internal layering, and naming cleanup.
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.

## At a Glance

Expand Down Expand Up @@ -173,6 +173,20 @@ If you want the built-in Minio backend:
pip install "ExcelAlchemy[minio]"
```

## Examples

Practical examples live in the repository:

- [`examples/annotated_schema.py`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/examples/annotated_schema.py)
- [`examples/custom_storage.py`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/examples/custom_storage.py)
- [`examples/fastapi_upload.py`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/examples/fastapi_upload.py)

## Public API Boundaries

If you want to know which modules are stable public entry points versus
compatibility shims or internal modules, see
[`docs/public-api.md`](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/public-api.md).

## Locale-Aware Workbook Output

`locale` affects workbook-facing display text such as:
Expand Down
2 changes: 1 addition & 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.1.0`,它在稳定的 ExcelAlchemy 2.x 线上继续推进了导入 facade 轻量化、内部结构分层和命名收口
当前稳定发布版本是 `2.2.0`,它在稳定的 ExcelAlchemy 2.x 线上继续推进了导入 facade 轻量化、更清晰的配置构造方式,以及更明确的 protocol-first storage 叙事

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

Expand Down
94 changes: 94 additions & 0 deletions docs/public-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Public API Guide

This page summarizes which ExcelAlchemy modules are intended to be stable public
entry points, which ones remain compatibility shims for the 2.x line, and which
ones should be treated as internal implementation details.

## Stable Public Modules

These modules are the recommended import paths for application code:

- `excelalchemy`
The package root re-exports the most common public types, codecs, config
objects, and result models.
- `excelalchemy.config`
Public workflow configuration objects such as `ImporterConfig`,
`ExporterConfig`, and `ImportMode`.
- `excelalchemy.metadata`
Public metadata entry points such as `FieldMeta(...)`, `ExcelMeta(...)`, and
`PatchFieldMeta`.
- `excelalchemy.results`
Structured import result models such as `ImportResult`,
`ValidateResult`, and `ValidateHeaderResult`.
- `excelalchemy.exceptions`
Stable exception module for `ConfigError`, `ExcelCellError`,
`ExcelRowError`, and `ProgrammaticError`.
- `excelalchemy.codecs`
Public codec namespace for built-in Excel field codecs.

## Stable Public Protocols And Concepts

- `ExcelStorage`
The recommended backend integration contract for workbook IO.
- `storage=...`
The recommended backend configuration pattern in the 2.x line.
- `ExcelArtifact`
The recommended return shape when you need bytes, base64, or data URLs.

## Compatibility Modules In 2.x

These imports still work in the 2.x line, but should be treated as migration
paths rather than long-term public module choices:

- `excelalchemy.exc`
Deprecated compatibility layer. Prefer `excelalchemy.exceptions`.
- `excelalchemy.identity`
Deprecated compatibility layer. Prefer imports from the package root.
- `excelalchemy.header_models`
Compatibility layer; application code should not depend on it.
- `excelalchemy.types.*`
Deprecated compatibility namespace retained for 2.x migrations.
- `excelalchemy.util.convertor`
Deprecated compatibility import. Prefer `excelalchemy.util.converter`.

## Internal Modules

These modules may change without notice and should not be imported directly in
application code:

- `excelalchemy.core.*`
- `excelalchemy.helper.*`
- `excelalchemy.i18n.*`
- `excelalchemy._primitives.*`

The internals are intentionally allowed to evolve as the 2.x architecture
continues to consolidate.

## Recommended Import Style

Prefer imports like:

```python
from excelalchemy import ExcelAlchemy, ExcelMeta, FieldMeta, ImporterConfig, ValidateResult
from excelalchemy.config import ExporterConfig, ImportMode
from excelalchemy.exceptions import ConfigError
```

Avoid depending on implementation details such as:

```python
from excelalchemy.core.alchemy import ExcelAlchemy
from excelalchemy.core.headers import ExcelHeaderParser
from excelalchemy._primitives.identity import UniqueLabel
```

## Deprecation Direction

The 2.x line keeps compatibility shims to support migration, but the long-term
direction is:

- public API from `excelalchemy`, `excelalchemy.config`,
`excelalchemy.metadata`, `excelalchemy.results`, `excelalchemy.exceptions`,
and `excelalchemy.codecs`
- backend integration through `ExcelStorage`
- internal orchestration and helper modules treated as implementation details
77 changes: 77 additions & 0 deletions docs/releases/2.2.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# 2.2.2 Release Checklist

This checklist is intended for the `2.2.2` release on top of the stable 2.x
line.

## Purpose

- publish the next stable 2.x refinement release of ExcelAlchemy
- present `2.2.2` as a developer-ergonomics and release-hardening release
- ship real integration examples and explicit public API documentation
- strengthen package-level smoke coverage in the release workflow

## Release Positioning

`2.2.2` should be presented as a repository-quality release:

- the public import and export workflow API stays stable
- examples now show realistic integration paths beyond README snippets
- public API boundaries are documented explicitly
- release publishing has stronger smoke verification for installed packages

## Before Tagging

1. Confirm the intended version in `src/excelalchemy/__init__.py`.
2. Review the `2.2.2` section in `CHANGELOG.md`.
3. Confirm `README.md`, `README_cn.md`, `README-pypi.md`, and `MIGRATIONS.md`
are aligned with the recommended public paths.
4. Confirm the new examples still reflect the current public API.
5. Confirm `docs/public-api.md` matches the current public module boundaries.

## Local Verification

Run these commands from the repository root:

```bash
uv sync --extra development
uv run ruff check .
uv run pyright
uv run pytest tests
python scripts/smoke_package.py
rm -rf dist
uv build
uvx twine check dist/*
```

## GitHub Release Steps

1. Push the release commit to the default branch.
2. In GitHub Releases, draft a new release.
3. Create a new tag: `v2.2.2`.
4. Use the `2.2.2` section from `CHANGELOG.md` as the release notes base.
5. Publish the release and monitor the `Upload Python Package` workflow.

## Release Focus

When reviewing the final release notes, make sure they communicate these three
themes clearly:

- the repository now includes real integration examples
- public API boundaries are documented explicitly
- release publishing now has stronger smoke verification for installed packages

## Recommended Release Messaging

Prefer wording that emphasizes maturity and usability:

- "continues the stable 2.x line"
- "adds real integration examples"
- "documents public API boundaries explicitly"
- "strengthens release-time smoke verification"

## Done When

- the tag `v2.2.2` is published
- the GitHub Release notes clearly communicate the three release themes
- examples and public API docs are linked from the main project pages
- release workflow smoke tests pass for installed packages
29 changes: 29 additions & 0 deletions examples/annotated_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""Minimal example that uses Annotated + ExcelMeta declarations."""

from __future__ import annotations

from typing import Annotated

from pydantic import BaseModel, Field

from excelalchemy import Email, ExcelAlchemy, ExcelMeta, ImporterConfig, Number


class EmployeeImporter(BaseModel):
full_name: Annotated[str, Field(min_length=2), ExcelMeta(label='Full name', order=1, hint='Use the legal name')]
age: Annotated[Number, Field(ge=18), ExcelMeta(label='Age', order=2)]
work_email: Annotated[
Email,
Field(min_length=8),
ExcelMeta(label='Work email', order=3, hint='Use your company email address'),
]


def main() -> None:
alchemy = ExcelAlchemy(ImporterConfig.for_create(EmployeeImporter, locale='en'))
template = alchemy.download_template_artifact(filename='employee-template.xlsx')
print(f'Generated template: {template.filename} ({len(template.as_bytes())} bytes)')


if __name__ == '__main__':
main()
Loading