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
@@ -22,27 +22,27 @@ from pycharter.etl_generator.extractors.cloud_storage import CloudStorageExtract
22
22
  from pycharter.etl_generator.extractors.database import DatabaseExtractor
23
23
  from pycharter.etl_generator.extractors.file import FileExtractor
24
24
  from pycharter.etl_generator.extractors.http import HTTPExtractor
25
+ from pycharter.etl_generator.extractors.mongodb import MongoDBExtractor
25
26
 
26
27
  logger = logging.getLogger(__name__)
27
28
 
28
29
 
29
30
  class ExtractorFactory:
30
31
  """
31
- Factory for creating extractor instances based on source type.
32
+ Factory for creating extractor instances based on type.
32
33
 
33
34
  Supports:
34
35
  - Explicit 'type' field (recommended)
35
- - Legacy 'source_type' field
36
- - Auto-detection from config keys (for backward compatibility)
36
+ - Auto-detection from config keys
37
37
 
38
38
  Example:
39
39
  # With explicit type (recommended)
40
40
  config = {"type": "http", "url": "https://api.example.com/data"}
41
41
  extractor = ExtractorFactory.create(config)
42
42
 
43
- # Auto-detected (legacy)
44
- config = {"url": "https://api.example.com/data"}
45
- extractor = ExtractorFactory.create(config) # Detected as HTTP
43
+ # Auto-detected from config keys
44
+ config = {"file_path": "/path/to/data.csv"}
45
+ extractor = ExtractorFactory.create(config) # Detected as file
46
46
  """
47
47
 
48
48
  # Registry of extractors by source type
@@ -51,6 +51,8 @@ class ExtractorFactory:
51
51
  "file": FileExtractor,
52
52
  "database": DatabaseExtractor,
53
53
  "cloud_storage": CloudStorageExtractor,
54
+ "mongodb": MongoDBExtractor,
55
+ "mongo": MongoDBExtractor, # Alias
54
56
  }
55
57
 
56
58
  @classmethod
@@ -97,8 +99,8 @@ class ExtractorFactory:
97
99
  Raises:
98
100
  ValueError: If type cannot be determined or is not registered
99
101
  """
100
- # Get type from config (check 'type' first, then 'source_type' for legacy)
101
- extract_type = config.get("type") or config.get("source_type")
102
+ # Get type from config
103
+ extract_type = config.get("type")
102
104
 
103
105
  # Auto-detect if not specified
104
106
  if not extract_type:
@@ -140,6 +142,10 @@ class ExtractorFactory:
140
142
 
141
143
  This is for backward compatibility. New configs should use explicit 'type'.
142
144
  """
145
+ # MongoDB indicators (check first as it has specific 'mongodb' config key)
146
+ if "mongodb" in config:
147
+ return "mongodb"
148
+
143
149
  # HTTP indicators
144
150
  if any(key in config for key in ("url", "base_url", "api_endpoint", "endpoint")):
145
151
  return "http"
@@ -148,7 +154,7 @@ class ExtractorFactory:
148
154
  if any(key in config for key in ("path", "file_path")) and "storage" not in config:
149
155
  return "file"
150
156
 
151
- # Database indicators
157
+ # Database indicators (SQL databases)
152
158
  if "query" in config or (
153
159
  "database" in config and "connection_string" not in config.get("database", {}).get("url", "s3")
154
160
  ):
@@ -159,27 +165,3 @@ class ExtractorFactory:
159
165
  return "cloud_storage"
160
166
 
161
167
  return None
