turbine-core 1.0.0__tar.gz
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.
- turbine_core-1.0.0/.gitignore +56 -0
- turbine_core-1.0.0/PKG-INFO +58 -0
- turbine_core-1.0.0/README.md +25 -0
- turbine_core-1.0.0/formal/product_line.dfy +176 -0
- turbine_core-1.0.0/formal/thresholds.dfy +119 -0
- turbine_core-1.0.0/pyproject.toml +50 -0
- turbine_core-1.0.0/src/turbine/core/__init__.py +9 -0
- turbine_core-1.0.0/src/turbine/core/app/CONTRACTS +29 -0
- turbine_core-1.0.0/src/turbine/core/app/__init__.py +31 -0
- turbine_core-1.0.0/src/turbine/core/app/profile.py +759 -0
- turbine_core-1.0.0/src/turbine/core/app/project.py +152 -0
- turbine_core-1.0.0/src/turbine/core/app/runs.py +327 -0
- turbine_core-1.0.0/src/turbine/core/app/scaffold.py +544 -0
- turbine_core-1.0.0/src/turbine/core/app/serve_context.py +152 -0
- turbine_core-1.0.0/src/turbine/core/app/starters.py +697 -0
- turbine_core-1.0.0/src/turbine/core/app/turbine.py +199 -0
- turbine_core-1.0.0/src/turbine/core/catalog/CONTRACTS +111 -0
- turbine_core-1.0.0/src/turbine/core/catalog/__init__.py +1 -0
- turbine_core-1.0.0/src/turbine/core/catalog/check_types/__init__.py +1 -0
- turbine_core-1.0.0/src/turbine/core/catalog/check_types/arguments.py +412 -0
- turbine_core-1.0.0/src/turbine/core/catalog/check_types/check_type.py +720 -0
- turbine_core-1.0.0/src/turbine/core/catalog/check_types/common_fields.py +126 -0
- turbine_core-1.0.0/src/turbine/core/catalog/check_types/engine.py +628 -0
- turbine_core-1.0.0/src/turbine/core/catalog/check_types/engines.py +238 -0
- turbine_core-1.0.0/src/turbine/core/catalog/check_types/file.py +127 -0
- turbine_core-1.0.0/src/turbine/core/catalog/check_types/front_matter.py +424 -0
- turbine_core-1.0.0/src/turbine/core/catalog/check_types/installed.py +297 -0
- turbine_core-1.0.0/src/turbine/core/catalog/check_types/profile.py +114 -0
- turbine_core-1.0.0/src/turbine/core/catalog/check_types/schema_validation.py +546 -0
- turbine_core-1.0.0/src/turbine/core/catalog/check_types/side_inputs.py +71 -0
- turbine_core-1.0.0/src/turbine/core/catalog/check_types/spec.py +275 -0
- turbine_core-1.0.0/src/turbine/core/catalog/check_types/target.py +252 -0
- turbine_core-1.0.0/src/turbine/core/catalog/check_types/thresholds.py +373 -0
- turbine_core-1.0.0/src/turbine/core/catalog/check_types/variables.py +115 -0
- turbine_core-1.0.0/src/turbine/core/catalog/datasources/__init__.py +1 -0
- turbine_core-1.0.0/src/turbine/core/catalog/datasources/connections.py +1029 -0
- turbine_core-1.0.0/src/turbine/core/catalog/datasources/declarations.py +494 -0
- turbine_core-1.0.0/src/turbine/core/catalog/derivations.py +273 -0
- turbine_core-1.0.0/src/turbine/core/catalog/project_modules.py +154 -0
- turbine_core-1.0.0/src/turbine/core/catalog/validation_context.py +53 -0
- turbine_core-1.0.0/src/turbine/core/extension_points/__init__.py +4 -0
- turbine_core-1.0.0/src/turbine/core/extension_points/cli_command.py +331 -0
- turbine_core-1.0.0/src/turbine/core/extension_points/serve_part.py +223 -0
- turbine_core-1.0.0/src/turbine/core/flags/CONTRACTS +58 -0
- turbine_core-1.0.0/src/turbine/core/flags/__init__.py +1 -0
- turbine_core-1.0.0/src/turbine/core/flags/ledger.py +686 -0
- turbine_core-1.0.0/src/turbine/core/flags/model.py +142 -0
- turbine_core-1.0.0/src/turbine/core/flags/row_key.py +100 -0
- turbine_core-1.0.0/src/turbine/core/flags/scan.py +458 -0
- turbine_core-1.0.0/src/turbine/core/flags/statements.py +560 -0
- turbine_core-1.0.0/src/turbine/core/formats/CONTRACTS +70 -0
- turbine_core-1.0.0/src/turbine/core/formats/__init__.py +5 -0
- turbine_core-1.0.0/src/turbine/core/formats/authoring/__init__.py +1 -0
- turbine_core-1.0.0/src/turbine/core/formats/authoring/bindings.py +147 -0
- turbine_core-1.0.0/src/turbine/core/formats/authoring/build.py +184 -0
- turbine_core-1.0.0/src/turbine/core/formats/authoring/claims.py +194 -0
- turbine_core-1.0.0/src/turbine/core/formats/authoring/compiled.py +409 -0
- turbine_core-1.0.0/src/turbine/core/formats/authoring/constraints.py +236 -0
- turbine_core-1.0.0/src/turbine/core/formats/authoring/custom_properties.py +318 -0
- turbine_core-1.0.0/src/turbine/core/formats/authoring/fields.py +451 -0
- turbine_core-1.0.0/src/turbine/core/formats/authoring/json_schema.py +697 -0
- turbine_core-1.0.0/src/turbine/core/formats/authoring/keys.py +255 -0
- turbine_core-1.0.0/src/turbine/core/formats/authoring/model.py +346 -0
- turbine_core-1.0.0/src/turbine/core/formats/authoring/standard.py +194 -0
- turbine_core-1.0.0/src/turbine/core/formats/check_templates.py +530 -0
- turbine_core-1.0.0/src/turbine/core/formats/checks/__init__.py +1 -0
- turbine_core-1.0.0/src/turbine/core/formats/checks/grammar.py +858 -0
- turbine_core-1.0.0/src/turbine/core/formats/codec.py +366 -0
- turbine_core-1.0.0/src/turbine/core/formats/datasource/__init__.py +1 -0
- turbine_core-1.0.0/src/turbine/core/formats/datasource/adbc.py +816 -0
- turbine_core-1.0.0/src/turbine/core/formats/datasource/datasource.py +269 -0
- turbine_core-1.0.0/src/turbine/core/formats/datasource/datasource_types.py +733 -0
- turbine_core-1.0.0/src/turbine/core/formats/installed.py +222 -0
- turbine_core-1.0.0/src/turbine/core/formats/navigate/__init__.py +1 -0
- turbine_core-1.0.0/src/turbine/core/formats/navigate/cursor.py +317 -0
- turbine_core-1.0.0/src/turbine/core/formats/navigate/fixes.py +499 -0
- turbine_core-1.0.0/src/turbine/core/formats/navigate/queries.py +1005 -0
- turbine_core-1.0.0/src/turbine/core/formats/read/__init__.py +1 -0
- turbine_core-1.0.0/src/turbine/core/formats/read/check_compile.py +1191 -0
- turbine_core-1.0.0/src/turbine/core/formats/read/findings.py +658 -0
- turbine_core-1.0.0/src/turbine/core/formats/read/pydantic_errors.py +275 -0
- turbine_core-1.0.0/src/turbine/core/formats/read/validate.py +335 -0
- turbine_core-1.0.0/src/turbine/core/formats/refinement.py +73 -0
- turbine_core-1.0.0/src/turbine/core/formats/render/__init__.py +1 -0
- turbine_core-1.0.0/src/turbine/core/formats/render/check_entries.py +540 -0
- turbine_core-1.0.0/src/turbine/core/formats/render/starter.py +681 -0
- turbine_core-1.0.0/src/turbine/core/formats/tree/__init__.py +1 -0
- turbine_core-1.0.0/src/turbine/core/formats/tree/compile.py +197 -0
- turbine_core-1.0.0/src/turbine/core/formats/tree/declarations.py +126 -0
- turbine_core-1.0.0/src/turbine/core/formats/tree/declared.py +644 -0
- turbine_core-1.0.0/src/turbine/core/formats/tree/document.py +366 -0
- turbine_core-1.0.0/src/turbine/core/formats/tree/nodes.py +338 -0
- turbine_core-1.0.0/src/turbine/core/formats/write/__init__.py +1 -0
- turbine_core-1.0.0/src/turbine/core/formats/write/encode.py +309 -0
- turbine_core-1.0.0/src/turbine/core/hosts/__init__.py +1 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/CONTRACTS +30 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/__init__.py +1 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/__main__.py +17 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/completion.py +116 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/invoke.py +243 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/mount.py +177 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/output_policy.py +584 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/settings.py +240 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/shell.py +438 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/terminal/__init__.py +1 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/terminal/display/__init__.py +1 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/terminal/display/diagnostics.py +220 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/terminal/display/inventory.py +449 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/terminal/display/logo.py +133 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/terminal/display/profile.py +750 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/terminal/picker/__init__.py +3 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/terminal/picker/fuzzy.py +38 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/terminal/picker/picker.py +201 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/terminal/picker/renderer.py +148 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/terminal/picker/session.py +119 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/verbs/__init__.py +1 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/verbs/check.py +127 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/verbs/init.py +214 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/verbs/lint.py +114 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/verbs/migrate.py +155 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/verbs/new.py +503 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/verbs/profile.py +301 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/verbs/run.py +683 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/verbs/serve.py +205 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/verbs/status.py +314 -0
- turbine_core-1.0.0/src/turbine/core/hosts/cli/verbs/validate.py +57 -0
- turbine_core-1.0.0/src/turbine/core/hosts/editor/CONTRACTS +21 -0
- turbine_core-1.0.0/src/turbine/core/hosts/editor/__init__.py +8 -0
- turbine_core-1.0.0/src/turbine/core/hosts/editor/actions.py +389 -0
- turbine_core-1.0.0/src/turbine/core/hosts/editor/diagnostics.py +152 -0
- turbine_core-1.0.0/src/turbine/core/hosts/editor/environment.py +84 -0
- turbine_core-1.0.0/src/turbine/core/hosts/editor/feedback.py +70 -0
- turbine_core-1.0.0/src/turbine/core/hosts/editor/names.py +305 -0
- turbine_core-1.0.0/src/turbine/core/hosts/editor/protocol.py +155 -0
- turbine_core-1.0.0/src/turbine/core/hosts/editor/run.py +450 -0
- turbine_core-1.0.0/src/turbine/core/hosts/editor/scaffold.py +301 -0
- turbine_core-1.0.0/src/turbine/core/hosts/editor/schema.py +203 -0
- turbine_core-1.0.0/src/turbine/core/hosts/editor/server.py +929 -0
- turbine_core-1.0.0/src/turbine/core/hosts/editor/session.py +300 -0
- turbine_core-1.0.0/src/turbine/core/hosts/editor/symbols.py +187 -0
- turbine_core-1.0.0/src/turbine/core/hosts/editor/template.py +178 -0
- turbine_core-1.0.0/src/turbine/core/hosts/editor/workspace.py +156 -0
- turbine_core-1.0.0/src/turbine/core/hosts/serve/CONTRACTS +19 -0
- turbine_core-1.0.0/src/turbine/core/hosts/serve/__init__.py +1 -0
- turbine_core-1.0.0/src/turbine/core/hosts/serve/app.py +121 -0
- turbine_core-1.0.0/src/turbine/core/hosts/serve/host.py +146 -0
- turbine_core-1.0.0/src/turbine/core/hosts/serve/manage.py +435 -0
- turbine_core-1.0.0/src/turbine/core/hosts/serve/runs.py +203 -0
- turbine_core-1.0.0/src/turbine/core/model/__init__.py +27 -0
- turbine_core-1.0.0/src/turbine/core/model/baseline.py +140 -0
- turbine_core-1.0.0/src/turbine/core/model/column.py +270 -0
- turbine_core-1.0.0/src/turbine/core/model/data_product.py +297 -0
- turbine_core-1.0.0/src/turbine/core/model/dataset.py +238 -0
- turbine_core-1.0.0/src/turbine/core/model/extension_properties.py +72 -0
- turbine_core-1.0.0/src/turbine/core/model/fields.py +505 -0
- turbine_core-1.0.0/src/turbine/core/model/fixes.py +33 -0
- turbine_core-1.0.0/src/turbine/core/model/foreign_key.py +296 -0
- turbine_core-1.0.0/src/turbine/core/model/logical_type.py +157 -0
- turbine_core-1.0.0/src/turbine/core/model/metadata.py +213 -0
- turbine_core-1.0.0/src/turbine/core/model/product_versions.py +67 -0
- turbine_core-1.0.0/src/turbine/core/model/quality.py +722 -0
- turbine_core-1.0.0/src/turbine/core/model/rules.py +402 -0
- turbine_core-1.0.0/src/turbine/core/model/sla.py +222 -0
- turbine_core-1.0.0/src/turbine/core/model/unmodelled.py +52 -0
- turbine_core-1.0.0/src/turbine/core/plugins/__init__.py +1 -0
- turbine_core-1.0.0/src/turbine/core/plugins/admission_rules.py +288 -0
- turbine_core-1.0.0/src/turbine/core/plugins/catalog.py +292 -0
- turbine_core-1.0.0/src/turbine/core/plugins/check_specs.py +177 -0
- turbine_core-1.0.0/src/turbine/core/plugins/claims.py +100 -0
- turbine_core-1.0.0/src/turbine/core/plugins/contribution.py +104 -0
- turbine_core-1.0.0/src/turbine/core/plugins/declare.py +579 -0
- turbine_core-1.0.0/src/turbine/core/plugins/discovery.py +706 -0
- turbine_core-1.0.0/src/turbine/core/plugins/kernel.py +127 -0
- turbine_core-1.0.0/src/turbine/core/primitives.py +606 -0
- turbine_core-1.0.0/src/turbine/core/project/CONTRACTS +12 -0
- turbine_core-1.0.0/src/turbine/core/project/__init__.py +1 -0
- turbine_core-1.0.0/src/turbine/core/project/compile_findings.py +161 -0
- turbine_core-1.0.0/src/turbine/core/project/datasources.py +393 -0
- turbine_core-1.0.0/src/turbine/core/project/file_reader.py +369 -0
- turbine_core-1.0.0/src/turbine/core/project/findings.py +175 -0
- turbine_core-1.0.0/src/turbine/core/project/layout.py +432 -0
- turbine_core-1.0.0/src/turbine/core/project/merge.py +614 -0
- turbine_core-1.0.0/src/turbine/core/project/placed_findings.py +126 -0
- turbine_core-1.0.0/src/turbine/core/project/reference_sites.py +397 -0
- turbine_core-1.0.0/src/turbine/core/project/request_errors.py +43 -0
- turbine_core-1.0.0/src/turbine/core/project/rules/__init__.py +1 -0
- turbine_core-1.0.0/src/turbine/core/project/rules/derive.py +526 -0
- turbine_core-1.0.0/src/turbine/core/project/rules/engine.py +470 -0
- turbine_core-1.0.0/src/turbine/core/project/rules/project_rules.py +143 -0
- turbine_core-1.0.0/src/turbine/core/project/selection.py +255 -0
- turbine_core-1.0.0/src/turbine/core/project/server_binder.py +862 -0
- turbine_core-1.0.0/src/turbine/core/project/snapshot.py +729 -0
- turbine_core-1.0.0/src/turbine/core/project/snapshot_cache.py +83 -0
- turbine_core-1.0.0/src/turbine/core/project/views.py +378 -0
- turbine_core-1.0.0/src/turbine/core/reports/__init__.py +9 -0
- turbine_core-1.0.0/src/turbine/core/reports/flags.py +120 -0
- turbine_core-1.0.0/src/turbine/core/reports/lint.py +104 -0
- turbine_core-1.0.0/src/turbine/core/reports/profile.py +220 -0
- turbine_core-1.0.0/src/turbine/core/reports/run.py +756 -0
- turbine_core-1.0.0/src/turbine/core/reports/status.py +191 -0
- turbine_core-1.0.0/src/turbine/core/runs/CONTRACTS +109 -0
- turbine_core-1.0.0/src/turbine/core/runs/__init__.py +1 -0
- turbine_core-1.0.0/src/turbine/core/runs/baselines.py +75 -0
- turbine_core-1.0.0/src/turbine/core/runs/check_runs.py +479 -0
- turbine_core-1.0.0/src/turbine/core/runs/connection_opener.py +347 -0
- turbine_core-1.0.0/src/turbine/core/runs/coordinator.py +999 -0
- turbine_core-1.0.0/src/turbine/core/runs/dataset_checks.py +454 -0
- turbine_core-1.0.0/src/turbine/core/runs/findings.py +346 -0
- turbine_core-1.0.0/src/turbine/core/runs/history/CONTRACTS +65 -0
- turbine_core-1.0.0/src/turbine/core/runs/history/__init__.py +1 -0
- turbine_core-1.0.0/src/turbine/core/runs/history/migrations/0001_initial.sql +105 -0
- turbine_core-1.0.0/src/turbine/core/runs/history/migrator.py +251 -0
- turbine_core-1.0.0/src/turbine/core/runs/history/noop.py +50 -0
- turbine_core-1.0.0/src/turbine/core/runs/history/opener.py +245 -0
- turbine_core-1.0.0/src/turbine/core/runs/history/read.py +586 -0
- turbine_core-1.0.0/src/turbine/core/runs/history/schema.py +250 -0
- turbine_core-1.0.0/src/turbine/core/runs/history/store.py +253 -0
- turbine_core-1.0.0/src/turbine/core/runs/history/target.py +162 -0
- turbine_core-1.0.0/src/turbine/core/runs/history/write.py +348 -0
- turbine_core-1.0.0/src/turbine/core/runs/plan.py +921 -0
- turbine_core-1.0.0/src/turbine/core/runs/ports.py +254 -0
- turbine_core-1.0.0/src/turbine/core/runs/readiness.py +299 -0
- turbine_core-1.0.0/src/turbine/core/runs/result.py +583 -0
- turbine_core-1.0.0/src/turbine/core/runs/window.py +232 -0
- turbine_core-1.0.0/src/turbine/core/sdk/__init__.py +75 -0
- turbine_core-1.0.0/src/turbine/core/sdk/checks.py +42 -0
- turbine_core-1.0.0/src/turbine/core/sdk/cli.py +31 -0
- turbine_core-1.0.0/src/turbine/core/sdk/datasource.py +36 -0
- turbine_core-1.0.0/src/turbine/core/sdk/derive.py +15 -0
- turbine_core-1.0.0/src/turbine/core/sdk/engine.py +62 -0
- turbine_core-1.0.0/src/turbine/core/sdk/format.py +35 -0
- turbine_core-1.0.0/src/turbine/core/sdk/lint.py +18 -0
- turbine_core-1.0.0/src/turbine/core/sdk/nodes.py +67 -0
- turbine_core-1.0.0/src/turbine/core/sdk/testing.py +169 -0
- turbine_core-1.0.0/src/turbine/core/text/__init__.py +1 -0
- turbine_core-1.0.0/src/turbine/core/text/edits.py +230 -0
- turbine_core-1.0.0/src/turbine/core/text/entity_refs.py +188 -0
- turbine_core-1.0.0/src/turbine/core/text/finding.py +519 -0
- turbine_core-1.0.0/src/turbine/core/text/fixes.py +214 -0
- turbine_core-1.0.0/src/turbine/core/text/options.py +70 -0
- turbine_core-1.0.0/src/turbine/core/text/parsed_document.py +196 -0
- turbine_core-1.0.0/src/turbine/core/text/placed.py +80 -0
- turbine_core-1.0.0/src/turbine/core/text/positions.py +288 -0
- turbine_core-1.0.0/src/turbine/core/text/uris.py +65 -0
- turbine_core-1.0.0/src/turbine/core/text/yaml.py +739 -0
- turbine_core-1.0.0/src/turbine/core/text/yaml_writer.py +73 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Local system and Python files
|
|
2
|
+
.DS_Store
|
|
3
|
+
__pycache__/
|
|
4
|
+
*.py[cod]
|
|
5
|
+
.env
|
|
6
|
+
.venv/
|
|
7
|
+
|
|
8
|
+
# Builds and package metadata
|
|
9
|
+
/build/
|
|
10
|
+
dist/
|
|
11
|
+
*.egg-info/
|
|
12
|
+
target/
|
|
13
|
+
|
|
14
|
+
# Test and quality-tool output
|
|
15
|
+
.coverage
|
|
16
|
+
.coverage.*
|
|
17
|
+
htmlcov/
|
|
18
|
+
.hypothesis/
|
|
19
|
+
.pytest_cache/
|
|
20
|
+
.ruff_cache/
|
|
21
|
+
/tests/
|
|
22
|
+
|
|
23
|
+
# Local package credentials
|
|
24
|
+
.netrc
|
|
25
|
+
.pypirc
|
|
26
|
+
.beads/
|
|
27
|
+
ai-docs/
|
|
28
|
+
|
|
29
|
+
# Documentation build output
|
|
30
|
+
public/
|
|
31
|
+
|
|
32
|
+
# mutmut copies the sources here to mutate them
|
|
33
|
+
mutants/
|
|
34
|
+
|
|
35
|
+
# Generated tool/agent artifacts (graphify graphs, Pi subagent transcripts).
|
|
36
|
+
# These are machine output, not source, and must not be committed.
|
|
37
|
+
graphify-out/
|
|
38
|
+
outputs/
|
|
39
|
+
.serena/
|
|
40
|
+
*.lit.*
|
|
41
|
+
packages/turbine-serve/turbine-serve.pdf
|
|
42
|
+
.pi/
|
|
43
|
+
.pi-subagents/
|
|
44
|
+
.claude/settings.local.json
|
|
45
|
+
packages/turbine-core/.complexipy_cache/
|
|
46
|
+
|
|
47
|
+
# Impeccable design context and scratch work
|
|
48
|
+
.impeccable/
|
|
49
|
+
/DESIGN.md
|
|
50
|
+
/PRODUCT.md
|
|
51
|
+
scratch/
|
|
52
|
+
.cache/
|
|
53
|
+
.delta/
|
|
54
|
+
docs/assets/diagrams/turbine-extension-interface.html
|
|
55
|
+
.complexipy_cache/
|
|
56
|
+
.claude/
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: turbine-core
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Turbine kernel: project snapshots, check-run pipeline, extension registry, and entrypoints
|
|
5
|
+
Requires-Python: >=3.12
|
|
6
|
+
Requires-Dist: annotated-types>=0.8.0
|
|
7
|
+
Requires-Dist: asgiref>=3.12.1
|
|
8
|
+
Requires-Dist: cyclopts>=5.1.0
|
|
9
|
+
Requires-Dist: jsonschema>=4.26.0
|
|
10
|
+
Requires-Dist: prompt-toolkit>=3.0.53
|
|
11
|
+
Requires-Dist: pydantic-core>=2.46.4
|
|
12
|
+
Requires-Dist: pydantic>=2.13.4
|
|
13
|
+
Requires-Dist: python-dotenv>=1.2.3
|
|
14
|
+
Requires-Dist: referencing>=0.37.0
|
|
15
|
+
Requires-Dist: rich>=15.0.0
|
|
16
|
+
Requires-Dist: ruamel-yaml>=0.18.16
|
|
17
|
+
Requires-Dist: semver>=3.0.4
|
|
18
|
+
Requires-Dist: sqlglot>=30.16.0
|
|
19
|
+
Requires-Dist: tree-sitter-yaml>=0.7.2
|
|
20
|
+
Requires-Dist: tree-sitter>=0.26.0
|
|
21
|
+
Requires-Dist: typing-extensions>=4.16.0
|
|
22
|
+
Requires-Dist: typing-inspection>=0.4.4
|
|
23
|
+
Requires-Dist: tzdata>=2026.3
|
|
24
|
+
Provides-Extra: editor
|
|
25
|
+
Requires-Dist: lsprotocol>=2023.0.1; extra == 'editor'
|
|
26
|
+
Requires-Dist: pygls>=2; extra == 'editor'
|
|
27
|
+
Provides-Extra: serve
|
|
28
|
+
Requires-Dist: anyio>=4; extra == 'serve'
|
|
29
|
+
Requires-Dist: asgi-lifespan>=2.1.0; extra == 'serve'
|
|
30
|
+
Requires-Dist: litestar>=2.15; extra == 'serve'
|
|
31
|
+
Requires-Dist: uvicorn>=0.34; extra == 'serve'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# turbine-core
|
|
35
|
+
|
|
36
|
+
Turbine checks that your data agrees with its Data Contract. You describe a table in a YAML
|
|
37
|
+
file, and Turbine compares the file with the live table and tests the data against the rules
|
|
38
|
+
in the file.
|
|
39
|
+
|
|
40
|
+
`turbine-core` is the kernel. It gives the `turbine` command, the Project model, and the
|
|
41
|
+
check run. It has no formats, check types, or database drivers of its own. Those come from
|
|
42
|
+
an Extension, such as `turbine-data`.
|
|
43
|
+
|
|
44
|
+
## Install
|
|
45
|
+
|
|
46
|
+
Install `turbine-data` with the driver of your database. It installs `turbine-core` too:
|
|
47
|
+
|
|
48
|
+
```console
|
|
49
|
+
uv add "turbine-data[duckdb]"
|
|
50
|
+
uv run turbine --help
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`turbine-core` has two extras:
|
|
54
|
+
|
|
55
|
+
| Extra | What it adds |
|
|
56
|
+
| --- | --- |
|
|
57
|
+
| `serve` | The `turbine serve` command and the Management API |
|
|
58
|
+
| `editor` | `turbine-lsp`, the language server for an editor |
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# turbine-core
|
|
2
|
+
|
|
3
|
+
Turbine checks that your data agrees with its Data Contract. You describe a table in a YAML
|
|
4
|
+
file, and Turbine compares the file with the live table and tests the data against the rules
|
|
5
|
+
in the file.
|
|
6
|
+
|
|
7
|
+
`turbine-core` is the kernel. It gives the `turbine` command, the Project model, and the
|
|
8
|
+
check run. It has no formats, check types, or database drivers of its own. Those come from
|
|
9
|
+
an Extension, such as `turbine-data`.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
Install `turbine-data` with the driver of your database. It installs `turbine-core` too:
|
|
14
|
+
|
|
15
|
+
```console
|
|
16
|
+
uv add "turbine-data[duckdb]"
|
|
17
|
+
uv run turbine --help
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`turbine-core` has two extras:
|
|
21
|
+
|
|
22
|
+
| Extra | What it adds |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
| `serve` | The `turbine serve` command and the Management API |
|
|
25
|
+
| `editor` | `turbine-lsp`, the language server for an editor |
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
// Formal model of `ProductLine.latest`
|
|
2
|
+
// (turbine.core.application.load_project.product_line) over `ProductKey` order
|
|
3
|
+
// (turbine.core.domain.product.key).
|
|
4
|
+
//
|
|
5
|
+
// The rule: the highest SemVer whose contract is not dying, else the highest
|
|
6
|
+
// version with a warning. A product without a version sorts below every
|
|
7
|
+
// versioned one and never counts as the latest while a versioned one exists.
|
|
8
|
+
//
|
|
9
|
+
// Model gap: SemVer is abstracted to a `nat` rank that `ProductKey.sort_key`
|
|
10
|
+
// supplies; `lines_of` sorts by that key, so `versions` is ascending here.
|
|
11
|
+
|
|
12
|
+
datatype Product = Product(versioned: bool, rank: nat, dying: bool)
|
|
13
|
+
|
|
14
|
+
// `ProductKey.sort_key` order restricted to one id: unversioned first, then rank.
|
|
15
|
+
predicate Leq(a: Product, b: Product) {
|
|
16
|
+
(!a.versioned && b.versioned) ||
|
|
17
|
+
(a.versioned == b.versioned && a.rank <= b.rank)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
predicate Ascending(s: seq<Product>) {
|
|
21
|
+
forall i, j :: 0 <= i < j < |s| ==> Leq(s[i], s[j])
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// The two filters in `ProductLine.latest`, written out so Z3 can unfold them.
|
|
25
|
+
function Versioned(s: seq<Product>): seq<Product> {
|
|
26
|
+
if |s| == 0 then []
|
|
27
|
+
else if s[0].versioned then [s[0]] + Versioned(s[1..])
|
|
28
|
+
else Versioned(s[1..])
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function Live(s: seq<Product>): seq<Product> {
|
|
32
|
+
if |s| == 0 then []
|
|
33
|
+
else if !s[0].dying then [s[0]] + Live(s[1..])
|
|
34
|
+
else Live(s[1..])
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// `ProductLine.latest`, line for line.
|
|
38
|
+
function Latest(versions: seq<Product>): Product
|
|
39
|
+
requires |versions| > 0
|
|
40
|
+
{
|
|
41
|
+
var versioned := Versioned(versions);
|
|
42
|
+
var candidates := if |versioned| > 0 then versioned else versions;
|
|
43
|
+
var live := Live(candidates);
|
|
44
|
+
var pool := if |live| > 0 then live else candidates;
|
|
45
|
+
pool[|pool| - 1]
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// --- Facts about the filters -------------------------------------------------
|
|
49
|
+
|
|
50
|
+
lemma VersionedFacts(s: seq<Product>)
|
|
51
|
+
ensures forall p :: p in Versioned(s) <==> (p in s && p.versioned)
|
|
52
|
+
ensures Ascending(s) ==> Ascending(Versioned(s))
|
|
53
|
+
{
|
|
54
|
+
if |s| > 0 {
|
|
55
|
+
VersionedFacts(s[1..]);
|
|
56
|
+
if Ascending(s) {
|
|
57
|
+
assert Ascending(s[1..]);
|
|
58
|
+
var v := Versioned(s);
|
|
59
|
+
forall i, j | 0 <= i < j < |v| ensures Leq(v[i], v[j]) {
|
|
60
|
+
assert v[j] in s[1..];
|
|
61
|
+
if s[0].versioned && i == 0 {
|
|
62
|
+
var k :| 0 <= k < |s[1..]| && s[1..][k] == v[j];
|
|
63
|
+
assert Leq(s[0], s[k + 1]);
|
|
64
|
+
} else {
|
|
65
|
+
var v1 := Versioned(s[1..]);
|
|
66
|
+
var off := if s[0].versioned then 1 else 0;
|
|
67
|
+
assert v[i] == v1[i - off] && v[j] == v1[j - off];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
lemma LiveFacts(s: seq<Product>)
|
|
75
|
+
ensures forall p :: p in Live(s) <==> (p in s && !p.dying)
|
|
76
|
+
ensures Ascending(s) ==> Ascending(Live(s))
|
|
77
|
+
{
|
|
78
|
+
if |s| > 0 {
|
|
79
|
+
LiveFacts(s[1..]);
|
|
80
|
+
if Ascending(s) {
|
|
81
|
+
assert Ascending(s[1..]);
|
|
82
|
+
var v := Live(s);
|
|
83
|
+
forall i, j | 0 <= i < j < |v| ensures Leq(v[i], v[j]) {
|
|
84
|
+
assert v[j] in s[1..];
|
|
85
|
+
if !s[0].dying && i == 0 {
|
|
86
|
+
var k :| 0 <= k < |s[1..]| && s[1..][k] == v[j];
|
|
87
|
+
assert Leq(s[0], s[k + 1]);
|
|
88
|
+
} else {
|
|
89
|
+
var v1 := Live(s[1..]);
|
|
90
|
+
var off := if !s[0].dying then 1 else 0;
|
|
91
|
+
assert v[i] == v1[i - off] && v[j] == v1[j - off];
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
lemma LastIsMax(s: seq<Product>)
|
|
99
|
+
requires Ascending(s) && |s| > 0
|
|
100
|
+
ensures forall p :: p in s ==> Leq(p, s[|s| - 1])
|
|
101
|
+
{
|
|
102
|
+
forall p | p in s ensures Leq(p, s[|s| - 1]) {
|
|
103
|
+
var i :| 0 <= i < |s| && s[i] == p;
|
|
104
|
+
if i < |s| - 1 { assert Leq(s[i], s[|s| - 1]); }
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// --- Properties (tests/application/load_project/test_product_line.py) -------
|
|
109
|
+
|
|
110
|
+
// latest is one of the versions.
|
|
111
|
+
lemma LatestIsMember(versions: seq<Product>)
|
|
112
|
+
requires |versions| > 0
|
|
113
|
+
ensures Latest(versions) in versions
|
|
114
|
+
{
|
|
115
|
+
VersionedFacts(versions);
|
|
116
|
+
var candidates := if |Versioned(versions)| > 0 then Versioned(versions) else versions;
|
|
117
|
+
LiveFacts(candidates);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// "none-never-wins": while a versioned product exists, latest is versioned.
|
|
121
|
+
lemma LatestIsVersionedWhenAnyIs(versions: seq<Product>)
|
|
122
|
+
requires |versions| > 0
|
|
123
|
+
requires exists p :: p in versions && p.versioned
|
|
124
|
+
ensures Latest(versions).versioned
|
|
125
|
+
{
|
|
126
|
+
VersionedFacts(versions);
|
|
127
|
+
var versioned := Versioned(versions);
|
|
128
|
+
assert |versioned| > 0;
|
|
129
|
+
LiveFacts(versioned);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// "skips-dying": while a live versioned product exists, latest is live.
|
|
133
|
+
lemma LatestIsLiveWhenAnyIs(versions: seq<Product>)
|
|
134
|
+
requires |versions| > 0
|
|
135
|
+
requires exists p :: p in versions && p.versioned && !p.dying
|
|
136
|
+
ensures !Latest(versions).dying
|
|
137
|
+
{
|
|
138
|
+
VersionedFacts(versions);
|
|
139
|
+
var versioned := Versioned(versions);
|
|
140
|
+
assert |versioned| > 0;
|
|
141
|
+
LiveFacts(versioned);
|
|
142
|
+
assert |Live(versioned)| > 0;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// "highest-live": latest is the maximum of every eligible product.
|
|
146
|
+
lemma LatestIsHighestEligible(versions: seq<Product>)
|
|
147
|
+
requires |versions| > 0 && Ascending(versions)
|
|
148
|
+
requires exists p :: p in versions && p.versioned && !p.dying
|
|
149
|
+
ensures forall p :: p in versions && p.versioned && !p.dying ==> Leq(p, Latest(versions))
|
|
150
|
+
{
|
|
151
|
+
VersionedFacts(versions);
|
|
152
|
+
var versioned := Versioned(versions);
|
|
153
|
+
assert |versioned| > 0;
|
|
154
|
+
LiveFacts(versioned);
|
|
155
|
+
var live := Live(versioned);
|
|
156
|
+
assert |live| > 0;
|
|
157
|
+
LastIsMax(live);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// "all-dying-takes-highest": with no live versioned product, latest is the
|
|
161
|
+
// highest versioned one.
|
|
162
|
+
lemma LatestIsHighestWhenAllDying(versions: seq<Product>)
|
|
163
|
+
requires |versions| > 0 && Ascending(versions)
|
|
164
|
+
requires exists p :: p in versions && p.versioned
|
|
165
|
+
requires forall p :: p in versions && p.versioned ==> p.dying
|
|
166
|
+
ensures forall p :: p in versions && p.versioned ==> Leq(p, Latest(versions))
|
|
167
|
+
{
|
|
168
|
+
VersionedFacts(versions);
|
|
169
|
+
var versioned := Versioned(versions);
|
|
170
|
+
assert |versioned| > 0;
|
|
171
|
+
LiveFacts(versioned);
|
|
172
|
+
assert |Live(versioned)| == 0 by {
|
|
173
|
+
if |Live(versioned)| > 0 { assert Live(versioned)[0] in Live(versioned); }
|
|
174
|
+
}
|
|
175
|
+
LastIsMax(versioned);
|
|
176
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// Formal model of `turbine.core.domain.product.quality.threshold_holds`.
|
|
2
|
+
//
|
|
3
|
+
// The Python decides pass/fail of every Check Definition. This file states
|
|
4
|
+
// the same rule over reals and proves the properties the Hypothesis tests in
|
|
5
|
+
// tests/domain/test_thresholds.py sample. Verify with `dafny verify`.
|
|
6
|
+
//
|
|
7
|
+
// Model gap: Python measures with `Decimal(str(float))`; this model uses
|
|
8
|
+
// `real`. The Hypothesis tests cover that seam; the lemmas cover the logic.
|
|
9
|
+
|
|
10
|
+
datatype Option<T> = None | Some(value: T)
|
|
11
|
+
|
|
12
|
+
datatype Bound = Bound(value: real, exclusive: bool)
|
|
13
|
+
|
|
14
|
+
datatype Op = LT | LTE | GTE | GT
|
|
15
|
+
|
|
16
|
+
datatype Threshold =
|
|
17
|
+
| Exact(v: real)
|
|
18
|
+
| NotExact(v: real)
|
|
19
|
+
| Cmp(op: Op, v: real)
|
|
20
|
+
| Range(min: Option<Bound>, max: Option<Bound>)
|
|
21
|
+
| NotRange(lo: Bound, hi: Bound)
|
|
22
|
+
|
|
23
|
+
// `RangeThreshold.__post_init__`: at least one bound.
|
|
24
|
+
predicate WellFormed(t: Threshold) {
|
|
25
|
+
t.Range? ==> (t.min.Some? || t.max.Some?)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function Compare(op: Op, m: real, v: real): bool {
|
|
29
|
+
match op
|
|
30
|
+
case LT => m < v
|
|
31
|
+
case LTE => m <= v
|
|
32
|
+
case GT => m > v
|
|
33
|
+
case GTE => m >= v
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// `_above`
|
|
37
|
+
function Above(m: real, b: Option<Bound>): bool {
|
|
38
|
+
match b
|
|
39
|
+
case None => true
|
|
40
|
+
case Some(bound) => if bound.exclusive then m > bound.value else m >= bound.value
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// `_below`
|
|
44
|
+
function Below(m: real, b: Option<Bound>): bool {
|
|
45
|
+
match b
|
|
46
|
+
case None => true
|
|
47
|
+
case Some(bound) => if bound.exclusive then m < bound.value else m <= bound.value
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// `threshold_holds` for a present threshold and a present measurement.
|
|
51
|
+
function Holds(t: Threshold, m: real): bool {
|
|
52
|
+
match t
|
|
53
|
+
case Exact(v) => m == v
|
|
54
|
+
case NotExact(v) => m != v
|
|
55
|
+
case Cmp(op, v) => Compare(op, m, v)
|
|
56
|
+
case Range(lo, hi) => Above(m, lo) && Below(m, hi)
|
|
57
|
+
case NotRange(lo, hi) => !(Above(m, Some(lo)) && Below(m, Some(hi)))
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// `threshold_holds` including the two absent cases.
|
|
61
|
+
function HoldsOpt(t: Option<Threshold>, m: Option<real>): bool {
|
|
62
|
+
match t
|
|
63
|
+
case None => true
|
|
64
|
+
case Some(threshold) =>
|
|
65
|
+
match m
|
|
66
|
+
case None => false
|
|
67
|
+
case Some(measured) => Holds(threshold, measured)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// --- Properties -------------------------------------------------------------
|
|
71
|
+
|
|
72
|
+
// tests: test_not_range_is_the_complement_of_range
|
|
73
|
+
lemma NotRangeIsComplementOfRange(lo: Bound, hi: Bound, m: real)
|
|
74
|
+
ensures Holds(NotRange(lo, hi), m) == !Holds(Range(Some(lo), Some(hi)), m)
|
|
75
|
+
{}
|
|
76
|
+
|
|
77
|
+
// tests: test_an_exclusive_end_rejects_its_own_value
|
|
78
|
+
lemma InclusiveEndAcceptsItself(x: real)
|
|
79
|
+
ensures Holds(Range(Some(Bound(x, false)), None), x)
|
|
80
|
+
ensures Holds(Range(None, Some(Bound(x, false))), x)
|
|
81
|
+
{}
|
|
82
|
+
|
|
83
|
+
lemma ExclusiveEndRejectsItself(x: real)
|
|
84
|
+
ensures !Holds(Range(Some(Bound(x, true)), None), x)
|
|
85
|
+
ensures !Holds(Range(None, Some(Bound(x, true))), x)
|
|
86
|
+
{}
|
|
87
|
+
|
|
88
|
+
// Exact and NotExact are complements.
|
|
89
|
+
lemma ExactIsComplementOfNotExact(v: real, m: real)
|
|
90
|
+
ensures Holds(Exact(v), m) == !Holds(NotExact(v), m)
|
|
91
|
+
{}
|
|
92
|
+
|
|
93
|
+
// LT/GTE and LTE/GT are complements: no measurement is undecided.
|
|
94
|
+
lemma ComparisonsAreComplements(v: real, m: real)
|
|
95
|
+
ensures Holds(Cmp(LT, v), m) == !Holds(Cmp(GTE, v), m)
|
|
96
|
+
ensures Holds(Cmp(LTE, v), m) == !Holds(Cmp(GT, v), m)
|
|
97
|
+
{}
|
|
98
|
+
|
|
99
|
+
// A one-sided range is the matching comparison.
|
|
100
|
+
lemma OneSidedRangeIsComparison(v: real, m: real)
|
|
101
|
+
ensures Holds(Range(Some(Bound(v, false)), None), m) == Holds(Cmp(GTE, v), m)
|
|
102
|
+
ensures Holds(Range(Some(Bound(v, true)), None), m) == Holds(Cmp(GT, v), m)
|
|
103
|
+
ensures Holds(Range(None, Some(Bound(v, false))), m) == Holds(Cmp(LTE, v), m)
|
|
104
|
+
ensures Holds(Range(None, Some(Bound(v, true))), m) == Holds(Cmp(LT, v), m)
|
|
105
|
+
{}
|
|
106
|
+
|
|
107
|
+
// Tightening a bound never accepts more.
|
|
108
|
+
lemma ExclusiveIsStricter(lo: Bound, hi: Bound, m: real)
|
|
109
|
+
requires !lo.exclusive && !hi.exclusive
|
|
110
|
+
ensures Holds(Range(Some(Bound(lo.value, true)), Some(Bound(hi.value, true))), m)
|
|
111
|
+
==> Holds(Range(Some(lo), Some(hi)), m)
|
|
112
|
+
{}
|
|
113
|
+
|
|
114
|
+
// tests: test_threshold_holds_decision_table_at_the_edges
|
|
115
|
+
lemma AbsentCases(t: Threshold, m: real)
|
|
116
|
+
ensures HoldsOpt(None, Some(m))
|
|
117
|
+
ensures HoldsOpt(None, None)
|
|
118
|
+
ensures !HoldsOpt(Some(t), None)
|
|
119
|
+
{}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "turbine-core"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
description = "Turbine kernel: project snapshots, check-run pipeline, extension registry, and entrypoints"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"annotated-types>=0.8.0",
|
|
9
|
+
"asgiref>=3.12.1",
|
|
10
|
+
"cyclopts>=5.1.0",
|
|
11
|
+
"jsonschema>=4.26.0",
|
|
12
|
+
"prompt-toolkit>=3.0.53",
|
|
13
|
+
"pydantic>=2.13.4",
|
|
14
|
+
"pydantic-core>=2.46.4",
|
|
15
|
+
"python-dotenv>=1.2.3",
|
|
16
|
+
"referencing>=0.37.0",
|
|
17
|
+
"rich>=15.0.0",
|
|
18
|
+
"ruamel-yaml>=0.18.16",
|
|
19
|
+
"semver>=3.0.4",
|
|
20
|
+
"sqlglot>=30.16.0",
|
|
21
|
+
"tree-sitter>=0.26.0",
|
|
22
|
+
"tree-sitter-yaml>=0.7.2",
|
|
23
|
+
"typing-extensions>=4.16.0",
|
|
24
|
+
"typing-inspection>=0.4.4",
|
|
25
|
+
"tzdata>=2026.3",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.optional-dependencies]
|
|
29
|
+
editor = ["lsprotocol>=2023.0.1", "pygls>=2"]
|
|
30
|
+
serve = ["anyio>=4", "asgi-lifespan>=2.1.0", "litestar>=2.15", "uvicorn>=0.34"]
|
|
31
|
+
|
|
32
|
+
[project.scripts]
|
|
33
|
+
turbine = "turbine.core.hosts.cli.__main__:main"
|
|
34
|
+
turbine-lsp = "turbine.core.hosts.editor.server:main"
|
|
35
|
+
|
|
36
|
+
[build-system]
|
|
37
|
+
requires = ["hatchling"]
|
|
38
|
+
build-backend = "hatchling.build"
|
|
39
|
+
|
|
40
|
+
[tool.hatch.build.targets.wheel]
|
|
41
|
+
packages = ["src/turbine"]
|
|
42
|
+
|
|
43
|
+
[dependency-groups]
|
|
44
|
+
dev = ["duckdb>=1.5.5", "pyarrow>=25.0.1", "pytest>=9.1.1"]
|
|
45
|
+
|
|
46
|
+
[tool.mutmut]
|
|
47
|
+
source_paths = ["src/turbine"]
|
|
48
|
+
# format_model.py is excluded because mutmut breaks its metaclass generator.
|
|
49
|
+
do_not_mutate = ["src/turbine/core/authoring/format/declare/format_model.py"]
|
|
50
|
+
pytest_add_cli_args = ["-p", "no:tach", "tests"]
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Turbine kernel: define, check, and serve Data Products from their contracts."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
# A library does not choose where its log goes. Without a handler, Python
|
|
6
|
+
# prints each warning and error to stderr, and that would put driver text in
|
|
7
|
+
# the normal command output. `--debug` and the editor server add their own
|
|
8
|
+
# handler.
|
|
9
|
+
logging.getLogger("turbine").addHandler(logging.NullHandler())
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
@cc [owner:Yassimba] profile.measures-are-check-types
|
|
2
|
+
Applies only to `profile_table` in `profile.py`.
|
|
3
|
+
|
|
4
|
+
Each number in `measures` is the measurement that a Check Engine gives for an installed Check
|
|
5
|
+
Type. The profile holds no SQL for such a number, and it names no Check Type.
|
|
6
|
+
|
|
7
|
+
@cc [owner:Yassimba] profile.values-count-the-profiled-rows
|
|
8
|
+
Applies only to `profile_table` in `profile.py`.
|
|
9
|
+
|
|
10
|
+
The most frequent values and the histogram of a column read rows as the measures do: the rows
|
|
11
|
+
of the filter of the Dataset and of the time window, and at most `sample` of them.
|
|
12
|
+
|
|
13
|
+
@cc [owner:Yassimba] profile.read-only
|
|
14
|
+
Applies only to `profile_table` in `profile.py`.
|
|
15
|
+
|
|
16
|
+
A profile writes nothing: no table, no file, and no Run History.
|
|
17
|
+
|
|
18
|
+
@cc [owner:Yassimba] profile.sample-is-a-limit
|
|
19
|
+
Applies only to `profile_table` in `profile.py`.
|
|
20
|
+
|
|
21
|
+
No query of a profile sorts the rows of the table. `sample` is a row limit, so the database
|
|
22
|
+
stops when it has that many rows, in no order. `sample` 0 reads each row.
|
|
23
|
+
|
|
24
|
+
@cc [owner:Yassimba] profile.window-is-the-event-time
|
|
25
|
+
Applies only to `profile_table` in `profile.py`.
|
|
26
|
+
|
|
27
|
+
`since` and `until` keep the rows with `since <= event time < until`, by the event time of the
|
|
28
|
+
Dataset, as the Check Window of a Check Run does. A time for a table that has no event time
|
|
29
|
+
raises ProfileRefusedError before a query runs.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""The application: `Turbine`, the composition root that a host holds, and its verb families.
|
|
2
|
+
|
|
3
|
+
A host imports an `app` name from the module that defines it, for example
|
|
4
|
+
`turbine.core.app.turbine`. This module names only the kernel values that a
|
|
5
|
+
host needs but cannot import from their own context. The tach rules do not
|
|
6
|
+
let the CLI and serve hosts import `runs`, `project`, `catalog`, `flags`, or
|
|
7
|
+
`plugins`. The editor cannot import `runs`.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from turbine.core.catalog.datasources.connections import ConnectionOpener as ConnectionOpener
|
|
11
|
+
from turbine.core.catalog.datasources.connections import OpenableDatasource as OpenableDatasource
|
|
12
|
+
from turbine.core.catalog.datasources.declarations import TableIdentifier as TableIdentifier
|
|
13
|
+
from turbine.core.flags.model import UnknownFlaggedTableError as UnknownFlaggedTableError
|
|
14
|
+
from turbine.core.plugins.discovery import ExtensionDiscovery as ExtensionDiscovery
|
|
15
|
+
from turbine.core.project.layout import DEFAULT_MAX_CONCURRENCY as DEFAULT_MAX_CONCURRENCY
|
|
16
|
+
from turbine.core.project.layout import ProjectConfigError as ProjectConfigError
|
|
17
|
+
from turbine.core.project.layout import ProjectLayout as ProjectLayout
|
|
18
|
+
from turbine.core.project.request_errors import CheckRunError as CheckRunError
|
|
19
|
+
from turbine.core.project.request_errors import UnknownChoiceError as UnknownChoiceError
|
|
20
|
+
from turbine.core.project.rules.project_rules import LintRunError as LintRunError
|
|
21
|
+
from turbine.core.project.server_binder import ServerRequest as ServerRequest
|
|
22
|
+
from turbine.core.project.snapshot import ProjectSnapshot as ProjectSnapshot
|
|
23
|
+
from turbine.core.runs.history.store import RunHistoryPreparationError as RunHistoryPreparationError
|
|
24
|
+
from turbine.core.runs.plan import CheckRunRequest as CheckRunRequest
|
|
25
|
+
from turbine.core.runs.plan import CheckSelection as CheckSelection
|
|
26
|
+
from turbine.core.runs.plan import PlannedDataset as PlannedDataset
|
|
27
|
+
from turbine.core.runs.plan import RunId as RunId
|
|
28
|
+
from turbine.core.runs.plan import RunKind as RunKind
|
|
29
|
+
from turbine.core.runs.plan import RunPlan as RunPlan
|
|
30
|
+
from turbine.core.runs.ports import RunHistoryUnavailableError as RunHistoryUnavailableError
|
|
31
|
+
from turbine.core.runs.window import parse_time as parse_time
|