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 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.dev3'
21
- __version_tuple__ = version_tuple = (0, 186, 1, 'dev3')
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
@@ -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
- self._run_audits_for_metadata_snapshots(plan, new_snapshots)
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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlmesh
3
- Version: 0.186.1.dev3
3
+ Version: 0.186.1.dev5
4
4
  Summary: Next-generation data transformation framework
5
5
  Author-email: "TobikoData Inc." <engineering@tobikodata.com>
6
6
  License: Apache License
@@ -1,5 +1,5 @@
1
1
  sqlmesh/__init__.py,sha256=69xw6bTmi4cW90M-sl3g6wLDgxVcLHcKg1q8GS3lqyA,7466
2
- sqlmesh/_version.py,sha256=q0wHKOOCel53puhXCfdhzyK_CaoMrYy0za8-7qWbl-I,528
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=scyhg-gq0czu7-2y9n1tBKnLfM0jT51QaYR_hFCeQU8,73917
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=ocRqGy36RKZyfkGBzaXDnCA1-p8JPkb5IF__ZrmEhL4,25724
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=dywc9i-diWLA3vB-X_28I8NX3BPoSWAjcaP31zkzr0k,11115
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.dev3.dist-info/licenses/LICENSE,sha256=OlMefUjgWJdULtf84BLW0AZZcY8DwdgQqb_1j2862j8,11346
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.dev3.dist-info/METADATA,sha256=Z5edNTAmrWqwHkPo1u9p_deLywLwvoyqe8j4knOuZuo,25523
390
- sqlmesh-0.186.1.dev3.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
391
- sqlmesh-0.186.1.dev3.dist-info/entry_points.txt,sha256=pIYKtg-u-uO7BK_Y0qrdmfyj0bYrcMc3Xiqr5WE3VFk,121
392
- sqlmesh-0.186.1.dev3.dist-info/top_level.txt,sha256=bspjo5vjELQkuN0qKuTFIbsrUt3Zeo8D2mlKeHG1LdE,12
393
- sqlmesh-0.186.1.dev3.dist-info/RECORD,,
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,,