ExcelAlchemy 2.3.0__tar.gz → 3.0.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.
Files changed (125) hide show
  1. excelalchemy-3.0.0/PKG-INFO +166 -0
  2. excelalchemy-3.0.0/README-pypi.md +126 -0
  3. {excelalchemy-2.3.0 → excelalchemy-3.0.0}/pyproject.toml +48 -39
  4. excelalchemy-3.0.0/src/excelalchemy/README.md +59 -0
  5. excelalchemy-3.0.0/src/excelalchemy/__init__.py +99 -0
  6. excelalchemy-3.0.0/src/excelalchemy/adapters/__init__.py +19 -0
  7. {excelalchemy-2.3.0/src/excelalchemy/helper → excelalchemy-3.0.0/src/excelalchemy/adapters}/pydantic.py +226 -63
  8. excelalchemy-3.0.0/src/excelalchemy/adapters/pydantic_fields.py +70 -0
  9. {excelalchemy-2.3.0 → excelalchemy-3.0.0}/src/excelalchemy/artifacts.py +1 -1
  10. excelalchemy-3.0.0/src/excelalchemy/codecs/__init__.py +29 -0
  11. {excelalchemy-2.3.0 → excelalchemy-3.0.0}/src/excelalchemy/codecs/boolean.py +13 -12
  12. excelalchemy-3.0.0/src/excelalchemy/codecs/choice.py +277 -0
  13. {excelalchemy-2.3.0 → excelalchemy-3.0.0}/src/excelalchemy/codecs/date.py +92 -17
  14. {excelalchemy-2.3.0 → excelalchemy-3.0.0}/src/excelalchemy/codecs/date_range.py +96 -33
  15. {excelalchemy-2.3.0 → excelalchemy-3.0.0}/src/excelalchemy/codecs/email.py +14 -9
  16. excelalchemy-2.3.0/src/excelalchemy/codecs/base.py → excelalchemy-3.0.0/src/excelalchemy/codecs/field_codec.py +27 -43
  17. {excelalchemy-2.3.0 → excelalchemy-3.0.0}/src/excelalchemy/codecs/number.py +26 -16
  18. {excelalchemy-2.3.0 → excelalchemy-3.0.0}/src/excelalchemy/codecs/number_range.py +54 -35
  19. excelalchemy-3.0.0/src/excelalchemy/codecs/phone_number.py +31 -0
  20. excelalchemy-2.3.0/src/excelalchemy/codecs/string.py → excelalchemy-3.0.0/src/excelalchemy/codecs/text.py +34 -12
  21. excelalchemy-3.0.0/src/excelalchemy/codecs/url.py +37 -0
  22. excelalchemy-3.0.0/src/excelalchemy/columns.py +156 -0
  23. excelalchemy-3.0.0/src/excelalchemy/config/__init__.py +29 -0
  24. excelalchemy-3.0.0/src/excelalchemy/config/exporter.py +86 -0
  25. excelalchemy-3.0.0/src/excelalchemy/config/importer.py +198 -0
  26. excelalchemy-3.0.0/src/excelalchemy/config/modes.py +19 -0
  27. excelalchemy-3.0.0/src/excelalchemy/config/options.py +71 -0
  28. {excelalchemy-2.3.0/src/excelalchemy/_primitives → excelalchemy-3.0.0/src/excelalchemy}/diagnostics.py +1 -1
  29. excelalchemy-2.3.0/src/excelalchemy/exceptions.py → excelalchemy-3.0.0/src/excelalchemy/errors.py +15 -10
  30. excelalchemy-3.0.0/src/excelalchemy/field_metadata/__init__.py +15 -0
  31. excelalchemy-3.0.0/src/excelalchemy/field_metadata/constraints.py +31 -0
  32. excelalchemy-3.0.0/src/excelalchemy/field_metadata/declaration.py +44 -0
  33. excelalchemy-3.0.0/src/excelalchemy/field_metadata/field.py +515 -0
  34. excelalchemy-3.0.0/src/excelalchemy/field_metadata/presentation.py +153 -0
  35. excelalchemy-3.0.0/src/excelalchemy/field_metadata/runtime.py +47 -0
  36. {excelalchemy-2.3.0/src/excelalchemy/i18n → excelalchemy-3.0.0/src/excelalchemy}/messages.py +194 -13
  37. excelalchemy-3.0.0/src/excelalchemy/policies.py +143 -0
  38. excelalchemy-3.0.0/src/excelalchemy/primitives/__init__.py +1 -0
  39. {excelalchemy-2.3.0/src/excelalchemy/_primitives → excelalchemy-3.0.0/src/excelalchemy/primitives}/constants.py +7 -6
  40. {excelalchemy-2.3.0/src/excelalchemy/_primitives → excelalchemy-3.0.0/src/excelalchemy/primitives}/identity.py +0 -4
  41. excelalchemy-3.0.0/src/excelalchemy/rendering/__init__.py +11 -0
  42. excelalchemy-2.3.0/src/excelalchemy/core/rendering.py → excelalchemy-3.0.0/src/excelalchemy/rendering/renderer.py +5 -5
  43. {excelalchemy-2.3.0/src/excelalchemy/core → excelalchemy-3.0.0/src/excelalchemy/rendering}/writer.py +208 -133
  44. excelalchemy-3.0.0/src/excelalchemy/results/__init__.py +51 -0
  45. excelalchemy-3.0.0/src/excelalchemy/results/import_result.py +88 -0
  46. excelalchemy-3.0.0/src/excelalchemy/results/issue_maps.py +456 -0
  47. excelalchemy-3.0.0/src/excelalchemy/results/lifecycle.py +106 -0
  48. excelalchemy-3.0.0/src/excelalchemy/results/preflight.py +129 -0
  49. excelalchemy-3.0.0/src/excelalchemy/results/remediation.py +353 -0
  50. excelalchemy-3.0.0/src/excelalchemy/runtime/__init__.py +22 -0
  51. {excelalchemy-2.3.0/src/excelalchemy/core → excelalchemy-3.0.0/src/excelalchemy/runtime}/executor.py +8 -9
  52. excelalchemy-2.3.0/src/excelalchemy/core/alchemy.py → excelalchemy-3.0.0/src/excelalchemy/runtime/facade.py +39 -60
  53. excelalchemy-2.3.0/src/excelalchemy/core/abstract.py → excelalchemy-3.0.0/src/excelalchemy/runtime/facade_protocol.py +4 -4
  54. {excelalchemy-2.3.0/src/excelalchemy/core → excelalchemy-3.0.0/src/excelalchemy/runtime}/import_session.py +70 -102
  55. {excelalchemy-2.3.0/src/excelalchemy/core → excelalchemy-3.0.0/src/excelalchemy/runtime}/preflight.py +7 -7
  56. {excelalchemy-2.3.0/src/excelalchemy/core → excelalchemy-3.0.0/src/excelalchemy/runtime}/rows.py +13 -10
  57. excelalchemy-3.0.0/src/excelalchemy/schema/__init__.py +5 -0
  58. excelalchemy-2.3.0/src/excelalchemy/core/schema.py → excelalchemy-3.0.0/src/excelalchemy/schema/layout.py +7 -7
  59. excelalchemy-3.0.0/src/excelalchemy/storage/__init__.py +5 -0
  60. excelalchemy-2.3.0/src/excelalchemy/core/storage_protocol.py → excelalchemy-3.0.0/src/excelalchemy/storage/base.py +6 -3
  61. excelalchemy-3.0.0/src/excelalchemy/storage/gateway.py +39 -0
  62. excelalchemy-2.3.0/src/excelalchemy/core/storage_minio.py → excelalchemy-3.0.0/src/excelalchemy/storage/minio.py +42 -42
  63. {excelalchemy-2.3.0 → excelalchemy-3.0.0}/src/excelalchemy/util/converter.py +3 -3
  64. {excelalchemy-2.3.0 → excelalchemy-3.0.0}/src/excelalchemy/util/file.py +4 -4
  65. excelalchemy-3.0.0/src/excelalchemy/worksheet/__init__.py +17 -0
  66. excelalchemy-3.0.0/src/excelalchemy/worksheet/header.py +27 -0
  67. excelalchemy-3.0.0/src/excelalchemy/worksheet/header_parser.py +81 -0
  68. excelalchemy-3.0.0/src/excelalchemy/worksheet/header_validator.py +76 -0
  69. excelalchemy-2.3.0/PKG-INFO +0 -211
  70. excelalchemy-2.3.0/README-pypi.md +0 -171
  71. excelalchemy-2.3.0/src/excelalchemy/README.md +0 -463
  72. excelalchemy-2.3.0/src/excelalchemy/__init__.py +0 -156
  73. excelalchemy-2.3.0/src/excelalchemy/_primitives/__init__.py +0 -1
  74. excelalchemy-2.3.0/src/excelalchemy/_primitives/deprecation.py +0 -22
  75. excelalchemy-2.3.0/src/excelalchemy/_primitives/header_models.py +0 -27
  76. excelalchemy-2.3.0/src/excelalchemy/codecs/__init__.py +0 -14
  77. excelalchemy-2.3.0/src/excelalchemy/codecs/money.py +0 -42
  78. excelalchemy-2.3.0/src/excelalchemy/codecs/multi_checkbox.py +0 -126
  79. excelalchemy-2.3.0/src/excelalchemy/codecs/organization.py +0 -110
  80. excelalchemy-2.3.0/src/excelalchemy/codecs/phone_number.py +0 -27
  81. excelalchemy-2.3.0/src/excelalchemy/codecs/radio.py +0 -112
  82. excelalchemy-2.3.0/src/excelalchemy/codecs/staff.py +0 -112
  83. excelalchemy-2.3.0/src/excelalchemy/codecs/tree.py +0 -89
  84. excelalchemy-2.3.0/src/excelalchemy/codecs/url.py +0 -33
  85. excelalchemy-2.3.0/src/excelalchemy/config.py +0 -409
  86. excelalchemy-2.3.0/src/excelalchemy/const.py +0 -3
  87. excelalchemy-2.3.0/src/excelalchemy/core/headers.py +0 -148
  88. excelalchemy-2.3.0/src/excelalchemy/core/storage.py +0 -54
  89. excelalchemy-2.3.0/src/excelalchemy/exc.py +0 -7
  90. excelalchemy-2.3.0/src/excelalchemy/header_models.py +0 -10
  91. excelalchemy-2.3.0/src/excelalchemy/helper/__init__.py +0 -0
  92. excelalchemy-2.3.0/src/excelalchemy/i18n/__init__.py +0 -23
  93. excelalchemy-2.3.0/src/excelalchemy/identity.py +0 -7
  94. excelalchemy-2.3.0/src/excelalchemy/metadata.py +0 -1040
  95. excelalchemy-2.3.0/src/excelalchemy/results.py +0 -880
  96. excelalchemy-2.3.0/src/excelalchemy/types/__init__.py +0 -15
  97. excelalchemy-2.3.0/src/excelalchemy/types/abstract.py +0 -7
  98. excelalchemy-2.3.0/src/excelalchemy/types/alchemy.py +0 -7
  99. excelalchemy-2.3.0/src/excelalchemy/types/field.py +0 -7
  100. excelalchemy-2.3.0/src/excelalchemy/types/header.py +0 -10
  101. excelalchemy-2.3.0/src/excelalchemy/types/identity.py +0 -7
  102. excelalchemy-2.3.0/src/excelalchemy/types/result.py +0 -7
  103. excelalchemy-2.3.0/src/excelalchemy/types/value/__init__.py +0 -7
  104. excelalchemy-2.3.0/src/excelalchemy/types/value/boolean.py +0 -7
  105. excelalchemy-2.3.0/src/excelalchemy/types/value/date.py +0 -7
  106. excelalchemy-2.3.0/src/excelalchemy/types/value/date_range.py +0 -7
  107. excelalchemy-2.3.0/src/excelalchemy/types/value/email.py +0 -7
  108. excelalchemy-2.3.0/src/excelalchemy/types/value/money.py +0 -7
  109. excelalchemy-2.3.0/src/excelalchemy/types/value/multi_checkbox.py +0 -7
  110. excelalchemy-2.3.0/src/excelalchemy/types/value/number.py +0 -7
  111. excelalchemy-2.3.0/src/excelalchemy/types/value/number_range.py +0 -7
  112. excelalchemy-2.3.0/src/excelalchemy/types/value/organization.py +0 -7
  113. excelalchemy-2.3.0/src/excelalchemy/types/value/phone_number.py +0 -7
  114. excelalchemy-2.3.0/src/excelalchemy/types/value/radio.py +0 -7
  115. excelalchemy-2.3.0/src/excelalchemy/types/value/staff.py +0 -7
  116. excelalchemy-2.3.0/src/excelalchemy/types/value/string.py +0 -7
  117. excelalchemy-2.3.0/src/excelalchemy/types/value/tree.py +0 -7
  118. excelalchemy-2.3.0/src/excelalchemy/types/value/url.py +0 -7
  119. excelalchemy-2.3.0/src/excelalchemy/util/__init__.py +0 -0
  120. excelalchemy-2.3.0/src/excelalchemy/util/convertor.py +0 -8
  121. {excelalchemy-2.3.0 → excelalchemy-3.0.0}/LICENSE +0 -0
  122. {excelalchemy-2.3.0/src/excelalchemy/_primitives → excelalchemy-3.0.0/src/excelalchemy/primitives}/payloads.py +0 -0
  123. {excelalchemy-2.3.0 → excelalchemy-3.0.0}/src/excelalchemy/py.typed +0 -0
  124. {excelalchemy-2.3.0/src/excelalchemy/core → excelalchemy-3.0.0/src/excelalchemy/util}/__init__.py +0 -0
  125. {excelalchemy-2.3.0/src/excelalchemy/core → excelalchemy-3.0.0/src/excelalchemy/worksheet}/table.py +0 -0
