pycharter 0.0.24__py3-none-any.whl → 0.0.26__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 (567) hide show
  1. pycharter/__init__.py +6 -0
  2. pycharter/api/README.md +340 -0
  3. {api → pycharter/api}/__init__.py +1 -1
  4. {api → pycharter/api}/dependencies/__init__.py +2 -2
  5. pycharter/api/dependencies/auth.py +158 -0
  6. {api → pycharter/api}/main.py +32 -4
  7. {api → pycharter/api}/models/__init__.py +4 -4
  8. pycharter/api/models/etl.py +66 -0
  9. {api → pycharter/api}/routes/v1/__init__.py +5 -1
  10. pycharter/api/routes/v1/auth.py +97 -0
  11. {api → pycharter/api}/routes/v1/contracts.py +14 -12
  12. {api → pycharter/api}/routes/v1/docs.py +2 -2
  13. pycharter/api/routes/v1/etl.py +131 -0
  14. {api → pycharter/api}/routes/v1/evolution.py +2 -2
  15. {api → pycharter/api}/routes/v1/metadata.py +5 -5
  16. {api → pycharter/api}/routes/v1/quality.py +3 -3
  17. {api → pycharter/api}/routes/v1/schemas.py +1 -1
  18. {api → pycharter/api}/routes/v1/settings.py +1 -1
  19. {api → pycharter/api}/routes/v1/tracking.py +1 -1
  20. {api → pycharter/api}/routes/v1/validation.py +2 -2
  21. {api → pycharter/api}/routes/v1/validation_jobs.py +3 -3
  22. pycharter/cli.py +9 -11
  23. pycharter/config.py +69 -0
  24. pycharter/contract_builder/builder.py +32 -37
  25. pycharter/data/seed/compliance_frameworks.yaml +22 -0
  26. pycharter/data/seed/contracts.yaml +130 -0
  27. pycharter/data/seed/data_feeds.yaml +22 -0
  28. pycharter/data/seed/domains.yaml +13 -0
  29. pycharter/data/seed/environments.yaml +19 -0
  30. pycharter/data/seed/owners.yaml +21 -0
  31. pycharter/data/seed/systems.yaml +13 -0
  32. pycharter/data/seed/tags.yaml +25 -0
  33. pycharter/data/templates/contract/README.md +161 -0
  34. pycharter/data/templates/contract/template_contract.yaml +37 -0
  35. pycharter/data/templates/etl/README.md +1 -1
  36. pycharter/data/templates/etl/extract_with_validation.yaml +86 -0
  37. pycharter/data/templates/etl/load_with_validation.yaml +111 -0
  38. pycharter/data/templates/etl/settings.yaml +55 -0
  39. pycharter/db/README.md +179 -0
  40. pycharter/db/cli.py +126 -4
  41. pycharter/db/migrations/versions/20260122000000_change_artifact_unique_constraints_to_title_version.py +2 -2
  42. pycharter/db/schemas/README.md +96 -0
  43. pycharter/etl_generator/ASYNC_AND_EXECUTION.md +91 -0
  44. pycharter/etl_generator/INTERFACES.md +142 -0
  45. pycharter/etl_generator/README.md +271 -0
  46. pycharter/etl_generator/TRANSFORMATION_GUIDE.md +452 -0
  47. pycharter/etl_generator/__init__.py +47 -11
  48. pycharter/etl_generator/config_models.py +673 -0
  49. pycharter/etl_generator/config_validator.py +133 -157
  50. pycharter/etl_generator/context.py +3 -0
  51. pycharter/etl_generator/database.py +5 -1
  52. pycharter/etl_generator/extractors/__init__.py +4 -2
  53. pycharter/etl_generator/extractors/cloud_storage.py +9 -9
  54. pycharter/etl_generator/extractors/database.py +2 -2
  55. pycharter/etl_generator/extractors/factory.py +15 -33
  56. pycharter/etl_generator/extractors/file.py +2 -2
  57. pycharter/etl_generator/extractors/http.py +2 -2
  58. pycharter/etl_generator/extractors/mongodb.py +393 -0
  59. pycharter/etl_generator/extractors/streaming.py +2 -2
  60. pycharter/etl_generator/loaders/__init__.py +15 -9
  61. pycharter/etl_generator/loaders/{cloud_storage_loader.py → cloud_storage.py} +95 -2
  62. pycharter/etl_generator/loaders/factory.py +16 -29
  63. pycharter/etl_generator/loaders/file.py +135 -1
  64. pycharter/etl_generator/loaders/mongodb.py +416 -0
  65. pycharter/etl_generator/pipeline.py +283 -164
  66. pycharter/etl_generator/result.py +16 -0
  67. pycharter/etl_generator/schemas/__init__.py +71 -42
  68. pycharter/etl_generator/transformers/config.py +3 -2
  69. pycharter/etl_generator/transformers/simple_operations.py +57 -4
  70. pycharter/etl_generator/validation.py +551 -0
  71. pycharter/metadata_store/README.md +229 -0
  72. pycharter/quality/README.md +235 -0
  73. pycharter/runtime_validator/__init__.py +7 -0
  74. pycharter/runtime_validator/utils.py +33 -0
  75. pycharter/runtime_validator/validator.py +13 -10
  76. pycharter/ui/.eslintrc.json +4 -0
  77. pycharter/ui/README.md +186 -0
  78. {ui → pycharter/ui}/__init__.py +3 -3
  79. pycharter/ui/components.json +17 -0
  80. pycharter/ui/package-lock.json +6617 -0
  81. pycharter/ui/package.json +37 -0
  82. {ui → pycharter/ui}/server.py +7 -8
  83. pycharter/ui/static/404/index.html +1 -0
  84. pycharter/ui/static/404.html +1 -0
  85. pycharter/ui/static/__next.__PAGE__.txt +10 -0
  86. pycharter/ui/static/__next._full.txt +30 -0
  87. pycharter/ui/static/__next._head.txt +7 -0
  88. pycharter/ui/static/__next._index.txt +9 -0
  89. pycharter/ui/static/__next._tree.txt +2 -0
  90. pycharter/ui/static/_next/static/YCnlK66gA7FV5vvcixspB/_clientMiddlewareManifest.json +1 -0
  91. pycharter/ui/static/_next/static/chunks/0fc1f70b787b8845.js +1 -0
  92. pycharter/ui/static/_next/static/chunks/17bb8075d7b75663.css +1 -0
  93. pycharter/ui/static/_next/static/chunks/381932864dcbfdb8.js +1 -0
  94. pycharter/ui/static/_next/static/chunks/4c951b8e4507e2b3.js +1 -0
  95. pycharter/ui/static/_next/static/chunks/68b87a6f65abd3ed.js +1 -0
  96. pycharter/ui/static/_next/static/chunks/78572617b8fae189.js +1 -0
  97. pycharter/ui/static/_next/static/chunks/8b7be2803e3fe184.js +1 -0
  98. pycharter/ui/static/_next/static/chunks/a8e529fd1e67f121.js +1 -0
  99. pycharter/ui/static/_next/static/chunks/c35d998f80be3ff5.js +1 -0
  100. pycharter/ui/static/_next/static/chunks/e453aa5d01c32c17.js +1 -0
  101. pycharter/ui/static/_next/static/chunks/f2d240eb057f898a.js +970 -0
  102. pycharter/ui/static/_next/static/chunks/f7722448f6040846.js +1 -0
  103. pycharter/ui/static/_not-found/__next._full.txt +17 -0
  104. pycharter/ui/static/_not-found/__next._head.txt +7 -0
  105. pycharter/ui/static/_not-found/__next._index.txt +9 -0
  106. pycharter/ui/static/_not-found/__next._not-found.__PAGE__.txt +5 -0
  107. pycharter/ui/static/_not-found/__next._not-found.txt +4 -0
  108. pycharter/ui/static/_not-found/__next._tree.txt +2 -0
  109. pycharter/ui/static/_not-found/index.html +1 -0
  110. pycharter/ui/static/_not-found/index.txt +17 -0
  111. pycharter/ui/static/contracts/__next._full.txt +21 -0
  112. pycharter/ui/static/contracts/__next._head.txt +7 -0
  113. pycharter/ui/static/contracts/__next._index.txt +9 -0
  114. pycharter/ui/static/contracts/__next._tree.txt +2 -0
  115. pycharter/ui/static/contracts/__next.contracts.__PAGE__.txt +9 -0
  116. pycharter/ui/static/contracts/__next.contracts.txt +4 -0
  117. pycharter/ui/static/contracts/index.html +1 -0
  118. pycharter/ui/static/contracts/index.txt +21 -0
  119. pycharter/ui/static/documentation/__next._full.txt +21 -0
  120. pycharter/ui/static/documentation/__next._head.txt +7 -0
  121. pycharter/ui/static/documentation/__next._index.txt +9 -0
  122. pycharter/ui/static/documentation/__next._tree.txt +2 -0
  123. pycharter/ui/static/documentation/__next.documentation.__PAGE__.txt +9 -0
  124. pycharter/ui/static/documentation/__next.documentation.txt +4 -0
  125. pycharter/ui/static/documentation/index.html +93 -0
  126. pycharter/ui/static/documentation/index.txt +21 -0
  127. pycharter/ui/static/etl/__next._full.txt +21 -0
  128. pycharter/ui/static/etl/__next._head.txt +7 -0
  129. pycharter/ui/static/etl/__next._index.txt +9 -0
  130. pycharter/ui/static/etl/__next._tree.txt +2 -0
  131. pycharter/ui/static/etl/__next.etl.__PAGE__.txt +9 -0
  132. pycharter/ui/static/etl/__next.etl.txt +4 -0
  133. pycharter/ui/static/etl/index.html +2 -0
  134. pycharter/ui/static/etl/index.txt +21 -0
  135. pycharter/ui/static/index.html +1 -0
  136. pycharter/ui/static/index.txt +30 -0
  137. pycharter/ui/static/metadata/__next._full.txt +21 -0
  138. pycharter/ui/static/metadata/__next._head.txt +7 -0
  139. pycharter/ui/static/metadata/__next._index.txt +9 -0
  140. pycharter/ui/static/metadata/__next._tree.txt +2 -0
  141. pycharter/ui/static/metadata/__next.metadata.__PAGE__.txt +9 -0
  142. pycharter/ui/static/metadata/__next.metadata.txt +4 -0
  143. pycharter/ui/static/metadata/index.html +1 -0
  144. pycharter/ui/static/metadata/index.txt +21 -0
  145. pycharter/ui/static/quality/__next._full.txt +21 -0
  146. pycharter/ui/static/quality/__next._head.txt +7 -0
  147. pycharter/ui/static/quality/__next._index.txt +9 -0
  148. pycharter/ui/static/quality/__next._tree.txt +2 -0
  149. pycharter/ui/static/quality/__next.quality.__PAGE__.txt +9 -0
  150. pycharter/ui/static/quality/__next.quality.txt +4 -0
  151. pycharter/ui/static/quality/index.html +2 -0
  152. pycharter/ui/static/quality/index.txt +21 -0
  153. pycharter/ui/static/rules/__next._full.txt +21 -0
  154. pycharter/ui/static/rules/__next._head.txt +7 -0
  155. pycharter/ui/static/rules/__next._index.txt +9 -0
  156. pycharter/ui/static/rules/__next._tree.txt +2 -0
  157. pycharter/ui/static/rules/__next.rules.__PAGE__.txt +9 -0
  158. pycharter/ui/static/rules/__next.rules.txt +4 -0
  159. pycharter/ui/static/rules/index.html +1 -0
  160. pycharter/ui/static/rules/index.txt +21 -0
  161. pycharter/ui/static/schemas/__next._full.txt +21 -0
  162. pycharter/ui/static/schemas/__next._head.txt +7 -0
  163. pycharter/ui/static/schemas/__next._index.txt +9 -0
  164. pycharter/ui/static/schemas/__next._tree.txt +2 -0
  165. pycharter/ui/static/schemas/__next.schemas.__PAGE__.txt +9 -0
  166. pycharter/ui/static/schemas/__next.schemas.txt +4 -0
  167. pycharter/ui/static/schemas/index.html +1 -0
  168. pycharter/ui/static/schemas/index.txt +21 -0
  169. pycharter/ui/static/settings/__next._full.txt +21 -0
  170. pycharter/ui/static/settings/__next._head.txt +7 -0
  171. pycharter/ui/static/settings/__next._index.txt +9 -0
  172. pycharter/ui/static/settings/__next._tree.txt +2 -0
  173. pycharter/ui/static/settings/__next.settings.__PAGE__.txt +9 -0
  174. pycharter/ui/static/settings/__next.settings.txt +4 -0
  175. pycharter/ui/static/settings/index.html +1 -0
  176. pycharter/ui/static/settings/index.txt +21 -0
  177. pycharter/ui/static/static/_next/static/2gKjNv6YvE6BcIdFthBLs/_clientMiddlewareManifest.json +1 -0
  178. pycharter/ui/static/static/static/_next/static/0rYA78L88aUyD2Uh38hhX/_clientMiddlewareManifest.json +1 -0
  179. pycharter/ui/static/static/static/_next/static/chunks/f7d1a90dd75d2572.js +1 -0
  180. pycharter/ui/static/static/static/static/.gitkeep +0 -0
  181. pycharter/ui/static/static/static/static/_next/static/chunks/222442f6da32302a.js +1 -0
  182. pycharter/ui/static/static/static/static/_next/static/chunks/247eb132b7f7b574.js +1 -0
  183. pycharter/ui/static/static/static/static/_next/static/chunks/297d55555b71baba.js +1 -0
  184. pycharter/ui/static/static/static/static/_next/static/chunks/414e77373f8ff61c.js +1 -0
  185. pycharter/ui/static/static/static/static/_next/static/chunks/652ad0aa26265c47.js +2 -0
  186. pycharter/ui/static/static/static/static/_next/static/chunks/9c23f44fff36548a.js +1 -0
  187. pycharter/ui/static/static/static/static/_next/static/chunks/a6dad97d9634a72d.js +1 -0
  188. pycharter/ui/static/static/static/static/_next/static/chunks/b32a0963684b9933.js +4 -0
  189. pycharter/ui/static/static/static/static/_next/static/chunks/db913959c675cea6.js +1 -0
  190. pycharter/ui/static/static/static/static/_next/static/chunks/f2e7afeab1178138.js +1 -0
  191. pycharter/ui/static/static/static/static/_next/static/chunks/ff1a16fafef87110.js +1 -0
  192. pycharter/ui/static/static/static/static/_next/static/chunks/turbopack-ffcb7ab6794027ef.js +3 -0
  193. pycharter/ui/static/static/static/static/_next/static/tNTkVW6puVXC4bAm4WrHl/_buildManifest.js +11 -0
  194. pycharter/ui/static/static/static/static/_next/static/tNTkVW6puVXC4bAm4WrHl/_clientMiddlewareManifest.json +1 -0
  195. pycharter/ui/static/static/static/static/_next/static/tNTkVW6puVXC4bAm4WrHl/_ssgManifest.js +1 -0
  196. pycharter/ui/static/validation/__next._full.txt +21 -0
  197. pycharter/ui/static/validation/__next._head.txt +7 -0
  198. pycharter/ui/static/validation/__next._index.txt +9 -0
  199. pycharter/ui/static/validation/__next._tree.txt +2 -0
  200. pycharter/ui/static/validation/__next.validation.__PAGE__.txt +9 -0
  201. pycharter/ui/static/validation/__next.validation.txt +4 -0
  202. pycharter/ui/static/validation/index.html +1 -0
  203. pycharter/ui/static/validation/index.txt +21 -0
  204. pycharter/ui/tsconfig.json +42 -0
  205. pycharter/worker/README.md +187 -0
  206. pycharter/worker/backends/__init__.py +8 -0
  207. pycharter/worker/backends/base.py +46 -0
  208. pycharter/worker/backends/spark.py +233 -0
  209. {worker → pycharter/worker}/cli.py +1 -1
  210. {worker → pycharter/worker}/processor.py +2 -2
  211. pycharter/worker/queue/__init__.py +8 -0
  212. pycharter/worker/queue/redis_queue.py +147 -0
  213. {pycharter-0.0.24.dist-info → pycharter-0.0.26.dist-info}/METADATA +57 -26
  214. pycharter-0.0.26.dist-info/RECORD +702 -0
  215. pycharter-0.0.26.dist-info/top_level.txt +1 -0
  216. pycharter/etl_generator/config_loader.py +0 -394
  217. pycharter/etl_generator/loaders/cloud.py +0 -87
  218. pycharter/etl_generator/loaders/file_loader.py +0 -130
  219. pycharter-0.0.24.dist-info/RECORD +0 -543
  220. pycharter-0.0.24.dist-info/top_level.txt +0 -4
  221. {api → pycharter/api}/dependencies/database.py +0 -0
  222. {api → pycharter/api}/dependencies/store.py +0 -0
  223. {api → pycharter/api}/models/contracts.py +0 -0
  224. {api → pycharter/api}/models/docs.py +0 -0
  225. {api → pycharter/api}/models/evolution.py +0 -0
  226. {api → pycharter/api}/models/metadata.py +0 -0
  227. {api → pycharter/api}/models/metadata_entities.py +0 -0
  228. {api → pycharter/api}/models/quality.py +0 -0
  229. {api → pycharter/api}/models/schemas.py +0 -0
  230. {api → pycharter/api}/models/tracking.py +0 -0
  231. {api → pycharter/api}/models/validation.py +0 -0
  232. {api → pycharter/api}/routes/__init__.py +0 -0
  233. {api → pycharter/api}/routes/v1/templates.py +0 -0
  234. {api → pycharter/api}/utils.py +0 -0
  235. {ui → pycharter/ui}/build.py +0 -0
  236. {ui → pycharter/ui}/dev.py +0 -0
  237. {ui → pycharter/ui}/static/.gitkeep +0 -0
  238. {ui/static/_next/static/2gKjNv6YvE6BcIdFthBLs → pycharter/ui/static/_next/static/YCnlK66gA7FV5vvcixspB}/_buildManifest.js +0 -0
  239. {ui/static/_next/static/2gKjNv6YvE6BcIdFthBLs → pycharter/ui/static/_next/static/YCnlK66gA7FV5vvcixspB}/_ssgManifest.js +0 -0
  240. {ui → pycharter/ui}/static/_next/static/chunks/222442f6da32302a.js +0 -0
  241. {ui → pycharter/ui}/static/_next/static/chunks/247eb132b7f7b574.js +0 -0
  242. {ui → pycharter/ui}/static/_next/static/chunks/297d55555b71baba.js +0 -0
  243. {ui → pycharter/ui}/static/_next/static/chunks/414e77373f8ff61c.js +0 -0
  244. {ui → pycharter/ui}/static/_next/static/chunks/652ad0aa26265c47.js +0 -0
  245. {ui → pycharter/ui}/static/_next/static/chunks/9c23f44fff36548a.js +0 -0
  246. {ui → pycharter/ui}/static/_next/static/chunks/a6dad97d9634a72d.js +0 -0
  247. {ui → pycharter/ui}/static/_next/static/chunks/b32a0963684b9933.js +0 -0
  248. {ui → pycharter/ui}/static/_next/static/chunks/db913959c675cea6.js +0 -0
  249. {ui → pycharter/ui}/static/_next/static/chunks/f2e7afeab1178138.js +0 -0
  250. {ui → pycharter/ui}/static/_next/static/chunks/f7d1a90dd75d2572.js +0 -0
  251. {ui → pycharter/ui}/static/_next/static/chunks/ff1a16fafef87110.js +0 -0
  252. {ui → pycharter/ui}/static/_next/static/chunks/turbopack-ffcb7ab6794027ef.js +0 -0
  253. {ui → pycharter/ui}/static/static/.gitkeep +0 -0
  254. {ui → pycharter/ui/static}/static/404/index.html +0 -0
  255. {ui → pycharter/ui/static}/static/404.html +0 -0
  256. {ui → pycharter/ui/static}/static/__next.__PAGE__.txt +0 -0
  257. {ui → pycharter/ui/static}/static/__next._full.txt +0 -0
  258. {ui → pycharter/ui/static}/static/__next._head.txt +0 -0
  259. {ui → pycharter/ui/static}/static/__next._index.txt +0 -0
  260. {ui → pycharter/ui/static}/static/__next._tree.txt +0 -0
  261. {ui/static/static/_next/static/0rYA78L88aUyD2Uh38hhX → pycharter/ui/static/static/_next/static/2gKjNv6YvE6BcIdFthBLs}/_buildManifest.js +0 -0
  262. {ui/static/static/_next/static/0rYA78L88aUyD2Uh38hhX → pycharter/ui/static/static/_next/static/2gKjNv6YvE6BcIdFthBLs}/_ssgManifest.js +0 -0
  263. {ui → pycharter/ui/static}/static/_next/static/chunks/13d4a0fbd74c1ee4.js +0 -0
  264. {ui → pycharter/ui}/static/static/_next/static/chunks/222442f6da32302a.js +0 -0
  265. {ui → pycharter/ui}/static/static/_next/static/chunks/247eb132b7f7b574.js +0 -0
  266. {ui → pycharter/ui/static}/static/_next/static/chunks/26dfc590f7714c03.js +0 -0
  267. {ui → pycharter/ui}/static/static/_next/static/chunks/297d55555b71baba.js +0 -0
  268. {ui → pycharter/ui/static}/static/_next/static/chunks/2ab439ce003cd691.js +0 -0
  269. {ui → pycharter/ui/static}/static/_next/static/chunks/2edb43b48432ac04.js +0 -0
  270. {ui → pycharter/ui/static}/static/_next/static/chunks/34d289e6db2ef551.js +0 -0
  271. {ui → pycharter/ui}/static/static/_next/static/chunks/414e77373f8ff61c.js +0 -0
  272. {ui → pycharter/ui/static}/static/_next/static/chunks/49ca65abd26ae49e.js +0 -0
  273. {ui → pycharter/ui}/static/static/_next/static/chunks/652ad0aa26265c47.js +0 -0
  274. {ui → pycharter/ui/static}/static/_next/static/chunks/9667e7a3d359eb39.js +0 -0
  275. {ui → pycharter/ui/static}/static/_next/static/chunks/99508d9d5869cc27.js +0 -0
  276. {ui → pycharter/ui}/static/static/_next/static/chunks/9c23f44fff36548a.js +0 -0
  277. {ui → pycharter/ui}/static/static/_next/static/chunks/a6dad97d9634a72d.js +0 -0
  278. {ui → pycharter/ui/static}/static/_next/static/chunks/b313c35a6ba76574.js +0 -0
  279. {ui → pycharter/ui}/static/static/_next/static/chunks/b32a0963684b9933.js +0 -0
  280. {ui → pycharter/ui/static}/static/_next/static/chunks/c69f6cba366bd988.js +0 -0
  281. {ui → pycharter/ui/static}/static/_next/static/chunks/d2363397e1b2bcab.css +0 -0
  282. {ui → pycharter/ui}/static/static/_next/static/chunks/db913959c675cea6.js +0 -0
  283. {ui → pycharter/ui/static}/static/_next/static/chunks/f061a4be97bfc3b3.js +0 -0
  284. {ui → pycharter/ui}/static/static/_next/static/chunks/f2e7afeab1178138.js +0 -0
  285. {ui → pycharter/ui}/static/static/_next/static/chunks/f7d1a90dd75d2572.js +0 -0
  286. {ui → pycharter/ui}/static/static/_next/static/chunks/ff1a16fafef87110.js +0 -0
  287. {ui → pycharter/ui}/static/static/_next/static/chunks/turbopack-ffcb7ab6794027ef.js +0 -0
  288. {ui → pycharter/ui/static}/static/_not-found/__next._full.txt +0 -0
  289. {ui → pycharter/ui/static}/static/_not-found/__next._head.txt +0 -0
  290. {ui → pycharter/ui/static}/static/_not-found/__next._index.txt +0 -0
  291. {ui → pycharter/ui/static}/static/_not-found/__next._not-found.__PAGE__.txt +0 -0
  292. {ui → pycharter/ui/static}/static/_not-found/__next._not-found.txt +0 -0
  293. {ui → pycharter/ui/static}/static/_not-found/__next._tree.txt +0 -0
  294. {ui → pycharter/ui/static}/static/_not-found/index.html +0 -0
  295. {ui → pycharter/ui/static}/static/_not-found/index.txt +0 -0
  296. {ui → pycharter/ui/static}/static/contracts/__next._full.txt +0 -0
  297. {ui → pycharter/ui/static}/static/contracts/__next._head.txt +0 -0
  298. {ui → pycharter/ui/static}/static/contracts/__next._index.txt +0 -0
  299. {ui → pycharter/ui/static}/static/contracts/__next._tree.txt +0 -0
  300. {ui → pycharter/ui/static}/static/contracts/__next.contracts.__PAGE__.txt +0 -0
  301. {ui → pycharter/ui/static}/static/contracts/__next.contracts.txt +0 -0
  302. {ui → pycharter/ui/static}/static/contracts/index.html +0 -0
  303. {ui → pycharter/ui/static}/static/contracts/index.txt +0 -0
  304. {ui → pycharter/ui/static}/static/documentation/__next._full.txt +0 -0
  305. {ui → pycharter/ui/static}/static/documentation/__next._head.txt +0 -0
  306. {ui → pycharter/ui/static}/static/documentation/__next._index.txt +0 -0
  307. {ui → pycharter/ui/static}/static/documentation/__next._tree.txt +0 -0
  308. {ui → pycharter/ui/static}/static/documentation/__next.documentation.__PAGE__.txt +0 -0
  309. {ui → pycharter/ui/static}/static/documentation/__next.documentation.txt +0 -0
  310. {ui → pycharter/ui/static}/static/documentation/index.html +0 -0
  311. {ui → pycharter/ui/static}/static/documentation/index.txt +0 -0
  312. {ui → pycharter/ui/static}/static/index.html +0 -0
  313. {ui → pycharter/ui/static}/static/index.txt +0 -0
  314. {ui → pycharter/ui/static}/static/metadata/__next._full.txt +0 -0
  315. {ui → pycharter/ui/static}/static/metadata/__next._head.txt +0 -0
  316. {ui → pycharter/ui/static}/static/metadata/__next._index.txt +0 -0
  317. {ui → pycharter/ui/static}/static/metadata/__next._tree.txt +0 -0
  318. {ui → pycharter/ui/static}/static/metadata/__next.metadata.__PAGE__.txt +0 -0
  319. {ui → pycharter/ui/static}/static/metadata/__next.metadata.txt +0 -0
  320. {ui → pycharter/ui/static}/static/metadata/index.html +0 -0
  321. {ui → pycharter/ui/static}/static/metadata/index.txt +0 -0
  322. {ui → pycharter/ui/static}/static/quality/__next._full.txt +0 -0
  323. {ui → pycharter/ui/static}/static/quality/__next._head.txt +0 -0
  324. {ui → pycharter/ui/static}/static/quality/__next._index.txt +0 -0
  325. {ui → pycharter/ui/static}/static/quality/__next._tree.txt +0 -0
  326. {ui → pycharter/ui/static}/static/quality/__next.quality.__PAGE__.txt +0 -0
  327. {ui → pycharter/ui/static}/static/quality/__next.quality.txt +0 -0
  328. {ui → pycharter/ui/static}/static/quality/index.html +0 -0
  329. {ui → pycharter/ui/static}/static/quality/index.txt +0 -0
  330. {ui → pycharter/ui/static}/static/rules/__next._full.txt +0 -0
  331. {ui → pycharter/ui/static}/static/rules/__next._head.txt +0 -0
  332. {ui → pycharter/ui/static}/static/rules/__next._index.txt +0 -0
  333. {ui → pycharter/ui/static}/static/rules/__next._tree.txt +0 -0
  334. {ui → pycharter/ui/static}/static/rules/__next.rules.__PAGE__.txt +0 -0
  335. {ui → pycharter/ui/static}/static/rules/__next.rules.txt +0 -0
  336. {ui → pycharter/ui/static}/static/rules/index.html +0 -0
  337. {ui → pycharter/ui/static}/static/rules/index.txt +0 -0
  338. {ui → pycharter/ui/static}/static/schemas/__next._full.txt +0 -0
  339. {ui → pycharter/ui/static}/static/schemas/__next._head.txt +0 -0
  340. {ui → pycharter/ui/static}/static/schemas/__next._index.txt +0 -0
  341. {ui → pycharter/ui/static}/static/schemas/__next._tree.txt +0 -0
  342. {ui → pycharter/ui/static}/static/schemas/__next.schemas.__PAGE__.txt +0 -0
  343. {ui → pycharter/ui/static}/static/schemas/__next.schemas.txt +0 -0
  344. {ui → pycharter/ui/static}/static/schemas/index.html +0 -0
  345. {ui → pycharter/ui/static}/static/schemas/index.txt +0 -0
  346. {ui → pycharter/ui/static}/static/settings/__next._full.txt +0 -0
  347. {ui → pycharter/ui/static}/static/settings/__next._head.txt +0 -0
  348. {ui → pycharter/ui/static}/static/settings/__next._index.txt +0 -0
  349. {ui → pycharter/ui/static}/static/settings/__next._tree.txt +0 -0
  350. {ui → pycharter/ui/static}/static/settings/__next.settings.__PAGE__.txt +0 -0
  351. {ui → pycharter/ui/static}/static/settings/__next.settings.txt +0 -0
  352. {ui → pycharter/ui/static}/static/settings/index.html +0 -0
  353. {ui → pycharter/ui/static}/static/settings/index.txt +0 -0
  354. {ui → pycharter/ui}/static/static/static/.gitkeep +0 -0
  355. {ui → pycharter/ui/static}/static/static/404/index.html +0 -0
  356. {ui → pycharter/ui/static}/static/static/404.html +0 -0
  357. {ui → pycharter/ui/static}/static/static/__next.__PAGE__.txt +0 -0
  358. {ui → pycharter/ui/static}/static/static/__next._full.txt +0 -0
  359. {ui → pycharter/ui/static}/static/static/__next._head.txt +0 -0
  360. {ui → pycharter/ui/static}/static/static/__next._index.txt +0 -0
  361. {ui → pycharter/ui/static}/static/static/__next._tree.txt +0 -0
  362. {ui/static/static/static/_next/static/tNTkVW6puVXC4bAm4WrHl → pycharter/ui/static/static/static/_next/static/0rYA78L88aUyD2Uh38hhX}/_buildManifest.js +0 -0
  363. {ui/static/static/static/_next/static/tNTkVW6puVXC4bAm4WrHl → pycharter/ui/static/static/static/_next/static/0rYA78L88aUyD2Uh38hhX}/_ssgManifest.js +0 -0
  364. {ui → pycharter/ui/static}/static/static/_next/static/chunks/13d4a0fbd74c1ee4.js +0 -0
  365. {ui → pycharter/ui}/static/static/static/_next/static/chunks/222442f6da32302a.js +0 -0
  366. {ui → pycharter/ui}/static/static/static/_next/static/chunks/247eb132b7f7b574.js +0 -0
  367. {ui → pycharter/ui}/static/static/static/_next/static/chunks/297d55555b71baba.js +0 -0
  368. {ui → pycharter/ui/static}/static/static/_next/static/chunks/2ab439ce003cd691.js +0 -0
  369. {ui → pycharter/ui/static}/static/static/_next/static/chunks/2edb43b48432ac04.js +0 -0
  370. {ui → pycharter/ui}/static/static/static/_next/static/chunks/414e77373f8ff61c.js +0 -0
  371. {ui → pycharter/ui/static}/static/static/_next/static/chunks/49ca65abd26ae49e.js +0 -0
  372. {ui → pycharter/ui/static}/static/static/_next/static/chunks/5e04d10c4a7b58a3.js +0 -0
  373. {ui → pycharter/ui}/static/static/static/_next/static/chunks/652ad0aa26265c47.js +0 -0
  374. {ui → pycharter/ui/static}/static/static/_next/static/chunks/75d88a058d8ffaa6.js +0 -0
  375. {ui → pycharter/ui/static}/static/static/_next/static/chunks/8c89634cf6bad76f.js +0 -0
  376. {ui → pycharter/ui/static}/static/static/_next/static/chunks/9667e7a3d359eb39.js +0 -0
  377. {ui → pycharter/ui}/static/static/static/_next/static/chunks/9c23f44fff36548a.js +0 -0
  378. {ui → pycharter/ui}/static/static/static/_next/static/chunks/a6dad97d9634a72d.js +0 -0
  379. {ui → pycharter/ui}/static/static/static/_next/static/chunks/b32a0963684b9933.js +0 -0
  380. {ui → pycharter/ui/static}/static/static/_next/static/chunks/c4fa4f4114b7c352.js +0 -0
  381. {ui → pycharter/ui/static}/static/static/_next/static/chunks/c69f6cba366bd988.js +0 -0
  382. {ui → pycharter/ui/static}/static/static/_next/static/chunks/d2363397e1b2bcab.css +0 -0
  383. {ui → pycharter/ui}/static/static/static/_next/static/chunks/db913959c675cea6.js +0 -0
  384. {ui → pycharter/ui/static}/static/static/_next/static/chunks/f061a4be97bfc3b3.js +0 -0
  385. {ui → pycharter/ui}/static/static/static/_next/static/chunks/f2e7afeab1178138.js +0 -0
  386. {ui → pycharter/ui}/static/static/static/_next/static/chunks/ff1a16fafef87110.js +0 -0
  387. {ui → pycharter/ui}/static/static/static/_next/static/chunks/turbopack-ffcb7ab6794027ef.js +0 -0
  388. {ui → pycharter/ui/static}/static/static/_not-found/__next._full.txt +0 -0
  389. {ui → pycharter/ui/static}/static/static/_not-found/__next._head.txt +0 -0
  390. {ui → pycharter/ui/static}/static/static/_not-found/__next._index.txt +0 -0
  391. {ui → pycharter/ui/static}/static/static/_not-found/__next._not-found.__PAGE__.txt +0 -0
  392. {ui → pycharter/ui/static}/static/static/_not-found/__next._not-found.txt +0 -0
  393. {ui → pycharter/ui/static}/static/static/_not-found/__next._tree.txt +0 -0
  394. {ui → pycharter/ui/static}/static/static/_not-found/index.html +0 -0
  395. {ui → pycharter/ui/static}/static/static/_not-found/index.txt +0 -0
  396. {ui → pycharter/ui/static}/static/static/contracts/__next._full.txt +0 -0
  397. {ui → pycharter/ui/static}/static/static/contracts/__next._head.txt +0 -0
  398. {ui → pycharter/ui/static}/static/static/contracts/__next._index.txt +0 -0
  399. {ui → pycharter/ui/static}/static/static/contracts/__next._tree.txt +0 -0
  400. {ui → pycharter/ui/static}/static/static/contracts/__next.contracts.__PAGE__.txt +0 -0
  401. {ui → pycharter/ui/static}/static/static/contracts/__next.contracts.txt +0 -0
  402. {ui → pycharter/ui/static}/static/static/contracts/index.html +0 -0
  403. {ui → pycharter/ui/static}/static/static/contracts/index.txt +0 -0
  404. {ui → pycharter/ui/static}/static/static/documentation/__next._full.txt +0 -0
  405. {ui → pycharter/ui/static}/static/static/documentation/__next._head.txt +0 -0
  406. {ui → pycharter/ui/static}/static/static/documentation/__next._index.txt +0 -0
  407. {ui → pycharter/ui/static}/static/static/documentation/__next._tree.txt +0 -0
  408. {ui → pycharter/ui/static}/static/static/documentation/__next.documentation.__PAGE__.txt +0 -0
  409. {ui → pycharter/ui/static}/static/static/documentation/__next.documentation.txt +0 -0
  410. {ui → pycharter/ui/static}/static/static/documentation/index.html +0 -0
  411. {ui → pycharter/ui/static}/static/static/documentation/index.txt +0 -0
  412. {ui → pycharter/ui/static}/static/static/index.html +0 -0
  413. {ui → pycharter/ui/static}/static/static/index.txt +0 -0
  414. {ui → pycharter/ui/static}/static/static/metadata/__next._full.txt +0 -0
  415. {ui → pycharter/ui/static}/static/static/metadata/__next._head.txt +0 -0
  416. {ui → pycharter/ui/static}/static/static/metadata/__next._index.txt +0 -0
  417. {ui → pycharter/ui/static}/static/static/metadata/__next._tree.txt +0 -0
  418. {ui → pycharter/ui/static}/static/static/metadata/__next.metadata.__PAGE__.txt +0 -0
  419. {ui → pycharter/ui/static}/static/static/metadata/__next.metadata.txt +0 -0
  420. {ui → pycharter/ui/static}/static/static/metadata/index.html +0 -0
  421. {ui → pycharter/ui/static}/static/static/metadata/index.txt +0 -0
  422. {ui → pycharter/ui/static}/static/static/quality/__next._full.txt +0 -0
  423. {ui → pycharter/ui/static}/static/static/quality/__next._head.txt +0 -0
  424. {ui → pycharter/ui/static}/static/static/quality/__next._index.txt +0 -0
  425. {ui → pycharter/ui/static}/static/static/quality/__next._tree.txt +0 -0
  426. {ui → pycharter/ui/static}/static/static/quality/__next.quality.__PAGE__.txt +0 -0
  427. {ui → pycharter/ui/static}/static/static/quality/__next.quality.txt +0 -0
  428. {ui → pycharter/ui/static}/static/static/quality/index.html +0 -0
  429. {ui → pycharter/ui/static}/static/static/quality/index.txt +0 -0
  430. {ui → pycharter/ui/static}/static/static/rules/__next._full.txt +0 -0
  431. {ui → pycharter/ui/static}/static/static/rules/__next._head.txt +0 -0
  432. {ui → pycharter/ui/static}/static/static/rules/__next._index.txt +0 -0
  433. {ui → pycharter/ui/static}/static/static/rules/__next._tree.txt +0 -0
  434. {ui → pycharter/ui/static}/static/static/rules/__next.rules.__PAGE__.txt +0 -0
  435. {ui → pycharter/ui/static}/static/static/rules/__next.rules.txt +0 -0
  436. {ui → pycharter/ui/static}/static/static/rules/index.html +0 -0
  437. {ui → pycharter/ui/static}/static/static/rules/index.txt +0 -0
  438. {ui → pycharter/ui/static}/static/static/schemas/__next._full.txt +0 -0
  439. {ui → pycharter/ui/static}/static/static/schemas/__next._head.txt +0 -0
  440. {ui → pycharter/ui/static}/static/static/schemas/__next._index.txt +0 -0
  441. {ui → pycharter/ui/static}/static/static/schemas/__next._tree.txt +0 -0
  442. {ui → pycharter/ui/static}/static/static/schemas/__next.schemas.__PAGE__.txt +0 -0
  443. {ui → pycharter/ui/static}/static/static/schemas/__next.schemas.txt +0 -0
  444. {ui → pycharter/ui/static}/static/static/schemas/index.html +0 -0
  445. {ui → pycharter/ui/static}/static/static/schemas/index.txt +0 -0
  446. {ui → pycharter/ui/static}/static/static/settings/__next._full.txt +0 -0
  447. {ui → pycharter/ui/static}/static/static/settings/__next._head.txt +0 -0
  448. {ui → pycharter/ui/static}/static/static/settings/__next._index.txt +0 -0
  449. {ui → pycharter/ui/static}/static/static/settings/__next._tree.txt +0 -0
  450. {ui → pycharter/ui/static}/static/static/settings/__next.settings.__PAGE__.txt +0 -0
  451. {ui → pycharter/ui/static}/static/static/settings/__next.settings.txt +0 -0
  452. {ui → pycharter/ui/static}/static/static/settings/index.html +0 -0
  453. {ui → pycharter/ui/static}/static/static/settings/index.txt +0 -0
  454. {ui → pycharter/ui/static}/static/static/static/404/index.html +0 -0
  455. {ui → pycharter/ui/static}/static/static/static/404.html +0 -0
  456. {ui → pycharter/ui/static}/static/static/static/__next.__PAGE__.txt +0 -0
  457. {ui → pycharter/ui/static}/static/static/static/__next._full.txt +0 -0
  458. {ui → pycharter/ui/static}/static/static/static/__next._head.txt +0 -0
  459. {ui → pycharter/ui/static}/static/static/static/__next._index.txt +0 -0
  460. {ui → pycharter/ui/static}/static/static/static/__next._tree.txt +0 -0
  461. {ui → pycharter/ui/static}/static/static/static/_next/static/chunks/2ab439ce003cd691.js +0 -0
  462. {ui → pycharter/ui/static}/static/static/static/_next/static/chunks/49ca65abd26ae49e.js +0 -0
  463. {ui → pycharter/ui/static}/static/static/static/_next/static/chunks/4e310fe5005770a3.css +0 -0
  464. {ui → pycharter/ui/static}/static/static/static/_next/static/chunks/5e04d10c4a7b58a3.js +0 -0
  465. {ui → pycharter/ui/static}/static/static/static/_next/static/chunks/5fc14c00a2779dc5.js +0 -0
  466. {ui → pycharter/ui/static}/static/static/static/_next/static/chunks/75d88a058d8ffaa6.js +0 -0
  467. {ui → pycharter/ui/static}/static/static/static/_next/static/chunks/8c89634cf6bad76f.js +0 -0
  468. {ui → pycharter/ui/static}/static/static/static/_next/static/chunks/9667e7a3d359eb39.js +0 -0
  469. {ui → pycharter/ui/static}/static/static/static/_next/static/chunks/b584574fdc8ab13e.js +0 -0
  470. {ui → pycharter/ui/static}/static/static/static/_next/static/chunks/c69f6cba366bd988.js +0 -0
  471. {ui → pycharter/ui/static}/static/static/static/_next/static/chunks/d5989c94d3614b3a.js +0 -0
  472. {ui → pycharter/ui/static}/static/static/static/_next/static/chunks/f061a4be97bfc3b3.js +0 -0
  473. {ui → pycharter/ui/static}/static/static/static/_not-found/__next._full.txt +0 -0
  474. {ui → pycharter/ui/static}/static/static/static/_not-found/__next._head.txt +0 -0
  475. {ui → pycharter/ui/static}/static/static/static/_not-found/__next._index.txt +0 -0
  476. {ui → pycharter/ui/static}/static/static/static/_not-found/__next._not-found.__PAGE__.txt +0 -0
  477. {ui → pycharter/ui/static}/static/static/static/_not-found/__next._not-found.txt +0 -0
  478. {ui → pycharter/ui/static}/static/static/static/_not-found/__next._tree.txt +0 -0
  479. {ui → pycharter/ui/static}/static/static/static/_not-found/index.html +0 -0
  480. {ui → pycharter/ui/static}/static/static/static/_not-found/index.txt +0 -0
  481. {ui → pycharter/ui/static}/static/static/static/contracts/__next._full.txt +0 -0
  482. {ui → pycharter/ui/static}/static/static/static/contracts/__next._head.txt +0 -0
  483. {ui → pycharter/ui/static}/static/static/static/contracts/__next._index.txt +0 -0
  484. {ui → pycharter/ui/static}/static/static/static/contracts/__next._tree.txt +0 -0
  485. {ui → pycharter/ui/static}/static/static/static/contracts/__next.contracts.__PAGE__.txt +0 -0
  486. {ui → pycharter/ui/static}/static/static/static/contracts/__next.contracts.txt +0 -0
  487. {ui → pycharter/ui/static}/static/static/static/contracts/index.html +0 -0
  488. {ui → pycharter/ui/static}/static/static/static/contracts/index.txt +0 -0
  489. {ui → pycharter/ui/static}/static/static/static/documentation/__next._full.txt +0 -0
  490. {ui → pycharter/ui/static}/static/static/static/documentation/__next._head.txt +0 -0
  491. {ui → pycharter/ui/static}/static/static/static/documentation/__next._index.txt +0 -0
  492. {ui → pycharter/ui/static}/static/static/static/documentation/__next._tree.txt +0 -0
  493. {ui → pycharter/ui/static}/static/static/static/documentation/__next.documentation.__PAGE__.txt +0 -0
  494. {ui → pycharter/ui/static}/static/static/static/documentation/__next.documentation.txt +0 -0
  495. {ui → pycharter/ui/static}/static/static/static/documentation/index.html +0 -0
  496. {ui → pycharter/ui/static}/static/static/static/documentation/index.txt +0 -0
  497. {ui → pycharter/ui/static}/static/static/static/index.html +0 -0
  498. {ui → pycharter/ui/static}/static/static/static/index.txt +0 -0
  499. {ui → pycharter/ui/static}/static/static/static/metadata/__next._full.txt +0 -0
  500. {ui → pycharter/ui/static}/static/static/static/metadata/__next._head.txt +0 -0
  501. {ui → pycharter/ui/static}/static/static/static/metadata/__next._index.txt +0 -0
  502. {ui → pycharter/ui/static}/static/static/static/metadata/__next._tree.txt +0 -0
  503. {ui → pycharter/ui/static}/static/static/static/metadata/__next.metadata.__PAGE__.txt +0 -0
  504. {ui → pycharter/ui/static}/static/static/static/metadata/__next.metadata.txt +0 -0
  505. {ui → pycharter/ui/static}/static/static/static/metadata/index.html +0 -0
  506. {ui → pycharter/ui/static}/static/static/static/metadata/index.txt +0 -0
  507. {ui → pycharter/ui/static}/static/static/static/quality/__next._full.txt +0 -0
  508. {ui → pycharter/ui/static}/static/static/static/quality/__next._head.txt +0 -0
  509. {ui → pycharter/ui/static}/static/static/static/quality/__next._index.txt +0 -0
  510. {ui → pycharter/ui/static}/static/static/static/quality/__next._tree.txt +0 -0
  511. {ui → pycharter/ui/static}/static/static/static/quality/__next.quality.__PAGE__.txt +0 -0
  512. {ui → pycharter/ui/static}/static/static/static/quality/__next.quality.txt +0 -0
  513. {ui → pycharter/ui/static}/static/static/static/quality/index.html +0 -0
  514. {ui → pycharter/ui/static}/static/static/static/quality/index.txt +0 -0
  515. {ui → pycharter/ui/static}/static/static/static/rules/__next._full.txt +0 -0
  516. {ui → pycharter/ui/static}/static/static/static/rules/__next._head.txt +0 -0
  517. {ui → pycharter/ui/static}/static/static/static/rules/__next._index.txt +0 -0
  518. {ui → pycharter/ui/static}/static/static/static/rules/__next._tree.txt +0 -0
  519. {ui → pycharter/ui/static}/static/static/static/rules/__next.rules.__PAGE__.txt +0 -0
  520. {ui → pycharter/ui/static}/static/static/static/rules/__next.rules.txt +0 -0
  521. {ui → pycharter/ui/static}/static/static/static/rules/index.html +0 -0
  522. {ui → pycharter/ui/static}/static/static/static/rules/index.txt +0 -0
  523. {ui → pycharter/ui/static}/static/static/static/schemas/__next._full.txt +0 -0
  524. {ui → pycharter/ui/static}/static/static/static/schemas/__next._head.txt +0 -0
  525. {ui → pycharter/ui/static}/static/static/static/schemas/__next._index.txt +0 -0
  526. {ui → pycharter/ui/static}/static/static/static/schemas/__next._tree.txt +0 -0
  527. {ui → pycharter/ui/static}/static/static/static/schemas/__next.schemas.__PAGE__.txt +0 -0
  528. {ui → pycharter/ui/static}/static/static/static/schemas/__next.schemas.txt +0 -0
  529. {ui → pycharter/ui/static}/static/static/static/schemas/index.html +0 -0
  530. {ui → pycharter/ui/static}/static/static/static/schemas/index.txt +0 -0
  531. {ui → pycharter/ui/static}/static/static/static/settings/__next._full.txt +0 -0
  532. {ui → pycharter/ui/static}/static/static/static/settings/__next._head.txt +0 -0
  533. {ui → pycharter/ui/static}/static/static/static/settings/__next._index.txt +0 -0
  534. {ui → pycharter/ui/static}/static/static/static/settings/__next._tree.txt +0 -0
  535. {ui → pycharter/ui/static}/static/static/static/settings/__next.settings.__PAGE__.txt +0 -0
  536. {ui → pycharter/ui/static}/static/static/static/settings/__next.settings.txt +0 -0
  537. {ui → pycharter/ui/static}/static/static/static/settings/index.html +0 -0
  538. {ui → pycharter/ui/static}/static/static/static/settings/index.txt +0 -0
  539. {ui → pycharter/ui/static}/static/static/static/validation/__next._full.txt +0 -0
  540. {ui → pycharter/ui/static}/static/static/static/validation/__next._head.txt +0 -0
  541. {ui → pycharter/ui/static}/static/static/static/validation/__next._index.txt +0 -0
  542. {ui → pycharter/ui/static}/static/static/static/validation/__next._tree.txt +0 -0
  543. {ui → pycharter/ui/static}/static/static/static/validation/__next.validation.__PAGE__.txt +0 -0
  544. {ui → pycharter/ui/static}/static/static/static/validation/__next.validation.txt +0 -0
  545. {ui → pycharter/ui/static}/static/static/static/validation/index.html +0 -0
  546. {ui → pycharter/ui/static}/static/static/static/validation/index.txt +0 -0
  547. {ui → pycharter/ui/static}/static/static/validation/__next._full.txt +0 -0
  548. {ui → pycharter/ui/static}/static/static/validation/__next._head.txt +0 -0
  549. {ui → pycharter/ui/static}/static/static/validation/__next._index.txt +0 -0
  550. {ui → pycharter/ui/static}/static/static/validation/__next._tree.txt +0 -0
  551. {ui → pycharter/ui/static}/static/static/validation/__next.validation.__PAGE__.txt +0 -0
  552. {ui → pycharter/ui/static}/static/static/validation/__next.validation.txt +0 -0
  553. {ui → pycharter/ui/static}/static/static/validation/index.html +0 -0
  554. {ui → pycharter/ui/static}/static/static/validation/index.txt +0 -0
  555. {ui → pycharter/ui/static}/static/validation/__next._full.txt +0 -0
  556. {ui → pycharter/ui/static}/static/validation/__next._head.txt +0 -0
  557. {ui → pycharter/ui/static}/static/validation/__next._index.txt +0 -0
  558. {ui → pycharter/ui/static}/static/validation/__next._tree.txt +0 -0
  559. {ui → pycharter/ui/static}/static/validation/__next.validation.__PAGE__.txt +0 -0
  560. {ui → pycharter/ui/static}/static/validation/__next.validation.txt +0 -0
  561. {ui → pycharter/ui/static}/static/validation/index.html +0 -0
  562. {ui → pycharter/ui/static}/static/validation/index.txt +0 -0
  563. {worker → pycharter/worker}/__init__.py +0 -0
  564. {worker → pycharter/worker}/models.py +0 -0
  565. {pycharter-0.0.24.dist-info → pycharter-0.0.26.dist-info}/WHEEL +0 -0
  566. {pycharter-0.0.24.dist-info → pycharter-0.0.26.dist-info}/entry_points.txt +0 -0
  567. {pycharter-0.0.24.dist-info → pycharter-0.0.26.dist-info}/licenses/LICENSE +0 -0
