caxton 0.1.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 (170) hide show
  1. caxton-0.1.0/.gitignore +55 -0
  2. caxton-0.1.0/CHANGELOG.md +27 -0
  3. caxton-0.1.0/LICENSE +21 -0
  4. caxton-0.1.0/PKG-INFO +145 -0
  5. caxton-0.1.0/README.md +119 -0
  6. caxton-0.1.0/changelog.d/README.md +35 -0
  7. caxton-0.1.0/pyproject.toml +239 -0
  8. caxton-0.1.0/scripts/bump_version.py +102 -0
  9. caxton-0.1.0/scripts/check_api_compatibility.py +55 -0
  10. caxton-0.1.0/scripts/validate_commits.py +136 -0
  11. caxton-0.1.0/scripts/validate_files.py +75 -0
  12. caxton-0.1.0/setup.cfg +56 -0
  13. caxton-0.1.0/src/caxton/__init__.py +215 -0
  14. caxton-0.1.0/src/caxton/__version__.py +1 -0
  15. caxton-0.1.0/src/caxton/_internal/__init__.py +0 -0
  16. caxton-0.1.0/src/caxton/_internal/aggregation/__init__.py +11 -0
  17. caxton-0.1.0/src/caxton/_internal/aggregation/execution.py +315 -0
  18. caxton-0.1.0/src/caxton/_internal/aggregation/keys.py +80 -0
  19. caxton-0.1.0/src/caxton/_internal/aggregation/matrices.py +308 -0
  20. caxton-0.1.0/src/caxton/_internal/aggregation/models.py +69 -0
  21. caxton-0.1.0/src/caxton/_internal/aggregation/tables.py +233 -0
  22. caxton-0.1.0/src/caxton/_internal/backends/__init__.py +5 -0
  23. caxton-0.1.0/src/caxton/_internal/backends/_common.py +27 -0
  24. caxton-0.1.0/src/caxton/_internal/backends/_xlsx_formats.py +112 -0
  25. caxton-0.1.0/src/caxton/_internal/backends/openpyxl/__init__.py +25 -0
  26. caxton-0.1.0/src/caxton/_internal/backends/openpyxl/conditional_formats.py +42 -0
  27. caxton-0.1.0/src/caxton/_internal/backends/openpyxl/extensions.py +105 -0
  28. caxton-0.1.0/src/caxton/_internal/backends/openpyxl/footers.py +51 -0
  29. caxton-0.1.0/src/caxton/_internal/backends/openpyxl/native_tables.py +65 -0
  30. caxton-0.1.0/src/caxton/_internal/backends/openpyxl/package.py +223 -0
  31. caxton-0.1.0/src/caxton/_internal/backends/openpyxl/renderer.py +98 -0
  32. caxton-0.1.0/src/caxton/_internal/backends/openpyxl/rows.py +111 -0
  33. caxton-0.1.0/src/caxton/_internal/backends/openpyxl/styles.py +118 -0
  34. caxton-0.1.0/src/caxton/_internal/backends/openpyxl/tables.py +32 -0
  35. caxton-0.1.0/src/caxton/_internal/backends/openpyxl/template_renderer.py +108 -0
  36. caxton-0.1.0/src/caxton/_internal/backends/openpyxl/template_workbook.py +479 -0
  37. caxton-0.1.0/src/caxton/_internal/backends/openpyxl/workbook.py +74 -0
  38. caxton-0.1.0/src/caxton/_internal/backends/xlsxwriter/__init__.py +8 -0
  39. caxton-0.1.0/src/caxton/_internal/backends/xlsxwriter/conditional_formats.py +41 -0
  40. caxton-0.1.0/src/caxton/_internal/backends/xlsxwriter/destination.py +81 -0
  41. caxton-0.1.0/src/caxton/_internal/backends/xlsxwriter/drawings.py +118 -0
  42. caxton-0.1.0/src/caxton/_internal/backends/xlsxwriter/execution.py +93 -0
  43. caxton-0.1.0/src/caxton/_internal/backends/xlsxwriter/footers.py +67 -0
  44. caxton-0.1.0/src/caxton/_internal/backends/xlsxwriter/native_tables.py +67 -0
  45. caxton-0.1.0/src/caxton/_internal/backends/xlsxwriter/renderer.py +118 -0
  46. caxton-0.1.0/src/caxton/_internal/backends/xlsxwriter/rows.py +220 -0
  47. caxton-0.1.0/src/caxton/_internal/backends/xlsxwriter/styles.py +121 -0
  48. caxton-0.1.0/src/caxton/_internal/backends/xlsxwriter/tables.py +63 -0
  49. caxton-0.1.0/src/caxton/_internal/backends/xlsxwriter/workbook.py +45 -0
  50. caxton-0.1.0/src/caxton/_internal/block_paths.py +24 -0
  51. caxton-0.1.0/src/caxton/_internal/compiler/__init__.py +5 -0
  52. caxton-0.1.0/src/caxton/_internal/compiler/formula_resolution.py +246 -0
  53. caxton-0.1.0/src/caxton/_internal/compiler/spreadsheet.py +690 -0
  54. caxton-0.1.0/src/caxton/_internal/const.py +144 -0
  55. caxton-0.1.0/src/caxton/_internal/data/__init__.py +9 -0
  56. caxton-0.1.0/src/caxton/_internal/data/accessors.py +72 -0
  57. caxton-0.1.0/src/caxton/_internal/data/sources.py +187 -0
  58. caxton-0.1.0/src/caxton/_internal/formulas.py +140 -0
  59. caxton-0.1.0/src/caxton/_internal/layout/__init__.py +21 -0
  60. caxton-0.1.0/src/caxton/_internal/layout/spreadsheet.py +392 -0
  61. caxton-0.1.0/src/caxton/_internal/normalization/__init__.py +3 -0
  62. caxton-0.1.0/src/caxton/_internal/normalization/coordinates.py +56 -0
  63. caxton-0.1.0/src/caxton/_internal/operations.py +204 -0
  64. caxton-0.1.0/src/caxton/_internal/rendering.py +35 -0
  65. caxton-0.1.0/src/caxton/_internal/requirements.py +252 -0
  66. caxton-0.1.0/src/caxton/_internal/resolver.py +248 -0
  67. caxton-0.1.0/src/caxton/_internal/semantic/__init__.py +3 -0
  68. caxton-0.1.0/src/caxton/_internal/semantic/evaluator.py +413 -0
  69. caxton-0.1.0/src/caxton/_internal/shape.py +14 -0
  70. caxton-0.1.0/src/caxton/_internal/sinks.py +177 -0
  71. caxton-0.1.0/src/caxton/_internal/templates/__init__.py +17 -0
  72. caxton-0.1.0/src/caxton/_internal/templates/xlsx.py +406 -0
  73. caxton-0.1.0/src/caxton/_internal/validation/__init__.py +5 -0
  74. caxton-0.1.0/src/caxton/_internal/validation/expressions.py +179 -0
  75. caxton-0.1.0/src/caxton/_internal/validation/features.py +316 -0
  76. caxton-0.1.0/src/caxton/_internal/validation/formulas.py +303 -0
  77. caxton-0.1.0/src/caxton/_internal/validation/spreadsheet.py +31 -0
  78. caxton-0.1.0/src/caxton/_internal/validation/structure.py +183 -0
  79. caxton-0.1.0/src/caxton/api/__init__.py +155 -0
  80. caxton-0.1.0/src/caxton/api/columns.py +145 -0
  81. caxton-0.1.0/src/caxton/api/operations.py +62 -0
  82. caxton-0.1.0/src/caxton/api/spreadsheet.py +307 -0
  83. caxton-0.1.0/src/caxton/api/templates.py +76 -0
  84. caxton-0.1.0/src/caxton/api/xlsx/__init__.py +19 -0
  85. caxton-0.1.0/src/caxton/core/__init__.py +11 -0
  86. caxton-0.1.0/src/caxton/core/_values.py +211 -0
  87. caxton-0.1.0/src/caxton/core/errors/__init__.py +87 -0
  88. caxton-0.1.0/src/caxton/core/errors/base.py +42 -0
  89. caxton-0.1.0/src/caxton/core/errors/data.py +136 -0
  90. caxton-0.1.0/src/caxton/core/errors/rendering.py +58 -0
  91. caxton-0.1.0/src/caxton/core/errors/validation.py +171 -0
  92. caxton-0.1.0/src/caxton/core/errors/warnings.py +14 -0
  93. caxton-0.1.0/src/caxton/core/formatting/__init__.py +59 -0
  94. caxton-0.1.0/src/caxton/core/formatting/alignment.py +14 -0
  95. caxton-0.1.0/src/caxton/core/formatting/display.py +160 -0
  96. caxton-0.1.0/src/caxton/core/formatting/styles.py +364 -0
  97. caxton-0.1.0/src/caxton/core/ir/__init__.py +51 -0
  98. caxton-0.1.0/src/caxton/core/ir/base.py +22 -0
  99. caxton-0.1.0/src/caxton/core/ir/spreadsheet.py +329 -0
  100. caxton-0.1.0/src/caxton/core/models/__init__.py +140 -0
  101. caxton-0.1.0/src/caxton/core/models/_operators.py +98 -0
  102. caxton-0.1.0/src/caxton/core/models/_validation.py +64 -0
  103. caxton-0.1.0/src/caxton/core/models/columns.py +233 -0
  104. caxton-0.1.0/src/caxton/core/models/common.py +38 -0
  105. caxton-0.1.0/src/caxton/core/models/expressions.py +282 -0
  106. caxton-0.1.0/src/caxton/core/models/formulas.py +302 -0
  107. caxton-0.1.0/src/caxton/core/models/spreadsheet.py +527 -0
  108. caxton-0.1.0/src/caxton/core/models/templates.py +115 -0
  109. caxton-0.1.0/src/caxton/core/protocols/__init__.py +55 -0
  110. caxton-0.1.0/src/caxton/core/protocols/data.py +49 -0
  111. caxton-0.1.0/src/caxton/core/protocols/rendering.py +64 -0
  112. caxton-0.1.0/src/caxton/core/protocols/templates.py +40 -0
  113. caxton-0.1.0/src/caxton/core/rendering.py +201 -0
  114. caxton-0.1.0/src/caxton/core/types/__init__.py +27 -0
  115. caxton-0.1.0/src/caxton/core/types/base.py +37 -0
  116. caxton-0.1.0/src/caxton/core/types/boolean.py +11 -0
  117. caxton-0.1.0/src/caxton/core/types/date.py +11 -0
  118. caxton-0.1.0/src/caxton/core/types/datetime.py +11 -0
  119. caxton-0.1.0/src/caxton/core/types/decimal.py +11 -0
  120. caxton-0.1.0/src/caxton/core/types/duration.py +11 -0
  121. caxton-0.1.0/src/caxton/core/types/integer.py +11 -0
  122. caxton-0.1.0/src/caxton/core/types/link.py +11 -0
  123. caxton-0.1.0/src/caxton/core/types/money.py +22 -0
  124. caxton-0.1.0/src/caxton/core/types/percentage.py +13 -0
  125. caxton-0.1.0/src/caxton/core/types/text.py +11 -0
  126. caxton-0.1.0/src/caxton/core/types/time.py +11 -0
  127. caxton-0.1.0/src/caxton/core/values.py +22 -0
  128. caxton-0.1.0/src/caxton/errors.py +63 -0
  129. caxton-0.1.0/src/caxton/py.typed +0 -0
  130. caxton-0.1.0/src/caxton/testing/__init__.py +102 -0
  131. caxton-0.1.0/src/caxton/testing/_artifact.py +297 -0
  132. caxton-0.1.0/src/caxton/testing/_assertions.py +394 -0
  133. caxton-0.1.0/src/caxton/testing/_diff.py +40 -0
  134. caxton-0.1.0/src/caxton/testing/_errors.py +13 -0
  135. caxton-0.1.0/src/caxton/testing/_layout.py +669 -0
  136. caxton-0.1.0/src/caxton/testing/_snapshots.py +173 -0
  137. caxton-0.1.0/src/caxton/testing/_spec.py +631 -0
  138. caxton-0.1.0/src/caxton/testing/_xlsx.py +186 -0
  139. caxton-0.1.0/src/caxton/testing/strategies.py +160 -0
  140. caxton-0.1.0/tests/test_benchmark_data_sources.py +78 -0
  141. caxton-0.1.0/tests/test_benchmark_grouping.py +160 -0
  142. caxton-0.1.0/tests/test_benchmark_grouping_scaling.py +184 -0
  143. caxton-0.1.0/tests/test_benchmark_openpyxl.py +191 -0
  144. caxton-0.1.0/tests/test_coordinates.py +17 -0
  145. caxton-0.1.0/tests/test_data_sources.py +218 -0
  146. caxton-0.1.0/tests/test_errors.py +127 -0
  147. caxton-0.1.0/tests/test_formulas.py +374 -0
  148. caxton-0.1.0/tests/test_grouping.py +736 -0
  149. caxton-0.1.0/tests/test_grouping_coverage.py +72 -0
  150. caxton-0.1.0/tests/test_grouping_regressions.py +318 -0
  151. caxton-0.1.0/tests/test_package.py +87 -0
  152. caxton-0.1.0/tests/test_rendering.py +455 -0
  153. caxton-0.1.0/tests/test_semantic_evaluator.py +305 -0
  154. caxton-0.1.0/tests/test_semantic_model.py +196 -0
  155. caxton-0.1.0/tests/test_semantic_types.py +82 -0
  156. caxton-0.1.0/tests/test_snapshots.py +87 -0
  157. caxton-0.1.0/tests/test_spreadsheet_blocks.py +294 -0
  158. caxton-0.1.0/tests/test_spreadsheet_compiler.py +213 -0
  159. caxton-0.1.0/tests/test_spreadsheet_features.py +498 -0
  160. caxton-0.1.0/tests/test_strategies.py +17 -0
  161. caxton-0.1.0/tests/test_streaming.py +251 -0
  162. caxton-0.1.0/tests/test_templates.py +359 -0
  163. caxton-0.1.0/tests/test_testing_api.py +429 -0
  164. caxton-0.1.0/tests/test_xlsx_template_package.py +85 -0
  165. caxton-0.1.0/tests/types/data_source.py +31 -0
  166. caxton-0.1.0/tests/types/formulas.py +23 -0
  167. caxton-0.1.0/tests/types/grouping.py +16 -0
  168. caxton-0.1.0/tests/types/row_accessor.py +13 -0
  169. caxton-0.1.0/tests/types/spreadsheet_features.py +37 -0
  170. caxton-0.1.0/tests/types/templates.py +20 -0
