ExcelAlchemy 2.0.0rc1__tar.gz → 2.2.2__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 (107) hide show
  1. excelalchemy-2.2.2/PKG-INFO +131 -0
  2. excelalchemy-2.2.2/README-pypi.md +91 -0
  3. excelalchemy-2.2.2/pyproject.toml +155 -0
  4. excelalchemy-2.2.2/src/excelalchemy/__init__.py +126 -0
  5. excelalchemy-2.2.2/src/excelalchemy/_primitives/__init__.py +1 -0
  6. excelalchemy-2.0.0rc1/src/excelalchemy/const.py → excelalchemy-2.2.2/src/excelalchemy/_primitives/constants.py +11 -11
  7. excelalchemy-2.2.2/src/excelalchemy/_primitives/deprecation.py +22 -0
  8. excelalchemy-2.2.2/src/excelalchemy/_primitives/header_models.py +27 -0
  9. {excelalchemy-2.0.0rc1/src/excelalchemy/types → excelalchemy-2.2.2/src/excelalchemy/_primitives}/identity.py +15 -11
  10. excelalchemy-2.2.2/src/excelalchemy/_primitives/payloads.py +17 -0
  11. excelalchemy-2.2.2/src/excelalchemy/artifacts.py +38 -0
  12. excelalchemy-2.2.2/src/excelalchemy/codecs/__init__.py +14 -0
  13. excelalchemy-2.2.2/src/excelalchemy/codecs/base.py +126 -0
  14. {excelalchemy-2.0.0rc1/src/excelalchemy/types/value → excelalchemy-2.2.2/src/excelalchemy/codecs}/boolean.py +13 -10
  15. {excelalchemy-2.0.0rc1/src/excelalchemy/types/value → excelalchemy-2.2.2/src/excelalchemy/codecs}/date.py +26 -13
  16. excelalchemy-2.2.2/src/excelalchemy/codecs/date_range.py +189 -0
  17. {excelalchemy-2.0.0rc1/src/excelalchemy/types/value → excelalchemy-2.2.2/src/excelalchemy/codecs}/email.py +8 -5
  18. excelalchemy-2.2.2/src/excelalchemy/codecs/money.py +29 -0
  19. {excelalchemy-2.0.0rc1/src/excelalchemy/types/value → excelalchemy-2.2.2/src/excelalchemy/codecs}/multi_checkbox.py +31 -22
  20. {excelalchemy-2.0.0rc1/src/excelalchemy/types/value → excelalchemy-2.2.2/src/excelalchemy/codecs}/number.py +36 -26
  21. excelalchemy-2.2.2/src/excelalchemy/codecs/number_range.py +141 -0
  22. excelalchemy-2.2.2/src/excelalchemy/codecs/organization.py +83 -0
  23. {excelalchemy-2.0.0rc1/src/excelalchemy/types/value → excelalchemy-2.2.2/src/excelalchemy/codecs}/phone_number.py +6 -3
  24. {excelalchemy-2.0.0rc1/src/excelalchemy/types/value → excelalchemy-2.2.2/src/excelalchemy/codecs}/radio.py +17 -12
  25. excelalchemy-2.2.2/src/excelalchemy/codecs/staff.py +88 -0
  26. {excelalchemy-2.0.0rc1/src/excelalchemy/types/value → excelalchemy-2.2.2/src/excelalchemy/codecs}/string.py +13 -15
  27. excelalchemy-2.2.2/src/excelalchemy/codecs/tree.py +64 -0
  28. {excelalchemy-2.0.0rc1/src/excelalchemy/types/value → excelalchemy-2.2.2/src/excelalchemy/codecs}/url.py +6 -3
  29. excelalchemy-2.2.2/src/excelalchemy/config.py +409 -0
  30. excelalchemy-2.2.2/src/excelalchemy/const.py +3 -0
  31. excelalchemy-2.2.2/src/excelalchemy/core/abstract.py +57 -0
  32. excelalchemy-2.2.2/src/excelalchemy/core/alchemy.py +372 -0
  33. excelalchemy-2.2.2/src/excelalchemy/core/executor.py +124 -0
  34. excelalchemy-2.2.2/src/excelalchemy/core/headers.py +149 -0
  35. excelalchemy-2.2.2/src/excelalchemy/core/import_session.py +307 -0
  36. {excelalchemy-2.0.0rc1 → excelalchemy-2.2.2}/src/excelalchemy/core/rendering.py +14 -12
  37. {excelalchemy-2.0.0rc1 → excelalchemy-2.2.2}/src/excelalchemy/core/rows.py +48 -38
  38. {excelalchemy-2.0.0rc1 → excelalchemy-2.2.2}/src/excelalchemy/core/schema.py +15 -12
  39. {excelalchemy-2.0.0rc1 → excelalchemy-2.2.2}/src/excelalchemy/core/storage.py +16 -7
  40. {excelalchemy-2.0.0rc1 → excelalchemy-2.2.2}/src/excelalchemy/core/storage_minio.py +22 -16
  41. {excelalchemy-2.0.0rc1 → excelalchemy-2.2.2}/src/excelalchemy/core/storage_protocol.py +1 -1
  42. {excelalchemy-2.0.0rc1 → excelalchemy-2.2.2}/src/excelalchemy/core/table.py +64 -29
  43. {excelalchemy-2.0.0rc1 → excelalchemy-2.2.2}/src/excelalchemy/core/writer.py +67 -60
  44. excelalchemy-2.2.2/src/excelalchemy/exc.py +7 -0
  45. excelalchemy-2.0.0rc1/src/excelalchemy/exc.py → excelalchemy-2.2.2/src/excelalchemy/exceptions.py +9 -7
  46. excelalchemy-2.2.2/src/excelalchemy/header_models.py +10 -0
  47. excelalchemy-2.2.2/src/excelalchemy/helper/pydantic.py +244 -0
  48. {excelalchemy-2.0.0rc1 → excelalchemy-2.2.2}/src/excelalchemy/i18n/messages.py +12 -20
  49. excelalchemy-2.2.2/src/excelalchemy/identity.py +7 -0
  50. excelalchemy-2.2.2/src/excelalchemy/metadata.py +899 -0
  51. excelalchemy-2.2.2/src/excelalchemy/results.py +91 -0
  52. excelalchemy-2.2.2/src/excelalchemy/types/__init__.py +15 -0
  53. excelalchemy-2.2.2/src/excelalchemy/types/abstract.py +7 -0
  54. excelalchemy-2.2.2/src/excelalchemy/types/alchemy.py +7 -0
  55. excelalchemy-2.2.2/src/excelalchemy/types/field.py +7 -0
  56. excelalchemy-2.2.2/src/excelalchemy/types/header.py +10 -0
  57. excelalchemy-2.2.2/src/excelalchemy/types/identity.py +7 -0
  58. excelalchemy-2.2.2/src/excelalchemy/types/result.py +7 -0
  59. excelalchemy-2.2.2/src/excelalchemy/types/value/__init__.py +7 -0
  60. excelalchemy-2.2.2/src/excelalchemy/types/value/boolean.py +7 -0
  61. excelalchemy-2.2.2/src/excelalchemy/types/value/date.py +7 -0
  62. excelalchemy-2.2.2/src/excelalchemy/types/value/date_range.py +7 -0
  63. excelalchemy-2.2.2/src/excelalchemy/types/value/email.py +7 -0
  64. excelalchemy-2.2.2/src/excelalchemy/types/value/money.py +7 -0
  65. excelalchemy-2.2.2/src/excelalchemy/types/value/multi_checkbox.py +7 -0
  66. excelalchemy-2.2.2/src/excelalchemy/types/value/number.py +7 -0
  67. excelalchemy-2.2.2/src/excelalchemy/types/value/number_range.py +7 -0
  68. excelalchemy-2.2.2/src/excelalchemy/types/value/organization.py +7 -0
  69. excelalchemy-2.2.2/src/excelalchemy/types/value/phone_number.py +7 -0
  70. excelalchemy-2.2.2/src/excelalchemy/types/value/radio.py +7 -0
  71. excelalchemy-2.2.2/src/excelalchemy/types/value/staff.py +7 -0
  72. excelalchemy-2.2.2/src/excelalchemy/types/value/string.py +7 -0
  73. excelalchemy-2.2.2/src/excelalchemy/types/value/tree.py +7 -0
  74. excelalchemy-2.2.2/src/excelalchemy/types/value/url.py +7 -0
  75. excelalchemy-2.2.2/src/excelalchemy/util/converter.py +50 -0
  76. excelalchemy-2.2.2/src/excelalchemy/util/convertor.py +8 -0
  77. excelalchemy-2.2.2/src/excelalchemy/util/file.py +52 -0
  78. excelalchemy-2.0.0rc1/PKG-INFO +0 -325
  79. excelalchemy-2.0.0rc1/README.md +0 -285
  80. excelalchemy-2.0.0rc1/pyproject.toml +0 -118
  81. excelalchemy-2.0.0rc1/src/excelalchemy/__init__.py +0 -75
  82. excelalchemy-2.0.0rc1/src/excelalchemy/core/abstract.py +0 -36
  83. excelalchemy-2.0.0rc1/src/excelalchemy/core/alchemy.py +0 -403
  84. excelalchemy-2.0.0rc1/src/excelalchemy/core/executor.py +0 -114
  85. excelalchemy-2.0.0rc1/src/excelalchemy/core/headers.py +0 -111
  86. excelalchemy-2.0.0rc1/src/excelalchemy/helper/pydantic.py +0 -191
  87. excelalchemy-2.0.0rc1/src/excelalchemy/types/abstract.py +0 -118
  88. excelalchemy-2.0.0rc1/src/excelalchemy/types/alchemy.py +0 -126
  89. excelalchemy-2.0.0rc1/src/excelalchemy/types/field.py +0 -434
  90. excelalchemy-2.0.0rc1/src/excelalchemy/types/header.py +0 -25
  91. excelalchemy-2.0.0rc1/src/excelalchemy/types/result.py +0 -77
  92. excelalchemy-2.0.0rc1/src/excelalchemy/types/value/__init__.py +0 -10
  93. excelalchemy-2.0.0rc1/src/excelalchemy/types/value/date_range.py +0 -165
  94. excelalchemy-2.0.0rc1/src/excelalchemy/types/value/money.py +0 -11
  95. excelalchemy-2.0.0rc1/src/excelalchemy/types/value/number_range.py +0 -99
  96. excelalchemy-2.0.0rc1/src/excelalchemy/types/value/organization.py +0 -70
  97. excelalchemy-2.0.0rc1/src/excelalchemy/types/value/staff.py +0 -73
  98. excelalchemy-2.0.0rc1/src/excelalchemy/types/value/tree.py +0 -54
  99. excelalchemy-2.0.0rc1/src/excelalchemy/util/__init__.py +0 -0
  100. excelalchemy-2.0.0rc1/src/excelalchemy/util/convertor.py +0 -47
  101. excelalchemy-2.0.0rc1/src/excelalchemy/util/file.py +0 -47
  102. {excelalchemy-2.0.0rc1 → excelalchemy-2.2.2}/LICENSE +0 -0
  103. {excelalchemy-2.0.0rc1 → excelalchemy-2.2.2}/src/excelalchemy/core/__init__.py +0 -0
  104. {excelalchemy-2.0.0rc1 → excelalchemy-2.2.2}/src/excelalchemy/helper/__init__.py +0 -0
  105. {excelalchemy-2.0.0rc1 → excelalchemy-2.2.2}/src/excelalchemy/i18n/__init__.py +0 -0
  106. {excelalchemy-2.0.0rc1 → excelalchemy-2.2.2}/src/excelalchemy/py.typed +0 -0
  107. {excelalchemy-2.0.0rc1/src/excelalchemy/types → excelalchemy-2.2.2/src/excelalchemy/util}/__init__.py +0 -0