@@ -3,7 +3,15 @@ Contract Builder - Constructs consolidated data contracts from separate artifact
3
3
 
4
4
  This module provides functionality to combine separate artifacts (schema, coercion rules,
5
5
  validation rules, metadata) into a single consolidated data contract that tracks all
6
- component versions and can be used for runtime validation.
6
+ component versions.
7
+
8
+ Note: The contract dict contains RAW schema + separate rules. The Validator class
9
+ handles merging rules into the schema internally during validation. This separation
10
+ ensures clarity:
11
+ - contract["schema"] = raw schema (editable, source of truth)
12
+ - contract["coercion_rules"] = separate coercion rules
13
+ - contract["validation_rules"] = separate validation rules
14
+ - For merged schema, use Validator or merge_rules_into_schema() utility
7
15
  """
8
16
 
9
17
  import copy
@@ -11,10 +19,6 @@ from dataclasses import dataclass
11
19
  from typing import Any, Dict, Optional
12
20
 
13
21
  from pycharter.metadata_store import MetadataStoreClient
14
- from pycharter.metadata_store.client import (
15
- _merge_coercion_rules,
16
- _merge_validation_rules,
17
- )
18
22
 
19
23
 
20
24
  @dataclass
@@ -82,8 +86,12 @@ def build_contract(
82
86
  Build a consolidated data contract from separate artifacts.
83
87
 
84
88
  This function combines schema, coercion rules, validation rules, and metadata
85
- into a single consolidated contract. It tracks versions of all components
86
- and produces a contract suitable for runtime validation.
89
+ into a single consolidated contract. It tracks versions of all components.
90
+
91
+ IMPORTANT: The schema in the returned contract is RAW (not merged with rules).
92
+ The Validator class handles merging rules into the schema internally during
93
+ validation. To get a merged schema explicitly, use merge_rules_into_schema()
94
+ from pycharter.runtime_validator.utils.
87
95
 
88
96
  Args:
89
97
  artifacts: ContractArtifacts object containing all separate artifacts
@@ -93,9 +101,9 @@ def build_contract(
93
101
 
94
102
  Returns:
95
103
  Consolidated contract dictionary with:
96
- - schema: Complete schema with coercion/validation rules merged (must have version)
97
- - coercion_rules: Coercion rules (if provided)
98
- - validation_rules: Validation rules (if provided)
104
+ - schema: RAW schema (no coercion/validation merged; must have version)
105
+ - coercion_rules: Coercion rules dictionary (always present, may be empty)
106
+ - validation_rules: Validation rules dictionary (always present, may be empty)
99
107
  - metadata: Metadata containing ownership and governance_rules (if include_metadata=True)
100
108
  - versions: Dictionary tracking versions of all components
101
109
 
@@ -116,10 +124,10 @@ def build_contract(
116
124
  >>> contract = build_contract(artifacts)
117
125
  >>> contract["versions"]
118
126
  {'schema': '1.0.0', 'coercion_rules': '1.0.0', 'validation_rules': '1.0.0', 'metadata': '1.0.0'}
119
- >>> contract["metadata"]["ownership"]
120
- {'owner': 'data-team', 'team': 'engineering'}
121
- >>> contract["metadata"]["governance_rules"]
122
- {'data_retention': {'days': 365}}
127
+ >>> contract["coercion_rules"] # Separate from schema
128
+ {'age': 'coerce_to_integer'}
129
+ >>> contract["schema"]["properties"]["age"].get("coercion") # Not in schema
130
+ None
123
131
  """
