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
@@ -0,0 +1,233 @@
1
+ """
2
+ Spark-based validation backend for large datasets.
3
+
4
+ Supports:
5
+ - Local mode: Single machine, no cluster needed (default)
6
+ - Remote mode: Submit to external Spark service
7
+ - Cluster mode: Connect to Spark cluster (future)
8
+ """
9
+
10
+ import json
11
+ import os
12
+ import pickle
13
+ from typing import Any, Dict, Optional
14
+
15
+ from pyspark.sql import DataFrame, SparkSession
16
+ from pyspark.sql.functions import col, udf
17
+ from pyspark.sql.types import (
18
+ ArrayType,
19
+ BooleanType,
20
+ StringType,
21
+ StructField,
22
+ StructType,
23
+ )
24
+
25
+ from pycharter import build_contract_from_store, get_model_from_contract
26
+ from pycharter.metadata_store import MetadataStoreClient
27
+ from pycharter.runtime_validator.validator_core import ValidationResult, validate
28
+
29
+ from pycharter.worker.backends.base import ValidationBackend
30
+
31
+
32
+ class SparkValidationBackend(ValidationBackend):
33
+ """
34
+ Spark-compatible validation backend.
35
+
36
+ Works in three modes:
37
+ 1. Local mode (default) - Single machine, no cluster needed
38
+ 2. Remote mode - Submit to external Spark service
39
+ 3. Cluster mode - Connect to Spark cluster (future)
40
+ """
41
+
42
+ def __init__(
43
+ self,
44
+ mode: str = "local", # "local", "remote", "cluster"
45
+ master: Optional[str] = None, # "local[*]", "spark://host:port", "yarn", etc.
46
+ app_name: str = "pycharter-validation",
47
+ ):
48
+ """
49
+ Initialize Spark validation backend.
50
+
51
+ Args:
52
+ mode: Spark mode ("local", "remote", "cluster")
53
+ master: Spark master URL (auto-detected if not provided)
54
+ app_name: Spark application name
55
+ """
56
+ self.mode = mode
57
+ self.master = master or self._get_default_master()
58
+ self.app_name = app_name
59
+ self.spark: Optional[SparkSession] = None
60
+
61
+ def _get_default_master(self) -> str:
62
+ """Get default Spark master based on mode."""
63
+ if self.mode == "local":
64
+ return "local[*]" # Use all CPU cores locally
65
+ elif self.mode == "remote":
66
+ # For remote Spark service (e.g., Spark on Kubernetes)
67
+ return os.getenv("SPARK_MASTER", "spark://localhost:7077")
68
+ else: # cluster
69
+ return os.getenv("SPARK_MASTER", "yarn")
70
+
71
+ def get_spark_session(self) -> SparkSession:
72
+ """Get or create Spark session."""
73
+ if self.spark is None:
74
+ self.spark = (
75
+ SparkSession.builder.appName(self.app_name)
76
+ .master(self.master)
77
+ .config("spark.sql.adaptive.enabled", "true")
78
+ .config("spark.sql.adaptive.coalescePartitions.enabled", "true")
79
+ .getOrCreate()
80
+ )
81
+ return self.spark
82
+
83
+ def validate(
84
+ self,
85
+ schema_id: str,
86
+ data_source: str, # S3 path, file path, database table, etc.
87
+ store: MetadataStoreClient,
88
+ options: Optional[Dict[str, Any]] = None,
89
+ ) -> Dict[str, Any]:
90
+ """
91
+ Validate data using Spark.
92
+
93
+ This method:
94
+ 1. Loads contract from metadata store
95
+ 2. Reads data from source
96
+ 3. Validates using PyCharter validation logic
97
+ 4. Returns aggregated results
98
+
99
+ Args:
100
+ schema_id: Schema identifier
101
+ data_source: Data source path or identifier
102
+ store: Metadata store client
103
+ options: Validation options
104
+
105
+ Returns:
106
+ Dictionary with validation results
107
+ """
108
+ spark = self.get_spark_session()
109
+ options = options or {}
110
+
111
+ # Load contract from metadata store
112
+ contract = build_contract_from_store(store, schema_title=schema_id)
113
+ model = get_model_from_contract(contract)
114
+
115
+ # Serialize model for Spark UDF
116
+ # Note: Pydantic models need to be pickled and broadcast
117
+ model_pickle = pickle.dumps(model)
118
+ model_broadcast = spark.sparkContext.broadcast(model_pickle)
119
+
120
+ # Read data
121
+ df = self._read_data(spark, data_source)
122
+
123
+ # Define validation UDF
124
+ @udf(
125
+ returnType=StructType(
126
+ [
127
+ StructField("is_valid", BooleanType()),
128
+ StructField("errors", ArrayType(StringType())),
129
+ StructField("data_json", StringType()),
130
+ ]
131
+ )
132
+ )
133
+ def validate_record(record_json: str) -> Dict[str, Any]:
134
+ """Validate a single record using PyCharter."""
135
+ import pickle
136
+
137
+ # Unpickle model
138
+ model = pickle.loads(model_broadcast.value)
139
+
140
+ # Parse record
141
+ record = json.loads(record_json)
142
+
143
+ # Validate using PyCharter
144
+ result = validate(model, record, strict=False)
145
+
146
+ # Return result
147
+ return {
148
+ "is_valid": result.is_valid,
149
+ "errors": result.errors or [],
150
+ "data_json": json.dumps(result.data.model_dump())
151
+ if result.data
152
+ else None,
153
+ }
154
+
155
+ # Convert DataFrame to JSON strings for validation
156
+ # Assuming data is already in a format we can work with
157
+ # If data is in columns, we need to convert to JSON
158
+ if "value" in df.columns:
159
+ # Data is already in JSON format
160
+ validation_df = df.withColumn(
161
+ "validation_result", validate_record(col("value"))
162
+ )
163
+ else:
164
+ # Convert row to JSON
165
+ from pyspark.sql.functions import to_json, struct
166
+
167
+ json_cols = [col(c) for c in df.columns]
168
+ df_with_json = df.withColumn("value", to_json(struct(*json_cols)))
169
+ validation_df = df_with_json.withColumn(
170
+ "validation_result", validate_record(col("value"))
171
+ )
172
+
173
+ # Aggregate results
174
+ results = validation_df.select(
175
+ col("validation_result.is_valid").alias("is_valid"),
176
+ col("validation_result.errors").alias("errors"),
177
+ ).collect()
178
+
179
+ # Calculate metrics
180
+ total_count = len(results)
181
+ valid_count = sum(1 for r in results if r.is_valid)
182
+ invalid_count = total_count - valid_count
183
+
184
+ # Collect violations
185
+ violations = []
186
+ for result in results:
187
+ if not result.is_valid and result.errors:
188
+ violations.extend(result.errors)
189
+
190
+ # Calculate quality score
191
+ quality_score = valid_count / total_count if total_count > 0 else 0.0
192
+
193
+ return {
194
+ "total_count": total_count,
195
+ "valid_count": valid_count,
196
+ "invalid_count": invalid_count,
197
+ "violations": violations,
198
+ "quality_score": quality_score,
199
+ "data_source": data_source,
200
+ }
201
+
202
+ def _read_data(self, spark: SparkSession, data_source: str) -> DataFrame:
203
+ """Read data from various sources."""
204
+ if data_source.startswith("s3://") or data_source.startswith("s3a://"):
205
+ # Read from S3
206
+ return spark.read.parquet(data_source)
207
+ elif data_source.startswith("hdfs://"):
208
+ # Read from HDFS
209
+ return spark.read.parquet(data_source)
210
+ elif data_source.endswith(".parquet"):
211
+ # Local parquet file
212
+ return spark.read.parquet(data_source)
213
+ elif data_source.endswith(".json"):
214
+ # JSON file
215
+ return spark.read.json(data_source)
216
+ elif data_source.endswith(".csv"):
217
+ # CSV file
218
+ return spark.read.csv(data_source, header=True, inferSchema=True)
219
+ else:
220
+ # Assume it's a database table or try to infer format
221
+ # For now, try JSON first
222
+ try:
223
+ return spark.read.json(data_source)
224
+ except Exception:
225
+ # Fallback to parquet
226
+ return spark.read.parquet(data_source)
227
+
228
+ def close(self):
229
+ """Close Spark session."""
230
+ if self.spark:
231
+ self.spark.stop()
232
+ self.spark = None
233
+
@@ -10,7 +10,7 @@ from typing import Optional
10
10
 
