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,385 @@
1
+ """
2
+ Quality Tracking Store - Storage backends for metrics.
3
+
4
+ Provides Protocol definition and implementations for storing
5
+ validation metrics.
6
+ """
7
+
8
+ import json
9
+ import sqlite3
10
+ import threading
11
+ from collections import defaultdict
12
+ from datetime import datetime, timedelta
13
+ from pathlib import Path
14
+ from typing import Any, Dict, List, Optional, Protocol
15
+
16
+ from pycharter.quality.tracking.models import MetricsFilter, MetricsSummary, ValidationMetric
17
+
18
+
19
+ class MetricsStore(Protocol):
20
+ """
21
+ Protocol for metrics storage backends.
22
+
23
+ Implementations must provide methods for storing, querying,
24
+ and summarizing validation metrics.
25
+ """
26
+
27
+ def store(self, metric: ValidationMetric) -> None:
28
+ """Store a validation metric."""
29
+ ...
30
+
31
+ def query(self, filters: MetricsFilter) -> List[ValidationMetric]:
32
+ """Query metrics with filters."""
33
+ ...
34
+
35
+ def get_summary(
36
+ self, schema_name: str, window_hours: int = 24
37
+ ) -> MetricsSummary:
38
+ """Get aggregated summary for a schema within a time window."""
39
+ ...
40
+
41
+ def delete(self, metric_id: str) -> bool:
42
+ """Delete a metric by ID. Returns True if deleted."""
43
+ ...
44
+
45
+ def clear(self, schema_name: Optional[str] = None) -> int:
46
+ """Clear metrics. If schema_name provided, only clear that schema. Returns count deleted."""
47
+ ...
48
+
49
+
50
+ class InMemoryMetricsStore:
51
+ """
52
+ In-memory metrics store for testing and development.
53
+
54
+ Stores metrics in memory. Data is lost when the process ends.
55
+ Thread-safe implementation.
56
+ """
57
+
58
+ def __init__(self, max_metrics: int = 10000):
59
+ """
60
+ Initialize in-memory store.
61
+
62
+ Args:
63
+ max_metrics: Maximum number of metrics to store (oldest removed when exceeded)
64
+ """
65
+ self._metrics: List[ValidationMetric] = []
66
+ self._lock = threading.Lock()
67
+ self._max_metrics = max_metrics
68
+
69
+ def store(self, metric: ValidationMetric) -> None:
70
+ """Store a validation metric."""
71
+ with self._lock:
72
+ self._metrics.append(metric)
73
+ # Remove oldest if over limit
74
+ if len(self._metrics) > self._max_metrics:
75
+ self._metrics = self._metrics[-self._max_metrics :]
76
+
77
+ def query(self, filters: MetricsFilter) -> List[ValidationMetric]:
78
+ """Query metrics with filters."""
79
+ with self._lock:
80
+ results = self._metrics.copy()
81
+
82
+ # Apply filters
83
+ if filters.schema_name:
84
+ results = [m for m in results if m.schema_name == filters.schema_name]
85
+ if filters.version:
86
+ results = [m for m in results if m.version == filters.version]
87
+ if filters.since:
88
+ results = [m for m in results if m.timestamp >= filters.since]
89
+ if filters.until:
90
+ results = [m for m in results if m.timestamp <= filters.until]
91
+ if filters.min_validity_rate is not None:
92
+ results = [m for m in results if m.validity_rate >= filters.min_validity_rate]
93
+
94
+ # Sort by timestamp descending (most recent first)
95
+ results.sort(key=lambda m: m.timestamp, reverse=True)
96
+
97
+ # Apply pagination
98
+ if filters.offset:
99
+ results = results[filters.offset :]
100
+ if filters.limit:
101
+ results = results[: filters.limit]
102
+
103
+ return results
104
+
105
+ def get_summary(
106
+ self, schema_name: str, window_hours: int = 24
107
+ ) -> MetricsSummary:
108
+ """Get aggregated summary for a schema within a time window."""
109
+ cutoff = datetime.utcnow() - timedelta(hours=window_hours)
110
+
111
+ filters = MetricsFilter(schema_name=schema_name, since=cutoff, limit=0)
112
+ metrics = self.query(filters)
113
+
114
+ if not metrics:
115
+ return MetricsSummary(
116
+ schema_name=schema_name,
117
+ period_start=cutoff,
118
+ period_end=datetime.utcnow(),
119
+ )
120
+
121
+ return self._compute_summary(schema_name, metrics, cutoff, datetime.utcnow())
122
+
123
+ def _compute_summary(
124
+ self,
125
+ schema_name: str,
126
+ metrics: List[ValidationMetric],
127
+ period_start: datetime,
128
+ period_end: datetime,
129
+ ) -> MetricsSummary:
130
+ """Compute summary statistics from a list of metrics."""
131
+ if not metrics:
132
+ return MetricsSummary(
133
+ schema_name=schema_name,
134
+ period_start=period_start,
135
+ period_end=period_end,
136
+ )
137
+
138
+ total_validations = len(metrics)
139
+ total_records = sum(m.record_count for m in metrics)
140
+ total_valid = sum(m.valid_count for m in metrics)
141
+ total_errors = sum(m.error_count for m in metrics)
142
+
143
+ validity_rates = [m.validity_rate for m in metrics]
144
+ avg_validity_rate = sum(validity_rates) / len(validity_rates)
145
+ min_validity_rate = min(validity_rates)
146
+ max_validity_rate = max(validity_rates)
147
+
148
+ completeness_values = [m.completeness for m in metrics]
149
+ avg_completeness = sum(completeness_values) / len(completeness_values)
150
+
151
+ durations = [m.duration_ms for m in metrics]
152
+ avg_duration_ms = sum(durations) / len(durations)
153
+
154
+ # Aggregate error types
155
+ error_counts: Dict[str, int] = defaultdict(int)
156
+ for m in metrics:
157
+ for error_type, count in m.errors_by_type.items():
158
+ error_counts[error_type] += count
159
+
160
+ # Get top 10 error types
161
+ top_errors = dict(
162
+ sorted(error_counts.items(), key=lambda x: x[1], reverse=True)[:10]
163
+ )
164
+
165
+ return MetricsSummary(
166
+ schema_name=schema_name,
167
+ period_start=period_start,
168
+ period_end=period_end,
169
+ total_validations=total_validations,
170
+ total_records=total_records,
171
+ total_valid=total_valid,
172
+ total_errors=total_errors,
173
+ avg_validity_rate=avg_validity_rate,
174
+ min_validity_rate=min_validity_rate,
175
+ max_validity_rate=max_validity_rate,
176
+ avg_completeness=avg_completeness,
177
+ avg_duration_ms=avg_duration_ms,
178
+ top_error_types=top_errors,
179
+ )
180
+
181
+ def delete(self, metric_id: str) -> bool:
182
+ """Delete a metric by ID."""
183
+ with self._lock:
184
+ original_len = len(self._metrics)
185
+ self._metrics = [m for m in self._metrics if m.id != metric_id]
186
+ return len(self._metrics) < original_len
187
+
188
+ def clear(self, schema_name: Optional[str] = None) -> int:
189
+ """Clear metrics."""
190
+ with self._lock:
191
+ if schema_name:
192
+ original_len = len(self._metrics)
193
+ self._metrics = [m for m in self._metrics if m.schema_name != schema_name]
194
+ return original_len - len(self._metrics)
195
+ else:
196
+ count = len(self._metrics)
197
+ self._metrics = []
198
+ return count
199
+
200
+
201
+ class SQLiteMetricsStore:
202
+ """
203
+ SQLite-based persistent metrics store.
204
+
205
+ Stores metrics in a SQLite database for persistence across restarts.
206
+ Thread-safe implementation.
207
+ """
208
+
209
+ def __init__(self, db_path: str = "metrics.db"):
210
+ """
211
+ Initialize SQLite store.
212
+
213
+ Args:
214
+ db_path: Path to SQLite database file
215
+ """
216
+ self._db_path = db_path
217
+ self._lock = threading.Lock()
218
+ self._init_db()
219
+
220
+ def _init_db(self) -> None:
221
+ """Initialize database schema."""
222
+ with self._get_connection() as conn:
223
+ conn.execute("""
224
+ CREATE TABLE IF NOT EXISTS validation_metrics (
225
+ id TEXT PRIMARY KEY,
226
+ schema_name TEXT NOT NULL,
227
+ version TEXT NOT NULL,
228
+ timestamp TEXT NOT NULL,
229
+ record_count INTEGER DEFAULT 0,
230
+ valid_count INTEGER DEFAULT 0,
231
+ error_count INTEGER DEFAULT 0,
232
+ validity_rate REAL DEFAULT 1.0,
233
+ completeness REAL DEFAULT 1.0,
234
+ field_completeness TEXT DEFAULT '{}',
235
+ duration_ms REAL DEFAULT 0.0,
236
+ errors_by_type TEXT DEFAULT '{}',
237
+ metadata TEXT DEFAULT '{}'
238
+ )
239
+ """)
240
+ conn.execute("""
241
+ CREATE INDEX IF NOT EXISTS idx_schema_name
242
+ ON validation_metrics(schema_name)
243
+ """)
244
+ conn.execute("""
245
+ CREATE INDEX IF NOT EXISTS idx_timestamp
246
+ ON validation_metrics(timestamp)
247
+ """)
248
+ conn.commit()
249
+
250
+ def _get_connection(self) -> sqlite3.Connection:
251
+ """Get database connection."""
252
+ return sqlite3.connect(self._db_path)
253
+
254
+ def store(self, metric: ValidationMetric) -> None:
255
+ """Store a validation metric."""
256
+ with self._lock:
257
+ with self._get_connection() as conn:
258
+ conn.execute(
259
+ """
260
+ INSERT OR REPLACE INTO validation_metrics
261
+ (id, schema_name, version, timestamp, record_count, valid_count,
262
+ error_count, validity_rate, completeness, field_completeness,
263
+ duration_ms, errors_by_type, metadata)
264
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
265
+ """,
266
+ (
267
+ metric.id,
268
+ metric.schema_name,
269
+ metric.version,
270
+ metric.timestamp.isoformat(),
271
+ metric.record_count,
272
+ metric.valid_count,
273
+ metric.error_count,
274
+ metric.validity_rate,
275
+ metric.completeness,
276
+ json.dumps(metric.field_completeness),
277
+ metric.duration_ms,
278
+ json.dumps(metric.errors_by_type),
279
+ json.dumps(metric.metadata),
280
+ ),
281
+ )
282
+ conn.commit()
283
+
284
+ def query(self, filters: MetricsFilter) -> List[ValidationMetric]:
285
+ """Query metrics with filters."""
286
+ conditions = []
287
+ params: List[Any] = []
288
+
289
+ if filters.schema_name:
290
+ conditions.append("schema_name = ?")
291
+ params.append(filters.schema_name)
292
+ if filters.version:
293
+ conditions.append("version = ?")
294
+ params.append(filters.version)
295
+ if filters.since:
296
+ conditions.append("timestamp >= ?")
297
+ params.append(filters.since.isoformat())
298
+ if filters.until:
299
+ conditions.append("timestamp <= ?")
300
+ params.append(filters.until.isoformat())
301
+ if filters.min_validity_rate is not None:
302
+ conditions.append("validity_rate >= ?")
303
+ params.append(filters.min_validity_rate)
304
+
305
+ where_clause = " AND ".join(conditions) if conditions else "1=1"
306
+ query = f"""
307
+ SELECT * FROM validation_metrics
308
+ WHERE {where_clause}
309
+ ORDER BY timestamp DESC
310
+ LIMIT ? OFFSET ?
311
+ """
312
+ params.extend([filters.limit, filters.offset])
313
+
314
+ with self._lock:
315
+ with self._get_connection() as conn:
316
+ conn.row_factory = sqlite3.Row
317
+ cursor = conn.execute(query, params)
318
+ rows = cursor.fetchall()
319
+
320
+ return [self._row_to_metric(row) for row in rows]
321
+
322
+ def _row_to_metric(self, row: sqlite3.Row) -> ValidationMetric:
323
+ """Convert database row to ValidationMetric."""
324
+ return ValidationMetric(
325
+ id=row["id"],
326
+ schema_name=row["schema_name"],
327
+ version=row["version"],
328
+ timestamp=datetime.fromisoformat(row["timestamp"]),
329
+ record_count=row["record_count"],
330
+ valid_count=row["valid_count"],
331
+ error_count=row["error_count"],
332
+ validity_rate=row["validity_rate"],
333
+ completeness=row["completeness"],
334
+ field_completeness=json.loads(row["field_completeness"]),
335
+ duration_ms=row["duration_ms"],
336
+ errors_by_type=json.loads(row["errors_by_type"]),
337
+ metadata=json.loads(row["metadata"]),
338
+ )
339
+
340
+ def get_summary(
341
+ self, schema_name: str, window_hours: int = 24
342
+ ) -> MetricsSummary:
343
+ """Get aggregated summary for a schema within a time window."""
344
+ cutoff = datetime.utcnow() - timedelta(hours=window_hours)
345
+
346
+ filters = MetricsFilter(
347
+ schema_name=schema_name, since=cutoff, limit=10000 # Get all for summary
348
+ )
349
+ metrics = self.query(filters)
350
+
351
+ if not metrics:
352
+ return MetricsSummary(
353
+ schema_name=schema_name,
354
+ period_start=cutoff,
355
+ period_end=datetime.utcnow(),
356
+ )
357
+
358
+ # Reuse InMemoryMetricsStore's compute logic
359
+ return InMemoryMetricsStore()._compute_summary(
360
+ schema_name, metrics, cutoff, datetime.utcnow()
361
+ )
362
+
363
+ def delete(self, metric_id: str) -> bool:
364
+ """Delete a metric by ID."""
365
+ with self._lock:
366
+ with self._get_connection() as conn:
367
+ cursor = conn.execute(
368
+ "DELETE FROM validation_metrics WHERE id = ?", (metric_id,)
369
+ )
370
+ conn.commit()
371
+ return cursor.rowcount > 0
372
+
373
+ def clear(self, schema_name: Optional[str] = None) -> int:
374
+ """Clear metrics."""
375
+ with self._lock:
376
+ with self._get_connection() as conn:
377
+ if schema_name:
378
+ cursor = conn.execute(
379
+ "DELETE FROM validation_metrics WHERE schema_name = ?",
380
+ (schema_name,),
381
+ )
382
+ else:
383
+ cursor = conn.execute("DELETE FROM validation_metrics")
384
+ conn.commit()
385
+ return cursor.rowcount
@@ -19,23 +19,33 @@ in pycharter. It can be instantiated with contract artifacts from various source
19
19
  >>> validator = Validator(store=store, schema_id="user_schema")