124
132
  if not artifacts.schema:
125
133
  raise ValueError("Schema is required to build a contract")
@@ -131,34 +139,21 @@ def build_contract(
131
139
  "Please ensure the schema dictionary contains 'version': '<version_string>'."
132
140
  )
133
141
 
134
- # Deep copy schema to avoid modifying original
135
- complete_schema = copy.deepcopy(artifacts.schema)
136
-
137
- # Extract and merge coercion rules
138
- coercion_rules = _extract_rules(artifacts.coercion_rules)
139
- if coercion_rules:
140
- _merge_coercion_rules(complete_schema, coercion_rules)
142
+ # Deep copy schema to avoid modifying original - NO MERGING
143
+ # The Validator class handles merging internally during validation
144
+ raw_schema = copy.deepcopy(artifacts.schema)
141
145
 
142
- # Extract and merge validation rules
143
- validation_rules = _extract_rules(artifacts.validation_rules)
144
- if validation_rules:
145
- _merge_validation_rules(complete_schema, validation_rules)
146
+ # Extract rules (but do NOT merge into schema)
147
+ coercion_rules = _extract_rules(artifacts.coercion_rules) or {}
148
+ validation_rules = _extract_rules(artifacts.validation_rules) or {}
146
149
 
147
- # Build contract
150
+ # Build contract with raw schema and separate rules
148
151
  contract: Dict[str, Any] = {
149
- "schema": complete_schema,
152
+ "schema": raw_schema,
153
+ "coercion_rules": copy.deepcopy(coercion_rules) if coercion_rules else {},
154
+ "validation_rules": copy.deepcopy(validation_rules) if validation_rules else {},
150
155
  }