11
11
  from pycharter.config import get_database_url
12
12
 
13
- from worker.processor import ValidationProcessor
13
+ from pycharter.worker.processor import ValidationProcessor
14
14
 
15
15
  logger = logging.getLogger(__name__)
16
16
 
@@ -16,8 +16,8 @@ from pycharter.metadata_store import (
16
16
  from pycharter.db.models.base import get_session
17
17
  from sqlalchemy.orm import Session
18
18
 
19
- from worker.backends.spark import SparkValidationBackend
20
- from worker.queue.redis_queue import ValidationJobQueue
19
+ from pycharter.worker.backends.spark import SparkValidationBackend
20
+ from pycharter.worker.queue.redis_queue import ValidationJobQueue
21
21
 
22
22
  logger = logging.getLogger(__name__)
23
23
 
@@ -0,0 +1,8 @@
1
+ """
2
+ Message queue implementations for worker component.
3
+ """
4
+
5
+ from pycharter.worker.queue.redis_queue import ValidationJobQueue
6
+
7
+ __all__ = ["ValidationJobQueue"]
8
+
@@ -0,0 +1,147 @@
1
+ """
2
+ Redis-based message queue for async validation jobs.
3
+ """
4
+
5
+ import asyncio
6
+ import json
7
+ from datetime import datetime
8
+ from typing import Dict, Any, Optional
9
+ import uuid
10
+
11
+ try:
12
+ import redis.asyncio as redis
13
+ REDIS_AVAILABLE = True
14
+ except ImportError:
15
+ REDIS_AVAILABLE = False
16
+ redis = None
17
+
18
+
19
+ class ValidationJobQueue:
20
+ """Message queue for async validation jobs using Redis."""
21
+
22
+ def __init__(self, redis_url: str = "redis://localhost:6379"):
23
+ """
24
+ Initialize Redis job queue.
25
+
26
+ Args:
27
+ redis_url: Redis connection URL
28
+ """
29
+ if not REDIS_AVAILABLE:
30
+ raise ImportError(
31
+ "redis package is required. Install with: pip install redis>=5.0.0"
32
+ )
33
+ self.redis_url = redis_url
34
+ self.redis_client: Optional[redis.Redis] = None
35
+
36
+ async def connect(self):
37
+ """Connect to Redis."""
38
+ if not REDIS_AVAILABLE:
39
+ raise ImportError("redis package is required")
40
+ self.redis_client = await redis.from_url(self.redis_url)
41
+
42
+ async def disconnect(self):
43
+ """Disconnect from Redis."""
44
+ if self.redis_client:
45
+ await self.redis_client.close()
46
+ self.redis_client = None
47
+
48
+ async def enqueue_job(self, job: Dict[str, Any]) -> str:
49
+ """
50
+ Enqueue a validation job.
51
+
52
+ Args:
53
+ job: Job dictionary with schema_id, data_source, options
54
+
55
+ Returns:
56
+ Job ID
57
+ """
58
+ if not self.redis_client:
59
+ await self.connect()
60
+
61
+ job_id = str(uuid.uuid4())
62
+ job["job_id"] = job_id
63
+ job["status"] = "queued"
64
+ job["created_at"] = datetime.utcnow().isoformat()
65
+
66
+ # Push to queue
67
+ await self.redis_client.lpush("validation-jobs", json.dumps(job))
68
+
69
+ # Store job metadata
70
+ await self.redis_client.setex(
71
+ f"job:{job_id}",
72
+ 3600, # 1 hour TTL
73
+ json.dumps({"status": "queued", "created_at": job["created_at"]}),
74
+ )
75
+
76
+ return job_id
77
+
78
+ async def get_job_status(self, job_id: str) -> Optional[Dict[str, Any]]:
79
+ """
80
+ Get job status.
81
+
82
+ Args:
83
+ job_id: Job identifier
84
+
85
+ Returns:
86
+ Job status dictionary or None if not found
87
+ """
88
+ if not self.redis_client:
89
+ await self.connect()
90
+
91
+ status_json = await self.redis_client.get(f"job:{job_id}")
92
+ if status_json:
93
+ return json.loads(status_json)
94
+ return None
95
+
96
+ async def update_job_status(
97
+ self,
98
+ job_id: str,
99
+ status: str,
100
+ result: Optional[Dict[str, Any]] = None,
101
+ error: Optional[str] = None,
102
+ ):
103
+ """
104
+ Update job status.
105
+
106
+ Args:
107
+ job_id: Job identifier
108
+ status: New status ("queued", "processing", "completed", "failed")
109
+ result: Optional result dictionary
110
+ error: Optional error message
111
+ """
112
+ if not self.redis_client:
113
+ await self.connect()
114
+
115
+ status_data = {
116
+ "status": status,
117
+ "updated_at": datetime.utcnow().isoformat(),
118
+ }
119
+ if result:
120
+ status_data["result"] = result
121
+ if error:
122
+ status_data["error"] = error
123
+
124
+ await self.redis_client.setex(
125
+ f"job:{job_id}",
126
+ 3600, # 1 hour TTL
127
+ json.dumps(status_data),
128
+ )
129
+
130
+ async def dequeue_job(self, timeout: int = 1) -> Optional[Dict[str, Any]]:
131
+ """
132
+ Dequeue a job from the queue (blocking).
133
+
134
+ Args:
135
+ timeout: Blocking timeout in seconds
136
+
137
+ Returns:
138
+ Job dictionary or None if timeout
139
+ """
140
+ if not self.redis_client:
141
+ await self.connect()
142
+
143
+ result = await self.redis_client.brpop("validation-jobs", timeout=timeout)
144
+ if result:
145
+ return json.loads(result[1])
146
+ return None
147
+
@@ -1,21 +1,19 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pycharter
3
- Version: 0.0.24
3
+ Version: 0.0.26
4
4
  Summary: A Python package for data contract management with five core services: contract parsing, metadata storage, Pydantic generation, JSON Schema conversion, and runtime validation
5
5
  Author-email: semantic developers <na@example.com>
6
6
  License-Expression: MIT
7
7
  Project-URL: Homepage, https://github.com/auscheng/pycharter
8
- Project-URL: Documentation, https://github.com/auscheng/pycharter#readme
8
+ Project-URL: Documentation, https://auscheng.github.io/pycharter/
9
9
  Project-URL: Repository, https://github.com/auscheng/pycharter
10
10
  Project-URL: Issues, https://github.com/auscheng/pycharter/issues
11
11
  Keywords: semantic,python,pydantic,contract,validation,schema
12
12
  Classifier: Development Status :: 3 - Alpha
13
13
  Classifier: Intended Audience :: Developers
14
14
  Classifier: Programming Language :: Python :: 3
15
- Classifier: Programming Language :: Python :: 3.10
16
- Classifier: Programming Language :: Python :: 3.11
17
- Classifier: Programming Language :: Python :: 3.12
18
- Requires-Python: >=3.10
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Requires-Python: >=3.13
19
17
  Description-Content-Type: text/markdown
20
18
  License-File: LICENSE
21
19
  Requires-Dist: pydantic>=2.0.0
@@ -39,11 +37,18 @@ Requires-Dist: ipykernel>=6.0.0; extra == "dev"
39
37
  Requires-Dist: psycopg2-binary>=2.9.0; extra == "dev"
40
38
  Requires-Dist: pymongo>=4.0.0; extra == "dev"
41
39
  Requires-Dist: boto3>=1.26.0; extra == "dev"
40
+ Provides-Extra: docs
41
+ Requires-Dist: mkdocs-material>=9.5.0; extra == "docs"
42
+ Requires-Dist: mkdocstrings[python]>=0.24.0; extra == "docs"
43
+ Requires-Dist: pymdown-extensions>=10.0.0; extra == "docs"
44
+ Requires-Dist: mike>=2.0.0; extra == "docs"
42
45
  Provides-Extra: api
43
46
  Requires-Dist: fastapi>=0.104.0; extra == "api"
44
47
  Requires-Dist: uvicorn[standard]>=0.24.0; extra == "api"
45
48
  Requires-Dist: pydantic-settings>=2.0.0; extra == "api"
46
49
  Requires-Dist: python-multipart>=0.0.6; extra == "api"
50
+ Requires-Dist: PyJWT>=2.8.0; extra == "api"
51
+ Requires-Dist: httpx>=0.24.0; extra == "api"
47
52
  Provides-Extra: ui
48
53
  Requires-Dist: fastapi>=0.104.0; extra == "ui"
49
54
  Requires-Dist: uvicorn[standard]>=0.24.0; extra == "ui"
@@ -59,13 +64,14 @@ Requires-Dist: google-cloud-storage>=2.0.0; extra == "etl"
59
64
  Requires-Dist: azure-storage-blob>=12.0.0; extra == "etl"
60
65
  Requires-Dist: openpyxl>=3.0.0; extra == "etl"
61
66
  Requires-Dist: lxml>=4.9.0; extra == "etl"
67
+ Requires-Dist: pymongo>=4.0.0; extra == "etl"
62
68
  Dynamic: license-file
63
69
 
64
70
  # PyCharter
65
71
 
66
- > **Dynamically generate Pydantic models from JSON schemas with coercion and validation support**
72
+ > **Data contract management and validation for Python: define schemas, enforce quality, and run ETL with contracts.**
67
73
 
68
- [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
74
+ [![Python 3.13+](https://img.shields.io/badge/python-3.13+-blue.svg)](https://www.python.org/downloads/)
69
75
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
70
76
  [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
71
77
 
@@ -162,6 +168,27 @@ pycharter ui dev # Development mode with hot reload
162
168
 
163
169
  **Note**: When installed from pip, the UI works immediately without Node.js. For development, Node.js is required. See `ui/INSTALLATION.md` for detailed instructions.
164
170
 
171
+ ### Database setup (for metadata store, API, and seed data)
172
+
173
+ If you use the **metadata store** (SQLite or PostgreSQL), the **REST API**, or **seed data**, initialize the database once:
174
+
175
+ ```bash
176
+ # Initialize database schema (SQLite default: sqlite:///pycharter.db)
177
+ pycharter db init
178
+
179
+ # Seed reference data (owners, domains, systems, environments, data feeds, compliance frameworks, tags)
180
+ pycharter db seed
181
+ ```
182
+
183
+ **From the project source** (e.g. after cloning the repo), you can run the full seed script to also load example aviation contracts into the metadata store:
184
+
185
+ ```bash
186
+ python bin/seed # seed data/seed + data/aviation_examples
187
+ python bin/seed --skip-aviation # seed only data/seed
188
+ ```
189
+
190
+ Use `pycharter db init --force` to drop and recreate all tables (SQLite only; **destroys existing data**). See [Configuration Guide](docs/guides/configuration.md) for connection options and migrations.
191
+
165
192
  ## 🚀 Quick Start
166
193
 
167
194
  ### Quick Start: ETL Pipelines
@@ -398,19 +425,20 @@ artifacts = ContractArtifacts(
398
425
 
399
426
  contract = build_contract(artifacts)
400
427
  # Contract now has:
401
- # - schema with rules merged
428
+ # - schema (RAW - rules NOT merged into it)
429
+ # - coercion_rules, validation_rules (separate)
402
430
  # - metadata, ownership, governance_rules
403
431
  # - versions tracking all components
404
432
 
405
433
  # Or build from metadata store
406
434
  contract = build_contract_from_store(store, "user_schema_v1")
407
435
 
408
- # Use for validation
436
+ # Use for validation - Validator merges rules internally
409
437
  from pycharter import validate_with_contract
410
438
  result = validate_with_contract(contract, {"name": "Alice", "age": "30"})
411
439
  ```
412
440
 
413
- **Contribution to Journey**: The contract builder is the **consolidation layer** that combines separate artifacts (stored independently in the database) into a single contract artifact. This consolidated contract tracks all component versions and can be used for runtime validation, distribution, or archival purposes.
441
+ **Contribution to Journey**: The contract builder is the **consolidation layer** that combines separate artifacts (stored independently in the database) into a single contract artifact. The contract contains **raw schema + separate rules** (not merged). The Validator class handles merging internally during validation, keeping the contract structure clear and editable.
414
442
 
415
443
  ---
416
444
 
@@ -469,7 +497,7 @@ validation_rules = store.get_validation_rules(schema_id)
469
497
 
470
498
  **Contribution to Journey**: The metadata store is the **persistence layer** that ensures contracts and their components are versioned, searchable, and accessible across your organization. It enables governance, audit trails, and schema evolution tracking.
471
499
 
472
- **See [Configuration Guide](CONFIGURATION.md) for database setup and initialization instructions.**
500
+ **See [Configuration Guide](docs/guides/configuration.md) for database setup and initialization instructions.**
473
501
 
474
502
  ---
475
503
 
@@ -808,7 +836,7 @@ def process_user_data_quick(raw_data):
808
836
 
809
837
  ---
810
838
 
811
- ### 7. 🌐 REST API (`api/`) (`api/`)
839
+ ### 7. 🌐 REST API (`pycharter.api`)
812
840
 
813
841
  **Purpose**: Expose all PyCharter services as REST API endpoints.
814
842
 
@@ -824,11 +852,11 @@ def process_user_data_quick(raw_data):
824
852
 
825
853
  **Example**:
826
854
  ```bash
827
- # Start the API server
855
+ # Start the API server (uses PYCHARTER_DATABASE_URL or sqlite:///pycharter.db)
828
856
  pycharter api
829
857
 
830
- # Or with uvicorn
831
- uvicorn api.main:app --reload
858
+ # With host/port
859
+ pycharter api --host 0.0.0.0 --port 8080
832
860
  ```
833
861
 
834
862
  **Endpoints**:
@@ -863,11 +891,11 @@ Each service is designed to be **independent** yet **composable**, allowing you
863
891
 
864
892
  ## 📖 Documentation
865
893
 
866
- - **[Data Journey Guide](DATA_JOURNEY.md)** - Complete guide to the data production journey, including both combined and separated workflows
867
- - **[Configuration Guide](CONFIGURATION.md)** - Database setup, connection configuration, initialization, and migration commands
868
- - **[Database ERD](DATABASE_ERD.md)** - Database schema documentation and entity relationship diagrams
869
- - **[Examples](examples/README.md)** - Complete working examples for all PyCharter services
870
- - **[API Documentation](api/README.md)** - REST API endpoints and usage
894
+ - **[Configuration Guide](docs/guides/configuration.md)** - Database connection, `pycharter db init` / `upgrade` / `seed`, migrations, and variable injection
895
+ - **[Data Journey Guide](docs/guides/data-journey.md)** - Data production journey: contract specification storage → validation → quality
896
+ - **[Database ERD](docs/guides/database-erd.md)** - Database schema and entity relationship diagrams
897
+ - **[Examples & Notebooks](docs/notebooks/README.md)** - Jupyter notebooks (ETL, contracts, validation, quality, metadata store, schema conversion)
898
+ - **[REST API](api/README.md)** - API endpoints and usage (install with `pip install pycharter[api]`)
871
899
 
872
900
  ## 📚 Usage Examples
873
901
 
@@ -1334,7 +1362,7 @@ The workflow automatically:
1334
1362
  make build # Builds package (UI built automatically via setup.py)
1335
1363
  ```
1336
1364
 
1337
- See `PUBLISHING.md` for complete documentation.
1365
+ See [Publishing guide](docs/contributing/publishing.md) for complete documentation.
1338
1366
 
1339
1367
  ## 📋 JSON Schema Compliance
1340
1368
 
@@ -1347,10 +1375,12 @@ PyCharter is fully compliant with **JSON Schema Draft 2020-12** standard:
1347
1375
 
1348
1376
  ## 🔗 Requirements
1349
1377
 
1350
- - Python 3.10+
1378
+ - **Python 3.13+**
1351
1379
  - Pydantic >= 2.0.0
1352
1380
  - jsonschema >= 4.0.0 (optional, for enhanced validation)
1353
1381
 
1382
+ See [pyproject.toml](pyproject.toml) for full dependencies and optional extras (`api`, `ui`, `dev`, `etl`, etc.).
1383
+
1354
1384
  ## 🤝 Contributing
1355
1385
 
1356
1386
  Contributions are welcome! Please feel free to submit a Pull Request.
@@ -1367,9 +1397,10 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
1367
1397
 
1368
1398
  ## 🔗 Links
1369
1399
 
1370
- - **Repository**: [GitHub](https://github.com/auscheng/schemantic)
1371
- - **Issues**: [GitHub Issues](https://github.com/auscheng/schemantic/issues)
1372
- - **Documentation**: [GitHub README](https://github.com/auscheng/schemantic#readme)
1400
+ - **Homepage**: [https://github.com/auscheng/pycharter](https://github.com/auscheng/pycharter)
1401
+ - **Repository**: [GitHub](https://github.com/auscheng/pycharter)
1402
+ - **Issues**: [GitHub Issues](https://github.com/auscheng/pycharter/issues)
1403
+ - **Documentation**: [Configuration & guides](docs/guides/configuration.md) · [API docs](api/README.md)
1373
1404
 
1374
1405
  ---
1375
1406