pycharter 0.0.22__py3-none-any.whl → 0.0.24__py3-none-any.whl

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 (404) hide show
  1. api/main.py +27 -1
  2. api/models/docs.py +68 -0
  3. api/models/evolution.py +117 -0
  4. api/models/tracking.py +111 -0
  5. api/models/validation.py +46 -6
  6. api/routes/v1/__init__.py +14 -1
  7. api/routes/v1/docs.py +187 -0
  8. api/routes/v1/evolution.py +337 -0
  9. api/routes/v1/templates.py +211 -27
  10. api/routes/v1/tracking.py +301 -0
  11. api/routes/v1/validation.py +68 -31
  12. pycharter/__init__.py +268 -58
  13. pycharter/data/templates/contract/template_coercion_rules.yaml +57 -0
  14. pycharter/data/templates/contract/template_contract.yaml +122 -0
  15. pycharter/data/templates/contract/template_metadata.yaml +68 -0
  16. pycharter/data/templates/contract/template_schema.yaml +100 -0
  17. pycharter/data/templates/contract/template_validation_rules.yaml +75 -0
  18. pycharter/data/templates/etl/README.md +224 -0
  19. pycharter/data/templates/etl/extract_cloud_azure.yaml +24 -0
  20. pycharter/data/templates/etl/extract_cloud_gcs.yaml +25 -0
  21. pycharter/data/templates/etl/extract_cloud_s3.yaml +30 -0
  22. pycharter/data/templates/etl/extract_database.yaml +34 -0
  23. pycharter/data/templates/etl/extract_database_ssh.yaml +40 -0
  24. pycharter/data/templates/etl/extract_file_csv.yaml +21 -0
  25. pycharter/data/templates/etl/extract_file_glob.yaml +25 -0
  26. pycharter/data/templates/etl/extract_file_json.yaml +24 -0
  27. pycharter/data/templates/etl/extract_file_parquet.yaml +20 -0
  28. pycharter/data/templates/etl/extract_http_paginated.yaml +79 -0
  29. pycharter/data/templates/etl/extract_http_path_params.yaml +38 -0
  30. pycharter/data/templates/etl/extract_http_simple.yaml +62 -0
  31. pycharter/data/templates/etl/load_cloud_azure.yaml +24 -0
  32. pycharter/data/templates/etl/load_cloud_gcs.yaml +22 -0
  33. pycharter/data/templates/etl/load_cloud_s3.yaml +27 -0
  34. pycharter/data/templates/etl/load_file.yaml +34 -0
  35. pycharter/data/templates/etl/load_insert.yaml +18 -0
  36. pycharter/data/templates/etl/load_postgresql.yaml +39 -0
  37. pycharter/data/templates/etl/load_sqlite.yaml +21 -0
  38. pycharter/data/templates/etl/load_truncate_and_load.yaml +20 -0
  39. pycharter/data/templates/etl/load_upsert.yaml +25 -0
  40. pycharter/data/templates/etl/load_with_dlq.yaml +34 -0
  41. pycharter/data/templates/etl/load_with_ssh_tunnel.yaml +35 -0
  42. pycharter/data/templates/etl/pipeline_http_to_db.yaml +75 -0
  43. pycharter/data/templates/etl/transform_combined.yaml +48 -0
  44. pycharter/data/templates/etl/transform_custom_function.yaml +58 -0
  45. pycharter/data/templates/etl/transform_jsonata.yaml +51 -0
  46. pycharter/data/templates/etl/transform_simple.yaml +59 -0
  47. pycharter/db/schemas/.ipynb_checkpoints/data_contract-checkpoint.py +160 -0
  48. pycharter/docs_generator/__init__.py +43 -0
  49. pycharter/docs_generator/generator.py +465 -0
  50. pycharter/docs_generator/renderers.py +247 -0
  51. pycharter/etl_generator/__init__.py +168 -80
  52. pycharter/etl_generator/builder.py +121 -0
  53. pycharter/etl_generator/config_loader.py +394 -0
  54. pycharter/etl_generator/config_validator.py +418 -0
  55. pycharter/etl_generator/context.py +132 -0
  56. pycharter/etl_generator/expression.py +499 -0
  57. pycharter/etl_generator/extractors/__init__.py +30 -0
  58. pycharter/etl_generator/extractors/base.py +70 -0
  59. pycharter/etl_generator/extractors/cloud_storage.py +530 -0
  60. pycharter/etl_generator/extractors/database.py +221 -0
  61. pycharter/etl_generator/extractors/factory.py +185 -0
  62. pycharter/etl_generator/extractors/file.py +475 -0
  63. pycharter/etl_generator/extractors/http.py +895 -0
  64. pycharter/etl_generator/extractors/streaming.py +57 -0
  65. pycharter/etl_generator/loaders/__init__.py +41 -0
  66. pycharter/etl_generator/loaders/base.py +35 -0
  67. pycharter/etl_generator/loaders/cloud.py +87 -0
  68. pycharter/etl_generator/loaders/cloud_storage_loader.py +275 -0
  69. pycharter/etl_generator/loaders/database.py +274 -0
  70. pycharter/etl_generator/loaders/factory.py +180 -0
  71. pycharter/etl_generator/loaders/file.py +72 -0
  72. pycharter/etl_generator/loaders/file_loader.py +130 -0
  73. pycharter/etl_generator/pipeline.py +743 -0
  74. pycharter/etl_generator/protocols.py +54 -0
  75. pycharter/etl_generator/result.py +63 -0
  76. pycharter/etl_generator/schemas/__init__.py +49 -0
  77. pycharter/etl_generator/transformers/__init__.py +49 -0
  78. pycharter/etl_generator/transformers/base.py +63 -0
  79. pycharter/etl_generator/transformers/config.py +45 -0
  80. pycharter/etl_generator/transformers/custom_function.py +101 -0
  81. pycharter/etl_generator/transformers/jsonata_transformer.py +56 -0
  82. pycharter/etl_generator/transformers/operations.py +218 -0
  83. pycharter/etl_generator/transformers/pipeline.py +54 -0
  84. pycharter/etl_generator/transformers/simple_operations.py +131 -0
  85. pycharter/quality/__init__.py +25 -0
  86. pycharter/quality/tracking/__init__.py +64 -0
  87. pycharter/quality/tracking/collector.py +318 -0
  88. pycharter/quality/tracking/exporters.py +238 -0
  89. pycharter/quality/tracking/models.py +194 -0
  90. pycharter/quality/tracking/store.py +385 -0
  91. pycharter/runtime_validator/__init__.py +20 -7
  92. pycharter/runtime_validator/builder.py +328 -0
  93. pycharter/runtime_validator/validator.py +311 -7
  94. pycharter/runtime_validator/validator_core.py +61 -0
  95. pycharter/schema_evolution/__init__.py +61 -0
  96. pycharter/schema_evolution/compatibility.py +270 -0
  97. pycharter/schema_evolution/diff.py +496 -0
  98. pycharter/schema_evolution/models.py +201 -0
  99. pycharter/shared/__init__.py +56 -0
  100. pycharter/shared/errors.py +296 -0
  101. pycharter/shared/protocols.py +234 -0
  102. {pycharter-0.0.22.dist-info → pycharter-0.0.24.dist-info}/METADATA +146 -26
  103. pycharter-0.0.24.dist-info/RECORD +543 -0
  104. {pycharter-0.0.22.dist-info → pycharter-0.0.24.dist-info}/WHEEL +1 -1
  105. ui/static/404/index.html +1 -1
  106. ui/static/404.html +1 -1
  107. ui/static/__next.__PAGE__.txt +1 -1
  108. ui/static/__next._full.txt +1 -1
  109. ui/static/__next._head.txt +1 -1
  110. ui/static/__next._index.txt +1 -1
  111. ui/static/__next._tree.txt +1 -1
  112. ui/static/_next/static/chunks/26dfc590f7714c03.js +1 -0
  113. ui/static/_next/static/chunks/34d289e6db2ef551.js +1 -0
  114. ui/static/_next/static/chunks/99508d9d5869cc27.js +1 -0
  115. ui/static/_next/static/chunks/b313c35a6ba76574.js +1 -0
  116. ui/static/_not-found/__next._full.txt +1 -1
  117. ui/static/_not-found/__next._head.txt +1 -1
  118. ui/static/_not-found/__next._index.txt +1 -1
  119. ui/static/_not-found/__next._not-found.__PAGE__.txt +1 -1
  120. ui/static/_not-found/__next._not-found.txt +1 -1
  121. ui/static/_not-found/__next._tree.txt +1 -1
  122. ui/static/_not-found/index.html +1 -1
  123. ui/static/_not-found/index.txt +1 -1
  124. ui/static/contracts/__next._full.txt +2 -2
  125. ui/static/contracts/__next._head.txt +1 -1
  126. ui/static/contracts/__next._index.txt +1 -1
  127. ui/static/contracts/__next._tree.txt +1 -1
  128. ui/static/contracts/__next.contracts.__PAGE__.txt +2 -2
  129. ui/static/contracts/__next.contracts.txt +1 -1
  130. ui/static/contracts/index.html +1 -1
  131. ui/static/contracts/index.txt +2 -2
  132. ui/static/documentation/__next._full.txt +1 -1
  133. ui/static/documentation/__next._head.txt +1 -1
  134. ui/static/documentation/__next._index.txt +1 -1
  135. ui/static/documentation/__next._tree.txt +1 -1
  136. ui/static/documentation/__next.documentation.__PAGE__.txt +1 -1
  137. ui/static/documentation/__next.documentation.txt +1 -1
  138. ui/static/documentation/index.html +2 -2
  139. ui/static/documentation/index.txt +1 -1
  140. ui/static/index.html +1 -1
  141. ui/static/index.txt +1 -1
  142. ui/static/metadata/__next._full.txt +1 -1
  143. ui/static/metadata/__next._head.txt +1 -1
  144. ui/static/metadata/__next._index.txt +1 -1
  145. ui/static/metadata/__next._tree.txt +1 -1
  146. ui/static/metadata/__next.metadata.__PAGE__.txt +1 -1
  147. ui/static/metadata/__next.metadata.txt +1 -1
  148. ui/static/metadata/index.html +1 -1
  149. ui/static/metadata/index.txt +1 -1
  150. ui/static/quality/__next._full.txt +2 -2
  151. ui/static/quality/__next._head.txt +1 -1
  152. ui/static/quality/__next._index.txt +1 -1
  153. ui/static/quality/__next._tree.txt +1 -1
  154. ui/static/quality/__next.quality.__PAGE__.txt +2 -2
  155. ui/static/quality/__next.quality.txt +1 -1
  156. ui/static/quality/index.html +2 -2
  157. ui/static/quality/index.txt +2 -2
  158. ui/static/rules/__next._full.txt +1 -1
  159. ui/static/rules/__next._head.txt +1 -1
  160. ui/static/rules/__next._index.txt +1 -1
  161. ui/static/rules/__next._tree.txt +1 -1
  162. ui/static/rules/__next.rules.__PAGE__.txt +1 -1
  163. ui/static/rules/__next.rules.txt +1 -1
  164. ui/static/rules/index.html +1 -1
  165. ui/static/rules/index.txt +1 -1
  166. ui/static/schemas/__next._full.txt +1 -1
  167. ui/static/schemas/__next._head.txt +1 -1
  168. ui/static/schemas/__next._index.txt +1 -1
  169. ui/static/schemas/__next._tree.txt +1 -1
  170. ui/static/schemas/__next.schemas.__PAGE__.txt +1 -1
  171. ui/static/schemas/__next.schemas.txt +1 -1
  172. ui/static/schemas/index.html +1 -1
  173. ui/static/schemas/index.txt +1 -1
  174. ui/static/settings/__next._full.txt +1 -1
  175. ui/static/settings/__next._head.txt +1 -1
  176. ui/static/settings/__next._index.txt +1 -1
  177. ui/static/settings/__next._tree.txt +1 -1
  178. ui/static/settings/__next.settings.__PAGE__.txt +1 -1
  179. ui/static/settings/__next.settings.txt +1 -1
  180. ui/static/settings/index.html +1 -1
  181. ui/static/settings/index.txt +1 -1
  182. ui/static/static/404/index.html +1 -1
  183. ui/static/static/404.html +1 -1
  184. ui/static/static/__next.__PAGE__.txt +1 -1
  185. ui/static/static/__next._full.txt +2 -2
  186. ui/static/static/__next._head.txt +1 -1
  187. ui/static/static/__next._index.txt +2 -2
  188. ui/static/static/__next._tree.txt +2 -2
  189. ui/static/static/_next/static/chunks/13d4a0fbd74c1ee4.js +1 -0
  190. ui/static/static/_next/static/chunks/2edb43b48432ac04.js +441 -0
  191. ui/static/static/_next/static/chunks/d2363397e1b2bcab.css +1 -0
  192. ui/static/static/_next/static/chunks/f7d1a90dd75d2572.js +1 -0
  193. ui/static/static/_not-found/__next._full.txt +2 -2
  194. ui/static/static/_not-found/__next._head.txt +1 -1
  195. ui/static/static/_not-found/__next._index.txt +2 -2
  196. ui/static/static/_not-found/__next._not-found.__PAGE__.txt +1 -1
  197. ui/static/static/_not-found/__next._not-found.txt +1 -1
  198. ui/static/static/_not-found/__next._tree.txt +2 -2
  199. ui/static/static/_not-found/index.html +1 -1
  200. ui/static/static/_not-found/index.txt +2 -2
  201. ui/static/static/contracts/__next._full.txt +3 -3
  202. ui/static/static/contracts/__next._head.txt +1 -1
  203. ui/static/static/contracts/__next._index.txt +2 -2
  204. ui/static/static/contracts/__next._tree.txt +2 -2
  205. ui/static/static/contracts/__next.contracts.__PAGE__.txt +2 -2
  206. ui/static/static/contracts/__next.contracts.txt +1 -1
  207. ui/static/static/contracts/index.html +1 -1
  208. ui/static/static/contracts/index.txt +3 -3
  209. ui/static/static/documentation/__next._full.txt +3 -3
  210. ui/static/static/documentation/__next._head.txt +1 -1
  211. ui/static/static/documentation/__next._index.txt +2 -2
  212. ui/static/static/documentation/__next._tree.txt +2 -2
  213. ui/static/static/documentation/__next.documentation.__PAGE__.txt +2 -2
  214. ui/static/static/documentation/__next.documentation.txt +1 -1
  215. ui/static/static/documentation/index.html +2 -2
  216. ui/static/static/documentation/index.txt +3 -3
  217. ui/static/static/index.html +1 -1
  218. ui/static/static/index.txt +2 -2
  219. ui/static/static/metadata/__next._full.txt +2 -2
  220. ui/static/static/metadata/__next._head.txt +1 -1
  221. ui/static/static/metadata/__next._index.txt +2 -2
  222. ui/static/static/metadata/__next._tree.txt +2 -2
  223. ui/static/static/metadata/__next.metadata.__PAGE__.txt +1 -1
  224. ui/static/static/metadata/__next.metadata.txt +1 -1
  225. ui/static/static/metadata/index.html +1 -1
  226. ui/static/static/metadata/index.txt +2 -2
  227. ui/static/static/quality/__next._full.txt +2 -2
  228. ui/static/static/quality/__next._head.txt +1 -1
  229. ui/static/static/quality/__next._index.txt +2 -2
  230. ui/static/static/quality/__next._tree.txt +2 -2
  231. ui/static/static/quality/__next.quality.__PAGE__.txt +1 -1
  232. ui/static/static/quality/__next.quality.txt +1 -1
  233. ui/static/static/quality/index.html +2 -2
  234. ui/static/static/quality/index.txt +2 -2
  235. ui/static/static/rules/__next._full.txt +2 -2
  236. ui/static/static/rules/__next._head.txt +1 -1
  237. ui/static/static/rules/__next._index.txt +2 -2
  238. ui/static/static/rules/__next._tree.txt +2 -2
  239. ui/static/static/rules/__next.rules.__PAGE__.txt +1 -1
  240. ui/static/static/rules/__next.rules.txt +1 -1
  241. ui/static/static/rules/index.html +1 -1
  242. ui/static/static/rules/index.txt +2 -2
  243. ui/static/static/schemas/__next._full.txt +2 -2
  244. ui/static/static/schemas/__next._head.txt +1 -1
  245. ui/static/static/schemas/__next._index.txt +2 -2
  246. ui/static/static/schemas/__next._tree.txt +2 -2
  247. ui/static/static/schemas/__next.schemas.__PAGE__.txt +1 -1
  248. ui/static/static/schemas/__next.schemas.txt +1 -1
  249. ui/static/static/schemas/index.html +1 -1
  250. ui/static/static/schemas/index.txt +2 -2
  251. ui/static/static/settings/__next._full.txt +2 -2
  252. ui/static/static/settings/__next._head.txt +1 -1
  253. ui/static/static/settings/__next._index.txt +2 -2
  254. ui/static/static/settings/__next._tree.txt +2 -2
  255. ui/static/static/settings/__next.settings.__PAGE__.txt +1 -1
  256. ui/static/static/settings/__next.settings.txt +1 -1
  257. ui/static/static/settings/index.html +1 -1
  258. ui/static/static/settings/index.txt +2 -2
  259. ui/static/static/static/.gitkeep +0 -0
  260. ui/static/static/static/404/index.html +1 -0
  261. ui/static/static/static/404.html +1 -0
  262. ui/static/static/static/__next.__PAGE__.txt +10 -0
  263. ui/static/static/static/__next._full.txt +30 -0
  264. ui/static/static/static/__next._head.txt +7 -0
  265. ui/static/static/static/__next._index.txt +9 -0
  266. ui/static/static/static/__next._tree.txt +2 -0
  267. ui/static/static/static/_next/static/chunks/222442f6da32302a.js +1 -0
  268. ui/static/static/static/_next/static/chunks/247eb132b7f7b574.js +1 -0
  269. ui/static/static/static/_next/static/chunks/297d55555b71baba.js +1 -0
  270. ui/static/static/static/_next/static/chunks/2ab439ce003cd691.js +1 -0
  271. ui/static/static/static/_next/static/chunks/414e77373f8ff61c.js +1 -0
  272. ui/static/static/static/_next/static/chunks/49ca65abd26ae49e.js +1 -0
  273. ui/static/static/static/_next/static/chunks/652ad0aa26265c47.js +2 -0
  274. ui/static/static/static/_next/static/chunks/9667e7a3d359eb39.js +1 -0
  275. ui/static/static/static/_next/static/chunks/9c23f44fff36548a.js +1 -0
  276. ui/static/static/static/_next/static/chunks/a6dad97d9634a72d.js +1 -0
  277. ui/static/static/static/_next/static/chunks/b32a0963684b9933.js +4 -0
  278. ui/static/static/static/_next/static/chunks/c69f6cba366bd988.js +1 -0
  279. ui/static/static/static/_next/static/chunks/db913959c675cea6.js +1 -0
  280. ui/static/static/static/_next/static/chunks/f061a4be97bfc3b3.js +1 -0
  281. ui/static/static/static/_next/static/chunks/f2e7afeab1178138.js +1 -0
  282. ui/static/static/static/_next/static/chunks/ff1a16fafef87110.js +1 -0
  283. ui/static/static/static/_next/static/chunks/turbopack-ffcb7ab6794027ef.js +3 -0
  284. ui/static/static/static/_next/static/tNTkVW6puVXC4bAm4WrHl/_buildManifest.js +11 -0
  285. ui/static/static/static/_next/static/tNTkVW6puVXC4bAm4WrHl/_ssgManifest.js +1 -0
  286. ui/static/static/static/_not-found/__next._full.txt +17 -0
  287. ui/static/static/static/_not-found/__next._head.txt +7 -0
  288. ui/static/static/static/_not-found/__next._index.txt +9 -0
  289. ui/static/static/static/_not-found/__next._not-found.__PAGE__.txt +5 -0
  290. ui/static/static/static/_not-found/__next._not-found.txt +4 -0
  291. ui/static/static/static/_not-found/__next._tree.txt +2 -0
  292. ui/static/static/static/_not-found/index.html +1 -0
  293. ui/static/static/static/_not-found/index.txt +17 -0
  294. ui/static/static/static/contracts/__next._full.txt +21 -0
  295. ui/static/static/static/contracts/__next._head.txt +7 -0
  296. ui/static/static/static/contracts/__next._index.txt +9 -0
  297. ui/static/static/static/contracts/__next._tree.txt +2 -0
  298. ui/static/static/static/contracts/__next.contracts.__PAGE__.txt +9 -0
  299. ui/static/static/static/contracts/__next.contracts.txt +4 -0
  300. ui/static/static/static/contracts/index.html +1 -0
  301. ui/static/static/static/contracts/index.txt +21 -0
  302. ui/static/static/static/documentation/__next._full.txt +21 -0
  303. ui/static/static/static/documentation/__next._head.txt +7 -0
  304. ui/static/static/static/documentation/__next._index.txt +9 -0
  305. ui/static/static/static/documentation/__next._tree.txt +2 -0
  306. ui/static/static/static/documentation/__next.documentation.__PAGE__.txt +9 -0
  307. ui/static/static/static/documentation/__next.documentation.txt +4 -0
  308. ui/static/static/static/documentation/index.html +93 -0
  309. ui/static/static/static/documentation/index.txt +21 -0
  310. ui/static/static/static/index.html +1 -0
  311. ui/static/static/static/index.txt +30 -0
  312. ui/static/static/static/metadata/__next._full.txt +21 -0
  313. ui/static/static/static/metadata/__next._head.txt +7 -0
  314. ui/static/static/static/metadata/__next._index.txt +9 -0
  315. ui/static/static/static/metadata/__next._tree.txt +2 -0
  316. ui/static/static/static/metadata/__next.metadata.__PAGE__.txt +9 -0
  317. ui/static/static/static/metadata/__next.metadata.txt +4 -0
  318. ui/static/static/static/metadata/index.html +1 -0
  319. ui/static/static/static/metadata/index.txt +21 -0
  320. ui/static/static/static/quality/__next._full.txt +21 -0
  321. ui/static/static/static/quality/__next._head.txt +7 -0
  322. ui/static/static/static/quality/__next._index.txt +9 -0
  323. ui/static/static/static/quality/__next._tree.txt +2 -0
  324. ui/static/static/static/quality/__next.quality.__PAGE__.txt +9 -0
  325. ui/static/static/static/quality/__next.quality.txt +4 -0
  326. ui/static/static/static/quality/index.html +2 -0
  327. ui/static/static/static/quality/index.txt +21 -0
  328. ui/static/static/static/rules/__next._full.txt +21 -0
  329. ui/static/static/static/rules/__next._head.txt +7 -0
  330. ui/static/static/static/rules/__next._index.txt +9 -0
  331. ui/static/static/static/rules/__next._tree.txt +2 -0
  332. ui/static/static/static/rules/__next.rules.__PAGE__.txt +9 -0
  333. ui/static/static/static/rules/__next.rules.txt +4 -0
  334. ui/static/static/static/rules/index.html +1 -0
  335. ui/static/static/static/rules/index.txt +21 -0
  336. ui/static/static/static/schemas/__next._full.txt +21 -0
  337. ui/static/static/static/schemas/__next._head.txt +7 -0
  338. ui/static/static/static/schemas/__next._index.txt +9 -0
  339. ui/static/static/static/schemas/__next._tree.txt +2 -0
  340. ui/static/static/static/schemas/__next.schemas.__PAGE__.txt +9 -0
  341. ui/static/static/static/schemas/__next.schemas.txt +4 -0
  342. ui/static/static/static/schemas/index.html +1 -0
  343. ui/static/static/static/schemas/index.txt +21 -0
  344. ui/static/static/static/settings/__next._full.txt +21 -0
  345. ui/static/static/static/settings/__next._head.txt +7 -0
  346. ui/static/static/static/settings/__next._index.txt +9 -0
  347. ui/static/static/static/settings/__next._tree.txt +2 -0
  348. ui/static/static/static/settings/__next.settings.__PAGE__.txt +9 -0
  349. ui/static/static/static/settings/__next.settings.txt +4 -0
  350. ui/static/static/static/settings/index.html +1 -0
  351. ui/static/static/static/settings/index.txt +21 -0
  352. ui/static/static/static/validation/__next._full.txt +21 -0
  353. ui/static/static/static/validation/__next._head.txt +7 -0
  354. ui/static/static/static/validation/__next._index.txt +9 -0
  355. ui/static/static/static/validation/__next._tree.txt +2 -0
  356. ui/static/static/static/validation/__next.validation.__PAGE__.txt +9 -0
  357. ui/static/static/static/validation/__next.validation.txt +4 -0
  358. ui/static/static/static/validation/index.html +1 -0
  359. ui/static/static/static/validation/index.txt +21 -0
  360. ui/static/static/validation/__next._full.txt +2 -2
  361. ui/static/static/validation/__next._head.txt +1 -1
  362. ui/static/static/validation/__next._index.txt +2 -2
  363. ui/static/static/validation/__next._tree.txt +2 -2
  364. ui/static/static/validation/__next.validation.__PAGE__.txt +1 -1
  365. ui/static/static/validation/__next.validation.txt +1 -1
  366. ui/static/static/validation/index.html +1 -1
  367. ui/static/static/validation/index.txt +2 -2
  368. ui/static/validation/__next._full.txt +2 -2
  369. ui/static/validation/__next._head.txt +1 -1
  370. ui/static/validation/__next._index.txt +1 -1
  371. ui/static/validation/__next._tree.txt +1 -1
  372. ui/static/validation/__next.validation.__PAGE__.txt +2 -2
  373. ui/static/validation/__next.validation.txt +1 -1
  374. ui/static/validation/index.html +1 -1
  375. ui/static/validation/index.txt +2 -2
  376. pycharter/data/templates/template_coercion_rules.yaml +0 -15
  377. pycharter/data/templates/template_contract.yaml +0 -587
  378. pycharter/data/templates/template_metadata.yaml +0 -38
  379. pycharter/data/templates/template_schema.yaml +0 -22
  380. pycharter/data/templates/template_transform_advanced.yaml +0 -50
  381. pycharter/data/templates/template_transform_simple.yaml +0 -59
  382. pycharter/data/templates/template_validation_rules.yaml +0 -29
  383. pycharter/etl_generator/extraction.py +0 -916
  384. pycharter/etl_generator/factory.py +0 -174
  385. pycharter/etl_generator/orchestrator.py +0 -1650
  386. pycharter/integrations/__init__.py +0 -19
  387. pycharter/integrations/kafka.py +0 -178
  388. pycharter/integrations/streaming.py +0 -100
  389. pycharter-0.0.22.dist-info/RECORD +0 -358
  390. {pycharter-0.0.22.dist-info → pycharter-0.0.24.dist-info}/entry_points.txt +0 -0
  391. {pycharter-0.0.22.dist-info → pycharter-0.0.24.dist-info}/licenses/LICENSE +0 -0
  392. {pycharter-0.0.22.dist-info → pycharter-0.0.24.dist-info}/top_level.txt +0 -0
  393. /ui/static/_next/static/{0rYA78L88aUyD2Uh38hhX → 2gKjNv6YvE6BcIdFthBLs}/_buildManifest.js +0 -0
  394. /ui/static/_next/static/{0rYA78L88aUyD2Uh38hhX → 2gKjNv6YvE6BcIdFthBLs}/_ssgManifest.js +0 -0
  395. /ui/static/static/_next/static/{tNTkVW6puVXC4bAm4WrHl → 0rYA78L88aUyD2Uh38hhX}/_buildManifest.js +0 -0
  396. /ui/static/static/_next/static/{tNTkVW6puVXC4bAm4WrHl → 0rYA78L88aUyD2Uh38hhX}/_ssgManifest.js +0 -0
  397. /ui/static/{_next → static/_next}/static/chunks/c4fa4f4114b7c352.js +0 -0
  398. /ui/static/static/{_next → static/_next}/static/chunks/4e310fe5005770a3.css +0 -0
  399. /ui/static/{_next → static/static/_next}/static/chunks/5e04d10c4a7b58a3.js +0 -0
  400. /ui/static/static/{_next → static/_next}/static/chunks/5fc14c00a2779dc5.js +0 -0
  401. /ui/static/{_next → static/static/_next}/static/chunks/75d88a058d8ffaa6.js +0 -0
  402. /ui/static/{_next → static/static/_next}/static/chunks/8c89634cf6bad76f.js +0 -0
  403. /ui/static/static/{_next → static/_next}/static/chunks/b584574fdc8ab13e.js +0 -0
  404. /ui/static/static/{_next → static/_next}/static/chunks/d5989c94d3614b3a.js +0 -0
