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
@@ -2,6 +2,7 @@
2
2
  Shared utilities used across all services.
3
3
 
4
4
  Includes:
5
+ - Protocols (interface definitions for extensible components)
5
6
  - Coercions (pre-validation transformations)
6
7
  - Validations (post-validation checks)
7
8
  - JSON Schema support utilities
@@ -20,6 +21,19 @@ from pycharter.shared.json_schema_validator import (
20
21
  is_valid_json_schema,
21
22
  validate_json_schema,
22
23
  )
24
+ from pycharter.shared.protocols import (
25
+ MetadataStore,
26
+ CoercionFunc,
27
+ CoercionRegistry,
28
+ ValidatorFunc,
29
+ ValidationFactory,
30
+ ValidationRegistry,
31
+ ContractParser,
32
+ ContractMetadataProtocol,
33
+ ModelGenerator,
34
+ DataValidator,
35
+ ValidationResultProtocol,
36
+ )
23
37
  from pycharter.shared.schema_parser import (
24
38
  get_schema_type,
25
39
  is_required,
@@ -33,8 +47,35 @@ from pycharter.shared.name_validator import (
33
47
  validate_name,
34
48
  )
35
49
  from pycharter.shared.validations import get_validation, register_validation
50
+ from pycharter.shared.errors import (
51
+ PyCharterError,
52
+ ConfigError,
53
+ ConfigValidationError,
54
+ ConfigLoadError,
55
+ ExpressionError,
56
+ ErrorMode,
57
+ ErrorContext,
58
+ get_error_context,
59
+ set_error_mode,
60
+ handle_error,
61
+ handle_warning,
62
+ StrictMode,
63
+ LenientMode,
64
+ )
36
65
 
37
66
  __all__ = [
67
+ # Protocols
68
+ "MetadataStore",
69
+ "CoercionFunc",
70
+ "CoercionRegistry",
71
+ "ValidatorFunc",
72
+ "ValidationFactory",
73
+ "ValidationRegistry",
74
+ "ContractParser",
75
+ "ContractMetadataProtocol",
76
+ "ModelGenerator",
77
+ "DataValidator",
78
+ "ValidationResultProtocol",
38
79
  # Coercions
39
80
  "get_coercion",
40
81
  "register_coercion",
@@ -62,4 +103,19 @@ __all__ = [
62
103
  "validate_name",
63
104
  "is_valid_name",
64
105
  "normalize_name",
106
+ # Exception hierarchy
107
+ "PyCharterError",
108
+ "ConfigError",
109
+ "ConfigValidationError",
110
+ "ConfigLoadError",
111
+ "ExpressionError",
112
+ # Error handling
113
+ "ErrorMode",
114
+ "ErrorContext",
115
+ "get_error_context",
116
+ "set_error_mode",
117
+ "handle_error",
118
+ "handle_warning",
119
+ "StrictMode",
120
+ "LenientMode",
65
121
  ]
@@ -0,0 +1,296 @@
1
+ """
2
+ Standardized error handling for pycharter.
3
+
4
+ Exception hierarchy:
5
+ - PyCharterError: Base for all pycharter exceptions (catch this for any pycharter error)
6
+ - ConfigError: Config loading/parsing failures (e.g. missing file, invalid YAML)
7
+ - ConfigValidationError: Schema validation failures (e.g. missing required 'type' field)
8
+ - ExpressionError: Expression evaluation failures (e.g. invalid syntax in add field)
9
+
10
+ Error handling modes:
11
+ - STRICT: Raise exceptions immediately on errors
12
+ - LENIENT: Log warnings and continue (best effort)
13
+ - COLLECT: Collect errors and return them with results
14
+ """
15
+
16
+ import logging
17
+ import warnings
18
+ from dataclasses import dataclass, field
19
+ from enum import Enum
20
+ from typing import Any, List, Optional
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+
25
+ # =============================================================================
26
+ # EXCEPTION HIERARCHY
27
+ # =============================================================================
28
+
29
+
30
+ class PyCharterError(Exception):
31
+ """
32
+ Base exception for all pycharter errors.
33
+
34
+ Catch this to handle any pycharter-related failure without depending on
35
+ specific exception types. Subclasses provide more specific handling.
36
+
37
+ Example:
38
+ try:
39
+ pipeline = Pipeline.from_config_files(extract="e.yaml", load="l.yaml")
40
+ except PyCharterError as e:
41
+ logger.error("Pipeline config failed: %s", e)
42
+ """
43
+ pass
44
+
45
+
46
+ class ConfigError(PyCharterError):
47
+ """
48
+ Raised when configuration cannot be loaded or parsed.
49
+
50
+ Use for: missing files, invalid YAML/JSON, I/O errors during config load.
51
+ """
52
+ def __init__(self, message: str, path: Optional[str] = None):
53
+ self.path = path
54
+ super().__init__(message + (f" (path: {path})" if path else ""))
55
+
56
+
57
+ class ConfigValidationError(PyCharterError):
58
+ """
59
+ Raised when configuration fails schema validation.
60
+
61
+ Use for: missing required fields (e.g. 'type'), invalid structure,
62
+ schema constraint violations. May include a list of validation errors.
63
+ """
64
+ def __init__(
65
+ self,
66
+ message: str,
67
+ errors: Optional[List[dict]] = None,
68
+ config_type: Optional[str] = None,
69
+ config_path: Optional[str] = None,
70
+ ):
71
+ self.message = message
72
+ self.errors = errors or []
73
+ self.config_type = config_type
74
+ self.config_path = config_path
75
+ super().__init__(self._format_message())
76
+
77
+ def _format_message(self) -> str:
78
+ parts = [self.message]
79
+ if self.config_path:
80
+ parts.append(f" File: {self.config_path}")
81
+ if self.errors:
82
+ parts.append("\nValidation errors:")
83
+ for i, error in enumerate(self.errors[:10], 1):
84
+ path = error.get("path", "")
85
+ msg = error.get("message", "Unknown error")
86
+ parts.append(f" {i}. {path}: {msg}" if path else f" {i}. {msg}")
87
+ if len(self.errors) > 10:
88
+ parts.append(f" ... and {len(self.errors) - 10} more errors")
89
+ return "\n".join(parts)
90
+
91
+
92
+ class ConfigLoadError(ConfigError):
93
+ """
94
+ Raised when pipeline config cannot be loaded (missing file, invalid YAML, I/O).
95
+
96
+ Subclass of ConfigError for backward compatibility and ETL-specific usage.
97
+ """
98
+ pass
99
+
100
+
101
+ class ExpressionError(PyCharterError):
102
+ """
103
+ Raised when an expression cannot be evaluated (e.g. in add field, defaults).
104
+
105
+ Use for: invalid expression syntax, missing variables, type errors in evaluation.
106
+ """
107
+ pass
108
+
109
+
110
+ class ErrorMode(Enum):
111
+ """Error handling mode for pycharter operations."""
112
+
113
+ STRICT = "strict"
114
+ """Raise exceptions immediately on any error."""
115
+
116
+ LENIENT = "lenient"
117
+ """Log warnings and continue with best effort."""
118
+
119
+ COLLECT = "collect"
120
+ """Collect errors and return them with results."""
121
+
122
+
123
+ @dataclass
124
+ class ErrorContext:
125
+ """
126
+ Context for tracking errors during operations.
127
+
128
+ Use with ErrorMode.COLLECT to gather errors without stopping.
129
+ """
130
+
131
+ mode: ErrorMode = ErrorMode.LENIENT
132
+ errors: List[str] = field(default_factory=list)
133
+ warnings: List[str] = field(default_factory=list)
134
+
135
+ def handle_error(
136
+ self,
137
+ message: str,
138
+ exception: Optional[Exception] = None,
139
+ category: str = "error",
140
+ ) -> None:
141
+ """
142
+ Handle an error according to the current mode.
143
+
144
+ Args:
145
+ message: Error message
146
+ exception: Optional exception that caused the error
147
+ category: Error category for logging
148
+ """
149
+ full_message = f"{category}: {message}"
150
+ if exception:
151
+ full_message += f" ({type(exception).__name__}: {exception})"
152
+
153
+ if self.mode == ErrorMode.STRICT:
154
+ if exception:
155
+ raise type(exception)(full_message) from exception
156
+ raise ValueError(full_message)
157
+
158
+ elif self.mode == ErrorMode.LENIENT:
159
+ warnings.warn(full_message)
160
+ logger.warning(full_message)
161
+ self.warnings.append(full_message)
162
+
163
+ elif self.mode == ErrorMode.COLLECT:
164
+ self.errors.append(full_message)
165
+ logger.warning(full_message)
166
+
167
+ def handle_warning(self, message: str, category: str = "warning") -> None:
168
+ """
169
+ Handle a warning (non-fatal issue).
170
+
171
+ Args:
172
+ message: Warning message
173
+ category: Warning category
174
+ """
175
+ full_message = f"{category}: {message}"
176
+ warnings.warn(full_message)
177
+ logger.warning(full_message)
178
+ self.warnings.append(full_message)
179
+
180
+ @property
181
+ def has_errors(self) -> bool:
182
+ """Whether any errors were collected."""
183
+ return len(self.errors) > 0
184
+
185
+ def raise_if_errors(self) -> None:
186
+ """Raise ValueError if any errors were collected."""
187
+ if self.errors:
188
+ raise ValueError(f"Errors occurred: {'; '.join(self.errors)}")
189
+
190
+ def clear(self) -> None:
191
+ """Clear all errors and warnings."""
192
+ self.errors.clear()
193
+ self.warnings.clear()
194
+
195
+
196
+ # Default error context (lenient by default)
197
+ _default_context = ErrorContext(mode=ErrorMode.LENIENT)
198
+
199
+
200
+ def get_error_context() -> ErrorContext:
201
+ """Get the default error context."""
202
+ return _default_context
203
+
204
+
205
+ def set_error_mode(mode: ErrorMode) -> None:
206
+ """
207
+ Set the default error handling mode.
208
+
209
+ Args:
210
+ mode: Error mode to use
211
+ """
212
+ _default_context.mode = mode
213
+
214
+
215
+ def handle_error(
216
+ message: str,
217
+ exception: Optional[Exception] = None,
218
+ category: str = "error",
219
+ context: Optional[ErrorContext] = None,
220
+ ) -> None:
221
+ """
222
+ Handle an error using the specified or default context.
223
+
224
+ Args:
225
+ message: Error message
226
+ exception: Optional exception that caused the error
227
+ category: Error category
228
+ context: Optional error context (uses default if not provided)
229
+ """
230
+ ctx = context or _default_context
231
+ ctx.handle_error(message, exception, category)
232
+
233
+
234
+ def handle_warning(
235
+ message: str,
236
+ category: str = "warning",
237
+ context: Optional[ErrorContext] = None,
238
+ ) -> None:
239
+ """
240
+ Handle a warning using the specified or default context.
241
+
242
+ Args:
243
+ message: Warning message
244
+ category: Warning category
245
+ context: Optional error context (uses default if not provided)
246
+ """
247
+ ctx = context or _default_context
248
+ ctx.handle_warning(message, category)
249
+
250
+
251
+ class StrictMode:
252
+ """
253
+ Context manager for temporarily enabling strict mode.
254
+
255
+ Example:
256
+ >>> with StrictMode():
257
+ ... # Errors will raise exceptions
258
+ ... validator.validate(data)
259
+ """
260
+
261
+ def __init__(self):
262
+ self._previous_mode: Optional[ErrorMode] = None
263
+
264
+ def __enter__(self):
265
+ self._previous_mode = _default_context.mode
266
+ _default_context.mode = ErrorMode.STRICT
267
+ return self
268
+
269
+ def __exit__(self, exc_type, exc_val, exc_tb):
270
+ if self._previous_mode is not None:
271
+ _default_context.mode = self._previous_mode
272
+ return False
273
+
274
+
275
+ class LenientMode:
276
+ """
277
+ Context manager for temporarily enabling lenient mode.
278
+
279
+ Example:
280
+ >>> with LenientMode():
281
+ ... # Errors will be logged as warnings
282
+ ... validator.validate(data)
283
+ """
284
+
285
+ def __init__(self):
286
+ self._previous_mode: Optional[ErrorMode] = None
287
+
288
+ def __enter__(self):
289
+ self._previous_mode = _default_context.mode
290
+ _default_context.mode = ErrorMode.LENIENT
291
+ return self
292
+
293
+ def __exit__(self, exc_type, exc_val, exc_tb):
294
+ if self._previous_mode is not None:
295
+ _default_context.mode = self._previous_mode
296
+ return False
@@ -0,0 +1,234 @@
1
+ """
2
+ Protocol definitions for pycharter interfaces.
3
+
4
+ These protocols define the expected interfaces for extensible components,
5
+ enabling type checking and clear contracts for custom implementations.
6
+ """
7
+
8
+ from typing import Any, Callable, Dict, List, Optional, Protocol, Type, runtime_checkable
9
+
10
+ from pydantic import BaseModel, ValidationInfo
11
+
12
+
13
+ # =============================================================================
14
+ # Metadata Store Protocols
15
+ # =============================================================================
16
+
17
+ @runtime_checkable
18
+ class MetadataStore(Protocol):
19
+ """
20
+ Protocol for metadata store implementations.
21
+
22
+ All metadata stores (SQLite, Postgres, MongoDB, Redis, InMemory) must
23
+ implement this interface for storing and retrieving data contracts.
24
+
25
+ Example implementation:
26
+ >>> class MyCustomStore:
27
+ ... def get_schema(self, schema_id: str, version: str = None) -> dict | None:
28
+ ... # Custom implementation
29
+ ... return {"type": "object", "properties": {...}}
30
+ """
31
+
32
+ def get_schema(
33
+ self, schema_id: str, version: Optional[str] = None
34
+ ) -> Optional[Dict[str, Any]]:
35
+ """Get a schema by ID and optional version."""
36
+ ...
37
+
38
+ def get_complete_schema(
39
+ self, schema_id: str, version: Optional[str] = None
40
+ ) -> Optional[Dict[str, Any]]:
41
+ """Get a complete schema with coercion and validation rules merged."""
42
+ ...
43
+
44
+ def store_schema(
45
+ self,
46
+ schema_id: str,
47
+ schema: Dict[str, Any],
48
+ version: Optional[str] = None,
49
+ ) -> str:
50
+ """Store a schema and return its ID."""
51
+ ...
52
+
53
+ def list_schemas(self) -> List[Dict[str, Any]]:
54
+ """List all available schemas."""
55
+ ...
56
+
57
+
58
+ # =============================================================================
59
+ # Coercion Protocols
60
+ # =============================================================================
61
+
62
+ # Type alias for coercion functions
63
+ CoercionFunc = Callable[[Any], Any]
64
+
65
+
66
+ @runtime_checkable
67
+ class CoercionRegistry(Protocol):
68
+ """
69
+ Protocol for coercion function registries.
70
+
71
+ Coercions are pre-validation transformations applied to data
72
+ before Pydantic validation (mode='before').
73
+ """
74
+
75
+ def get(self, name: str) -> CoercionFunc:
76
+ """Get a coercion function by name."""
77
+ ...
78
+
79
+ def register(self, name: str, func: CoercionFunc) -> None:
80
+ """Register a custom coercion function."""
81
+ ...
82
+
83
+ def list_available(self) -> List[str]:
84
+ """List all available coercion names."""
85
+ ...
86
+
87
+
88
+ # =============================================================================
89
+ # Validation Protocols
90
+ # =============================================================================
91
+
92
+ # Type alias for validation functions (factory pattern)
93
+ # A validation factory returns a validator function that takes (value, info) -> value
94
+ ValidatorFunc = Callable[[Any, ValidationInfo], Any]
95
+ ValidationFactory = Callable[..., ValidatorFunc]
96
+
97
+
98
+ @runtime_checkable
99
+ class ValidationRegistry(Protocol):
100
+ """
101
+ Protocol for validation function registries.
102
+
103
+ Validations are post-validation checks applied to data
104
+ after Pydantic validation (mode='after').
105
+ """
106
+
107
+ def get(self, name: str) -> ValidationFactory:
108
+ """Get a validation factory by name."""
109
+ ...
110
+
111
+ def register(self, name: str, factory: ValidationFactory) -> None:
112
+ """Register a custom validation factory."""
113
+ ...
114
+
115
+ def list_available(self) -> List[str]:
116
+ """List all available validation names."""
117
+ ...
118
+
119
+
120
+ # =============================================================================
121
+ # Contract Parser Protocols
122
+ # =============================================================================
123
+
124
+ @runtime_checkable
125
+ class ContractParser(Protocol):
126
+ """
127
+ Protocol for contract parsers.
128
+
129
+ Contract parsers decompose data contract files/dicts into
130
+ their constituent components (schema, coercion_rules, validation_rules, metadata).
131
+ """
132
+
133
+ def parse(self, contract_data: Dict[str, Any]) -> "ContractMetadataProtocol":
134
+ """Parse contract data into metadata components."""
135
+ ...
136
+
137
+ def parse_file(self, file_path: str) -> "ContractMetadataProtocol":
138
+ """Parse contract from file."""
139
+ ...
140
+
141
+
142
+ @runtime_checkable
143
+ class ContractMetadataProtocol(Protocol):
144
+ """Protocol for contract metadata containers."""
145
+
146
+ @property
147
+ def schema(self) -> Dict[str, Any]:
148
+ """Get the JSON Schema definition."""
149
+ ...
150
+
151
+ @property
152
+ def coercion_rules(self) -> Dict[str, Any]:
153
+ """Get coercion rules."""
154
+ ...
155
+
156
+ @property
157
+ def validation_rules(self) -> Dict[str, Any]:
158
+ """Get validation rules."""
159
+ ...
160
+
161
+ @property
162
+ def metadata(self) -> Dict[str, Any]:
163
+ """Get additional metadata."""
164
+ ...
165
+
166
+ def to_dict(self) -> Dict[str, Any]:
167
+ """Convert to dictionary."""
168
+ ...
169
+
170
+
171
+ # =============================================================================
172
+ # Model Generator Protocols
173
+ # =============================================================================
174
+
175
+ @runtime_checkable
176
+ class ModelGenerator(Protocol):
177
+ """
178
+ Protocol for Pydantic model generators.
179
+
180
+ Model generators take JSON Schemas and produce Pydantic model classes.
181
+ """
182
+
183
+ def generate(
184
+ self, schema: Dict[str, Any], model_name: str = "DynamicModel"
185
+ ) -> Type[BaseModel]:
186
+ """Generate a Pydantic model from JSON Schema."""
187
+ ...
188
+
189
+
190
+ # =============================================================================
191
+ # Validator Protocols
192
+ # =============================================================================
193
+
194
+ @runtime_checkable
195
+ class DataValidator(Protocol):
196
+ """
197
+ Protocol for data validators.
198
+
199
+ Validators validate data against contracts/schemas and return results.
200
+ """
201
+
202
+ def validate(self, data: Dict[str, Any]) -> "ValidationResultProtocol":
203
+ """Validate a single data record."""
204
+ ...
205
+
206
+ def validate_batch(
207
+ self, data_list: List[Dict[str, Any]]
208
+ ) -> List["ValidationResultProtocol"]:
209
+ """Validate a batch of data records."""
210
+ ...
211
+
212
+ def get_model(self) -> Type[BaseModel]:
213
+ """Get the underlying Pydantic model."""
214
+ ...
215
+
216
+
217
+ @runtime_checkable
218
+ class ValidationResultProtocol(Protocol):
219
+ """Protocol for validation results."""
220
+
221
+ @property
222
+ def is_valid(self) -> bool:
223
+ """Whether validation passed."""
224
+ ...
225
+
226
+ @property
227
+ def data(self) -> Optional[Any]:
228
+ """Validated/coerced data (if valid)."""
229
+ ...
230
+
231
+ @property
232
+ def errors(self) -> List[Dict[str, Any]]:
233
+ """Validation errors (if any)."""
234
+ ...