precis-cli 0.1.3__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 (442) hide show
  1. app/__init__.py +16 -0
  2. app/api/__init__.py +32 -0
  3. app/api/dependencies.py +185 -0
  4. app/api/main.py +301 -0
  5. app/api/middleware/__init__.py +34 -0
  6. app/api/middleware/exception_handler.py +126 -0
  7. app/api/middleware/request_logging.py +97 -0
  8. app/api/middleware/token_auth.py +215 -0
  9. app/api/models/__init__.py +151 -0
  10. app/api/models/connection_rules.py +98 -0
  11. app/api/models/files.py +99 -0
  12. app/api/models/full_validation.py +554 -0
  13. app/api/models/project.py +117 -0
  14. app/api/models/projects.py +80 -0
  15. app/api/models/schema.py +121 -0
  16. app/api/models/v2_responses.py +46 -0
  17. app/api/models/validation.py +303 -0
  18. app/api/models/workspace.py +118 -0
  19. app/api/routers/__init__.py +56 -0
  20. app/api/routers/ai/__init__.py +36 -0
  21. app/api/routers/ai/chat.py +243 -0
  22. app/api/routers/ai/generate.py +156 -0
  23. app/api/routers/ai/hardware.py +199 -0
  24. app/api/routers/ai/jobs.py +544 -0
  25. app/api/routers/ai/migrate.py +471 -0
  26. app/api/routers/ai/models.py +352 -0
  27. app/api/routers/ai/ollama.py +108 -0
  28. app/api/routers/ai/providers.py +491 -0
  29. app/api/routers/ai/router.py +44 -0
  30. app/api/routers/ai/stream.py +281 -0
  31. app/api/routers/ai/utils.py +182 -0
  32. app/api/routers/core/__init__.py +34 -0
  33. app/api/routers/core/connection_rules.py +188 -0
  34. app/api/routers/core/data_sources.py +374 -0
  35. app/api/routers/core/regex.py +333 -0
  36. app/api/routers/core/reporting.py +263 -0
  37. app/api/routers/files/__init__.py +24 -0
  38. app/api/routers/files/ops.py +179 -0
  39. app/api/routers/files/transfer.py +101 -0
  40. app/api/routers/preview/__init__.py +35 -0
  41. app/api/routers/preview/content_mode.py +264 -0
  42. app/api/routers/preview/header_row.py +154 -0
  43. app/api/routers/preview/models.py +81 -0
  44. app/api/routers/preview/path_mode.py +440 -0
  45. app/api/routers/preview/router.py +30 -0
  46. app/api/routers/project/__init__.py +61 -0
  47. app/api/routers/project/base.py +111 -0
  48. app/api/routers/project/constraint.py +345 -0
  49. app/api/routers/project/full_config.py +411 -0
  50. app/api/routers/project/full_config_writer.py +327 -0
  51. app/api/routers/project/helpers.py +167 -0
  52. app/api/routers/project/inspection_fix.py +330 -0
  53. app/api/routers/project/manifest.py +605 -0
  54. app/api/routers/project/models.py +177 -0
  55. app/api/routers/project/pattern.py +268 -0
  56. app/api/routers/project/regex.py +358 -0
  57. app/api/routers/project/scanner.py +157 -0
  58. app/api/routers/project/schema.py +567 -0
  59. app/api/routers/project/schema_helpers.py +149 -0
  60. app/api/routers/project/settings.py +399 -0
  61. app/api/routers/project/template.py +325 -0
  62. app/api/routers/project/validation.py +227 -0
  63. app/api/routers/project/view.py +177 -0
  64. app/api/routers/project/workspaces.py +167 -0
  65. app/api/routers/projects/__init__.py +25 -0
  66. app/api/routers/projects/create.py +121 -0
  67. app/api/routers/projects/open.py +103 -0
  68. app/api/routers/projects/scan.py +100 -0
  69. app/api/routers/validation/__init__.py +39 -0
  70. app/api/routers/validation/common.py +263 -0
  71. app/api/routers/validation/content_mode.py +401 -0
  72. app/api/routers/validation/history.py +235 -0
  73. app/api/routers/validation/inline_mode.py +196 -0
  74. app/api/routers/validation/path_mode.py +314 -0
  75. app/api/routers/validation/router.py +51 -0
  76. app/api/services/full_validation_response_builder.py +412 -0
  77. app/api/services/io_error_messages.py +41 -0
  78. app/api/services/preview_service.py +248 -0
  79. app/cli/__init__.py +18 -0
  80. app/cli/__main__.py +30 -0
  81. app/cli/shared_services/__init__.py +42 -0
  82. app/cli/shared_services/config_ops.py +581 -0
  83. app/cli/shared_services/generation_ops.py +160 -0
  84. app/cli/shared_services/project_ops.py +288 -0
  85. app/cli/shell/__init__.py +48 -0
  86. app/cli/shell/commands/__init__.py +63 -0
  87. app/cli/shell/commands/ai/__init__.py +260 -0
  88. app/cli/shell/commands/ai/chat.py +331 -0
  89. app/cli/shell/commands/ai/delete.py +165 -0
  90. app/cli/shell/commands/ai/diff.py +70 -0
  91. app/cli/shell/commands/ai/display.py +428 -0
  92. app/cli/shell/commands/ai/executor.py +225 -0
  93. app/cli/shell/commands/ai/executor_utils.py +271 -0
  94. app/cli/shell/commands/ai/generate.py +285 -0
  95. app/cli/shell/commands/ai/interaction.py +262 -0
  96. app/cli/shell/commands/ai/migrate.py +281 -0
  97. app/cli/shell/commands/ai/resolver.py +224 -0
  98. app/cli/shell/commands/ai/status.py +101 -0
  99. app/cli/shell/commands/ai/switch.py +158 -0
  100. app/cli/shell/commands/ai/utils.py +52 -0
  101. app/cli/shell/commands/base.py +343 -0
  102. app/cli/shell/commands/config/__init__.py +131 -0
  103. app/cli/shell/commands/config/base.py +80 -0
  104. app/cli/shell/commands/config/check.py +246 -0
  105. app/cli/shell/commands/config/edit.py +148 -0
  106. app/cli/shell/commands/config/get.py +111 -0
  107. app/cli/shell/commands/config/init.py +123 -0
  108. app/cli/shell/commands/config/inspect.py +164 -0
  109. app/cli/shell/commands/config/list.py +104 -0
  110. app/cli/shell/commands/config/set.py +119 -0
  111. app/cli/shell/commands/config/show.py +150 -0
  112. app/cli/shell/commands/exit.py +67 -0
  113. app/cli/shell/commands/help.py +104 -0
  114. app/cli/shell/commands/infer_schema.py +156 -0
  115. app/cli/shell/commands/open.py +201 -0
  116. app/cli/shell/commands/project.py +215 -0
  117. app/cli/shell/commands/provider.py +619 -0
  118. app/cli/shell/commands/system.py +170 -0
  119. app/cli/shell/commands/validate.py +455 -0
  120. app/cli/shell/completer.py +231 -0
  121. app/cli/shell/config_storage.py +191 -0
  122. app/cli/shell/exceptions.py +90 -0
  123. app/cli/shell/formatter.py +371 -0
  124. app/cli/shell/interactive_menu.py +348 -0
  125. app/cli/shell/main.py +286 -0
  126. app/cli/shell/parser.py +266 -0
  127. app/cli/start.py +180 -0
  128. app/cli_main.py +52 -0
  129. app/mcp_server.py +311 -0
  130. app/shared/core/__init__.py +18 -0
  131. app/shared/core/app_version.py +59 -0
  132. app/shared/core/config/__init__.py +119 -0
  133. app/shared/core/config/server.py +193 -0
  134. app/shared/core/data_source/__init__.py +106 -0
  135. app/shared/core/data_source/loader.py +348 -0
  136. app/shared/core/data_source/loaders/__init__.py +213 -0
  137. app/shared/core/data_source/loaders/base.py +215 -0
  138. app/shared/core/data_source/loaders/converter.py +337 -0
  139. app/shared/core/data_source/loaders/csv_loader.py +252 -0
  140. app/shared/core/data_source/loaders/excel_loader.py +666 -0
  141. app/shared/core/data_source/loaders/extractor.py +268 -0
  142. app/shared/core/data_source/loaders/json_loader.py +354 -0
  143. app/shared/core/data_source/loaders/registry.py +88 -0
  144. app/shared/core/data_source/loaders/sql_loader.py +313 -0
  145. app/shared/core/data_source/loaders/strategies/__init__.py +100 -0
  146. app/shared/core/data_source/loaders/strategies/array_parser.py +277 -0
  147. app/shared/core/data_source/loaders/strategies/lines_parser.py +355 -0
  148. app/shared/core/data_source/loaders/strategies/object_parser.py +278 -0
  149. app/shared/core/data_source/schema_info.py +50 -0
  150. app/shared/core/data_source/specs/__init__.py +128 -0
  151. app/shared/core/data_source/specs/base.py +258 -0
  152. app/shared/core/data_source/specs/csv_source.py +137 -0
  153. app/shared/core/data_source/specs/excel_source.py +141 -0
  154. app/shared/core/data_source/specs/file_base.py +252 -0
  155. app/shared/core/data_source/specs/json_source.py +226 -0
  156. app/shared/core/data_source/specs/sql_source.py +161 -0
  157. app/shared/core/encoding.py +36 -0
  158. app/shared/core/io/__init__.py +24 -0
  159. app/shared/core/io/yaml.py +379 -0
  160. app/shared/core/manifest_schema/__init__.py +52 -0
  161. app/shared/core/manifest_schema/types.py +99 -0
  162. app/shared/core/manifest_schema/version.py +175 -0
  163. app/shared/core/patterns/__init__.py +24 -0
  164. app/shared/core/patterns/loader.py +134 -0
  165. app/shared/core/patterns/writer.py +244 -0
  166. app/shared/core/project/__init__.py +47 -0
  167. app/shared/core/project/constraint/builders/__init__.py +50 -0
  168. app/shared/core/project/constraint/builders/base.py +100 -0
  169. app/shared/core/project/constraint/builders/composite.py +77 -0
  170. app/shared/core/project/constraint/builders/conditional.py +67 -0
  171. app/shared/core/project/constraint/builders/foreign_key.py +53 -0
  172. app/shared/core/project/constraint/builders/registry.py +64 -0
  173. app/shared/core/project/constraint/builders/scripted.py +51 -0
  174. app/shared/core/project/constraint/builders/single_column.py +86 -0
  175. app/shared/core/project/constraint/builders/unique.py +53 -0
  176. app/shared/core/project/constraint/factory.py +170 -0
  177. app/shared/core/project/constraint/reader.py +214 -0
  178. app/shared/core/project/constraint/registry.py +233 -0
  179. app/shared/core/project/constraint/types/__init__.py +63 -0
  180. app/shared/core/project/constraint/types/constraint_file.py +261 -0
  181. app/shared/core/project/constraint/types/refs.py +460 -0
  182. app/shared/core/project/constraint/types.py +28 -0
  183. app/shared/core/project/constraint/writer.py +181 -0
  184. app/shared/core/project/loader/__init__.py +56 -0
  185. app/shared/core/project/loader/loader.py +30 -0
  186. app/shared/core/project/loader/loader_parts/config_inspector.py +137 -0
  187. app/shared/core/project/loader/loader_parts/embedded_constraints.py +224 -0
  188. app/shared/core/project/loader/loader_parts/file_loaders.py +58 -0
  189. app/shared/core/project/loader/loader_parts/inspection_ids.py +85 -0
  190. app/shared/core/project/loader/loader_parts/inspector_helpers.py +312 -0
  191. app/shared/core/project/loader/loader_parts/inspector_id_checks.py +274 -0
  192. app/shared/core/project/loader/loader_parts/inspector_reference_checks.py +690 -0
  193. app/shared/core/project/loader/loader_parts/inspector_uniqueness_checks.py +286 -0
  194. app/shared/core/project/loader/loader_parts/loading_error_messages.py +298 -0
  195. app/shared/core/project/loader/loader_parts/main.py +432 -0
  196. app/shared/core/project/loader/loader_parts/path_validation.py +117 -0
  197. app/shared/core/project/loader/loader_parts/runtime.py +125 -0
  198. app/shared/core/project/loader/types.py +246 -0
  199. app/shared/core/project/manifest/coverage.py +391 -0
  200. app/shared/core/project/manifest/reader.py +260 -0
  201. app/shared/core/project/manifest/types.py +91 -0
  202. app/shared/core/project/manifest/types_parts/__init__.py +60 -0
  203. app/shared/core/project/manifest/types_parts/constants.py +40 -0
  204. app/shared/core/project/manifest/types_parts/data_source.py +68 -0
  205. app/shared/core/project/manifest/types_parts/info.py +59 -0
  206. app/shared/core/project/manifest/types_parts/manifest.py +294 -0
  207. app/shared/core/project/manifest/types_parts/refs.py +153 -0
  208. app/shared/core/project/manifest/types_parts/settings.py +92 -0
  209. app/shared/core/project/manifest/types_parts/settings_file_processing.py +64 -0
  210. app/shared/core/project/manifest/types_parts/settings_script_security.py +78 -0
  211. app/shared/core/project/manifest/types_parts/settings_validation.py +83 -0
  212. app/shared/core/project/manifest/types_parts/template.py +66 -0
  213. app/shared/core/project/manifest/writer.py +262 -0
  214. app/shared/core/project/manual_data/__init__.py +27 -0
  215. app/shared/core/project/manual_data/types.py +75 -0
  216. app/shared/core/project/regex/reader.py +197 -0
  217. app/shared/core/project/regex/types.py +405 -0
  218. app/shared/core/project/regex/writer.py +123 -0
  219. app/shared/core/project/schema/reader.py +170 -0
  220. app/shared/core/project/schema/types.py +47 -0
  221. app/shared/core/project/schema/types_parts/__init__.py +36 -0
  222. app/shared/core/project/schema/types_parts/column.py +174 -0
  223. app/shared/core/project/schema/types_parts/column_utils.py +72 -0
  224. app/shared/core/project/schema/types_parts/constraint.py +165 -0
  225. app/shared/core/project/schema/types_parts/schema_id.py +66 -0
  226. app/shared/core/project/schema/types_parts/source.py +255 -0
  227. app/shared/core/project/schema/types_parts/source_options.py +347 -0
  228. app/shared/core/project/schema/types_parts/table.py +230 -0
  229. app/shared/core/project/schema/writer.py +139 -0
  230. app/shared/core/project/schema_ref_check.py +95 -0
  231. app/shared/core/project/template/__init__.py +27 -0
  232. app/shared/core/project/template/expander.py +263 -0
  233. app/shared/core/project/template/reader.py +120 -0
  234. app/shared/core/project/template/types.py +114 -0
  235. app/shared/core/project/transform/reader.py +76 -0
  236. app/shared/core/project/transform/types.py +116 -0
  237. app/shared/core/project/transform/writer.py +84 -0
  238. app/shared/core/pydantic_messages.py +59 -0
  239. app/shared/core/reporter/__init__.py +46 -0
  240. app/shared/core/reporter/reporter.py +220 -0
  241. app/shared/core/reporter/reporters/__init__.py +65 -0
  242. app/shared/core/reporter/reporters/base.py +188 -0
  243. app/shared/core/reporter/reporters/dingtalk_app_reporter.py +274 -0
  244. app/shared/core/reporter/reporters/email_reporter.py +271 -0
  245. app/shared/core/reporter/reporters/feishu_app_reporter.py +467 -0
  246. app/shared/core/reporter/reporters/local_file_reporter.py +208 -0
  247. app/shared/core/reporter/reporters/wecom_app_reporter.py +268 -0
  248. app/shared/core/utils/__init__.py +18 -0
  249. app/shared/core/utils/path_utils.py +60 -0
  250. app/shared/core/utils/regex_extract.py +113 -0
  251. app/shared/domain/__init__.py +114 -0
  252. app/shared/domain/constraints/__init__.py +76 -0
  253. app/shared/domain/constraints/allowed_values.py +211 -0
  254. app/shared/domain/constraints/base.py +141 -0
  255. app/shared/domain/constraints/charset.py +337 -0
  256. app/shared/domain/constraints/composite.py +174 -0
  257. app/shared/domain/constraints/condition_registry.py +130 -0
  258. app/shared/domain/constraints/conditional.py +629 -0
  259. app/shared/domain/constraints/date_logic.py +731 -0
  260. app/shared/domain/constraints/foreign_key.py +261 -0
  261. app/shared/domain/constraints/key_normalization.py +56 -0
  262. app/shared/domain/constraints/not_null.py +185 -0
  263. app/shared/domain/constraints/range.py +360 -0
  264. app/shared/domain/constraints/regex.py +218 -0
  265. app/shared/domain/constraints/scripted.py +276 -0
  266. app/shared/domain/constraints/unique.py +233 -0
  267. app/shared/domain/data_engine.py +384 -0
  268. app/shared/domain/data_types.py +113 -0
  269. app/shared/domain/data_types_parts/__init__.py +67 -0
  270. app/shared/domain/data_types_parts/base.py +204 -0
  271. app/shared/domain/data_types_parts/composite.py +250 -0
  272. app/shared/domain/data_types_parts/expression.py +202 -0
  273. app/shared/domain/data_types_parts/extracted.py +106 -0
  274. app/shared/domain/data_types_parts/json_types.py +234 -0
  275. app/shared/domain/data_types_parts/scalars.py +719 -0
  276. app/shared/domain/data_types_parts/sequence.py +129 -0
  277. app/shared/domain/dataset_schema.py +48 -0
  278. app/shared/domain/eval_sandbox.py +63 -0
  279. app/shared/domain/expression_system.py +366 -0
  280. app/shared/domain/regex_flags.py +53 -0
  281. app/shared/domain/schema/builder.py +223 -0
  282. app/shared/domain/schema/models.py +339 -0
  283. app/shared/domain/transforms/__init__.py +28 -0
  284. app/shared/domain/transforms/aggregate.py +141 -0
  285. app/shared/domain/transforms/base.py +171 -0
  286. app/shared/domain/transforms/cast_type.py +120 -0
  287. app/shared/domain/transforms/concat.py +103 -0
  288. app/shared/domain/transforms/conditional_assign.py +114 -0
  289. app/shared/domain/transforms/date_format.py +81 -0
  290. app/shared/domain/transforms/digits.py +77 -0
  291. app/shared/domain/transforms/drop_duplicates.py +94 -0
  292. app/shared/domain/transforms/fill_na.py +94 -0
  293. app/shared/domain/transforms/filter_rows.py +97 -0
  294. app/shared/domain/transforms/lookup.py +78 -0
  295. app/shared/domain/transforms/lower_case.py +70 -0
  296. app/shared/domain/transforms/map_value.py +90 -0
  297. app/shared/domain/transforms/math_expr.py +112 -0
  298. app/shared/domain/transforms/modulo.py +82 -0
  299. app/shared/domain/transforms/regex_extract.py +103 -0
  300. app/shared/domain/transforms/registry.py +95 -0
  301. app/shared/domain/transforms/replace.py +88 -0
  302. app/shared/domain/transforms/sort_rows.py +94 -0
  303. app/shared/domain/transforms/string_split.py +84 -0
  304. app/shared/domain/transforms/strip.py +73 -0
  305. app/shared/domain/transforms/substring.py +92 -0
  306. app/shared/domain/transforms/upper_case.py +70 -0
  307. app/shared/domain/transforms/weighted_sum.py +104 -0
  308. app/shared/domain/validation_constraints.py +69 -0
  309. app/shared/services/__init__.py +62 -0
  310. app/shared/services/ai/__init__.py +48 -0
  311. app/shared/services/ai/agent/__init__.py +40 -0
  312. app/shared/services/ai/agent/chat_tools/__init__.py +47 -0
  313. app/shared/services/ai/agent/chat_tools/apply_actions.py +592 -0
  314. app/shared/services/ai/agent/chat_tools/ask_user.py +237 -0
  315. app/shared/services/ai/agent/chat_tools/read_canvas.py +140 -0
  316. app/shared/services/ai/agent/chat_tools/read_project.py +160 -0
  317. app/shared/services/ai/agent/chat_tools/read_table.py +301 -0
  318. app/shared/services/ai/agent/chat_tools/schemas.py +105 -0
  319. app/shared/services/ai/agent/chat_tools/validate_table.py +131 -0
  320. app/shared/services/ai/agent/executor.py +554 -0
  321. app/shared/services/ai/agent/memory.py +256 -0
  322. app/shared/services/ai/agent/planner.py +282 -0
  323. app/shared/services/ai/agent/tool_registry.py +296 -0
  324. app/shared/services/ai/agent/tools/__init__.py +32 -0
  325. app/shared/services/ai/agent/tools/config_generate.py +133 -0
  326. app/shared/services/ai/agent/tools/config_refine.py +109 -0
  327. app/shared/services/ai/agent/tools/config_validate.py +403 -0
  328. app/shared/services/ai/agent/tools/merge_results.py +136 -0
  329. app/shared/services/ai/agent/tools/plan_chunks.py +79 -0
  330. app/shared/services/ai/agent/tools/script_parse.py +359 -0
  331. app/shared/services/ai/agent/types.py +138 -0
  332. app/shared/services/ai/chat_agent_runner.py +596 -0
  333. app/shared/services/ai/chat_orchestrator.py +725 -0
  334. app/shared/services/ai/failure_messages.py +65 -0
  335. app/shared/services/ai/job_storage.py +274 -0
  336. app/shared/services/ai/migrate_service.py +550 -0
  337. app/shared/services/ai/streaming/__init__.py +65 -0
  338. app/shared/services/ai/streaming/event_journal.py +197 -0
  339. app/shared/services/ai/streaming/orchestrator.py +262 -0
  340. app/shared/services/ai/streaming/pending_interaction_store.py +227 -0
  341. app/shared/services/ai/streaming/sse_response.py +148 -0
  342. app/shared/services/ai/streaming/types.py +73 -0
  343. app/shared/services/ai/types.py +213 -0
  344. app/shared/services/ai/utils.py +322 -0
  345. app/shared/services/diff/config_diff.py +320 -0
  346. app/shared/services/hardware.py +237 -0
  347. app/shared/services/llm/__init__.py +62 -0
  348. app/shared/services/llm/actions/__init__.py +42 -0
  349. app/shared/services/llm/actions/_canvas_validator.py +147 -0
  350. app/shared/services/llm/actions/_constraint_validator.py +401 -0
  351. app/shared/services/llm/actions/_regex_validator.py +85 -0
  352. app/shared/services/llm/actions/_schema_validator.py +82 -0
  353. app/shared/services/llm/actions/_settings_validator.py +76 -0
  354. app/shared/services/llm/actions/_transform_validator.py +78 -0
  355. app/shared/services/llm/actions/action_handlers.py +400 -0
  356. app/shared/services/llm/actions/action_parser.py +63 -0
  357. app/shared/services/llm/actions/action_processor.py +468 -0
  358. app/shared/services/llm/actions/action_validator.py +311 -0
  359. app/shared/services/llm/actions/diff_compute.py +195 -0
  360. app/shared/services/llm/actions/regex_handlers.py +284 -0
  361. app/shared/services/llm/actions/registry.py +336 -0
  362. app/shared/services/llm/actions/schema_handlers.py +335 -0
  363. app/shared/services/llm/actions/settings_handlers.py +180 -0
  364. app/shared/services/llm/actions/specs.py +259 -0
  365. app/shared/services/llm/actions/transform_handlers.py +279 -0
  366. app/shared/services/llm/actions/validation_types.py +147 -0
  367. app/shared/services/llm/cache/__init__.py +18 -0
  368. app/shared/services/llm/cache/response_cache.py +80 -0
  369. app/shared/services/llm/chat/__init__.py +35 -0
  370. app/shared/services/llm/chat/chat_system_prompt.py +561 -0
  371. app/shared/services/llm/chat/response_parser.py +296 -0
  372. app/shared/services/llm/config/__init__.py +45 -0
  373. app/shared/services/llm/config/crypto.py +135 -0
  374. app/shared/services/llm/config/loader.py +258 -0
  375. app/shared/services/llm/config/models.py +202 -0
  376. app/shared/services/llm/config/presets.py +128 -0
  377. app/shared/services/llm/config_generator.py +163 -0
  378. app/shared/services/llm/constraints/__init__.py +41 -0
  379. app/shared/services/llm/constraints/constraint_builder.py +177 -0
  380. app/shared/services/llm/constraints/constraint_deletion.py +84 -0
  381. app/shared/services/llm/constraints/constraint_id.py +174 -0
  382. app/shared/services/llm/constraints/frontend_instructions.py +333 -0
  383. app/shared/services/llm/constraints/inline_batch.py +279 -0
  384. app/shared/services/llm/discovery/__init__.py +35 -0
  385. app/shared/services/llm/discovery/scanner.py +181 -0
  386. app/shared/services/llm/generation/__init__.py +42 -0
  387. app/shared/services/llm/generation/agent_wiring.py +156 -0
  388. app/shared/services/llm/generation/config_builder.py +386 -0
  389. app/shared/services/llm/generation/errors.py +36 -0
  390. app/shared/services/llm/generation/existing_config.py +99 -0
  391. app/shared/services/llm/generation/profiler.py +279 -0
  392. app/shared/services/llm/generation/prompt_builder.py +199 -0
  393. app/shared/services/llm/generation/response_parser.py +144 -0
  394. app/shared/services/llm/generation/service.py +622 -0
  395. app/shared/services/llm/models.py +104 -0
  396. app/shared/services/llm/providers/__init__.py +48 -0
  397. app/shared/services/llm/providers/base.py +310 -0
  398. app/shared/services/llm/providers/cached_provider.py +90 -0
  399. app/shared/services/llm/providers/ollama.py +498 -0
  400. app/shared/services/llm/providers/openai.py +334 -0
  401. app/shared/services/llm/providers/registry.py +108 -0
  402. app/shared/services/llm/schema_resolver.py +141 -0
  403. app/shared/services/llm/suggestion_utils.py +219 -0
  404. app/shared/services/llm/validate_executor.py +163 -0
  405. app/shared/services/llm/yaml_io.py +406 -0
  406. app/shared/services/preview/__init__.py +18 -0
  407. app/shared/services/preview/loader.py +145 -0
  408. app/shared/services/preview/path_validation.py +138 -0
  409. app/shared/services/project_loader.py +57 -0
  410. app/shared/services/schema_inference.py +260 -0
  411. app/shared/services/schema_runtime_builder.py +120 -0
  412. app/shared/services/validation/__init__.py +52 -0
  413. app/shared/services/validation/chunked_loader.py +509 -0
  414. app/shared/services/validation/dag/__init__.py +35 -0
  415. app/shared/services/validation/dag/builder.py +141 -0
  416. app/shared/services/validation/dag/executor.py +225 -0
  417. app/shared/services/validation/dag/sorter.py +77 -0
  418. app/shared/services/validation/data_loader.py +231 -0
  419. app/shared/services/validation/engine.py +446 -0
  420. app/shared/services/validation/executor.py +1030 -0
  421. app/shared/services/validation/extractors.py +266 -0
  422. app/shared/services/validation/history.py +209 -0
  423. app/shared/services/validation/json_payload.py +136 -0
  424. app/shared/services/validation/loader.py +152 -0
  425. app/shared/services/validation/memory_monitor.py +179 -0
  426. app/shared/services/validation/postprocess.py +208 -0
  427. app/shared/services/validation/progress.py +64 -0
  428. app/shared/services/validation/report_export.py +222 -0
  429. app/shared/services/validation/resolver.py +180 -0
  430. app/shared/services/validation/service.py +418 -0
  431. app/shared/services/validation/types.py +238 -0
  432. app/shared/services/validation/validators/__init__.py +36 -0
  433. app/shared/services/validation/validators/adapter.py +182 -0
  434. app/shared/services/validation/validators/base.py +332 -0
  435. app/shared/services/validation/validators/composite.py +233 -0
  436. app/shared/services/validation/validators/date_logic.py +276 -0
  437. app/start_server.py +133 -0
  438. precis_cli-0.1.3.dist-info/METADATA +180 -0
  439. precis_cli-0.1.3.dist-info/RECORD +442 -0
  440. precis_cli-0.1.3.dist-info/WHEEL +5 -0
  441. precis_cli-0.1.3.dist-info/entry_points.txt +4 -0
  442. precis_cli-0.1.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,223 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ #
