sqlmesh 0.206.2.dev1__py3-none-any.whl → 0.206.2.dev3__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.206.2.dev1'
21
- __version_tuple__ = version_tuple = (0, 206, 2, 'dev1')
20
+ __version__ = version = '0.206.2.dev3'
21
+ __version_tuple__ = version_tuple = (0, 206, 2, 'dev3')
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import abc
4
- from dataclasses import dataclass
4
+ from dataclasses import dataclass, field
5
5
  from pathlib import Path
6
6
 
7
7
  from sqlmesh.core.model import Model
@@ -49,12 +49,21 @@ class TextEdit:
49
49
  new_text: str
50
50
 
51
51
 
52
+ @dataclass(frozen=True)
53
+ class CreateFile:
54
+ """Create a new file with the provided text."""
55
+
56
+ path: Path
57
+ text: str
58
+
59
+
52
60
  @dataclass(frozen=True)
53
61
  class Fix:
54
62
  """A fix that can be applied to resolve a rule violation."""
55
63
 
56
64
  title: str
57
- edits: t.List[TextEdit]
65
+ edits: t.List[TextEdit] = field(default_factory=list)
66
+ create_files: t.List[CreateFile] = field(default_factory=list)
58
67
 
59
68
 
60
69
  class _Rule(abc.ABCMeta):
@@ -14,7 +14,15 @@ from sqlmesh.core.linter.helpers import (
14
14
  get_range_of_model_block,
15
15
  read_range_from_string,
16
16
  )
17
- from sqlmesh.core.linter.rule import Rule, RuleViolation, Range, Fix, TextEdit, Position
17
+ from sqlmesh.core.linter.rule import (
18
+ Rule,
19
+ RuleViolation,
20
+ Range,
21
+ Fix,
22
+ TextEdit,
23
+ Position,
24
+ CreateFile,
25
+ )
18
26
  from sqlmesh.core.linter.definition import RuleSet
19
27
  from sqlmesh.core.model import Model, SqlModel, ExternalModel
20
28
  from sqlmesh.utils.lineage import extract_references_from_query, ExternalModelReference
@@ -227,7 +235,16 @@ class NoMissingExternalModels(Rule):
227
235
 
228
236
  external_models_path = root / EXTERNAL_MODELS_YAML
229
237
  if not external_models_path.exists():
230
- return None
238
+ return Fix(
239
+ title="Add external model file",
240
+ edits=[],
241
+ create_files=[
242
+ CreateFile(
243
+ path=external_models_path,
244
+ text=f"- name: '{model_name}'\n",
245
+ )
246
+ ],
247
+ )
231
248
 
232
249
  # Figure out the position to insert the new external model at the end of the file, whether
233
250
  # needs new line or not.
