ExcelAlchemy 2.2.8__tar.gz → 2.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/PKG-INFO +15 -3
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/README-pypi.md +14 -2
- excelalchemy-2.3.0/src/excelalchemy/README.md +463 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/__init__.py +13 -2
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/codecs/boolean.py +1 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/codecs/date.py +1 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/codecs/date_range.py +1 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/codecs/multi_checkbox.py +1 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/codecs/number.py +1 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/codecs/organization.py +6 -1
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/codecs/radio.py +1 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/codecs/staff.py +8 -1
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/codecs/string.py +1 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/codecs/tree.py +6 -1
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/core/abstract.py +13 -3
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/core/alchemy.py +27 -4
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/core/import_session.py +118 -48
- excelalchemy-2.3.0/src/excelalchemy/core/preflight.py +97 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/core/storage_minio.py +6 -2
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/exceptions.py +7 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/i18n/messages.py +3 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/metadata.py +27 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/results.py +301 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/LICENSE +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/pyproject.toml +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/_primitives/__init__.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/_primitives/constants.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/_primitives/deprecation.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/_primitives/diagnostics.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/_primitives/header_models.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/_primitives/identity.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/_primitives/payloads.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/artifacts.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/codecs/__init__.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/codecs/base.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/codecs/email.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/codecs/money.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/codecs/number_range.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/codecs/phone_number.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/codecs/url.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/config.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/const.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/core/__init__.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/core/executor.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/core/headers.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/core/rendering.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/core/rows.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/core/schema.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/core/storage.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/core/storage_protocol.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/core/table.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/core/writer.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/exc.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/header_models.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/helper/__init__.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/helper/pydantic.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/i18n/__init__.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/identity.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/py.typed +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/types/__init__.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/types/abstract.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/types/alchemy.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/types/field.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/types/header.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/types/identity.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/types/result.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/types/value/__init__.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/types/value/boolean.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/types/value/date.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/types/value/date_range.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/types/value/email.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/types/value/money.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/types/value/multi_checkbox.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/types/value/number.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/types/value/number_range.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/types/value/organization.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/types/value/phone_number.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/types/value/radio.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/types/value/staff.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/types/value/string.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/types/value/tree.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/types/value/url.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/util/__init__.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/util/converter.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/util/convertor.py +0 -0
- {excelalchemy-2.2.8 → excelalchemy-2.3.0}/src/excelalchemy/util/file.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ExcelAlchemy
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: Schema-driven Python library for typed Excel import/export workflows with Pydantic and locale-aware workbooks.
|
|
5
5
|
Keywords: excel,openpyxl,pydantic,minio,schema
|
|
6
6
|
Author: Ray
|
|
@@ -49,7 +49,10 @@ ExcelAlchemy turns Pydantic models into typed workbook contracts:
|
|
|
49
49
|
- render workbook-facing output in `zh-CN` or `en`
|
|
50
50
|
- keep storage pluggable through `ExcelStorage`
|
|
51
51
|
|
|
52
|
-
The current stable release is `2.
|
|
52
|
+
The current stable release is `2.3.0`, which continues the 2.x line with a
|
|
53
|
+
more complete import workflow: clearer template guidance before upload,
|
|
54
|
+
lightweight structural preflight before execution, synchronous lifecycle
|
|
55
|
+
visibility during import, and remediation-oriented payloads after failures.
|
|
53
56
|
|
|
54
57
|
[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) · [Integration Roadmap](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/integration-roadmap.md) · [Result Objects](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/result-objects.md) · [API Response Cookbook](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/api-response-cookbook.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)
|
|
55
58
|
|
|
@@ -108,7 +111,12 @@ class Importer(BaseModel):
|
|
|
108
111
|
email: Annotated[
|
|
109
112
|
Email,
|
|
110
113
|
Field(min_length=10),
|
|
111
|
-
ExcelMeta(
|
|
114
|
+
ExcelMeta(
|
|
115
|
+
label='Email',
|
|
116
|
+
order=1,
|
|
117
|
+
hint='Use your work email',
|
|
118
|
+
example_value='alice@company.com',
|
|
119
|
+
),
|
|
112
120
|
]
|
|
113
121
|
|
|
114
122
|
|
|
@@ -116,6 +124,10 @@ alchemy = ExcelAlchemy(ImporterConfig(Importer, locale='en'))
|
|
|
116
124
|
template = alchemy.download_template_artifact(filename='people-template.xlsx')
|
|
117
125
|
```
|
|
118
126
|
|
|
127
|
+
This template metadata is additive: it leaves the worksheet layout alone and
|
|
128
|
+
improves the generated header comment with both guidance text and a concrete
|
|
129
|
+
example value.
|
|
130
|
+
|
|
119
131
|
## Example Outputs
|
|
120
132
|
|
|
121
133
|
These fixed outputs are generated from the repository examples by
|
|
@@ -10,7 +10,10 @@ ExcelAlchemy turns Pydantic models into typed workbook contracts:
|
|
|
10
10
|
- render workbook-facing output in `zh-CN` or `en`
|
|
11
11
|
- keep storage pluggable through `ExcelStorage`
|
|
12
12
|
|
|
13
|
-
The current stable release is `2.
|
|
13
|
+
The current stable release is `2.3.0`, which continues the 2.x line with a
|
|
14
|
+
more complete import workflow: clearer template guidance before upload,
|
|
15
|
+
lightweight structural preflight before execution, synchronous lifecycle
|
|
16
|
+
visibility during import, and remediation-oriented payloads after failures.
|
|
14
17
|
|
|
15
18
|
[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) · [Integration Roadmap](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/integration-roadmap.md) · [Result Objects](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/result-objects.md) · [API Response Cookbook](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/api-response-cookbook.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)
|
|
16
19
|
|
|
@@ -69,7 +72,12 @@ class Importer(BaseModel):
|
|
|
69
72
|
email: Annotated[
|
|
70
73
|
Email,
|
|
71
74
|
Field(min_length=10),
|
|
72
|
-
ExcelMeta(
|
|
75
|
+
ExcelMeta(
|
|
76
|
+
label='Email',
|
|
77
|
+
order=1,
|
|
78
|
+
hint='Use your work email',
|
|
79
|
+
example_value='alice@company.com',
|
|
80
|
+
),
|
|
73
81
|
]
|
|
74
82
|
|
|
75
83
|
|
|
@@ -77,6 +85,10 @@ alchemy = ExcelAlchemy(ImporterConfig(Importer, locale='en'))
|
|
|
77
85
|
template = alchemy.download_template_artifact(filename='people-template.xlsx')
|
|
78
86
|
```
|
|
79
87
|
|
|
88
|
+
This template metadata is additive: it leaves the worksheet layout alone and
|
|
89
|
+
improves the generated header comment with both guidance text and a concrete
|
|
90
|
+
example value.
|
|
91
|
+
|
|
80
92
|
## Example Outputs
|
|
81
93
|
|
|
82
94
|
These fixed outputs are generated from the repository examples by
|
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
# `src/excelalchemy/` Package Guide
|
|
2
|
+
|
|
3
|
+
This file explains the internal structure of the main package directory.
|
|
4
|
+
It is meant for developers and AI agents who need to change implementation details without confusing public API, compatibility layers, and internal collaborators.
|
|
5
|
+
|
|
6
|
+
## Related docs
|
|
7
|
+
|
|
8
|
+
- [../../README.md](../../README.md) for the public-facing overview.
|
|
9
|
+
- [../../AGENTS.md](../../AGENTS.md) for repository-local editing guidance.
|
|
10
|
+
- [../../docs/repo-map.md](../../docs/repo-map.md) for top-level repository navigation.
|
|
11
|
+
- [../../docs/domain-model.md](../../docs/domain-model.md) for the main concepts implemented here.
|
|
12
|
+
- [../../docs/invariants.md](../../docs/invariants.md) for important behavioral constraints.
|
|
13
|
+
- [../../tests/README.md](../../tests/README.md) for where this package's behavior is protected.
|
|
14
|
+
|
|
15
|
+
## Role of This Package
|
|
16
|
+
|
|
17
|
+
- `src/excelalchemy/` is the main library package.
|
|
18
|
+
- It contains:
|
|
19
|
+
- the stable public surface used by application code
|
|
20
|
+
- the internal orchestration that implements import, export, template generation, rendering, and storage integration
|
|
21
|
+
- compatibility modules retained for the 2.x line
|
|
22
|
+
- The package is organized around a small public facade and a set of focused internal collaborators.
|
|
23
|
+
|
|
24
|
+
## High-Level Package Structure
|
|
25
|
+
|
|
26
|
+
- `__init__.py`
|
|
27
|
+
- Main public re-export surface.
|
|
28
|
+
- If application-facing imports change, start here.
|
|
29
|
+
- `config.py`
|
|
30
|
+
- Public workflow configuration types.
|
|
31
|
+
- `metadata.py`
|
|
32
|
+
- Public metadata declarations plus the internal layered field-metadata model.
|
|
33
|
+
- `results.py`
|
|
34
|
+
- Public result models and API-friendly error maps.
|
|
35
|
+
- `exceptions.py`
|
|
36
|
+
- Public exception types.
|
|
37
|
+
- `artifacts.py`
|
|
38
|
+
- Public workbook artifact wrapper.
|
|
39
|
+
- `codecs/`
|
|
40
|
+
- Public field codecs and codec base classes.
|
|
41
|
+
- `core/`
|
|
42
|
+
- Internal workflow orchestration and execution.
|
|
43
|
+
- `helper/`
|
|
44
|
+
- Internal adapter layer, currently centered on Pydantic integration.
|
|
45
|
+
- `i18n/`
|
|
46
|
+
- Internal message and locale handling.
|
|
47
|
+
- `_primitives/`
|
|
48
|
+
- Internal low-level types, constants, payload aliases, diagnostics, and deprecation helpers.
|
|
49
|
+
- `types/`, `exc.py`, `identity.py`, `header_models.py`, `const.py`, `util/convertor.py`
|
|
50
|
+
- Compatibility-oriented modules retained in the 2.x line.
|
|
51
|
+
|
|
52
|
+
## Public Surface vs Internal Implementation
|
|
53
|
+
|
|
54
|
+
### Public surface
|
|
55
|
+
|
|
56
|
+
These modules are the stable public entry points documented in `docs/public-api.md`:
|
|
57
|
+
|
|
58
|
+
- `src/excelalchemy/__init__.py`
|
|
59
|
+
- `src/excelalchemy/config.py`
|
|
60
|
+
- `src/excelalchemy/metadata.py`
|
|
61
|
+
- `src/excelalchemy/results.py`
|
|
62
|
+
- `src/excelalchemy/exceptions.py`
|
|
63
|
+
- `src/excelalchemy/codecs/`
|
|
64
|
+
- `src/excelalchemy/artifacts.py`
|
|
65
|
+
|
|
66
|
+
### Internal implementation
|
|
67
|
+
|
|
68
|
+
These modules implement behavior but are not the recommended import paths for application code:
|
|
69
|
+
|
|
70
|
+
- `src/excelalchemy/core/`
|
|
71
|
+
- `src/excelalchemy/helper/`
|
|
72
|
+
- `src/excelalchemy/i18n/`
|
|
73
|
+
- `src/excelalchemy/_primitives/`
|
|
74
|
+
|
|
75
|
+
### Compatibility-only surface
|
|
76
|
+
|
|
77
|
+
These exist to support the 2.x line and should not be treated as preferred implementation entry points for new work:
|
|
78
|
+
|
|
79
|
+
- `src/excelalchemy/types/`
|
|
80
|
+
- `src/excelalchemy/exc.py`
|
|
81
|
+
- `src/excelalchemy/identity.py`
|
|
82
|
+
- `src/excelalchemy/header_models.py`
|
|
83
|
+
- `src/excelalchemy/const.py`
|
|
84
|
+
- `src/excelalchemy/util/convertor.py`
|
|
85
|
+
|
|
86
|
+
## Major Modules and Responsibilities
|
|
87
|
+
|
|
88
|
+
### Public-facing root modules
|
|
89
|
+
|
|
90
|
+
- `src/excelalchemy/__init__.py`
|
|
91
|
+
- Re-exports `ExcelAlchemy`, configs, codecs, result types, exception types, and common identity/value types.
|
|
92
|
+
- Changes here affect top-level user imports directly.
|
|
93
|
+
|
|
94
|
+
- `src/excelalchemy/config.py`
|
|
95
|
+
- Defines:
|
|
96
|
+
- `ExcelMode`
|
|
97
|
+
- `ImportMode`
|
|
98
|
+
- `ImporterConfig`
|
|
99
|
+
- `ExporterConfig`
|
|
100
|
+
- normalized schema/behavior/storage option groupings
|
|
101
|
+
- Also contains legacy Minio compatibility handling and deprecation warnings.
|
|
102
|
+
|
|
103
|
+
- `src/excelalchemy/metadata.py`
|
|
104
|
+
- Defines public declaration helpers:
|
|
105
|
+
- `FieldMeta(...)`
|
|
106
|
+
- `ExcelMeta(...)`
|
|
107
|
+
- Also defines the internal metadata layers behind `FieldMetaInfo`:
|
|
108
|
+
- `DeclaredFieldMeta`
|
|
109
|
+
- `RuntimeFieldBinding`
|
|
110
|
+
- `WorkbookPresentationMeta`
|
|
111
|
+
- `ImportConstraints`
|
|
112
|
+
- This file is central when changing field declaration behavior, workbook comments, formatting hints, or constraint overlay rules.
|
|
113
|
+
|
|
114
|
+
- `src/excelalchemy/results.py`
|
|
115
|
+
- Defines public result objects:
|
|
116
|
+
- `ImportResult`
|
|
117
|
+
- `ValidateHeaderResult`
|
|
118
|
+
- `ValidateResult`
|
|
119
|
+
- `ValidateRowResult`
|
|
120
|
+
- `CellErrorMap`
|
|
121
|
+
- `RowIssueMap`
|
|
122
|
+
- This is the main file for API payload shape and structured error access.
|
|
123
|
+
|
|
124
|
+
- `src/excelalchemy/exceptions.py`
|
|
125
|
+
- Defines the public exception model:
|
|
126
|
+
- `ExcelAlchemyError`
|
|
127
|
+
- `ExcelCellError`
|
|
128
|
+
- `ExcelRowError`
|
|
129
|
+
- `ProgrammaticError`
|
|
130
|
+
- `ConfigError`
|
|
131
|
+
|
|
132
|
+
- `src/excelalchemy/artifacts.py`
|
|
133
|
+
- Defines `ExcelArtifact`, which wraps rendered workbook content as bytes, base64, or a data URL.
|
|
134
|
+
|
|
135
|
+
### `core/` internal orchestration
|
|
136
|
+
|
|
137
|
+
- `src/excelalchemy/core/alchemy.py`
|
|
138
|
+
- Main facade implementation.
|
|
139
|
+
- Builds layout and storage, exposes the top-level workflow methods, and surfaces inspection properties like `worksheet_table` and `cell_error_map`.
|
|
140
|
+
- This is the first internal file to inspect when changing how the facade behaves.
|
|
141
|
+
|
|
142
|
+
- `src/excelalchemy/core/import_session.py`
|
|
143
|
+
- Owns one import run’s runtime state.
|
|
144
|
+
- Tracks:
|
|
145
|
+
- workbook load state
|
|
146
|
+
- header table
|
|
147
|
+
- worksheet table
|
|
148
|
+
- issue maps
|
|
149
|
+
- execution counts
|
|
150
|
+
- result rendering state
|
|
151
|
+
- `ImportSessionSnapshot`
|
|
152
|
+
- This is the main import lifecycle owner.
|
|
153
|
+
|
|
154
|
+
- `src/excelalchemy/core/schema.py`
|
|
155
|
+
- Converts extracted field metadata into `ExcelSchemaLayout`.
|
|
156
|
+
- Responsible for:
|
|
157
|
+
- layout ordering
|
|
158
|
+
- unique label/key indexing
|
|
159
|
+
- composite field expansion
|
|
160
|
+
- merged-header detection for selected output keys
|
|
161
|
+
|
|
162
|
+
- `src/excelalchemy/core/headers.py`
|
|
163
|
+
- Header parsing and header validation.
|
|
164
|
+
- Responsible for:
|
|
165
|
+
- detecting simple vs merged headers
|
|
166
|
+
- normalizing parsed headers into `ExcelHeader` objects
|
|
167
|
+
- comparing workbook headers against schema layout
|
|
168
|
+
|
|
169
|
+
- `src/excelalchemy/core/rows.py`
|
|
170
|
+
- Row reconstruction and issue tracking.
|
|
171
|
+
- `RowAggregator` groups flattened worksheet data back into model-shaped payloads.
|
|
172
|
+
- `ImportIssueTracker` maps row/cell failures back to workbook coordinates and prepends result columns.
|
|
173
|
+
|
|
174
|
+
- `src/excelalchemy/core/executor.py`
|
|
175
|
+
- Dispatches the actual import execution path.
|
|
176
|
+
- Responsible for:
|
|
177
|
+
- choosing create/update/create-or-update behavior
|
|
178
|
+
- validating reconstructed payloads
|
|
179
|
+
- invoking configured callbacks
|
|
180
|
+
- mapping failures into row/cell issues
|
|
181
|
+
|
|
182
|
+
- `src/excelalchemy/core/rendering.py`
|
|
183
|
+
- High-level rendering entry points for templates, exports, and import result workbooks.
|
|
184
|
+
|
|
185
|
+
- `src/excelalchemy/core/writer.py`
|
|
186
|
+
- Lower-level workbook writing details:
|
|
187
|
+
- comments
|
|
188
|
+
- fills/colors
|
|
189
|
+
- workbook rows/cells
|
|
190
|
+
- result/reason columns
|
|
191
|
+
|
|
192
|
+
- `src/excelalchemy/core/storage_protocol.py`
|
|
193
|
+
- Defines the `ExcelStorage` protocol.
|
|
194
|
+
- This is the main storage extension boundary.
|
|
195
|
+
|
|
196
|
+
- `src/excelalchemy/core/storage.py`
|
|
197
|
+
- Resolves configured storage into a concrete gateway.
|
|
198
|
+
- Also defines the missing-storage fallback path.
|
|
199
|
+
|
|
200
|
+
- `src/excelalchemy/core/storage_minio.py`
|
|
201
|
+
- Built-in Minio-backed storage implementation.
|
|
202
|
+
|
|
203
|
+
- `src/excelalchemy/core/table.py`
|
|
204
|
+
- Defines `WorksheetTable`, `WorksheetRow`, and related helpers.
|
|
205
|
+
- This is the internal table abstraction used instead of pandas.
|
|
206
|
+
|
|
207
|
+
### `codecs/` field behavior
|
|
208
|
+
|
|
209
|
+
- `src/excelalchemy/codecs/base.py`
|
|
210
|
+
- Defines:
|
|
211
|
+
- `ExcelFieldCodec`
|
|
212
|
+
- `CompositeExcelFieldCodec`
|
|
213
|
+
- fallback logging helpers
|
|
214
|
+
- Start here when changing the codec contract itself.
|
|
215
|
+
|
|
216
|
+
- `src/excelalchemy/codecs/*.py`
|
|
217
|
+
- Built-in concrete field codecs such as:
|
|
218
|
+
- `string.py`
|
|
219
|
+
- `number.py`
|
|
220
|
+
- `date.py`
|
|
221
|
+
- `date_range.py`
|
|
222
|
+
- `email.py`
|
|
223
|
+
- `phone_number.py`
|
|
224
|
+
- `money.py`
|
|
225
|
+
- `radio.py`
|
|
226
|
+
- `multi_checkbox.py`
|
|
227
|
+
- `organization.py`
|
|
228
|
+
- `staff.py`
|
|
229
|
+
- `tree.py`
|
|
230
|
+
- `url.py`
|
|
231
|
+
|
|
232
|
+
### Adapter, i18n, and primitive helpers
|
|
233
|
+
|
|
234
|
+
- `src/excelalchemy/helper/pydantic.py`
|
|
235
|
+
- Isolates the Pydantic boundary.
|
|
236
|
+
- Responsible for:
|
|
237
|
+
- extracting model metadata
|
|
238
|
+
- resolving codec types
|
|
239
|
+
- normalizing validation messages
|
|
240
|
+
- mapping Pydantic validation output to `ExcelCellError` and `ExcelRowError`
|
|
241
|
+
|
|
242
|
+
- `src/excelalchemy/i18n/messages.py`
|
|
243
|
+
- Central message lookup and locale handling.
|
|
244
|
+
- Important when changing workbook-facing text, runtime error text, or locale policy.
|
|
245
|
+
|
|
246
|
+
- `src/excelalchemy/_primitives/constants.py`
|
|
247
|
+
- Internal constants and enum-like definitions used across the package.
|
|
248
|
+
|
|
249
|
+
- `src/excelalchemy/_primitives/identity.py`
|
|
250
|
+
- Internal typed wrappers for labels, keys, row indexes, column indexes, URLs, and related string-like identifiers.
|
|
251
|
+
|
|
252
|
+
- `src/excelalchemy/_primitives/payloads.py`
|
|
253
|
+
- Shared payload type aliases for import/export/data-converter/callback paths.
|
|
254
|
+
|
|
255
|
+
- `src/excelalchemy/_primitives/diagnostics.py`
|
|
256
|
+
- Developer-facing diagnostic logging helpers.
|
|
257
|
+
|
|
258
|
+
- `src/excelalchemy/_primitives/deprecation.py`
|
|
259
|
+
- Deprecation warning helpers used by compatibility modules.
|
|
260
|
+
|
|
261
|
+
- `src/excelalchemy/_primitives/header_models.py`
|
|
262
|
+
- Internal parsed-header model objects.
|
|
263
|
+
|
|
264
|
+
## Major Internal Flows
|
|
265
|
+
|
|
266
|
+
### Import validation flow
|
|
267
|
+
|
|
268
|
+
The import path is implemented roughly in this order:
|
|
269
|
+
|
|
270
|
+
1. `src/excelalchemy/core/alchemy.py`
|
|
271
|
+
- `ExcelAlchemy.import_data(...)` creates a new import session.
|
|
272
|
+
2. `src/excelalchemy/core/import_session.py`
|
|
273
|
+
- loads workbook data through storage
|
|
274
|
+
- builds header and worksheet state
|
|
275
|
+
3. `src/excelalchemy/core/headers.py`
|
|
276
|
+
- parses headers
|
|
277
|
+
- validates headers against the schema layout
|
|
278
|
+
4. `src/excelalchemy/core/rows.py`
|
|
279
|
+
- reconstructs model-shaped row payloads
|
|
280
|
+
5. `src/excelalchemy/core/executor.py`
|
|
281
|
+
- validates and dispatches create/update/upsert logic
|
|
282
|
+
6. `src/excelalchemy/helper/pydantic.py`
|
|
283
|
+
- adapts Pydantic validation into ExcelAlchemy issues
|
|
284
|
+
7. `src/excelalchemy/core/rows.py`
|
|
285
|
+
- records row/cell failures in workbook coordinates
|
|
286
|
+
8. `src/excelalchemy/core/rendering.py` and `src/excelalchemy/core/writer.py`
|
|
287
|
+
- render the import result workbook when rows fail
|
|
288
|
+
9. `src/excelalchemy/results.py`
|
|
289
|
+
- exposes the final result through `ImportResult`, `CellErrorMap`, and `RowIssueMap`
|
|
290
|
+
|
|
291
|
+
### Template generation flow
|
|
292
|
+
|
|
293
|
+
The template path is implemented roughly in this order:
|
|
294
|
+
|
|
295
|
+
1. `src/excelalchemy/core/alchemy.py`
|
|
296
|
+
- selects output keys and header shape
|
|
297
|
+
2. `src/excelalchemy/core/schema.py`
|
|
298
|
+
- provides ordered layout and merged-header decisions
|
|
299
|
+
3. `src/excelalchemy/codecs/`
|
|
300
|
+
- provide comments, display formatting, and field-specific workbook semantics
|
|
301
|
+
4. `src/excelalchemy/core/rendering.py`
|
|
302
|
+
5. `src/excelalchemy/core/writer.py`
|
|
303
|
+
- produce the workbook output
|
|
304
|
+
6. `src/excelalchemy/artifacts.py`
|
|
305
|
+
- wraps the output when the artifact API is used
|
|
306
|
+
|
|
307
|
+
### Export flow
|
|
308
|
+
|
|
309
|
+
The export path is implemented roughly in this order:
|
|
310
|
+
|
|
311
|
+
1. `src/excelalchemy/core/alchemy.py`
|
|
312
|
+
- accepts export rows and selected keys
|
|
313
|
+
2. `src/excelalchemy/core/schema.py`
|
|
314
|
+
- resolves output layout and merged-header needs
|
|
315
|
+
3. `src/excelalchemy/codecs/`
|
|
316
|
+
- format workbook-facing values
|
|
317
|
+
4. `src/excelalchemy/core/rendering.py`
|
|
318
|
+
5. `src/excelalchemy/core/writer.py`
|
|
319
|
+
6. `src/excelalchemy/core/storage_protocol.py` and `src/excelalchemy/core/storage.py`
|
|
320
|
+
- are used only when the upload path is chosen
|
|
321
|
+
|
|
322
|
+
### Storage integration flow
|
|
323
|
+
|
|
324
|
+
Storage-related behavior is split into three concerns:
|
|
325
|
+
|
|
326
|
+
- contract:
|
|
327
|
+
- `src/excelalchemy/core/storage_protocol.py`
|
|
328
|
+
- resolution:
|
|
329
|
+
- `src/excelalchemy/core/storage.py`
|
|
330
|
+
- built-in Minio backend:
|
|
331
|
+
- `src/excelalchemy/core/storage_minio.py`
|
|
332
|
+
|
|
333
|
+
The recommended 2.x design is:
|
|
334
|
+
|
|
335
|
+
- config holds `storage=...`
|
|
336
|
+
- `build_storage_gateway(...)` resolves it
|
|
337
|
+
- import reads workbook data as `WorksheetTable`
|
|
338
|
+
- export/import-result uploads return a URL through the storage implementation
|
|
339
|
+
- custom storage readers currently use `src/excelalchemy/core/table.py` for that `WorksheetTable` contract
|
|
340
|
+
|
|
341
|
+
## Where To Look When Changing Specific Behavior
|
|
342
|
+
|
|
343
|
+
### Changing public API behavior
|
|
344
|
+
|
|
345
|
+
Start here:
|
|
346
|
+
|
|
347
|
+
- `src/excelalchemy/__init__.py`
|
|
348
|
+
- `src/excelalchemy/config.py`
|
|
349
|
+
- `src/excelalchemy/metadata.py`
|
|
350
|
+
- `src/excelalchemy/results.py`
|
|
351
|
+
- `src/excelalchemy/exceptions.py`
|
|
352
|
+
- `docs/public-api.md`
|
|
353
|
+
- `MIGRATIONS.md`
|
|
354
|
+
- `tests/contracts/`
|
|
355
|
+
|
|
356
|
+
Use extra caution when changing:
|
|
357
|
+
|
|
358
|
+
- exported names
|
|
359
|
+
- config constructor behavior
|
|
360
|
+
- result payload shape
|
|
361
|
+
- exception wording or exception type mapping
|
|
362
|
+
- compatibility aliases
|
|
363
|
+
|
|
364
|
+
### Changing import validation behavior
|
|
365
|
+
|
|
366
|
+
Start here:
|
|
367
|
+
|
|
368
|
+
- `src/excelalchemy/core/import_session.py`
|
|
369
|
+
- `src/excelalchemy/core/headers.py`
|
|
370
|
+
- `src/excelalchemy/core/rows.py`
|
|
371
|
+
- `src/excelalchemy/core/executor.py`
|
|
372
|
+
- `src/excelalchemy/helper/pydantic.py`
|
|
373
|
+
- `src/excelalchemy/results.py`
|
|
374
|
+
- `tests/contracts/test_import_contract.py`
|
|
375
|
+
- `tests/contracts/test_core_components_contract.py`
|
|
376
|
+
- `tests/contracts/test_pydantic_contract.py`
|
|
377
|
+
|
|
378
|
+
Typical examples:
|
|
379
|
+
|
|
380
|
+
- header validation rules
|
|
381
|
+
- row reconstruction
|
|
382
|
+
- Pydantic error mapping
|
|
383
|
+
- create/update/upsert behavior
|
|
384
|
+
- result-workbook error placement
|
|
385
|
+
|
|
386
|
+
### Changing export or template generation behavior
|
|
387
|
+
|
|
388
|
+
Start here:
|
|
389
|
+
|
|
390
|
+
- `src/excelalchemy/core/alchemy.py`
|
|
391
|
+
- `src/excelalchemy/core/schema.py`
|
|
392
|
+
- `src/excelalchemy/core/rendering.py`
|
|
393
|
+
- `src/excelalchemy/core/writer.py`
|
|
394
|
+
- `src/excelalchemy/codecs/`
|
|
395
|
+
- `tests/contracts/test_template_contract.py`
|
|
396
|
+
- `tests/contracts/test_export_contract.py`
|
|
397
|
+
|
|
398
|
+
Typical examples:
|
|
399
|
+
|
|
400
|
+
- workbook comments
|
|
401
|
+
- merged headers
|
|
402
|
+
- selected output keys
|
|
403
|
+
- workbook-facing display formatting
|
|
404
|
+
- artifact generation
|
|
405
|
+
|
|
406
|
+
### Changing storage integration behavior
|
|
407
|
+
|
|
408
|
+
Start here:
|
|
409
|
+
|
|
410
|
+
- `src/excelalchemy/core/storage_protocol.py`
|
|
411
|
+
- `src/excelalchemy/core/storage.py`
|
|
412
|
+
- `src/excelalchemy/core/storage_minio.py`
|
|
413
|
+
- `src/excelalchemy/config.py`
|
|
414
|
+
- `examples/custom_storage.py`
|
|
415
|
+
- `tests/contracts/test_storage_contract.py`
|
|
416
|
+
- `tests/unit/test_config_options.py`
|
|
417
|
+
|
|
418
|
+
Typical examples:
|
|
419
|
+
|
|
420
|
+
- storage contract shape
|
|
421
|
+
- default gateway selection
|
|
422
|
+
- missing-storage behavior
|
|
423
|
+
- Minio compatibility behavior
|
|
424
|
+
- upload payload expectations
|
|
425
|
+
|
|
426
|
+
### Changing locale-aware output behavior
|
|
427
|
+
|
|
428
|
+
Start here:
|
|
429
|
+
|
|
430
|
+
- `src/excelalchemy/i18n/messages.py`
|
|
431
|
+
- `src/excelalchemy/metadata.py`
|
|
432
|
+
- `src/excelalchemy/core/alchemy.py`
|
|
433
|
+
- `src/excelalchemy/core/writer.py`
|
|
434
|
+
- `docs/locale.md`
|
|
435
|
+
- `tests/contracts/test_template_contract.py`
|
|
436
|
+
- `tests/contracts/test_import_contract.py`
|
|
437
|
+
|
|
438
|
+
Typical examples:
|
|
439
|
+
|
|
440
|
+
- workbook instruction text
|
|
441
|
+
- header comments
|
|
442
|
+
- result/reason column labels
|
|
443
|
+
- row status text
|
|
444
|
+
- fallback locale behavior
|
|
445
|
+
|
|
446
|
+
## Implementation Cautions
|
|
447
|
+
|
|
448
|
+
- Do not treat compatibility modules under `src/excelalchemy/types/` and the root compatibility shims as preferred edit points for new behavior.
|
|
449
|
+
- Do not reintroduce pandas-style assumptions into the runtime path; this package now uses `WorksheetTable`.
|
|
450
|
+
- Do not hard-wire Minio into core workflow logic; storage is intentionally abstracted behind `ExcelStorage`.
|
|
451
|
+
- Treat `src/excelalchemy/core/table.py` as a narrow extension seam for current 2.x storage integrations, not as a general application import surface.
|
|
452
|
+
- If you change result payload shape, inspect:
|
|
453
|
+
- `src/excelalchemy/results.py`
|
|
454
|
+
- `docs/result-objects.md`
|
|
455
|
+
- `docs/api-response-cookbook.md`
|
|
456
|
+
- `scripts/smoke_api_payload_snapshot.py`
|
|
457
|
+
- `files/example-outputs/import-failure-api-payload.json`
|
|
458
|
+
- If you change docs-visible example behavior, inspect:
|
|
459
|
+
- `examples/`
|
|
460
|
+
- `files/example-outputs/`
|
|
461
|
+
- `scripts/generate_example_output_assets.py`
|
|
462
|
+
- `scripts/smoke_examples.py`
|
|
463
|
+
- `scripts/smoke_docs_assets.py`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""A Python Library for Reading and Writing Excel Files"""
|
|
2
2
|
|
|
3
|
-
__version__ = '2.
|
|
3
|
+
__version__ = '2.3.0'
|
|
4
4
|
from excelalchemy._primitives.constants import CharacterSet, DataRangeOption, DateFormat, Option
|
|
5
5
|
from excelalchemy._primitives.deprecation import ExcelAlchemyDeprecationWarning
|
|
6
6
|
from excelalchemy._primitives.identity import (
|
|
@@ -45,7 +45,13 @@ from excelalchemy.codecs.url import Url, UrlCodec
|
|
|
45
45
|
from excelalchemy.config import ExporterConfig, ImporterConfig, ImportMode
|
|
46
46
|
from excelalchemy.core.alchemy import ExcelAlchemy
|
|
47
47
|
from excelalchemy.core.storage_protocol import ExcelStorage
|
|
48
|
-
from excelalchemy.exceptions import
|
|
48
|
+
from excelalchemy.exceptions import (
|
|
49
|
+
ConfigError,
|
|
50
|
+
ExcelCellError,
|
|
51
|
+
ExcelRowError,
|
|
52
|
+
ProgrammaticError,
|
|
53
|
+
WorksheetNotFoundError,
|
|
54
|
+
)
|
|
49
55
|
from excelalchemy.helper.pydantic import extract_pydantic_model
|
|
50
56
|
from excelalchemy.metadata import ExcelMeta, FieldMeta, PatchFieldMeta
|
|
51
57
|
from excelalchemy.results import (
|
|
@@ -53,6 +59,8 @@ from excelalchemy.results import (
|
|
|
53
59
|
CellIssueRecord,
|
|
54
60
|
CodeIssueSummary,
|
|
55
61
|
FieldIssueSummary,
|
|
62
|
+
ImportPreflightResult,
|
|
63
|
+
ImportPreflightStatus,
|
|
56
64
|
ImportResult,
|
|
57
65
|
RowIssueMap,
|
|
58
66
|
RowIssueRecord,
|
|
@@ -94,6 +102,8 @@ __all__ = [
|
|
|
94
102
|
'FieldIssueSummary',
|
|
95
103
|
'FieldMeta',
|
|
96
104
|
'ImportMode',
|
|
105
|
+
'ImportPreflightResult',
|
|
106
|
+
'ImportPreflightStatus',
|
|
97
107
|
'ImportResult',
|
|
98
108
|
'ImporterConfig',
|
|
99
109
|
'Key',
|
|
@@ -140,6 +150,7 @@ __all__ = [
|
|
|
140
150
|
'ValidateHeaderResult',
|
|
141
151
|
'ValidateResult',
|
|
142
152
|
'ValidateRowResult',
|
|
153
|
+
'WorksheetNotFoundError',
|
|
143
154
|
'extract_pydantic_model',
|
|
144
155
|
'flatten',
|
|
145
156
|
]
|
|
@@ -62,6 +62,7 @@ class DateRange(CompositeExcelFieldCodec):
|
|
|
62
62
|
declared.comment_required,
|
|
63
63
|
presentation.comment_date_format,
|
|
64
64
|
dmsg(MessageKey.COMMENT_DATE_RANGE_START_NOT_AFTER_END, extra_hint=presentation.hint or ''),
|
|
65
|
+
*([presentation.comment_example] if presentation.comment_example else []),
|
|
65
66
|
]
|
|
66
67
|
)
|
|
67
68
|
|
|
@@ -60,6 +60,7 @@ class MultiCheckbox(ExcelFieldCodec, list[str]):
|
|
|
60
60
|
presentation.comment_options,
|
|
61
61
|
dmsg(MessageKey.COMMENT_SELECTION_MODE, value=dmsg(MessageKey.COMMENT_SELECTION_VALUE_MULTI)),
|
|
62
62
|
presentation.comment_hint,
|
|
63
|
+
*([presentation.comment_example] if presentation.comment_example else []),
|
|
63
64
|
]
|
|
64
65
|
)
|
|
65
66
|
|
|
@@ -56,6 +56,7 @@ class Number(Decimal, ExcelFieldCodec):
|
|
|
56
56
|
presentation.comment_fraction_digits,
|
|
57
57
|
dmsg(MessageKey.COMMENT_NUMBER_INPUT_RANGE, value=cls.__get_range_description__(field_meta)),
|
|
58
58
|
presentation.comment_unit,
|
|
59
|
+
*([presentation.comment_example] if presentation.comment_example else []),
|
|
59
60
|
]
|
|
60
61
|
)
|
|
61
62
|
|
|
@@ -28,7 +28,11 @@ class SingleOrganization(Radio):
|
|
|
28
28
|
else MessageKey.COMMENT_REQUIRED_VALUE_OPTIONAL
|
|
29
29
|
)
|
|
30
30
|
return '\n'.join(
|
|
31
|
-
[
|
|
31
|
+
[
|
|
32
|
+
dmsg(MessageKey.COMMENT_REQUIRED, value=dmsg(value_key)),
|
|
33
|
+
dmsg(MessageKey.COMMENT_HINT, value=extra_hint),
|
|
34
|
+
*([presentation.comment_example] if presentation.comment_example else []),
|
|
35
|
+
]
|
|
32
36
|
)
|
|
33
37
|
|
|
34
38
|
@classmethod
|
|
@@ -64,6 +68,7 @@ class MultiOrganization(MultiCheckbox):
|
|
|
64
68
|
[
|
|
65
69
|
declared.comment_required,
|
|
66
70
|
dmsg(MessageKey.COMMENT_HINT, value=presentation.hint or dmsg(MessageKey.MULTI_ORGANIZATION_HINT)),
|
|
71
|
+
*([presentation.comment_example] if presentation.comment_example else []),
|
|
67
72
|
]
|
|
68
73
|
)
|
|
69
74
|
|
|
@@ -61,6 +61,7 @@ class Radio(ExcelFieldCodec, str):
|
|
|
61
61
|
presentation.comment_options,
|
|
62
62
|
dmsg(MessageKey.COMMENT_SELECTION_MODE, value=dmsg(MessageKey.COMMENT_SELECTION_VALUE_SINGLE)),
|
|
63
63
|
presentation.comment_hint,
|
|
64
|
+
*([presentation.comment_example] if presentation.comment_example else []),
|
|
64
65
|
]
|
|
65
66
|
)
|
|
66
67
|
|