@@ -0,0 +1,465 @@
1
+ """
2
+ Documentation Generator - Core generation logic.
3
+
4
+ Transforms ContractMetadata into human-readable documentation.
5
+ """
6
+
7
+ import json
8
+ from typing import Any, Dict, List, Optional, Union
9
+
10
+ from pycharter.contract_parser import ContractMetadata
11
+ from pycharter.docs_generator.renderers import DocsRenderer, MarkdownRenderer
12
+
13
+
14
+ class DocsGenerator:
15
+ """
16
+ Generate documentation from data contracts.
17
+
18
+ Transforms ContractMetadata objects into human-readable documentation
19
+ in various formats (Markdown, HTML, etc.).
20
+
21
+ Example:
22
+ >>> from pycharter import parse_contract_file
23
+ >>> from pycharter.docs_generator import DocsGenerator
24
+ >>>
25
+ >>> contract = parse_contract_file("contract.yaml")
26
+ >>> generator = DocsGenerator()
27
+ >>> docs = generator.generate(contract)
28
+ >>> print(docs)
29
+ """
30
+
31
+ def __init__(self, renderer: Optional[DocsRenderer] = None):
32
+ """
33
+ Initialize the documentation generator.
34
+
35
+ Args:
36
+ renderer: Renderer to use for output format. Defaults to MarkdownRenderer.
37
+ """
38
+ self.renderer = renderer or MarkdownRenderer()
39
+
40
+ def generate(
41
+ self,
42
+ contract: ContractMetadata,
43
+ include_schema: bool = True,
44
+ include_coercions: bool = True,
45
+ include_validations: bool = True,
46
+ include_metadata: bool = True,
47
+ ) -> str:
48
+ """
49
+ Generate full documentation for a contract.
50
+
51
+ Args:
52
+ contract: ContractMetadata object to document
53
+ include_schema: Include schema field documentation
54
+ include_coercions: Include coercion rules documentation
55
+ include_validations: Include validation rules documentation
56
+ include_metadata: Include metadata/ownership documentation
57
+
58
+ Returns:
59
+ Generated documentation as string
60
+ """
61
+ parts = []
62
+
63
+ # Get title from schema or metadata
64
+ title = self._get_title(contract)
65
+ version = contract.versions.get("schema") or contract.schema.get("version")
66
+
67
+ # Header
68
+ parts.append(self.renderer.render_header(title, version))
69
+
70
+ # Description
71
+ description = contract.schema.get("description") or contract.metadata.get(
72
+ "description"
73
+ )
74
+ if description:
75
+ parts.append(self.renderer.render_description(description))
76
+
77
+ # Schema section
78
+ if include_schema and contract.schema:
79
+ parts.append(self.generate_schema_section(contract.schema))
80
+
81
+ # Coercion rules section
82
+ if include_coercions and contract.coercion_rules:
83
+ parts.append(self.generate_coercion_section(contract.coercion_rules))
84
+
85
+ # Validation rules section
86
+ if include_validations and contract.validation_rules:
87
+ parts.append(self.generate_validation_section(contract.validation_rules))
88
+
89
+ # Metadata section
90
+ if include_metadata and contract.metadata:
91
+ parts.append(self.generate_metadata_section(contract))
92
+
93
+ # Footer for HTML
94
+ if hasattr(self.renderer, "render_footer"):
95
+ parts.append(self.renderer.render_footer())
96
+
97
+ return "".join(parts)
98
+
99
+ def generate_schema_section(self, schema: Dict[str, Any]) -> str:
100
+ """
101
+ Generate documentation for schema fields.
102
+
103
+ Args:
104
+ schema: JSON Schema dictionary
105
+
106
+ Returns:
107
+ Formatted schema documentation
108
+ """
109
+ properties = schema.get("properties", {})
110
+ required = set(schema.get("required", []))
111
+
112
+ if not properties:
113
+ return ""
114
+
115
+ # Build table rows for fields
116
+ headers = ["Field", "Type", "Required", "Description", "Constraints"]
117
+ rows = []
118
+
119
+ for field_name, field_def in properties.items():
120
+ row = self._build_field_row(field_name, field_def, field_name in required)
121
+ rows.append(row)
122
+
123
+ table = self.renderer.render_table(headers, rows)
124
+ return self.renderer.render_section("Schema Fields", table)
125
+
126
+ def generate_coercion_section(self, rules: Dict[str, Any]) -> str:
127
+ """
128
+ Generate documentation for coercion rules.
129
+
130
+ Args:
131
+ rules: Coercion rules dictionary
132
+
133
+ Returns:
134
+ Formatted coercion documentation
135
+ """
136
+ # Filter out version key
137
+ coercion_rules = {k: v for k, v in rules.items() if k != "version"}
138
+
139
+ if not coercion_rules:
140
+ return ""
141
+
142
+ headers = ["Field", "Coercion", "Description"]
143
+ rows = []
144
+
145
+ for field, coercion in coercion_rules.items():
146
+ if isinstance(coercion, str):
147
+ coercion_name = coercion
148
+ description = self._get_coercion_description(coercion_name)
149
+ elif isinstance(coercion, dict):
150
+ coercion_name = coercion.get("type", str(coercion))
151
+ description = coercion.get(
152
+ "description", self._get_coercion_description(coercion_name)
153
+ )
154
+ else:
155
+ coercion_name = str(coercion)
156
+ description = ""
157
+
158
+ rows.append([f"`{field}`", f"`{coercion_name}`", description])
159
+
160
+ content = self.renderer.render_description(
161
+ "Coercions are applied before validation to transform incoming data."
162
+ )
163
+ content += self.renderer.render_table(headers, rows)
164
+ return self.renderer.render_section("Coercion Rules", content)
165
+
166
+ def generate_validation_section(self, rules: Dict[str, Any]) -> str:
167
+ """
168
+ Generate documentation for validation rules.
169
+
170
+ Args:
171
+ rules: Validation rules dictionary
172
+
173
+ Returns:
174
+ Formatted validation documentation
175
+ """
176
+ # Filter out version key
177
+ validation_rules = {k: v for k, v in rules.items() if k != "version"}
178
+
179
+ if not validation_rules:
180
+ return ""
181
+
182
+ headers = ["Field", "Validation", "Configuration"]
183
+ rows = []
184
+
185
+ for field, validations in validation_rules.items():
186
+ if isinstance(validations, dict):
187
+ for val_name, val_config in validations.items():
188
+ config_str = self._format_config(val_config)
189
+ rows.append([f"`{field}`", f"`{val_name}`", config_str])
190
+ elif isinstance(validations, str):
191
+ rows.append([f"`{field}`", f"`{validations}`", ""])
192
+ elif isinstance(validations, list):
193
+ for val in validations:
194
+ rows.append([f"`{field}`", f"`{val}`", ""])
195
+
196
+ content = self.renderer.render_description(
197
+ "Validations are applied after coercion to ensure data meets requirements."
198
+ )
199
+ content += self.renderer.render_table(headers, rows)
200
+ return self.renderer.render_section("Validation Rules", content)
201
+
202
+ def generate_metadata_section(self, contract: ContractMetadata) -> str:
203
+ """
204
+ Generate documentation for contract metadata.
205
+
206
+ Args:
207
+ contract: ContractMetadata object
208
+
209
+ Returns:
210
+ Formatted metadata documentation
211
+ """
212
+ parts = []
213
+
214
+ # Ownership section
215
+ if contract.ownership:
216
+ ownership_content = self._format_ownership(contract.ownership)
217
+ parts.append(
218
+ self.renderer.render_section("Ownership", ownership_content)
219
+ )
220
+
221
+ # Governance rules
222
+ if contract.governance_rules:
223
+ governance_content = self._format_governance(contract.governance_rules)
224
+ parts.append(
225
+ self.renderer.render_section("Governance Rules", governance_content)
226
+ )
227
+
228
+ # Version information
229
+ if contract.versions:
230
+ version_content = self._format_versions(contract.versions)
231
+ parts.append(
232
+ self.renderer.render_section("Version Information", version_content)
233
+ )
234
+
235
+ # Other metadata
236
+ other_metadata = {
237
+ k: v
238
+ for k, v in contract.metadata.items()
239
+ if k not in ["ownership", "governance_rules", "version"]
240
+ }
241
+ if other_metadata:
242
+ other_content = self._format_metadata_dict(other_metadata)
243
+ parts.append(
244
+ self.renderer.render_section("Additional Metadata", other_content)
245
+ )
246
+
247
+ return "".join(parts)
248
+
249
+ def _get_title(self, contract: ContractMetadata) -> str:
250
+ """Extract title from contract."""
251
+ # Try schema title
252
+ if "title" in contract.schema:
253
+ return contract.schema["title"]
254
+ # Try metadata title
255
+ if "title" in contract.metadata:
256
+ return contract.metadata["title"]
257
+ # Try schema $id
258
+ if "$id" in contract.schema:
259
+ return contract.schema["$id"]
260
+ return "Data Contract Documentation"
261
+
262
+ def _build_field_row(
263
+ self, field_name: str, field_def: Dict[str, Any], is_required: bool
264
+ ) -> List[str]:
265
+ """Build a table row for a schema field."""
266
+ # Type
267
+ field_type = self._get_field_type(field_def)
268
+
269
+ # Required badge
270
+ required_str = "Yes" if is_required else "No"
271
+
272
+ # Description
273
+ description = field_def.get("description", "")
274
+
275
+ # Constraints
276
+ constraints = self._get_field_constraints(field_def)
277
+
278
+ return [f"`{field_name}`", field_type, required_str, description, constraints]
279
+
280
+ def _get_field_type(self, field_def: Dict[str, Any]) -> str:
281
+ """Extract field type from definition."""
282
+ if "type" in field_def:
283
+ base_type = field_def["type"]
284
+ if base_type == "array" and "items" in field_def:
285
+ items_type = self._get_field_type(field_def["items"])
286
+ return f"array[{items_type}]"
287
+ return base_type
288
+ if "anyOf" in field_def:
289
+ types = [self._get_field_type(t) for t in field_def["anyOf"]]
290
+ return " | ".join(types)
291
+ if "oneOf" in field_def:
292
+ types = [self._get_field_type(t) for t in field_def["oneOf"]]
293
+ return " | ".join(types)
294
+ if "$ref" in field_def:
295
+ return f"ref: {field_def['$ref']}"
296
+ return "any"
297
+
298
+ def _get_field_constraints(self, field_def: Dict[str, Any]) -> str:
299
+ """Extract constraints from field definition."""
300
+ constraints = []
301
+
302
+ # String constraints
303
+ if "minLength" in field_def:
304
+ constraints.append(f"minLength: {field_def['minLength']}")
305
+ if "maxLength" in field_def:
306
+ constraints.append(f"maxLength: {field_def['maxLength']}")
307
+ if "pattern" in field_def:
308
+ constraints.append(f"pattern: `{field_def['pattern']}`")
309
+ if "format" in field_def:
310
+ constraints.append(f"format: {field_def['format']}")
311
+
312
+ # Number constraints
313
+ if "minimum" in field_def:
314
+ constraints.append(f"min: {field_def['minimum']}")
315
+ if "maximum" in field_def:
316
+ constraints.append(f"max: {field_def['maximum']}")
317
+ if "exclusiveMinimum" in field_def:
318
+ constraints.append(f"exclusiveMin: {field_def['exclusiveMinimum']}")
319
+ if "exclusiveMaximum" in field_def:
320
+ constraints.append(f"exclusiveMax: {field_def['exclusiveMaximum']}")
321
+ if "multipleOf" in field_def:
322
+ constraints.append(f"multipleOf: {field_def['multipleOf']}")
323
+
324
+ # Enum
325
+ if "enum" in field_def:
326
+ enum_vals = ", ".join(str(v) for v in field_def["enum"][:5])
327
+ if len(field_def["enum"]) > 5:
328
+ enum_vals += "..."
329
+ constraints.append(f"enum: [{enum_vals}]")
330
+
331
+ # Default
332
+ if "default" in field_def:
333
+ constraints.append(f"default: {field_def['default']}")
334
+
335
+ return "; ".join(constraints) if constraints else ""
336
+
337
+ def _get_coercion_description(self, coercion_name: str) -> str:
338
+ """Get description for built-in coercion types."""
339
+ descriptions = {
340
+ "to_string": "Convert value to string",
341
+ "to_integer": "Convert value to integer",
342
+ "to_float": "Convert value to float",
343
+ "to_number": "Convert value to number",
344
+ "to_boolean": "Convert value to boolean",
345
+ "to_datetime": "Parse value as datetime",
346
+ "to_date": "Parse value as date",
347
+ "trim": "Remove leading/trailing whitespace",
348
+ "lowercase": "Convert to lowercase",
349
+ "uppercase": "Convert to uppercase",
350
+ "strip_html": "Remove HTML tags",
351
+ "normalize_whitespace": "Normalize whitespace characters",
352
+ }
353
+ return descriptions.get(coercion_name, "")
354
+
355
+ def _format_config(self, config: Any) -> str:
356
+ """Format validation configuration for display."""
357
+ if config is None:
358
+ return ""
359
+ if isinstance(config, bool):
360
+ return "enabled" if config else "disabled"
361
+ if isinstance(config, (int, float, str)):
362
+ return str(config)
363
+ if isinstance(config, dict):
364
+ parts = [f"{k}={v}" for k, v in config.items()]
365
+ return ", ".join(parts)
366
+ if isinstance(config, list):
367
+ return ", ".join(str(v) for v in config)
368
+ return str(config)
369
+
370
+ def _format_ownership(self, ownership: Dict[str, Any]) -> str:
371
+ """Format ownership information."""
372
+ headers = ["Role", "Contact"]
373
+ rows = []
374
+
375
+ role_labels = {
376
+ "business_owners": "Business Owners",
377
+ "bu_sme": "Business Unit SME",
378
+ "it_application_owners": "IT Application Owners",
379
+ "it_sme": "IT SME",
380
+ "support_lead": "Support Lead",
381
+ "owner": "Owner",
382
+ "team": "Team",
383
+ }
384
+
385
+ for key, value in ownership.items():
386
+ label = role_labels.get(key, key.replace("_", " ").title())
387
+ if isinstance(value, list):
388
+ value_str = ", ".join(str(v) for v in value)
389
+ else:
390
+ value_str = str(value)
391
+ rows.append([label, value_str])
392
+
393
+ return self.renderer.render_table(headers, rows)
394
+
395
+ def _format_governance(self, governance: Dict[str, Any]) -> str:
396
+ """Format governance rules."""
397
+ headers = ["Rule", "Configuration"]
398
+ rows = []
399
+
400
+ for rule, config in governance.items():
401
+ rule_label = rule.replace("_", " ").title()
402
+ config_str = self._format_config(config)
403
+ rows.append([rule_label, config_str])
404
+
405
+ return self.renderer.render_table(headers, rows)
406
+
407
+ def _format_versions(self, versions: Dict[str, str]) -> str:
408
+ """Format version information."""
409
+ headers = ["Component", "Version"]
410
+ rows = [[comp.replace("_", " ").title(), ver] for comp, ver in versions.items()]
411
+ return self.renderer.render_table(headers, rows)
412
+
413
+ def _format_metadata_dict(self, metadata: Dict[str, Any]) -> str:
414
+ """Format a metadata dictionary."""
415
+ headers = ["Property", "Value"]
416
+ rows = []
417
+ for key, value in metadata.items():
418
+ if isinstance(value, (dict, list)):
419
+ value_str = json.dumps(value, indent=2)
420
+ else:
421
+ value_str = str(value)
422
+ rows.append([key.replace("_", " ").title(), value_str])
423
+ return self.renderer.render_table(headers, rows)
424
+
425
+
426
+ def generate_docs(
427
+ contract: Union[ContractMetadata, Dict[str, Any]],
428
+ format: str = "markdown",
429
+ **kwargs,
430
+ ) -> str:
431
+ """
432
+ Convenience function to generate documentation from a contract.
433
+
434
+ Args:
435
+ contract: ContractMetadata object or contract dictionary
436
+ format: Output format ('markdown' or 'html')
437
+ **kwargs: Additional options passed to DocsGenerator.generate()
438
+
439
+ Returns:
440
+ Generated documentation as string
441
+
442
+ Example:
443
+ >>> from pycharter import parse_contract_file
444
+ >>> from pycharter.docs_generator import generate_docs
445
+ >>>
446
+ >>> contract = parse_contract_file("contract.yaml")
447
+ >>> markdown = generate_docs(contract)
448
+ >>> html = generate_docs(contract, format="html")
449
+ """
450
+ from pycharter.docs_generator.renderers import HTMLRenderer, MarkdownRenderer
451
+
452
+ # Convert dict to ContractMetadata if needed
453
+ if isinstance(contract, dict):
454
+ from pycharter.contract_parser import parse_contract
455
+
456
+ contract = parse_contract(contract, validate=False)
457
+
458
+ # Select renderer
459
+ if format.lower() == "html":
460
+ renderer = HTMLRenderer()
461
+ else:
462
+ renderer = MarkdownRenderer()
463
+
464
+ generator = DocsGenerator(renderer=renderer)
465
+ return generator.generate(contract, **kwargs)