151
156
 
152
- # Add coercion rules as top-level field (for UI display)
153
- # Note: coercion_rules is already extracted above
154
- if coercion_rules:
155
- contract["coercion_rules"] = copy.deepcopy(coercion_rules)
156
-
157
- # Add validation rules as top-level field (for UI display)
158
- # Note: validation_rules is already extracted above
159
- if validation_rules:
160
- contract["validation_rules"] = copy.deepcopy(validation_rules)
161
-
162
157
  # Track versions
163
158
  versions: Dict[str, str] = {}
164
159
 
@@ -0,0 +1,22 @@
1
+ # Generic seed: compliance_frameworks (name required; code, description, framework_type, is_active, additional_metadata optional)
2
+
3
+ - name: "internal-policy"
4
+ code: "INTERNAL"
5
+ description: "Internal data policy"
6
+ framework_type: "policy"
7
+ is_active: true
8
+ additional_metadata: {}
9
+
10
+ - name: "soc2"
11
+ code: "SOC2"
12
+ description: "System and Organization Controls 2"
13
+ framework_type: "certification"
14
+ is_active: true
15
+ additional_metadata: {}
16
+
17
+ - name: "gdpr"
18
+ code: "GDPR"
19
+ description: "General Data Protection Regulation"
20
+ framework_type: "regulation"
21
+ is_active: true
22
+ additional_metadata: {}
@@ -0,0 +1,130 @@
1
+ # Example contract artifacts for pycharter db seed
2
+ # Each entry creates a data contract with schema, coercion rules, validation rules, and metadata.
3
+ # Skipped if a contract with the same name and version already exists.
4
+
5
+ - name: example_user_contract
6
+ version: "1.0.0"
7
+ status: active
8
+ description: Example user data contract with schema, coercion, validation, and metadata
9
+
10
+ schema:
11
+ type: object
12
+ title: example_user
13
+ version: "1.0.0"
14
+ properties:
15
+ user_id:
16
+ type: string
17
+ description: Unique user identifier
18
+ minLength: 1
19
+ name:
20
+ type: string
21
+ description: Full name
22
+ minLength: 1
23
+ maxLength: 100
24
+ email:
25
+ type: string
26
+ format: email
27
+ description: Email address
28
+ status:
29
+ type: string
30
+ enum: [active, inactive, pending]
31
+ description: Account status
32
+ created_at:
33
+ type: string
34
+ format: date-time
35
+ description: Creation timestamp
36
+ required:
37
+ - user_id
38
+ - name
39
+ - email
40
+ - status
41
+ - created_at
42
+
43
+ coercion_rules:
44
+ title: example_user_coercion
45
+ version: "1.0.0"
46
+ rules:
47
+ user_id: coerce_to_string
48
+ name: coerce_to_stripped_string
49
+ email: coerce_to_lowercase
50
+ status: coerce_to_lowercase
51
+ created_at: coerce_to_datetime
52
+
53
+ validation_rules:
54
+ title: example_user_validation
55
+ version: "1.0.0"
56
+ rules:
57
+ user_id:
58
+ non_empty_string: null
59
+ name:
60
+ non_empty_string: null
61
+ max_length:
62
+ threshold: 100
63
+ email:
64
+ is_email: null
65
+ status:
66
+ only_allow:
67
+ allowed_values: [active, inactive, pending]
68
+
69
+ metadata:
70
+ title: example_user_metadata
71
+ version: "1.0.0"
72
+ status: active
73
+ description: Example user contract metadata
74
+ governance_rules:
75
+ data_retention:
76
+ days: 365
77
+ reason: Standard retention
78
+ sensitivity: internal
79
+ access_control:
80
+ read: [data-team]
81
+ write: [data-team]
82
+
83
+ # Second example: minimal event contract
84
+ - name: example_event_contract
85
+ version: "1.0.0"
86
+ status: active
87
+ description: Minimal event contract for demos
88
+
89
+ schema:
90
+ type: object
91
+ title: example_event
92
+ version: "1.0.0"
93
+ properties:
94
+ event_id:
95
+ type: string
96
+ description: Event identifier
97
+ event_type:
98
+ type: string
99
+ description: Type of event
100
+ occurred_at:
101
+ type: string
102
+ format: date-time
103
+ required:
104
+ - event_id
105
+ - event_type
106
+ - occurred_at
107
+
108
+ coercion_rules:
109
+ title: example_event_coercion
110
+ version: "1.0.0"
111
+ rules:
112
+ event_id: coerce_to_string
113
+ event_type: coerce_to_lowercase
114
+ occurred_at: coerce_to_datetime
115
+
116
+ validation_rules:
117
+ title: example_event_validation
118
+ version: "1.0.0"
119
+ rules:
120
+ event_id:
121
+ non_empty_string: null
122
+ event_type:
123
+ non_empty_string: null
124
+
125
+ metadata:
126
+ title: example_event_metadata
127
+ version: "1.0.0"
128
+ status: active
129
+ description: Example event contract metadata
130
+ governance_rules: {}
@@ -0,0 +1,22 @@
1
+ # Generic seed: data_feeds (name required; title, feed_type, description, is_active, additional_metadata optional)
2
+
3
+ - name: "default_feed"
4
+ title: "Default Feed"
5
+ feed_type: "batch"
6
+ description: "Default data feed"
7
+ is_active: true
8
+ additional_metadata: {}
9
+
10
+ - name: "streaming_feed"
11
+ title: "Streaming Feed"
12
+ feed_type: "streaming"
13
+ description: "Streaming data feed"
14
+ is_active: true
15
+ additional_metadata: {}
16
+
17
+ - name: "operational_feed"
18
+ title: "Operational Feed"
19
+ feed_type: "operational"
20
+ description: "Operational data feed"
21
+ is_active: true
22
+ additional_metadata: {}
@@ -0,0 +1,13 @@
1
+ # Generic seed: domains (name required; description optional)
2
+
3
+ - name: "default"
4
+ description: "Default domain"
5
+
6
+ - name: "operations"
7
+ description: "Operations and runbooks"
8
+
9
+ - name: "analytics"
10
+ description: "Analytics and reporting"
11
+
12
+ - name: "platform"
13
+ description: "Platform and infrastructure"
@@ -0,0 +1,19 @@
1
+ # Generic seed: environments (name required; description, environment_type, is_production, additional_metadata optional)
2
+
3
+ - name: "development"
4
+ description: "Development environment"
5
+ environment_type: "non_production"
6
+ is_production: false
7
+ additional_metadata: {}
8
+
9
+ - name: "staging"
10
+ description: "Staging environment"
11
+ environment_type: "non_production"
12
+ is_production: false
13
+ additional_metadata: {}
14
+
15
+ - name: "production"
16
+ description: "Production environment"
17
+ environment_type: "production"
18
+ is_production: true
19
+ additional_metadata: {}
@@ -0,0 +1,21 @@
1
+ # Generic seed: owners (id is required; name, email, team, additional_info optional)
2
+
3
+ - id: "default-owner"
4
+ name: "Default Owner"
5
+ email: "owner@example.com"
6
+ team: "data-engineering"
7
+ additional_info: {}
8
+
9
+ - id: "platform-team"
10
+ name: "Platform Team"
11
+ email: "platform@example.com"
12
+ team: "platform-engineering"
13
+ additional_info:
14
+ description: "Platform and infrastructure"
15
+
16
+ - id: "product-team"
17
+ name: "Product Team"
18
+ email: "product@example.com"
19
+ team: "product"
20
+ additional_info:
21
+ description: "Product and analytics"
@@ -0,0 +1,13 @@
1
+ # Generic seed: systems (name required; app_id, description optional)
2
+
3
+ - name: "core-api"
4
+ app_id: "APP-CORE"
5
+ description: "Core API service"
6
+
7
+ - name: "pipeline-engine"
8
+ app_id: "APP-PIPELINE"
9
+ description: "Data pipeline engine"
10
+
11
+ - name: "catalog"
12
+ app_id: "APP-CATALOG"
13
+ description: "Data catalog and metadata"
@@ -0,0 +1,25 @@
1
+ # Generic seed: tags (name required; description, category, color, additional_metadata optional)
2
+
3
+ - name: "default"
4
+ description: "Default tag"
5
+ category: "general"
6
+ color: "#808080"
7
+ additional_metadata: {}
8
+
9
+ - name: "critical"
10
+ description: "Critical data"
11
+ category: "classification"
12
+ color: "#FF0000"
13
+ additional_metadata: {}
14
+
15
+ - name: "internal"
16
+ description: "Internal use only"
17
+ category: "classification"
18
+ color: "#FFA500"
19
+ additional_metadata: {}
20
+
21
+ - name: "pii"
22
+ description: "Personally identifiable information"
23
+ category: "classification"
24
+ color: "#9933CC"
25
+ additional_metadata: {}
@@ -0,0 +1,161 @@
1
+ # Data Contract Templates
2
+
3
+ Templates for creating data contracts with schema, coercion rules, validation rules, and metadata.
4
+
5
+ ## Quick Start
6
+
7
+ ```python
8
+ from pycharter import parse_contract, validate_with_contract
9
+
10
+ # Option 1: Complete contract in one file
11
+ contract = {
12
+ "schema": {
13
+ "type": "object",
14
+ "properties": {
15
+ "id": {"type": "string"},
16
+ "name": {"type": "string", "minLength": 1},
17
+ },
18
+ "required": ["id", "name"]
19
+ },
20
+ "metadata": {"version": "1.0.0"},
21
+ "ownership": {"owner": "data-team"}
22
+ }
23
+
24
+ # Validate data
25
+ result = validate_with_contract(contract, {"id": "123", "name": "Alice"})
26
+ print(f"Valid: {result.is_valid}")
27
+ ```
28
+
29
+ ## Template Files
30
+
31
+ | Template | Description |
32
+ |----------|-------------|
33
+ | `template_contract.yaml` | Complete contract (schema + rules + metadata) |
34
+ | `template_schema.yaml` | JSON Schema with PyCharter extensions |
35
+ | `template_coercion_rules.yaml` | Data type transformation rules |
36
+ | `template_validation_rules.yaml` | Business validation rules |
37
+ | `template_metadata.yaml` | Ownership and governance metadata |
38
+
39
+ ## Contract Structure
40
+
41
+ ```yaml
42
+ # Complete contract structure (parse_contract / create-mixed compatible)
43
+ schema: # JSON Schema (required). May include inline coercion/validations
44
+ type: object
45
+ title: my_entity
46
+ version: "1.0.0"
47
+ properties:
48
+ field_name:
49
+ type: string
50
+ coercion: coerce_to_string # Optional: inline coercion
51
+ validations: # Optional: inline validation rules
52
+ max_length: {threshold: 100}
53
+
54
+ # Optional: top-level rules (same format as template_coercion_rules / template_validation_rules)
55
+ coercion_rules:
56
+ version: "1.0.0"
57
+ rules:
58
+ field_name: coerce_to_string
59
+ validation_rules:
60
+ version: "1.0.0"
61
+ rules:
62
+ field_name: { max_length: { threshold: 100 } }
63
+
64
+ # Metadata: version, description; ownership and governance_rules must be nested here
65
+ metadata:
66
+ version: "1.0.0"
67
+ description: "Contract description"
68
+ ownership: # Nested in metadata (not top-level)
69
+ owner: team-name
70
+ team: department
71
+ governance_rules: # Nested in metadata
72
+ data_retention: {days: 365}
73
+ pii_fields: {fields: [email]}
74
+
75
+ versions: # Optional: explicit version tracking
76
+ schema: "1.0.0"
77
+ coercion_rules: "1.0.0"
78
+ validation_rules: "1.0.0"
79
+ metadata: "1.0.0"
80
+ ```
81
+
82
+ ## Coercion Rules
83
+
84
+ Applied BEFORE Pydantic validation to transform input data:
85
+
86
+ | Rule | Description |
87
+ |------|-------------|
88
+ | `coerce_to_string` | Convert to string |
89
+ | `coerce_to_integer` | Convert to int |
90
+ | `coerce_to_float` | Convert to float |
91
+ | `coerce_to_boolean` | Convert to bool |
92
+ | `coerce_to_datetime` | Parse datetime |
93
+ | `coerce_to_date` | Parse date |
94
+ | `coerce_to_uuid` | Parse UUID |
95
+ | `coerce_to_lowercase` | Lowercase string |
96
+ | `coerce_to_uppercase` | Uppercase string |
97
+ | `coerce_to_stripped_string` | Trim whitespace |
98
+ | `coerce_to_nullable_*` | Handle null values |
99
+
100
+ ## Validation Rules
101
+
102
+ Applied AFTER Pydantic validation for business rules:
103
+
104
+ | Rule | Parameters | Description |
105
+ |------|------------|-------------|
106
+ | `min_length` | `{threshold: N}` | Minimum string length |
107
+ | `max_length` | `{threshold: N}` | Maximum string length |
108
+ | `greater_than_or_equal_to` | `{threshold: N}` | Minimum value |
109
+ | `less_than_or_equal_to` | `{threshold: N}` | Maximum value |
110
+ | `only_allow` | `{allowed_values: [...]}` | Enum validation |
111
+ | `non_empty_string` | `null` | Non-empty string |
112
+ | `is_email` | `null` | Email format |
113
+ | `is_url` | `null` | URL format |
114
+ | `matches_regex` | `{pattern: "..."}` | Regex match |
115
+
116
+ ## Usage Patterns
117
+
118
+ ### 1. Validate with Contract
119
+
120
+ ```python
121
+ from pycharter import validate_with_contract
122
+
123
+ result = validate_with_contract(
124
+ "path/to/contract.yaml", # or dict
125
+ {"id": "123", "name": "Alice"}
126
+ )
127
+
128
+ if result.is_valid:
129
+ print(f"Data: {result.data}")
130
+ else:
131
+ print(f"Errors: {result.errors}")
132
+ ```
133
+
134
+ ### 2. Build Contract from Artifacts
135
+
136
+ ```python
137
+ from pycharter import build_contract
138
+
139
+ contract = build_contract(
140
+ schema=schema_dict,
141
+ metadata=metadata_dict,
142
+ coercion_rules=coercion_dict,
143
+ validation_rules=validation_dict,
144
+ )
145
+ ```
146
+
147
+ ### 3. Quality Check
148
+
149
+ ```python
150
+ from pycharter import QualityCheck
151
+
152
+ report = QualityCheck().run(
153
+ contract=contract,
154
+ data=records
155
+ )
156
+ print(f"Score: {report.quality_score.overall_score}/100")
157
+ ```
158
+
159
+ ## Examples
160
+
161
+ See `docs/notebooks/03_contracts.ipynb` and `docs/notebooks/04_validation_quality.ipynb` for working examples.
@@ -89,6 +89,43 @@ schema:
89
89
  - status