162
-
163
- # Legacy method names for backward compatibility
164
- @classmethod
165
- def register_extractor(cls, source_type: str, extractor_class: Type[BaseExtractor]) -> None:
166
- """Legacy method. Use register() instead."""
167
- cls.register(source_type, extractor_class)
168
-
169
- @classmethod
170
- def get_extractor(cls, extract_config: Dict[str, Any]) -> BaseExtractor:
171
- """Legacy method. Use create() instead."""
172
- return cls.create(extract_config)
173
-
174
-
175
- def get_extractor(extract_config: Dict[str, Any]) -> BaseExtractor:
176
- """
177
- Convenience function to get extractor instance.
178
-
179
- Args:
180
- extract_config: Extract configuration dictionary
181
-
182
- Returns:
183
- Extractor instance
184
- """
185
- return ExtractorFactory.create(extract_config)
@@ -99,8 +99,8 @@ class FileExtractor(BaseExtractor):
99
99
 
100
100
  def validate_config(self, extract_config: Dict[str, Any]) -> None:
101
101
  """Validate file extractor configuration."""
102
- if 'source_type' in extract_config and extract_config['source_type'] != 'file':
103
- raise ValueError(f"FileExtractor requires source_type='file', got '{extract_config.get('source_type')}'")
102
+ if 'type' in extract_config and extract_config['type'] != 'file':
103
+ raise ValueError(f"FileExtractor requires type='file', got '{extract_config.get('type')}'")
104
104
 
105
105
  file_path = extract_config.get('file_path')
106
106
  if not file_path:
@@ -121,8 +121,8 @@ class HTTPExtractor(BaseExtractor):
121
121
 
122
122
  def validate_config(self, extract_config: Dict[str, Any]) -> None:
123
123
  """Validate HTTP extractor configuration."""
124
- if 'source_type' in extract_config and extract_config['source_type'] != 'http':
125
- raise ValueError(f"HTTPExtractor requires source_type='http', got '{extract_config.get('source_type')}'")
124
+ if 'type' in extract_config and extract_config['type'] != 'http':
125
+ raise ValueError(f"HTTPExtractor requires type='http', got '{extract_config.get('type')}'")
126
126
 
127
127
  # Check for required HTTP config fields
128
128
  if not extract_config.get('api_endpoint') and not extract_config.get('base_url'):
