Skip to content

Commit a7d353b

Browse files
authored
Merge branch 'main' into trey/comment-jinja-model
2 parents 69fcfc3 + 341cc3c commit a7d353b

File tree

14 files changed

+220
-17
lines changed

14 files changed

+220
-17
lines changed

pyproject.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ dependencies = [
2424
"requests",
2525
"rich[jupyter]",
2626
"ruamel.yaml",
27-
"sqlglot[rs]~=27.14.0",
27+
"sqlglot[rs]~=27.15.3",
2828
"tenacity",
2929
"time-machine",
3030
"json-stream"
@@ -56,7 +56,7 @@ dev = [
5656
"agate",
5757
"beautifulsoup4",
5858
"clickhouse-connect",
59-
"cryptography",
59+
"cryptography<46.0.0",
6060
"databricks-sql-connector",
6161
"dbt-bigquery",
6262
"dbt-core",
@@ -119,7 +119,7 @@ postgres = ["psycopg2"]
119119
redshift = ["redshift_connector"]
120120
slack = ["slack_sdk"]
121121
snowflake = [
122-
"cryptography",
122+
"cryptography<46.0.0",
123123
"snowflake-connector-python[pandas,secure-local-storage]",
124124
"snowflake-snowpark-python",
125125
]
@@ -135,7 +135,7 @@ lsp = [
135135
# Duplicate of web
136136
"fastapi==0.115.5",
137137
"watchfiles>=0.19.0",
138-
"uvicorn[standard]==0.22.0",
138+
# "uvicorn[standard]==0.22.0",
139139
"sse-starlette>=0.2.2",
140140
"pyarrow",
141141
# For lsp

sqlmesh/core/engine_adapter/base.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,6 +1044,7 @@ def clone_table(
10441044
target_table_name: TableName,
10451045
source_table_name: TableName,
10461046
replace: bool = False,
1047+
exists: bool = True,
10471048
clone_kwargs: t.Optional[t.Dict[str, t.Any]] = None,
10481049
**kwargs: t.Any,
10491050
) -> None:
@@ -1053,6 +1054,7 @@ def clone_table(
10531054
target_table_name: The name of the table that should be created.
10541055
source_table_name: The name of the source table that should be cloned.
10551056
replace: Whether or not to replace an existing table.
1057+
exists: Indicates whether to include the IF NOT EXISTS check.
10561058
"""
10571059
if not self.SUPPORTS_CLONING:
10581060
raise NotImplementedError(f"Engine does not support cloning: {type(self)}")
@@ -1063,6 +1065,7 @@ def clone_table(
10631065
this=exp.to_table(target_table_name),
10641066
kind="TABLE",
10651067
replace=replace,
1068+
exists=exists,
10661069
clone=exp.Clone(
10671070
this=exp.to_table(source_table_name),
10681071
**(clone_kwargs or {}),

sqlmesh/core/engine_adapter/databricks.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@ def clone_table(
299299
target_table_name: TableName,
300300
source_table_name: TableName,
301301
replace: bool = False,
302+
exists: bool = True,
302303
clone_kwargs: t.Optional[t.Dict[str, t.Any]] = None,
303304
**kwargs: t.Any,
304305
) -> None:

sqlmesh/core/engine_adapter/snowflake.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,7 @@ def clone_table(
610610
target_table_name: TableName,
611611
source_table_name: TableName,
612612
replace: bool = False,
613+
exists: bool = True,
613614
clone_kwargs: t.Optional[t.Dict[str, t.Any]] = None,
614615
**kwargs: t.Any,
615616
) -> None:

sqlmesh/core/plan/common.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ def should_force_rebuild(old: Snapshot, new: Snapshot) -> bool:
1616
if new.is_view and new.is_indirect_non_breaking and not new.is_forward_only:
1717
# View models always need to be rebuilt to reflect updated upstream dependencies
1818
return True
19-
if new.is_seed:
19+
if new.is_seed and not new.is_metadata:
2020
# Seed models always need to be rebuilt to reflect changes in the seed file
21+
# Unless only their metadata has been updated (eg description added) and the seed file has not been touched
2122
return True
2223
return is_breaking_kind_change(old, new)
2324

sqlmesh/core/snapshot/evaluator.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
from sqlglot import exp, select
3434
from sqlglot.executor import execute
35+
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_not_exception_type
3536

3637
from sqlmesh.core import constants as c
3738
from sqlmesh.core import dialect as d
@@ -76,6 +77,7 @@
7677
from sqlmesh.utils.errors import (
7778
ConfigError,
7879
DestructiveChangeError,
80+
MigrationNotSupportedError,
7981
SQLMeshError,
8082
format_destructive_change_msg,
8183
format_additive_change_msg,
@@ -1035,7 +1037,6 @@ def _clone_snapshot_in_dev(
10351037
adapter.clone_table(
10361038
target_table_name,
10371039
snapshot.table_name(),
1038-
replace=True,
10391040
rendered_physical_properties=rendered_physical_properties,
10401041
)
10411042
self._migrate_target_table(
@@ -1111,6 +1112,15 @@ def _migrate_snapshot(
11111112
dry_run=True,
11121113
)
11131114

1115+
# Retry in case when the table is migrated concurrently from another plan application
1116+
@retry(
1117+
reraise=True,
1118+
stop=stop_after_attempt(5),
1119+
wait=wait_exponential(min=1, max=16),
1120+
retry=retry_if_not_exception_type(
1121+
(DestructiveChangeError, AdditiveChangeError, MigrationNotSupportedError)
1122+
),
1123+
)
11141124
def _migrate_target_table(
11151125
self,
11161126
target_table_name: str,
@@ -1440,8 +1450,9 @@ def _can_clone(self, snapshot: Snapshot, deployability_index: DeployabilityIndex
14401450
and adapter.SUPPORTS_CLONING
14411451
# managed models cannot have their schema mutated because theyre based on queries, so clone + alter wont work
14421452
and not snapshot.is_managed
1443-
# If the deployable table is missing we can't clone it
14441453
and not deployability_index.is_deployable(snapshot)
1454+
# If the deployable table is missing we can't clone it
1455+
and adapter.table_exists(snapshot.table_name())
14451456
)
14461457

14471458
def _get_data_objects(
@@ -2671,7 +2682,7 @@ def migrate(
26712682
)
26722683
if len(potential_alter_operations) > 0:
26732684
# this can happen if a user changes a managed model and deliberately overrides a plan to be forward only, eg `sqlmesh plan --forward-only`
2674-
raise SQLMeshError(
2685+
raise MigrationNotSupportedError(
26752686
f"The schema of the managed model '{target_table_name}' cannot be updated in a forward-only fashion."
26762687
)
26772688

sqlmesh/utils/errors.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,10 @@ class AdditiveChangeError(SQLMeshError):
151151
pass
152152

153153

154+
class MigrationNotSupportedError(SQLMeshError):
155+
pass
156+
157+
154158
class NotificationTargetError(SQLMeshError):
155159
pass
156160

tests/core/engine_adapter/integration/test_integration.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
from sqlmesh import Config, Context
2424
from sqlmesh.cli.project_init import init_example_project
25+
from sqlmesh.core.config.common import VirtualEnvironmentMode
2526
from sqlmesh.core.config.connection import ConnectionConfig
2627
import sqlmesh.core.dialect as d
2728
from sqlmesh.core.environment import EnvironmentSuffixTarget
@@ -1938,7 +1939,12 @@ def test_transaction(ctx: TestContext):
19381939
ctx.compare_with_current(table, input_data)
19391940

19401941

1941-
def test_sushi(ctx: TestContext, tmp_path: pathlib.Path):
1942+
@pytest.mark.parametrize(
1943+
"virtual_environment_mode", [VirtualEnvironmentMode.FULL, VirtualEnvironmentMode.DEV_ONLY]
1944+
)
1945+
def test_sushi(
1946+
ctx: TestContext, tmp_path: pathlib.Path, virtual_environment_mode: VirtualEnvironmentMode
1947+
):
19421948
if ctx.mark == "athena_hive":
19431949
pytest.skip(
19441950
"Sushi end-to-end tests only need to run once for Athena because sushi needs a hybrid of both Hive and Iceberg"
@@ -1984,6 +1990,7 @@ def _mutate_config(gateway: str, config: Config) -> None:
19841990
).sql(dialect=config.model_defaults.dialect)
19851991
for e in before_all
19861992
]
1993+
config.virtual_environment_mode = virtual_environment_mode
19871994

19881995
context = ctx.create_context(_mutate_config, path=tmp_path, ephemeral_state_connection=False)
19891996

tests/core/engine_adapter/test_base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3347,7 +3347,7 @@ def test_clone_table(make_mocked_engine_adapter: t.Callable):
33473347
adapter.clone_table("target_table", "source_table")
33483348

33493349
adapter.cursor.execute.assert_called_once_with(
3350-
"CREATE TABLE `target_table` CLONE `source_table`"
3350+
"CREATE TABLE IF NOT EXISTS `target_table` CLONE `source_table`"
33513351
)
33523352

33533353

tests/core/engine_adapter/test_databricks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ def test_clone_table(mocker: MockFixture, make_mocked_engine_adapter: t.Callable
106106
adapter = make_mocked_engine_adapter(DatabricksEngineAdapter, default_catalog="test_catalog")
107107
adapter.clone_table("target_table", "source_table")
108108
adapter.cursor.execute.assert_called_once_with(
109-
"CREATE TABLE `target_table` SHALLOW CLONE `source_table`"
109+
"CREATE TABLE IF NOT EXISTS `target_table` SHALLOW CLONE `source_table`"
110110
)
111111

112112

0 commit comments

Comments
 (0)