sqlmesh 0.186.1.dev3__py3-none-any.whl → 0.186.1.dev5__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/connection.py +38 -0
- sqlmesh/core/plan/evaluator.py +23 -2
- sqlmesh/utils/pydantic.py +18 -0
- {sqlmesh-0.186.1.dev3.dist-info → sqlmesh-0.186.1.dev5.dist-info}/METADATA +1 -1
- {sqlmesh-0.186.1.dev3.dist-info → sqlmesh-0.186.1.dev5.dist-info}/RECORD +10 -10
- {sqlmesh-0.186.1.dev3.dist-info → sqlmesh-0.186.1.dev5.dist-info}/WHEEL +0 -0
- {sqlmesh-0.186.1.dev3.dist-info → sqlmesh-0.186.1.dev5.dist-info}/entry_points.txt +0 -0
- {sqlmesh-0.186.1.dev3.dist-info → sqlmesh-0.186.1.dev5.dist-info}/licenses/LICENSE +0 -0
- {sqlmesh-0.186.1.dev3.dist-info → sqlmesh-0.186.1.dev5.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.186.1.
|
|
21
|
-
__version_tuple__ = version_tuple = (0, 186, 1, '
|
|
20
|
+
__version__ = version = '0.186.1.dev5'
|
|
21
|
+
__version_tuple__ = version_tuple = (0, 186, 1, 'dev5')
|
|
@@ -13,6 +13,7 @@ from functools import partial
|
|
|
13
13
|
|
|
14
14
|
import pydantic
|
|
15
15
|
from pydantic import Field
|
|
16
|
+
from pydantic_core import from_json
|
|
16
17
|
from packaging import version
|
|
17
18
|
from sqlglot import exp
|
|
18
19
|
from sqlglot.helper import subclasses
|
|
@@ -33,6 +34,7 @@ from sqlmesh.utils.pydantic import (
|
|
|
33
34
|
field_validator,
|
|
34
35
|
model_validator,
|
|
35
36
|
validation_error_message,
|
|
37
|
+
get_concrete_types_from_typehint,
|
|
36
38
|
)
|
|
37
39
|
from sqlmesh.utils.aws import validate_s3_uri
|
|
38
40
|
|
|
@@ -177,6 +179,42 @@ class ConnectionConfig(abc.ABC, BaseConfig):
|
|
|
177
179
|
return self.db
|
|
178
180
|
return None
|
|
179
181
|
|
|
182
|
+
@model_validator(mode="before")
|
|
183
|
+
@classmethod
|
|
184
|
+
def _expand_json_strings_to_concrete_types(cls, data: t.Any) -> t.Any:
|
|
185
|
+
"""
|
|
186
|
+
There are situations where a connection config class has a field that is some kind of complex type
|
|
187
|
+
(eg a list of strings or a dict) but the value is being supplied from a source such as an environment variable
|
|
188
|
+
|
|
189
|
+
When this happens, the value is supplied as a string rather than a Python object. We need some way
|
|
190
|
+
of turning this string into the corresponding Python list or dict.
|
|
191
|
+
|
|
192
|
+
Rather than doing this piecemeal on every config subclass, this provides a generic implementatation
|
|
193
|
+
to identify fields that may be be supplied as JSON strings and handle them transparently
|
|
194
|
+
"""
|
|
195
|
+
if data and isinstance(data, dict):
|
|
196
|
+
for maybe_json_field_name in cls._get_list_and_dict_field_names():
|
|
197
|
+
if (value := data.get(maybe_json_field_name)) and isinstance(value, str):
|
|
198
|
+
# crude JSON check as we dont want to try and parse every string we get
|
|
199
|
+
value = value.strip()
|
|
200
|
+
if value.startswith("{") or value.startswith("["):
|
|
201
|
+
data[maybe_json_field_name] = from_json(value)
|
|
202
|
+
|
|
203
|
+
return data
|
|
204
|
+
|
|
205
|
+
@classmethod
|
|
206
|
+
def _get_list_and_dict_field_names(cls) -> t.Set[str]:
|
|
207
|
+
field_names = set()
|
|
208
|
+
for name, field in cls.model_fields.items():
|
|
209
|
+
if field.annotation:
|
|
210
|
+
field_types = get_concrete_types_from_typehint(field.annotation)
|
|
211
|
+
|
|
212
|
+
# check if the field type is something that could concievably be supplied as a json string
|
|
213
|
+
if any(ft is t for t in (list, tuple, set, dict) for ft in field_types):
|
|
214
|
+
field_names.add(name)
|
|
215
|
+
|
|
216
|
+
return field_names
|
|
217
|
+
|
|
180
218
|
|
|
181
219
|
class DuckDBAttachOptions(BaseConfig):
|
|
182
220
|
type: str
|
sqlmesh/core/plan/evaluator.py
CHANGED
|
@@ -116,6 +116,7 @@ class BuiltInPlanEvaluator(PlanEvaluator):
|
|
|
116
116
|
after_promote_snapshots = all_names - before_promote_snapshots
|
|
117
117
|
deployability_index_for_evaluation = DeployabilityIndex.all_deployable()
|
|
118
118
|
|
|
119
|
+
# Step 1: Run before_all environment statements before doing anything else
|
|
119
120
|
execute_environment_statements(
|
|
120
121
|
adapter=self.snapshot_evaluator.adapter,
|
|
121
122
|
environment_statements=plan.environment_statements or [],
|
|
@@ -128,15 +129,24 @@ class BuiltInPlanEvaluator(PlanEvaluator):
|
|
|
128
129
|
execution_time=plan.execution_time,
|
|
129
130
|
)
|
|
130
131
|
|
|
131
|
-
|
|
132
|
-
|
|
132
|
+
# Step 2:Store new snapshot records in the state and create physical tables for them
|
|
133
133
|
push_completion_status = self._push(plan, snapshots, deployability_index_for_creation)
|
|
134
134
|
if push_completion_status.is_nothing_to_do:
|
|
135
135
|
self.console.log_success(
|
|
136
136
|
"" if plan.restatements else "\nSKIP: No physical layer updates to perform"
|
|
137
137
|
)
|
|
138
|
+
|
|
139
|
+
# Step 3: Update the intervals for the new forward-only snapshots
|
|
138
140
|
update_intervals_for_new_snapshots(plan.new_snapshots, self.state_sync)
|
|
141
|
+
|
|
142
|
+
# Step 4: Run audits without evaluations for snapshots that capture audit metadata changes
|
|
143
|
+
self._run_audits_for_metadata_snapshots(plan, new_snapshots)
|
|
144
|
+
|
|
145
|
+
# Step 5: Remove intervals for snapshots that need to be restated
|
|
139
146
|
self._restate(plan, snapshots_by_name)
|
|
147
|
+
|
|
148
|
+
# Step 6: Backfill missing intervals for snapshots that can be backfilled before updating
|
|
149
|
+
# the schema of production tables
|
|
140
150
|
first_bf_completion_status = self._backfill(
|
|
141
151
|
plan,
|
|
142
152
|
snapshots_by_name,
|
|
@@ -144,9 +154,15 @@ class BuiltInPlanEvaluator(PlanEvaluator):
|
|
|
144
154
|
deployability_index_for_evaluation,
|
|
145
155
|
circuit_breaker=circuit_breaker,
|
|
146
156
|
)
|
|
157
|
+
|
|
158
|
+
# Step 7: Update the target environment record in the state and migrate table schemas for forward-only
|
|
159
|
+
# snapshots if deploying to production
|
|
147
160
|
promotion_result = self._promote(
|
|
148
161
|
plan, snapshots, before_promote_snapshots, deployability_index_for_creation
|
|
149
162
|
)
|
|
163
|
+
|
|
164
|
+
# Step 8: Backfill missing intervals for snapshots that can be backfilled only after updating
|
|
165
|
+
# the schema of production tables
|
|
150
166
|
second_bf_completion_status = self._backfill(
|
|
151
167
|
plan,
|
|
152
168
|
snapshots_by_name,
|
|
@@ -154,15 +170,20 @@ class BuiltInPlanEvaluator(PlanEvaluator):
|
|
|
154
170
|
deployability_index_for_evaluation,
|
|
155
171
|
circuit_breaker=circuit_breaker,
|
|
156
172
|
)
|
|
173
|
+
|
|
157
174
|
if (
|
|
158
175
|
first_bf_completion_status.is_nothing_to_do
|
|
159
176
|
and second_bf_completion_status.is_nothing_to_do
|
|
160
177
|
):
|
|
161
178
|
self.console.log_success("SKIP: No model batches to execute")
|
|
179
|
+
|
|
180
|
+
# Step 9: Update environment views to point at new physical tables and finalize the environment
|
|
181
|
+
# record in the state
|
|
162
182
|
self._update_views(
|
|
163
183
|
plan, snapshots, promotion_result, deployability_index_for_evaluation
|
|
164
184
|
)
|
|
165
185
|
|
|
186
|
+
# Step 10: Run after_all environment statements
|
|
166
187
|
execute_environment_statements(
|
|
167
188
|
adapter=self.snapshot_evaluator.adapter,
|
|
168
189
|
environment_statements=plan.environment_statements or [],
|
sqlmesh/utils/pydantic.py
CHANGED
|
@@ -306,6 +306,24 @@ def cron_validator(v: t.Any) -> str:
|
|
|
306
306
|
return v
|
|
307
307
|
|
|
308
308
|
|
|
309
|
+
def get_concrete_types_from_typehint(typehint: type[t.Any]) -> set[type[t.Any]]:
|
|
310
|
+
concrete_types = set()
|
|
311
|
+
unpacked = t.get_origin(typehint)
|
|
312
|
+
if unpacked is None:
|
|
313
|
+
if type(typehint) == type(type):
|
|
314
|
+
return {typehint}
|
|
315
|
+
elif unpacked is t.Union:
|
|
316
|
+
for item in t.get_args(typehint):
|
|
317
|
+
if str(item).startswith("typing."):
|
|
318
|
+
concrete_types |= get_concrete_types_from_typehint(item)
|
|
319
|
+
else:
|
|
320
|
+
concrete_types.add(item)
|
|
321
|
+
else:
|
|
322
|
+
concrete_types.add(unpacked)
|
|
323
|
+
|
|
324
|
+
return concrete_types
|
|
325
|
+
|
|
326
|
+
|
|
309
327
|
if t.TYPE_CHECKING:
|
|
310
328
|
SQLGlotListOfStrings = t.List[str]
|
|
311
329
|
SQLGlotString = str
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
sqlmesh/__init__.py,sha256=69xw6bTmi4cW90M-sl3g6wLDgxVcLHcKg1q8GS3lqyA,7466
|
|
2
|
-
sqlmesh/_version.py,sha256=
|
|
2
|
+
sqlmesh/_version.py,sha256=3v3CElNhp7edOXQqADP-xzMSjCYE9ldTFk_BbXg7f8U,528
|
|
3
3
|
sqlmesh/magics.py,sha256=JHorAZNtezf123jmTyNSoUC9yHmv-08hMP205PJmmIo,39750
|
|
4
4
|
sqlmesh/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
sqlmesh/cicd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -41,7 +41,7 @@ sqlmesh/core/config/__init__.py,sha256=b4gFb04tpeZpowqJD-7h3U3TLgxrpQhZahVEAo6VW
|
|
|
41
41
|
sqlmesh/core/config/base.py,sha256=t8NQmsgQoZSc-k0dlDiCb8t1jj0AMYdGZ-6se9q_Pks,4898
|
|
42
42
|
sqlmesh/core/config/categorizer.py,sha256=6vzUoNLjR6GOEb_2mYVz2TwmMv2BfldgHX2u-Le5HZs,1975
|
|
43
43
|
sqlmesh/core/config/common.py,sha256=-o_HoRFtR4u84frg_TLno7z7vS9II6ASiOayb59MKHo,2806
|
|
44
|
-
sqlmesh/core/config/connection.py,sha256=
|
|
44
|
+
sqlmesh/core/config/connection.py,sha256=NlTFCqRVA9S18EfdXELH3Qb79Qfj84Tt-_eW0-4P0Eg,75808
|
|
45
45
|
sqlmesh/core/config/feature_flag.py,sha256=JRcD31OG_t2cYc24meKbHDGB0iVID0P07V2oOeB_mgA,203
|
|
46
46
|
sqlmesh/core/config/format.py,sha256=6CXFbvnor56xbldKE-Vrm9k_ABRoY4v6vgIb3mCihiQ,1355
|
|
47
47
|
sqlmesh/core/config/gateway.py,sha256=tYngyqwd_4Qr9lhcv2hlvLvb_2pgYYtKu6hdGsTr-4I,1931
|
|
@@ -95,7 +95,7 @@ sqlmesh/core/model/seed.py,sha256=ctUHH6CmeEnBVJyIAZznx0xJBm09W7VIZ-76Cfwfq28,50
|
|
|
95
95
|
sqlmesh/core/plan/__init__.py,sha256=ctpnu9mK3uTujs0It8qRMqcj9GdObXDnvSgn4rD2zqc,450
|
|
96
96
|
sqlmesh/core/plan/builder.py,sha256=Fd5raxq6r6b_3mOZndiI2U7SmliVYevcrpxWNqRV_OE,38471
|
|
97
97
|
sqlmesh/core/plan/definition.py,sha256=SI3zi2poPkKJKTZogYv60Q7eIOhksaAcFUcu-J2-XqI,13218
|
|
98
|
-
sqlmesh/core/plan/evaluator.py,sha256=
|
|
98
|
+
sqlmesh/core/plan/evaluator.py,sha256=RAHJgQoV5Y5SIG_pV2O_Bn0VFlD1yzMC0UrUU6eaB_E,26842
|
|
99
99
|
sqlmesh/core/snapshot/__init__.py,sha256=Z5HTetNCZGoKF1WAKXk4LWL9dc8EC8lwS2O4TtoBmt4,1317
|
|
100
100
|
sqlmesh/core/snapshot/cache.py,sha256=MRYi_koDvp2yeQ5NDGoNFzhuJTw7Vh7mI0oJyeVbqio,4022
|
|
101
101
|
sqlmesh/core/snapshot/categorizer.py,sha256=qGG5870mu1jR2whKisSBH_GFbsyh96RnzJDgkN7DV9g,2482
|
|
@@ -264,11 +264,11 @@ sqlmesh/utils/jinja.py,sha256=6Iob2Pv88L2rCaHyl_V90b5GKsG9hI10Ua_FRWhQIl0,23628
|
|
|
264
264
|
sqlmesh/utils/metaprogramming.py,sha256=i1rxWi-oxdh1VwKoBh5Qvy0GgHm9GaDZMvIrv3QXGt4,23083
|
|
265
265
|
sqlmesh/utils/migration.py,sha256=R7Ck6FX-LfcujGy7sgS0kDWlK-xAEBODr3gqIQ8gC08,835
|
|
266
266
|
sqlmesh/utils/pandas.py,sha256=uKI-ygEtMcGDRzXdBu0RkGmMBkYxwu5O2Wabho841Ls,2196
|
|
267
|
-
sqlmesh/utils/pydantic.py,sha256=
|
|
267
|
+
sqlmesh/utils/pydantic.py,sha256=I898jAFqa3qU6lG2uPpRebVFncOUo8ZrLWM_R3K3DHU,11685
|
|
268
268
|
sqlmesh/utils/rich.py,sha256=xNZyPCqEc4TAlJlsEthg-5eYUWpaizz0QjBzO7a1Yv4,1509
|
|
269
269
|
sqlmesh/utils/windows.py,sha256=r7Yin4WEwbvH7sKA3hOJtRsclmscNuBeCklCfVPvtQs,611
|
|
270
270
|
sqlmesh/utils/yaml.py,sha256=np-WVcwmwsKghCgAj1OBBMsK1SXSRn4wR-H37cGiFr8,2282
|
|
271
|
-
sqlmesh-0.186.1.
|
|
271
|
+
sqlmesh-0.186.1.dev5.dist-info/licenses/LICENSE,sha256=OlMefUjgWJdULtf84BLW0AZZcY8DwdgQqb_1j2862j8,11346
|
|
272
272
|
web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
273
273
|
web/client/dist/index.html,sha256=xQIU9G6dbuTnmbHZ61bSYbh0gYz9A2lb4BRwLlXL94Y,5472
|
|
274
274
|
web/client/dist/assets/Audits-Dcl7Y5yf.js,sha256=D2CfXzrdXFdD_-7c51tBJCKNwUY9yGeIpDEaRae7V8I,1041
|
|
@@ -386,8 +386,8 @@ web/server/api/endpoints/models.py,sha256=ud-lRwriyI_OYg9tZchrBgeiXELiRTLNEodraf
|
|
|
386
386
|
web/server/api/endpoints/modules.py,sha256=8hqqgonGay_mJmpCw0IdbjsPhWlQH2VLdKAqha-myac,468
|
|
387
387
|
web/server/api/endpoints/plan.py,sha256=OYuQ_4dgbhG9ibTcX1a8mvYgH3ANxw9Fhbb4wg6QWqc,9222
|
|
388
388
|
web/server/api/endpoints/table_diff.py,sha256=Wd5YxeKbZB7AkrDvqFgvV9ZQlnKYOF1n5W_w2EHE_Zw,2085
|
|
389
|
-
sqlmesh-0.186.1.
|
|
390
|
-
sqlmesh-0.186.1.
|
|
391
|
-
sqlmesh-0.186.1.
|
|
392
|
-
sqlmesh-0.186.1.
|
|
393
|
-
sqlmesh-0.186.1.
|
|
389
|
+
sqlmesh-0.186.1.dev5.dist-info/METADATA,sha256=NiKDb3CP2KKR8HBi_lw8Gpwnx38auqfQg0rNmy3yifg,25523
|
|
390
|
+
sqlmesh-0.186.1.dev5.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
|
391
|
+
sqlmesh-0.186.1.dev5.dist-info/entry_points.txt,sha256=pIYKtg-u-uO7BK_Y0qrdmfyj0bYrcMc3Xiqr5WE3VFk,121
|
|
392
|
+
sqlmesh-0.186.1.dev5.dist-info/top_level.txt,sha256=bspjo5vjELQkuN0qKuTFIbsrUt3Zeo8D2mlKeHG1LdE,12
|
|
393
|
+
sqlmesh-0.186.1.dev5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|