@@ -157,7 +157,7 @@ def _add_variables_to_python_env(
157
157
 
158
158
  if blueprint_variables:
159
159
  blueprint_variables = {
160
- k: SqlValue(sql=v.sql(dialect=dialect)) if isinstance(v, exp.Expression) else v
160
+ k.lower(): SqlValue(sql=v.sql(dialect=dialect)) if isinstance(v, exp.Expression) else v
161
161
  for k, v in blueprint_variables.items()
162
162
  }
163
163
  python_env[c.SQLMESH_BLUEPRINT_VARS] = Executable.value(
sqlmesh/lsp/context.py CHANGED
@@ -273,13 +273,41 @@ class LSPContext:
273
273
  if found_violation is not None and found_violation.fixes:
274
274
  # Create code actions for each fix
275
275
  for fix in found_violation.fixes:
276
- # Convert our Fix to LSP TextEdits
277
276
  changes: t.Dict[str, t.List[types.TextEdit]] = {}
277
+ document_changes: t.List[
278
+ t.Union[
279
+ types.TextDocumentEdit,
280
+ types.CreateFile,
281
+ types.RenameFile,
282
+ types.DeleteFile,
283
+ ]
284
+ ] = []
285
+
286
+ for create in fix.create_files:
287
+ create_uri = URI.from_path(create.path).value
288
+ document_changes.append(types.CreateFile(uri=create_uri))
289
+ document_changes.append(
290
+ types.TextDocumentEdit(
291
+ text_document=types.OptionalVersionedTextDocumentIdentifier(
292
+ uri=create_uri,
293
+ version=None,
294
+ ),
295
+ edits=[
296
+ types.TextEdit(
297
+ range=types.Range(
298
+ start=types.Position(line=0, character=0),
299
+ end=types.Position(line=0, character=0),
300
+ ),
301
+ new_text=create.text,
302
+ )
303
+ ],
304
+ )
305
+ )
306
+
278
307
  for edit in fix.edits:
279
308
  uri_key = URI.from_path(edit.path).value
280
309
  if uri_key not in changes:
281
310
  changes[uri_key] = []
282
- # Create a TextEdit for the LSP
283
311
  changes[uri_key].append(
284
312
  types.TextEdit(
285
313
  range=types.Range(
@@ -296,12 +324,15 @@ class LSPContext:
296
324
  )
297
325
  )
298
326
 
299
- # Create the code action
327
+ workspace_edit = types.WorkspaceEdit(
328
+ changes=changes if changes else None,
329
+ document_changes=document_changes if document_changes else None,
330
+ )
300
331
  code_action = types.CodeAction(
301
332
  title=fix.title,
302
333
  kind=types.CodeActionKind.QuickFix,
303
334
  diagnostics=[diagnostic],
304
- edit=types.WorkspaceEdit(changes=changes),
335
+ edit=workspace_edit,
305
336
  )
306
337
  code_actions.append(code_action)
307
338
 
@@ -0,0 +1,138 @@
1
+ """
2
+ Normalizes blueprint variables, so Customer_Field is stored as customer_field in the `python_env`:
3
+
4
+ MODEL (
5
+ ...
6
+ blueprints (
7
+ Customer_Field := 1
8
+ )
9
+ );
10
+
11
+ SELECT
12
+ @customer_field AS col
13
+ """
14
+
15
+ import json
16
+ import logging
17
+ from dataclasses import dataclass
18
+
19
+ from sqlglot import exp
20
+ from sqlmesh.core.console import get_console
21
+ from sqlmesh.utils.migration import index_text_type, blob_text_type
22
+
23
+
24
+ logger = logging.getLogger(__name__)
25
+
26
+
27
+ SQLMESH_BLUEPRINT_VARS = "__sqlmesh__blueprint__vars__"
28
+
29
+
30
+ # Make sure `SqlValue` is defined so it can be used by `eval` call in the migration
31
+ @dataclass
32
+ class SqlValue:
33
+ """A SQL string representing a generated SQLGlot AST."""
34
+
35
+ sql: str
36
+
37
+
38
+ def migrate(state_sync, **kwargs): # type: ignore
39
+ import pandas as pd
40
+
41
+ engine_adapter = state_sync.engine_adapter
42
+ schema = state_sync.schema
43
+ snapshots_table = "_snapshots"
44
+ if schema:
45
+ snapshots_table = f"{schema}.{snapshots_table}"
46
+
47
+ migration_needed = False
48
+ new_snapshots = []
49
+
50
+ for (
51
+ name,
52
+ identifier,
53
+ version,
54
+ snapshot,
55
+ kind_name,
56
+ updated_ts,
57
+ unpaused_ts,
58
+ ttl_ms,
59
+ unrestorable,
60
+ ) in engine_adapter.fetchall(
61
+ exp.select(
62
+ "name",
63
+ "identifier",
64
+ "version",
65
+ "snapshot",
66
+ "kind_name",
67
+ "updated_ts",
68
+ "unpaused_ts",
69
+ "ttl_ms",
70
+ "unrestorable",
71
+ ).from_(snapshots_table),
72
+ quote_identifiers=True,
73
+ ):
74
+ parsed_snapshot = json.loads(snapshot)
75
+ node = parsed_snapshot["node"]
76
+ python_env = node.get("python_env") or {}
77
+
78
+ migrate_snapshot = False
79
+
80
+ if blueprint_vars_executable := python_env.get(SQLMESH_BLUEPRINT_VARS):
81
+ blueprint_vars = eval(blueprint_vars_executable["payload"])
82
+
83
+ for var, value in dict(blueprint_vars).items():
84
+ lowercase_var = var.lower()
85
+ if var != lowercase_var:
86
+ if lowercase_var in blueprint_vars:
87
+ get_console().log_warning(
88
+ "SQLMesh is unable to fully migrate the state database, because the "
89
+ f"model '{node['name']}' contains two blueprint variables ('{var}' and "
90
+ f"'{lowercase_var}') that resolve to the same value ('{lowercase_var}'). "
91
+ "This may result in unexpected changes being reported by the next "
92
+ "`sqlmesh plan` command. If this happens, consider renaming either variable, "
93
+ "so that the lowercase version of their names are different."
94
+ )
95
+ else:
96
+ del blueprint_vars[var]
97
+ blueprint_vars[lowercase_var] = value
98
+ migrate_snapshot = True
99
+
100
+ if migrate_snapshot:
101
+ migration_needed = True
102
+ blueprint_vars_executable["payload"] = repr(blueprint_vars)
103
+
104
+ new_snapshots.append(
105
+ {
106
+ "name": name,
107
+ "identifier": identifier,
108
+ "version": version,
109
+ "snapshot": json.dumps(parsed_snapshot),
110
+ "kind_name": kind_name,
111
+ "updated_ts": updated_ts,
112
+ "unpaused_ts": unpaused_ts,
113
+ "ttl_ms": ttl_ms,
114
+ "unrestorable": unrestorable,
115
+ }
116
+ )
117
+
118
+ if migration_needed and new_snapshots:
119
+ engine_adapter.delete_from(snapshots_table, "TRUE")
120
+
121
+ index_type = index_text_type(engine_adapter.dialect)
122
+ blob_type = blob_text_type(engine_adapter.dialect)
123
+
124
+ engine_adapter.insert_append(
125
+ snapshots_table,
126
+ pd.DataFrame(new_snapshots),
127
+ columns_to_types={
128
+ "name": exp.DataType.build(index_type),
129
+ "identifier": exp.DataType.build(index_type),
130
+ "version": exp.DataType.build(index_type),
131
+ "snapshot": exp.DataType.build(blob_type),
132
+ "kind_name": exp.DataType.build("text"),
133
+ "updated_ts": exp.DataType.build("bigint"),
134
+ "unpaused_ts": exp.DataType.build("bigint"),
135
+ "ttl_ms": exp.DataType.build("bigint"),
136
+ "unrestorable": exp.DataType.build("boolean"),
137
+ },
138
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlmesh
3
- Version: 0.206.2.dev1
3
+ Version: 0.206.2.dev3
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=QjwaamJIdW7voXoS880yAx7tHm-Im4_mqGA-XJgafos,7631
2
- sqlmesh/_version.py,sha256=S4s0lANCdCA8rxuKgeIztkdnzaNgM5vUafG7dP6Q4hU,528
2
+ sqlmesh/_version.py,sha256=81qxsWTVH02pMJYGoBBAKEIHMBdl80V7JtlCq12vfoQ,528
3
3
  sqlmesh/magics.py,sha256=bEzYqXHcM0P3CjyUZ1O9arlmXAdLAhoglKbQ29fD9AE,41842
4
4
  sqlmesh/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  sqlmesh/cicd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -78,15 +78,15 @@ sqlmesh/core/engine_adapter/trino.py,sha256=Tws3GxqnC6BmXFohqru1TDxsgPH-21qV6Oky
78
78
  sqlmesh/core/linter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
79
79
  sqlmesh/core/linter/definition.py,sha256=JDJTkhByUw4Tr3nF-BOHKFAx_eASQqEqzX6AUVQUz8I,5659
80
80
  sqlmesh/core/linter/helpers.py,sha256=Bv11aGRIrnv9Ym9fudy3XQB0k-FvchkLtBTkGI91SEw,6504
81
- sqlmesh/core/linter/rule.py,sha256=MgFwfvlGEvh4nijsxc7Bbk_S9ctJ_m-nKCom9LIN4W4,3734
81
+ sqlmesh/core/linter/rule.py,sha256=nB3o1rHyN44ZOg5ImICP16SeUHimf-12ObdXJjkTGyM,3964
82
82
  sqlmesh/core/linter/rules/__init__.py,sha256=gevzfb67vFqckTCoVAe_TBGf6hQ-YtE1_YuGuXyh1L0,77
83
- sqlmesh/core/linter/rules/builtin.py,sha256=2H4yV4eVUCY25uFgO2M62czpZt5dXdK5mW6XGGOc12Q,9857
83
+ sqlmesh/core/linter/rules/builtin.py,sha256=BVBoBr1Ru-DA4VPnwfaodZdVq84afCc9qBgPLmwrfiA,10204
84
84
  sqlmesh/core/metric/__init__.py,sha256=H1HmoD5IwN4YWe9iJXyueLYNmTQFZwok5nSWNJcZIBQ,237
85
85
  sqlmesh/core/metric/definition.py,sha256=Yd5aVgsZCDPJ43aGP7WqtzZOuuSUtB8uJGVA6Jw9x9M,7201
86
86
  sqlmesh/core/metric/rewriter.py,sha256=GiSTHfn2kinqCfNPYgZPRk93JFLzVaaejHtHDQ0yXZI,7326
87
87
  sqlmesh/core/model/__init__.py,sha256=C8GRZ53xuXEA9hQv3BQS9pNNyd9rZ06R_B96UYGhDu4,1644
88
88
  sqlmesh/core/model/cache.py,sha256=csun0RJguHzKX6-qITcOs4fVP4f8_Ts8qiUVV4sHY6Q,7869
89
- sqlmesh/core/model/common.py,sha256=mUVJZ1otbcY9IPqeJQWxZOgv_2QnYEEKdFwcPvZGe9c,17961
89
+ sqlmesh/core/model/common.py,sha256=Gt1nBdbILfR52Rhq2KxF0EMGkB3J5zfk6UH7ecLpMZI,17969
90
90
  sqlmesh/core/model/decorator.py,sha256=wUUg5t0K559tV9Pqt6FE2EWXt5TPGb4wF2Yg4B4hX4w,9251
91
91
  sqlmesh/core/model/definition.py,sha256=UsRFDlO3A5so4HM2_x6M0sdTR-VlTIxw1d-T_gxS_9Q,113897
92
92
  sqlmesh/core/model/kind.py,sha256=8Dp8yiTiXltboZWrB2FJ-LQ3zx4Fv_5Tj0KdUIPwCHI,36358
@@ -166,7 +166,7 @@ sqlmesh/integrations/github/cicd/controller.py,sha256=0I5mHPz3HBJR5lkR-2J9Bj06Yn
166
166
  sqlmesh/lsp/api.py,sha256=_lA_buSPZFIoLJuINbS53LbNOOaHp3orb0uFTE3aCqI,2328
167
167
  sqlmesh/lsp/commands.py,sha256=7tZPePSH-IwBYmXJPIlqGM7pi4rOCLEtc3fKJglAxZs,72
168
168
  sqlmesh/lsp/completions.py,sha256=7Lhboh6xyoMJ3kkHG3aZz1xVbDwKiXeQKdIRj5xlUOA,6674
169
- sqlmesh/lsp/context.py,sha256=xaKZycAycH3-Ugzyg0dLni3shcClOEo1xq5OV2cxccU,19423
169
+ sqlmesh/lsp/context.py,sha256=VIL_Xl3II6I79ILZ67UTY9u6OzgkLHDTEpTK91DJxAA,20892
170
170
  sqlmesh/lsp/custom.py,sha256=3gfN_z9IXKOhTGkaZX7V5I8WUmI4z1GWe1sViOo92pw,3980
171
171
  sqlmesh/lsp/errors.py,sha256=3NMim_5J00Eypz7t8b7XbkBfy8gIsRkeq-VcjD4COtc,1489
172
172
  sqlmesh/lsp/helpers.py,sha256=EFc1u3-b7kSv5-tNwmKUDxId72RCLDBnN2lLTgRSzzQ,1020
@@ -263,6 +263,7 @@ sqlmesh/migrations/v0083_use_sql_for_scd_time_data_type_data_hash.py,sha256=0r-S
263
263
  sqlmesh/migrations/v0084_normalize_quote_when_matched_and_merge_filter.py,sha256=w1TbhvB98czuq5VZxsfcQE2w7o-nd96aKEIG-M1dn6A,329
264
264
  sqlmesh/migrations/v0085_deterministic_repr.py,sha256=mkbZV0rzXJ5bmN1Y75kFI9T6gbnx_sy-zn_UzbOL1Sg,4265
265
265
  sqlmesh/migrations/v0086_check_deterministic_bug.py,sha256=WiYcmhQD434GXWiiakQtcy9ESmB35spXMltV43nvU7Q,2953
266
+ sqlmesh/migrations/v0087_normalize_blueprint_variables.py,sha256=GI6KKA-6PtONUoOnyvLpRTUmPjbpa-CKhDa0iqJW01U,4421
266
267
  sqlmesh/schedulers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
267
268
  sqlmesh/utils/__init__.py,sha256=51VqA2etTZ6kX54250s1hN5ui7D89OeUTUQ9kgMze7s,11554
268
269
  sqlmesh/utils/aws.py,sha256=krxyhrKtsMJDEjT567UbGZogjJ9JRHkvAV-Cg3FVndM,1062
@@ -287,7 +288,7 @@ sqlmesh/utils/pydantic.py,sha256=o_NsXbIpDqNpUA1Uc5xF0ZzoXQYYB0DfHwdRxBwXPNk,120
287
288
  sqlmesh/utils/rich.py,sha256=cwQ5nJ6sgz64xHtoh6_ec7ReV5YpsOGhMtUJnwoRfEI,3549
288
289
  sqlmesh/utils/windows.py,sha256=r7Yin4WEwbvH7sKA3hOJtRsclmscNuBeCklCfVPvtQs,611
289
290
  sqlmesh/utils/yaml.py,sha256=hvo5lmybYLcIx4p6CQwufS8X4MbwS60lEBnCmYJCXmU,2336
290
- sqlmesh-0.206.2.dev1.dist-info/licenses/LICENSE,sha256=OlMefUjgWJdULtf84BLW0AZZcY8DwdgQqb_1j2862j8,11346
291
+ sqlmesh-0.206.2.dev3.dist-info/licenses/LICENSE,sha256=OlMefUjgWJdULtf84BLW0AZZcY8DwdgQqb_1j2862j8,11346
291
292
  web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
292
293
  web/client/dist/index.html,sha256=SXykdSRNgrT1k6I2dPZPEfpxPjIsi8-yVFijt-naSA4,5472
293
294
  web/client/dist/assets/Audits-Jm353fhk.js,sha256=ry6b5IKT3hLAfD5C3T2BqxulfauEV0n0YZ2vsP4eQ_U,1041
@@ -405,8 +406,8 @@ web/server/api/endpoints/models.py,sha256=kwj0s7uve3iZSMfmjkoPVMFMeY1sD0peTeyrWf
405
406
  web/server/api/endpoints/modules.py,sha256=8hqqgonGay_mJmpCw0IdbjsPhWlQH2VLdKAqha-myac,468
406
407
  web/server/api/endpoints/plan.py,sha256=bbbY50W_2MsZSTxOHWMKz0tbIm75nsRSlPy8GI2fg9Q,9306
407
408
  web/server/api/endpoints/table_diff.py,sha256=SCy3-pr5x6bEEiOaZGCDbiHQhpgxwmnz3Acqa2Ie6jI,2090
408
- sqlmesh-0.206.2.dev1.dist-info/METADATA,sha256=v7lvQZd0_0twHOAcdcG3OnLLxO9Bf45E6gUP6ADSlHM,26685
409
- sqlmesh-0.206.2.dev1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
410
- sqlmesh-0.206.2.dev1.dist-info/entry_points.txt,sha256=pIYKtg-u-uO7BK_Y0qrdmfyj0bYrcMc3Xiqr5WE3VFk,121
411
- sqlmesh-0.206.2.dev1.dist-info/top_level.txt,sha256=bspjo5vjELQkuN0qKuTFIbsrUt3Zeo8D2mlKeHG1LdE,12
412
- sqlmesh-0.206.2.dev1.dist-info/RECORD,,
409
+ sqlmesh-0.206.2.dev3.dist-info/METADATA,sha256=5Y9CyunF4DqlvQ-HoC44EjxiboczgoA4ha-fz_fv3F0,26685
410
+ sqlmesh-0.206.2.dev3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
411
+ sqlmesh-0.206.2.dev3.dist-info/entry_points.txt,sha256=pIYKtg-u-uO7BK_Y0qrdmfyj0bYrcMc3Xiqr5WE3VFk,121
412
+ sqlmesh-0.206.2.dev3.dist-info/top_level.txt,sha256=bspjo5vjELQkuN0qKuTFIbsrUt3Zeo8D2mlKeHG1LdE,12
413
+ sqlmesh-0.206.2.dev3.dist-info/RECORD,,