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,197 @@
|
|
|
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
|
+
- 从 *.regex.yaml 文件读取正则节点配置
|
|
21
|
+
- 解析正则表达式(支持引用模式和直接模式)
|
|
22
|
+
|
|
23
|
+
架构设计:
|
|
24
|
+
- 唯一入口: 该模块是 Regex 节点配置读取的唯一入口
|
|
25
|
+
- 双模式支持: load_regex_node 加载配置,resolve_regex_pattern 解析表达式
|
|
26
|
+
- 读写配合: 与 writer.py 配合实现正则节点配置全生命周期管理
|
|
27
|
+
|
|
28
|
+
输入示例:
|
|
29
|
+
# phone.regex.yaml
|
|
30
|
+
version: 2
|
|
31
|
+
id: phone
|
|
32
|
+
name: 手机号校验
|
|
33
|
+
uses_pattern:
|
|
34
|
+
registry: patterns
|
|
35
|
+
pattern_name: phone_cn
|
|
36
|
+
|
|
37
|
+
输出示例:
|
|
38
|
+
regex_node = load_regex_node("regex/phone.regex.yaml")
|
|
39
|
+
pattern = resolve_regex_pattern(regex_node, patterns_registry)
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
from __future__ import annotations
|
|
43
|
+
|
|
44
|
+
import re
|
|
45
|
+
from pathlib import Path
|
|
46
|
+
from typing import TYPE_CHECKING, cast
|
|
47
|
+
|
|
48
|
+
from pydantic import ValidationError
|
|
49
|
+
|
|
50
|
+
from app.shared.core.io.yaml import read_yaml
|
|
51
|
+
from app.shared.domain.regex_flags import parse_regex_flags
|
|
52
|
+
|
|
53
|
+
from .types import RegexNodeFile
|
|
54
|
+
|
|
55
|
+
if TYPE_CHECKING:
|
|
56
|
+
from app.shared.domain.expression_system import ExpressionPattern, ExpressionRegistry
|
|
57
|
+
|
|
58
|
+
from .types import RegexNodeFile
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _parse_regex_flags(flag_str: str) -> int:
|
|
62
|
+
"""把 flags 配置字符串解析为 re 模块标志位(薄委托 domain 单一事实源)。
|
|
63
|
+
|
|
64
|
+
语义细节见 app.shared.domain.regex_flags.parse_regex_flags:
|
|
65
|
+
逗号/空白切分整词匹配,不得子串包含(`"i" in "multiline"` 为真会误开 IGNORECASE)。
|
|
66
|
+
"""
|
|
67
|
+
return parse_regex_flags(flag_str)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def load_regex_node(regex_path: str | Path) -> RegexNodeFile:
|
|
71
|
+
"""
|
|
72
|
+
@methoddesc 从 YAML 文件加载正则节点配置。
|
|
73
|
+
|
|
74
|
+
处理流程:
|
|
75
|
+
1. 将路径转换为 Path 对象
|
|
76
|
+
2. 调用 YAML 读取工具读取文件内容
|
|
77
|
+
3. 使用 Pydantic 模型验证配置有效性
|
|
78
|
+
4. 返回验证后的 RegexNodeFile 对象
|
|
79
|
+
|
|
80
|
+
:param regex_path: regex 文件路径,可以是相对路径或绝对路径
|
|
81
|
+
:return: RegexNodeFile 对象,包含正则节点的完整配置
|
|
82
|
+
:raises ValueError: 文件不存在、格式错误或验证失败
|
|
83
|
+
:raises FileNotFoundError: 文件路径不存在
|
|
84
|
+
"""
|
|
85
|
+
# 步骤1:转换为 Path 对象(统一处理路径格式)
|
|
86
|
+
path = Path(regex_path)
|
|
87
|
+
|
|
88
|
+
# 步骤2:读取 YAML 文件内容
|
|
89
|
+
# read_yaml 会解析 YAML 文件并返回字典结构
|
|
90
|
+
raw = read_yaml(path)
|
|
91
|
+
|
|
92
|
+
# 步骤3:使用 Pydantic 进行数据验证
|
|
93
|
+
# model_validate 会检查所有字段是否符合类型和约束要求
|
|
94
|
+
try:
|
|
95
|
+
return RegexNodeFile.model_validate(raw)
|
|
96
|
+
except ValidationError as e:
|
|
97
|
+
# 包装验证错误,提供更友好的错误信息
|
|
98
|
+
raise ValueError(f"regex_node 校验失败: {path}\n{e}") from e
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def find_pattern_by_name(registry: ExpressionRegistry, pattern_name: str) -> ExpressionPattern | None:
|
|
102
|
+
"""
|
|
103
|
+
@methoddesc 按名称从注册表中查找表达式模式。
|
|
104
|
+
|
|
105
|
+
处理流程:
|
|
106
|
+
1. 遍历注册表中所有已注册的模式
|
|
107
|
+
2. 匹配模式名称
|
|
108
|
+
3. 返回第一个匹配的模式,或 None
|
|
109
|
+
|
|
110
|
+
:param registry: ExpressionRegistry 实例,包含已注册的模式列表
|
|
111
|
+
:param pattern_name: 要查找的模式名称
|
|
112
|
+
:return: 找到的 ExpressionPattern 对象,或 None(未找到)
|
|
113
|
+
"""
|
|
114
|
+
# 遍历所有已注册的模式,查找名称匹配的对象
|
|
115
|
+
# _patterns 是注册表内部的模式列表
|
|
116
|
+
for pattern in registry._patterns:
|
|
117
|
+
if pattern.name == pattern_name:
|
|
118
|
+
return pattern
|
|
119
|
+
# 未找到匹配的模式,返回 None
|
|
120
|
+
return None
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def resolve_regex_pattern(regex_config: RegexNodeFile, registries: dict) -> re.Pattern:
|
|
124
|
+
"""
|
|
125
|
+
@methoddesc 解析正则节点的正则表达式。
|
|
126
|
+
|
|
127
|
+
根据配置模式(引用模式或直接模式)获取并编译正则表达式。
|
|
128
|
+
引用模式支持配置覆盖(pattern_overrides),如修改 flags 等。
|
|
129
|
+
|
|
130
|
+
处理流程(引用模式):
|
|
131
|
+
1. 检查是否使用引用模式(uses_pattern 字段)
|
|
132
|
+
2. 从 registries 获取 expression_registry
|
|
133
|
+
3. 根据 pattern_name 在注册表中查找表达式
|
|
134
|
+
4. 如果存在 pattern_overrides,应用覆盖配置(如 flags)
|
|
135
|
+
5. 返回编译后的正则表达式对象
|
|
136
|
+
|
|
137
|
+
处理流程(直接模式):
|
|
138
|
+
1. 检查是否使用直接模式(pattern 字段)
|
|
139
|
+
2. 直接编译 pattern 字段中的正则表达式
|
|
140
|
+
3. 返回编译后的正则表达式对象
|
|
141
|
+
|
|
142
|
+
:param regex_config: regex 节点配置,包含正则表达式定义
|
|
143
|
+
:param registries: 包含 expression_registry 的字典
|
|
144
|
+
:return: 编译后的正则表达式对象(re.Pattern 类型)
|
|
145
|
+
:raises ValueError: 注册表未加载、模式未找到或配置错误
|
|
146
|
+
"""
|
|
147
|
+
# 判断使用哪种模式
|
|
148
|
+
if regex_config.uses_pattern:
|
|
149
|
+
# ========== 引用模式处理流程 ==========
|
|
150
|
+
# 步骤1:获取要引用的模式名称
|
|
151
|
+
pattern_name = regex_config.uses_pattern.pattern_name
|
|
152
|
+
|
|
153
|
+
# 步骤2:从注册表字典中获取表达式注册表
|
|
154
|
+
registry = registries.get("expression_registry")
|
|
155
|
+
|
|
156
|
+
# 步骤3:检查注册表是否已加载
|
|
157
|
+
if registry is None:
|
|
158
|
+
raise ValueError("未加载注册表:expression_registry")
|
|
159
|
+
|
|
160
|
+
# 步骤4:在注册表中查找指定的表达式模式
|
|
161
|
+
pattern = find_pattern_by_name(registry, pattern_name)
|
|
162
|
+
if pattern is None:
|
|
163
|
+
raise ValueError(
|
|
164
|
+
f"在 patterns 目录中未找到表达式模式:'{pattern_name}'(请检查 patterns/ 目录中的 YAML 文件)"
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
# 步骤5:获取原始正则表达式
|
|
168
|
+
effective_pattern = pattern.regex.pattern
|
|
169
|
+
|
|
170
|
+
# 步骤6:检查是否有配置覆盖(允许修改 flags 等)
|
|
171
|
+
overrides = regex_config.pattern_overrides or {}
|
|
172
|
+
if "flags" in overrides:
|
|
173
|
+
# 存在 flags 覆盖,需要重新编译(精确 token 匹配,见 _parse_regex_flags)
|
|
174
|
+
import re as re_module
|
|
175
|
+
|
|
176
|
+
flags = _parse_regex_flags(str(overrides["flags"]))
|
|
177
|
+
|
|
178
|
+
# 使用覆盖后的 flags 重新编译
|
|
179
|
+
return re_module.compile(effective_pattern, flags)
|
|
180
|
+
|
|
181
|
+
# 步骤7:无覆盖时返回原始编译后的正则表达式
|
|
182
|
+
return cast(re.Pattern, pattern.regex)
|
|
183
|
+
|
|
184
|
+
# ========== 直接模式处理流程 ==========
|
|
185
|
+
# 检查是否配置了直接模式的正则表达式
|
|
186
|
+
if not regex_config.pattern:
|
|
187
|
+
raise ValueError("regex_node 必须指定 pattern 或 uses_pattern")
|
|
188
|
+
|
|
189
|
+
# 解析 flags(与引用模式的 pattern_overrides 分支保持一致)
|
|
190
|
+
# 过去直接模式完全忽略 regex_config.flags / case_sensitive,导致大小写等配置失效
|
|
191
|
+
flags = _parse_regex_flags(str(getattr(regex_config, "flags", "") or ""))
|
|
192
|
+
# case_sensitive=False 同样触发 IGNORECASE(与 RegexConstraint 语义一致)
|
|
193
|
+
if getattr(regex_config, "case_sensitive", True) is False:
|
|
194
|
+
flags |= re.IGNORECASE
|
|
195
|
+
|
|
196
|
+
# 直接编译 pattern 字段中的正则表达式
|
|
197
|
+
return re.compile(regex_config.pattern, flags)
|
|
@@ -0,0 +1,405 @@
|
|
|
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
|
+
- 定义 V2 正则节点的数据类型
|
|
21
|
+
- 支持直接模式和引用模式
|
|
22
|
+
- 使用 Pydantic BaseModel 进行数据验证
|
|
23
|
+
|
|
24
|
+
架构设计:
|
|
25
|
+
- 类型定义核心: Regex 节点配置的数据模型层
|
|
26
|
+
- 双模式设计: pattern 字段直接编写,uses_pattern 字段引用预定义模式
|
|
27
|
+
- 自定义验证: 使用 model_validator 实现业务级校验逻辑
|
|
28
|
+
|
|
29
|
+
输入示例:
|
|
30
|
+
RegexNodeFile(
|
|
31
|
+
version=2,
|
|
32
|
+
id="phone",
|
|
33
|
+
name="手机号校验",
|
|
34
|
+
uses_pattern=PatternRef(registry="patterns", pattern_name="phone_cn"),
|
|
35
|
+
match_mode="full",
|
|
36
|
+
enabled=True,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
输出示例:
|
|
40
|
+
data = node.model_dump(exclude_none=True)
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
from __future__ import annotations
|
|
44
|
+
|
|
45
|
+
from typing import Any, Literal
|
|
46
|
+
|
|
47
|
+
from pydantic import BaseModel, Field, model_validator
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class RegexSourceRef(BaseModel):
|
|
51
|
+
"""
|
|
52
|
+
@classdesc 上游表列引用。
|
|
53
|
+
|
|
54
|
+
============================================================================
|
|
55
|
+
配置文件对应关系 (这个类对应哪种配置文件)
|
|
56
|
+
============================================================================
|
|
57
|
+
本类对应 *.regex.yaml 中的 source_ref 字段:
|
|
58
|
+
|
|
59
|
+
```yaml
|
|
60
|
+
# *.regex.yaml 中的 source_ref 配置
|
|
61
|
+
source_ref:
|
|
62
|
+
table_id: users # 上游表的 ID
|
|
63
|
+
column_id: phone # 上游列的 ID
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
============================================================================
|
|
67
|
+
字段映射说明
|
|
68
|
+
============================================================================
|
|
69
|
+
| YAML 字段 | Python 属性 | 数据类型 | 说明 |
|
|
70
|
+
|----------|------------|---------|------|
|
|
71
|
+
| table_id | table_id | str | 上游表的 ID |
|
|
72
|
+
| column_id | column_id | str | 上游列的 ID |
|
|
73
|
+
|
|
74
|
+
============================================================================
|
|
75
|
+
业务场景 (这个类在什么地方被使用)
|
|
76
|
+
============================================================================
|
|
77
|
+
- 场景1: 重建画布连线关系
|
|
78
|
+
在 UI 上显示 Regex 节点与其他节点之间的连线时使用。
|
|
79
|
+
|
|
80
|
+
- 场景2: 数据流追踪
|
|
81
|
+
追踪数据的来源和走向。
|
|
82
|
+
|
|
83
|
+
:param table_id: 上游表的 ID
|
|
84
|
+
:param column_id: 上游列的 ID
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
# 上游表的 ID
|
|
88
|
+
table_id: str
|
|
89
|
+
# 上游列的 ID
|
|
90
|
+
column_id: str
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class PatternRef(BaseModel):
|
|
94
|
+
"""
|
|
95
|
+
@classdesc 引用 patterns 中已注册的表达式模式。
|
|
96
|
+
|
|
97
|
+
============================================================================
|
|
98
|
+
配置文件对应关系 (这个类对应哪种配置文件)
|
|
99
|
+
============================================================================
|
|
100
|
+
本类对应 *.regex.yaml 中的 uses_pattern 字段:
|
|
101
|
+
|
|
102
|
+
```yaml
|
|
103
|
+
# *.regex.yaml 中的 uses_pattern 配置
|
|
104
|
+
uses_pattern:
|
|
105
|
+
registry: patterns # 注册表类型
|
|
106
|
+
pattern_name: email_validation # 引用的表达式名称
|
|
107
|
+
as_alias: personal_email # 可选的别名
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
============================================================================
|
|
111
|
+
字段映射说明
|
|
112
|
+
============================================================================
|
|
113
|
+
| YAML 字段 | Python 属性 | 数据类型 | 说明 | 示例值 |
|
|
114
|
+
|----------|------------|---------|------|-------|
|
|
115
|
+
| registry | registry | Literal | 注册表类型 | "patterns" |
|
|
116
|
+
| pattern_name | pattern_name | str | 表达式名称 | "email_validation" |
|
|
117
|
+
| as_alias | as_alias | Optional[str] | 可选别名 | "personal_email" |
|
|
118
|
+
|
|
119
|
+
============================================================================
|
|
120
|
+
业务场景 (这个类在什么地方被使用)
|
|
121
|
+
============================================================================
|
|
122
|
+
- 场景1: 复用预定义表达式
|
|
123
|
+
使用已注册的表达式模式,避免重复定义。
|
|
124
|
+
|
|
125
|
+
- 场景2: 统一管理
|
|
126
|
+
所有表达式在一个地方管理,方便修改。
|
|
127
|
+
|
|
128
|
+
:param registry: 注册表类型
|
|
129
|
+
:param pattern_name: 引用的表达式名称
|
|
130
|
+
:param as_alias: 可选别名
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
# 注册表类型,目前固定为 patterns
|
|
134
|
+
# patterns 是存放预定义正则表达式的目录
|
|
135
|
+
registry: Literal["patterns"] = Field(..., description="注册表类型:patterns(表达式模式)")
|
|
136
|
+
# 引用的表达式名称,对应 YAML 文件中的 name 字段
|
|
137
|
+
# 在 patterns/ 目录下的各个 YAML 文件中定义
|
|
138
|
+
pattern_name: str = Field(..., description="引用的表达式名称(对应 YAML 中的 name 字段)")
|
|
139
|
+
# 可选的别名,用于在当前节点中二次命名
|
|
140
|
+
# 当需要在同一节点中多次使用同一模式,但参数不同时使用
|
|
141
|
+
as_alias: str | None = Field(None, description="可选的别名,用于在当前节点中二次命名")
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class RegexNodeFile(BaseModel):
|
|
145
|
+
r"""
|
|
146
|
+
@classdesc 单条 Regex 节点文件内容(前端画布 Regex 节点落盘)。
|
|
147
|
+
|
|
148
|
+
============================================================================
|
|
149
|
+
配置文件对应关系 (这个类对应哪种配置文件)
|
|
150
|
+
============================================================================
|
|
151
|
+
本类对应整个 *.regex.yaml 文件:
|
|
152
|
+
|
|
153
|
+
```yaml
|
|
154
|
+
# ============================================================
|
|
155
|
+
# 正则节点配置文件 (*.regex.yaml)
|
|
156
|
+
# ============================================================
|
|
157
|
+
# Regex 节点用于定义数据校验规则,通过正则表达式匹配数据
|
|
158
|
+
# 支持两种配置模式:引用模式(推荐)和直接模式
|
|
159
|
+
|
|
160
|
+
# 配置版本号,固定为 2
|
|
161
|
+
version: 2
|
|
162
|
+
|
|
163
|
+
# Regex 节点 ID(稳定的唯一标识符)
|
|
164
|
+
id: phone_number
|
|
165
|
+
|
|
166
|
+
# Regex 节点名称(展示用)
|
|
167
|
+
name: 手机号校验
|
|
168
|
+
|
|
169
|
+
# 节点的描述信息
|
|
170
|
+
description: "校验中国大陆手机号格式"
|
|
171
|
+
|
|
172
|
+
# ========== 引用模式(推荐使用)==========
|
|
173
|
+
uses_pattern:
|
|
174
|
+
registry: patterns
|
|
175
|
+
pattern_name: phone_cn
|
|
176
|
+
|
|
177
|
+
# 对引用表达式的覆盖配置
|
|
178
|
+
pattern_overrides:
|
|
179
|
+
flags: "i"
|
|
180
|
+
|
|
181
|
+
# ========== 直接模式(兼容使用)==========
|
|
182
|
+
# pattern: "^1[3-9]\\d{9}$"
|
|
183
|
+
|
|
184
|
+
# ========== 通用配置 ==========
|
|
185
|
+
match_mode: full # full: 完全匹配 / partial: 部分匹配 / extract: 提取
|
|
186
|
+
case_sensitive: false # 是否区分大小写
|
|
187
|
+
flags: "" # 正则 flags 字符串
|
|
188
|
+
enabled: true # 是否启用该节点
|
|
189
|
+
parameters: [] # 参数列表(保留字段)
|
|
190
|
+
rules: [] # 规则列表(前端 RegexDesign 结构)
|
|
191
|
+
|
|
192
|
+
# 上游表列引用(用于重建画布中的连线关系)
|
|
193
|
+
source_ref:
|
|
194
|
+
table_id: users
|
|
195
|
+
column_id: phone
|
|
196
|
+
|
|
197
|
+
# 上游列名(兼容/展示用)
|
|
198
|
+
source_column_name: phone
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
============================================================================
|
|
202
|
+
字段映射说明 (YAML 如何变成 Python 对象)
|
|
203
|
+
============================================================================
|
|
204
|
+
| YAML 字段 | Python 属性 | 数据类型 | 说明 | 示例值 |
|
|
205
|
+
|----------|------------|---------|------|-------|
|
|
206
|
+
| version | version | int | 配置版本号 | 2 |
|
|
207
|
+
| id | id | str | Regex 节点 ID | "phone_number" |
|
|
208
|
+
| name | name | str | 节点名称 | "手机号校验" |
|
|
209
|
+
| description | description | Optional[str] | 节点描述 | "校验手机号格式" |
|
|
210
|
+
| uses_pattern | uses_pattern | Optional[PatternRef] | 引用模式 | PatternRef(...) |
|
|
211
|
+
| pattern_overrides | pattern_overrides | Dict[str, Any] | 覆盖配置 | {"flags": "i"} |
|
|
212
|
+
| pattern | pattern | Optional[str] | 直接模式 | "^1[3-9]\\d{9}$" |
|
|
213
|
+
| match_mode | match_mode | Literal | 匹配模式 | "full" |
|
|
214
|
+
| case_sensitive | case_sensitive | bool | 大小写敏感 | false |
|
|
215
|
+
| flags | flags | str | 正则 flags | "i" |
|
|
216
|
+
| enabled | enabled | bool | 是否启用 | true |
|
|
217
|
+
| parameters | parameters | List[Dict] | 参数列表 | [] |
|
|
218
|
+
| rules | rules | List[Dict] | 规则列表 | [] |
|
|
219
|
+
| source_ref | source_ref | Optional[RegexSourceRef] | 上游引用 | RegexSourceRef(...) |
|
|
220
|
+
| source_column_name | source_column_name | Optional[str] | 上游列名 | "phone" |
|
|
221
|
+
|
|
222
|
+
============================================================================
|
|
223
|
+
业务场景 (这个类在什么地方被使用)
|
|
224
|
+
============================================================================
|
|
225
|
+
- 场景1: 创建正则校验节点
|
|
226
|
+
用户在 UI 上创建一个正则校验节点,配置校验规则。
|
|
227
|
+
|
|
228
|
+
- 场景2: 加载正则节点配置
|
|
229
|
+
系统读取 *.regex.yaml 文件,解析为 RegexNodeFile 对象。
|
|
230
|
+
|
|
231
|
+
- 场景3: 保存正则节点配置
|
|
232
|
+
用户修改正则节点配置后,将 RegexNodeFile 对象写回 YAML 文件。
|
|
233
|
+
|
|
234
|
+
============================================================================
|
|
235
|
+
两种模式对比
|
|
236
|
+
============================================================================
|
|
237
|
+
模式1: 引用模式(uses_pattern)
|
|
238
|
+
优点:
|
|
239
|
+
- 复用性:同一表达式可在多个节点中使用
|
|
240
|
+
- 可维护性:修改表达式定义后,所有引用自动更新
|
|
241
|
+
- 灵活性:通过 pattern_overrides 支持局部配置覆盖
|
|
242
|
+
- 可追踪:方便了解表达式的来源和用途
|
|
243
|
+
|
|
244
|
+
模式2: 直接模式(pattern)
|
|
245
|
+
优点:
|
|
246
|
+
- 简单快捷:无需预先定义表达式
|
|
247
|
+
- 适合一次性场景
|
|
248
|
+
|
|
249
|
+
缺点:
|
|
250
|
+
- 难以复用
|
|
251
|
+
- 修改需遍历所有使用位置
|
|
252
|
+
|
|
253
|
+
推荐:优先使用引用模式
|
|
254
|
+
|
|
255
|
+
============================================================================
|
|
256
|
+
验证器说明
|
|
257
|
+
============================================================================
|
|
258
|
+
1. _validate_pattern_mode:
|
|
259
|
+
- 功能:验证必须使用引用模式或直接模式之一
|
|
260
|
+
- 触发时机:模型验证阶段(mode="after")
|
|
261
|
+
- 目的:确保模式配置正确
|
|
262
|
+
- 异常:ValueError - 当两种模式同时使用或都未使用时
|
|
263
|
+
|
|
264
|
+
============================================================================
|
|
265
|
+
使用示例
|
|
266
|
+
============================================================================
|
|
267
|
+
【创建引用模式节点】
|
|
268
|
+
```python
|
|
269
|
+
from app.shared.core.project.regex.types import RegexNodeFile, PatternRef, RegexSourceRef
|
|
270
|
+
|
|
271
|
+
node = RegexNodeFile(
|
|
272
|
+
version=2,
|
|
273
|
+
id="phone_number",
|
|
274
|
+
name="手机号校验",
|
|
275
|
+
description="校验中国大陆手机号格式",
|
|
276
|
+
uses_pattern=PatternRef(
|
|
277
|
+
registry="patterns",
|
|
278
|
+
pattern_name="phone_cn"
|
|
279
|
+
),
|
|
280
|
+
pattern_overrides={"flags": "i"},
|
|
281
|
+
match_mode="full",
|
|
282
|
+
source_ref=RegexSourceRef(
|
|
283
|
+
table_id="users",
|
|
284
|
+
column_id="phone"
|
|
285
|
+
)
|
|
286
|
+
)
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
【创建直接模式节点】
|
|
290
|
+
```python
|
|
291
|
+
node = RegexNodeFile(
|
|
292
|
+
id="email_direct",
|
|
293
|
+
name="邮箱校验",
|
|
294
|
+
pattern=r"^[\w\.-]+@[\w\.-]+\.\w+$",
|
|
295
|
+
match_mode="full"
|
|
296
|
+
)
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
【从 YAML 加载】
|
|
300
|
+
```python
|
|
301
|
+
raw = read_yaml(Path("regex_nodes/phone_number.regex.yaml"))
|
|
302
|
+
node = RegexNodeFile.model_validate(raw)
|
|
303
|
+
```
|
|
304
|
+
"""
|
|
305
|
+
|
|
306
|
+
# 配置版本号,固定为 2
|
|
307
|
+
version: int = Field(2, description="配置版本号(固定为 2)")
|
|
308
|
+
# Regex 节点 ID,稳定的唯一标识符
|
|
309
|
+
id: str = Field(..., description="Regex 节点 ID(稳定标识)")
|
|
310
|
+
# Regex 节点名称,用于展示和识别
|
|
311
|
+
name: str = Field(..., description="Regex 节点名称(展示用)")
|
|
312
|
+
# 节点的描述信息,说明节点的用途
|
|
313
|
+
description: str | None = Field(None, description="描述")
|
|
314
|
+
|
|
315
|
+
# ========== 引用模式(推荐使用) ==========
|
|
316
|
+
# 引用已注册的表达式模式,便于复用和管理
|
|
317
|
+
# 当使用此字段时,pattern 字段应为空
|
|
318
|
+
uses_pattern: PatternRef | None = Field(None, description="引用已注册的表达式模式(推荐使用,便于复用和管理)")
|
|
319
|
+
# 对引用表达式的覆盖配置
|
|
320
|
+
# 允许在引用时修改原始表达式的某些参数
|
|
321
|
+
# 支持的配置项:flags(正则标志)、case_sensitive(大小写敏感)等
|
|
322
|
+
pattern_overrides: dict[str, Any] | None = Field(
|
|
323
|
+
default_factory=dict, description="对引用表达式的覆盖配置(如 flags、case_sensitive 等)"
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
# ========== 直接模式(兼容使用) ==========
|
|
327
|
+
# 直接编写正则表达式字符串
|
|
328
|
+
# 建议使用 uses_pattern 引用模式,便于维护
|
|
329
|
+
pattern: str | None = Field(None, description="直接的正则表达式(建议使用 uses_pattern 引用模式)")
|
|
330
|
+
|
|
331
|
+
# ========== 通用配置 ==========
|
|
332
|
+
# 匹配模式,决定如何应用正则表达式
|
|
333
|
+
# - full: 完全匹配(整个字符串符合正则)
|
|
334
|
+
# - partial: 部分匹配(字符串包含符合正则的部分)
|
|
335
|
+
# - extract: 提取模式(提取匹配的部分)
|
|
336
|
+
match_mode: Literal["full", "partial", "extract"] = Field("full", description="匹配模式")
|
|
337
|
+
# 是否区分大小写
|
|
338
|
+
# §3.9: 默认 True(区分大小写)——与前端保存侧(regexBuilder !== false)和运行时
|
|
339
|
+
# 语义(未设置=敏感)三方一致;原 False 使手写 YAML 不设该字段时界面显示"不敏感"
|
|
340
|
+
# 而实际校验"敏感"(语义翻转)
|
|
341
|
+
case_sensitive: bool = Field(True, description="是否区分大小写")
|
|
342
|
+
# 正则 flags 字符串
|
|
343
|
+
# 支持:i (ignorecase), m (multiline), s (dotall) 等
|
|
344
|
+
flags: str = Field("", description="正则 flags 字符串")
|
|
345
|
+
# 是否启用该节点
|
|
346
|
+
# 禁用时在数据校验中会跳过该节点
|
|
347
|
+
enabled: bool = Field(True, description="是否启用")
|
|
348
|
+
# 参数列表,保留字段,用于前端扩展
|
|
349
|
+
parameters: list[dict[str, Any]] = Field(default_factory=list, description="参数列表(保留)")
|
|
350
|
+
# 规则列表,存储前端的 RegexDesign 结构
|
|
351
|
+
# 用于可视化编辑时的数据持久化
|
|
352
|
+
rules: list[dict[str, Any]] = Field(default_factory=list, description="规则列表(前端 RegexDesign 结构)")
|
|
353
|
+
# 数据流输入接口(新增)
|
|
354
|
+
# 若存在,优先于 source_ref 使用
|
|
355
|
+
input_from_node: str | None = Field(None, description="上游数据流节点 ID(优先于 source_ref)")
|
|
356
|
+
input_column: str | None = Field(None, description="上游节点中的目标列名")
|
|
357
|
+
|
|
358
|
+
# Extract 模式专用配置
|
|
359
|
+
# 当 match_mode="extract" 时,定义捕获组到输出列的映射
|
|
360
|
+
capture_groups: list[dict[str, Any]] = Field(
|
|
361
|
+
default_factory=list, description="Extract 模式下的捕获组定义 [{name, group_index}]"
|
|
362
|
+
)
|
|
363
|
+
output_columns: list[str] = Field(default_factory=list, description="Extract 模式下的输出列名列表")
|
|
364
|
+
|
|
365
|
+
# 上游表列引用,用于重建画布中的连线关系
|
|
366
|
+
source_ref: RegexSourceRef | None = Field(None, description="上游表列引用(用于重建连线)")
|
|
367
|
+
# 上游列名,兼容/展示用
|
|
368
|
+
source_column_name: str | None = Field(None, description="上游列名(兼容/展示用)")
|
|
369
|
+
|
|
370
|
+
@model_validator(mode="after")
|
|
371
|
+
def _validate_pattern_mode(self) -> RegexNodeFile:
|
|
372
|
+
"""
|
|
373
|
+
@methoddesc 验证必须使用引用模式或直接模式之一。
|
|
374
|
+
|
|
375
|
+
处理流程:
|
|
376
|
+
1. 检查 uses_pattern 字段是否有值(引用模式)
|
|
377
|
+
2. 检查 pattern 字段是否有值(直接模式)
|
|
378
|
+
3. 验证两种模式的互斥关系:
|
|
379
|
+
- 不能同时使用两者
|
|
380
|
+
- 必须至少使用其中之一
|
|
381
|
+
|
|
382
|
+
:return: 验证通过的 RegexNodeFile 对象
|
|
383
|
+
:raises ValueError: 当模式配置不符合要求时
|
|
384
|
+
"""
|
|
385
|
+
# 检查是否使用了引用模式
|
|
386
|
+
has_ref = self.uses_pattern is not None
|
|
387
|
+
# 检查是否使用了直接模式(需要非空且非空白字符串)
|
|
388
|
+
has_direct = self.pattern is not None and self.pattern.strip() != ""
|
|
389
|
+
|
|
390
|
+
# 验证:不能同时使用两种模式
|
|
391
|
+
if has_ref and has_direct:
|
|
392
|
+
raise ValueError("不能同时使用 'uses_pattern' 引用模式和 'pattern' 直接模式,请选择其一")
|
|
393
|
+
|
|
394
|
+
# 验证:必须至少使用一种模式
|
|
395
|
+
if not has_ref and not has_direct:
|
|
396
|
+
raise ValueError("必须使用 'uses_pattern' 引用模式或 'pattern' 直接模式之一")
|
|
397
|
+
|
|
398
|
+
return self
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
# 兼容别名
|
|
402
|
+
# 提供 V2 版本标识的别名,便于后续版本升级时的迁移
|
|
403
|
+
RegexSourceRefV2 = RegexSourceRef
|
|
404
|
+
PatternRefV2 = PatternRef
|
|
405
|
+
RegexNodeFileV2 = RegexNodeFile
|