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,83 @@
|
|
|
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
|
+
|
|
23
|
+
架构设计:
|
|
24
|
+
- 类型安全: 使用 Literal 限制可选值
|
|
25
|
+
- 范围限制: timeout_seconds 和 batch_max_files 有取值范围
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
from typing import Literal
|
|
31
|
+
|
|
32
|
+
from pydantic import BaseModel, Field
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ValidationSettings(BaseModel):
|
|
36
|
+
"""
|
|
37
|
+
@classdesc 验证设置
|
|
38
|
+
|
|
39
|
+
定义数据验证的行为和策略。
|
|
40
|
+
|
|
41
|
+
字段说明:
|
|
42
|
+
- auto_validate: 是否在连接或配置变更时自动触发校验
|
|
43
|
+
- strict_mode: 严格模式,任何错误都会导致校验失败
|
|
44
|
+
- error_handling: 遇到错误时的处理策略
|
|
45
|
+
- stop: 立即停止校验
|
|
46
|
+
- continue: 跳过错误继续校验其他数据
|
|
47
|
+
- report: 记录错误但继续,生成完整报告
|
|
48
|
+
- timeout_seconds: 单次校验最大超时时间 (1-300秒)
|
|
49
|
+
- batch_max_files: 批量校验的最大文件数 (1-1000)
|
|
50
|
+
|
|
51
|
+
输入示例 (manifest.yaml):
|
|
52
|
+
settings:
|
|
53
|
+
validation:
|
|
54
|
+
auto_validate: true
|
|
55
|
+
strict_mode: false
|
|
56
|
+
error_handling: continue
|
|
57
|
+
timeout_seconds: 60
|
|
58
|
+
batch_max_files: 200
|
|
59
|
+
|
|
60
|
+
输出示例:
|
|
61
|
+
ValidationSettings(
|
|
62
|
+
auto_validate=True,
|
|
63
|
+
strict_mode=False,
|
|
64
|
+
error_handling="continue",
|
|
65
|
+
timeout_seconds=60,
|
|
66
|
+
batch_max_files=200
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
默认值:
|
|
70
|
+
ValidationSettings(
|
|
71
|
+
auto_validate=True,
|
|
72
|
+
strict_mode=False,
|
|
73
|
+
error_handling="continue",
|
|
74
|
+
timeout_seconds=30,
|
|
75
|
+
batch_max_files=100
|
|
76
|
+
)
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
auto_validate: bool = Field(True, description="是否在连接或配置变更时自动执行校验")
|
|
80
|
+
strict_mode: bool = Field(False, description="是否严格模式,发现任何错误即标记为校验失败")
|
|
81
|
+
error_handling: Literal["stop", "continue", "report"] = Field("continue", description="遇到校验错误时的处理策略")
|
|
82
|
+
timeout_seconds: int = Field(30, ge=1, le=300, description="单次校验的最大执行时间(秒)")
|
|
83
|
+
batch_max_files: int = Field(100, ge=1, le=1000, description="批量校验的最大文件数量")
|
|
@@ -0,0 +1,66 @@
|
|
|
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
|
+
- TemplateRef: 模板定义文件的引用(id + path)
|
|
21
|
+
- TemplateInstanceRef: 模板实例的引用(含参数绑定值)
|
|
22
|
+
|
|
23
|
+
架构设计:
|
|
24
|
+
- 与 SchemaRef / ConstraintRef 等保持一致的结构
|
|
25
|
+
- TemplateInstanceRef 额外包含 template_id 和 params 字段
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
from typing import Any
|
|
31
|
+
|
|
32
|
+
from pydantic import BaseModel, Field
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class TemplateRef(BaseModel):
|
|
36
|
+
"""@classdesc 模板定义文件引用
|
|
37
|
+
|
|
38
|
+
字段说明:
|
|
39
|
+
- id: 模板唯一标识(必须与 .template.yaml 文件中的 id 一致)
|
|
40
|
+
- path: 模板文件路径(相对于 manifest 所在目录)
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
id: str
|
|
44
|
+
path: str
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class TemplateInstanceRef(BaseModel):
|
|
48
|
+
"""@classdesc 模板实例引用
|
|
49
|
+
|
|
50
|
+
字段说明:
|
|
51
|
+
- id: 实例唯一标识(全局唯一)
|
|
52
|
+
- template_id: 引用的模板 ID
|
|
53
|
+
- enabled: 是否启用
|
|
54
|
+
- params: 参数绑定值(覆盖模板声明的默认值,展开时对 {{param}} 占位符做替换)
|
|
55
|
+
- input_from_node: 实例级上游节点 ID(通常指向 Schema,覆盖节点级 input_from_node)
|
|
56
|
+
|
|
57
|
+
展开行为:
|
|
58
|
+
加载时由 expander 将此实例展开为一组 TransformFile / ConstraintFile / RegexNodeFile / ManualDataFile,
|
|
59
|
+
展开后的节点 ID 格式为 {instance_id}__{local_node_id}。
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
id: str = Field(..., description="实例 ID(全局唯一)")
|
|
63
|
+
template_id: str = Field(..., description="引用的模板 ID")
|
|
64
|
+
enabled: bool = Field(True, description="是否启用")
|
|
65
|
+
params: dict[str, Any] = Field(default_factory=dict, description="参数绑定值")
|
|
66
|
+
input_from_node: str | None = Field(None, description="实例级上游节点 ID(通常指向 Schema)")
|
|
@@ -0,0 +1,262 @@
|
|
|
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
|
+
- 将项目清单写入 project.precis.yaml 文件
|
|
21
|
+
- 提供清单的持久化功能
|
|
22
|
+
- 管理清单中各种引用(schema、constraint、regex)
|
|
23
|
+
|
|
24
|
+
架构设计:
|
|
25
|
+
- 写入职责: 专注于清单文件保存和引用管理
|
|
26
|
+
- 工具函数: 提供 ensure_*_ref 系列函数用于动态添加引用
|
|
27
|
+
- 完整性保证: 写入时自动排除空值字段,确保配置简洁
|
|
28
|
+
|
|
29
|
+
输入示例:
|
|
30
|
+
manifest = ProjectManifest(
|
|
31
|
+
version=2,
|
|
32
|
+
project=ProjectInfo(id="my-project", name="My Project"),
|
|
33
|
+
schemas=[SchemaRef(id="users", path="schemas/users.schema.yaml")],
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
输出示例:
|
|
37
|
+
save_manifest(manifest, "project.precis.yaml")
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
from __future__ import annotations
|
|
41
|
+
|
|
42
|
+
from pathlib import Path
|
|
43
|
+
|
|
44
|
+
from app.shared.core.io.yaml import write_yaml_atomic
|
|
45
|
+
|
|
46
|
+
from .types import ConstraintRef, ManualDataRef, ProjectManifest, RegexRef, SchemaRef
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def save_manifest(manifest: ProjectManifest, manifest_path: str | Path) -> None:
|
|
50
|
+
"""
|
|
51
|
+
@methoddesc 将项目清单保存到 YAML 文件。
|
|
52
|
+
|
|
53
|
+
本函数将 ProjectManifest 对象序列化为 YAML 格式并写入指定文件。
|
|
54
|
+
写入时自动排除空值字段(exclude_none=True),生成干净简洁的配置文件。
|
|
55
|
+
|
|
56
|
+
处理流程:
|
|
57
|
+
1. 路径标准化:将路径转换为 Path 对象
|
|
58
|
+
2. 模型序列化:将 Pydantic 模型转换为字典(排除 None 值)
|
|
59
|
+
3. YAML 写入:调用底层 YAML 工具写入文件
|
|
60
|
+
|
|
61
|
+
参数说明:
|
|
62
|
+
manifest: 已构建的 ProjectManifest 对象,包含完整的项目配置。
|
|
63
|
+
建议在保存前确保所有必要字段已正确填充。
|
|
64
|
+
manifest_path: 目标文件路径,支持字符串或 Path 对象。
|
|
65
|
+
如果父目录不存在,写入前需要确保目录已创建。
|
|
66
|
+
|
|
67
|
+
返回值:
|
|
68
|
+
无返回值。函数执行完成后,清单内容已持久化到指定文件。
|
|
69
|
+
|
|
70
|
+
异常抛出:
|
|
71
|
+
可能抛出 I/O 相关异常(如权限不足、磁盘空间不足等)。
|
|
72
|
+
|
|
73
|
+
示例:
|
|
74
|
+
>>> manifest = ProjectManifest(
|
|
75
|
+
... version=2,
|
|
76
|
+
... project=ProjectInfo(id="my-project", name="My Project"),
|
|
77
|
+
... schemas=[SchemaRef(id="users", path="schemas/users.yaml")]
|
|
78
|
+
... )
|
|
79
|
+
>>> save_manifest(manifest, "./project.precis.yaml")
|
|
80
|
+
>>> # 文件内容已写入
|
|
81
|
+
"""
|
|
82
|
+
# 将 Pydantic 模型序列化为字典,exclude_none=True 排除空值字段
|
|
83
|
+
# 这样可以生成干净简洁的 YAML 配置文件
|
|
84
|
+
write_yaml_atomic(Path(manifest_path), manifest.model_dump(exclude_none=True))
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def ensure_schema_ref(manifest: ProjectManifest, table_id: str, default_path: str | None = None) -> SchemaRef:
|
|
88
|
+
"""
|
|
89
|
+
@methoddesc 确保清单中包含指定 table_id 的 schema 引用。
|
|
90
|
+
|
|
91
|
+
本函数用于动态向清单添加 schema 引用。如果指定的 schema 引用已存在,
|
|
92
|
+
直接返回现有引用;如果不存在,则创建新的引用并添加到清单中。
|
|
93
|
+
|
|
94
|
+
处理流程:
|
|
95
|
+
1. 查找现有引用:在 manifest.schemas 列表中查找匹配的 ID
|
|
96
|
+
2. 存在判断:找到则直接返回,找不到则进入步骤 3
|
|
97
|
+
3. 创建新引用:使用提供的 table_id 和 default_path 构建新引用
|
|
98
|
+
4. 添加到清单:将新引用追加到 manifest.schemas 列表
|
|
99
|
+
5. 返回引用:返回找到或创建的 SchemaRef 对象
|
|
100
|
+
|
|
101
|
+
参数说明:
|
|
102
|
+
manifest: 目标 ProjectManifest 对象,引用将被添加到此清单。
|
|
103
|
+
table_id: Schema 文件对应的表 ID,必须与 schema 文件内部的 id 一致。
|
|
104
|
+
default_path: 当引用不存在时使用的默认路径。
|
|
105
|
+
默认为 "schemas/{table_id}.schema.yaml"。
|
|
106
|
+
|
|
107
|
+
返回值:
|
|
108
|
+
SchemaRef: 找到或创建的 schema 引用对象,包含:
|
|
109
|
+
- id: 表 ID
|
|
110
|
+
- path: schema 文件相对路径
|
|
111
|
+
|
|
112
|
+
示例:
|
|
113
|
+
>>> manifest = ProjectManifest(...)
|
|
114
|
+
>>> # 确保 users schema 引用存在
|
|
115
|
+
>>> ref = ensure_schema_ref(manifest, "users")
|
|
116
|
+
>>> print(ref.path)
|
|
117
|
+
'schemas/users.schema.yaml'
|
|
118
|
+
"""
|
|
119
|
+
# Step 1: 线性查找 - 在现有 schema 引用列表中查找匹配 ID
|
|
120
|
+
# 使用生成器表达式配合 next() 实现高效的首次匹配查找
|
|
121
|
+
ref = next((s for s in manifest.schemas if s.id == table_id), None)
|
|
122
|
+
|
|
123
|
+
# Step 2: 存在则直接返回 - 无需修改清单
|
|
124
|
+
if ref:
|
|
125
|
+
return ref
|
|
126
|
+
|
|
127
|
+
# Step 3: 不存在则创建新引用 - 使用默认路径或自定义路径
|
|
128
|
+
# 默认路径格式: schemas/{table_id}.schema.yaml
|
|
129
|
+
new_ref = SchemaRef(id=table_id, path=default_path or f"schemas/{table_id}.schema.yaml")
|
|
130
|
+
|
|
131
|
+
# Step 4: 添加到清单 - 修改传入的 manifest 对象
|
|
132
|
+
manifest.schemas.append(new_ref)
|
|
133
|
+
|
|
134
|
+
# Step 5: 返回引用 - 供调用方使用
|
|
135
|
+
return new_ref
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def ensure_constraint_ref(
|
|
139
|
+
manifest: ProjectManifest, constraint_id: str, default_path: str | None = None
|
|
140
|
+
) -> ConstraintRef:
|
|
141
|
+
"""
|
|
142
|
+
@methoddesc 确保清单中包含指定 constraint_id 的约束引用。
|
|
143
|
+
|
|
144
|
+
本函数用于动态向清单添加 constraint 引用。如果指定的 constraint 引用已存在,
|
|
145
|
+
直接返回现有引用;如果不存在,则创建新的引用并添加到清单中。
|
|
146
|
+
|
|
147
|
+
处理流程:
|
|
148
|
+
1. 查找现有引用:在 manifest.constraints 列表中查找匹配的 ID
|
|
149
|
+
2. 存在判断:找到则直接返回,找不到则进入步骤 3
|
|
150
|
+
3. 创建新引用:使用提供的 constraint_id 和 default_path 构建新引用
|
|
151
|
+
4. 添加到清单:将新引用追加到 manifest.constraints 列表
|
|
152
|
+
5. 返回引用:返回找到或创建的 ConstraintRef 对象
|
|
153
|
+
|
|
154
|
+
参数说明:
|
|
155
|
+
manifest: 目标 ProjectManifest 对象,引用将被添加到此清单。
|
|
156
|
+
constraint_id: Constraint 文件对应的约束 ID,必须与 constraint 文件内部的 id 一致。
|
|
157
|
+
default_path: 当引用不存在时使用的默认路径。
|
|
158
|
+
默认为 "constraints/{constraint_id}.constraint.yaml"。
|
|
159
|
+
|
|
160
|
+
返回值:
|
|
161
|
+
ConstraintRef: 找到或创建的 constraint 引用对象,包含:
|
|
162
|
+
- id: 约束 ID
|
|
163
|
+
- path: constraint 文件相对路径
|
|
164
|
+
|
|
165
|
+
示例:
|
|
166
|
+
>>> manifest = ProjectManifest(...)
|
|
167
|
+
>>> # 确保 email_format constraint 引用存在
|
|
168
|
+
>>> ref = ensure_constraint_ref(manifest, "email_format")
|
|
169
|
+
>>> print(ref.path)
|
|
170
|
+
'constraints/email_format.constraint.yaml'
|
|
171
|
+
"""
|
|
172
|
+
# Step 1: 线性查找 - 在现有 constraint 引用列表中查找匹配 ID
|
|
173
|
+
ref = next((c for c in manifest.constraints if c.id == constraint_id), None)
|
|
174
|
+
|
|
175
|
+
# Step 2: 存在则直接返回
|
|
176
|
+
if ref:
|
|
177
|
+
return ref
|
|
178
|
+
|
|
179
|
+
# Step 3: 不存在则创建新引用 - 使用默认路径或自定义路径
|
|
180
|
+
# 默认路径格式: constraints/{constraint_id}.constraint.yaml
|
|
181
|
+
new_ref = ConstraintRef(id=constraint_id, path=default_path or f"constraints/{constraint_id}.constraint.yaml")
|
|
182
|
+
|
|
183
|
+
# Step 4: 添加到清单
|
|
184
|
+
manifest.constraints.append(new_ref)
|
|
185
|
+
|
|
186
|
+
# Step 5: 返回引用
|
|
187
|
+
return new_ref
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def ensure_regex_ref(manifest: ProjectManifest, regex_id: str, default_path: str | None = None) -> RegexRef:
|
|
191
|
+
"""
|
|
192
|
+
@methoddesc 确保清单中包含指定 regex_id 的正则节点引用。
|
|
193
|
+
|
|
194
|
+
本函数用于动态向清单添加 regex 引用。如果指定的 regex 引用已存在,
|
|
195
|
+
直接返回现有引用;如果不存在,则创建新的引用并添加到清单中。
|
|
196
|
+
|
|
197
|
+
处理流程:
|
|
198
|
+
1. 查找现有引用:在 manifest.regex_nodes 列表中查找匹配的 ID
|
|
199
|
+
2. 存在判断:找到则直接返回,找不到则进入步骤 3
|
|
200
|
+
3. 创建新引用:使用提供的 regex_id 和 default_path 构建新引用
|
|
201
|
+
4. 添加到清单:将新引用追加到 manifest.regex_nodes 列表
|
|
202
|
+
5. 返回引用:返回找到或创建的 RegexRef 对象
|
|
203
|
+
|
|
204
|
+
参数说明:
|
|
205
|
+
manifest: 目标 ProjectManifest 对象,引用将被添加到此清单。
|
|
206
|
+
regex_id: Regex 节点文件对应的 ID,必须与 regex 文件内部的 id 一致。
|
|
207
|
+
default_path: 当引用不存在时使用的默认路径。
|
|
208
|
+
默认为 "regex/{regex_id}.regex.yaml"。
|
|
209
|
+
|
|
210
|
+
返回值:
|
|
211
|
+
RegexRef: 找到或创建的 regex 引用对象,包含:
|
|
212
|
+
- id: 正则节点 ID
|
|
213
|
+
- path: regex 文件相对路径
|
|
214
|
+
|
|
215
|
+
示例:
|
|
216
|
+
>>> manifest = ProjectManifest(...)
|
|
217
|
+
>>> # 确保 phone_number regex 引用存在
|
|
218
|
+
>>> ref = ensure_regex_ref(manifest, "phone_number")
|
|
219
|
+
>>> print(ref.path)
|
|
220
|
+
'regex/phone_number.regex.yaml'
|
|
221
|
+
"""
|
|
222
|
+
# Step 1: 线性查找 - 在现有 regex 引用列表中查找匹配 ID
|
|
223
|
+
ref = next((r for r in manifest.regex_nodes if r.id == regex_id), None)
|
|
224
|
+
|
|
225
|
+
# Step 2: 存在则直接返回
|
|
226
|
+
if ref:
|
|
227
|
+
return ref
|
|
228
|
+
|
|
229
|
+
# Step 3: 不存在则创建新引用 - 使用默认路径或自定义路径
|
|
230
|
+
# 默认路径格式: regex/{regex_id}.regex.yaml
|
|
231
|
+
new_ref = RegexRef(id=regex_id, path=default_path or f"regex/{regex_id}.regex.yaml")
|
|
232
|
+
|
|
233
|
+
# Step 4: 添加到清单
|
|
234
|
+
manifest.regex_nodes.append(new_ref)
|
|
235
|
+
|
|
236
|
+
# Step 5: 返回引用
|
|
237
|
+
return new_ref
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def ensure_manual_data_ref(
|
|
241
|
+
manifest: ProjectManifest, manual_data_id: str, default_path: str | None = None
|
|
242
|
+
) -> ManualDataRef:
|
|
243
|
+
"""@methoddesc 确保清单中包含指定 manual_data_id 的 ManualData 引用。
|
|
244
|
+
|
|
245
|
+
如果引用已存在则直接返回,否则创建新引用并添加到清单中。
|
|
246
|
+
|
|
247
|
+
参数:
|
|
248
|
+
manifest: 目标 ProjectManifest 对象
|
|
249
|
+
manual_data_id: ManualData 节点 ID
|
|
250
|
+
default_path: 默认路径(若为 None 则自动生成)
|
|
251
|
+
|
|
252
|
+
返回:
|
|
253
|
+
找到或创建的 ManualDataRef 对象
|
|
254
|
+
"""
|
|
255
|
+
ref = next((md for md in manifest.manual_data if md.id == manual_data_id), None)
|
|
256
|
+
|
|
257
|
+
if ref:
|
|
258
|
+
return ref
|
|
259
|
+
|
|
260
|
+
new_ref = ManualDataRef(id=manual_data_id, path=default_path or f"manual_data/{manual_data_id}.manual_data.yaml")
|
|
261
|
+
manifest.manual_data.append(new_ref)
|
|
262
|
+
return new_ref
|
|
@@ -0,0 +1,27 @@
|
|
|
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 ManualData 配置模块
|
|
18
|
+
|
|
19
|
+
功能概述:
|
|
20
|
+
- 定义 ManualData 节点的数据模型 (ManualDataFile)
|
|
21
|
+
- 用于持久化画布上的内联测试数据节点
|
|
22
|
+
|
|
23
|
+
架构设计:
|
|
24
|
+
- ManualDataFile 对应 manual_data/*.yaml 配置文件
|
|
25
|
+
- 在 manifest 中通过 ManualDataRef 引用
|
|
26
|
+
- 模板展开时,模板内 manualData 节点展开为 ManualDataFile
|
|
27
|
+
"""
|
|
@@ -0,0 +1,75 @@
|
|
|
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 ManualData 节点配置类型定义
|
|
18
|
+
|
|
19
|
+
功能概述:
|
|
20
|
+
- 定义 ManualData 节点的数据模型 (ManualDataFile)
|
|
21
|
+
- 支持单列内联数据的持久化
|
|
22
|
+
|
|
23
|
+
架构设计:
|
|
24
|
+
- ManualDataFile 对应 manual_data/{id}.yaml 配置文件
|
|
25
|
+
- 在 manifest 中通过 ManualDataRef 引用
|
|
26
|
+
- 模板展开时,模板内 manualData 节点展开为 ManualDataFile
|
|
27
|
+
|
|
28
|
+
输入示例:
|
|
29
|
+
ManualDataFile(
|
|
30
|
+
version=2,
|
|
31
|
+
id="ti1__md1",
|
|
32
|
+
column_name="age",
|
|
33
|
+
column_data_type="integer",
|
|
34
|
+
rows=[["18"], ["25"], ["65"]],
|
|
35
|
+
)
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
from __future__ import annotations
|
|
39
|
+
|
|
40
|
+
from typing import Literal
|
|
41
|
+
|
|
42
|
+
from pydantic import BaseModel, Field
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class ManualDataFile(BaseModel):
|
|
46
|
+
"""@classdesc ManualData 节点文件内容
|
|
47
|
+
|
|
48
|
+
用于持久化画布上的内联测试数据节点。
|
|
49
|
+
manualData 是单列数据节点,rows 为二维数组(每行一个字段)。
|
|
50
|
+
|
|
51
|
+
字段说明:
|
|
52
|
+
- version: 配置版本号(固定为 2)
|
|
53
|
+
- id: 节点 ID(与 manifest ref id 一致)
|
|
54
|
+
- column_name: 列名
|
|
55
|
+
- column_data_type: 列数据类型
|
|
56
|
+
- rows: 二维字符串数组,每行一个字段值
|
|
57
|
+
- enabled: 是否启用
|
|
58
|
+
- description: 描述
|
|
59
|
+
- input_from_node: 上游节点 ID(当从 Schema 列注入数据时设置)
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
version: int = Field(2, description="配置版本号(固定为 2)")
|
|
63
|
+
id: str = Field(..., description="节点 ID(与 manifest ref id 一致)")
|
|
64
|
+
column_name: str = Field("Column1", description="列名")
|
|
65
|
+
column_data_type: Literal["string", "integer", "float", "decimal", "boolean", "date"] = Field(
|
|
66
|
+
"string", description="列数据类型"
|
|
67
|
+
)
|
|
68
|
+
rows: list[list[str]] = Field(default_factory=list, description="二维字符串数组,每行一个字段值")
|
|
69
|
+
enabled: bool = Field(True, description="是否启用")
|
|
70
|
+
description: str | None = Field(None, description="描述")
|
|
71
|
+
input_from_node: str | None = Field(None, description="上游节点 ID(当从 Schema 列注入数据时设置)")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# 兼容别名
|
|
75
|
+
ManualDataFileV2 = ManualDataFile
|