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,99 @@
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
+ """文件操作 API 模型:读/写文件、目录扫描、mkdir、存在性检查的请求/响应定义。"""
17
+
18
+ from __future__ import annotations
19
+
20
+ from pydantic import BaseModel, Field
21
+
22
+
23
+ class ReadFileRequest(BaseModel):
24
+ """读取文件请求。
25
+
26
+ B-sec1 安全约束: path 必须位于 root 指定的项目根目录下,由后端 assert_path_within_root 强制校验。
27
+ """
28
+
29
+ path: str
30
+ root: str = Field(..., description="项目根目录绝对路径,作为白名单根;path 必须落于此目录内")
31
+
32
+
33
+ class ReadFileResponse(BaseModel):
34
+ content: str
35
+ encoding: str = "utf-8"
36
+
37
+
38
+ class WriteFileRequest(BaseModel):
39
+ """写入文件请求。
40
+
41
+ B-sec1 安全约束: path 必须位于 root 指定的项目根目录下。
42
+ """
43
+
44
+ path: str
45
+ content: str
46
+ root: str = Field(..., description="项目根目录绝对路径,作为白名单根;path 必须落于此目录内")
47
+
48
+
49
+ class WriteFileResponse(BaseModel):
50
+ success: bool
51
+
52
+
53
+ class FileExistsRequest(BaseModel):
54
+ """检查存在性请求。
55
+
56
+ B-sec1 安全约束: path 必须位于 root 指定的项目根目录下。
57
+ """
58
+
59
+ path: str
60
+ root: str = Field(..., description="项目根目录绝对路径,作为白名单根;path 必须落于此目录内")
61
+
62
+
63
+ class FileExistsResponse(BaseModel):
64
+ exists: bool
65
+
66
+
67
+ class ScanDirectoryRequest(BaseModel):
68
+ """扫描目录请求。
69
+
70
+ B-sec1 安全约束: path 必须位于 root 指定的项目根目录下。
71
+ """
72
+
73
+ path: str
74
+ extensions: list[str] | None = None
75
+ root: str = Field(..., description="项目根目录绝对路径,作为白名单根;path 必须落于此目录内")
76
+
77
+
78
+ class ScanDirectoryResponse(BaseModel):
79
+ entries: list[DirectoryEntry]
80
+
81
+
82
+ class DirectoryEntry(BaseModel):
83
+ name: str
84
+ path: str
85
+ is_dir: bool
86
+
87
+
88
+ class MkdirRequest(BaseModel):
89
+ """创建目录请求。
90
+
91
+ B-sec1 安全约束: path 必须位于 root 指定的项目根目录下。
92
+ """
93
+
94
+ path: str
95
+ root: str = Field(..., description="项目根目录绝对路径,作为白名单根;path 必须落于此目录内")
96
+
97
+
98
+ class MkdirResponse(BaseModel):
99
+ success: bool
@@ -0,0 +1,554 @@
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
+ # backend/app/api/models/full_validation.py
17
+ """
18
+ @fileoverview 全量校验响应模型
19
+
20
+ 功能概述:
21
+ - 定义全量数据校验相关的 Pydantic 数据模型
22
+ - 包含校验请求、选项、摘要、错误项、通过项、统计信息等模型
23
+ - 支持校验设置覆盖(验证、文件处理、脚本安全)
24
+
25
+ 输入示例:
26
+ ValidationTaskRequest(
27
+ target=ValidationTaskTarget(type="full_project"),
28
+ run_options=ValidationTaskRunOptions(data_directory="./data")
29
+ )
30
+
31
+ 输出示例:
32
+ FullValidationResponse(
33
+ success=True,
34
+ summary=FullValidationSummary(
35
+ files_total=5, files_loaded=5, tables_loaded=3,
36
+ loading_error_count=0, format_error_count=1,
37
+ constraint_error_count=2, total_error_count=3,
38
+ duration_ms=1250
39
+ ),
40
+ errors=[...],
41
+ statistics=ValidationStatistics(...)
42
+ )
43
+ """
44
+
45
+ from typing import Literal
46
+
47
+ from pydantic import BaseModel, ConfigDict, Field, computed_field
48
+
49
+
50
+ class CoverageRef(BaseModel):
51
+ """
52
+ 资源引用模型
53
+
54
+ 用于在校验覆盖报告中标识单个资源(Schema、Constraint 或 RegexNode)。
55
+
56
+ Attributes:
57
+ id: 资源的唯一标识符
58
+ path: 资源文件相对于项目根目录的路径
59
+ """
60
+
61
+ id: str = Field(..., description="资源 ID") # 资源的唯一标识符,对应配置文件中的 id 字段
62
+ path: str = Field(..., description="相对路径") # 资源文件相对于项目根目录的相对路径
63
+
64
+
65
+ class CoverageGroup(BaseModel):
66
+ """
67
+ 资源分组模型
68
+
69
+ 按资源类型(Schema、Constraint、RegexNode)分组列出引用信息,
70
+ 用于描述未入清单或悬空引用的资源集合。
71
+
72
+ Attributes:
73
+ schemas: Schema 资源引用列表
74
+ constraints: Constraint 资源引用列表
75
+ regex_nodes: RegexNode 资源引用列表
76
+ """
77
+
78
+ schemas: list[CoverageRef] = Field(default_factory=list, description="Schema 引用列表") # 表结构定义资源列表
79
+ constraints: list[CoverageRef] = Field(default_factory=list, description="Constraint 引用列表") # 约束规则资源列表
80
+ regex_nodes: list[CoverageRef] = Field(default_factory=list, description="RegexNode 引用列表") # 正则节点资源列表
81
+
82
+
83
+ class ValidationCoverage(BaseModel):
84
+ """
85
+ 校验覆盖一致性模型
86
+
87
+ 用于报告项目清单(project.precis.yaml)与磁盘实际文件之间的一致性状态。
88
+ 帮助用户发现"目录存在但未入清单"或"清单引用但磁盘缺失"的资源问题。
89
+
90
+ Attributes:
91
+ is_complete: 覆盖是否完整(无 unlisted 且无 dangling 时为 True)
92
+ unlisted: 磁盘存在但未在 project.precis.yaml 中声明的资源
93
+ dangling: project.precis.yaml 中声明但磁盘缺失或不可读的资源
94
+ """
95
+
96
+ is_complete: bool = Field(..., description="校验覆盖是否完整") # True 表示清单与磁盘完全一致,无遗漏也无悬空引用
97
+ unlisted: CoverageGroup = Field(..., description="目录存在但未入清单的资源") # 磁盘上存在但未在清单中注册的资源分组
98
+ dangling: CoverageGroup = Field(
99
+ ..., description="清单引用但磁盘缺失/不可读的资源"
100
+ ) # 清单中注册但磁盘上缺失或不可读的资源分组
101
+
102
+
103
+ class ValidationSettingsOverride(BaseModel):
104
+ """
105
+ 校验设置覆盖模型
106
+
107
+ 用于在单次校验任务中临时覆盖 project.precis.yaml 中的校验相关设置。
108
+ 所有字段均为可选,未提供的字段保持项目原有配置。
109
+
110
+ Attributes:
111
+ auto_validate: 是否开启自动校验
112
+ strict_mode: 是否启用严格模式(遇到首个错误即停止)
113
+ error_handling: 错误处理策略(stop/continue/report)
114
+ timeout_seconds: 单次校验超时时间(秒),范围 1-300
115
+ batch_max_files: 批量处理最大文件数,范围 1-1000
116
+ """
117
+
118
+ model_config = ConfigDict(extra="forbid") # 禁止额外字段,防止传入未定义的配置项
119
+
120
+ auto_validate: bool | None = Field(default=None) # True 表示加载数据后自动执行校验,None 表示使用项目默认配置
121
+ strict_mode: bool | None = Field(default=None) # True 表示遇到首个错误即停止校验,False 表示继续执行并汇总所有错误
122
+ error_handling: Literal["stop", "continue", "report"] | None = Field(
123
+ default=None
124
+ ) # 错误处理策略:stop(停止)、continue(继续)、report(仅报告)
125
+ timeout_seconds: int | None = Field(default=None, ge=1, le=300) # 校验任务超时时间(秒),最小 1 秒,最大 300 秒
126
+ batch_max_files: int | None = Field(
127
+ default=None, ge=1, le=1000
128
+ ) # 批量加载文件时的最大文件数量限制,最小 1,最大 1000
129
+
130
+
131
+ class FileProcessingSettingsOverride(BaseModel):
132
+ """
133
+ 文件处理设置覆盖模型
134
+
135
+ 用于在单次校验任务中临时覆盖 project.precis.yaml 中的文件处理相关设置。
136
+
137
+ Attributes:
138
+ default_encoding: 默认文件编码(utf-8/gbk/auto)
139
+ csv_delimiter: CSV 文件分隔符(如逗号、分号、制表符)
140
+ """
141
+
142
+ model_config = ConfigDict(extra="forbid") # 禁止额外字段,确保配置严格受控
143
+
144
+ default_encoding: Literal["utf-8", "gbk", "auto"] | None = Field(
145
+ default=None
146
+ ) # 文件编码:utf-8、gbk 或自动检测(auto)
147
+ csv_delimiter: str | None = Field(default=None) # CSV 文件列分隔符,如 "," ";" "\t",None 表示使用项目默认配置
148
+
149
+
150
+ class ScriptSecuritySettingsOverride(BaseModel):
151
+ """
152
+ 脚本安全设置覆盖模型
153
+
154
+ 用于在单次校验任务中临时覆盖 project.precis.yaml 中的脚本执行安全策略。
155
+ 涉及 eval/exec 等危险操作的权限控制。
156
+
157
+ Attributes:
158
+ allow_eval: 是否允许执行 eval 表达式
159
+ allow_exec: 是否允许执行 exec 代码块
160
+ sandbox_mode: 是否启用沙箱模式隔离脚本执行环境
161
+ timeout_seconds: 脚本执行超时时间(秒),范围 1-60
162
+ """
163
+
164
+ model_config = ConfigDict(extra="forbid") # 禁止额外字段,防止安全配置被绕过
165
+
166
+ allow_eval: bool | None = Field(default=None) # True 允许在校验中使用 eval 执行动态表达式,存在代码注入风险
167
+ allow_exec: bool | None = Field(default=None) # True 允许在校验中使用 exec 执行代码块,安全风险较高
168
+ sandbox_mode: bool | None = Field(default=None) # True 启用沙箱隔离,限制脚本执行环境访问范围
169
+ timeout_seconds: int | None = Field(
170
+ default=None, ge=1, le=60
171
+ ) # 单个脚本执行的最大允许时间(秒),最小 1 秒,最大 60 秒
172
+
173
+
174
+ class ProjectSettingsOverride(BaseModel):
175
+ """
176
+ 项目设置覆盖模型
177
+
178
+ 作为全量校验时所有配置覆盖项的顶层聚合容器,
179
+ 包含校验设置、文件处理设置和脚本安全设置三个子模块。
180
+
181
+ Attributes:
182
+ validation: 校验执行相关设置的覆盖项
183
+ file_processing: 文件加载与解析相关设置的覆盖项
184
+ script_security: 脚本执行安全策略的覆盖项
185
+ """
186
+
187
+ model_config = ConfigDict(extra="forbid") # 禁止额外字段,保持配置结构清晰
188
+
189
+ validation: ValidationSettingsOverride | None = Field(default=None) # 校验行为设置覆盖,如严格模式、超时等
190
+ file_processing: FileProcessingSettingsOverride | None = Field(default=None) # 文件处理设置覆盖,如编码、分隔符等
191
+ script_security: ScriptSecuritySettingsOverride | None = Field(default=None) # 脚本安全策略覆盖,如 eval/exec 权限
192
+
193
+
194
+ class ValidationTaskTarget(BaseModel):
195
+ """
196
+ 校验任务目标模型
197
+
198
+ 定义单次校验任务的作用范围:全项目、单表或单文件。
199
+ 根据 type 字段的不同,table_id 或 file_path 可能为必填项。
200
+
201
+ Attributes:
202
+ type: 校验目标类型(full_project/single_table/single_file)
203
+ table_id: 单表校验时指定的表 ID(schema 文件中的 id)
204
+ file_path: 单文件校验时指定的数据源文件路径
205
+ display_name: 前端展示用的任务名称(可选,用于任务列表显示)
206
+ """
207
+
208
+ model_config = ConfigDict(extra="forbid") # 禁止额外字段,确保目标定义严格
209
+
210
+ type: Literal["full_project", "single_table", "single_file"] = Field(
211
+ ..., description="校验目标类型"
212
+ ) # 校验范围:全项目、单表、单文件
213
+ table_id: str | None = Field(
214
+ default=None, description="单表校验时的表 ID"
215
+ ) # 当 type 为 single_table 时,指定目标表的 ID
216
+ file_path: str | None = Field(
217
+ default=None, description="单文件校验时的文件路径"
218
+ ) # 当 type 为 single_file 时,指定目标文件路径
219
+ display_name: str | None = Field(default=None, description="前端展示名称") # 任务在前端界面中显示的友好名称,可选
220
+
221
+
222
+ class ValidationTaskRunOptions(BaseModel):
223
+ """
224
+ 校验任务运行选项模型
225
+
226
+ 配置校验任务执行时的运行时参数,如数据目录和配置覆盖。
227
+
228
+ Attributes:
229
+ data_directory: 数据根目录路径(用于解析 relative_file 类型的 source.path)
230
+ override_settings: 可选的项目设置覆盖项
231
+ """
232
+
233
+ model_config = ConfigDict(extra="forbid") # 禁止额外字段,防止传入无效运行参数
234
+
235
+ data_directory: str | None = Field(
236
+ default=None, description="数据目录(用于解析 relative_file source.path)"
237
+ ) # 数据文件根目录,relative_file 类型的数据源路径基于此解析
238
+ override_settings: ProjectSettingsOverride | None = Field(
239
+ default=None,
240
+ description="可选:覆盖 project.precis.yaml 中 settings 的部分字段",
241
+ ) # 临时覆盖项目配置,仅对本次校验任务生效
242
+
243
+
244
+ class ValidationTaskPreflightOptions(BaseModel):
245
+ """
246
+ 校验任务预检选项模型
247
+
248
+ 定义校验任务执行前的预处理策略,如自动保存和未合并资源处理。
249
+
250
+ Attributes:
251
+ save_before_run: 执行校验前是否自动保存当前项目状态
252
+ missing_resources_strategy: 发现未合并资源时的处理策略
253
+ """
254
+
255
+ model_config = ConfigDict(extra="forbid") # 禁止额外字段,保持预检逻辑稳定
256
+
257
+ save_before_run: bool = Field(
258
+ default=True, description="执行前是否自动保存项目"
259
+ ) # True 表示在校验执行前自动保存项目配置,避免丢失未保存的更改
260
+ missing_resources_strategy: Literal["ask", "merge_then_run", "run_directly"] = Field(
261
+ default="ask",
262
+ description="发现未合并资源时的处理策略",
263
+ ) # 未合并资源处理策略:ask(询问用户)、merge_then_run(先合并再执行)、run_directly(直接执行忽略未合并资源)
264
+
265
+
266
+ class ValidationTaskRequest(BaseModel):
267
+ """
268
+ 校验任务请求模型
269
+
270
+ 触发全量或定向校验的完整请求体,聚合目标、运行选项和预检策略。
271
+
272
+ Attributes:
273
+ target: 校验目标定义(范围、具体表/文件)
274
+ run_options: 运行时参数(数据目录、配置覆盖)
275
+ preflight_options: 执行前预处理策略
276
+ """
277
+
278
+ model_config = ConfigDict(extra="forbid") # 禁止额外字段,确保请求结构清晰可控
279
+
280
+ target: ValidationTaskTarget = Field(..., description="校验目标") # 定义本次校验的作用范围和具体对象,必填
281
+ run_options: ValidationTaskRunOptions = Field(
282
+ default_factory=ValidationTaskRunOptions, description="运行参数"
283
+ ) # 校验执行参数,默认使用空选项(全部使用项目默认配置)
284
+ preflight_options: ValidationTaskPreflightOptions = Field(
285
+ default_factory=ValidationTaskPreflightOptions,
286
+ description="运行前策略",
287
+ ) # 校验前预处理策略,默认自动保存项目并在发现未合并资源时询问用户
288
+
289
+
290
+ class FullValidationOptions(BaseModel):
291
+ """
292
+ 全量校验选项模型
293
+
294
+ 配置全量校验的执行参数。
295
+
296
+ Attributes:
297
+ data_directory: 数据目录路径(用于解析相对路径的数据源)
298
+ override_settings: 可选的配置覆盖项
299
+ allow_unsafe_eval: 是否允许执行含 eval 的脚本化约束
300
+ """
301
+
302
+ data_directory: str | None = Field(
303
+ None, description="数据目录(用于解析 relative_file source.path)"
304
+ ) # 数据文件根目录,relative_file 类型的数据源路径基于此解析
305
+ override_settings: ProjectSettingsOverride | None = Field(
306
+ default=None,
307
+ description="可选:覆盖 project.precis.yaml 中 settings 的部分字段(validation/file_processing/script_security)",
308
+ ) # 临时覆盖项目配置,仅对本次全量校验任务生效
309
+ allow_unsafe_eval: bool | None = Field(
310
+ default=None,
311
+ description="是否允许执行含 eval 的脚本化约束;None 表示使用项目默认配置",
312
+ ) # True 允许脚本化约束使用 eval,False 强制禁用,None 遵循项目配置
313
+
314
+
315
+ class FullValidationRequest(BaseModel):
316
+ """
317
+ 全量校验请求模型
318
+
319
+ 触发全量数据校验的请求体。
320
+
321
+ Attributes:
322
+ target: 校验目标(可选,默认 full_project)
323
+ options: 全量校验选项
324
+ """
325
+
326
+ target: ValidationTaskTarget | None = Field(
327
+ default=None, description="校验目标"
328
+ ) # 校验目标定义,None 表示默认校验整个项目
329
+ options: FullValidationOptions | None = Field(
330
+ default=None, description="全量校验选项"
331
+ ) # 校验执行选项,None 表示使用项目默认配置
332
+
333
+
334
+ class FullValidationSummary(BaseModel):
335
+ """
336
+ 全量校验摘要模型
337
+
338
+ 汇总全量校验的统计信息。
339
+
340
+ Attributes:
341
+ files_total: 本次解析涉及的源文件总数
342
+ files_loaded: 成功加载的源文件数量
343
+ tables_loaded: 成功加载的数据表数量
344
+ loading_error_count: 加载阶段错误数量
345
+ format_error_count: 格式校验错误数量
346
+ constraint_error_count: 逻辑约束错误数量
347
+ total_error_count: 总错误数量
348
+ duration_ms: 总耗时(毫秒)
349
+ """
350
+
351
+ files_total: int = Field(
352
+ ..., description="本次解析涉及的源文件数量"
353
+ ) # 校验过程中扫描到的所有源文件总数(含成功和失败)
354
+ files_loaded: int = Field(..., description="成功加载的源文件数量") # 成功读取并解析的源文件数量
355
+ tables_loaded: int = Field(
356
+ ..., description="成功加载的数据表数量"
357
+ ) # 成功构建为内部数据表的 Schema 数量(一个文件可能对应多个表)
358
+ loading_error_count: int = Field(
359
+ ..., description="加载阶段错误数量(缺文件/格式不支持/读取失败等)"
360
+ ) # 数据加载阶段发生的错误数,如文件缺失、格式不支持、读取权限不足等
361
+ format_error_count: int = Field(
362
+ ..., description="格式校验错误数量(缺列/类型不匹配等)"
363
+ ) # 数据格式校验阶段发现的错误数,如缺少必需列、数据类型不匹配等
364
+ constraint_error_count: int = Field(
365
+ ..., description="逻辑约束错误数量(非空/唯一/外键等)"
366
+ ) # 逻辑约束校验阶段发现的错误数,如非空违反、唯一性冲突、外键引用无效等
367
+ total_error_count: int = Field(
368
+ ..., description="总错误数量"
369
+ ) # 所有阶段错误数量的总和(loading + format + constraint)
370
+ duration_ms: int = Field(..., description="总耗时(毫秒)") # 从校验开始到完成的总耗时,单位为毫秒
371
+ errors_truncated: bool = Field(
372
+ default=False, description="错误列表是否被截断"
373
+ ) # 回归 #10: 当真实错误数超过响应上限时为 True,errors 只含截断后的子集,
374
+ # 但 total_error_count 保留真实总数,供前端显示"显示 X/Y 条"。
375
+ interrupted: bool = Field(
376
+ default=False, description="校验是否因遇错即停(error_handling=stop)而提前终止"
377
+ ) # C6: True 表示校验在发现首个错误后即停止,剩余检查未执行(快速失败)。
378
+ timed_out: bool = Field(
379
+ default=False, description="校验是否因超时而提前终止"
380
+ ) # D6: True 表示校验因超过 timeout_seconds 而中断(约束之间或约束内部超时)。
381
+
382
+ @computed_field
383
+ def error_count(self) -> int:
384
+ """总错误数量(兼容旧 API 字段名)。"""
385
+ return self.total_error_count
386
+
387
+
388
+ class FullValidationErrorItem(BaseModel):
389
+ """
390
+ 全量校验错误项模型
391
+
392
+ 记录全量校验中发现的单个错误详情。
393
+
394
+ Attributes:
395
+ stage: 错误发生阶段(preflight/loading/format/constraint)
396
+ error_type: 错误类型标识
397
+ check_type: 检查类型标识(可选)
398
+ message: 错误说明文本
399
+ table: 表名(运行时名称,可选)
400
+ table_id: 表 ID(schema 文件中的 ID,可选)
401
+ column: 列名(可选)
402
+ column_id: 列 ID(可选)
403
+ row_index: 行索引(从 0 开始,可选)
404
+ value: 相关值(可选)
405
+ source_path: 相关源文件路径(可选)
406
+ """
407
+
408
+ stage: str = Field(
409
+ ..., description="错误阶段:preflight|loading|format|constraint"
410
+ ) # 错误发生的阶段:preflight(预检)、loading(加载)、format(格式)、constraint(约束)
411
+ error_type: str = Field(
412
+ ..., description="错误类型"
413
+ ) # 错误的具体类型标识,如 FileNotFound、MissingColumn、NotNullViolation 等
414
+ check_type: str | None = Field(
415
+ default=None, description="检查类型"
416
+ ) # 触发错误的检查类型,如 NotNull、Unique、Range 等,预检/加载阶段可能为空
417
+ message: str = Field(..., description="错误说明") # 面向用户的错误描述文本,说明错误原因和影响
418
+ table: str | None = Field(
419
+ default=None, description="表名(运行时 name)"
420
+ ) # 错误关联的数据表运行时名称(解析后的名称),可选
421
+ table_id: str | None = Field(
422
+ default=None, description="表 ID(schema 文件中的 id)"
423
+ ) # 错误关联的数据表在 schema 配置文件中的原始 ID,可选
424
+ column: str | None = Field(default=None, description="列名") # 错误关联的数据列运行时名称,可选
425
+ column_id: str | None = Field(
426
+ default=None, description="列 ID"
427
+ ) # 错误关联的数据列在 schema 配置文件中的原始 ID,可选
428
+ row_index: int | None = Field(
429
+ default=None, description="行索引(从0开始)"
430
+ ) # 错误发生的行索引(数据行,从 0 开始计数),可选
431
+ value: str | None = Field(default=None, description="相关值(可选)") # 触发错误的单元格原始值或相关数据,可选
432
+ source_path: str | None = Field(
433
+ default=None, description="相关源文件路径(可选)"
434
+ ) # 错误关联的源数据文件绝对路径,可选
435
+ source_file: str | None = Field(
436
+ default=None, description="配置文件内定义的数据源文件名(可选)"
437
+ ) # schema 配置中 source.path 定义的原始文件名,可选
438
+ source_sheet: str | None = Field(
439
+ default=None, description="配置文件内定义的 Excel Sheet 名(可选)"
440
+ ) # schema 配置中 source.sheet 定义的 Excel 工作表名称,可选
441
+
442
+
443
+ class ValidationPassedItem(BaseModel):
444
+ """
445
+ 校验通过项模型
446
+
447
+ 记录全量校验中通过的检查项详情。
448
+
449
+ Attributes:
450
+ stage: 检查阶段(loading/format/constraint/regex)
451
+ check_type: 检查类型(如:NotNull, Unique, AllowedValues, Regex等)
452
+ message: 通过说明文本
453
+ table: 表名(运行时名称)
454
+ table_id: 表 ID(schema 文件中的 ID)
455
+ column: 列名
456
+ column_id: 列 ID
457
+ source_path: 相关源文件路径(可选)
458
+ """
459
+
460
+ stage: str = Field(
461
+ ..., description="检查阶段:loading|format|constraint|regex"
462
+ ) # 检查通过的阶段:loading(加载)、format(格式)、constraint(约束)、regex(正则)
463
+ check_type: str = Field(
464
+ ..., description="检查类型"
465
+ ) # 通过检查的类型标识,如 NotNull、Unique、AllowedValues、Regex 等
466
+ message: str = Field(..., description="通过说明") # 面向用户的通过说明文本,描述检查内容和结果
467
+ table: str | None = Field(default=None, description="表名(运行时 name)") # 通过检查关联的数据表运行时名称,可选
468
+ table_id: str | None = Field(
469
+ default=None, description="表 ID(schema 文件中的 id)"
470
+ ) # 通过检查关联的数据表在 schema 配置文件中的原始 ID,可选
471
+ column: str | None = Field(default=None, description="列名") # 通过检查关联的数据列运行时名称,可选
472
+ column_id: str | None = Field(
473
+ default=None, description="列 ID"
474
+ ) # 通过检查关联的数据列在 schema 配置文件中的原始 ID,可选
475
+ source_path: str | None = Field(
476
+ default=None, description="相关源文件路径(可选)"
477
+ ) # 通过检查关联的源数据文件绝对路径,可选
478
+ source_file: str | None = Field(
479
+ default=None, description="配置文件内定义的数据源文件名(可选)"
480
+ ) # schema 配置中 source.path 定义的原始文件名,可选
481
+ source_sheet: str | None = Field(
482
+ default=None, description="配置文件内定义的 Excel Sheet 名(可选)"
483
+ ) # schema 配置中 source.sheet 定义的 Excel 工作表名称,可选
484
+
485
+
486
+ class ValidationStatistics(BaseModel):
487
+ """
488
+ 校验统计信息模型
489
+
490
+ 汇总全量校验的详细统计信息。
491
+
492
+ Attributes:
493
+ total_checks: 总检查项数
494
+ passed_count: 通过数量
495
+ failed_count: 失败数量
496
+ pass_rate: 通过率(百分比)
497
+ by_type: 按类型统计(约束/正则/类型等)
498
+ by_table: 按表统计
499
+ """
500
+
501
+ total_checks: int = Field(..., description="总检查项数") # 本次校验执行的所有检查项总数(含通过和失败)
502
+ passed_count: int = Field(..., description="通过数量") # 所有检查项中校验通过的数量
503
+ failed_count: int = Field(..., description="失败数量") # 所有检查项中校验失败的数量
504
+ pass_rate: float = Field(
505
+ ..., description="通过率(百分比,0-100)"
506
+ ) # 通过率百分比,计算公式:(passed_count / total_checks) * 100,范围 0-100
507
+ by_type: dict[str, dict[str, int]] = Field(
508
+ default_factory=dict, description="按类型统计,如:{'constraint': {'total': 10, 'passed': 8, 'failed': 2}}"
509
+ ) # 按检查类型分组的统计信息,外层 key 为类型(constraint/regex/format),内层包含 total/passed/failed 计数
510
+ by_table: dict[str, dict[str, int]] = Field(
511
+ default_factory=dict, description="按表统计,如:{'users': {'total': 5, 'passed': 4, 'failed': 1}}"
512
+ ) # 按数据表分组的统计信息,外层 key 为表名,内层包含 total/passed/failed 计数
513
+
514
+
515
+ class FullValidationResponse(BaseModel):
516
+ """
517
+ 全量校验响应模型
518
+
519
+ 全量校验接口的标准响应格式。
520
+
521
+ Attributes:
522
+ success: 请求是否成功
523
+ summary: 摘要统计信息
524
+ errors: 错误明细列表
525
+ passed_items: 通过项列表
526
+ statistics: 详细统计信息
527
+ error: 致命错误信息(可选)
528
+ warnings: 警告信息列表(可选)
529
+ """
530
+
531
+ success: bool = Field(
532
+ ..., description="请求是否成功"
533
+ ) # True 表示校验任务成功完成(可能包含错误项),False 表示任务执行失败(如配置错误、异常中断)
534
+ summary: FullValidationSummary = Field(
535
+ ..., description="摘要统计"
536
+ ) # 校验结果的摘要统计信息,包含文件数、错误数、耗时等核心指标
537
+ errors: list[FullValidationErrorItem] = Field(
538
+ default_factory=list, description="错误明细列表"
539
+ ) # 校验过程中发现的所有错误明细列表,按阶段分类
540
+ passed_items: list[ValidationPassedItem] = Field(
541
+ default_factory=list, description="通过项列表"
542
+ ) # 校验通过的所有检查项明细列表,用于展示完整校验覆盖情况
543
+ statistics: ValidationStatistics | None = Field(
544
+ default=None, description="详细统计信息"
545
+ ) # 校验的详细统计信息,包含按类型和按表的分组统计,可选
546
+ error: str | None = Field(
547
+ default=None, description="致命错误信息(可选)"
548
+ ) # 当 success 为 False 时的致命错误描述,如任务启动失败、配置解析异常等
549
+ warnings: list[str] = Field(
550
+ default_factory=list, description="警告信息列表(可选)"
551
+ ) # 校验过程中的非致命警告信息列表,如建议优化项、已自动修复的问题等
552
+ coverage: ValidationCoverage | None = Field(
553
+ default=None, description="清单一致性覆盖信息(可选)"
554
+ ) # 项目清单与磁盘文件的一致性检查结果,可选