3
+ # Copyright 2026 Precis Team
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ """
17
+ @fileoverview 数据 Schema 类型构建器
18
+
19
+ 功能概述:
20
+ - 提供从配置文件构建数据类型实例的工厂函数
21
+ - 管理类型注册表(TYPE_REGISTRY)
22
+
23
+ 架构设计:
24
+ - 类型注册表: 将配置中的类型名称映射到 Python 类型对象
25
+ - 工厂函数: build_type_from_config 根据配置递归构建 DataType 实例
26
+
27
+ 约束注册表已迁移至 app.shared.core.project.constraint.registry
28
+ """
29
+
30
+ from typing import Any, cast
31
+
32
+ # 1. 项目内部导入
33
+ from app.shared.domain.data_types import (
34
+ BooleanType,
35
+ CompositeConditionType,
36
+ DataType,
37
+ DateType,
38
+ DecimalType,
39
+ ExpressionType,
40
+ ExtractedType,
41
+ FloatType,
42
+ IntegerType,
43
+ JsonArrayType,
44
+ JsonNullType,
45
+ JsonObjectType,
46
+ SequenceType,
47
+ StringType,
48
+ )
49
+ from app.shared.domain.expression_system import (
50
+ ExpressionRegistry,
51
+ )
52
+
53
+ # ============================================================================
54
+ # 类型注册表
55
+ # ============================================================================
56
+ # 将配置中的类型名称映射到 Python 类型对象
57
+ # 使用示例:
58
+ # "int" -> IntegerType()
59
+ # "string" -> StringType()
60
+ # "Expr" -> ExpressionType (类,非实例)
61
+
62
+ TYPE_REGISTRY: dict[str, Any] = {
63
+ "Int": IntegerType(),
64
+ "Str": StringType(),
65
+ "Float": FloatType(),
66
+ "Decimal": DecimalType(),
67
+ "Boolean": BooleanType(),
68
+ "Date": DateType(),
69
+ "int": IntegerType(),
70
+ "integer": IntegerType(),
71
+ "string": StringType(),
72
+ "str": StringType(),
73
+ "float": FloatType(),
74
+ "decimal": DecimalType(),
75
+ "boolean": BooleanType(),
76
+ "bool": BooleanType(),
77
+ "date": DateType(),
78
+ "Expr": ExpressionType,
79
+ "CompositeExpr": CompositeConditionType,
80
+ "Sequence": SequenceType,
81
+ "Extracted": ExtractedType,
82
+ "JsonObject": JsonObjectType(),
83
+ "json_object": JsonObjectType(),
84
+ "JsonArray": JsonArrayType(),
85
+ "json_array": JsonArrayType(),
86
+ "JsonNull": JsonNullType(),
87
+ "json_null": JsonNullType(),
88
+ # JSON-Schema 规范类型名别名(用户手写或旧版序列化器可能直接使用这些名字)
89
+ # 与前端 toJsonBackendType 的映射保持一致,避免直接读取此类文件时报错
90
+ "number": FloatType(),
91
+ "object": JsonObjectType(),
92
+ "array": JsonArrayType(),
93
+ "null": JsonNullType(),
94
+ }
95
+
96
+
97
+ def build_type_from_config(config: Any, registries: dict[str, ExpressionRegistry] | None = None) -> DataType:
98
+ """
99
+ 从配置构建数据类型实例。
100
+
101
+ ============================================================================
102
+ 配置文件示例 (本函数处理的配置文件长这样)
103
+ ============================================================================
104
+ 本函数处理以下格式的类型配置:
105
+
106
+ ```yaml
107
+ # 方式1: 字符串形式(简单类型)
108
+ column:
109
+ type: "int" # 或 "string", "float", "decimal"
110
+
111
+ # 方式2: 字典形式(带参数的类型)
112
+ column:
113
+ type:
114
+ name: "Sequence" # 类型名称
115
+ item_type: "string" # 元素类型
116
+ delimiter: "," # 分隔符
117
+
118
+ # 方式3: 字典形式(带表达式的类型)
119
+ column:
120
+ type:
121
+ name: "Expr" # 表达式类型
122
+ registry: "patterns" # 注册表名称
123
+ ```
124
+
125
+ ============================================================================
126
+ 业务场景 (什么情况下会调用这个函数)
127
+ ============================================================================
128
+ - 场景1: 从配置文件加载 Schema 时
129
+ 读取 *.schema.yaml 文件后,需要将配置中的类型字符串转换为实际的类型对象。
130
+
131
+ - 场景2: 运行时动态创建类型
132
+ 根据用户输入动态创建数据类型实例。
133
+
134
+ ============================================================================
135
+ 数据流 (输入如何变成输出)
136
+ ============================================================================
137
+ 输入参数:
138
+ - config: Any,类型配置
139
+ 示例值: "int" 或 {"name": "Sequence", "item_type": "string", "delimiter": ","}
140
+ - registries: Dict[str, ExpressionRegistry],表达式注册表(可选)
141
+ 示例值: {"patterns": ExpressionRegistry(...)}
142
+
143
+ 处理步骤:
144
+ ┌─────────────────────────────────────────────────────────────┐
145
+ │ Step 1: 判断配置类型 │
146
+ ├─────────────────────────────────────────────────────────────┤
147
+ │ 输入: config │
148
+ │ 操作: 检查是字符串还是字典 │
149
+ │ 输出: 配置类型 │
150
+ └─────────────────────────────────────────────────────────────┘
151
+
152
+ ┌─────────────────────────────────────────────────────────────┤
153
+ │ Step 2: 字符串形式处理 │
154
+ ├─────────────────────────────────────────────────────────────┤
155
+ │ 输入: config = "int" │
156
+ │ 操作: 从 TYPE_REGISTRY 查找类型 │
157
+ │ 输出: IntegerType() 实例 │
158
+ └─────────────────────────────────────────────────────────────┘
159
+
160
+ ┌─────────────────────────────────────────────────────────────┤
161
+ │ Step 3: 字典形式处理 │
162
+ ├─────────────────────────────────────────────────────────────┤
163
+ │ 输入: config = {"name": "Sequence", ...} │
164
+ │ 操作: 提取 name,从 REGISTRY 查找类 │
165
+ │ 递归处理 item_type、registry 参数 │
166
+ │ 输出: SequenceType(StringType(), ",") 实例 │
167
+ └─────────────────────────────────────────────────────────────┘
168
+
169
+ 最终输出: DataType 实例
170
+ 示例:
171
+ build_type_from_config("int") # 返回 IntegerType() 实例
172
+ build_type_from_config({"name": "Sequence", "item_type": "string"})
173
+ # 返回 SequenceType(StringType(), ";")
174
+
175
+ ============================================================================
176
+ 边界情况处理
177
+ ============================================================================
178
+ - 未知类型名称: 抛出 ValueError
179
+ - 无效的配置格式: 抛出 TypeError
180
+ - 缺失的 registry: 抛出 ValueError
181
+
182
+ :param config: 类型配置(字符串或字典)
183
+ :param registries: 表达式注册表字典
184
+ :return: DataType 实例
185
+ :raises ValueError: 类型名称不存在或 registry 缺失
186
+ :raises TypeError: 配置格式无效
187
+ """
188
+ if isinstance(config, str):
189
+ type_name = config
190
+ if type_name not in TYPE_REGISTRY:
191
+ raise ValueError(f"未知的类型名称: '{type_name}'")
192
+ return cast(DataType, TYPE_REGISTRY[type_name])
193
+
194
+ elif isinstance(config, dict):
195
+ type_name = cast(str, config.get("name"))
196
+ if not type_name or type_name not in TYPE_REGISTRY:
197
+ raise ValueError(f"类型配置字典中缺少或包含未知的类型名称: {config}")
198
+
199
+ type_class = TYPE_REGISTRY[type_name]
200
+ params = config.copy()
201
+ params.pop("name")
202
+
203
+ if "item_type" in params:
204
+ params["item_type"] = build_type_from_config(params["item_type"], registries)
205
+
206
+ if "registry" in params and isinstance(params["registry"], str):
207
+ registry_name = params["registry"]
208
+ if registries and registry_name in registries:
209
+ params["registry"] = registries[registry_name]
210
+ else:
211
+ raise ValueError(f"名为 '{registry_name}' 的表达式注册中心未提供。")
212
+
213
+ if "atomic_registry" in params and isinstance(params["atomic_registry"], str):
214
+ registry_name = params["atomic_registry"]
215
+ if registries and registry_name in registries:
216
+ params["registry"] = registries[registry_name]
217
+ else:
218
+ raise ValueError(f"名为 '{registry_name}' 的表达式注册中心未提供。")
219
+
220
+ return cast(DataType, type_class(**params))
221
+
222
+ else:
223
+ raise TypeError(f"无效的类型配置格式: {type(config)}")
@@ -0,0 +1,339 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ #
3
+ # Copyright 2026 Precis Team
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ """
17
+ @fileoverview 数据 Schema 模型模块
18
+
19
+ 功能概述:
20
+ - 定义数据集的结构(表、字段、约束)
21
+
22
+ 架构设计:
23
+ - 本模块只定义 Schema 模型类(ColumnSchema/TableSchema/DataSetSchema)
24
+ - TYPE_REGISTRY 与工厂函数 build_type_from_config 的单一事实源在 builder.py
25
+ - 本模块 re-export TYPE_REGISTRY 仅用于保持向后兼容的导入路径
26
+
27
+ 输入示例:
28
+ from app.shared.domain.dataset_schema import DataSetSchema, TableSchema, ColumnSchema
29
+
30
+ col1 = ColumnSchema(name="user_id", data_type=IntegerType(), is_primary_key=True)
31
+ table = TableSchema(name="users", columns=[col1, col2], source_file="data/users.xlsx")
32
+ schema = DataSetSchema(tables={"users": table}, constraints=[])
33
+
34
+ 输出示例:
35
+ schema: 完整的数据集 Schema 对象,可用于驱动 process_dataframe 和约束校验
36
+ """
37
+
38
+ from typing import Any
39
+
40
+ from app.shared.domain.constraints.base import Constraint
41
+ from app.shared.domain.data_types import DataType
42
+
43
+ # 1. 项目内部导入
44
+ # TYPE_REGISTRY 的单一事实源在 builder.py,此处 re-export 以保持向后兼容的导入路径。
45
+ # 过去本模块维护了一份独立副本,导致与 builder.py 漂移(如 JSON-Schema 别名缺失)。
46
+ from app.shared.domain.schema.builder import TYPE_REGISTRY # noqa: F401
47
+
48
+
49
+ class ColumnSchema:
50
+ """
51
+ 字段 Schema 定义。
52
+
53
+ ============================================================================
54
+ 配置文件示例 (这个类对应哪种配置)
55
+ ============================================================================
56
+ 本类对应 *.schema.yaml 中的 columns 列表项:
57
+
58
+ ```yaml
59
+ columns:
60
+ - id: user_id
61
+ name: user_id
62
+ type: int
63
+ primary_key: true
64
+ expand: false
65
+
66
+ - id: email
67
+ name: email
68
+ type: string
69
+ primary_key: false
70
+ ```
71
+
72
+ ============================================================================
73
+ 字段映射说明
74
+ ============================================================================
75
+ | YAML 字段 | Python 属性 | 数据类型 | 说明 | 示例值 |
76
+ |----------|------------|---------|------|-------|
77
+ | id | (自动生成) | str | 列 ID | "user_id" |
78
+ | name | name | str | 列名 | "user_id" |
79
+ | type | data_type | DataType | 数据类型 | IntegerType() |
80
+ | primary_key | is_primary_key | bool | 是否主键 | true |
81
+ | expand | expand | bool | 是否展开 | false |
82
+
83
+ ============================================================================
84
+ 业务场景 (什么情况下会使用这个类)
85
+ ============================================================================
86
+ - 场景1: 定义表的列结构
87
+ 创建表时定义每一列的名称、类型、是否主键等。
88
+
89
+ - 场景2: 数据校验
90
+ 根据 ColumnSchema 对数据列进行类型验证。
91
+
92
+ ============================================================================
93
+ 使用示例
94
+ ============================================================================
95
+ 【创建实例】
96
+ ```python
97
+ from app.shared.domain.dataset_schema import ColumnSchema
98
+ from app.shared.domain.data_types import IntegerType, StringType
99
+
100
+ col = ColumnSchema(
101
+ name="user_id",
102
+ data_type=IntegerType(),
103
+ is_primary_key=True,
104
+ expand=False
105
+ )
106
+ ```
107
+
108
+ 【从配置创建】
109
+ ```python
110
+ config = {"name": "user_id", "type": "int", "primary_key": True}
111
+ data_type = build_type_from_config(config["type"])
112
+ col = ColumnSchema(name=config["name"], data_type=data_type)
113
+ ```
114
+ """
115
+
116
+ def __init__(
117
+ self,
118
+ name: str,
119
+ data_type: DataType,
120
+ is_primary_key: bool = False,
121
+ expand: bool = False,
122
+ nullable: bool = True,
123
+ id: str | None = None,
124
+ json_path: str | None = None,
125
+ children: list["ColumnSchema"] | None = None,
126
+ ):
127
+ self.name = name
128
+ self.data_type = data_type
129
+ self.is_primary_key = is_primary_key
130
+ self.expand = expand
131
+ self.nullable = nullable
132
+ self.id = id
133
+ self.json_path = json_path
134
+ self.children = children
135
+
136
+
137
+ class TableSchema:
138
+ """
139
+ 表 Schema 定义。
140
+
141
+ ============================================================================
142
+ 配置文件示例 (这个类对应哪种配置)
143
+ ============================================================================
144
+ 本类对应 *.schema.yaml 文件的主体:
145
+
146
+ ```yaml
147
+ id: users
148
+ name: users
149
+ source:
150
+ mode: relative_file
151
+ path: data/users.xlsx
152
+ sheet: Sheet1
153
+ header_row: 0
154
+ columns:
155
+ - name: user_id
156
+ type: int
157
+ primary_key: true
158
+ - name: email
159
+ type: string
160
+ ```
161
+
162
+ ============================================================================
163
+ 字段映射说明
164
+ ============================================================================
165
+ | YAML 字段 | Python 属性 | 数据类型 | 说明 | 示例值 |
166
+ |----------|------------|---------|------|-------|
167
+ | id | (表名) | str | 表 ID | "users" |
168
+ | name | name | str | 表名 | "users" |
169
+ | source.path | source_file | str | 数据文件路径 | "data/users.xlsx" |
170
+ | source.sheet | sheet_name | str | Excel sheet | "Sheet1" |
171
+ | source.header_row | header_row | int | 表头行 | 0 |
172
+ | columns | columns | Dict[str, ColumnSchema] | 列定义字典 | {"user_id": ColumnSchema(...)} |
173
+
174
+ ============================================================================
175
+ 业务场景 (什么情况下会使用这个类)
176
+ ============================================================================
177
+ - 场景1: 定义单张表的结构
178
+ 定义表的名称、列定义、数据源位置等。
179
+
180
+ - 场景2: 加载数据文件
181
+ 根据 TableSchema 的 source_file、sheet_name 等信息加载数据。
182
+
183
+ ============================================================================
184
+ 使用示例
185
+ ============================================================================
186
+ 【创建实例】
187
+ ```python
188
+ from app.shared.domain.dataset_schema import TableSchema, ColumnSchema
189
+ from app.shared.domain.data_types import IntegerType, StringType
190
+
191
+ table = TableSchema(
192
+ name="users",
193
+ columns=[
194
+ ColumnSchema(name="user_id", data_type=IntegerType(), is_primary_key=True),
195
+ ColumnSchema(name="email", data_type=StringType())
196
+ ],
197
+ source_file="data/users.xlsx",
198
+ sheet_name="Sheet1"
199
+ )
200
+
201
+ # 访问列
202
+ col = table.get_column("user_id")
203
+ print(col.is_primary_key) # True
204
+ ```
205
+ """
206
+
207
+ def __init__(
208
+ self,
209
+ id: str | None = None,
210
+ name: str | None = None,
211
+ columns: list[ColumnSchema] | None = None,
212
+ source_file: str | None = None,
213
+ sheet_name: str | None = None,
214
+ header_row: int = 0,
215
+ script_checks: list[dict] | None = None,
216
+ source_config: dict[str, Any] | None = None,
217
+ ):
218
+ self.id = id
219
+ self.name = name
220
+ self.columns: dict[str, ColumnSchema] = {col.name: col for col in (columns or [])}
221
+ self.source_file = source_file
222
+ self.sheet_name = sheet_name
223
+ self.header_row = header_row
224
+ self.script_checks = script_checks or []
225
+ self.source_config = source_config or {}
226
+
227
+ def get_column(self, name: str) -> ColumnSchema | None:
228
+ """
229
+ @methoddesc 根据列名获取列定义
230
+
231
+ 参数:
232
+ name: 列名
233
+
234
+ 返回:
235
+ ColumnSchema 实例,如果列不存在则返回 None
236
+ """
237
+ return self.columns.get(name)
238
+
239
+
240
+ class DataSetSchema:
241
+ """
242
+ 数据集 Schema 定义。
243
+
244
+ ============================================================================
245
+ 配置文件示例 (这个类对应哪种配置)
246
+ ============================================================================
247
+ 本类是整个数据集的顶层结构:
248
+
249
+ ```yaml
250
+ # 表定义
251
+ tables:
252
+ users:
253
+ name: users
254
+ columns:
255
+ - name: user_id
256
+ type: int
257
+ - name: email
258
+ type: string
259
+ orders:
260
+ name: orders
261
+ columns:
262
+ - name: order_id
263
+ type: int
264
+
265
+ # 约束定义(独立文件)
266
+ constraints:
267
+ - type: Unique
268
+ table: users
269
+ column: email
270
+ - type: ForeignKey
271
+ from_table: orders
272
+ from_column: user_id
273
+ to_table: users
274
+ to_column: user_id
275
+ ```
276
+
277
+ ============================================================================
278
+ 字段映射说明
279
+ ============================================================================
280
+ | 概念 | Python 属性 | 数据类型 | 说明 |
281
+ |------|------------|---------|------|
282
+ | 多个表 | tables | Dict[str, TableSchema] | 表名 -> 表定义 |
283
+ | 约束列表 | constraints | List[Constraint] | 全局约束列表 |
284
+
285
+ ============================================================================
286
+ 业务场景 (什么情况下会使用这个类)
287
+ ============================================================================
288
+ - 场景1: 定义完整的数据集结构
289
+ 包含多张表及其之间的约束关系。
290
+
291
+ - 场景2: 执行完整校验
292
+ DataSetSchema 是 validate_full_dataset 的核心输入。
293
+
294
+ ============================================================================
295
+ 使用示例
296
+ ============================================================================
297
+ 【创建实例】
298
+ ```python
299
+ from app.shared.domain.dataset_schema import DataSetSchema, TableSchema, ColumnSchema
300
+ from app.shared.domain.data_types import IntegerType, StringType
301
+ from app.shared.domain.validation_constraints import UniqueConstraint
302
+
303
+ # 创建表
304
+ users_table = TableSchema(
305
+ name="users",
306
+ columns=[
307
+ ColumnSchema(name="user_id", data_type=IntegerType()),
308
+ ColumnSchema(name="email", data_type=StringType())
309
+ ]
310
+ )
311
+
312
+ orders_table = TableSchema(
313
+ name="orders",
314
+ columns=[
315
+ ColumnSchema(name="order_id", data_type=IntegerType()),
316
+ ColumnSchema(name="user_id", data_type=IntegerType())
317
+ ]
318
+ )
319
+
320
+ # 创建约束
321
+ constraints = [
322
+ UniqueConstraint(table="users", column="email")
323
+ ]
324
+
325
+ # 创建数据集 Schema
326
+ schema = DataSetSchema(
327
+ tables={"users": users_table, "orders": orders_table},
328
+ constraints=constraints
329
+ )
330
+
331
+ # 访问
332
+ print(schema.tables.keys()) # dict_keys(['users', 'orders'])
333
+ print(len(schema.constraints)) # 1
334
+ ```
335
+ """
336
+
337
+ def __init__(self, tables: dict[str, TableSchema], constraints: list[Constraint]):
338
+ self.tables = tables
339
+ self.constraints = constraints
@@ -0,0 +1,28 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ #
3
+ # Copyright 2026 Precis Team
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ """
17
+ @fileoverview Transform 运行器包
18
+
19
+ 导出:
20
+ - TransformRunner: 抽象基类
21
+ - create_runner: 工厂函数
22
+ - TRANSFORM_REGISTRY: 注册表
23
+ """
24
+
25
+ from .base import TransformRunner
26
+ from .registry import TRANSFORM_REGISTRY, create_runner
27
+
28
+ __all__ = ["TransformRunner", "TRANSFORM_REGISTRY", "create_runner"]