sqlmesh 0.187.6.dev25__py3-none-any.whl → 0.187.7__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/_version.py +2 -2
- sqlmesh/core/config/root.py +0 -2
- sqlmesh/core/config/scheduler.py +7 -11
- sqlmesh/core/context.py +45 -76
- sqlmesh/core/context_diff.py +18 -38
- sqlmesh/core/model/cache.py +3 -11
- sqlmesh/core/plan/builder.py +5 -6
- sqlmesh/core/schema_diff.py +0 -22
- sqlmesh/core/selector.py +1 -1
- sqlmesh/core/test/definition.py +1 -4
- sqlmesh/dbt/loader.py +22 -17
- sqlmesh/dbt/manifest.py +4 -31
- sqlmesh/dbt/package.py +0 -1
- sqlmesh/integrations/github/cicd/command.py +4 -2
- sqlmesh/integrations/github/cicd/controller.py +8 -1
- sqlmesh/lsp/custom.py +1 -1
- sqlmesh/lsp/main.py +33 -178
- sqlmesh/lsp/reference.py +3 -194
- {sqlmesh-0.187.6.dev25.dist-info → sqlmesh-0.187.7.dist-info}/METADATA +7 -29
- {sqlmesh-0.187.6.dev25.dist-info → sqlmesh-0.187.7.dist-info}/RECORD +70 -70
- web/client/dist/assets/{Audits-CxDNe6z-.js → Audits-DB1HcP9M.js} +1 -1
- web/client/dist/assets/{Banner-DgEFplVH.js → Banner-DNY__4sG.js} +1 -1
- web/client/dist/assets/{ChevronDownIcon-BH5O_hpi.js → ChevronDownIcon-lHn9zjvd.js} +1 -1
- web/client/dist/assets/{ChevronRightIcon-B2tR7wtU.js → ChevronRightIcon-oQ5f5ZGP.js} +1 -1
- web/client/dist/assets/{Content-CiZNHHa7.js → Content-Da0wstVW.js} +1 -1
- web/client/dist/assets/{Content-CQOt5HQJ.js → Content-QpBh5BIf.js} +1 -1
- web/client/dist/assets/{Data-CcafCjCX.js → Data-C7p96ruh.js} +1 -1
- web/client/dist/assets/{DataCatalog-FDQcoVzu.js → DataCatalog-C7cUGv8x.js} +1 -1
- web/client/dist/assets/{Editor-DPJUo9Bh.js → Editor-B6PRl__L.js} +1 -1
- web/client/dist/assets/{Editor-UHmKFABp.js → Editor-S5kDO3v1.js} +1 -1
- web/client/dist/assets/{Errors-PPhF0BLv.js → Errors-CxCutNFm.js} +1 -1
- web/client/dist/assets/{FileExplorer-Dn5aKM9r.js → FileExplorer-kP-IjmYP.js} +1 -1
- web/client/dist/assets/{Footer-C3l7iM3A.js → Footer-rRlYYZGX.js} +1 -1
- web/client/dist/assets/{Header-iNVdvXN8.js → Header-DWsJQ7Zd.js} +1 -1
- web/client/dist/assets/{Input-CettPX-D.js → Input-DdPN19Px.js} +1 -1
- web/client/dist/assets/Lineage-BQJPyHVL.js +1 -0
- web/client/dist/assets/{ListboxShow-BaJGpuWH.js → ListboxShow-BmQk-sC6.js} +1 -1
- web/client/dist/assets/{ModelLineage-zSYJ8qL6.js → ModelLineage-Cb-ryU8k.js} +1 -1
- web/client/dist/assets/{Models-BpC_5kGJ.js → Models-Bv0YKo6C.js} +1 -1
- web/client/dist/assets/{Page-Bq-HPl_L.js → Page-C-F04Qw-.js} +1 -1
- web/client/dist/assets/{Plan-DBHhKyK_.js → Plan-DfF6_rdE.js} +1 -1
- web/client/dist/assets/{PlusCircleIcon-Bh1eQZZw.js → PlusCircleIcon-D8BJTuwF.js} +1 -1
- web/client/dist/assets/{ReportErrors-BvekyVWZ.js → ReportErrors-BR3yV5Ru.js} +1 -1
- web/client/dist/assets/{Root-B3mVFWm-.js → Root-gCyYAZOq.js} +1 -1
- web/client/dist/assets/{SearchList-BoZPD5Ug.js → SearchList-Mw4DP7x1.js} +1 -1
- web/client/dist/assets/{SelectEnvironment-DVTyPJgk.js → SelectEnvironment-C-I8dl8g.js} +1 -1
- web/client/dist/assets/{SourceList-De_bjt2z.js → SourceList-nJbKxW-u.js} +1 -1
- web/client/dist/assets/{SourceListItem-s3cjyYyg.js → SourceListItem-Cpx6p_wh.js} +1 -1
- web/client/dist/assets/{SplitPane-YXb1GDjg.js → SplitPane-CwtTNpO8.js} +1 -1
- web/client/dist/assets/{Tests-CABcm50Q.js → Tests-BKeeabY_.js} +1 -1
- web/client/dist/assets/{Welcome-BmBt__Vn.js → Welcome-D191sGJC.js} +1 -1
- web/client/dist/assets/{context-C6hLZh3v.js → context-5PbIKqqT.js} +1 -1
- web/client/dist/assets/{context-0jZBOaYJ.js → context-CVkhr9QB.js} +2 -2
- web/client/dist/assets/{editor-Dn-V5hys.js → editor-DWINdd81.js} +1 -1
- web/client/dist/assets/{file-FSJHKTZR.js → file-e9qyDfWg.js} +1 -1
- web/client/dist/assets/{floating-ui.react-dom-CwIPOwQR.js → floating-ui.react-dom-B-NNWGkz.js} +1 -1
- web/client/dist/assets/{help-Eh_Sg5R6.js → help-CjbSQwWi.js} +1 -1
- web/client/dist/assets/{index-OgPYo7hm.js → index-BZGZqBUO.js} +1 -1
- web/client/dist/assets/{index-hHSGLUzW.js → index-BkNpRAHt.js} +15 -15
- web/client/dist/assets/{plan-Crz4bZML.js → plan-C2UHjG7p.js} +1 -1
- web/client/dist/assets/{popover-CiOVW6r6.js → popover-C8e3ENo3.js} +1 -1
- web/client/dist/assets/{project-6bhvIw3F.js → project-BDZ1fnja.js} +1 -1
- web/client/dist/index.html +1 -1
- web/server/api/endpoints/commands.py +1 -1
- web/server/api/endpoints/files.py +1 -1
- web/server/utils.py +2 -1
- web/client/dist/assets/Lineage-DPXlJvwM.js +0 -1
- {sqlmesh-0.187.6.dev25.dist-info → sqlmesh-0.187.7.dist-info}/WHEEL +0 -0
- {sqlmesh-0.187.6.dev25.dist-info → sqlmesh-0.187.7.dist-info}/entry_points.txt +0 -0
- {sqlmesh-0.187.6.dev25.dist-info → sqlmesh-0.187.7.dist-info}/licenses/LICENSE +0 -0
- {sqlmesh-0.187.6.dev25.dist-info → sqlmesh-0.187.7.dist-info}/top_level.txt +0 -0
sqlmesh/_version.py
CHANGED
|
@@ -17,5 +17,5 @@ __version__: str
|
|
|
17
17
|
__version_tuple__: VERSION_TUPLE
|
|
18
18
|
version_tuple: VERSION_TUPLE
|
|
19
19
|
|
|
20
|
-
__version__ = version = '0.187.
|
|
21
|
-
__version_tuple__ = version_tuple = (0, 187,
|
|
20
|
+
__version__ = version = '0.187.7'
|
|
21
|
+
__version_tuple__ = version_tuple = (0, 187, 7)
|
sqlmesh/core/config/root.py
CHANGED
|
@@ -107,7 +107,6 @@ class Config(BaseConfig):
|
|
|
107
107
|
physical_schema_mapping: A mapping from regular expressions to names of schemas in which physical tables for corresponding models will be placed.
|
|
108
108
|
environment_suffix_target: Indicates whether to append the environment name to the schema or table name.
|
|
109
109
|
gateway_managed_virtual_layer: Whether the models' views in the virtual layer are created by the model-specific gateway rather than the default gateway.
|
|
110
|
-
infer_python_dependencies: Whether to statically analyze Python code to automatically infer Python package requirements.
|
|
111
110
|
environment_catalog_mapping: A mapping from regular expressions to catalog names. The catalog name is used to determine the target catalog for a given environment.
|
|
112
111
|
default_target_environment: The name of the environment that will be the default target for the `sqlmesh plan` and `sqlmesh run` commands.
|
|
113
112
|
log_limit: The default number of logs to keep.
|
|
@@ -147,7 +146,6 @@ class Config(BaseConfig):
|
|
|
147
146
|
default=EnvironmentSuffixTarget.default
|
|
148
147
|
)
|
|
149
148
|
gateway_managed_virtual_layer: bool = False
|
|
150
|
-
infer_python_dependencies: bool = True
|
|
151
149
|
environment_catalog_mapping: RegexKeyDict = {}
|
|
152
150
|
default_target_environment: str = c.PROD
|
|
153
151
|
log_limit: int = c.DEFAULT_LOG_LIMIT
|
sqlmesh/core/config/scheduler.py
CHANGED
|
@@ -47,8 +47,8 @@ class SchedulerConfig(abc.ABC):
|
|
|
47
47
|
"""
|
|
48
48
|
|
|
49
49
|
@abc.abstractmethod
|
|
50
|
-
def
|
|
51
|
-
"""Returns the default catalog for
|
|
50
|
+
def get_default_catalog(self, context: GenericContext) -> t.Optional[str]:
|
|
51
|
+
"""Returns the default catalog for the Scheduler.
|
|
52
52
|
|
|
53
53
|
Args:
|
|
54
54
|
context: The SQLMesh Context.
|
|
@@ -66,7 +66,7 @@ class SchedulerConfig(abc.ABC):
|
|
|
66
66
|
class _EngineAdapterStateSyncSchedulerConfig(SchedulerConfig):
|
|
67
67
|
def create_state_sync(self, context: GenericContext) -> StateSync:
|
|
68
68
|
state_connection = (
|
|
69
|
-
context.config.get_state_connection(context.gateway) or context.
|
|
69
|
+
context.config.get_state_connection(context.gateway) or context._connection_config
|
|
70
70
|
)
|
|
71
71
|
|
|
72
72
|
warehouse_connection = context.config.get_connection(context.gateway)
|
|
@@ -110,7 +110,7 @@ class _EngineAdapterStateSyncSchedulerConfig(SchedulerConfig):
|
|
|
110
110
|
|
|
111
111
|
def state_sync_fingerprint(self, context: GenericContext) -> str:
|
|
112
112
|
state_connection = (
|
|
113
|
-
context.config.get_state_connection(context.gateway) or context.
|
|
113
|
+
context.config.get_state_connection(context.gateway) or context._connection_config
|
|
114
114
|
)
|
|
115
115
|
return md5(
|
|
116
116
|
[
|
|
@@ -132,16 +132,12 @@ class BuiltInSchedulerConfig(_EngineAdapterStateSyncSchedulerConfig, BaseConfig)
|
|
|
132
132
|
state_sync=context.state_sync,
|
|
133
133
|
snapshot_evaluator=context.snapshot_evaluator,
|
|
134
134
|
create_scheduler=context.create_scheduler,
|
|
135
|
-
default_catalog=context
|
|
135
|
+
default_catalog=self.get_default_catalog(context),
|
|
136
136
|
console=context.console,
|
|
137
137
|
)
|
|
138
138
|
|
|
139
|
-
def
|
|
140
|
-
|
|
141
|
-
for gateway, adapter in context.engine_adapters.items():
|
|
142
|
-
if catalog := adapter.default_catalog:
|
|
143
|
-
default_catalogs_per_gateway[gateway] = catalog
|
|
144
|
-
return default_catalogs_per_gateway
|
|
139
|
+
def get_default_catalog(self, context: GenericContext) -> t.Optional[str]:
|
|
140
|
+
return context.engine_adapter.default_catalog
|
|
145
141
|
|
|
146
142
|
|
|
147
143
|
SCHEDULER_CONFIG_TO_TYPE = {
|
sqlmesh/core/context.py
CHANGED
|
@@ -62,9 +62,7 @@ from sqlmesh.core.config import (
|
|
|
62
62
|
Config,
|
|
63
63
|
load_configs,
|
|
64
64
|
)
|
|
65
|
-
from sqlmesh.core.config.connection import ConnectionConfig
|
|
66
65
|
from sqlmesh.core.config.loader import C
|
|
67
|
-
from sqlmesh.core.config.root import RegexKeyDict
|
|
68
66
|
from sqlmesh.core.console import get_console
|
|
69
67
|
from sqlmesh.core.context_diff import ContextDiff
|
|
70
68
|
from sqlmesh.core.dialect import (
|
|
@@ -369,9 +367,6 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
369
367
|
self._excluded_requirements: t.Set[str] = set()
|
|
370
368
|
self._default_catalog: t.Optional[str] = None
|
|
371
369
|
self._default_catalog_per_gateway: t.Optional[t.Dict[str, str]] = None
|
|
372
|
-
self._engine_adapter: t.Optional[EngineAdapter] = None
|
|
373
|
-
self._connection_config: t.Optional[ConnectionConfig] = None
|
|
374
|
-
self._test_connection_config: t.Optional[ConnectionConfig] = None
|
|
375
370
|
self._linters: t.Dict[str, Linter] = {}
|
|
376
371
|
self._loaded: bool = False
|
|
377
372
|
|
|
@@ -388,6 +383,7 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
388
383
|
self.pinned_environments = Environment.sanitize_names(self.config.pinned_environments)
|
|
389
384
|
self.auto_categorize_changes = self.config.plan.auto_categorize_changes
|
|
390
385
|
self.selected_gateway = gateway or self.config.default_gateway_name
|
|
386
|
+
self.gateway_managed_virtual_layer = self.config.gateway_managed_virtual_layer
|
|
391
387
|
|
|
392
388
|
gw_model_defaults = self.config.gateways[self.selected_gateway].model_defaults
|
|
393
389
|
if gw_model_defaults:
|
|
@@ -411,15 +407,24 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
411
407
|
for path, config in self.configs.items()
|
|
412
408
|
]
|
|
413
409
|
|
|
414
|
-
self.
|
|
410
|
+
self._connection_config = self.config.get_connection(self.gateway)
|
|
415
411
|
self._state_connection_config = (
|
|
416
|
-
self.config.get_state_connection(self.gateway) or self.
|
|
412
|
+
self.config.get_state_connection(self.gateway) or self._connection_config
|
|
417
413
|
)
|
|
414
|
+
self.concurrent_tasks = concurrent_tasks or self._connection_config.concurrent_tasks
|
|
415
|
+
|
|
416
|
+
self._engine_adapters: t.Dict[str, EngineAdapter] = {
|
|
417
|
+
self.selected_gateway: self._connection_config.create_engine_adapter()
|
|
418
|
+
}
|
|
418
419
|
|
|
419
420
|
self._snapshot_evaluator: t.Optional[SnapshotEvaluator] = None
|
|
420
421
|
|
|
421
422
|
self.console = get_console()
|
|
422
|
-
setattr(self.console, "dialect", self.
|
|
423
|
+
setattr(self.console, "dialect", self.engine_adapter.dialect)
|
|
424
|
+
|
|
425
|
+
self._test_connection_config = self.config.get_test_connection(
|
|
426
|
+
self.gateway, self.default_catalog, default_catalog_dialect=self.engine_adapter.DIALECT
|
|
427
|
+
)
|
|
423
428
|
|
|
424
429
|
self._provided_state_sync: t.Optional[StateSync] = state_sync
|
|
425
430
|
self._state_sync: t.Optional[StateSync] = None
|
|
@@ -430,6 +435,14 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
430
435
|
self.users = list({user.username: user for user in self.users}.values())
|
|
431
436
|
self._register_notification_targets()
|
|
432
437
|
|
|
438
|
+
if (
|
|
439
|
+
self.config.environment_catalog_mapping
|
|
440
|
+
and not self.engine_adapter.catalog_support.is_multi_catalog_supported
|
|
441
|
+
):
|
|
442
|
+
raise SQLMeshError(
|
|
443
|
+
"Environment catalog mapping is only supported for engine adapters that support multiple catalogs"
|
|
444
|
+
)
|
|
445
|
+
|
|
433
446
|
if load:
|
|
434
447
|
self.load()
|
|
435
448
|
|
|
@@ -440,9 +453,7 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
440
453
|
@property
|
|
441
454
|
def engine_adapter(self) -> EngineAdapter:
|
|
442
455
|
"""Returns the default engine adapter."""
|
|
443
|
-
|
|
444
|
-
self._engine_adapter = self.connection_config.create_engine_adapter()
|
|
445
|
-
return self._engine_adapter
|
|
456
|
+
return self._engine_adapters[self.selected_gateway]
|
|
446
457
|
|
|
447
458
|
@property
|
|
448
459
|
def snapshot_evaluator(self) -> SnapshotEvaluator:
|
|
@@ -921,22 +932,19 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
921
932
|
|
|
922
933
|
return snapshot
|
|
923
934
|
|
|
924
|
-
def config_for_path(self, path: Path) ->
|
|
925
|
-
"""Returns the config and path of the said project for a given file path."""
|
|
935
|
+
def config_for_path(self, path: Path) -> Config:
|
|
926
936
|
for config_path, config in self.configs.items():
|
|
927
937
|
try:
|
|
928
938
|
path.relative_to(config_path)
|
|
929
|
-
return config
|
|
939
|
+
return config
|
|
930
940
|
except ValueError:
|
|
931
941
|
pass
|
|
932
|
-
return self.config
|
|
942
|
+
return self.config
|
|
933
943
|
|
|
934
944
|
def config_for_node(self, node: str | Model | Audit) -> Config:
|
|
935
945
|
if isinstance(node, str):
|
|
936
|
-
return self.config_for_path(self.get_snapshot(node, raise_if_missing=True).node._path)
|
|
937
|
-
|
|
938
|
-
] # type: ignore
|
|
939
|
-
return self.config_for_path(node._path)[0] # type: ignore
|
|
946
|
+
return self.config_for_path(self.get_snapshot(node, raise_if_missing=True).node._path) # type: ignore
|
|
947
|
+
return self.config_for_path(node._path) # type: ignore
|
|
940
948
|
|
|
941
949
|
@property
|
|
942
950
|
def models(self) -> MappingProxyType[str, Model]:
|
|
@@ -969,8 +977,8 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
969
977
|
|
|
970
978
|
@property
|
|
971
979
|
def default_catalog(self) -> t.Optional[str]:
|
|
972
|
-
if self._default_catalog is None
|
|
973
|
-
self._default_catalog = self.
|
|
980
|
+
if self._default_catalog is None:
|
|
981
|
+
self._default_catalog = self._scheduler.get_default_catalog(self)
|
|
974
982
|
return self._default_catalog
|
|
975
983
|
|
|
976
984
|
@python_api_analytics
|
|
@@ -1527,7 +1535,7 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
1527
1535
|
allow_destructive_models=expanded_destructive_models,
|
|
1528
1536
|
environment_ttl=environment_ttl,
|
|
1529
1537
|
environment_suffix_target=self.config.environment_suffix_target,
|
|
1530
|
-
environment_catalog_mapping=self.environment_catalog_mapping,
|
|
1538
|
+
environment_catalog_mapping=self.config.environment_catalog_mapping,
|
|
1531
1539
|
categorizer_config=categorizer_config or self.auto_categorize_changes,
|
|
1532
1540
|
auto_categorization_enabled=not no_auto_categorization,
|
|
1533
1541
|
effective_from=effective_from,
|
|
@@ -1539,6 +1547,7 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
1539
1547
|
),
|
|
1540
1548
|
end_bounded=not run,
|
|
1541
1549
|
ensure_finalized_snapshots=self.config.plan.use_finalized_state,
|
|
1550
|
+
engine_schema_differ=self.engine_adapter.SCHEMA_DIFFER,
|
|
1542
1551
|
interval_end_per_model=max_interval_end_per_model,
|
|
1543
1552
|
console=self.console,
|
|
1544
1553
|
user_provided_flags=user_provided_flags,
|
|
@@ -1627,7 +1636,7 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
1627
1636
|
self.console.show_model_difference_summary(
|
|
1628
1637
|
context_diff,
|
|
1629
1638
|
EnvironmentNamingInfo.from_environment_catalog_mapping(
|
|
1630
|
-
self.environment_catalog_mapping,
|
|
1639
|
+
self.config.environment_catalog_mapping,
|
|
1631
1640
|
name=environment,
|
|
1632
1641
|
suffix_target=self.config.environment_suffix_target,
|
|
1633
1642
|
normalize_name=context_diff.normalize_environment_name,
|
|
@@ -1715,7 +1724,7 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
1715
1724
|
if target_snapshot and source_snapshot:
|
|
1716
1725
|
if (source_snapshot.fingerprint != target_snapshot.fingerprint) and (
|
|
1717
1726
|
(source_snapshot.version != target_snapshot.version)
|
|
1718
|
-
or source_snapshot.is_forward_only
|
|
1727
|
+
or (source_snapshot.is_forward_only or target_snapshot.is_forward_only)
|
|
1719
1728
|
):
|
|
1720
1729
|
# Compare the virtual layer instead of the physical layer because the virtual layer is guaranteed to point
|
|
1721
1730
|
# to the correct/active snapshot for the model in the specified environment, taking into account things like dev previews
|
|
@@ -1981,7 +1990,7 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
1981
1990
|
|
|
1982
1991
|
try:
|
|
1983
1992
|
model_to_test = self.get_model(model, raise_if_missing=True)
|
|
1984
|
-
test_adapter = self.
|
|
1993
|
+
test_adapter = self._test_connection_config.create_engine_adapter(
|
|
1985
1994
|
register_comments_override=False
|
|
1986
1995
|
)
|
|
1987
1996
|
|
|
@@ -2027,7 +2036,7 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
2027
2036
|
preserve_fixtures=preserve_fixtures,
|
|
2028
2037
|
stream=stream,
|
|
2029
2038
|
default_catalog=self.default_catalog,
|
|
2030
|
-
default_catalog_dialect=self.
|
|
2039
|
+
default_catalog_dialect=self.engine_adapter.DIALECT,
|
|
2031
2040
|
)
|
|
2032
2041
|
|
|
2033
2042
|
@python_api_analytics
|
|
@@ -2466,7 +2475,7 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
2466
2475
|
self.console.log_test_results(
|
|
2467
2476
|
result,
|
|
2468
2477
|
test_output,
|
|
2469
|
-
self.
|
|
2478
|
+
self._test_connection_config._engine_adapter.DIALECT,
|
|
2470
2479
|
)
|
|
2471
2480
|
if not result.wasSuccessful():
|
|
2472
2481
|
raise PlanError(
|
|
@@ -2487,7 +2496,7 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
2487
2496
|
if snapshot.version
|
|
2488
2497
|
else snapshot.qualified_view_name.for_environment(
|
|
2489
2498
|
EnvironmentNamingInfo.from_environment_catalog_mapping(
|
|
2490
|
-
self.environment_catalog_mapping,
|
|
2499
|
+
self.config.environment_catalog_mapping,
|
|
2491
2500
|
name=c.PROD,
|
|
2492
2501
|
suffix_target=self.config.environment_suffix_target,
|
|
2493
2502
|
)
|
|
@@ -2499,63 +2508,24 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
2499
2508
|
@cached_property
|
|
2500
2509
|
def engine_adapters(self) -> t.Dict[str, EngineAdapter]:
|
|
2501
2510
|
"""Returns all the engine adapters for the gateways defined in the configuration."""
|
|
2502
|
-
adapters: t.Dict[str, EngineAdapter] = {self.selected_gateway: self.engine_adapter}
|
|
2503
2511
|
for gateway_name in self.config.gateways:
|
|
2504
2512
|
if gateway_name != self.selected_gateway:
|
|
2505
2513
|
connection = self.config.get_connection(gateway_name)
|
|
2506
2514
|
adapter = connection.create_engine_adapter(concurrent_tasks=self.concurrent_tasks)
|
|
2507
|
-
|
|
2508
|
-
return
|
|
2515
|
+
self._engine_adapters[gateway_name] = adapter
|
|
2516
|
+
return self._engine_adapters
|
|
2509
2517
|
|
|
2510
2518
|
@cached_property
|
|
2511
2519
|
def default_catalog_per_gateway(self) -> t.Dict[str, str]:
|
|
2512
2520
|
"""Returns the default catalogs for each engine adapter."""
|
|
2513
2521
|
if self._default_catalog_per_gateway is None:
|
|
2514
|
-
self._default_catalog_per_gateway =
|
|
2515
|
-
|
|
2516
|
-
|
|
2522
|
+
self._default_catalog_per_gateway = {
|
|
2523
|
+
name: adapter.default_catalog
|
|
2524
|
+
for name, adapter in self.engine_adapters.items()
|
|
2525
|
+
if adapter.default_catalog
|
|
2526
|
+
}
|
|
2517
2527
|
return self._default_catalog_per_gateway
|
|
2518
2528
|
|
|
2519
|
-
@cached_property
|
|
2520
|
-
def concurrent_tasks(self) -> int:
|
|
2521
|
-
if self._concurrent_tasks is None:
|
|
2522
|
-
self._concurrent_tasks = self.connection_config.concurrent_tasks
|
|
2523
|
-
return self._concurrent_tasks
|
|
2524
|
-
|
|
2525
|
-
@cached_property
|
|
2526
|
-
def connection_config(self) -> ConnectionConfig:
|
|
2527
|
-
if self._connection_config is None:
|
|
2528
|
-
self._connection_config = self.config.get_connection(self.selected_gateway)
|
|
2529
|
-
return self._connection_config
|
|
2530
|
-
|
|
2531
|
-
@cached_property
|
|
2532
|
-
def test_connection_config(self) -> ConnectionConfig:
|
|
2533
|
-
if self._test_connection_config is None:
|
|
2534
|
-
self._test_connection_config = self.config.get_test_connection(
|
|
2535
|
-
self.gateway,
|
|
2536
|
-
self.default_catalog,
|
|
2537
|
-
default_catalog_dialect=self.engine_adapter.DIALECT,
|
|
2538
|
-
)
|
|
2539
|
-
return self._test_connection_config
|
|
2540
|
-
|
|
2541
|
-
@cached_property
|
|
2542
|
-
def environment_catalog_mapping(self) -> RegexKeyDict:
|
|
2543
|
-
engine_adapter = None
|
|
2544
|
-
try:
|
|
2545
|
-
engine_adapter = self.engine_adapter
|
|
2546
|
-
except Exception:
|
|
2547
|
-
pass
|
|
2548
|
-
|
|
2549
|
-
if (
|
|
2550
|
-
self.config.environment_catalog_mapping
|
|
2551
|
-
and engine_adapter
|
|
2552
|
-
and not self.engine_adapter.catalog_support.is_multi_catalog_supported
|
|
2553
|
-
):
|
|
2554
|
-
raise SQLMeshError(
|
|
2555
|
-
"Environment catalog mapping is only supported for engine adapters that support multiple catalogs"
|
|
2556
|
-
)
|
|
2557
|
-
return self.config.environment_catalog_mapping
|
|
2558
|
-
|
|
2559
2529
|
def _get_engine_adapter(self, gateway: t.Optional[str] = None) -> EngineAdapter:
|
|
2560
2530
|
if gateway:
|
|
2561
2531
|
if adapter := self.engine_adapters.get(gateway):
|
|
@@ -2616,8 +2586,7 @@ class GenericContext(BaseContext, t.Generic[C]):
|
|
|
2616
2586
|
ensure_finalized_snapshots=ensure_finalized_snapshots,
|
|
2617
2587
|
diff_rendered=diff_rendered,
|
|
2618
2588
|
environment_statements=self._environment_statements,
|
|
2619
|
-
gateway_managed_virtual_layer=self.
|
|
2620
|
-
infer_python_dependencies=self.config.infer_python_dependencies,
|
|
2589
|
+
gateway_managed_virtual_layer=self.gateway_managed_virtual_layer,
|
|
2621
2590
|
)
|
|
2622
2591
|
|
|
2623
2592
|
def _destroy(self) -> None:
|
sqlmesh/core/context_diff.py
CHANGED
|
@@ -102,7 +102,6 @@ class ContextDiff(PydanticModel):
|
|
|
102
102
|
diff_rendered: bool = False,
|
|
103
103
|
environment_statements: t.Optional[t.List[EnvironmentStatements]] = [],
|
|
104
104
|
gateway_managed_virtual_layer: bool = False,
|
|
105
|
-
infer_python_dependencies: bool = True,
|
|
106
105
|
) -> ContextDiff:
|
|
107
106
|
"""Create a ContextDiff object.
|
|
108
107
|
|
|
@@ -117,12 +116,6 @@ class ContextDiff(PydanticModel):
|
|
|
117
116
|
the environment is not finalized.
|
|
118
117
|
provided_requirements: Python dependencies sourced from the lock file.
|
|
119
118
|
excluded_requirements: Python dependencies to exclude.
|
|
120
|
-
diff_rendered: Whether to compute the diff of the rendered version of the compared expressions.
|
|
121
|
-
environment_statements: A list of `before_all` or `after_all` statements associated with the environment.
|
|
122
|
-
gateway_managed_virtual_layer: Whether the models' views in the virtual layer are created by the
|
|
123
|
-
model-specific gateway rather than the default gateway.
|
|
124
|
-
infer_python_dependencies: Whether to statically analyze Python code to automatically infer Python
|
|
125
|
-
package requirements.
|
|
126
119
|
|
|
127
120
|
Returns:
|
|
128
121
|
The ContextDiff object.
|
|
@@ -215,7 +208,6 @@ class ContextDiff(PydanticModel):
|
|
|
215
208
|
provided_requirements or {},
|
|
216
209
|
excluded_requirements or set(),
|
|
217
210
|
snapshots.values(),
|
|
218
|
-
infer_python_dependencies=infer_python_dependencies,
|
|
219
211
|
)
|
|
220
212
|
|
|
221
213
|
previous_environment_statements = state_reader.get_environment_statements(environment)
|
|
@@ -483,41 +475,29 @@ def _build_requirements(
|
|
|
483
475
|
provided_requirements: t.Dict[str, str],
|
|
484
476
|
excluded_requirements: t.Set[str],
|
|
485
477
|
snapshots: t.Collection[Snapshot],
|
|
486
|
-
infer_python_dependencies: bool = True,
|
|
487
478
|
) -> t.Dict[str, str]:
|
|
488
479
|
requirements = {
|
|
489
480
|
k: v for k, v in provided_requirements.items() if k not in excluded_requirements
|
|
490
481
|
}
|
|
491
|
-
|
|
492
|
-
if not infer_python_dependencies:
|
|
493
|
-
return requirements
|
|
494
|
-
|
|
495
482
|
distributions = metadata.packages_distributions()
|
|
496
483
|
|
|
497
484
|
for snapshot in snapshots:
|
|
498
|
-
if
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
):
|
|
517
|
-
requirements[dist] = metadata.version(dist)
|
|
518
|
-
except metadata.PackageNotFoundError:
|
|
519
|
-
from sqlmesh.core.console import get_console
|
|
520
|
-
|
|
521
|
-
get_console().log_warning(f"Failed to find package for {lib}.")
|
|
522
|
-
|
|
485
|
+
if snapshot.is_model:
|
|
486
|
+
for executable in snapshot.model.python_env.values():
|
|
487
|
+
if executable.kind == "import":
|
|
488
|
+
try:
|
|
489
|
+
start = "from " if executable.payload.startswith("from ") else "import "
|
|
490
|
+
lib = executable.payload.split(start)[1].split()[0].split(".")[0]
|
|
491
|
+
if lib in distributions:
|
|
492
|
+
for dist in distributions[lib]:
|
|
493
|
+
if (
|
|
494
|
+
dist not in requirements
|
|
495
|
+
and dist not in IGNORED_PACKAGES
|
|
496
|
+
and dist not in excluded_requirements
|
|
497
|
+
):
|
|
498
|
+
requirements[dist] = metadata.version(dist)
|
|
499
|
+
except metadata.PackageNotFoundError:
|
|
500
|
+
from sqlmesh.core.console import get_console
|
|
501
|
+
|
|
502
|
+
get_console().log_warning(f"Failed to find package for {lib}.")
|
|
523
503
|
return requirements
|
sqlmesh/core/model/cache.py
CHANGED
|
@@ -142,7 +142,6 @@ class OptimizedQueryCache:
|
|
|
142
142
|
|
|
143
143
|
def _put(self, name: str, model: SqlModel) -> None:
|
|
144
144
|
optimized_query = model.render_query()
|
|
145
|
-
|
|
146
145
|
new_entry = OptimizedQueryCacheEntry(
|
|
147
146
|
optimized_rendered_query=optimized_query,
|
|
148
147
|
renderer_violations=model.violated_rules_for_query,
|
|
@@ -181,17 +180,10 @@ def load_optimized_query(
|
|
|
181
180
|
assert _optimized_query_cache
|
|
182
181
|
model, snapshot_id = model_snapshot_id
|
|
183
182
|
|
|
184
|
-
entry_name = None
|
|
185
|
-
|
|
186
183
|
if isinstance(model, SqlModel):
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
# this can happen if there is a query rendering error.
|
|
191
|
-
# for example, the model query references some python library or function that was available
|
|
192
|
-
# at the time the model was created but has since been removed locally
|
|
193
|
-
logger.exception(f"Failed to cache optimized query for model '{model.name}'")
|
|
194
|
-
|
|
184
|
+
entry_name = _optimized_query_cache.put(model)
|
|
185
|
+
else:
|
|
186
|
+
entry_name = None
|
|
195
187
|
return snapshot_id, entry_name
|
|
196
188
|
|
|
197
189
|
|
sqlmesh/core/plan/builder.py
CHANGED
|
@@ -21,11 +21,7 @@ from sqlmesh.core.plan.definition import (
|
|
|
21
21
|
UserProvidedFlags,
|
|
22
22
|
earliest_interval_start,
|
|
23
23
|
)
|
|
24
|
-
from sqlmesh.core.schema_diff import
|
|
25
|
-
get_schema_differ,
|
|
26
|
-
has_drop_alteration,
|
|
27
|
-
get_dropped_column_names,
|
|
28
|
-
)
|
|
24
|
+
from sqlmesh.core.schema_diff import SchemaDiffer, has_drop_alteration, get_dropped_column_names
|
|
29
25
|
from sqlmesh.core.snapshot import (
|
|
30
26
|
DeployabilityIndex,
|
|
31
27
|
Snapshot,
|
|
@@ -82,12 +78,14 @@ class PlanBuilder:
|
|
|
82
78
|
ensure_finalized_snapshots: Whether to compare against snapshots from the latest finalized
|
|
83
79
|
environment state, or to use whatever snapshots are in the current environment state even if
|
|
84
80
|
the environment is not finalized.
|
|
81
|
+
engine_schema_differ: Schema differ from the context engine adapter.
|
|
85
82
|
interval_end_per_model: The mapping from model FQNs to target end dates.
|
|
86
83
|
"""
|
|
87
84
|
|
|
88
85
|
def __init__(
|
|
89
86
|
self,
|
|
90
87
|
context_diff: ContextDiff,
|
|
88
|
+
engine_schema_differ: SchemaDiffer,
|
|
91
89
|
start: t.Optional[TimeLike] = None,
|
|
92
90
|
end: t.Optional[TimeLike] = None,
|
|
93
91
|
execution_time: t.Optional[TimeLike] = None,
|
|
@@ -139,6 +137,7 @@ class PlanBuilder:
|
|
|
139
137
|
self._backfill_models = backfill_models
|
|
140
138
|
self._end = end or default_end
|
|
141
139
|
self._apply = apply
|
|
140
|
+
self._engine_schema_differ = engine_schema_differ
|
|
142
141
|
self._console = console or get_console()
|
|
143
142
|
self._choices: t.Dict[SnapshotId, SnapshotChangeCategory] = {}
|
|
144
143
|
self._user_provided_flags = user_provided_flags
|
|
@@ -494,7 +493,7 @@ class PlanBuilder:
|
|
|
494
493
|
if columns_to_types_all_known(old_columns_to_types) and columns_to_types_all_known(
|
|
495
494
|
new_columns_to_types
|
|
496
495
|
):
|
|
497
|
-
schema_diff =
|
|
496
|
+
schema_diff = self._engine_schema_differ.compare_columns(
|
|
498
497
|
new.name,
|
|
499
498
|
old_columns_to_types,
|
|
500
499
|
new_columns_to_types,
|
sqlmesh/core/schema_diff.py
CHANGED
|
@@ -723,27 +723,5 @@ def get_dropped_column_names(alter_expressions: t.List[exp.Alter]) -> t.List[str
|
|
|
723
723
|
return dropped_columns
|
|
724
724
|
|
|
725
725
|
|
|
726
|
-
def get_schema_differ(dialect: str) -> SchemaDiffer:
|
|
727
|
-
"""
|
|
728
|
-
Returns the appropriate SchemaDiffer for a given dialect without initializing the engine adapter.
|
|
729
|
-
|
|
730
|
-
Args:
|
|
731
|
-
dialect: The dialect for which to get the schema differ.
|
|
732
|
-
|
|
733
|
-
Returns:
|
|
734
|
-
The SchemaDiffer instance configured for the given dialect.
|
|
735
|
-
"""
|
|
736
|
-
from sqlmesh.core.engine_adapter import (
|
|
737
|
-
DIALECT_TO_ENGINE_ADAPTER,
|
|
738
|
-
DIALECT_ALIASES,
|
|
739
|
-
EngineAdapter,
|
|
740
|
-
)
|
|
741
|
-
|
|
742
|
-
dialect = dialect.lower()
|
|
743
|
-
dialect = DIALECT_ALIASES.get(dialect, dialect)
|
|
744
|
-
engine_adapter_class = DIALECT_TO_ENGINE_ADAPTER.get(dialect, EngineAdapter)
|
|
745
|
-
return getattr(engine_adapter_class, "SCHEMA_DIFFER", SchemaDiffer())
|
|
746
|
-
|
|
747
|
-
|
|
748
726
|
def _get_name_and_type(struct: exp.ColumnDef) -> t.Tuple[exp.Identifier, exp.DataType]:
|
|
749
727
|
return struct.this, struct.args["kind"]
|
sqlmesh/core/selector.py
CHANGED
sqlmesh/core/test/definition.py
CHANGED
|
@@ -559,10 +559,7 @@ class ModelTest(unittest.TestCase):
|
|
|
559
559
|
) -> pd.DataFrame:
|
|
560
560
|
query = values.get("query")
|
|
561
561
|
if query:
|
|
562
|
-
|
|
563
|
-
query = self._add_missing_columns(query, columns)
|
|
564
|
-
|
|
565
|
-
return self._execute(query)
|
|
562
|
+
return self._execute(self._add_missing_columns(query, columns))
|
|
566
563
|
|
|
567
564
|
rows = values["rows"]
|
|
568
565
|
if columns:
|
sqlmesh/dbt/loader.py
CHANGED
|
@@ -28,6 +28,7 @@ from sqlmesh.utils import UniqueKeyDict
|
|
|
28
28
|
from sqlmesh.utils.errors import ConfigError
|
|
29
29
|
from sqlmesh.utils.jinja import (
|
|
30
30
|
JinjaMacroRegistry,
|
|
31
|
+
extract_macro_references_and_variables,
|
|
31
32
|
make_jinja_registry,
|
|
32
33
|
)
|
|
33
34
|
|
|
@@ -239,11 +240,11 @@ class DbtLoader(Loader):
|
|
|
239
240
|
def _load_environment_statements(self, macros: MacroRegistry) -> t.List[EnvironmentStatements]:
|
|
240
241
|
"""Loads dbt's on_run_start, on_run_end hooks into sqlmesh's before_all, after_all statements respectively."""
|
|
241
242
|
|
|
242
|
-
|
|
243
|
-
project_names: t.Set[str] = set()
|
|
243
|
+
environment_statements: t.List[EnvironmentStatements] = []
|
|
244
244
|
dialect = self.config.dialect
|
|
245
245
|
for project in self._load_projects():
|
|
246
246
|
context = project.context
|
|
247
|
+
hooks_by_package_name: t.Dict[str, EnvironmentStatements] = {}
|
|
247
248
|
for package_name, package in project.packages.items():
|
|
248
249
|
context.set_and_render_variables(package.variables, package_name)
|
|
249
250
|
on_run_start: t.List[str] = [
|
|
@@ -255,14 +256,18 @@ class DbtLoader(Loader):
|
|
|
255
256
|
for on_run_hook in sorted(package.on_run_end.values(), key=lambda h: h.index)
|
|
256
257
|
]
|
|
257
258
|
|
|
258
|
-
if on_run_start
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
259
|
+
if statements := on_run_start + on_run_end:
|
|
260
|
+
jinja_references, used_variables = extract_macro_references_and_variables(
|
|
261
|
+
*statements
|
|
262
|
+
)
|
|
262
263
|
|
|
263
|
-
statements_context = context.context_for_dependencies(
|
|
264
|
+
statements_context = context.context_for_dependencies(
|
|
265
|
+
Dependencies(
|
|
266
|
+
variables=used_variables,
|
|
267
|
+
)
|
|
268
|
+
)
|
|
264
269
|
jinja_registry = make_jinja_registry(
|
|
265
|
-
statements_context.jinja_macros, package_name,
|
|
270
|
+
statements_context.jinja_macros, package_name, jinja_references
|
|
266
271
|
)
|
|
267
272
|
jinja_registry.add_globals(statements_context.jinja_globals)
|
|
268
273
|
|
|
@@ -278,15 +283,15 @@ class DbtLoader(Loader):
|
|
|
278
283
|
python_env={},
|
|
279
284
|
jinja_macros=jinja_registry,
|
|
280
285
|
)
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
286
|
+
# Project hooks should be executed first and then rest of the packages
|
|
287
|
+
environment_statements = [
|
|
288
|
+
statements
|
|
289
|
+
for _, statements in sorted(
|
|
290
|
+
hooks_by_package_name.items(),
|
|
291
|
+
key=lambda item: 0 if item[0] == context.project_name else 1,
|
|
292
|
+
)
|
|
293
|
+
]
|
|
294
|
+
return environment_statements
|
|
290
295
|
|
|
291
296
|
def _compute_yaml_max_mtime_per_subfolder(self, root: Path) -> t.Dict[Path, float]:
|
|
292
297
|
if not root.is_dir():
|