90
90
  - created_at
91
91
 
92
+ # Optional: top-level coercion rules (same as template_coercion_rules.yaml structure)
93
+ # When present, parse_contract returns them; use with create-mixed or store for separate artifacts.
94
+ coercion_rules:
95
+ version: "1.0.0"
96
+ rules:
97
+ user_id: coerce_to_string
98
+ name: coerce_to_stripped_string
99
+ email: coerce_to_lowercase
100
+ age: coerce_to_integer
101
+ status: coerce_to_lowercase
102
+ created_at: coerce_to_datetime
103
+ notes: coerce_to_nullable_string
104
+
105
+ # Optional: top-level validation rules (same as template_validation_rules.yaml structure)
106
+ validation_rules:
107
+ version: "1.0.0"
108
+ rules:
109
+ user_id:
110
+ non_empty_string: null
111
+ name:
112
+ non_empty_string: null
113
+ max_length:
114
+ threshold: 100
115
+ email:
116
+ is_email: null
117
+ age:
118
+ greater_than_or_equal_to:
119
+ threshold: 0
120
+ less_than_or_equal_to:
121
+ threshold: 150
122
+ status:
123
+ only_allow:
124
+ allowed_values: [active, inactive, pending]
125
+ notes:
126
+ max_length:
127
+ threshold: 500
128
+
92
129
  # Contract metadata (ownership and governance nested inside)
