sqlmesh 0.217.1.dev1__py3-none-any.whl → 0.227.2.dev20__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.
- sqlmesh/__init__.py +12 -2
- sqlmesh/_version.py +2 -2
- sqlmesh/cli/project_init.py +10 -2
- sqlmesh/core/_typing.py +1 -0
- sqlmesh/core/audit/definition.py +8 -2
- sqlmesh/core/config/__init__.py +1 -1
- sqlmesh/core/config/connection.py +20 -5
- sqlmesh/core/config/dbt.py +13 -0
- sqlmesh/core/config/janitor.py +12 -0
- sqlmesh/core/config/loader.py +7 -0
- sqlmesh/core/config/model.py +2 -0
- sqlmesh/core/config/root.py +3 -0
- sqlmesh/core/console.py +80 -2
- sqlmesh/core/constants.py +1 -1
- sqlmesh/core/context.py +112 -35
- sqlmesh/core/dialect.py +3 -0
- sqlmesh/core/engine_adapter/_typing.py +2 -0
- sqlmesh/core/engine_adapter/base.py +330 -23
- sqlmesh/core/engine_adapter/base_postgres.py +17 -1
- sqlmesh/core/engine_adapter/bigquery.py +146 -7
- sqlmesh/core/engine_adapter/clickhouse.py +17 -13
- sqlmesh/core/engine_adapter/databricks.py +50 -2
- sqlmesh/core/engine_adapter/fabric.py +110 -29
- sqlmesh/core/engine_adapter/mixins.py +142 -48
- sqlmesh/core/engine_adapter/mssql.py +15 -4
- sqlmesh/core/engine_adapter/mysql.py +2 -2
- sqlmesh/core/engine_adapter/postgres.py +9 -3
- sqlmesh/core/engine_adapter/redshift.py +4 -0
- sqlmesh/core/engine_adapter/risingwave.py +1 -0
- sqlmesh/core/engine_adapter/shared.py +6 -0
- sqlmesh/core/engine_adapter/snowflake.py +82 -11
- sqlmesh/core/engine_adapter/spark.py +14 -10
- sqlmesh/core/engine_adapter/trino.py +5 -2
- sqlmesh/core/janitor.py +181 -0
- sqlmesh/core/lineage.py +1 -0
- sqlmesh/core/linter/rules/builtin.py +15 -0
- sqlmesh/core/loader.py +17 -30
- sqlmesh/core/macros.py +35 -13
- sqlmesh/core/model/common.py +2 -0
- sqlmesh/core/model/definition.py +72 -4
- sqlmesh/core/model/kind.py +66 -2
- sqlmesh/core/model/meta.py +107 -2
- sqlmesh/core/node.py +101 -2
- sqlmesh/core/plan/builder.py +15 -10
- sqlmesh/core/plan/common.py +196 -2
- sqlmesh/core/plan/definition.py +21 -6
- sqlmesh/core/plan/evaluator.py +72 -113
- sqlmesh/core/plan/explainer.py +90 -8
- sqlmesh/core/plan/stages.py +42 -21
- sqlmesh/core/renderer.py +26 -18
- sqlmesh/core/scheduler.py +60 -19
- sqlmesh/core/selector.py +137 -9
- sqlmesh/core/signal.py +64 -1
- sqlmesh/core/snapshot/__init__.py +1 -0
- sqlmesh/core/snapshot/definition.py +109 -25
- sqlmesh/core/snapshot/evaluator.py +610 -50
- sqlmesh/core/state_sync/__init__.py +0 -1
- sqlmesh/core/state_sync/base.py +31 -27
- sqlmesh/core/state_sync/cache.py +12 -4
- sqlmesh/core/state_sync/common.py +216 -111
- sqlmesh/core/state_sync/db/facade.py +30 -15
- sqlmesh/core/state_sync/db/interval.py +27 -7
- sqlmesh/core/state_sync/db/migrator.py +14 -8
- sqlmesh/core/state_sync/db/snapshot.py +119 -87
- sqlmesh/core/table_diff.py +2 -2
- sqlmesh/core/test/definition.py +14 -9
- sqlmesh/core/test/discovery.py +4 -0
- sqlmesh/dbt/adapter.py +20 -11
- sqlmesh/dbt/basemodel.py +52 -41
- sqlmesh/dbt/builtin.py +27 -11
- sqlmesh/dbt/column.py +17 -5
- sqlmesh/dbt/common.py +4 -2
- sqlmesh/dbt/context.py +14 -1
- sqlmesh/dbt/loader.py +60 -8
- sqlmesh/dbt/manifest.py +136 -8
- sqlmesh/dbt/model.py +105 -25
- sqlmesh/dbt/package.py +16 -1
- sqlmesh/dbt/profile.py +3 -3
- sqlmesh/dbt/project.py +12 -7
- sqlmesh/dbt/seed.py +1 -1
- sqlmesh/dbt/source.py +6 -1
- sqlmesh/dbt/target.py +25 -6
- sqlmesh/dbt/test.py +31 -1
- sqlmesh/integrations/github/cicd/controller.py +6 -2
- sqlmesh/lsp/context.py +4 -2
- sqlmesh/magics.py +1 -1
- sqlmesh/migrations/v0000_baseline.py +3 -6
- sqlmesh/migrations/v0061_mysql_fix_blob_text_type.py +2 -5
- sqlmesh/migrations/v0062_add_model_gateway.py +2 -2
- sqlmesh/migrations/v0063_change_signals.py +2 -4
- sqlmesh/migrations/v0064_join_when_matched_strings.py +2 -4
- sqlmesh/migrations/v0065_add_model_optimize.py +2 -2
- sqlmesh/migrations/v0066_add_auto_restatements.py +2 -6
- sqlmesh/migrations/v0067_add_tsql_date_full_precision.py +2 -2
- sqlmesh/migrations/v0068_include_unrendered_query_in_metadata_hash.py +2 -2
- sqlmesh/migrations/v0069_update_dev_table_suffix.py +2 -4
- sqlmesh/migrations/v0070_include_grains_in_metadata_hash.py +2 -2
- sqlmesh/migrations/v0071_add_dev_version_to_intervals.py +2 -6
- sqlmesh/migrations/v0072_add_environment_statements.py +2 -4
- sqlmesh/migrations/v0073_remove_symbolic_disable_restatement.py +2 -4
- sqlmesh/migrations/v0074_add_partition_by_time_column_property.py +2 -2
- sqlmesh/migrations/v0075_remove_validate_query.py +2 -4
- sqlmesh/migrations/v0076_add_cron_tz.py +2 -2
- sqlmesh/migrations/v0077_fix_column_type_hash_calculation.py +2 -2
- sqlmesh/migrations/v0078_warn_if_non_migratable_python_env.py +2 -4
- sqlmesh/migrations/v0079_add_gateway_managed_property.py +7 -9
- sqlmesh/migrations/v0080_add_batch_size_to_scd_type_2_models.py +2 -2
- sqlmesh/migrations/v0081_update_partitioned_by.py +2 -4
- sqlmesh/migrations/v0082_warn_if_incorrectly_duplicated_statements.py +2 -4
- sqlmesh/migrations/v0083_use_sql_for_scd_time_data_type_data_hash.py +2 -2
- sqlmesh/migrations/v0084_normalize_quote_when_matched_and_merge_filter.py +2 -2
- sqlmesh/migrations/v0085_deterministic_repr.py +2 -4
- sqlmesh/migrations/v0086_check_deterministic_bug.py +2 -4
- sqlmesh/migrations/v0087_normalize_blueprint_variables.py +2 -4
- sqlmesh/migrations/v0088_warn_about_variable_python_env_diffs.py +2 -4
- sqlmesh/migrations/v0089_add_virtual_environment_mode.py +2 -2
- sqlmesh/migrations/v0090_add_forward_only_column.py +2 -6
- sqlmesh/migrations/v0091_on_additive_change.py +2 -2
- sqlmesh/migrations/v0092_warn_about_dbt_data_type_diff.py +2 -4
- sqlmesh/migrations/v0093_use_raw_sql_in_fingerprint.py +2 -2
- sqlmesh/migrations/v0094_add_dev_version_and_fingerprint_columns.py +2 -6
- sqlmesh/migrations/v0095_warn_about_dbt_raw_sql_diff.py +2 -4
- sqlmesh/migrations/v0096_remove_plan_dags_table.py +2 -4
- sqlmesh/migrations/v0097_add_dbt_name_in_node.py +2 -2
- sqlmesh/migrations/v0098_add_dbt_node_info_in_node.py +103 -0
- sqlmesh/migrations/v0099_add_last_altered_to_intervals.py +25 -0
- sqlmesh/migrations/v0100_add_grants_and_grants_target_layer.py +9 -0
- sqlmesh/utils/__init__.py +8 -1
- sqlmesh/utils/cache.py +5 -1
- sqlmesh/utils/date.py +1 -1
- sqlmesh/utils/errors.py +4 -0
- sqlmesh/utils/git.py +3 -1
- sqlmesh/utils/jinja.py +25 -2
- sqlmesh/utils/pydantic.py +6 -6
- sqlmesh/utils/windows.py +13 -3
- {sqlmesh-0.217.1.dev1.dist-info → sqlmesh-0.227.2.dev20.dist-info}/METADATA +5 -5
- {sqlmesh-0.217.1.dev1.dist-info → sqlmesh-0.227.2.dev20.dist-info}/RECORD +188 -183
- sqlmesh_dbt/cli.py +70 -7
- sqlmesh_dbt/console.py +14 -6
- sqlmesh_dbt/operations.py +103 -24
- sqlmesh_dbt/selectors.py +39 -1
- web/client/dist/assets/{Audits-Ucsx1GzF.js → Audits-CBiYyyx-.js} +1 -1
- web/client/dist/assets/{Banner-BWDzvavM.js → Banner-DSRbUlO5.js} +1 -1
- web/client/dist/assets/{ChevronDownIcon-D2VL13Ah.js → ChevronDownIcon-MK_nrjD_.js} +1 -1
- web/client/dist/assets/{ChevronRightIcon-DWGYbf1l.js → ChevronRightIcon-CLWtT22Q.js} +1 -1
- web/client/dist/assets/{Content-DdHDZM3I.js → Content-BNuGZN5l.js} +1 -1
- web/client/dist/assets/{Content-Bikfy8fh.js → Content-CSHJyW0n.js} +1 -1
- web/client/dist/assets/{Data-CzAJH7rW.js → Data-C1oRDbLx.js} +1 -1
- web/client/dist/assets/{DataCatalog-BJF11g8f.js → DataCatalog-HXyX2-_j.js} +1 -1
- web/client/dist/assets/{Editor-s0SBpV2y.js → Editor-BDyfpUuw.js} +1 -1
- web/client/dist/assets/{Editor-DgLhgKnm.js → Editor-D0jNItwC.js} +1 -1
- web/client/dist/assets/{Errors-D0m0O1d3.js → Errors-BfuFLcPi.js} +1 -1
- web/client/dist/assets/{FileExplorer-CEv0vXkt.js → FileExplorer-BR9IE3he.js} +1 -1
- web/client/dist/assets/{Footer-BwzXn8Ew.js → Footer-CgBEtiAh.js} +1 -1
- web/client/dist/assets/{Header-6heDkEqG.js → Header-DSqR6nSO.js} +1 -1
- web/client/dist/assets/{Input-obuJsD6k.js → Input-B-oZ6fGO.js} +1 -1
- web/client/dist/assets/Lineage-DYQVwDbD.js +1 -0
- web/client/dist/assets/{ListboxShow-HM9_qyrt.js → ListboxShow-BE5-xevs.js} +1 -1
- web/client/dist/assets/{ModelLineage-zWdKo0U2.js → ModelLineage-DkIFAYo4.js} +1 -1
- web/client/dist/assets/{Models-Bcu66SRz.js → Models-D5dWr8RB.js} +1 -1
- web/client/dist/assets/{Page-BWEEQfIt.js → Page-C-XfU5BR.js} +1 -1
- web/client/dist/assets/{Plan-C4gXCqlf.js → Plan-ZEuTINBq.js} +1 -1
- web/client/dist/assets/{PlusCircleIcon-CVDO651q.js → PlusCircleIcon-DVXAHG8_.js} +1 -1
- web/client/dist/assets/{ReportErrors-BT6xFwAr.js → ReportErrors-B7FEPzMB.js} +1 -1
- web/client/dist/assets/{Root-ryJoBK4h.js → Root-8aZyhPxF.js} +1 -1
- web/client/dist/assets/{SearchList-DB04sPb9.js → SearchList-W_iT2G82.js} +1 -1
- web/client/dist/assets/{SelectEnvironment-CUYcXUu6.js → SelectEnvironment-C65jALmO.js} +1 -1
- web/client/dist/assets/{SourceList-Doo_9ZGp.js → SourceList-DSLO6nVJ.js} +1 -1
- web/client/dist/assets/{SourceListItem-D5Mj7Dly.js → SourceListItem-BHt8d9-I.js} +1 -1
- web/client/dist/assets/{SplitPane-qHmkD1qy.js → SplitPane-CViaZmw6.js} +1 -1
- web/client/dist/assets/{Tests-DH1Z74ML.js → Tests-DhaVt5t1.js} +1 -1
- web/client/dist/assets/{Welcome-DqUJUNMF.js → Welcome-DvpjH-_4.js} +1 -1
- web/client/dist/assets/context-BctCsyGb.js +71 -0
- web/client/dist/assets/{context-Dr54UHLi.js → context-DFNeGsFF.js} +1 -1
- web/client/dist/assets/{editor-DYIP1yQ4.js → editor-CcO28cqd.js} +1 -1
- web/client/dist/assets/{file-DarlIDVi.js → file-CvJN3aZO.js} +1 -1
- web/client/dist/assets/{floating-ui.react-dom-BH3TFvkM.js → floating-ui.react-dom-CjE-JNW1.js} +1 -1
- web/client/dist/assets/{help-Bl8wqaQc.js → help-DuPhjipa.js} +1 -1
- web/client/dist/assets/{index-D1sR7wpN.js → index-C-dJH7yZ.js} +1 -1
- web/client/dist/assets/{index-O3mjYpnE.js → index-Dj0i1-CA.js} +2 -2
- web/client/dist/assets/{plan-CehRrJUG.js → plan-BTRSbjKn.js} +1 -1
- web/client/dist/assets/{popover-CqgMRE0G.js → popover-_Sf0yvOI.js} +1 -1
- web/client/dist/assets/{project-6gxepOhm.js → project-BvSOI8MY.js} +1 -1
- web/client/dist/index.html +1 -1
- web/client/dist/assets/Lineage-D0Hgdz2v.js +0 -1
- web/client/dist/assets/context-DgX0fp2E.js +0 -68
- {sqlmesh-0.217.1.dev1.dist-info → sqlmesh-0.227.2.dev20.dist-info}/WHEEL +0 -0
- {sqlmesh-0.217.1.dev1.dist-info → sqlmesh-0.227.2.dev20.dist-info}/entry_points.txt +0 -0
- {sqlmesh-0.217.1.dev1.dist-info → sqlmesh-0.227.2.dev20.dist-info}/licenses/LICENSE +0 -0
- {sqlmesh-0.217.1.dev1.dist-info → sqlmesh-0.227.2.dev20.dist-info}/top_level.txt +0 -0
sqlmesh/core/context.py
CHANGED
|
@@ -93,7 +93,7 @@ from sqlmesh.core.plan.definition import UserProvidedFlags
|
|
|
93
93
|
from sqlmesh.core.reference import ReferenceGraph
|
|
94
94
|
from sqlmesh.core.scheduler import Scheduler, CompletionStatus
|
|
95
95
|
from sqlmesh.core.schema_loader import create_external_models_file
|
|
96
|
-
from sqlmesh.core.selector import Selector
|
|
96
|
+
from sqlmesh.core.selector import Selector, NativeSelector
|
|
97
97
|
from sqlmesh.core.snapshot import (
|
|
98
98
|
DeployabilityIndex,
|
|
99
99
|
Snapshot,
|
|
@@ -107,14 +107,15 @@ from sqlmesh.core.state_sync import (
|
|
|
107
107
|
CachingStateSync,
|
|
108
108
|
StateReader,
|
|
109
109
|
StateSync,
|
|
110
|
-
cleanup_expired_views,
|
|
111
110
|
)
|
|
111
|
+
from sqlmesh.core.janitor import cleanup_expired_views, delete_expired_snapshots
|
|
112
112
|
from sqlmesh.core.table_diff import TableDiff
|
|
113
113
|
from sqlmesh.core.test import (
|
|
114
114
|
ModelTextTestResult,
|
|
115
115
|
ModelTestMetadata,
|
|
116
116
|
generate_test,
|
|
117
117
|
run_tests,
|
|
118
|
+
filter_tests_by_patterns,
|
|
118
119
|
)
|
|
119
120
|
from sqlmesh.core.user import User
|
|
120
121
|
from sqlmesh.utils import UniqueKeyDict, Verbosity
|
|
@@ -139,6 +140,7 @@ from sqlmesh.utils.errors import (
|
|
|
139
140
|
)
|
|
140
141
|
from sqlmesh.utils.config import print_config
|
|
141
142
|
from sqlmesh.utils.jinja import JinjaMacroRegistry
|
|
143
|
+
from sqlmesh.utils.windows import IS_WINDOWS, fix_windows_path
|
|
142
144
|
|
|
143
145
|
if t.TYPE_CHECKING:
|
|
144
146
|
import pandas as pd
|
|
@@ -153,6 +155,8 @@ if t.TYPE_CHECKING:
|
|
|
153
155
|
)
|
|
154
156
|
from sqlmesh.core.snapshot import Node
|
|
155
157
|
|
|
158
|
+
from sqlmesh.core.snapshot.definition import Intervals
|
|
159
|
+
|
|
156
160
|
ModelOrSnapshot = t.Union[str, Model, Snapshot]
|
|
157
161
|
NodeOrSnapshot = t.Union[str, Model, StandaloneAudit, Snapshot]
|
|
158
162
|
|
|
@@ -274,6 +278,8 @@ class ExecutionContext(BaseContext):
|
|
|
274
278
|
deployability_index: t.Optional[DeployabilityIndex] = None,
|
|
275
279
|
default_dialect: t.Optional[str] = None,
|
|
276
280
|
default_catalog: t.Optional[str] = None,
|
|
281
|
+
is_restatement: t.Optional[bool] = None,
|
|
282
|
+
parent_intervals: t.Optional[Intervals] = None,
|
|
277
283
|
variables: t.Optional[t.Dict[str, t.Any]] = None,
|
|
278
284
|
blueprint_variables: t.Optional[t.Dict[str, t.Any]] = None,
|
|
279
285
|
):
|
|
@@ -284,6 +290,8 @@ class ExecutionContext(BaseContext):
|
|
|
284
290
|
self._default_dialect = default_dialect
|
|
285
291
|
self._variables = variables or {}
|
|
286
292
|
self._blueprint_variables = blueprint_variables or {}
|
|
293
|
+
self._is_restatement = is_restatement
|
|
294
|
+
self._parent_intervals = parent_intervals
|
|
287
295
|
|
|
288
296
|
@property
|
|
289
297
|
def default_dialect(self) -> t.Optional[str]:
|
|
@@ -308,6 +316,14 @@ class ExecutionContext(BaseContext):
|
|
|
308
316
|
"""Returns the gateway name."""
|
|
309
317
|
return self.var(c.GATEWAY)
|
|
310
318
|
|
|
319
|
+
@property
|
|
320
|
+
def is_restatement(self) -> t.Optional[bool]:
|
|
321
|
+
return self._is_restatement
|
|
322
|
+
|
|
323
|
+
@property
|
|
324
|
+
def parent_intervals(self) -> t.Optional[Intervals]:
|
|
325
|
+
return self._parent_intervals
|
|
326
|
+
|
|
311
327
|
def var(self, var_name: str, default: t.Optional[t.Any] = None) -> t.Optional[t.Any]:
|
|
312
328
|
"""Returns a variable value."""
|
|
313
329
|
return self._variables.get(var_name.lower(), default)
|
|
@@ -328,6 +344,7 @@ class ExecutionContext(BaseContext):
|
|
|
328
344
|
self.deployability_index,
|
|
329
345
|
self._default_dialect,
|
|
330
346
|
self._default_catalog,
|
|
347
|
+
self._is_restatement,
|
|
331
348
|
variables=variables,
|
|
332
349
|
blueprint_variables=blueprint_variables,
|
|
333
350
|
)
|
|
@@ -368,6 +385,7 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
368
385
|
load: bool = True,
|
|
369
386
|
users: t.Optional[t.List[User]] = None,
|
|
370
387
|
config_loader_kwargs: t.Optional[t.Dict[str, t.Any]] = None,
|
|
388
|
+
selector: t.Optional[t.Type[Selector]] = None,
|
|
371
389
|
):
|
|
372
390
|
self.configs = (
|
|
373
391
|
config
|
|
@@ -381,6 +399,11 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
381
399
|
self._standalone_audits: UniqueKeyDict[str, StandaloneAudit] = UniqueKeyDict(
|
|
382
400
|
"standaloneaudits"
|
|
383
401
|
)
|
|
402
|
+
self._model_test_metadata: t.List[ModelTestMetadata] = []
|
|
403
|
+
self._model_test_metadata_path_index: t.Dict[Path, t.List[ModelTestMetadata]] = {}
|
|
404
|
+
self._model_test_metadata_fully_qualified_name_index: t.Dict[str, ModelTestMetadata] = {}
|
|
405
|
+
self._models_with_tests: t.Set[str] = set()
|
|
406
|
+
|
|
384
407
|
self._macros: UniqueKeyDict[str, ExecutableOrMacro] = UniqueKeyDict("macros")
|
|
385
408
|
self._metrics: UniqueKeyDict[str, Metric] = UniqueKeyDict("metrics")
|
|
386
409
|
self._jinja_macros = JinjaMacroRegistry()
|
|
@@ -390,6 +413,7 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
390
413
|
self._engine_adapter: t.Optional[EngineAdapter] = None
|
|
391
414
|
self._linters: t.Dict[str, Linter] = {}
|
|
392
415
|
self._loaded: bool = False
|
|
416
|
+
self._selector_cls = selector or NativeSelector
|
|
393
417
|
|
|
394
418
|
self.path, self.config = t.cast(t.Tuple[Path, C], next(iter(self.configs.items())))
|
|
395
419
|
|
|
@@ -618,6 +642,10 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
618
642
|
self._excluded_requirements.clear()
|
|
619
643
|
self._linters.clear()
|
|
620
644
|
self._environment_statements = []
|
|
645
|
+
self._model_test_metadata.clear()
|
|
646
|
+
self._model_test_metadata_path_index.clear()
|
|
647
|
+
self._model_test_metadata_fully_qualified_name_index.clear()
|
|
648
|
+
self._models_with_tests.clear()
|
|
621
649
|
|
|
622
650
|
for loader, project in zip(self._loaders, loaded_projects):
|
|
623
651
|
self._jinja_macros = self._jinja_macros.merge(project.jinja_macros)
|
|
@@ -630,6 +658,16 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
630
658
|
self._excluded_requirements.update(project.excluded_requirements)
|
|
631
659
|
self._environment_statements.extend(project.environment_statements)
|
|
632
660
|
|
|
661
|
+
self._model_test_metadata.extend(project.model_test_metadata)
|
|
662
|
+
for metadata in project.model_test_metadata:
|
|
663
|
+
if metadata.path not in self._model_test_metadata_path_index:
|
|
664
|
+
self._model_test_metadata_path_index[metadata.path] = []
|
|
665
|
+
self._model_test_metadata_path_index[metadata.path].append(metadata)
|
|
666
|
+
self._model_test_metadata_fully_qualified_name_index[
|
|
667
|
+
metadata.fully_qualified_test_name
|
|
668
|
+
] = metadata
|
|
669
|
+
self._models_with_tests.add(metadata.model_name)
|
|
670
|
+
|
|
633
671
|
config = loader.config
|
|
634
672
|
self._linters[config.project] = Linter.from_rules(
|
|
635
673
|
BUILTIN_RULES.union(project.user_rules), config.linter
|
|
@@ -1031,6 +1069,11 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
1031
1069
|
"""Returns all registered standalone audits in this context."""
|
|
1032
1070
|
return MappingProxyType(self._standalone_audits)
|
|
1033
1071
|
|
|
1072
|
+
@property
|
|
1073
|
+
def models_with_tests(self) -> t.Set[str]:
|
|
1074
|
+
"""Returns all models with tests in this context."""
|
|
1075
|
+
return self._models_with_tests
|
|
1076
|
+
|
|
1034
1077
|
@property
|
|
1035
1078
|
def snapshots(self) -> t.Dict[str, Snapshot]:
|
|
1036
1079
|
"""Generates and returns snapshots based on models registered in this context.
|
|
@@ -1429,6 +1472,7 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
1429
1472
|
explain: t.Optional[bool] = None,
|
|
1430
1473
|
ignore_cron: t.Optional[bool] = None,
|
|
1431
1474
|
min_intervals: t.Optional[int] = None,
|
|
1475
|
+
always_include_local_changes: t.Optional[bool] = None,
|
|
1432
1476
|
) -> PlanBuilder:
|
|
1433
1477
|
"""Creates a plan builder.
|
|
1434
1478
|
|
|
@@ -1467,6 +1511,8 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
1467
1511
|
diff_rendered: Whether the diff should compare raw vs rendered models
|
|
1468
1512
|
min_intervals: Adjust the plan start date on a per-model basis in order to ensure at least this many intervals are covered
|
|
1469
1513
|
on every model when checking for missing intervals
|
|
1514
|
+
always_include_local_changes: Usually when restatements are present, local changes in the filesystem are ignored.
|
|
1515
|
+
However, it can be desirable to deploy changes + restatements in the same plan, so this flag overrides the default behaviour.
|
|
1470
1516
|
|
|
1471
1517
|
Returns:
|
|
1472
1518
|
The plan builder.
|
|
@@ -1583,13 +1629,20 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
1583
1629
|
"Selector did not return any models. Please check your model selection and try again."
|
|
1584
1630
|
)
|
|
1585
1631
|
|
|
1632
|
+
if always_include_local_changes is None:
|
|
1633
|
+
# default behaviour - if restatements are detected; we operate entirely out of state and ignore local changes
|
|
1634
|
+
force_no_diff = restate_models is not None or (
|
|
1635
|
+
backfill_models is not None and not backfill_models
|
|
1636
|
+
)
|
|
1637
|
+
else:
|
|
1638
|
+
force_no_diff = not always_include_local_changes
|
|
1639
|
+
|
|
1586
1640
|
snapshots = self._snapshots(models_override)
|
|
1587
1641
|
context_diff = self._context_diff(
|
|
1588
1642
|
environment or c.PROD,
|
|
1589
1643
|
snapshots=snapshots,
|
|
1590
1644
|
create_from=create_from,
|
|
1591
|
-
force_no_diff=
|
|
1592
|
-
or (backfill_models is not None and not backfill_models),
|
|
1645
|
+
force_no_diff=force_no_diff,
|
|
1593
1646
|
ensure_finalized_snapshots=self.config.plan.use_finalized_state,
|
|
1594
1647
|
diff_rendered=diff_rendered,
|
|
1595
1648
|
always_recreate_environment=self.config.plan.always_recreate_environment,
|
|
@@ -1644,6 +1697,14 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
1644
1697
|
elif forward_only is None:
|
|
1645
1698
|
forward_only = self.config.plan.forward_only
|
|
1646
1699
|
|
|
1700
|
+
# When handling prod restatements, only clear intervals from other model versions if we are using full virtual environments
|
|
1701
|
+
# If we are not, then there is no point, because none of the data in dev environments can be promoted by definition
|
|
1702
|
+
restate_all_snapshots = (
|
|
1703
|
+
expanded_restate_models is not None
|
|
1704
|
+
and not is_dev
|
|
1705
|
+
and self.config.virtual_environment_mode.is_full
|
|
1706
|
+
)
|
|
1707
|
+
|
|
1647
1708
|
return self.PLAN_BUILDER_TYPE(
|
|
1648
1709
|
context_diff=context_diff,
|
|
1649
1710
|
start=start,
|
|
@@ -1651,6 +1712,7 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
1651
1712
|
execution_time=execution_time,
|
|
1652
1713
|
apply=self.apply,
|
|
1653
1714
|
restate_models=expanded_restate_models,
|
|
1715
|
+
restate_all_snapshots=restate_all_snapshots,
|
|
1654
1716
|
backfill_models=backfill_models,
|
|
1655
1717
|
no_gaps=no_gaps,
|
|
1656
1718
|
skip_backfill=skip_backfill,
|
|
@@ -1678,9 +1740,9 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
1678
1740
|
console=self.console,
|
|
1679
1741
|
user_provided_flags=user_provided_flags,
|
|
1680
1742
|
selected_models={
|
|
1681
|
-
|
|
1743
|
+
dbt_unique_id
|
|
1682
1744
|
for model in model_selector.expand_model_selections(select_models or "*")
|
|
1683
|
-
if (
|
|
1745
|
+
if (dbt_unique_id := snapshots[model].node.dbt_unique_id)
|
|
1684
1746
|
},
|
|
1685
1747
|
explain=explain or False,
|
|
1686
1748
|
ignore_cron=ignore_cron or False,
|
|
@@ -2183,7 +2245,7 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
2183
2245
|
|
|
2184
2246
|
pd.set_option("display.max_columns", None)
|
|
2185
2247
|
|
|
2186
|
-
test_meta = self.
|
|
2248
|
+
test_meta = self.select_tests(tests=tests, patterns=match_patterns)
|
|
2187
2249
|
|
|
2188
2250
|
result = run_tests(
|
|
2189
2251
|
model_test_metadata=test_meta,
|
|
@@ -2242,6 +2304,7 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
2242
2304
|
snapshot=snapshot,
|
|
2243
2305
|
start=start,
|
|
2244
2306
|
end=end,
|
|
2307
|
+
execution_time=execution_time,
|
|
2245
2308
|
snapshots=self.snapshots,
|
|
2246
2309
|
):
|
|
2247
2310
|
audit_id = f"{audit_result.audit.name}"
|
|
@@ -2562,12 +2625,15 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
2562
2625
|
)
|
|
2563
2626
|
|
|
2564
2627
|
def clear_caches(self) -> None:
|
|
2565
|
-
for path in self.configs
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2628
|
+
paths_to_remove = [path / c.CACHE for path in self.configs]
|
|
2629
|
+
paths_to_remove.append(self.cache_dir)
|
|
2630
|
+
|
|
2631
|
+
if IS_WINDOWS:
|
|
2632
|
+
paths_to_remove = [fix_windows_path(path) for path in paths_to_remove]
|
|
2633
|
+
|
|
2634
|
+
for path in paths_to_remove:
|
|
2635
|
+
if path.exists():
|
|
2636
|
+
rmtree(path)
|
|
2571
2637
|
|
|
2572
2638
|
if isinstance(self._state_sync, CachingStateSync):
|
|
2573
2639
|
self._state_sync.clear_cache()
|
|
@@ -2824,19 +2890,14 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
2824
2890
|
# Clean up expired environments by removing their views and schemas
|
|
2825
2891
|
self._cleanup_environments(current_ts=current_ts)
|
|
2826
2892
|
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
on_complete=self.console.update_cleanup_progress,
|
|
2893
|
+
delete_expired_snapshots(
|
|
2894
|
+
self.state_sync,
|
|
2895
|
+
self.snapshot_evaluator,
|
|
2896
|
+
current_ts=current_ts,
|
|
2897
|
+
ignore_ttl=ignore_ttl,
|
|
2898
|
+
console=self.console,
|
|
2899
|
+
batch_size=self.config.janitor.expired_snapshots_batch_size,
|
|
2835
2900
|
)
|
|
2836
|
-
|
|
2837
|
-
# Delete the expired snapshot records from the state sync
|
|
2838
|
-
self.state_sync.delete_expired_snapshots(ignore_ttl=ignore_ttl, current_ts=current_ts)
|
|
2839
|
-
|
|
2840
2901
|
self.state_sync.compact_intervals()
|
|
2841
2902
|
|
|
2842
2903
|
def _cleanup_environments(self, current_ts: t.Optional[int] = None) -> None:
|
|
@@ -2874,7 +2935,7 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
2874
2935
|
def _new_selector(
|
|
2875
2936
|
self, models: t.Optional[UniqueKeyDict[str, Model]] = None, dag: t.Optional[DAG[str]] = None
|
|
2876
2937
|
) -> Selector:
|
|
2877
|
-
return
|
|
2938
|
+
return self._selector_cls(
|
|
2878
2939
|
self.state_reader,
|
|
2879
2940
|
models=models or self._models,
|
|
2880
2941
|
context_path=self.path,
|
|
@@ -3157,18 +3218,34 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
3157
3218
|
|
|
3158
3219
|
return all_violations
|
|
3159
3220
|
|
|
3160
|
-
def
|
|
3161
|
-
self,
|
|
3221
|
+
def select_tests(
|
|
3222
|
+
self,
|
|
3223
|
+
tests: t.Optional[t.List[str]] = None,
|
|
3224
|
+
patterns: t.Optional[t.List[str]] = None,
|
|
3162
3225
|
) -> t.List[ModelTestMetadata]:
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3226
|
+
"""Filter pre-loaded test metadata based on tests and patterns."""
|
|
3227
|
+
|
|
3228
|
+
test_meta = self._model_test_metadata
|
|
3229
|
+
|
|
3230
|
+
if tests:
|
|
3231
|
+
filtered_tests = []
|
|
3232
|
+
for test in tests:
|
|
3233
|
+
if "::" in test:
|
|
3234
|
+
if test in self._model_test_metadata_fully_qualified_name_index:
|
|
3235
|
+
filtered_tests.append(
|
|
3236
|
+
self._model_test_metadata_fully_qualified_name_index[test]
|
|
3237
|
+
)
|
|
3238
|
+
else:
|
|
3239
|
+
test_path = Path(test)
|
|
3240
|
+
if test_path in self._model_test_metadata_path_index:
|
|
3241
|
+
filtered_tests.extend(self._model_test_metadata_path_index[test_path])
|
|
3242
|
+
|
|
3243
|
+
test_meta = filtered_tests
|
|
3166
3244
|
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
model_tests.extend(loader.load_model_tests(tests=tests, patterns=patterns))
|
|
3245
|
+
if patterns:
|
|
3246
|
+
test_meta = filter_tests_by_patterns(test_meta, patterns)
|
|
3170
3247
|
|
|
3171
|
-
return
|
|
3248
|
+
return test_meta
|
|
3172
3249
|
|
|
3173
3250
|
|
|
3174
3251
|
class Context(GenericContext[Config]):
|
sqlmesh/core/dialect.py
CHANGED
|
@@ -174,6 +174,7 @@ def _parse_id_var(
|
|
|
174
174
|
|
|
175
175
|
while (
|
|
176
176
|
identifier
|
|
177
|
+
and not identifier.args.get("quoted")
|
|
177
178
|
and self._is_connected()
|
|
178
179
|
and (
|
|
179
180
|
self._match_texts(("{", SQLMESH_MACRO_PREFIX))
|
|
@@ -349,6 +350,7 @@ def _parse_select(
|
|
|
349
350
|
parse_subquery_alias: bool = True,
|
|
350
351
|
parse_set_operation: bool = True,
|
|
351
352
|
consume_pipe: bool = True,
|
|
353
|
+
from_: t.Optional[exp.From] = None,
|
|
352
354
|
) -> t.Optional[exp.Expression]:
|
|
353
355
|
select = self.__parse_select( # type: ignore
|
|
354
356
|
nested=nested,
|
|
@@ -356,6 +358,7 @@ def _parse_select(
|
|
|
356
358
|
parse_subquery_alias=parse_subquery_alias,
|
|
357
359
|
parse_set_operation=parse_set_operation,
|
|
358
360
|
consume_pipe=consume_pipe,
|
|
361
|
+
from_=from_,
|
|
359
362
|
)
|
|
360
363
|
|
|
361
364
|
if (
|