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,149 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2026 Precis Team
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
"""
|
|
17
|
+
@fileoverview Schema 辅助函数模块
|
|
18
|
+
|
|
19
|
+
功能概述:
|
|
20
|
+
- 提供 Schema 文件路径查找、冲突检测和合并等辅助函数
|
|
21
|
+
- 支持查找策略:manifest 引用、schemas/ 目录文件名匹配
|
|
22
|
+
- 用于 Schema CRUD API 的底层支撑
|
|
23
|
+
|
|
24
|
+
架构设计:
|
|
25
|
+
- 纯函数设计,无状态无副作用,便于单元测试
|
|
26
|
+
- 与 schema.py 路由层解耦,职责分离
|
|
27
|
+
- 使用 YAML 读取和 Pydantic 模型进行数据验证
|
|
28
|
+
|
|
29
|
+
输入示例:
|
|
30
|
+
path = _get_schema_path(manifest, "users", "/project/root")
|
|
31
|
+
conflicts = _compute_conflicts(existing_schema, new_schema)
|
|
32
|
+
merged = _merge_schemas(existing_schema, new_schema)
|
|
33
|
+
|
|
34
|
+
输出示例:
|
|
35
|
+
"/project/root/schemas/users.schema.yaml"
|
|
36
|
+
["columns", "constraints"]
|
|
37
|
+
{"version": 2, "id": "users", "columns": [...]}
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
import os
|
|
41
|
+
from typing import Any
|
|
42
|
+
|
|
43
|
+
from app.shared.core.project.manifest.types import ProjectManifestV2
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _get_schema_path(manifest: ProjectManifestV2, table_id: str, config_path: str) -> str | None:
|
|
47
|
+
"""
|
|
48
|
+
获取 schema 文件路径。
|
|
49
|
+
|
|
50
|
+
查找策略:
|
|
51
|
+
1. 从 manifest.schemas 中查找引用,并验证引用路径实际存在
|
|
52
|
+
2. 扫描 schemas/ 目录,按文件名(去除 .schema.yaml 后缀)= table_id 查找
|
|
53
|
+
(兼容直接以节点 ID 作为文件名的项目)
|
|
54
|
+
"""
|
|
55
|
+
ref = next((s for s in manifest.schemas if s.id == table_id), None)
|
|
56
|
+
if ref:
|
|
57
|
+
ref_path = os.path.join(config_path, ref.path)
|
|
58
|
+
if os.path.isfile(ref_path):
|
|
59
|
+
return ref_path
|
|
60
|
+
|
|
61
|
+
schemas_dir = os.path.join(config_path, "schemas")
|
|
62
|
+
if os.path.isdir(schemas_dir):
|
|
63
|
+
for filename in os.listdir(schemas_dir):
|
|
64
|
+
if filename.lower().endswith(".schema.yaml"):
|
|
65
|
+
tid = filename[:-12]
|
|
66
|
+
if tid == table_id:
|
|
67
|
+
return os.path.join(schemas_dir, filename)
|
|
68
|
+
return None
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _compute_conflicts(existing: dict[str, Any], new: dict[str, Any]) -> list[str]:
|
|
72
|
+
"""
|
|
73
|
+
计算两个 schema 之间的冲突字段。
|
|
74
|
+
|
|
75
|
+
比较策略:
|
|
76
|
+
- 顶层字段:version, id, name, source, sheet, columns, constraints, script_checks
|
|
77
|
+
- columns 列表:比较列 ID、name、type
|
|
78
|
+
- constraints 列表:比较约束 ID 和类型
|
|
79
|
+
"""
|
|
80
|
+
conflict_fields = []
|
|
81
|
+
|
|
82
|
+
for field in ["version", "id", "name", "source", "sheet", "columns", "constraints", "script_checks"]:
|
|
83
|
+
if field in existing and field in new:
|
|
84
|
+
if field == "columns":
|
|
85
|
+
existing_cols = existing.get("columns", [])
|
|
86
|
+
new_cols = new.get("columns", [])
|
|
87
|
+
if len(existing_cols) != len(new_cols):
|
|
88
|
+
conflict_fields.append(f"columns (数量: {len(existing_cols)} vs {len(new_cols)})")
|
|
89
|
+
else:
|
|
90
|
+
column_conflicts = []
|
|
91
|
+
for i, (ec, nc) in enumerate(zip(existing_cols, new_cols)):
|
|
92
|
+
if (
|
|
93
|
+
ec.get("id") != nc.get("id")
|
|
94
|
+
or ec.get("name") != nc.get("name")
|
|
95
|
+
or ec.get("type") != nc.get("type")
|
|
96
|
+
):
|
|
97
|
+
column_conflicts.append(f"columns[{i}]")
|
|
98
|
+
if column_conflicts:
|
|
99
|
+
conflict_fields.append("columns")
|
|
100
|
+
conflict_fields.extend(column_conflicts)
|
|
101
|
+
elif field == "constraints":
|
|
102
|
+
existing_constraints = existing.get("constraints", [])
|
|
103
|
+
new_constraints = new.get("constraints", [])
|
|
104
|
+
if len(existing_constraints) != len(new_constraints):
|
|
105
|
+
conflict_fields.append(f"constraints (数量: {len(existing_constraints)} vs {len(new_constraints)})")
|
|
106
|
+
elif existing[field] != new[field]:
|
|
107
|
+
conflict_fields.append(field)
|
|
108
|
+
elif field in existing or field in new:
|
|
109
|
+
conflict_fields.append(field)
|
|
110
|
+
|
|
111
|
+
return conflict_fields
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _merge_schemas(existing: dict[str, Any], new: dict[str, Any]) -> dict[str, Any]:
|
|
115
|
+
"""
|
|
116
|
+
合并两个 schema 配置。
|
|
117
|
+
|
|
118
|
+
合并策略:
|
|
119
|
+
- version: 使用新的
|
|
120
|
+
- id: 使用新的(必须一致)
|
|
121
|
+
- name: 使用新的
|
|
122
|
+
- source: 使用新的
|
|
123
|
+
- sheet: 使用新的
|
|
124
|
+
- columns: 使用新的(替换)
|
|
125
|
+
- constraints: 追加新的约束,保留已有的
|
|
126
|
+
- script_checks: 追加新的,保留已有的
|
|
127
|
+
"""
|
|
128
|
+
merged = existing.copy()
|
|
129
|
+
|
|
130
|
+
for field in ["version", "id", "name", "source", "sheet", "columns"]:
|
|
131
|
+
if field in new:
|
|
132
|
+
merged[field] = new[field]
|
|
133
|
+
|
|
134
|
+
if "constraints" in new:
|
|
135
|
+
existing_constraints = merged.get("constraints", [])
|
|
136
|
+
new_constraints = new.get("constraints", [])
|
|
137
|
+
existing_ids = {c.get("id") for c in existing_constraints}
|
|
138
|
+
for nc in new_constraints:
|
|
139
|
+
if nc.get("id") not in existing_ids:
|
|
140
|
+
existing_constraints.append(nc)
|
|
141
|
+
merged["constraints"] = existing_constraints
|
|
142
|
+
|
|
143
|
+
if "script_checks" in new:
|
|
144
|
+
existing_checks = merged.get("script_checks", [])
|
|
145
|
+
new_checks = new.get("script_checks", [])
|
|
146
|
+
existing_checks.extend(new_checks)
|
|
147
|
+
merged["script_checks"] = existing_checks
|
|
148
|
+
|
|
149
|
+
return merged
|
|
@@ -0,0 +1,399 @@
|
|
|
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 设置 API - 项目设置、校验设置、文件处理、脚本安全
|
|
18
|
+
|
|
19
|
+
功能概述:
|
|
20
|
+
- 提供项目各类设置的独立读写接口(ProjectSettings / Validation / FileProcessing / ScriptSecurity)
|
|
21
|
+
- 所有设置存储在 manifest 的 settings 字段中,保证原子性
|
|
22
|
+
- 支持按需加载与保存,减少前端数据传输
|
|
23
|
+
|
|
24
|
+
架构设计:
|
|
25
|
+
- 每个设置类别有独立的 GET/PUT 端点,避免全量覆盖
|
|
26
|
+
- 读取时解析 manifest,写入时仅更新对应子字段
|
|
27
|
+
- 使用 exclude_none=True 清理空值,保持 YAML 整洁
|
|
28
|
+
|
|
29
|
+
输入示例:
|
|
30
|
+
GET /config/settings
|
|
31
|
+
PUT /config/validation (body: ValidationSettingsV2)
|
|
32
|
+
|
|
33
|
+
输出示例:
|
|
34
|
+
ProjectSettingsV2 / ValidationSettingsV2 / FileProcessingSettingsV2 / ScriptSecuritySettingsV2
|
|
35
|
+
StandardResponse: 操作结果消息
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
import logging
|
|
39
|
+
import os
|
|
40
|
+
from collections.abc import Callable
|
|
41
|
+
from pathlib import Path
|
|
42
|
+
|
|
43
|
+
from fastapi import APIRouter, Depends, HTTPException
|
|
44
|
+
|
|
45
|
+
from app.api.dependencies import get_project_config_path
|
|
46
|
+
from app.shared.core.io.yaml import read_yaml, write_yaml_atomic
|
|
47
|
+
from app.shared.core.project.manifest.types import ProjectManifestV2
|
|
48
|
+
|
|
49
|
+
from .base import (
|
|
50
|
+
FileProcessingSettingsV2,
|
|
51
|
+
ProjectSettingsV2,
|
|
52
|
+
ScriptSecuritySettingsV2,
|
|
53
|
+
StandardResponse,
|
|
54
|
+
ValidationSettingsV2,
|
|
55
|
+
_v2_manifest_path,
|
|
56
|
+
)
|
|
57
|
+
from .helpers import project_lock
|
|
58
|
+
|
|
59
|
+
router = APIRouter(prefix="", tags=["Project-Settings"])
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _save_manifest_field(
|
|
63
|
+
config_path: str,
|
|
64
|
+
apply: Callable[[ProjectManifestV2], None],
|
|
65
|
+
*,
|
|
66
|
+
read_log: str,
|
|
67
|
+
write_log: str,
|
|
68
|
+
success_message: str,
|
|
69
|
+
) -> dict[str, str]:
|
|
70
|
+
"""读取 manifest → 修改指定字段 → 写回的通用辅助函数。
|
|
71
|
+
|
|
72
|
+
所有 PUT 端点共享此逻辑,仅 apply 回调(修改哪个字段)和文案不同。
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
config_path: 项目配置根目录
|
|
76
|
+
apply: 接收 manifest 对象并就地修改目标字段的回调
|
|
77
|
+
read_log: 读取失败时的日志消息
|
|
78
|
+
write_log: 写入失败时的日志消息
|
|
79
|
+
success_message: 成功时返回给前端的消息
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
{"message": success_message}
|
|
83
|
+
"""
|
|
84
|
+
manifest_path = _v2_manifest_path(config_path)
|
|
85
|
+
if not os.path.isfile(manifest_path):
|
|
86
|
+
raise HTTPException(
|
|
87
|
+
status_code=404,
|
|
88
|
+
detail={
|
|
89
|
+
# §2.1: 结构化错误码统一(与 dependencies.py 的 manifest 缺失出口同构),
|
|
90
|
+
# 前端按 detail.code 识别项目失效并触发自愈
|
|
91
|
+
"code": "PROJECT_NOT_FOUND",
|
|
92
|
+
"message": f"项目配置文件(project.precis.yaml)不存在,请确认项目是否已被移动或删除(配置目录: {manifest_path})",
|
|
93
|
+
"path": str(
|
|
94
|
+
config_path
|
|
95
|
+
), # §2.1: 项目根目录(前端与 activeProjectPath 同口径比对,勿传 manifest 文件路径)
|
|
96
|
+
},
|
|
97
|
+
)
|
|
98
|
+
try:
|
|
99
|
+
raw = read_yaml(Path(manifest_path))
|
|
100
|
+
manifest = ProjectManifestV2.model_validate(raw)
|
|
101
|
+
except Exception as exc:
|
|
102
|
+
logging.getLogger(__name__).exception(read_log)
|
|
103
|
+
raise HTTPException(status_code=500, detail=f"设置文件读取失败: {exc}")
|
|
104
|
+
apply(manifest)
|
|
105
|
+
try:
|
|
106
|
+
with project_lock(config_path):
|
|
107
|
+
write_yaml_atomic(Path(manifest_path), manifest.model_dump(exclude_none=True))
|
|
108
|
+
except Exception as exc:
|
|
109
|
+
logging.getLogger(__name__).exception(write_log)
|
|
110
|
+
raise HTTPException(status_code=500, detail=f"设置文件保存失败: {exc}")
|
|
111
|
+
return {"message": success_message}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@router.get(
|
|
115
|
+
"/config/settings",
|
|
116
|
+
response_model=ProjectSettingsV2,
|
|
117
|
+
summary="读取当前项目的设置",
|
|
118
|
+
responses={
|
|
119
|
+
404: {"description": "项目配置文件(project.precis.yaml)不存在"},
|
|
120
|
+
500: {"description": "设置文件读取失败"},
|
|
121
|
+
},
|
|
122
|
+
)
|
|
123
|
+
def get_v2_project_settings(config_path: str = Depends(get_project_config_path)) -> ProjectSettingsV2:
|
|
124
|
+
"""
|
|
125
|
+
读取当前项目的设置(从 project.precis.yaml 的 settings 字段)。
|
|
126
|
+
|
|
127
|
+
使用场景:
|
|
128
|
+
- 前端加载项目设置界面
|
|
129
|
+
- 需要获取项目的通用配置
|
|
130
|
+
|
|
131
|
+
副作用:
|
|
132
|
+
- 如果 manifest 文件不存在,返回 404 错误
|
|
133
|
+
|
|
134
|
+
参数:
|
|
135
|
+
config_path: 项目配置根目录(通过 Depends 注入)
|
|
136
|
+
|
|
137
|
+
返回:
|
|
138
|
+
ProjectSettingsV2: 项目设置对象
|
|
139
|
+
"""
|
|
140
|
+
manifest_path = _v2_manifest_path(config_path)
|
|
141
|
+
if not os.path.isfile(manifest_path):
|
|
142
|
+
raise HTTPException(
|
|
143
|
+
status_code=404,
|
|
144
|
+
detail={
|
|
145
|
+
# §2.1: 结构化错误码统一(与 dependencies.py 的 manifest 缺失出口同构),
|
|
146
|
+
# 前端按 detail.code 识别项目失效并触发自愈
|
|
147
|
+
"code": "PROJECT_NOT_FOUND",
|
|
148
|
+
"message": f"项目配置文件(project.precis.yaml)不存在,请确认项目是否已被移动或删除(配置目录: {manifest_path})",
|
|
149
|
+
"path": str(
|
|
150
|
+
config_path
|
|
151
|
+
), # §2.1: 项目根目录(前端与 activeProjectPath 同口径比对,勿传 manifest 文件路径)
|
|
152
|
+
},
|
|
153
|
+
)
|
|
154
|
+
try:
|
|
155
|
+
raw = read_yaml(Path(manifest_path))
|
|
156
|
+
manifest = ProjectManifestV2.model_validate(raw)
|
|
157
|
+
except Exception as exc:
|
|
158
|
+
logging.getLogger(__name__).exception("Failed to read project settings")
|
|
159
|
+
raise HTTPException(status_code=500, detail=f"设置文件读取失败: {exc}")
|
|
160
|
+
return manifest.settings
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
@router.put(
|
|
164
|
+
"/config/settings",
|
|
165
|
+
response_model=StandardResponse,
|
|
166
|
+
summary="写入当前项目的设置",
|
|
167
|
+
responses={
|
|
168
|
+
404: {"description": "项目配置文件(project.precis.yaml)不存在"},
|
|
169
|
+
500: {"description": "设置文件保存失败"},
|
|
170
|
+
},
|
|
171
|
+
)
|
|
172
|
+
def put_v2_project_settings(
|
|
173
|
+
settings: ProjectSettingsV2, config_path: str = Depends(get_project_config_path)
|
|
174
|
+
) -> dict[str, str]:
|
|
175
|
+
"""
|
|
176
|
+
写入当前项目的设置(更新 project.precis.yaml 的 settings 字段)。
|
|
177
|
+
|
|
178
|
+
使用场景:
|
|
179
|
+
- 用户修改项目设置后保存
|
|
180
|
+
|
|
181
|
+
副作用:
|
|
182
|
+
- 直接覆盖 manifest 中的 settings 字段
|
|
183
|
+
- 使用 exclude_none=True 清理空值
|
|
184
|
+
|
|
185
|
+
参数:
|
|
186
|
+
settings: 新的项目设置
|
|
187
|
+
config_path: 项目配置根目录(通过 Depends 注入)
|
|
188
|
+
|
|
189
|
+
返回:
|
|
190
|
+
StandardResponse: 操作结果消息
|
|
191
|
+
"""
|
|
192
|
+
return _save_manifest_field(
|
|
193
|
+
config_path,
|
|
194
|
+
lambda m: setattr(m, "settings", settings),
|
|
195
|
+
read_log="Failed to read project settings for update",
|
|
196
|
+
write_log="Failed to write project settings",
|
|
197
|
+
success_message="项目设置已保存。",
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
@router.get(
|
|
202
|
+
"/config/validation",
|
|
203
|
+
response_model=ValidationSettingsV2,
|
|
204
|
+
summary="读取当前项目的校验行为设置",
|
|
205
|
+
responses={
|
|
206
|
+
500: {"description": "服务器内部错误"},
|
|
207
|
+
},
|
|
208
|
+
)
|
|
209
|
+
def get_v2_validation_settings(config_path: str = Depends(get_project_config_path)) -> ValidationSettingsV2:
|
|
210
|
+
"""
|
|
211
|
+
读取当前项目的校验行为设置。
|
|
212
|
+
|
|
213
|
+
使用场景:
|
|
214
|
+
- 前端加载校验设置界面
|
|
215
|
+
- 全量校验时获取校验配置
|
|
216
|
+
|
|
217
|
+
副作用:
|
|
218
|
+
- 调用 get_v2_project_settings 获取完整设置
|
|
219
|
+
|
|
220
|
+
参数:
|
|
221
|
+
config_path: 项目配置根目录(通过 Depends 注入)
|
|
222
|
+
|
|
223
|
+
返回:
|
|
224
|
+
ValidationSettingsV2: 校验设置对象
|
|
225
|
+
"""
|
|
226
|
+
settings = get_v2_project_settings(config_path)
|
|
227
|
+
return settings.validation
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
@router.put(
|
|
231
|
+
"/config/validation",
|
|
232
|
+
response_model=StandardResponse,
|
|
233
|
+
summary="写入当前项目的校验行为设置",
|
|
234
|
+
responses={
|
|
235
|
+
404: {"description": "项目配置文件(project.precis.yaml)不存在"},
|
|
236
|
+
500: {"description": "设置文件保存失败"},
|
|
237
|
+
},
|
|
238
|
+
)
|
|
239
|
+
def put_v2_validation_settings(
|
|
240
|
+
validation: ValidationSettingsV2, config_path: str = Depends(get_project_config_path)
|
|
241
|
+
) -> dict[str, str]:
|
|
242
|
+
"""
|
|
243
|
+
写入当前项目的校验行为设置。
|
|
244
|
+
|
|
245
|
+
使用场景:
|
|
246
|
+
- 用户修改校验设置后保存
|
|
247
|
+
|
|
248
|
+
副作用:
|
|
249
|
+
- 只更新 settings.validation 字段
|
|
250
|
+
- 保留其他 settings 字段不变
|
|
251
|
+
|
|
252
|
+
参数:
|
|
253
|
+
validation: 新的校验设置
|
|
254
|
+
config_path: 项目配置根目录(通过 Depends 注入)
|
|
255
|
+
|
|
256
|
+
返回:
|
|
257
|
+
StandardResponse: 操作结果消息
|
|
258
|
+
"""
|
|
259
|
+
return _save_manifest_field(
|
|
260
|
+
config_path,
|
|
261
|
+
lambda m: setattr(m.settings, "validation", validation),
|
|
262
|
+
read_log="Failed to read validation settings",
|
|
263
|
+
write_log="Failed to write validation settings",
|
|
264
|
+
success_message="校验设置已保存。",
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
@router.get(
|
|
269
|
+
"/config/file-processing",
|
|
270
|
+
response_model=FileProcessingSettingsV2,
|
|
271
|
+
summary="读取当前项目的文件处理设置",
|
|
272
|
+
responses={
|
|
273
|
+
500: {"description": "服务器内部错误"},
|
|
274
|
+
},
|
|
275
|
+
)
|
|
276
|
+
def get_v2_file_processing_settings(config_path: str = Depends(get_project_config_path)) -> FileProcessingSettingsV2:
|
|
277
|
+
"""
|
|
278
|
+
读取当前项目的文件处理设置。
|
|
279
|
+
|
|
280
|
+
使用场景:
|
|
281
|
+
- 前端加载文件处理设置界面
|
|
282
|
+
- 数据加载时获取文件编码、分隔符等配置
|
|
283
|
+
|
|
284
|
+
副作用:
|
|
285
|
+
- 调用 get_v2_project_settings 获取完整设置
|
|
286
|
+
|
|
287
|
+
参数:
|
|
288
|
+
config_path: 项目配置根目录(通过 Depends 注入)
|
|
289
|
+
|
|
290
|
+
返回:
|
|
291
|
+
FileProcessingSettingsV2: 文件处理设置对象
|
|
292
|
+
"""
|
|
293
|
+
settings = get_v2_project_settings(config_path)
|
|
294
|
+
return settings.file_processing
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
@router.put(
|
|
298
|
+
"/config/file-processing",
|
|
299
|
+
response_model=StandardResponse,
|
|
300
|
+
summary="写入当前项目的文件处理设置",
|
|
301
|
+
responses={
|
|
302
|
+
404: {"description": "项目配置文件(project.precis.yaml)不存在"},
|
|
303
|
+
500: {"description": "设置文件保存失败"},
|
|
304
|
+
},
|
|
305
|
+
)
|
|
306
|
+
def put_v2_file_processing_settings(
|
|
307
|
+
file_processing: FileProcessingSettingsV2, config_path: str = Depends(get_project_config_path)
|
|
308
|
+
) -> dict[str, str]:
|
|
309
|
+
"""
|
|
310
|
+
写入当前项目的文件处理设置。
|
|
311
|
+
|
|
312
|
+
使用场景:
|
|
313
|
+
- 用户修改文件处理设置后保存(如 CSV 分隔符、编码等)
|
|
314
|
+
|
|
315
|
+
副作用:
|
|
316
|
+
- 只更新 settings.file_processing 字段
|
|
317
|
+
- 保留其他 settings 字段不变
|
|
318
|
+
|
|
319
|
+
参数:
|
|
320
|
+
file_processing: 新的文件处理设置
|
|
321
|
+
config_path: 项目配置根目录(通过 Depends 注入)
|
|
322
|
+
|
|
323
|
+
返回:
|
|
324
|
+
StandardResponse: 操作结果消息
|
|
325
|
+
"""
|
|
326
|
+
return _save_manifest_field(
|
|
327
|
+
config_path,
|
|
328
|
+
lambda m: setattr(m.settings, "file_processing", file_processing),
|
|
329
|
+
read_log="Failed to read file-processing settings",
|
|
330
|
+
write_log="Failed to write file-processing settings",
|
|
331
|
+
success_message="文件处理设置已保存。",
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
@router.get(
|
|
336
|
+
"/config/script-security",
|
|
337
|
+
response_model=ScriptSecuritySettingsV2,
|
|
338
|
+
summary="读取当前项目的脚本安全设置",
|
|
339
|
+
responses={
|
|
340
|
+
500: {"description": "服务器内部错误"},
|
|
341
|
+
},
|
|
342
|
+
)
|
|
343
|
+
def get_v2_script_security_settings(config_path: str = Depends(get_project_config_path)) -> ScriptSecuritySettingsV2:
|
|
344
|
+
"""
|
|
345
|
+
读取当前项目的脚本安全设置。
|
|
346
|
+
|
|
347
|
+
使用场景:
|
|
348
|
+
- 前端加载脚本安全设置界面
|
|
349
|
+
- 约束校验时判断是否允许 eval/exec
|
|
350
|
+
|
|
351
|
+
副作用:
|
|
352
|
+
- 调用 get_v2_project_settings 获取完整设置
|
|
353
|
+
|
|
354
|
+
参数:
|
|
355
|
+
config_path: 项目配置根目录(通过 Depends 注入)
|
|
356
|
+
|
|
357
|
+
返回:
|
|
358
|
+
ScriptSecuritySettingsV2: 脚本安全设置对象
|
|
359
|
+
"""
|
|
360
|
+
settings = get_v2_project_settings(config_path)
|
|
361
|
+
return settings.script_security
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
@router.put(
|
|
365
|
+
"/config/script-security",
|
|
366
|
+
response_model=StandardResponse,
|
|
367
|
+
summary="写入当前项目的脚本安全设置",
|
|
368
|
+
responses={
|
|
369
|
+
404: {"description": "项目配置文件(project.precis.yaml)不存在"},
|
|
370
|
+
500: {"description": "设置文件保存失败"},
|
|
371
|
+
},
|
|
372
|
+
)
|
|
373
|
+
def put_v2_script_security_settings(
|
|
374
|
+
script_security: ScriptSecuritySettingsV2, config_path: str = Depends(get_project_config_path)
|
|
375
|
+
) -> dict[str, str]:
|
|
376
|
+
"""
|
|
377
|
+
写入当前项目的脚本安全设置。
|
|
378
|
+
|
|
379
|
+
使用场景:
|
|
380
|
+
- 用户修改脚本安全设置后保存(如是否允许 eval/exec)
|
|
381
|
+
|
|
382
|
+
副作用:
|
|
383
|
+
- 只更新 settings.script_security 字段
|
|
384
|
+
- 保留其他 settings 字段不变
|
|
385
|
+
|
|
386
|
+
参数:
|
|
387
|
+
script_security: 新的脚本安全设置
|
|
388
|
+
config_path: 项目配置根目录(通过 Depends 注入)
|
|
389
|
+
|
|
390
|
+
返回:
|
|
391
|
+
StandardResponse: 操作结果消息
|
|
392
|
+
"""
|
|
393
|
+
return _save_manifest_field(
|
|
394
|
+
config_path,
|
|
395
|
+
lambda m: setattr(m.settings, "script_security", script_security),
|
|
396
|
+
read_log="Failed to read script-security settings",
|
|
397
|
+
write_log="Failed to write script-security settings",
|
|
398
|
+
success_message="脚本安全设置已保存。",
|
|
399
|
+
)
|