93
130
  metadata:
94
131
  version: "1.0.0"
@@ -221,4 +221,4 @@ result = await pipeline.run()
221
221
 
222
222
  ## Examples
223
223
 
224
- See `examples/etl_config_example/` for working examples with config files.
224
+ See `docs/notebooks/02_etl_pipelines.ipynb` (config-driven section) for pipeline-from-YAML examples.
@@ -0,0 +1,86 @@
1
+ # Template: HTTP Extraction with Source Validation
2
+ # Copy to your pipeline directory as extract.yaml
3
+ #
4
+ # This template demonstrates source schema validation after extraction.
5
+ # Invalid records can be skipped, quarantined (sent to DLQ), or cause failures.
6
+ #
7
+ # Usage:
8
+ # pipeline = Pipeline.from_config_dir("path/to/pipeline")
9
+ # result = await pipeline.run()
10
+ # print(f"Valid records: {result.rows_transformed}")
11
+ # print(f"Quarantined at extract: {result.rows_quarantined_extract}")
12
+
13
+ title: http_extraction_with_validation
14
+ description: Extract from HTTP API with source schema validation
15
+ version: "1.0.0"
16
+
17
+ # Source type (required)
18
+ type: http
19
+
20
+ # API URL
21
+ url: https://api.example.com/v1/orders
22
+
23
+ # HTTP method
24
+ method: GET
25
+
26
+ # Request headers
27
+ headers:
28
+ Accept: application/json
29
+ Authorization: Bearer ${API_TOKEN}
30
+
31
+ # Response handling
32
+ response_format: json
33
+ response_path: data.orders # Path to data array in response
34
+
35
+ # Batch size
36
+ batch_size: 1000
37
+
38
+ # ============================================================================
39
+ # Source Schema Validation (Optional)
40
+ # ============================================================================
41
+ # Validate extracted data against a JSON/YAML schema before transformation.
42
+ # This catches malformed data early in the pipeline.
43
+
44
+ validation:
45
+ # Path to source schema file (JSON Schema or Pydantic schema YAML)
46
+ # Can be absolute or relative to config directory
47
+ schema: ./source_schema.yaml
48
+
49
+ # Action when validation fails:
50
+ # - fail: Stop pipeline immediately (default)
51
+ # - warn: Log warning but continue with all records
52
+ # - skip: Skip invalid records silently
53
+ # - quarantine: Send invalid records to DLQ
54
+ on_error: quarantine
55
+
56
+ # DLQ configuration (optional, overrides settings.yaml)
57
+ # Can be true (use settings.yaml defaults), false (disable), or object
58
+ dlq: true # Use default DLQ from settings.yaml
59
+
60
+ # Or customize per-stage:
61
+ # dlq:
62
+ # enabled: true
63
+ # backend: file
64
+ # path: ./dlq/extract
65
+
66
+ # ============================================================================
67
+ # Example Source Schema (create as source_schema.yaml)
68
+ # ============================================================================
69
+ # version: "1.0.0"
70
+ # type: object
71
+ # properties:
72
+ # order_id:
73
+ # type: string
74
+ # pattern: "^ORD-[0-9]{6}$"
75
+ # customer_id:
76
+ # type: integer
77
+ # status:
78
+ # type: string
79
+ # enum: ["pending", "processing", "shipped", "delivered"]
80
+ # total_amount:
81
+ # type: number
82
+ # minimum: 0
83
+ # required:
84
+ # - order_id
85
+ # - customer_id
86
+ # - status