@@ -0,0 +1,166 @@
1
+ Metadata-Version: 2.4
2
+ Name: ExcelAlchemy
3
+ Version: 3.0.0
4
+ Summary: Schema-driven Python library for typed Excel import/export workflows with Pydantic and locale-aware workbooks.
5
+ Keywords: excel,openpyxl,pydantic,minio,schema
6
+ Author: Ray
7
+ Requires-Python: >=3.12
8
+ Description-Content-Type: text/markdown
9
+ Classifier: Development Status :: 5 - Production/Stable
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Office/Business :: Financial :: Spreadsheet
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ License-File: LICENSE
22
+ Requires-Dist: pydantic[email] >=2.12, <3
23
+ Requires-Dist: openpyxl >=3.1.5, <4
24
+ Requires-Dist: pendulum >=3.2.0, <4
25
+ Requires-Dist: minio >=7.2.20, <8 ; extra == "development"
26
+ Requires-Dist: pre-commit ; extra == "development"
27
+ Requires-Dist: pyright==1.1.408 ; extra == "development"
28
+ Requires-Dist: pytest ; extra == "development"
29
+ Requires-Dist: coverage ; extra == "development"
30
+ Requires-Dist: pytest-cov ; extra == "development"
31
+ Requires-Dist: ruff ; extra == "development"
32
+ Requires-Dist: minio >=7.2.20, <8 ; extra == "minio"
33
+ Project-URL: Documentation, https://github.com/RayCarterLab/ExcelAlchemy#readme
34
+ Project-URL: Home, https://github.com/RayCarterLab/ExcelAlchemy
35
+ Project-URL: Issues, https://github.com/RayCarterLab/ExcelAlchemy/issues
36
+ Project-URL: Repository, https://github.com/RayCarterLab/ExcelAlchemy
37
+ Provides-Extra: development
38
+ Provides-Extra: minio
39
+
40
+ # ExcelAlchemy
41
+
42
+ Schema-driven Python library for typed Excel import/export workflows with
43
+ Pydantic and locale-aware workbooks.
44
+
45
+ ExcelAlchemy turns Pydantic models into workbook contracts:
46
+
47
+ - generate Excel templates from code
48
+ - validate uploaded workbooks
49
+ - map failures back to rows and cells
50
+ - return result workbooks and API-friendly error payloads
51
+ - keep workbook IO pluggable through `ExcelStorage`
52
+
53
+ The current stable release is ExcelAlchemy 3.0. It uses ordinary Python
54
+ annotations plus explicit `ExcelColumn(...)` metadata. Old 2.x field factories,
55
+ compatibility imports, legacy config fields, and facade aliases are not current
56
+ API.
57
+
58
+ [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](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/examples/README.md) · [Public API](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/public-api.md) · [Migration Notes](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/migrations.md)
59
+
60
+ ## Screenshots
61
+
62
+ ### Template
63
+
64
+ ![Excel template screenshot](https://raw.githubusercontent.com/RayCarterLab/ExcelAlchemy/main/docs/assets/images/portfolio-template-en.png)
65
+
66
+ ### Import Result
67
+
68
+ ![Excel import result screenshot](https://raw.githubusercontent.com/RayCarterLab/ExcelAlchemy/main/docs/assets/images/portfolio-import-result-en.png)
69
+
70
+ ## Install
71
+
72
+ ```bash
73
+ pip install ExcelAlchemy
74
+ ```
75
+
76
+ Optional Minio-compatible storage support:
77
+
78
+ ```bash
79
+ pip install "ExcelAlchemy[minio]"
80
+ ```
81
+
82
+ ## Quick Example
83
+
84
+ ```python
85
+ from typing import Annotated
86
+
87
+ from pydantic import BaseModel, Field
88
+
89
+ from excelalchemy import EmailCodec, ExcelAlchemy, ExcelColumn, ImporterConfig
90
+
91
+
92
+ class EmployeeImport(BaseModel):
93
+ name: Annotated[str, ExcelColumn(label='Name', order=1)]
94
+ email: Annotated[
95
+ str,
96
+ Field(min_length=8),
97
+ ExcelColumn(
98
+ label='Email',
99
+ codec=EmailCodec(),
100
+ order=2,
101
+ hint='Use your work email',
102
+ example_value='alice@company.com',
103
+ ),
104
+ ]
105
+
106
+
107
+ alchemy = ExcelAlchemy(ImporterConfig(EmployeeImport, locale='en'))
108
+ template = alchemy.download_template_artifact(filename='employees-template.xlsx')
109
+
110
+ excel_bytes = template.as_bytes()
111
+ ```
112
+
113
+ ## Import Workflow
114
+
115
+ The shortest import path is:
116
+
117
+ ```text
118
+ template -> preflight -> import -> remediation -> delivery
119
+ ```
120
+
121
+ Minimal backend sketch:
122
+
123
+ ```python
124
+ from excelalchemy.results import ImportLifecycleEvent, build_frontend_remediation_payload
125
+
126
+
127
+ events: list[ImportLifecycleEvent] = []
128
+
129
+ preflight = alchemy.preflight_import('employees.xlsx')
130
+ if preflight.is_valid:
131
+ result = await alchemy.import_data(
132
+ 'employees.xlsx',
133
+ 'employees-result.xlsx',
134
+ on_event=events.append,
135
+ )
136
+ payload = {
137
+ 'result': result.to_api_payload(),
138
+ 'cell_errors': alchemy.cell_error_map.to_api_payload(),
139
+ 'row_errors': alchemy.row_error_map.to_api_payload(),
140
+ 'remediation': build_frontend_remediation_payload(
141
+ result=result,
142
+ cell_error_map=alchemy.cell_error_map,
143
+ row_error_map=alchemy.row_error_map,
144
+ ),
145
+ }
146
+ ```
147
+
148
+ ## Why ExcelAlchemy
149
+
150
+ - Pydantic v2-based schema extraction and validation
151
+ - `Annotated[..., ExcelColumn(...)]` declaration style
152
+ - workbook comments and result workbooks in `zh-CN`, `en`, or `ja`
153
+ - pluggable storage instead of a hard-coded backend
154
+ - `openpyxl`-based runtime path without pandas
155
+ - contract tests, Ruff, and Pyright in the development workflow
156
+
157
+ ## Learn More
158
+
159
+ - [Full project README](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/README.md)
160
+ - [Getting started](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/getting-started.md)
161
+ - [Examples showcase](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/examples-showcase.md)
162
+ - [Result objects](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/result-objects.md)
163
+ - [API response cookbook](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/api-response-cookbook.md)
164
+ - [Platform architecture](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/platform-architecture.md)
165
+ - [Migration notes](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/migrations.md)
166
+
@@ -0,0 +1,126 @@
1
+ # ExcelAlchemy
2
+
3
+ Schema-driven Python library for typed Excel import/export workflows with
4
+ Pydantic and locale-aware workbooks.
5
+
6
+ ExcelAlchemy turns Pydantic models into workbook contracts:
7
+
8
+ - generate Excel templates from code
9
+ - validate uploaded workbooks
10
+ - map failures back to rows and cells
11
+ - return result workbooks and API-friendly error payloads
12
+ - keep workbook IO pluggable through `ExcelStorage`
13
+
14
+ The current stable release is ExcelAlchemy 3.0. It uses ordinary Python
15
+ annotations plus explicit `ExcelColumn(...)` metadata. Old 2.x field factories,
16
+ compatibility imports, legacy config fields, and facade aliases are not current
17
+ API.
18
+
19
+ [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](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/examples/README.md) · [Public API](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/public-api.md) · [Migration Notes](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/migrations.md)
20
+
21
+ ## Screenshots
22
+
23
+ ### Template
24
+
25
+ ![Excel template screenshot](https://raw.githubusercontent.com/RayCarterLab/ExcelAlchemy/main/docs/assets/images/portfolio-template-en.png)
26
+
27
+ ### Import Result
28
+
29
+ ![Excel import result screenshot](https://raw.githubusercontent.com/RayCarterLab/ExcelAlchemy/main/docs/assets/images/portfolio-import-result-en.png)
30
+
31
+ ## Install
32
+
33
+ ```bash
34
+ pip install ExcelAlchemy
35
+ ```
36
+
37
+ Optional Minio-compatible storage support:
38
+
39
+ ```bash
40
+ pip install "ExcelAlchemy[minio]"
41
+ ```
42
+
43
+ ## Quick Example
44
+
45
+ ```python
46
+ from typing import Annotated
47
+
48
+ from pydantic import BaseModel, Field
49
+
50
+ from excelalchemy import EmailCodec, ExcelAlchemy, ExcelColumn, ImporterConfig
51
+
52
+
53
+ class EmployeeImport(BaseModel):
54
+ name: Annotated[str, ExcelColumn(label='Name', order=1)]
55
+ email: Annotated[
56
+ str,
57
+ Field(min_length=8),
58
+ ExcelColumn(
59
+ label='Email',
60
+ codec=EmailCodec(),
61
+ order=2,
62
+ hint='Use your work email',
63
+ example_value='alice@company.com',
64
+ ),
65
+ ]
66
+
67
+
68
+ alchemy = ExcelAlchemy(ImporterConfig(EmployeeImport, locale='en'))
69
+ template = alchemy.download_template_artifact(filename='employees-template.xlsx')
70
+
71
+ excel_bytes = template.as_bytes()
72
+ ```
73
+
74
+ ## Import Workflow
75
+
76
+ The shortest import path is:
77
+
78
+ ```text
79
+ template -> preflight -> import -> remediation -> delivery
80
+ ```
81
+
82
+ Minimal backend sketch:
83
+
84
+ ```python
85
+ from excelalchemy.results import ImportLifecycleEvent, build_frontend_remediation_payload
86
+
87
+
88
+ events: list[ImportLifecycleEvent] = []
89
+
90
+ preflight = alchemy.preflight_import('employees.xlsx')
91
+ if preflight.is_valid:
92
+ result = await alchemy.import_data(
93
+ 'employees.xlsx',
94
+ 'employees-result.xlsx',
95
+ on_event=events.append,
96
+ )
97
+ payload = {
98
+ 'result': result.to_api_payload(),
99
+ 'cell_errors': alchemy.cell_error_map.to_api_payload(),
100
+ 'row_errors': alchemy.row_error_map.to_api_payload(),
101
+ 'remediation': build_frontend_remediation_payload(
102
+ result=result,
103
+ cell_error_map=alchemy.cell_error_map,
104
+ row_error_map=alchemy.row_error_map,
105
+ ),
106
+ }
107
+ ```
108
+
109
+ ## Why ExcelAlchemy
110
+
111
+ - Pydantic v2-based schema extraction and validation
112
+ - `Annotated[..., ExcelColumn(...)]` declaration style
113
+ - workbook comments and result workbooks in `zh-CN`, `en`, or `ja`
114
+ - pluggable storage instead of a hard-coded backend
115
+ - `openpyxl`-based runtime path without pandas
116
+ - contract tests, Ruff, and Pyright in the development workflow
117
+
118
+ ## Learn More
119
+
120
+ - [Full project README](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/README.md)
121
+ - [Getting started](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/getting-started.md)
122
+ - [Examples showcase](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/examples-showcase.md)
123
+ - [Result objects](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/result-objects.md)
124
+ - [API response cookbook](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/api-response-cookbook.md)
125
+ - [Platform architecture](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/platform-architecture.md)
126
+ - [Migration notes](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/migrations.md)
@@ -63,7 +63,6 @@ exclude = [
63
63
  '**/.mypy_cache',
64
64
  '**/__pycache__',
65
65
  '**/.pytest_cache',
66
- 'src/excelalchemy/types/field.py',
67
66
  ]
68
67
  enableTypeIgnoreComments = false
69
68
  reportAbstractUsage = false
@@ -72,48 +71,64 @@ reportCallIssue = false
72
71
  reportPrivateImportUsage = false
73
72
  reportRedeclaration = false
74
73
  strict = [
75
- 'src/excelalchemy/_primitives/constants.py',
76
- 'src/excelalchemy/_primitives/deprecation.py',
77
- 'src/excelalchemy/_primitives/header_models.py',
78
- 'src/excelalchemy/_primitives/identity.py',
79
- 'src/excelalchemy/_primitives/payloads.py',
74
+ 'src/excelalchemy/adapters/pydantic.py',
80
75
  'src/excelalchemy/artifacts.py',
81
- 'src/excelalchemy/codecs/base.py',
82
76
  'src/excelalchemy/codecs/boolean.py',
77
+ 'src/excelalchemy/codecs/choice.py',
83
78
  'src/excelalchemy/codecs/date.py',
84
79
  'src/excelalchemy/codecs/date_range.py',
85
80
  'src/excelalchemy/codecs/email.py',
86
- 'src/excelalchemy/codecs/money.py',
87
- 'src/excelalchemy/codecs/multi_checkbox.py',
81
+ 'src/excelalchemy/codecs/field_codec.py',
88
82
  'src/excelalchemy/codecs/number.py',
89
83
  'src/excelalchemy/codecs/number_range.py',
90
- 'src/excelalchemy/codecs/organization.py',
91
84
  'src/excelalchemy/codecs/phone_number.py',
92
- 'src/excelalchemy/codecs/radio.py',
93
- 'src/excelalchemy/codecs/staff.py',
94
- 'src/excelalchemy/codecs/string.py',
95
- 'src/excelalchemy/codecs/tree.py',
85
+ 'src/excelalchemy/codecs/text.py',
96
86
  'src/excelalchemy/codecs/url.py',
97
- 'src/excelalchemy/config.py',
98
- 'src/excelalchemy/core/alchemy.py',
99
- 'src/excelalchemy/core/abstract.py',
100
- 'src/excelalchemy/core/executor.py',
101
- 'src/excelalchemy/core/rendering.py',
102
- 'src/excelalchemy/core/schema.py',
103
- 'src/excelalchemy/core/storage.py',
104
- 'src/excelalchemy/core/storage_minio.py',
105
- 'src/excelalchemy/core/storage_protocol.py',
106
- 'src/excelalchemy/core/table.py',
107
- 'src/excelalchemy/core/writer.py',
108
- 'src/excelalchemy/exceptions.py',
109
- 'src/excelalchemy/core/headers.py',
110
- 'src/excelalchemy/core/rows.py',
111
- 'src/excelalchemy/helper/pydantic.py',
112
- 'src/excelalchemy/i18n/messages.py',
113
- 'src/excelalchemy/metadata.py',
114
- 'src/excelalchemy/results.py',
115
- 'src/excelalchemy/util/convertor.py',
87
+ 'src/excelalchemy/columns.py',
88
+ 'src/excelalchemy/config/__init__.py',
89
+ 'src/excelalchemy/config/exporter.py',
90
+ 'src/excelalchemy/config/importer.py',
91
+ 'src/excelalchemy/config/modes.py',
92
+ 'src/excelalchemy/config/options.py',
93
+ 'src/excelalchemy/diagnostics.py',
94
+ 'src/excelalchemy/errors.py',
95
+ 'src/excelalchemy/messages.py',
96
+ 'src/excelalchemy/policies.py',
97
+ 'src/excelalchemy/primitives/constants.py',
98
+ 'src/excelalchemy/primitives/identity.py',
99
+ 'src/excelalchemy/primitives/payloads.py',
100
+ 'src/excelalchemy/rendering/renderer.py',
101
+ 'src/excelalchemy/rendering/writer.py',
102
+ 'src/excelalchemy/results/__init__.py',
103
+ 'src/excelalchemy/results/import_result.py',
104
+ 'src/excelalchemy/results/issue_maps.py',
105
+ 'src/excelalchemy/results/lifecycle.py',
106
+ 'src/excelalchemy/results/preflight.py',
107
+ 'src/excelalchemy/results/remediation.py',
108
+ 'src/excelalchemy/runtime/executor.py',
109
+ 'src/excelalchemy/runtime/facade.py',
110
+ 'src/excelalchemy/runtime/facade_protocol.py',
111
+ 'src/excelalchemy/runtime/import_session.py',
112
+ 'src/excelalchemy/runtime/preflight.py',
113
+ 'src/excelalchemy/runtime/rows.py',
114
+ 'src/excelalchemy/schema/layout.py',
115
+ 'src/excelalchemy/storage/__init__.py',
116
+ 'src/excelalchemy/storage/base.py',
117
+ 'src/excelalchemy/storage/gateway.py',
118
+ 'src/excelalchemy/storage/minio.py',
116
119
  'src/excelalchemy/util/file.py',
120
+ 'src/excelalchemy/field_metadata/__init__.py',
121
+ 'src/excelalchemy/field_metadata/constraints.py',
122
+ 'src/excelalchemy/field_metadata/declaration.py',
123
+ 'src/excelalchemy/field_metadata/field.py',
124
+ 'src/excelalchemy/field_metadata/presentation.py',
125
+ 'src/excelalchemy/field_metadata/runtime.py',
126
+ 'src/excelalchemy/worksheet/__init__.py',
127
+ 'src/excelalchemy/worksheet/header.py',
128
+ 'src/excelalchemy/worksheet/header_parser.py',
129
+ 'src/excelalchemy/worksheet/header_validator.py',
130
+ 'src/excelalchemy/worksheet/table.py',
131
+ 'src/excelalchemy/adapters/pydantic_fields.py',
117
132
  ]
118
133
  typeCheckingMode = 'basic'
119
134
 
@@ -129,12 +144,6 @@ ignore = ['E501', 'RUF001', 'RUF002', 'RUF003']
129
144
 
130
145
  [tool.ruff.lint.per-file-ignores]
131
146
  '**/__init__.py' = ['F401']
132
- 'src/excelalchemy/const.py' = ['RUF100']
133
- 'src/excelalchemy/exc.py' = ['E402', 'RUF100']
134
- 'src/excelalchemy/header_models.py' = ['E402', 'RUF100']
135
- 'src/excelalchemy/identity.py' = ['E402', 'RUF100']
136
- 'src/excelalchemy/types/*.py' = ['E402', 'RUF100']
137
- 'src/excelalchemy/types/**/*.py' = ['E402', 'RUF100']
138
147
 
139
148
  [tool.ruff.format]
140
149
  quote-style = 'preserve'
@@ -0,0 +1,59 @@
1
+ # ExcelAlchemy Package Map
2
+
3
+ This package is being shaped for ExcelAlchemy 3.0. Use concrete responsibility
4
+ modules when editing code; do not add a generic `_internal` package and do not
5
+ restore 2.x compatibility shims.
6
+
7
+ ## Public Entry Points
8
+
9
+ - `excelalchemy`: package root exports the common public API.
10
+ - `config/`: `ImporterConfig`, `ExporterConfig`, `ImportMode`, and normalized
11
+ storage options.
12
+ - `columns.py`: `ExcelColumn(...)` and immutable column declarations for
13
+ `typing.Annotated`.
14
+ - `codecs/`: built-in workbook codecs and codec extension base classes.
15
+ - `field_metadata/`: resolved Excel-facing field metadata used by the runtime.
16
+ - `results/`: import results, issue maps, preflight results, lifecycle events,
17
+ and API payload helpers.
18
+ - `errors.py`: public exception exports.
19
+ - `storage/`: `ExcelStorage` protocol.
20
+ - `storage/gateway.py`: configured storage resolver and missing-storage
21
+ fallback.
22
+ - `artifacts.py`: binary/data-URL workbook transport wrapper.
23
+
24
+ ## Implementation Areas
25
+
26
+ - `adapters/`: framework boundaries, currently Pydantic model extraction and
27
+ validation error normalization.
28
+ - `schema/`: Excel schema layout extraction and flattened column planning.
29
+ - `worksheet/`: worksheet tables, header records, header parsing, and header validation.
30
+ - `runtime/`: facade, import sessions, row aggregation, execution, and preflight.
31
+ - `rendering/`: workbook rendering and low-level writing.
32
+ - `messages.py`: runtime and workbook-facing message lookup.
33
+ - `policies.py`: named deterministic policies for layout, payload, result,
34
+ event, and missing-value behavior.
35
+ - `diagnostics.py`: logger names and structured diagnostics helpers.
36
+
37
+ ## Removed 2.x Surfaces
38
+
39
+ These paths and aliases are intentionally absent in 3.0:
40
+
41
+ - `excelalchemy.core.*`
42
+ - `excelalchemy.helper.*`
43
+ - `excelalchemy.i18n.*`
44
+ - `excelalchemy._primitives.*`
45
+ - `excelalchemy.const`
46
+ - `excelalchemy.exc`
47
+ - `excelalchemy.identity`
48
+ - `excelalchemy.header_models`
49
+ - `excelalchemy.metadata`
50
+ - `excelalchemy.types.*`
51
+ - `excelalchemy.util.convertor`
52
+ - facade aliases `df`, `header_df`, `cell_errors`, `row_errors`
53
+ - config fields `minio`, `bucket_name`, `url_expires`
54
+ - codec aliases `comment`, `serialize`, `deserialize`, `__validate__`,
55
+ `model_items`
56
+ - metadata alias `value_type`
57
+
58
+ Use `storage=...` with an `ExcelStorage` implementation for any backend,
59
+ including `MinioStorageGateway`.
@@ -0,0 +1,99 @@
1
+ """Public ExcelAlchemy API."""
2
+
3
+ __version__ = '3.0.0'
4
+ from excelalchemy.artifacts import ExcelArtifact
5
+ from excelalchemy.codecs.boolean import BooleanCodec
6
+ from excelalchemy.codecs.choice import MultiChoiceCodec, SingleChoiceCodec
7
+ from excelalchemy.codecs.date import DateCodec
8
+ from excelalchemy.codecs.date_range import DateRangeCodec
9
+ from excelalchemy.codecs.email import EmailCodec
10
+ from excelalchemy.codecs.field_codec import CompositeExcelFieldCodec, ExcelFieldCodec, ExcelFieldCodecSpec
11
+ from excelalchemy.codecs.number import NumberCodec
12
+ from excelalchemy.codecs.number_range import NumberRangeCodec
13
+ from excelalchemy.codecs.phone_number import PhoneNumberCodec
14
+ from excelalchemy.codecs.text import TextCodec
15
+ from excelalchemy.codecs.url import UrlCodec
16
+ from excelalchemy.columns import ExcelColumn
17
+ from excelalchemy.config import ExportConfig, ExporterConfig, ImportConfig, ImporterConfig, ImportMode
18
+ from excelalchemy.errors import (
19
+ ConfigError,
20
+ ExcelCellError,
21
+ ExcelRowError,
22
+ ProgrammaticError,
23
+ WorksheetNotFoundError,
24
+ )
25
+ from excelalchemy.primitives.constants import CharacterSet, DataRangeOption, DateFormat, Option
26
+ from excelalchemy.primitives.identity import (
27
+ ColumnIndex,
28
+ DataUrlStr,
29
+ Key,
30
+ Label,
31
+ OptionId,
32
+ RowIndex,
33
+ UniqueKey,
34
+ UniqueLabel,
35
+ UrlStr,
36
+ )
37
+ from excelalchemy.results import (
38
+ CellErrorMap,
39
+ ImportPreflightResult,
40
+ ImportPreflightStatus,
41
+ ImportResult,
42
+ RowIssueMap,
43
+ ValidateHeaderResult,
44
+ ValidateResult,
45
+ ValidateRowResult,
46
+ )
47
+ from excelalchemy.runtime.facade import ExcelAlchemy
48
+ from excelalchemy.storage import ExcelStorage
49
+
50
+ __all__ = [
51
+ 'BooleanCodec',
52
+ 'CellErrorMap',
53
+ 'ColumnIndex',
54
+ 'CompositeExcelFieldCodec',
55
+ 'ConfigError',
56
+ 'DataRangeOption',
57
+ 'DataUrlStr',
58
+ 'DateCodec',
59
+ 'DateFormat',
60
+ 'DateRangeCodec',
61
+ 'EmailCodec',
62
+ 'ExcelAlchemy',
63
+ 'ExcelArtifact',
64
+ 'ExcelCellError',
65
+ 'ExcelColumn',
66
+ 'ExcelFieldCodec',
67
+ 'ExcelFieldCodecSpec',
68
+ 'ExcelRowError',
69
+ 'ExcelStorage',
70
+ 'ExportConfig',
71
+ 'ExporterConfig',
72
+ 'ImportConfig',
73
+ 'ImportMode',
74
+ 'ImportPreflightResult',
75
+ 'ImportPreflightStatus',
76
+ 'ImportResult',
77
+ 'ImporterConfig',
78
+ 'Key',
79
+ 'Label',
80
+ 'MultiChoiceCodec',
81
+ 'NumberCodec',
82
+ 'NumberRangeCodec',
83
+ 'Option',
84
+ 'OptionId',
85
+ 'PhoneNumberCodec',
86
+ 'ProgrammaticError',
87
+ 'RowIndex',
88
+ 'RowIssueMap',
89
+ 'SingleChoiceCodec',
90
+ 'TextCodec',
91
+ 'UniqueKey',
92
+ 'UniqueLabel',
93
+ 'UrlCodec',
94
+ 'UrlStr',
95
+ 'ValidateHeaderResult',
96
+ 'ValidateResult',
97
+ 'ValidateRowResult',
98
+ 'WorksheetNotFoundError',
99
+ ]
@@ -0,0 +1,19 @@
1
+ """Framework adapter boundaries."""
2
+
3
+ from excelalchemy.adapters.pydantic import (
4
+ PydanticFieldAdapter,
5
+ PydanticModelAdapter,
6
+ ValidationMessageNormalizationPolicy,
7
+ extract_pydantic_model,
8
+ get_model_field_names,
9
+ instantiate_pydantic_model,
10
+ )
11
+
12
+ __all__ = [
13
+ 'PydanticFieldAdapter',
14
+ 'PydanticModelAdapter',
15
+ 'ValidationMessageNormalizationPolicy',
16
+ 'extract_pydantic_model',
17
+ 'get_model_field_names',
18
+ 'instantiate_pydantic_model',
19
+ ]