@@ -0,0 +1,55 @@
1
+ # Byte-compiled files and caches
2
+ __pycache__/
3
+ *.py[cod]
4
+ .pytest_cache/
5
+ .mypy_cache/
6
+ .ruff_cache/
7
+ .tox/
8
+
9
+ # Environments
10
+ .venv/
11
+ venv/
12
+
13
+ # Distribution / packaging
14
+ .Python
15
+ build/
16
+ develop-eggs/
17
+ dist/
18
+ downloads/
19
+ eggs/
20
+ .eggs/
21
+ lib/
22
+ lib64/
23
+ parts/
24
+ sdist/
25
+ var/
26
+ wheels/
27
+ share/python-wheels/
28
+ *.egg-info/
29
+ .installed.cfg
30
+ *.egg
31
+ MANIFEST
32
+
33
+ # PyInstaller
34
+ # Usually these files are written by a python script from a template
35
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
36
+ *.manifest
37
+ *.spec
38
+
39
+ # Documentation
40
+ site/
41
+ .cache/
42
+
43
+ # Coverage
44
+ .coverage
45
+ coverage/
46
+ coverage.xml
47
+ htmlcov/
48
+
49
+ # IDE and operating system files
50
+ .idea/
51
+ .vscode/
52
+ .DS_Store
53
+
54
+ backend/stations.sqlite3
55
+ **/output/**
@@ -0,0 +1,27 @@
1
+ # Changelog
2
+
3
+ <!-- towncrier release notes start -->
4
+
5
+ ## [0.1.0] - 2026-08-19
6
+
7
+ ### Features
8
+
9
+ - Add public spreadsheet API with data-source ingestion, semantic types, references, validation, styles, formulas,
10
+ streaming, and direct XLSX output ([#2](https://github.com/dzhalaevd/caxton/issues/2))
11
+ - Add declarative spreadsheet blocks: `title`, `spacer`, `image`, `chart` and the `stack` flow container.
12
+ A sheet now places its blocks sequentially without manual `start_row` arithmetic, explicit `anchor` stays
13
+ available as a layout escape hatch, overlapping placed blocks are rejected during validation, and the
14
+ XlsxWriter backend lowers titles, images and the supported chart
15
+ kinds. ([#3](https://github.com/dzhalaevd/caxton/issues/3))
16
+ - Add grouped reports and pivot matrices with flexible aggregates, typed keys,
17
+ and single-pass buffering. Enforce XLSX bounds and avoid dense sparse
18
+ materialization. ([#4](https://github.com/dzhalaevd/caxton/issues/4))
19
+ - Add a format-independent template specification and a dedicated XLSX template
20
+ route with named-range table targets, styled block repetition, OpenPyXL hooks,
21
+ and pivot package post-processing. ([#5](https://github.com/dzhalaevd/caxton/issues/5))
22
+
23
+ ### Documentation
24
+
25
+ - Added a MkDocs documentation site with a Material theme and a mkdocstrings API
26
+ reference, a `docs` dependency group, `docs` and `docs-serve` tox environments, and a
27
+ GitHub Pages deployment workflow that builds with `--strict`. ([#6](https://github.com/dzhalaevd/caxton/issues/6))
caxton-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 David Dzhalaev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
caxton-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,145 @@
1
+ Metadata-Version: 2.5
2
+ Name: caxton
3
+ Version: 0.1.0
4
+ Summary: A declarative way to describe files in Python
5
+ Project-URL: Homepage, https://github.com/dzhalaevd/caxton
6
+ Project-URL: Repository, https://github.com/dzhalaevd/caxton
7
+ Project-URL: Issues, https://github.com/dzhalaevd/caxton/issues
8
+ Author: David Dzhalaev
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: declarative,files,validation
12
+ Classifier: Development Status :: 2 - Pre-Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Typing :: Typed
20
+ Requires-Python: >=3.11
21
+ Requires-Dist: openpyxl<4.0,>=3.1.5
22
+ Requires-Dist: xlsxwriter<4.0,>=3.2.9
23
+ Provides-Extra: hypothesis
24
+ Requires-Dist: hypothesis<7.0,>=6.165; extra == 'hypothesis'
25
+ Description-Content-Type: text/markdown
26
+
27
+ <div align="center">
28
+
29
+ # Caxton
30
+
31
+ **Declarative document generation for Python**
32
+
33
+ [![Contributors][contributors-shield]][contributors-url]
34
+ [![Forks][forks-shield]][forks-url]
35
+ [![Stars][stars-shield]][stars-url]
36
+ [![Issues][issues-shield]][issues-url]
37
+
38
+ </div>
39
+
40
+ ---
41
+
42
+ | 🏗️ This project is currently under development and is **not ready for production use**. |
43
+ |------------------------------------------------------------------------------------------|
44
+
45
+ ## :mag: About
46
+
47
+ Declarative Python library for describing and generating documents
48
+ from application data. Users define the document structure and semantics, while
49
+ renderers handle output formats and backend-specific details.
50
+
51
+ ## :alembic: Built With
52
+
53
+ ![Python][python-shield]
54
+ ![Excel][excel-shield]
55
+ ![uv][uv-shield]
56
+ ![wps][wemake-shield]
57
+
58
+ ## Quick start
59
+
60
+ ```python
61
+ from caxton import render, sheet, spreadsheet, table, text, write
62
+
63
+ rows = [{"name": "Ada Lovelace"}, {"name": "Grace Hopper"}]
64
+
65
+ report = spreadsheet(
66
+ sheet(
67
+ "People",
68
+ table(
69
+ rows,
70
+ text("name").titled("Name"),
71
+ ),
72
+ ),
73
+ )
74
+
75
+ result = render(report)
76
+
77
+ write(report, "people.xlsx")
78
+ ```
79
+
80
+ More examples are available in the [example projects](example).
81
+
82
+ ## :books: Documentation
83
+
84
+ Full documentation is at [dzhalaevd.github.io/caxton](https://dzhalaevd.github.io/caxton/).
85
+
86
+ ## :scroll: Licensing
87
+
88
+ - The project is licensed under the [MIT](LICENSE)
89
+
90
+ <div align="center">
91
+
92
+ ### Works on Open-Source
93
+
94
+ If you find this project interesting, consider giving it a ⭐
95
+
96
+ </div>
97
+
98
+
99
+ [contributors-shield]: https://img.shields.io/github/contributors/dzhalaevd/caxton.svg?style=for-the-badge
100
+
101
+ [contributors-url]: https://github.com/dzhalaevd/caxton/graphs/contributors
102
+
103
+ [forks-shield]: https://img.shields.io/github/forks/dzhalaevd/caxton.svg?style=for-the-badge
104
+
105
+ [forks-url]: https://github.com/dzhalaevd/caxton/network/members
106
+
107
+ [stars-shield]: https://img.shields.io/github/stars/dzhalaevd/caxton.svg?style=for-the-badge
108
+
109
+ [stars-url]: https://github.com/dzhalaevd/caxton/stargazers
110
+
111
+ [issues-shield]: https://img.shields.io/github/issues/dzhalaevd/caxton.svg?style=for-the-badge
112
+
113
+ [issues-url]: https://github.com/dzhalaevd/caxton/issues
114
+
115
+ [python-shield]: https://img.shields.io/badge/python-3670A0?style=for-the-badge&logo=python&logoColor=ffdd54
116
+
117
+ [uv-shield]: https://img.shields.io/badge/uv-%23DE5FE9.svg?style=for-the-badge&logo=uv&logoColor=white
118
+
119
+ [fastapi-shield]: https://img.shields.io/badge/FastAPI-005571.svg?style=for-the-badge&logo=fastapi
120
+
121
+ [sqlalchemy-shield]: https://img.shields.io/badge/sqlalchemy-%23D71F00.svg?style=for-the-badge&logo=sqlalchemy&logoColor=white
122
+
123
+ [pytest-shield]: https://img.shields.io/badge/pytest-%23ffffff.svg?style=for-the-badge&logo=pytest&logoColor=2f9fe3
124
+
125
+ [telegram-shield]: https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge&logo=telegram&logoColor=white
126
+
127
+ [react-shield]: https://img.shields.io/badge/react-%2320232a.svg?style=for-the-badge&logo=react&logoColor=%2361DAFB
128
+
129
+ [typescript-shield]: https://img.shields.io/badge/typescript-%23007ACC.svg?style=for-the-badge&logo=typescript&logoColor=white
130
+
131
+ [vite-shield]: https://img.shields.io/badge/vite-%23646CFF.svg?style=for-the-badge&logo=vite&logoColor=white
132
+
133
+ [postgres-shield]: https://img.shields.io/badge/postgres-%23316192.svg?style=for-the-badge&logo=postgresql&logoColor=white
134
+
135
+ [otel-shield]: https://img.shields.io/badge/OpenTelemetry-FFFFFF?style=for-the-badge&logo=opentelemetry&logoColor=black
136
+
137
+ [grafana-shield]: https://img.shields.io/badge/grafana-%23F46800.svg?style=for-the-badge&logo=grafana&logoColor=white
138
+
139
+ [prometheus-shield]: https://img.shields.io/badge/Prometheus-E6522C?style=for-the-badge&logo=Prometheus&logoColor=white
140
+
141
+ [docker-shield]: https://img.shields.io/badge/docker-%230db7ed.svg?style=for-the-badge&logo=docker&logoColor=white
142
+
143
+ [wemake-shield]: https://img.shields.io/badge/Style_WPS-%23000000.svg?style=for-the-badge&logo=python&logoColor=white
144
+
145
+ [excel-shield]: https://img.shields.io/badge/Microsoft_Excel-217346?style=for-the-badge&logo=microsoft-excel&logoColor=white
caxton-0.1.0/README.md ADDED
@@ -0,0 +1,119 @@
1
+ <div align="center">
2
+
3
+ # Caxton
4
+
5
+ **Declarative document generation for Python**
6
+
7
+ [![Contributors][contributors-shield]][contributors-url]
8
+ [![Forks][forks-shield]][forks-url]
9
+ [![Stars][stars-shield]][stars-url]
10
+ [![Issues][issues-shield]][issues-url]
11
+
12
+ </div>
13
+
14
+ ---
15
+
16
+ | 🏗️ This project is currently under development and is **not ready for production use**. |
17
+ |------------------------------------------------------------------------------------------|
18
+
19
+ ## :mag: About
20
+
21
+ Declarative Python library for describing and generating documents
22
+ from application data. Users define the document structure and semantics, while
23
+ renderers handle output formats and backend-specific details.
24
+
25
+ ## :alembic: Built With
26
+
27
+ ![Python][python-shield]
28
+ ![Excel][excel-shield]
29
+ ![uv][uv-shield]
30
+ ![wps][wemake-shield]
31
+
32
+ ## Quick start
33
+
34
+ ```python
35
+ from caxton import render, sheet, spreadsheet, table, text, write
36
+
37
+ rows = [{"name": "Ada Lovelace"}, {"name": "Grace Hopper"}]
38
+
39
+ report = spreadsheet(
40
+ sheet(
41
+ "People",
42
+ table(
43
+ rows,
44
+ text("name").titled("Name"),
45
+ ),
46
+ ),
47
+ )
48
+
49
+ result = render(report)
50
+
51
+ write(report, "people.xlsx")
52
+ ```
53
+
54
+ More examples are available in the [example projects](example).
55
+
56
+ ## :books: Documentation
57
+
58
+ Full documentation is at [dzhalaevd.github.io/caxton](https://dzhalaevd.github.io/caxton/).
59
+
60
+ ## :scroll: Licensing
61
+
62
+ - The project is licensed under the [MIT](LICENSE)
63
+
64
+ <div align="center">
65
+
66
+ ### Works on Open-Source
67
+
68
+ If you find this project interesting, consider giving it a ⭐
69
+
70
+ </div>
71
+
72
+
73
+ [contributors-shield]: https://img.shields.io/github/contributors/dzhalaevd/caxton.svg?style=for-the-badge
74
+
75
+ [contributors-url]: https://github.com/dzhalaevd/caxton/graphs/contributors
76
+
77
+ [forks-shield]: https://img.shields.io/github/forks/dzhalaevd/caxton.svg?style=for-the-badge
78
+
79
+ [forks-url]: https://github.com/dzhalaevd/caxton/network/members
80
+
81
+ [stars-shield]: https://img.shields.io/github/stars/dzhalaevd/caxton.svg?style=for-the-badge
82
+
83
+ [stars-url]: https://github.com/dzhalaevd/caxton/stargazers
84
+
85
+ [issues-shield]: https://img.shields.io/github/issues/dzhalaevd/caxton.svg?style=for-the-badge
86
+
87
+ [issues-url]: https://github.com/dzhalaevd/caxton/issues
88
+
89
+ [python-shield]: https://img.shields.io/badge/python-3670A0?style=for-the-badge&logo=python&logoColor=ffdd54
90
+
91
+ [uv-shield]: https://img.shields.io/badge/uv-%23DE5FE9.svg?style=for-the-badge&logo=uv&logoColor=white
92
+
93
+ [fastapi-shield]: https://img.shields.io/badge/FastAPI-005571.svg?style=for-the-badge&logo=fastapi
94
+
95
+ [sqlalchemy-shield]: https://img.shields.io/badge/sqlalchemy-%23D71F00.svg?style=for-the-badge&logo=sqlalchemy&logoColor=white
96
+
97
+ [pytest-shield]: https://img.shields.io/badge/pytest-%23ffffff.svg?style=for-the-badge&logo=pytest&logoColor=2f9fe3
98
+
99
+ [telegram-shield]: https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge&logo=telegram&logoColor=white
100
+
101
+ [react-shield]: https://img.shields.io/badge/react-%2320232a.svg?style=for-the-badge&logo=react&logoColor=%2361DAFB
102
+
103
+ [typescript-shield]: https://img.shields.io/badge/typescript-%23007ACC.svg?style=for-the-badge&logo=typescript&logoColor=white
104
+
105
+ [vite-shield]: https://img.shields.io/badge/vite-%23646CFF.svg?style=for-the-badge&logo=vite&logoColor=white
106
+
107
+ [postgres-shield]: https://img.shields.io/badge/postgres-%23316192.svg?style=for-the-badge&logo=postgresql&logoColor=white
108
+
109
+ [otel-shield]: https://img.shields.io/badge/OpenTelemetry-FFFFFF?style=for-the-badge&logo=opentelemetry&logoColor=black
110
+
111
+ [grafana-shield]: https://img.shields.io/badge/grafana-%23F46800.svg?style=for-the-badge&logo=grafana&logoColor=white
112
+
113
+ [prometheus-shield]: https://img.shields.io/badge/Prometheus-E6522C?style=for-the-badge&logo=Prometheus&logoColor=white
114
+
115
+ [docker-shield]: https://img.shields.io/badge/docker-%230db7ed.svg?style=for-the-badge&logo=docker&logoColor=white
116
+
117
+ [wemake-shield]: https://img.shields.io/badge/Style_WPS-%23000000.svg?style=for-the-badge&logo=python&logoColor=white
118
+
119
+ [excel-shield]: https://img.shields.io/badge/Microsoft_Excel-217346?style=for-the-badge&logo=microsoft-excel&logoColor=white
@@ -0,0 +1,35 @@
1
+ # Changelog fragments
2
+
3
+ Towncrier reads release notes from this directory and renders them into
4
+ `CHANGELOG.md`.
5
+
6
+ Create one fragment per change:
7
+
8
+ ```text
9
+ <issue-id>.<type>.md
10
+ ```
11
+
12
+ Supported types are `breaking`, `feature`, `bugfix`, `doc`, `generation` and
13
+ `ci`. For example: `123.feature.md`.
14
+
15
+ Create a fragment with Towncrier:
16
+
17
+ ```bash
18
+ hatch run towncrier create --content "Describe the user-visible change." 123.feature.md
19
+ ```
20
+
21
+ Use a GitHub issue or pull request number when one exists. Otherwise, prefix a
22
+ short unique identifier with `+`, for example `+typing.bugfix.md`.
23
+
24
+ Preview the next changelog entry without modifying files:
25
+
26
+ ```bash
27
+ hatch run changelog-draft
28
+ ```
29
+
30
+ Build the changelog during a release, using the version from
31
+ `src/caxton/__version__.py`:
32
+
33
+ ```bash
34
+ hatch run changelog-build "$(hatch version)"
35
+ ```
@@ -0,0 +1,239 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.31,<2.0"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "caxton"
7
+ dynamic = ["version"]
8
+ description = "A declarative way to describe files in Python"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = "MIT"
12
+ authors = [
13
+ { name = "David Dzhalaev" },
14
+ ]
15
+ keywords = ["files", "declarative", "validation"]
16
+ classifiers = [
17
+ "Development Status :: 2 - Pre-Alpha",
18
+ "Intended Audience :: Developers",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.11",
21
+ "Programming Language :: Python :: 3.12",
22
+ "Programming Language :: Python :: 3.13",
23
+ "Programming Language :: Python :: 3.14",
24
+ "Typing :: Typed",
25
+ ]
26
+ dependencies = [
27
+ "xlsxwriter>=3.2.9,<4.0",
28
+ "openpyxl>=3.1.5,<4.0",
29
+ ]
30
+
31
+ [project.optional-dependencies]
32
+ hypothesis = ["hypothesis>=6.165,<7.0"]
33
+
34
+ [project.urls]
35
+ Homepage = "https://github.com/dzhalaevd/caxton"
36
+ Repository = "https://github.com/dzhalaevd/caxton"
37
+ Issues = "https://github.com/dzhalaevd/caxton/issues"
38
+
39
+ [tool.hatch.version]
40
+ path = "src/caxton/__version__.py"
41
+
42
+ [tool.hatch.build.targets.wheel]
43
+ packages = ["src/caxton"]
44
+
45
+ [tool.hatch.build.targets.sdist]
46
+ include = [
47
+ "/LICENSE",
48
+ "/CHANGELOG.md",
49
+ "/README.md",
50
+ "/changelog.d",
51
+ "/pyproject.toml",
52
+ "/setup.cfg",
53
+ "/scripts",
54
+ "/src",
55
+ "/tests",
56
+ ]
57
+
58
+ [tool.hatch.envs.default]
59
+ dependency-groups = ["dev"]
60
+
61
+ [tool.hatch.envs.default.scripts]
62
+ lint = "flake8 ."
63
+ typecheck = "mypy"
64
+ test = "pytest {args:tests}"
65
+ docs = "mkdocs build --strict"
66
+ docs-serve = "mkdocs serve {args}"
67
+ api-compatibility = "griffe check --search src caxton {args}"
68
+ check = [
69
+ "flake8 .",
70
+ "mypy",
71
+ "pytest",
72
+ "towncrier build --draft",
73
+ ]
74
+ changelog-draft = "towncrier build --draft"
75
+ changelog-build = "towncrier build --yes --version {args}"
76
+ validate-changelog = "python scripts/validate_files.py {args}"
77
+ bump-version = "python scripts/bump_version.py {args}"
78
+
79
+ [tool.pytest.ini_options]
80
+ addopts = "-ra"
81
+ testpaths = ["tests"]
82
+
83
+ [tool.coverage.run]
84
+ branch = true
85
+ source = ["caxton"]
86
+
87
+ [tool.coverage.paths]
88
+ source = [
89
+ "src/caxton",
90
+ "*/.tox/*/lib/python*/site-packages/caxton",
91
+ "*/.tox/*/Lib/site-packages/caxton",
92
+ "*\\.tox\\*\\Lib\\site-packages\\caxton",
93
+ ]
94
+
95
+ [tool.coverage.report]
96
+ fail_under = 85
97
+ show_missing = true
98
+
99
+ [tool.deptry]
100
+ known_first_party = ["caxton"]
101
+
102
+ [tool.importlinter]
103
+ root_packages = ["caxton"]
104
+
105
+ [[tool.importlinter.contracts]]
106
+ name = "Core does not depend on orchestration"
107
+ type = "forbidden"
108
+ source_modules = ["caxton.core"]
109
+ forbidden_modules = [
110
+ "caxton.api",
111
+ "caxton._internal",
112
+ "caxton.testing",
113
+ ]
114
+
115
+ [[tool.importlinter.contracts]]
116
+ name = "Internal implementation does not depend on public API"
117
+ type = "forbidden"
118
+ source_modules = ["caxton._internal"]
119
+ forbidden_modules = ["caxton.api"]
120
+
121
+ [[tool.importlinter.contracts]]
122
+ name = "Internal spreadsheet pipeline is layered"
123
+ type = "layers"
124
+ layers = [
125
+ "caxton._internal.compiler",
126
+ "caxton._internal.validation",
127
+ "caxton._internal.layout",
128
+ "caxton._internal.aggregation",
129
+ "caxton._internal.semantic",
130
+ "caxton._internal.data",
131
+ ]
132
+
133
+ [[tool.importlinter.contracts]]
134
+ name = "Bundled XLSX backends are independent"
135
+ type = "independence"
136
+ modules = [
137
+ "caxton._internal.backends.openpyxl",
138
+ "caxton._internal.backends.xlsxwriter",
139
+ ]
140
+
141
+ [dependency-groups]
142
+ build = [
143
+ "twine>=7.0,<8.0",
144
+ ]
145
+ coverage = [
146
+ "coverage>=7.15,<8.0",
147
+ ]
148
+ dependencies = [
149
+ "deptry>=0.25.1,<0.26",
150
+ ]
151
+ docs = [
152
+ "hypothesis>=6.165,<7.0",
153
+ "mkdocs>=1.6,<2.0",
154
+ "mkdocs-material>=9.7,<10.0",
155
+ "mkdocstrings[python]>=1.0,<2.0",
156
+ ]
157
+ imports = [
158
+ "import-linter>=2.13,<3.0",
159
+ ]
160
+ lint = [
161
+ "flake8>=7.3,<8.0",
162
+ "ruff>=0.16,<0.17",
163
+ "wemake-python-styleguide>=1.7,<2.0",
164
+ ]
165
+ maintenance = [
166
+ "griffe>=2.1,<3.0",
167
+ "hatch>=1.17,<2.0",
168
+ "pip>=25,<27",
169
+ "towncrier>=25.8,<26.0",
170
+ ]
171
+ pre-commit = [
172
+ "pre-commit>=4.6.1,<5.0",
173
+ ]
174
+ test = [
175
+ "hypothesis>=6.165,<7.0",
176
+ "pytest>=9.1,<10.0",
177
+ "pytest-benchmark>=5.2,<6.0",
178
+ "pytest-cov>=7.1,<8.0",
179
+ ]
180
+ tox = [
181
+ "tox>=4.52.1,<5.0",
182
+ "tox-uv>=1.29,<2.0",
183
+ ]
184
+ typecheck = [
185
+ "mypy>=2.3,<3.0",
186
+ "types-openpyxl>=3.1.5.20260518,<3.2",
187
+ ]
188
+ dev = [
189
+ { include-group = "build" },
190
+ { include-group = "coverage" },
191
+ { include-group = "dependencies" },
192
+ { include-group = "docs" },
193
+ { include-group = "imports" },
194
+ { include-group = "lint" },
195
+ { include-group = "maintenance" },
196
+ { include-group = "pre-commit" },
197
+ { include-group = "test" },
198
+ { include-group = "tox" },
199
+ { include-group = "typecheck" },
200
+ ]
201
+
202
+ [tool.towncrier]
203
+ directory = "changelog.d"
204
+ filename = "CHANGELOG.md"
205
+ issue_format = "[#{issue}](https://github.com/dzhalaevd/caxton/issues/{issue})"
206
+ orphan_prefix = "+"
207
+ start_string = "<!-- towncrier release notes start -->\n"
208
+ title_format = "## [{version}] - {project_date}"
209
+ underlines = ["", "", ""]
210
+
211
+ [[tool.towncrier.type]]
212
+ directory = "breaking"
213
+ name = "Breaking changes"
214
+ showcontent = true
215
+
216
+ [[tool.towncrier.type]]
217
+ directory = "feature"
218
+ name = "Features"
219
+ showcontent = true
220
+
221
+ [[tool.towncrier.type]]
222
+ directory = "bugfix"
223
+ name = "Bug fixes"
224
+ showcontent = true
225
+
226
+ [[tool.towncrier.type]]
227
+ directory = "doc"
228
+ name = "Documentation"
229
+ showcontent = true
230
+
231
+ [[tool.towncrier.type]]
232
+ directory = "generation"
233
+ name = "Code generation"
234
+ showcontent = true
235
+
236
+ [[tool.towncrier.type]]
237
+ directory = "ci"
238
+ name = "CI and tooling"
239
+ showcontent = true