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.
- app/__init__.py +16 -0
- app/api/__init__.py +32 -0
- app/api/dependencies.py +185 -0
- app/api/main.py +301 -0
- app/api/middleware/__init__.py +34 -0
- app/api/middleware/exception_handler.py +126 -0
- app/api/middleware/request_logging.py +97 -0
- app/api/middleware/token_auth.py +215 -0
- app/api/models/__init__.py +151 -0
- app/api/models/connection_rules.py +98 -0
- app/api/models/files.py +99 -0
- app/api/models/full_validation.py +554 -0
- app/api/models/project.py +117 -0
- app/api/models/projects.py +80 -0
- app/api/models/schema.py +121 -0
- app/api/models/v2_responses.py +46 -0
- app/api/models/validation.py +303 -0
- app/api/models/workspace.py +118 -0
- app/api/routers/__init__.py +56 -0
- app/api/routers/ai/__init__.py +36 -0
- app/api/routers/ai/chat.py +243 -0
- app/api/routers/ai/generate.py +156 -0
- app/api/routers/ai/hardware.py +199 -0
- app/api/routers/ai/jobs.py +544 -0
- app/api/routers/ai/migrate.py +471 -0
- app/api/routers/ai/models.py +352 -0
- app/api/routers/ai/ollama.py +108 -0
- app/api/routers/ai/providers.py +491 -0
- app/api/routers/ai/router.py +44 -0
- app/api/routers/ai/stream.py +281 -0
- app/api/routers/ai/utils.py +182 -0
- app/api/routers/core/__init__.py +34 -0
- app/api/routers/core/connection_rules.py +188 -0
- app/api/routers/core/data_sources.py +374 -0
- app/api/routers/core/regex.py +333 -0
- app/api/routers/core/reporting.py +263 -0
- app/api/routers/files/__init__.py +24 -0
- app/api/routers/files/ops.py +179 -0
- app/api/routers/files/transfer.py +101 -0
- app/api/routers/preview/__init__.py +35 -0
- app/api/routers/preview/content_mode.py +264 -0
- app/api/routers/preview/header_row.py +154 -0
- app/api/routers/preview/models.py +81 -0
- app/api/routers/preview/path_mode.py +440 -0
- app/api/routers/preview/router.py +30 -0
- app/api/routers/project/__init__.py +61 -0
- app/api/routers/project/base.py +111 -0
- app/api/routers/project/constraint.py +345 -0
- app/api/routers/project/full_config.py +411 -0
- app/api/routers/project/full_config_writer.py +327 -0
- app/api/routers/project/helpers.py +167 -0
- app/api/routers/project/inspection_fix.py +330 -0
- app/api/routers/project/manifest.py +605 -0
- app/api/routers/project/models.py +177 -0
- app/api/routers/project/pattern.py +268 -0
- app/api/routers/project/regex.py +358 -0
- app/api/routers/project/scanner.py +157 -0
- app/api/routers/project/schema.py +567 -0
- app/api/routers/project/schema_helpers.py +149 -0
- app/api/routers/project/settings.py +399 -0
- app/api/routers/project/template.py +325 -0
- app/api/routers/project/validation.py +227 -0
- app/api/routers/project/view.py +177 -0
- app/api/routers/project/workspaces.py +167 -0
- app/api/routers/projects/__init__.py +25 -0
- app/api/routers/projects/create.py +121 -0
- app/api/routers/projects/open.py +103 -0
- app/api/routers/projects/scan.py +100 -0
- app/api/routers/validation/__init__.py +39 -0
- app/api/routers/validation/common.py +263 -0
- app/api/routers/validation/content_mode.py +401 -0
- app/api/routers/validation/history.py +235 -0
- app/api/routers/validation/inline_mode.py +196 -0
- app/api/routers/validation/path_mode.py +314 -0
- app/api/routers/validation/router.py +51 -0
- app/api/services/full_validation_response_builder.py +412 -0
- app/api/services/io_error_messages.py +41 -0
- app/api/services/preview_service.py +248 -0
- app/cli/__init__.py +18 -0
- app/cli/__main__.py +30 -0
- app/cli/shared_services/__init__.py +42 -0
- app/cli/shared_services/config_ops.py +581 -0
- app/cli/shared_services/generation_ops.py +160 -0
- app/cli/shared_services/project_ops.py +288 -0
- app/cli/shell/__init__.py +48 -0
- app/cli/shell/commands/__init__.py +63 -0
- app/cli/shell/commands/ai/__init__.py +260 -0
- app/cli/shell/commands/ai/chat.py +331 -0
- app/cli/shell/commands/ai/delete.py +165 -0
- app/cli/shell/commands/ai/diff.py +70 -0
- app/cli/shell/commands/ai/display.py +428 -0
- app/cli/shell/commands/ai/executor.py +225 -0
- app/cli/shell/commands/ai/executor_utils.py +271 -0
- app/cli/shell/commands/ai/generate.py +285 -0
- app/cli/shell/commands/ai/interaction.py +262 -0
- app/cli/shell/commands/ai/migrate.py +281 -0
- app/cli/shell/commands/ai/resolver.py +224 -0
- app/cli/shell/commands/ai/status.py +101 -0
- app/cli/shell/commands/ai/switch.py +158 -0
- app/cli/shell/commands/ai/utils.py +52 -0
- app/cli/shell/commands/base.py +343 -0
- app/cli/shell/commands/config/__init__.py +131 -0
- app/cli/shell/commands/config/base.py +80 -0
- app/cli/shell/commands/config/check.py +246 -0
- app/cli/shell/commands/config/edit.py +148 -0
- app/cli/shell/commands/config/get.py +111 -0
- app/cli/shell/commands/config/init.py +123 -0
- app/cli/shell/commands/config/inspect.py +164 -0
- app/cli/shell/commands/config/list.py +104 -0
- app/cli/shell/commands/config/set.py +119 -0
- app/cli/shell/commands/config/show.py +150 -0
- app/cli/shell/commands/exit.py +67 -0
- app/cli/shell/commands/help.py +104 -0
- app/cli/shell/commands/infer_schema.py +156 -0
- app/cli/shell/commands/open.py +201 -0
- app/cli/shell/commands/project.py +215 -0
- app/cli/shell/commands/provider.py +619 -0
- app/cli/shell/commands/system.py +170 -0
- app/cli/shell/commands/validate.py +455 -0
- app/cli/shell/completer.py +231 -0
- app/cli/shell/config_storage.py +191 -0
- app/cli/shell/exceptions.py +90 -0
- app/cli/shell/formatter.py +371 -0
- app/cli/shell/interactive_menu.py +348 -0
- app/cli/shell/main.py +286 -0
- app/cli/shell/parser.py +266 -0
- app/cli/start.py +180 -0
- app/cli_main.py +52 -0
- app/mcp_server.py +311 -0
- app/shared/core/__init__.py +18 -0
- app/shared/core/app_version.py +59 -0
- app/shared/core/config/__init__.py +119 -0
- app/shared/core/config/server.py +193 -0
- app/shared/core/data_source/__init__.py +106 -0
- app/shared/core/data_source/loader.py +348 -0
- app/shared/core/data_source/loaders/__init__.py +213 -0
- app/shared/core/data_source/loaders/base.py +215 -0
- app/shared/core/data_source/loaders/converter.py +337 -0
- app/shared/core/data_source/loaders/csv_loader.py +252 -0
- app/shared/core/data_source/loaders/excel_loader.py +666 -0
- app/shared/core/data_source/loaders/extractor.py +268 -0
- app/shared/core/data_source/loaders/json_loader.py +354 -0
- app/shared/core/data_source/loaders/registry.py +88 -0
- app/shared/core/data_source/loaders/sql_loader.py +313 -0
- app/shared/core/data_source/loaders/strategies/__init__.py +100 -0
- app/shared/core/data_source/loaders/strategies/array_parser.py +277 -0
- app/shared/core/data_source/loaders/strategies/lines_parser.py +355 -0
- app/shared/core/data_source/loaders/strategies/object_parser.py +278 -0
- app/shared/core/data_source/schema_info.py +50 -0
- app/shared/core/data_source/specs/__init__.py +128 -0
- app/shared/core/data_source/specs/base.py +258 -0
- app/shared/core/data_source/specs/csv_source.py +137 -0
- app/shared/core/data_source/specs/excel_source.py +141 -0
- app/shared/core/data_source/specs/file_base.py +252 -0
- app/shared/core/data_source/specs/json_source.py +226 -0
- app/shared/core/data_source/specs/sql_source.py +161 -0
- app/shared/core/encoding.py +36 -0
- app/shared/core/io/__init__.py +24 -0
- app/shared/core/io/yaml.py +379 -0
- app/shared/core/manifest_schema/__init__.py +52 -0
- app/shared/core/manifest_schema/types.py +99 -0
- app/shared/core/manifest_schema/version.py +175 -0
- app/shared/core/patterns/__init__.py +24 -0
- app/shared/core/patterns/loader.py +134 -0
- app/shared/core/patterns/writer.py +244 -0
- app/shared/core/project/__init__.py +47 -0
- app/shared/core/project/constraint/builders/__init__.py +50 -0
- app/shared/core/project/constraint/builders/base.py +100 -0
- app/shared/core/project/constraint/builders/composite.py +77 -0
- app/shared/core/project/constraint/builders/conditional.py +67 -0
- app/shared/core/project/constraint/builders/foreign_key.py +53 -0
- app/shared/core/project/constraint/builders/registry.py +64 -0
- app/shared/core/project/constraint/builders/scripted.py +51 -0
- app/shared/core/project/constraint/builders/single_column.py +86 -0
- app/shared/core/project/constraint/builders/unique.py +53 -0
- app/shared/core/project/constraint/factory.py +170 -0
- app/shared/core/project/constraint/reader.py +214 -0
- app/shared/core/project/constraint/registry.py +233 -0
- app/shared/core/project/constraint/types/__init__.py +63 -0
- app/shared/core/project/constraint/types/constraint_file.py +261 -0
- app/shared/core/project/constraint/types/refs.py +460 -0
- app/shared/core/project/constraint/types.py +28 -0
- app/shared/core/project/constraint/writer.py +181 -0
- app/shared/core/project/loader/__init__.py +56 -0
- app/shared/core/project/loader/loader.py +30 -0
- app/shared/core/project/loader/loader_parts/config_inspector.py +137 -0
- app/shared/core/project/loader/loader_parts/embedded_constraints.py +224 -0
- app/shared/core/project/loader/loader_parts/file_loaders.py +58 -0
- app/shared/core/project/loader/loader_parts/inspection_ids.py +85 -0
- app/shared/core/project/loader/loader_parts/inspector_helpers.py +312 -0
- app/shared/core/project/loader/loader_parts/inspector_id_checks.py +274 -0
- app/shared/core/project/loader/loader_parts/inspector_reference_checks.py +690 -0
- app/shared/core/project/loader/loader_parts/inspector_uniqueness_checks.py +286 -0
- app/shared/core/project/loader/loader_parts/loading_error_messages.py +298 -0
- app/shared/core/project/loader/loader_parts/main.py +432 -0
- app/shared/core/project/loader/loader_parts/path_validation.py +117 -0
- app/shared/core/project/loader/loader_parts/runtime.py +125 -0
- app/shared/core/project/loader/types.py +246 -0
- app/shared/core/project/manifest/coverage.py +391 -0
- app/shared/core/project/manifest/reader.py +260 -0
- app/shared/core/project/manifest/types.py +91 -0
- app/shared/core/project/manifest/types_parts/__init__.py +60 -0
- app/shared/core/project/manifest/types_parts/constants.py +40 -0
- app/shared/core/project/manifest/types_parts/data_source.py +68 -0
- app/shared/core/project/manifest/types_parts/info.py +59 -0
- app/shared/core/project/manifest/types_parts/manifest.py +294 -0
- app/shared/core/project/manifest/types_parts/refs.py +153 -0
- app/shared/core/project/manifest/types_parts/settings.py +92 -0
- app/shared/core/project/manifest/types_parts/settings_file_processing.py +64 -0
- app/shared/core/project/manifest/types_parts/settings_script_security.py +78 -0
- app/shared/core/project/manifest/types_parts/settings_validation.py +83 -0
- app/shared/core/project/manifest/types_parts/template.py +66 -0
- app/shared/core/project/manifest/writer.py +262 -0
- app/shared/core/project/manual_data/__init__.py +27 -0
- app/shared/core/project/manual_data/types.py +75 -0
- app/shared/core/project/regex/reader.py +197 -0
- app/shared/core/project/regex/types.py +405 -0
- app/shared/core/project/regex/writer.py +123 -0
- app/shared/core/project/schema/reader.py +170 -0
- app/shared/core/project/schema/types.py +47 -0
- app/shared/core/project/schema/types_parts/__init__.py +36 -0
- app/shared/core/project/schema/types_parts/column.py +174 -0
- app/shared/core/project/schema/types_parts/column_utils.py +72 -0
- app/shared/core/project/schema/types_parts/constraint.py +165 -0
- app/shared/core/project/schema/types_parts/schema_id.py +66 -0
- app/shared/core/project/schema/types_parts/source.py +255 -0
- app/shared/core/project/schema/types_parts/source_options.py +347 -0
- app/shared/core/project/schema/types_parts/table.py +230 -0
- app/shared/core/project/schema/writer.py +139 -0
- app/shared/core/project/schema_ref_check.py +95 -0
- app/shared/core/project/template/__init__.py +27 -0
- app/shared/core/project/template/expander.py +263 -0
- app/shared/core/project/template/reader.py +120 -0
- app/shared/core/project/template/types.py +114 -0
- app/shared/core/project/transform/reader.py +76 -0
- app/shared/core/project/transform/types.py +116 -0
- app/shared/core/project/transform/writer.py +84 -0
- app/shared/core/pydantic_messages.py +59 -0
- app/shared/core/reporter/__init__.py +46 -0
- app/shared/core/reporter/reporter.py +220 -0
- app/shared/core/reporter/reporters/__init__.py +65 -0
- app/shared/core/reporter/reporters/base.py +188 -0
- app/shared/core/reporter/reporters/dingtalk_app_reporter.py +274 -0
- app/shared/core/reporter/reporters/email_reporter.py +271 -0
- app/shared/core/reporter/reporters/feishu_app_reporter.py +467 -0
- app/shared/core/reporter/reporters/local_file_reporter.py +208 -0
- app/shared/core/reporter/reporters/wecom_app_reporter.py +268 -0
- app/shared/core/utils/__init__.py +18 -0
- app/shared/core/utils/path_utils.py +60 -0
- app/shared/core/utils/regex_extract.py +113 -0
- app/shared/domain/__init__.py +114 -0
- app/shared/domain/constraints/__init__.py +76 -0
- app/shared/domain/constraints/allowed_values.py +211 -0
- app/shared/domain/constraints/base.py +141 -0
- app/shared/domain/constraints/charset.py +337 -0
- app/shared/domain/constraints/composite.py +174 -0
- app/shared/domain/constraints/condition_registry.py +130 -0
- app/shared/domain/constraints/conditional.py +629 -0
- app/shared/domain/constraints/date_logic.py +731 -0
- app/shared/domain/constraints/foreign_key.py +261 -0
- app/shared/domain/constraints/key_normalization.py +56 -0
- app/shared/domain/constraints/not_null.py +185 -0
- app/shared/domain/constraints/range.py +360 -0
- app/shared/domain/constraints/regex.py +218 -0
- app/shared/domain/constraints/scripted.py +276 -0
- app/shared/domain/constraints/unique.py +233 -0
- app/shared/domain/data_engine.py +384 -0
- app/shared/domain/data_types.py +113 -0
- app/shared/domain/data_types_parts/__init__.py +67 -0
- app/shared/domain/data_types_parts/base.py +204 -0
- app/shared/domain/data_types_parts/composite.py +250 -0
- app/shared/domain/data_types_parts/expression.py +202 -0
- app/shared/domain/data_types_parts/extracted.py +106 -0
- app/shared/domain/data_types_parts/json_types.py +234 -0
- app/shared/domain/data_types_parts/scalars.py +719 -0
- app/shared/domain/data_types_parts/sequence.py +129 -0
- app/shared/domain/dataset_schema.py +48 -0
- app/shared/domain/eval_sandbox.py +63 -0
- app/shared/domain/expression_system.py +366 -0
- app/shared/domain/regex_flags.py +53 -0
- app/shared/domain/schema/builder.py +223 -0
- app/shared/domain/schema/models.py +339 -0
- app/shared/domain/transforms/__init__.py +28 -0
- app/shared/domain/transforms/aggregate.py +141 -0
- app/shared/domain/transforms/base.py +171 -0
- app/shared/domain/transforms/cast_type.py +120 -0
- app/shared/domain/transforms/concat.py +103 -0
- app/shared/domain/transforms/conditional_assign.py +114 -0
- app/shared/domain/transforms/date_format.py +81 -0
- app/shared/domain/transforms/digits.py +77 -0
- app/shared/domain/transforms/drop_duplicates.py +94 -0
- app/shared/domain/transforms/fill_na.py +94 -0
- app/shared/domain/transforms/filter_rows.py +97 -0
- app/shared/domain/transforms/lookup.py +78 -0
- app/shared/domain/transforms/lower_case.py +70 -0
- app/shared/domain/transforms/map_value.py +90 -0
- app/shared/domain/transforms/math_expr.py +112 -0
- app/shared/domain/transforms/modulo.py +82 -0
- app/shared/domain/transforms/regex_extract.py +103 -0
- app/shared/domain/transforms/registry.py +95 -0
- app/shared/domain/transforms/replace.py +88 -0
- app/shared/domain/transforms/sort_rows.py +94 -0
- app/shared/domain/transforms/string_split.py +84 -0
- app/shared/domain/transforms/strip.py +73 -0
- app/shared/domain/transforms/substring.py +92 -0
- app/shared/domain/transforms/upper_case.py +70 -0
- app/shared/domain/transforms/weighted_sum.py +104 -0
- app/shared/domain/validation_constraints.py +69 -0
- app/shared/services/__init__.py +62 -0
- app/shared/services/ai/__init__.py +48 -0
- app/shared/services/ai/agent/__init__.py +40 -0
- app/shared/services/ai/agent/chat_tools/__init__.py +47 -0
- app/shared/services/ai/agent/chat_tools/apply_actions.py +592 -0
- app/shared/services/ai/agent/chat_tools/ask_user.py +237 -0
- app/shared/services/ai/agent/chat_tools/read_canvas.py +140 -0
- app/shared/services/ai/agent/chat_tools/read_project.py +160 -0
- app/shared/services/ai/agent/chat_tools/read_table.py +301 -0
- app/shared/services/ai/agent/chat_tools/schemas.py +105 -0
- app/shared/services/ai/agent/chat_tools/validate_table.py +131 -0
- app/shared/services/ai/agent/executor.py +554 -0
- app/shared/services/ai/agent/memory.py +256 -0
- app/shared/services/ai/agent/planner.py +282 -0
- app/shared/services/ai/agent/tool_registry.py +296 -0
- app/shared/services/ai/agent/tools/__init__.py +32 -0
- app/shared/services/ai/agent/tools/config_generate.py +133 -0
- app/shared/services/ai/agent/tools/config_refine.py +109 -0
- app/shared/services/ai/agent/tools/config_validate.py +403 -0
- app/shared/services/ai/agent/tools/merge_results.py +136 -0
- app/shared/services/ai/agent/tools/plan_chunks.py +79 -0
- app/shared/services/ai/agent/tools/script_parse.py +359 -0
- app/shared/services/ai/agent/types.py +138 -0
- app/shared/services/ai/chat_agent_runner.py +596 -0
- app/shared/services/ai/chat_orchestrator.py +725 -0
- app/shared/services/ai/failure_messages.py +65 -0
- app/shared/services/ai/job_storage.py +274 -0
- app/shared/services/ai/migrate_service.py +550 -0
- app/shared/services/ai/streaming/__init__.py +65 -0
- app/shared/services/ai/streaming/event_journal.py +197 -0
- app/shared/services/ai/streaming/orchestrator.py +262 -0
- app/shared/services/ai/streaming/pending_interaction_store.py +227 -0
- app/shared/services/ai/streaming/sse_response.py +148 -0
- app/shared/services/ai/streaming/types.py +73 -0
- app/shared/services/ai/types.py +213 -0
- app/shared/services/ai/utils.py +322 -0
- app/shared/services/diff/config_diff.py +320 -0
- app/shared/services/hardware.py +237 -0
- app/shared/services/llm/__init__.py +62 -0
- app/shared/services/llm/actions/__init__.py +42 -0
- app/shared/services/llm/actions/_canvas_validator.py +147 -0
- app/shared/services/llm/actions/_constraint_validator.py +401 -0
- app/shared/services/llm/actions/_regex_validator.py +85 -0
- app/shared/services/llm/actions/_schema_validator.py +82 -0
- app/shared/services/llm/actions/_settings_validator.py +76 -0
- app/shared/services/llm/actions/_transform_validator.py +78 -0
- app/shared/services/llm/actions/action_handlers.py +400 -0
- app/shared/services/llm/actions/action_parser.py +63 -0
- app/shared/services/llm/actions/action_processor.py +468 -0
- app/shared/services/llm/actions/action_validator.py +311 -0
- app/shared/services/llm/actions/diff_compute.py +195 -0
- app/shared/services/llm/actions/regex_handlers.py +284 -0
- app/shared/services/llm/actions/registry.py +336 -0
- app/shared/services/llm/actions/schema_handlers.py +335 -0
- app/shared/services/llm/actions/settings_handlers.py +180 -0
- app/shared/services/llm/actions/specs.py +259 -0
- app/shared/services/llm/actions/transform_handlers.py +279 -0
- app/shared/services/llm/actions/validation_types.py +147 -0
- app/shared/services/llm/cache/__init__.py +18 -0
- app/shared/services/llm/cache/response_cache.py +80 -0
- app/shared/services/llm/chat/__init__.py +35 -0
- app/shared/services/llm/chat/chat_system_prompt.py +561 -0
- app/shared/services/llm/chat/response_parser.py +296 -0
- app/shared/services/llm/config/__init__.py +45 -0
- app/shared/services/llm/config/crypto.py +135 -0
- app/shared/services/llm/config/loader.py +258 -0
- app/shared/services/llm/config/models.py +202 -0
- app/shared/services/llm/config/presets.py +128 -0
- app/shared/services/llm/config_generator.py +163 -0
- app/shared/services/llm/constraints/__init__.py +41 -0
- app/shared/services/llm/constraints/constraint_builder.py +177 -0
- app/shared/services/llm/constraints/constraint_deletion.py +84 -0
- app/shared/services/llm/constraints/constraint_id.py +174 -0
- app/shared/services/llm/constraints/frontend_instructions.py +333 -0
- app/shared/services/llm/constraints/inline_batch.py +279 -0
- app/shared/services/llm/discovery/__init__.py +35 -0
- app/shared/services/llm/discovery/scanner.py +181 -0
- app/shared/services/llm/generation/__init__.py +42 -0
- app/shared/services/llm/generation/agent_wiring.py +156 -0
- app/shared/services/llm/generation/config_builder.py +386 -0
- app/shared/services/llm/generation/errors.py +36 -0
- app/shared/services/llm/generation/existing_config.py +99 -0
- app/shared/services/llm/generation/profiler.py +279 -0
- app/shared/services/llm/generation/prompt_builder.py +199 -0
- app/shared/services/llm/generation/response_parser.py +144 -0
- app/shared/services/llm/generation/service.py +622 -0
- app/shared/services/llm/models.py +104 -0
- app/shared/services/llm/providers/__init__.py +48 -0
- app/shared/services/llm/providers/base.py +310 -0
- app/shared/services/llm/providers/cached_provider.py +90 -0
- app/shared/services/llm/providers/ollama.py +498 -0
- app/shared/services/llm/providers/openai.py +334 -0
- app/shared/services/llm/providers/registry.py +108 -0
- app/shared/services/llm/schema_resolver.py +141 -0
- app/shared/services/llm/suggestion_utils.py +219 -0
- app/shared/services/llm/validate_executor.py +163 -0
- app/shared/services/llm/yaml_io.py +406 -0
- app/shared/services/preview/__init__.py +18 -0
- app/shared/services/preview/loader.py +145 -0
- app/shared/services/preview/path_validation.py +138 -0
- app/shared/services/project_loader.py +57 -0
- app/shared/services/schema_inference.py +260 -0
- app/shared/services/schema_runtime_builder.py +120 -0
- app/shared/services/validation/__init__.py +52 -0
- app/shared/services/validation/chunked_loader.py +509 -0
- app/shared/services/validation/dag/__init__.py +35 -0
- app/shared/services/validation/dag/builder.py +141 -0
- app/shared/services/validation/dag/executor.py +225 -0
- app/shared/services/validation/dag/sorter.py +77 -0
- app/shared/services/validation/data_loader.py +231 -0
- app/shared/services/validation/engine.py +446 -0
- app/shared/services/validation/executor.py +1030 -0
- app/shared/services/validation/extractors.py +266 -0
- app/shared/services/validation/history.py +209 -0
- app/shared/services/validation/json_payload.py +136 -0
- app/shared/services/validation/loader.py +152 -0
- app/shared/services/validation/memory_monitor.py +179 -0
- app/shared/services/validation/postprocess.py +208 -0
- app/shared/services/validation/progress.py +64 -0
- app/shared/services/validation/report_export.py +222 -0
- app/shared/services/validation/resolver.py +180 -0
- app/shared/services/validation/service.py +418 -0
- app/shared/services/validation/types.py +238 -0
- app/shared/services/validation/validators/__init__.py +36 -0
- app/shared/services/validation/validators/adapter.py +182 -0
- app/shared/services/validation/validators/base.py +332 -0
- app/shared/services/validation/validators/composite.py +233 -0
- app/shared/services/validation/validators/date_logic.py +276 -0
- app/start_server.py +133 -0
- precis_cli-0.1.3.dist-info/METADATA +180 -0
- precis_cli-0.1.3.dist-info/RECORD +442 -0
- precis_cli-0.1.3.dist-info/WHEEL +5 -0
- precis_cli-0.1.3.dist-info/entry_points.txt +4 -0
- precis_cli-0.1.3.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,114 @@
|
|
|
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 模板数据模型定义
|
|
18
|
+
|
|
19
|
+
功能概述:
|
|
20
|
+
- 定义模板内部节点 (TemplateNode)
|
|
21
|
+
- 定义模板文件根模型 (TemplateFile)
|
|
22
|
+
|
|
23
|
+
架构设计:
|
|
24
|
+
- TemplateFile 是 *.template.yaml 文件解析后的根 Pydantic 模型
|
|
25
|
+
- 模板内节点 ID 为局部命名空间,展开时映射为全局 ID
|
|
26
|
+
- 模板节点存完整默认值,无参数占位符替换机制
|
|
27
|
+
- 展开后用户直接在画布上编辑内部节点
|
|
28
|
+
|
|
29
|
+
输入示例:
|
|
30
|
+
TemplateFile(
|
|
31
|
+
id="age_check",
|
|
32
|
+
name="年龄校验",
|
|
33
|
+
nodes=[
|
|
34
|
+
TemplateNode(id="md1", kind="manualData", type="ManualData", column_name="age", rows=[["18"]]),
|
|
35
|
+
TemplateNode(id="check_range", kind="constraint", type="Range", input_from_node="md1", params={"min": 0, "max": 120}),
|
|
36
|
+
],
|
|
37
|
+
)
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
from __future__ import annotations
|
|
41
|
+
|
|
42
|
+
from typing import Any, Literal
|
|
43
|
+
|
|
44
|
+
from pydantic import BaseModel, Field
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class TemplateNode(BaseModel):
|
|
48
|
+
"""@classdesc 模板内部 DAG 节点
|
|
49
|
+
|
|
50
|
+
字段说明:
|
|
51
|
+
- id: 模板内局部 ID(展开时映射为 {instance_id}__{local_id})
|
|
52
|
+
- kind: 节点类型分类(transform/constraint/regex/manualData)
|
|
53
|
+
- type: 具体类型名称(如 StringSplit/Range/NotNull 等);manualData kind 时固定为 "ManualData"
|
|
54
|
+
- input_from_node: 上游节点 ID(仅支持模板内部节点引用)
|
|
55
|
+
- input_column: 输入列名
|
|
56
|
+
- params: 转换/约束参数(完整默认值)
|
|
57
|
+
- output_columns: 输出列名列表
|
|
58
|
+
- refs: 约束引用区
|
|
59
|
+
- enabled: 是否启用
|
|
60
|
+
- description: 描述
|
|
61
|
+
- column_name: manualData 专用 — 列名
|
|
62
|
+
- rows: manualData 专用 — 占位数据(二维字符串数组)
|
|
63
|
+
- column_data_type: manualData 专用 — 列数据类型
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
id: str
|
|
67
|
+
kind: Literal["transform", "constraint", "regex", "manualData"]
|
|
68
|
+
type: str
|
|
69
|
+
input_from_node: str | None = None
|
|
70
|
+
input_column: str | None = None
|
|
71
|
+
params: dict[str, Any] = Field(default_factory=dict)
|
|
72
|
+
output_columns: list[str] = Field(default_factory=list)
|
|
73
|
+
refs: dict[str, Any] = Field(default_factory=dict)
|
|
74
|
+
description: str | None = None
|
|
75
|
+
enabled: bool = True
|
|
76
|
+
# manualData 专用字段
|
|
77
|
+
column_name: str = ""
|
|
78
|
+
rows: list[list[str]] = Field(default_factory=list)
|
|
79
|
+
column_data_type: str = "string"
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class TemplateParameter(BaseModel):
|
|
83
|
+
"""@classdesc 模板参数声明
|
|
84
|
+
|
|
85
|
+
字段说明:
|
|
86
|
+
- name: 参数名(对应节点值中的 {{name}} 占位符)
|
|
87
|
+
- default: 参数默认值(实例未提供该参数时使用)
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
name: str
|
|
91
|
+
default: Any = None
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class TemplateFile(BaseModel):
|
|
95
|
+
"""@classdesc 模板定义文件根模型
|
|
96
|
+
|
|
97
|
+
对应 *.template.yaml 文件的结构。
|
|
98
|
+
展开时由 expander 将节点映射为标准的 TransformFile/ConstraintFile/RegexNodeFile/ManualDataFile。
|
|
99
|
+
|
|
100
|
+
字段说明:
|
|
101
|
+
- version: 配置版本号(固定为 2)
|
|
102
|
+
- id: 模板唯一标识
|
|
103
|
+
- name: 模板显示名称
|
|
104
|
+
- description: 模板描述
|
|
105
|
+
- parameters: 参数声明列表(展开时对节点值中的 {{param}} 占位符做替换)
|
|
106
|
+
- nodes: 内部 DAG 节点列表
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
version: int = Field(2, description="配置版本号(固定为 2)")
|
|
110
|
+
id: str = Field(..., description="模板唯一标识")
|
|
111
|
+
name: str = Field(..., description="模板显示名称")
|
|
112
|
+
description: str | None = Field(None, description="模板描述")
|
|
113
|
+
parameters: list[TemplateParameter] = Field(default_factory=list, description="参数声明列表")
|
|
114
|
+
nodes: list[TemplateNode] = Field(default_factory=list, description="内部 DAG 节点列表")
|
|
@@ -0,0 +1,76 @@
|
|
|
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
|
+
- 读取并解析 .transform.yaml 配置文件
|
|
21
|
+
- 使用 Pydantic 模型进行数据验证
|
|
22
|
+
|
|
23
|
+
输入示例:
|
|
24
|
+
transform_path = Path("/path/to/project/transforms/split.yaml")
|
|
25
|
+
|
|
26
|
+
# 文件内容:
|
|
27
|
+
# version: 2
|
|
28
|
+
# id: split_name
|
|
29
|
+
# type: StringSplit
|
|
30
|
+
# enabled: true
|
|
31
|
+
# input_column: full_name
|
|
32
|
+
# params:
|
|
33
|
+
# delimiter: " "
|
|
34
|
+
# output_columns: [first_name, last_name]
|
|
35
|
+
|
|
36
|
+
输出示例:
|
|
37
|
+
TransformFile(
|
|
38
|
+
version=2,
|
|
39
|
+
id="split_name",
|
|
40
|
+
type="StringSplit",
|
|
41
|
+
enabled=True,
|
|
42
|
+
input_column="full_name",
|
|
43
|
+
params={"delimiter": " "},
|
|
44
|
+
output_columns=["first_name", "last_name"]
|
|
45
|
+
)
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
from __future__ import annotations
|
|
49
|
+
|
|
50
|
+
from pathlib import Path
|
|
51
|
+
|
|
52
|
+
import yaml
|
|
53
|
+
|
|
54
|
+
from .types import TransformFile
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def load_transform(transform_path: Path) -> TransformFile:
|
|
58
|
+
"""@methoddesc 加载 Transform 配置文件
|
|
59
|
+
|
|
60
|
+
输入示例:
|
|
61
|
+
transform_path = Path("/path/to/project/transforms/split.yaml")
|
|
62
|
+
|
|
63
|
+
输出示例:
|
|
64
|
+
TransformFile(
|
|
65
|
+
version=2,
|
|
66
|
+
id="split_name",
|
|
67
|
+
type="StringSplit",
|
|
68
|
+
enabled=True,
|
|
69
|
+
input_column="full_name",
|
|
70
|
+
params={"delimiter": " "},
|
|
71
|
+
output_columns=["first_name", "last_name"]
|
|
72
|
+
)
|
|
73
|
+
"""
|
|
74
|
+
with open(transform_path, encoding="utf-8") as f:
|
|
75
|
+
raw = yaml.safe_load(f) or {}
|
|
76
|
+
return TransformFile.model_validate(raw)
|
|
@@ -0,0 +1,116 @@
|
|
|
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 功能/转换节点配置模块
|
|
18
|
+
|
|
19
|
+
功能概述:
|
|
20
|
+
- 定义 Transform 节点的数据模型 (TransformFile)
|
|
21
|
+
- 支持 StringSplit、RegexExtract、MathExpr、DateFormat 等转换类型
|
|
22
|
+
- 使用 Pydantic BaseModel 进行数据验证
|
|
23
|
+
|
|
24
|
+
架构设计:
|
|
25
|
+
- 统一入口: TransformFile 作为所有功能节点的根模型
|
|
26
|
+
- 类型区分: type 字段标识具体转换逻辑
|
|
27
|
+
- 参数灵活: params 为 Dict,各子类型自行定义内部结构
|
|
28
|
+
|
|
29
|
+
输入示例:
|
|
30
|
+
TransformFile(
|
|
31
|
+
version=2,
|
|
32
|
+
id="split_id_card",
|
|
33
|
+
type="StringSplit",
|
|
34
|
+
input_from_node="source_users_01",
|
|
35
|
+
input_column="id_card",
|
|
36
|
+
params={
|
|
37
|
+
"strategy": "fixed_position",
|
|
38
|
+
"ranges": [
|
|
39
|
+
{"name": "region_code", "start": 0, "end": 6},
|
|
40
|
+
{"name": "birth_date", "start": 6, "end": 14},
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
output_columns=["region_code", "birth_date"]
|
|
44
|
+
)
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
from __future__ import annotations
|
|
48
|
+
|
|
49
|
+
from typing import Any, Literal
|
|
50
|
+
|
|
51
|
+
from pydantic import BaseModel, Field
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class TransformFile(BaseModel):
|
|
55
|
+
"""
|
|
56
|
+
@classdesc 单条功能/转换节点文件内容。
|
|
57
|
+
|
|
58
|
+
支持类型(22 种):
|
|
59
|
+
- 多列输出: StringSplit, RegexExtract
|
|
60
|
+
- 单列输出(行数不变): MathExpr, DateFormat, Lookup, Strip, UpperCase, LowerCase,
|
|
61
|
+
Replace, FillNA, CastType, Concat, Substring, ConditionalAssign,
|
|
62
|
+
Digits, WeightedSum, Modulo, MapValue
|
|
63
|
+
- 行数改变: FilterRows, DropDuplicates, Aggregate, SortRows
|
|
64
|
+
(运行器已在 transforms/registry.py 注册;行位重排对约束错误 row_index
|
|
65
|
+
语义的影响见 docs/contracts/validate-json-v1.md)
|
|
66
|
+
|
|
67
|
+
输入接口:
|
|
68
|
+
- input_from_node: 上游节点 ID(优先)
|
|
69
|
+
- input_column: 上游节点中的目标列名
|
|
70
|
+
|
|
71
|
+
输出接口:
|
|
72
|
+
- output_columns: 转换后产生的列名列表
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
version: int = Field(2, description="配置版本号(固定为 2)")
|
|
76
|
+
id: str = Field(..., description="转换节点 ID(稳定标识)")
|
|
77
|
+
type: Literal[
|
|
78
|
+
"StringSplit",
|
|
79
|
+
"RegexExtract",
|
|
80
|
+
"MathExpr",
|
|
81
|
+
"DateFormat",
|
|
82
|
+
"Lookup",
|
|
83
|
+
"Strip",
|
|
84
|
+
"UpperCase",
|
|
85
|
+
"LowerCase",
|
|
86
|
+
"Replace",
|
|
87
|
+
"FillNA",
|
|
88
|
+
"FilterRows",
|
|
89
|
+
"DropDuplicates",
|
|
90
|
+
"CastType",
|
|
91
|
+
"Concat",
|
|
92
|
+
"Substring",
|
|
93
|
+
"Aggregate",
|
|
94
|
+
"ConditionalAssign",
|
|
95
|
+
"SortRows",
|
|
96
|
+
"Digits",
|
|
97
|
+
"WeightedSum",
|
|
98
|
+
"Modulo",
|
|
99
|
+
"MapValue",
|
|
100
|
+
] = Field(..., description="转换类型")
|
|
101
|
+
enabled: bool = Field(True, description="是否启用")
|
|
102
|
+
description: str | None = Field(None, description="描述")
|
|
103
|
+
|
|
104
|
+
# 输入接口
|
|
105
|
+
input_from_node: str | None = Field(None, description="上游数据流节点 ID")
|
|
106
|
+
input_column: str | None = Field(None, description="上游节点中的目标列名")
|
|
107
|
+
|
|
108
|
+
# 功能参数(因类型而异,各子类型自行约定结构)
|
|
109
|
+
params: dict[str, Any] = Field(default_factory=dict, description="转换参数(因类型而异)")
|
|
110
|
+
|
|
111
|
+
# 输出定义
|
|
112
|
+
output_columns: list[str] = Field(default_factory=list, description="转换后产生的列名列表")
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
# 兼容别名
|
|
116
|
+
TransformFileV2 = TransformFile
|
|
@@ -0,0 +1,84 @@
|
|
|
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
|
+
"""@fileoverview Transform 节点写入模块
|
|
17
|
+
|
|
18
|
+
功能概述:
|
|
19
|
+
- 写入 *.transform.yaml 文件
|
|
20
|
+
- 优化字段顺序,提升 YAML 可读性
|
|
21
|
+
|
|
22
|
+
架构设计:
|
|
23
|
+
- 唯一入口: 封装 Pydantic 模型到 YAML 文件的转换逻辑
|
|
24
|
+
- 字段排序: 按重要程度分组(核心 / 可选 / 内部)
|
|
25
|
+
- 一致性: 与 schema/writer.py、regex/writer.py 保持一致的排序策略
|
|
26
|
+
|
|
27
|
+
输入示例:
|
|
28
|
+
transform = TransformFile(
|
|
29
|
+
version=2,
|
|
30
|
+
id="cast_price",
|
|
31
|
+
type="CastType",
|
|
32
|
+
input_column="price",
|
|
33
|
+
params={"target_type": "decimal"},
|
|
34
|
+
output_columns=["price"],
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
输出示例:
|
|
38
|
+
save_transform(transform, "transforms/cast_price.transform.yaml")
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
from __future__ import annotations
|
|
42
|
+
|
|
43
|
+
from pathlib import Path
|
|
44
|
+
from typing import TYPE_CHECKING
|
|
45
|
+
|
|
46
|
+
from app.shared.core.io.yaml import write_yaml_atomic
|
|
47
|
+
|
|
48
|
+
from .types import TransformFile
|
|
49
|
+
|
|
50
|
+
if TYPE_CHECKING:
|
|
51
|
+
from .types import TransformFile
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def save_transform(transform: TransformFile, transform_path: str | Path) -> None:
|
|
55
|
+
"""
|
|
56
|
+
@methoddesc 保存 Transform 节点到 YAML 文件。
|
|
57
|
+
|
|
58
|
+
字段顺序优化(按重要程度分组):
|
|
59
|
+
L1(核心):type, description, params, input_from_node, input_column
|
|
60
|
+
L2(可选):enabled, output_columns
|
|
61
|
+
L3(内部):version, id
|
|
62
|
+
|
|
63
|
+
:param transform: TransformFile 对象,包含转换节点的完整配置
|
|
64
|
+
:param transform_path: 保存路径,可以是相对路径或绝对路径
|
|
65
|
+
:raises IOError: 文件写入失败时抛出
|
|
66
|
+
"""
|
|
67
|
+
data = transform.model_dump()
|
|
68
|
+
|
|
69
|
+
ordered = {
|
|
70
|
+
# L1 - 核心字段
|
|
71
|
+
"type": data["type"],
|
|
72
|
+
"description": data.get("description"),
|
|
73
|
+
"input_from_node": data.get("input_from_node"),
|
|
74
|
+
"input_column": data.get("input_column"),
|
|
75
|
+
"params": data.get("params", {}),
|
|
76
|
+
# L2 - 可选配置
|
|
77
|
+
"enabled": data.get("enabled", True),
|
|
78
|
+
"output_columns": data.get("output_columns", []),
|
|
79
|
+
# L3 - 内部字段
|
|
80
|
+
"version": data["version"],
|
|
81
|
+
"id": data["id"],
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
write_yaml_atomic(Path(transform_path), ordered)
|
|
@@ -0,0 +1,59 @@
|
|
|
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 Pydantic 校验消息的中文本地化(单一事实源)
|
|
18
|
+
|
|
19
|
+
Pydantic 的校验消息默认是英文("Input should be a valid integer" 等),
|
|
20
|
+
直接透给用户属于黑话。本模块提供常见消息的中文映射(子串替换,保留
|
|
21
|
+
位置与字段等上下文),供 422 全局 handler 与 LLM 动作 spec 校验共用。
|
|
22
|
+
未命中的消息保留原文,不会显示空白。
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
# 英文片段 → 中文(按出现顺序做子串替换)
|
|
28
|
+
_PATTERNS: list[tuple[str, str]] = [
|
|
29
|
+
("Input should be a valid integer", "应为整数"),
|
|
30
|
+
("Input should be a valid number", "应为数字"),
|
|
31
|
+
("Input should be a valid string", "应为文本"),
|
|
32
|
+
("Input should be a valid boolean", "应为 true/false"),
|
|
33
|
+
("Input should be a valid dictionary", "应为对象"),
|
|
34
|
+
("Input should be a valid list", "应为列表"),
|
|
35
|
+
("Input should be a valid date", "应为日期"),
|
|
36
|
+
("Input should be a valid email address", "应为有效的邮箱地址"),
|
|
37
|
+
("Input should be a valid URL", "应为有效的 URL"),
|
|
38
|
+
("Field required", "缺少必填字段"),
|
|
39
|
+
("Extra inputs are not permitted", "存在不允许的多余字段"),
|
|
40
|
+
("Input should be greater than or equal to", "不能小于"),
|
|
41
|
+
("Input should be less than or equal to", "不能大于"),
|
|
42
|
+
("String should have at least 1 character", "内容不能为空"),
|
|
43
|
+
("Input should be a valid enumeration value", "取值不在允许范围内"),
|
|
44
|
+
("Unable to extract tag using discriminator", "数据结构与预期的不一致"),
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def localize_pydantic_msg(msg: str) -> str:
|
|
49
|
+
"""将一条 Pydantic 校验消息中的常见英文片段替换为中文。
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
msg: Pydantic 的 msg 字段原文
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
本地化后的消息(未命中的片段保持原文)
|
|
56
|
+
"""
|
|
57
|
+
for en, zh in _PATTERNS:
|
|
58
|
+
msg = msg.replace(en, zh)
|
|
59
|
+
return msg
|
|
@@ -0,0 +1,46 @@
|
|
|
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 校验结果多渠道报告器模块包入口
|
|
18
|
+
|
|
19
|
+
功能概述:
|
|
20
|
+
- 提供数据校验结果的多渠道报告能力
|
|
21
|
+
- 支持本地文件、邮件、企业微信、飞书、钉钉等多种报告渠道
|
|
22
|
+
- 通过 ReportService 统一管理和调度所有报告器
|
|
23
|
+
|
|
24
|
+
架构设计:
|
|
25
|
+
- 策略模式 (Strategy Pattern): 各报告器继承自 Reporter 抽象基类,实现统一的 configure() 和 report() 接口
|
|
26
|
+
- 注册表模式: ReportService 维护报告者注册表,根据配置动态激活对应的报告器
|
|
27
|
+
- 统一入口: 外部通过 ReportService 调用,无需关心底层具体报告器的实现细节
|
|
28
|
+
|
|
29
|
+
输入示例:
|
|
30
|
+
通过 ReportService 传入错误列表:
|
|
31
|
+
errors = [
|
|
32
|
+
{
|
|
33
|
+
"error_type": "TypeValidationError",
|
|
34
|
+
"row_index": 2,
|
|
35
|
+
"column": "age",
|
|
36
|
+
"value": "abc",
|
|
37
|
+
"error_message": "必须是整数"
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
输出示例:
|
|
42
|
+
各报告器将错误信息发送到对应渠道:
|
|
43
|
+
- 本地文件: 生成 JSON 日志文件到 logs/error_report_20240115_143052.json
|
|
44
|
+
- 邮件: 发送 HTML 格式邮件到指定收件箱
|
|
45
|
+
- 企业微信/飞书/钉钉: 推送 Markdown/卡片消息到对应应用
|
|
46
|
+
"""
|