@@ -0,0 +1,131 @@
1
+ Metadata-Version: 2.4
2
+ Name: ExcelAlchemy
3
+ Version: 2.2.2
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 Pydantic and locale-aware workbooks.
43
+
44
+ ExcelAlchemy turns Pydantic models into typed workbook contracts:
45
+
46
+ - generate Excel templates from code
47
+ - validate uploaded workbooks
48
+ - map failures back to rows and cells
49
+ - render workbook-facing output in `zh-CN` or `en`
50
+ - keep storage pluggable through `ExcelStorage`
51
+
52
+ [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)
53
+
54
+ ## Screenshots
55
+
56
+ ### Template
57
+
58
+ ![Excel template screenshot](https://raw.githubusercontent.com/RayCarterLab/ExcelAlchemy/main/images/portfolio-template-en.png)
59
+
60
+ ### Import Result
61
+
62
+ ![Excel import result screenshot](https://raw.githubusercontent.com/RayCarterLab/ExcelAlchemy/main/images/portfolio-import-result-en.png)
63
+
64
+ ## Install
65
+
66
+ ```bash
67
+ pip install ExcelAlchemy
68
+ ```
69
+
70
+ Optional Minio support:
71
+
72
+ ```bash
73
+ pip install "ExcelAlchemy[minio]"
74
+ ```
75
+
76
+ ## Minimal Example
77
+
78
+ ```python
79
+ from pydantic import BaseModel
80
+
81
+ from excelalchemy import ExcelAlchemy, FieldMeta, ImporterConfig, Number, String
82
+
83
+
84
+ class Importer(BaseModel):
85
+ age: Number = FieldMeta(label='Age', order=1)
86
+ name: String = FieldMeta(label='Name', order=2)
87
+
88
+
89
+ alchemy = ExcelAlchemy(ImporterConfig(Importer, locale='en'))
90
+ template = alchemy.download_template_artifact(filename='people-template.xlsx')
91
+
92
+ excel_bytes = template.as_bytes()
93
+ ```
94
+
95
+ ## Modern Annotated Example
96
+
97
+ ```python
98
+ from typing import Annotated
99
+
100
+ from pydantic import BaseModel, Field
101
+
102
+ from excelalchemy import Email, ExcelAlchemy, ExcelMeta, ImporterConfig
103
+
104
+
105
+ class Importer(BaseModel):
106
+ email: Annotated[
107
+ Email,
108
+ Field(min_length=10),
109
+ ExcelMeta(label='Email', order=1, hint='Use your work email'),
110
+ ]
111
+
112
+
113
+ alchemy = ExcelAlchemy(ImporterConfig(Importer, locale='en'))
114
+ template = alchemy.download_template_artifact(filename='people-template.xlsx')
115
+ ```
116
+
117
+ ## Why ExcelAlchemy
118
+
119
+ - Pydantic v2-based schema extraction and validation
120
+ - locale-aware workbook comments and result workbooks
121
+ - pluggable storage instead of a hard-coded backend
122
+ - `openpyxl`-based runtime path without pandas
123
+ - contract tests, Ruff, and Pyright in the development workflow
124
+
125
+ ## Learn More
126
+
127
+ - [Full project README](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/README.md)
128
+ - [Architecture notes](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/architecture.md)
129
+ - [Locale policy](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/locale.md)
130
+ - [Migration notes](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/MIGRATIONS.md)
131
+
@@ -0,0 +1,91 @@
1
+ # ExcelAlchemy
2
+
3
+ Schema-driven Python library for typed Excel import/export workflows with Pydantic and locale-aware workbooks.
4
+
5
+ ExcelAlchemy turns Pydantic models into typed workbook contracts:
6
+
7
+ - generate Excel templates from code
8
+ - validate uploaded workbooks
9
+ - map failures back to rows and cells
10
+ - render workbook-facing output in `zh-CN` or `en`
11
+ - keep storage pluggable through `ExcelStorage`
12
+
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)
14
+
15
+ ## Screenshots
16
+
17
+ ### Template
18
+
19
+ ![Excel template screenshot](https://raw.githubusercontent.com/RayCarterLab/ExcelAlchemy/main/images/portfolio-template-en.png)
20
+
21
+ ### Import Result
22
+
23
+ ![Excel import result screenshot](https://raw.githubusercontent.com/RayCarterLab/ExcelAlchemy/main/images/portfolio-import-result-en.png)
24
+
25
+ ## Install
26
+
27
+ ```bash
28
+ pip install ExcelAlchemy
29
+ ```
30
+
31
+ Optional Minio support:
32
+
33
+ ```bash
34
+ pip install "ExcelAlchemy[minio]"
35
+ ```
36
+
37
+ ## Minimal Example
38
+
39
+ ```python
40
+ from pydantic import BaseModel
41
+
42
+ from excelalchemy import ExcelAlchemy, FieldMeta, ImporterConfig, Number, String
43
+
44
+
45
+ class Importer(BaseModel):
46
+ age: Number = FieldMeta(label='Age', order=1)
47
+ name: String = FieldMeta(label='Name', order=2)
48
+
49
+
50
+ alchemy = ExcelAlchemy(ImporterConfig(Importer, locale='en'))
51
+ template = alchemy.download_template_artifact(filename='people-template.xlsx')
52
+
53
+ excel_bytes = template.as_bytes()
54
+ ```
55
+
56
+ ## Modern Annotated Example
57
+
58
+ ```python
59
+ from typing import Annotated
60
+
61
+ from pydantic import BaseModel, Field
62
+
63
+ from excelalchemy import Email, ExcelAlchemy, ExcelMeta, ImporterConfig
64
+
65
+
66
+ class Importer(BaseModel):
67
+ email: Annotated[
68
+ Email,
69
+ Field(min_length=10),
70
+ ExcelMeta(label='Email', order=1, hint='Use your work email'),
71
+ ]
72
+
73
+
74
+ alchemy = ExcelAlchemy(ImporterConfig(Importer, locale='en'))
75
+ template = alchemy.download_template_artifact(filename='people-template.xlsx')
76
+ ```
77
+
78
+ ## Why ExcelAlchemy
79
+
80
+ - Pydantic v2-based schema extraction and validation
81
+ - locale-aware workbook comments and result workbooks
82
+ - pluggable storage instead of a hard-coded backend
83
+ - `openpyxl`-based runtime path without pandas
84
+ - contract tests, Ruff, and Pyright in the development workflow
85
+
86
+ ## Learn More
87
+
88
+ - [Full project README](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/README.md)
89
+ - [Architecture notes](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/architecture.md)
90
+ - [Locale policy](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/docs/locale.md)
91
+ - [Migration notes](https://github.com/RayCarterLab/ExcelAlchemy/blob/main/MIGRATIONS.md)
@@ -0,0 +1,155 @@
1
+ [build-system]
2
+ requires = ['flit_core >=3.12,<4']
3
+ build-backend = 'flit_core.buildapi'
4
+
5
+ [project]
6
+ name = 'ExcelAlchemy'
7
+ description = 'Schema-driven Python library for typed Excel import/export workflows with Pydantic and locale-aware workbooks.'
8
+ authors = [{ name = 'Ray' }]
9
+ readme = { file = 'README-pypi.md', content-type = 'text/markdown' }
10
+ license = { file = 'LICENSE' }
11
+ keywords = ['excel', 'openpyxl', 'pydantic', 'minio', 'schema']
12
+ classifiers = [
13
+ 'Development Status :: 5 - Production/Stable',
14
+ 'Intended Audience :: Developers',
15
+ 'License :: OSI Approved :: MIT License',
16
+ 'Operating System :: OS Independent',
17
+ 'Programming Language :: Python',
18
+ 'Programming Language :: Python :: 3',
19
+ 'Programming Language :: Python :: 3 :: Only',
20
+ 'Programming Language :: Python :: 3.12',
21
+ 'Programming Language :: Python :: 3.13',
22
+ 'Programming Language :: Python :: 3.14',
23
+ 'Topic :: Office/Business :: Financial :: Spreadsheet',
24
+ 'Topic :: Software Development :: Libraries :: Python Modules',
25
+ ]
26
+ dynamic = ['version']
27
+ requires-python = '>=3.12'
28
+ dependencies = [
29
+ 'pydantic[email] >=2.12, <3',
30
+ 'openpyxl >=3.1.5, <4',
31
+ 'pendulum >=3.2.0, <4',
32
+ ]
33
+
34
+ [tool.flit.module]
35
+ name = 'excelalchemy'
36
+
37
+ [project.urls]
38
+ Home = 'https://github.com/RayCarterLab/ExcelAlchemy'
39
+ Repository = 'https://github.com/RayCarterLab/ExcelAlchemy'
40
+ Documentation = 'https://github.com/RayCarterLab/ExcelAlchemy#readme'
41
+ Issues = 'https://github.com/RayCarterLab/ExcelAlchemy/issues'
42
+
43
+ [project.optional-dependencies]
44
+ minio = [
45
+ 'minio >=7.2.20, <8',
46
+ ]
47
+ development = [
48
+ 'minio >=7.2.20, <8',
49
+ 'pre-commit',
50
+ 'pyright==1.1.408',
51
+ 'pytest',
52
+ 'coverage',
53
+ 'pytest-cov',
54
+ 'ruff',
55
+ ]
56
+
57
+ [tool.pyright]
58
+ include = ['src/excelalchemy', 'tests']
59
+ exclude = [
60
+ '.venv',
61
+ 'venv',
62
+ '.git',
63
+ '**/.mypy_cache',
64
+ '**/__pycache__',
65
+ '**/.pytest_cache',
66
+ 'src/excelalchemy/types/field.py',
67
+ ]
68
+ enableTypeIgnoreComments = false
69
+ reportAbstractUsage = false
70
+ reportAttributeAccessIssue = false
71
+ reportCallIssue = false
72
+ reportPrivateImportUsage = false
73
+ reportRedeclaration = false
74
+ 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',
80
+ 'src/excelalchemy/artifacts.py',
81
+ 'src/excelalchemy/codecs/base.py',
82
+ 'src/excelalchemy/codecs/boolean.py',
83
+ 'src/excelalchemy/codecs/date.py',
84
+ 'src/excelalchemy/codecs/date_range.py',
85
+ 'src/excelalchemy/codecs/email.py',
86
+ 'src/excelalchemy/codecs/money.py',
87
+ 'src/excelalchemy/codecs/multi_checkbox.py',
88
+ 'src/excelalchemy/codecs/number.py',
89
+ 'src/excelalchemy/codecs/number_range.py',
90
+ 'src/excelalchemy/codecs/organization.py',
91
+ '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',
96
+ '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',
116
+ 'src/excelalchemy/util/file.py',
117
+ ]
118
+ typeCheckingMode = 'basic'
119
+
120
+ [tool.ruff]
121
+ line-length = 120
122
+ target-version = 'py312'
123
+ src = ['src', 'tests']
124
+ extend-exclude = ['files']
125
+
126
+ [tool.ruff.lint]
127
+ select = ['E', 'F', 'I', 'UP', 'B', 'SIM', 'C4', 'RUF', 'PERF']
128
+ ignore = ['E501', 'RUF001', 'RUF002', 'RUF003']
129
+
130
+ [tool.ruff.lint.per-file-ignores]
131
+ '**/__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
+
139
+ [tool.ruff.format]
140
+ quote-style = 'preserve'
141
+ indent-style = 'space'
142
+ line-ending = 'auto'
143
+
144
+ [tool.pytest.ini_options]
145
+ addopts = ['--import-mode=importlib']
146
+ testpaths = ['tests']
147
+
148
+ [tool.coverage.run]
149
+ branch = true
150
+ source = ['excelalchemy']
151
+
152
+ [tool.coverage.report]
153
+ fail_under = 85
154
+ skip_covered = true
155
+ show_missing = true
@@ -0,0 +1,126 @@
1
+ """A Python Library for Reading and Writing Excel Files"""
2
+
3
+ __version__ = '2.2.2'
4
+ from excelalchemy._primitives.constants import CharacterSet, DataRangeOption, DateFormat, Option
5
+ from excelalchemy._primitives.deprecation import ExcelAlchemyDeprecationWarning
6
+ from excelalchemy._primitives.identity import (
7
+ Base64Str,
8
+ ColumnIndex,
9
+ DataUrlStr,
10
+ Key,
11
+ Label,
12
+ OptionId,
13
+ RowIndex,
14
+ UniqueKey,
15
+ UniqueLabel,
16
+ UrlStr,
17
+ )
18
+ from excelalchemy.artifacts import ExcelArtifact
19
+ from excelalchemy.codecs.base import CompositeExcelFieldCodec, ExcelFieldCodec
20
+ from excelalchemy.codecs.boolean import Boolean, BooleanCodec
21
+ from excelalchemy.codecs.date import Date, DateCodec
22
+ from excelalchemy.codecs.date_range import DateRange, DateRangeCodec
23
+ from excelalchemy.codecs.email import Email, EmailCodec
24
+ from excelalchemy.codecs.money import Money, MoneyCodec
25
+ from excelalchemy.codecs.multi_checkbox import MultiCheckbox, MultiChoiceCodec
26
+ from excelalchemy.codecs.number import Number, NumberCodec
27
+ from excelalchemy.codecs.number_range import NumberRange, NumberRangeCodec
28
+ from excelalchemy.codecs.organization import (
29
+ MultiOrganization,
30
+ MultiOrganizationCodec,
31
+ SingleOrganization,
32
+ SingleOrganizationCodec,
33
+ )
34
+ from excelalchemy.codecs.phone_number import PhoneNumber, PhoneNumberCodec
35
+ from excelalchemy.codecs.radio import Radio, SingleChoiceCodec
36
+ from excelalchemy.codecs.staff import MultiStaff, MultiStaffCodec, SingleStaff, SingleStaffCodec
37
+ from excelalchemy.codecs.string import String, StringCodec
38
+ from excelalchemy.codecs.tree import (
39
+ MultiTreeNode,
40
+ MultiTreeNodeCodec,
41
+ SingleTreeNode,
42
+ SingleTreeNodeCodec,
43
+ )
44
+ from excelalchemy.codecs.url import Url, UrlCodec
45
+ from excelalchemy.config import ExporterConfig, ImporterConfig, ImportMode
46
+ from excelalchemy.core.alchemy import ExcelAlchemy
47
+ from excelalchemy.core.storage_protocol import ExcelStorage
48
+ from excelalchemy.exceptions import ConfigError, ExcelCellError, ExcelRowError, ProgrammaticError
49
+ from excelalchemy.helper.pydantic import extract_pydantic_model
50
+ from excelalchemy.metadata import ExcelMeta, FieldMeta, PatchFieldMeta
51
+ from excelalchemy.results import ImportResult, ValidateHeaderResult, ValidateResult, ValidateRowResult
52
+ from excelalchemy.util.file import flatten
53
+
54
+ __all__ = [
55
+ 'Base64Str',
56
+ 'Boolean',
57
+ 'BooleanCodec',
58
+ 'ColumnIndex',
59
+ 'CompositeExcelFieldCodec',
60
+ 'ConfigError',
61
+ 'DataRangeOption',
62
+ 'DataUrlStr',
63
+ 'Date',
64
+ 'DateCodec',
65
+ 'DateFormat',
66
+ 'DateRange',
67
+ 'DateRangeCodec',
68
+ 'Email',
69
+ 'EmailCodec',
70
+ 'ExcelAlchemy',
71
+ 'ExcelAlchemyDeprecationWarning',
72
+ 'ExcelArtifact',
73
+ 'ExcelCellError',
74
+ 'ExcelFieldCodec',
75
+ 'ExcelMeta',
76
+ 'ExcelRowError',
77
+ 'ExcelStorage',
78
+ 'ExporterConfig',
79
+ 'FieldMeta',
80
+ 'ImportMode',
81
+ 'ImportResult',
82
+ 'ImporterConfig',
83
+ 'Key',
84
+ 'Label',
85
+ 'Money',
86
+ 'MoneyCodec',
87
+ 'MultiCheckbox',
88
+ 'MultiChoiceCodec',
89
+ 'MultiOrganization',
90
+ 'MultiOrganizationCodec',
91
+ 'MultiStaff',
92
+ 'MultiStaffCodec',
93
+ 'MultiTreeNode',
94
+ 'MultiTreeNodeCodec',
95
+ 'Number',
96
+ 'NumberCodec',
97
+ 'NumberRange',
98
+ 'NumberRangeCodec',
99
+ 'Option',
100
+ 'OptionId',
101
+ 'PatchFieldMeta',
102
+ 'PhoneNumber',
103
+ 'PhoneNumberCodec',
104
+ 'ProgrammaticError',
105
+ 'Radio',
106
+ 'RowIndex',
107
+ 'SingleChoiceCodec',
108
+ 'SingleOrganization',
109
+ 'SingleOrganizationCodec',
110
+ 'SingleStaff',
111
+ 'SingleStaffCodec',
112
+ 'SingleTreeNode',
113
+ 'SingleTreeNodeCodec',
114
+ 'String',
115
+ 'StringCodec',
116
+ 'UniqueKey',
117
+ 'UniqueLabel',
118
+ 'Url',
119
+ 'UrlCodec',
120
+ 'UrlStr',
121
+ 'ValidateHeaderResult',
122
+ 'ValidateResult',
123
+ 'ValidateRowResult',
124
+ 'extract_pydantic_model',
125
+ 'flatten',
126
+ ]
@@ -0,0 +1 @@
1
+ """Private primitive building blocks used by ExcelAlchemy internals."""
@@ -1,24 +1,24 @@
1
1
  from dataclasses import dataclass
2
- from enum import Enum
2
+ from enum import StrEnum
3
3
  from typing import Any
4
4
 
5
+ from excelalchemy._primitives.identity import Key, Label, OptionId
5
6
  from excelalchemy.i18n.messages import MessageKey
6
7
  from excelalchemy.i18n.messages import display_message as dmsg
7
- from excelalchemy.types.identity import Key, Label, OptionId
8
8
 
9
9
  HEADER_HINT = dmsg(MessageKey.HEADER_HINT, locale='zh-CN')
10
10
 
11
11
  EXCEL_COMMENT_FORMAT = {'height': 100, 'width': 300, 'font_size': 7}
12
12
  CHARACTER_WIDTH = 1.3
13
13
  DEFAULT_SHEET_NAME = 'Sheet1'
14
- # 连接符
14
+ # Connector used when flattening merged workbook headers.
15
15
  UNIQUE_HEADER_CONNECTOR: str = '·'
16
16
 
17
- # 数据导出结果列
17
+ # Result workbook status column.
18
18
  RESULT_COLUMN_LABEL: Label = Label(dmsg(MessageKey.RESULT_COLUMN_LABEL, locale='zh-CN'))
19
19
  RESULT_COLUMN_KEY: Key = Key('__result__')
20
20
 
21
- # 数据导出原因列
21
+ # Result workbook reason column.
22
22
  REASON_COLUMN_LABEL: Label = Label(dmsg(MessageKey.REASON_COLUMN_LABEL, locale='zh-CN'))
23
23
  REASON_COLUMN_KEY: Key = Key('__reason__')
24
24
 
@@ -26,15 +26,15 @@ BACKGROUND_REQUIRED_COLOR = 'FDAFB5'
26
26
  BACKGROUND_ERROR_COLOR = 'FEC100'
27
27
  FONT_READ_COLOR = 'FF0000'
28
28
 
29
- # 多选分隔符
29
+ # Display separator used for multi-choice workbook cells.
30
30
  MULTI_CHECKBOX_SEPARATOR = ','
31
31
 
32
32
  FIELD_DATA_KEY = Key('fieldData')
33
33
 
34
- # 毫秒转换为秒
34
+ # Millisecond to second conversion factor.
35
35
  MILLISECOND_TO_SECOND = 1000
36
36
 
37
- # options 最多允许的选项数量
37
+ # Soft option-count limit used for warning logs.
38
38
  MAX_OPTIONS_COUNT = 100
39
39
 
40
40
  DEFAULT_FIELD_META_ORDER = -1
@@ -45,7 +45,7 @@ type ListStr = list[str]
45
45
  type IntStr = int | str
46
46
 
47
47
 
48
- class CharacterSet(str, Enum):
48
+ class CharacterSet(StrEnum):
49
49
  CHINESE = 'CHINESE'
50
50
  NUMBER = 'NUMBER'
51
51
  LOWERCASE_LETTERS = 'LOWERCASE_LETTERS'
@@ -53,14 +53,14 @@ class CharacterSet(str, Enum):
53
53
  SPECIAL_SYMBOLS = 'SPECIAL_SYMBOLS'
54
54
 
55
55
 
56
- class DateFormat(str, Enum):
56
+ class DateFormat(StrEnum):
57
57
  YEAR = 'YEAR'
58
58
  MONTH = 'MONTH'
59
59
  DAY = 'DAY'
60
60
  MINUTE = 'MINUTE'
61
61
 
62
62
 
63
- class DataRangeOption(str, Enum):
63
+ class DataRangeOption(StrEnum):
64
64
  NONE = 'NONE'
65
65
  PRE = 'PRE'
66
66
  NEXT = 'NEXT'
@@ -0,0 +1,22 @@
1
+ """Deprecation helpers for public compatibility layers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import warnings
6
+
7
+ DEPRECATION_REMOVAL_VERSION = '3.0'
8
+
9
+
10
+ class ExcelAlchemyDeprecationWarning(FutureWarning):
11
+ """Warning emitted for deprecated public APIs that still have a compatibility shim."""
12
+
13
+
14
+ def warn_compat_import(import_path: str, replacement: str) -> None:
15
+ warnings.warn(
16
+ (
17
+ f'`{import_path}` is deprecated and will be removed in ExcelAlchemy '
18
+ f'{DEPRECATION_REMOVAL_VERSION}. Import from `{replacement}` instead.'
19
+ ),
20
+ category=ExcelAlchemyDeprecationWarning,
21
+ stacklevel=2,
22
+ )
@@ -0,0 +1,27 @@
1
+ """Internal workbook header models."""
2
+
3
+ from pydantic import BaseModel
4
+ from pydantic.fields import Field
5
+
6
+ from excelalchemy._primitives.constants import UNIQUE_HEADER_CONNECTOR
7
+ from excelalchemy._primitives.identity import Label, UniqueLabel
8
+
9
+
10
+ class ExcelHeader(BaseModel):
11
+ """Normalized workbook header extracted from user input."""
12
+
13
+ label: Label = Field(description='Workbook header label.')
14
+ parent_label: Label = Field(
15
+ description='Parent workbook header label. Falls back to the label itself for flat headers.'
16
+ )
17
+ offset: int = Field(default=0, description='Child-column offset under a merged parent header.')
18
+
19
+ @property
20
+ def unique_label(self) -> UniqueLabel:
21
+ """Return the fully qualified workbook header label."""
22
+ label = (
23
+ f'{self.parent_label}{UNIQUE_HEADER_CONNECTOR}{self.label}'
24
+ if self.parent_label != self.label
25
+ else self.label
26
+ )
27
+ return UniqueLabel(label)
@@ -1,4 +1,4 @@
1
- """定义了一些用于标识的类型"""
1
+ """Internal typed primitives used across the ExcelAlchemy core layer."""
2
2
 
3
3
  from typing import Any
4
4
 
@@ -27,36 +27,40 @@ class _IntegerIdentity(int):
27
27
 
28
28
 
29
29
  class Label(_StringIdentity):
30
- """Excel 的列名"""
30
+ """Workbook header label."""
31
31
 
32
32
 
33
33
  class UniqueLabel(Label):
34
- """Excel 唯一的列名"""
34
+ """Fully qualified workbook header label."""
35
35
 
36
36
 
37
37
  class Key(_StringIdentity):
38
- """Python 模型的键名"""
38
+ """Schema key used by the Python model."""
39
39
 
40
40
 
41
41
  class UniqueKey(Key):
42
- """Python 模型唯一的键名"""
42
+ """Fully qualified schema key."""
43
43
 
44
44
 
45
45
  class RowIndex(_IntegerIdentity):
46
- """Excel 的行索引, 0 开始"""
46
+ """Zero-based workbook row index."""
47
47
 
48
48
 
49
49
  class ColumnIndex(_IntegerIdentity):
50
- """Excel 的列索引, 0 开始"""
50
+ """Zero-based workbook column index."""
51
51
 
52
52
 
53
53
  class OptionId(_StringIdentity):
54
- """选项 ID"""
54
+ """Selection option identifier."""
55
55
 
56
56
 
57
- class Base64Str(_StringIdentity):
58
- """Base64 编码的字符串"""
57
+ class DataUrlStr(_StringIdentity):
58
+ """Data URL string."""
59
+
60
+
61
+ class Base64Str(DataUrlStr):
62
+ """Deprecated compatibility alias for the legacy data URL string return type."""
59
63
 
60
64
 
61
65
  class UrlStr(_StringIdentity):
62
- """URL 字符串"""
66
+ """Generic URL string."""