@@ -0,0 +1,393 @@
1
+ """
2
+ MongoDB extractor for ETL orchestrator.
3
+
4
+ Supports extracting data from MongoDB collections using:
5
+ - Simple find() queries with filters
6
+ - Aggregation pipelines for complex transformations
7
+
8
+ Configuration example:
9
+ ```yaml
10
+ type: mongodb
11
+ mongodb:
12
+ url: mongodb://user:pass@localhost:27017
13
+ database: mydb
14
+ collection: users
15
+ ssh_tunnel:
16
+ enabled: false
17
+ host: bastion.example.com
18
+ username: tunnel_user
19
+ remote_host: mongo-internal.example.com
20
+ remote_port: 27017
21
+
22
+ # Option 1: Simple query filter
23
+ query:
24
+ status: active
25
+ created_at:
26
+ $gte: "2024-01-01"
27
+
28
+ # Option 2: Aggregation pipeline (takes precedence over query)
29
+ pipeline:
30
+ - $match:
31
+ status: active
32
+ - $project:
33
+ name: 1
34
+ email: 1
35
+ _id: 0
36
+
37
+ # Optional: projection for simple queries
38
+ projection:
39
+ name: 1
40
+ email: 1
41
+ _id: 0
42
+
43
+ # Optional: sorting
44
+ sort:
45
+ created_at: -1
46
+
47
+ # Optional: limit results
48
+ limit: 1000
49
+ ```
50
+ """
51
+
52
+ import logging
53
+ from typing import Any, AsyncIterator, Dict, List, Optional
54
+
55
+ from bson import ObjectId
56
+ from pymongo import MongoClient
57
+
58
+ from pycharter.etl_generator.extractors.base import BaseExtractor
59
+ from pycharter.etl_generator.database import (
60
+ create_ssh_tunnel,
61
+ DEFAULT_TUNNEL_LOCAL_PORT,
62
+ )
63
+ from pycharter.utils.value_injector import resolve_values
64
+
65
+ logger = logging.getLogger(__name__)
66
+
67
+ # Default MongoDB port
68
+ DEFAULT_MONGODB_PORT = 27017
69
+
70
+
71
+ def _serialize_document(doc: Dict[str, Any]) -> Dict[str, Any]:
72
+ """
73
+ Serialize a MongoDB document for JSON compatibility.
74
+
75
+ Converts:
76
+ - ObjectId to string
77
+ - Other BSON types as needed
78
+
79
+ Args:
80
+ doc: MongoDB document
81
+
82
+ Returns:
83
+ JSON-serializable dictionary
84
+ """
85
+ result = {}
86
+ for key, value in doc.items():
87
+ if isinstance(value, ObjectId):
88
+ result[key] = str(value)
89
+ elif isinstance(value, dict):
90
+ result[key] = _serialize_document(value)
91
+ elif isinstance(value, list):
92
+ result[key] = [
93
+ _serialize_document(item) if isinstance(item, dict)
94
+ else str(item) if isinstance(item, ObjectId)
95
+ else item
96
+ for item in value
97
+ ]
98
+ else:
99
+ result[key] = value
100
+ return result
101
+
102
+
103
+ def _modify_mongodb_url_for_tunnel(url: str, local_port: int) -> str:
104
+ """
105
+ Modify MongoDB URL to use local tunnel port.
106
+
107
+ Args:
108
+ url: Original MongoDB URL
109
+ local_port: Local tunnel port
110
+
111
+ Returns:
112
+ Modified URL pointing to localhost tunnel
113
+ """
114
+ import re
115
+ # Match mongodb:// or mongodb+srv:// URLs
116
+ # Replace host:port with 127.0.0.1:local_port
117
+ # Handle URLs with or without port
118
+ pattern = r'mongodb(\+srv)?://([^@]+@)?([^/:]+)(:\d+)?'
119
+
120
+ def replace_host(match):
121
+ protocol = match.group(1) or ''
122
+ auth = match.group(2) or ''
123
+ # For tunneled connections, we don't use SRV
124
+ return f'mongodb://{auth}127.0.0.1:{local_port}'
125
+
126
+ return re.sub(pattern, replace_host, url)
127
+
128
+
129
+ class MongoDBExtractor(BaseExtractor):
130
+ """
131
+ Extractor for MongoDB data sources.
132
+
133
+ Supports two query modes:
134
+ 1. Simple find() queries with optional projection and sorting
135
+ 2. Aggregation pipelines for complex data transformations
136
+
137
+ Example (programmatic API):
138
+ >>> extractor = MongoDBExtractor(
139
+ ... connection_string="mongodb://localhost:27017",
140
+ ... database="mydb",
141
+ ... collection="users",
142
+ ... query={"status": "active"},
143
+ ... )
144
+ >>> async for batch in extractor.extract():
145
+ ... process(batch)
146
+
147
+ Example (config-driven):
148
+ >>> extractor = MongoDBExtractor()
149
+ >>> async for batch in extractor.extract_streaming(config, params, headers):
150
+ ... process(batch)
151
+ """
152
+
153
+ def __init__(
154
+ self,
155
+ connection_string: Optional[str] = None,
156
+ database: Optional[str] = None,
157
+ collection: Optional[str] = None,
158
+ query: Optional[Dict[str, Any]] = None,
159
+ pipeline: Optional[List[Dict[str, Any]]] = None,
160
+ projection: Optional[Dict[str, Any]] = None,
161
+ sort: Optional[Dict[str, int]] = None,
162
+ batch_size: int = 1000,
163
+ max_records: Optional[int] = None,
164
+ ssh_tunnel: Optional[Dict[str, Any]] = None,
165
+ ):
166
+ """
167
+ Initialize MongoDB extractor.
168
+
169
+ Args:
170
+ connection_string: MongoDB connection URL
171
+ database: Database name
172
+ collection: Collection name
173
+ query: MongoDB query filter (for find operations)
174
+ pipeline: Aggregation pipeline (takes precedence over query)
175
+ projection: Fields to include/exclude (for find operations)
176
+ sort: Sort specification (for find operations)
177
+ batch_size: Number of records per batch
178
+ max_records: Maximum records to extract (None = all)
179
+ ssh_tunnel: SSH tunnel configuration
180
+ """
181
+ self.connection_string = connection_string
182
+ self.database = database
183
+ self.collection = collection
184
+ self.query = query or {}
185
+ self.pipeline = pipeline
186
+ self.projection = projection
187
+ self.sort = sort
188
+ self.batch_size = batch_size
189
+ self.max_records = max_records
190
+ self.ssh_tunnel = ssh_tunnel
191
+
192
+ @classmethod
193
+ def from_config(cls, config: Dict[str, Any]) -> "MongoDBExtractor":
194
+ """Create extractor from configuration dict."""
195
+ mongo_config = config.get("mongodb", {})
196
+ return cls(
197
+ connection_string=mongo_config.get("url") or config.get("connection_string"),
198
+ database=mongo_config.get("database") or config.get("database"),
199
+ collection=mongo_config.get("collection") or config.get("collection"),
200
+ query=config.get("query", {}),
201
+ pipeline=config.get("pipeline"),
202
+ projection=config.get("projection"),
203
+ sort=config.get("sort"),
204
+ batch_size=config.get("batch_size", 1000),
205
+ max_records=config.get("max_records"),
206
+ ssh_tunnel=mongo_config.get("ssh_tunnel"),
207
+ )
208
+
209
+ async def extract(self, **params) -> AsyncIterator[List[Dict[str, Any]]]:
210
+ """
211
+ Extract data from MongoDB.
212
+
213
+ Yields:
214
+ Batches of records as dictionaries
215
+ """
216
+ if not self.connection_string:
217
+ raise ValueError("MongoDB connection string is required")
218
+ if not self.database:
219
+ raise ValueError("MongoDB database name is required")
220
+ if not self.collection:
221
+ raise ValueError("MongoDB collection name is required")
222
+
223
+ extract_config = {
224
+ "mongodb": {
225
+ "url": self.connection_string,
226
+ "database": self.database,
227
+ "collection": self.collection,
228
+ "ssh_tunnel": self.ssh_tunnel,
229
+ },
230
+ "query": self.query,
231
+ "pipeline": self.pipeline,
232
+ "projection": self.projection,
233
+ "sort": self.sort,
234
+ }
235
+
236
+ async for batch in self.extract_streaming(
237
+ extract_config, params, {},
238
+ batch_size=self.batch_size,
239
+ max_records=self.max_records,
240
+ ):
241
+ yield batch
242
+
243
+ def validate_config(self, extract_config: Dict[str, Any]) -> None:
244
+ """Validate MongoDB extractor configuration."""
245
+ source_type = extract_config.get('type') or extract_config.get('source_type')
246
+ if source_type and source_type not in ('mongodb', 'mongo'):
247
+ raise ValueError(
248
+ f"MongoDBExtractor requires type='mongodb', got '{source_type}'"
249
+ )
250
+
251
+ mongo_config = extract_config.get('mongodb', {})
252
+ if not mongo_config.get('url'):
253
+ raise ValueError("MongoDB extractor requires 'mongodb.url' in extract_config")
254
+ if not mongo_config.get('database'):
255
+ raise ValueError("MongoDB extractor requires 'mongodb.database' in extract_config")
256
+ if not mongo_config.get('collection'):
257
+ raise ValueError("MongoDB extractor requires 'mongodb.collection' in extract_config")
258
+
259
+ async def extract_streaming(
260
+ self,
261
+ extract_config: Dict[str, Any],
262
+ params: Dict[str, Any],
263
+ headers: Dict[str, Any],
264
+ contract_dir: Optional[Any] = None,
265
+ batch_size: int = 1000,
266
+ max_records: Optional[int] = None,
267
+ config_context: Optional[Dict[str, Any]] = None,
268
+ ) -> AsyncIterator[List[Dict[str, Any]]]:
269
+ """
270
+ Extract data from MongoDB using find() or aggregation pipeline.
271
+
272
+ Yields batches of records as lists of dictionaries.
273
+ """
274
+ # Get MongoDB configuration
275
+ mongo_config = extract_config.get('mongodb', {})
276
+
277
+ # Resolve variables
278
+ source_file = str(contract_dir / "extract.yaml") if contract_dir else None
279
+ mongo_url = resolve_values(
280
+ mongo_config.get('url'),
281
+ context=config_context,
282
+ source_file=source_file
283
+ )
284
+ db_name = resolve_values(
285
+ mongo_config.get('database'),
286
+ context=config_context,
287
+ source_file=source_file
288
+ )
289
+ collection_name = resolve_values(
290
+ mongo_config.get('collection'),
291
+ context=config_context,
292
+ source_file=source_file
293
+ )
294
+
295
+ if not mongo_url:
296
+ raise ValueError("MongoDB URL is required")
297
+ if not db_name:
298
+ raise ValueError("MongoDB database name is required")
299
+ if not collection_name:
300
+ raise ValueError("MongoDB collection name is required")
301
+
302
+ # Handle SSH tunnel if configured
303
+ ssh_config = mongo_config.get('ssh_tunnel', {})
304
+ tunnel = None
305
+ if ssh_config:
306
+ ssh_config = resolve_values(ssh_config, context=config_context, source_file=source_file)
307
+ enabled_value = ssh_config.get('enabled', False)
308
+ if isinstance(enabled_value, str):
309
+ enabled_lower = enabled_value.lower()
310
+ ssh_config['enabled'] = enabled_lower in ('true', '1', 'yes', 'on')
311
+ elif not isinstance(enabled_value, bool):
312
+ ssh_config['enabled'] = bool(enabled_value)
313
+
314
+ if ssh_config.get('enabled', False):
315
+ # Set default remote port for MongoDB if not specified
316
+ if 'remote_port' not in ssh_config:
317
+ ssh_config['remote_port'] = DEFAULT_MONGODB_PORT
318
+
319
+ tunnel = create_ssh_tunnel(ssh_config)
320
+ if tunnel:
321
+ local_port = int(ssh_config.get('local_port', DEFAULT_TUNNEL_LOCAL_PORT))
322
+ mongo_url = _modify_mongodb_url_for_tunnel(mongo_url, local_port)
323
+
324
+ # Get query/pipeline configuration
325
+ query = extract_config.get('query', {})
326
+ pipeline = extract_config.get('pipeline')
327
+ projection = extract_config.get('projection')
328
+ sort_spec = extract_config.get('sort')
329
+ limit = extract_config.get('limit')
330
+
331
+ # Merge params into query for parameterized queries
332
+ if params:
333
+ query = {**query, **params}
334
+
335
+ # Create MongoDB client
336
+ client = MongoClient(mongo_url)
337
+ db = client[db_name]
338
+ collection = db[collection_name]
339
+
340
+ try:
341
+ logger.info(
342
+ f"Extracting from MongoDB: {db_name}.{collection_name} "
343
+ f"(pipeline: {bool(pipeline)}, query: {bool(query)})"
344
+ )
345
+
346
+ # Choose extraction method
347
+ if pipeline:
348
+ # Use aggregation pipeline
349
+ cursor = collection.aggregate(pipeline, batchSize=batch_size)
350
+ else:
351
+ # Use find() with optional projection, sort, limit
352
+ cursor = collection.find(query, projection)
353
+
354
+ if sort_spec:
355
+ # Convert dict to list of tuples for pymongo
356
+ sort_list = [(k, v) for k, v in sort_spec.items()]
357
+ cursor = cursor.sort(sort_list)
358
+
359
+ if limit:
360
+ cursor = cursor.limit(limit)
361
+
362
+ cursor = cursor.batch_size(batch_size)
363
+
364
+ # Stream results in batches
365
+ current_batch = []
366
+ total_extracted = 0
367
+
368
+ for doc in cursor:
369
+ if max_records and total_extracted >= max_records:
370
+ break
371
+
372
+ # Serialize document for JSON compatibility
373
+ record = _serialize_document(doc)
374
+ current_batch.append(record)
375
+ total_extracted += 1
376
+
377
+ if len(current_batch) >= batch_size:
378
+ yield current_batch
379
+ current_batch = []
380
+
381
+ # Yield remaining records
382
+ if current_batch:
383
+ yield current_batch
384
+
385
+ logger.info(f"MongoDB extraction completed: {total_extracted} records extracted")
386
+
387
+ except Exception as e:
388
+ logger.error(f"MongoDB extraction error: {e}", exc_info=True)
389
+ raise RuntimeError(f"MongoDB extraction failed: {e}") from e
390
+ finally:
391
+ client.close()
392
+ if tunnel:
393
+ tunnel.stop()
@@ -28,7 +28,7 @@ async def extract_with_pagination_streaming(
28
28
  - Cloud storage (S3, GCS, Azure Blob)
29
29
 
30
30
  The source type is auto-detected from extract_config or can be explicitly set
31
- via 'source_type' field.
31
+ via 'type' field.
32
32
 
33
33
  Yields batches as they are extracted, preventing memory exhaustion for large datasets.
34
34
 
@@ -44,7 +44,7 @@ async def extract_with_pagination_streaming(
44
44
  Yields:
45
45
  Batches of extracted records (lists of dictionaries)
46
46
  """
47
- extractor = ExtractorFactory.get_extractor(extract_config)
47
+ extractor = ExtractorFactory.create(extract_config)
48
48
  async for batch in extractor.extract_streaming(
49
49
  extract_config,
50
50
  params,
@@ -7,32 +7,38 @@ Two APIs:
7
7
 
8
8
  Supports:
9
9
  - Database (PostgreSQL, MySQL, SQLite, MSSQL)
10
+ - MongoDB (insert, upsert, replace, update, delete)
10
11
  - File (local JSON, CSV, Parquet, JSONL)
11
12
  - Cloud storage (AWS S3, Google Cloud Storage, Azure Blob)
12
13
  """
13
14
 
14
- # Class-based loaders (new API)
15
+ # Base class
15
16
  from pycharter.etl_generator.loaders.base import BaseLoader
17
+
18
+ # Database loaders
16
19
  from pycharter.etl_generator.loaders.database import PostgresLoader, DatabaseLoader
17
- from pycharter.etl_generator.loaders.file import FileLoader
18
- from pycharter.etl_generator.loaders.cloud import CloudStorageLoader
19
20
 
20
- # Factory
21
- from pycharter.etl_generator.loaders.factory import LoaderFactory, get_loader
21
+ # MongoDB loader
22
+ from pycharter.etl_generator.loaders.mongodb import MongoDBLoader
23
+
24
+ # File loaders (class and function APIs)
25
+ from pycharter.etl_generator.loaders.file import FileLoader, load_to_file
22
26
 
23
- # Function-based loaders (config-driven)
24
- from pycharter.etl_generator.loaders.file_loader import load_to_file
25
- from pycharter.etl_generator.loaders.cloud_storage_loader import load_to_cloud_storage
27
+ # Cloud storage loaders (class and function APIs)
28
+ from pycharter.etl_generator.loaders.cloud_storage import CloudStorageLoader, load_to_cloud_storage
29
+
30
+ # Factory
31
+ from pycharter.etl_generator.loaders.factory import LoaderFactory
26
32
 
27
33
  __all__ = [
28
34
  # Base class
29
35
  "BaseLoader",
30
36
  # Factory
31
37
  "LoaderFactory",
32
- "get_loader",
33
38
  # Class-based loaders
34
39
  "PostgresLoader",
35
40
  "DatabaseLoader",
41
+ "MongoDBLoader",
36
42
  "FileLoader",
37
43
  "CloudStorageLoader",
38
44
  # Function-based loaders