20
20
  >>> result = validator.validate({"name": "Alice", "age": 30})
21
21
  >>>
22
- >>> # From contract file
23
- >>> validator = Validator(contract_file="contracts/user.yaml")
22
+ >>> # Using builder pattern
23
+ >>> from pycharter.runtime_validator import ValidatorBuilder
24
+ >>> validator = (
25
+ ... ValidatorBuilder()
26
+ ... .from_directory("data/contracts/user")
27
+ ... .strict()
28
+ ... .with_quality_checks()
29
+ ... .build()
30
+ ... )
24
31
  >>> result = validator.validate({"name": "Alice", "age": 30})
32
+ >>> print(result.quality.completeness)
25
33
 
26
34
  Core Components:
27
- - validator: Validator class (PRIMARY INTERFACE - use this for all validation)
28
- - validator_core: Core validation utilities (ValidationResult, validate, validate_batch)
29
- - wrappers: Convenience wrapper functions
30
- - decorators: Validation decorators for functions
35
+ - Validator: Primary validation class
36
+ - ValidatorBuilder: Fluent API for constructing validators
37
+ - ValidationResult: Validation result with optional quality metrics
38
+ - QualityMetrics: Data quality metrics
31
39
  """
32
40
 
41
+ from pycharter.runtime_validator.builder import ValidatorBuilder
33
42
  from pycharter.runtime_validator.decorators import (
34
43
  validate_input,
35
44
  validate_output,
36
45
  validate_with_contract as validate_with_contract_decorator,
37
46
  )
38
47
  from pycharter.runtime_validator.validator_core import (
48
+ QualityMetrics,
39
49
  ValidationResult,
40
50
  validate,
41
51
  validate_batch,
@@ -54,10 +64,13 @@ from pycharter.runtime_validator.validator import (
54
64
  )
55
65
 
56
66
  __all__ = [
57
- # PRIMARY INTERFACE: Validator class (use this for all validation)
67
+ # PRIMARY INTERFACE: Validator and Builder
58
68
  "Validator",
69
+ "ValidatorBuilder",
59
70
  "create_validator",
71
+ # Result classes
60
72
  "ValidationResult",
73
+ "QualityMetrics",
61
74
  # Low-level validation functions (for direct model validation)
62
75
  "validate",
63
76
  "validate_batch",