sqlmesh 0.200.0__py3-none-any.whl → 0.200.1.dev2__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/console.py +4 -1
- sqlmesh/core/scheduler.py +1 -1
- sqlmesh/migrations/v0085_deterministic_repr.py +134 -0
- sqlmesh/utils/metaprogramming.py +35 -1
- {sqlmesh-0.200.0.dist-info → sqlmesh-0.200.1.dev2.dist-info}/METADATA +1 -1
- {sqlmesh-0.200.0.dist-info → sqlmesh-0.200.1.dev2.dist-info}/RECORD +11 -10
- {sqlmesh-0.200.0.dist-info → sqlmesh-0.200.1.dev2.dist-info}/WHEEL +0 -0
- {sqlmesh-0.200.0.dist-info → sqlmesh-0.200.1.dev2.dist-info}/entry_points.txt +0 -0
- {sqlmesh-0.200.0.dist-info → sqlmesh-0.200.1.dev2.dist-info}/licenses/LICENSE +0 -0
- {sqlmesh-0.200.0.dist-info → sqlmesh-0.200.1.dev2.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.200.
|
|
21
|
-
__version_tuple__ = version_tuple = (0, 200,
|
|
20
|
+
__version__ = version = '0.200.1.dev2'
|
|
21
|
+
__version_tuple__ = version_tuple = (0, 200, 1, 'dev2')
|
sqlmesh/core/console.py
CHANGED
|
@@ -912,6 +912,7 @@ class TerminalConsole(Console):
|
|
|
912
912
|
self.table_diff_model_tasks: t.Dict[str, TaskID] = {}
|
|
913
913
|
self.table_diff_progress_live: t.Optional[Live] = None
|
|
914
914
|
|
|
915
|
+
self.signal_progress_logged = False
|
|
915
916
|
self.signal_status_tree: t.Optional[Tree] = None
|
|
916
917
|
|
|
917
918
|
self.verbosity = verbosity
|
|
@@ -956,7 +957,8 @@ class TerminalConsole(Console):
|
|
|
956
957
|
) -> None:
|
|
957
958
|
"""Indicates that a new snapshot evaluation/auditing progress has begun."""
|
|
958
959
|
# Add a newline to separate signal checking from evaluation
|
|
959
|
-
self.
|
|
960
|
+
if self.signal_progress_logged:
|
|
961
|
+
self._print("")
|
|
960
962
|
|
|
961
963
|
if not self.evaluation_progress_live:
|
|
962
964
|
self.evaluation_total_progress = make_progress_bar(
|
|
@@ -1188,6 +1190,7 @@ class TerminalConsole(Console):
|
|
|
1188
1190
|
if self.signal_status_tree is not None:
|
|
1189
1191
|
self._print(self.signal_status_tree)
|
|
1190
1192
|
self.signal_status_tree = None
|
|
1193
|
+
self.signal_progress_logged = True
|
|
1191
1194
|
|
|
1192
1195
|
def start_creation_progress(
|
|
1193
1196
|
self,
|
sqlmesh/core/scheduler.py
CHANGED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"""
|
|
2
|
+
When serializing some objects, like `__sqlmesh__vars__`, the order of keys in the dictionary were not deterministic
|
|
3
|
+
and therefore this migration applies deterministic sorting to the keys of the dictionary.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import typing as t
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
|
|
10
|
+
from sqlglot import exp
|
|
11
|
+
|
|
12
|
+
from sqlmesh.utils.migration import index_text_type, blob_text_type
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# Make sure `SqlValue` is defined so it can be used by `eval` call in the migration
|
|
16
|
+
@dataclass
|
|
17
|
+
class SqlValue:
|
|
18
|
+
"""A SQL string representing a generated SQLGlot AST."""
|
|
19
|
+
|
|
20
|
+
sql: str
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _deterministic_repr(obj: t.Any) -> str:
|
|
24
|
+
"""
|
|
25
|
+
This is a copy of the function from utils.metaprogramming
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def _normalize_for_repr(o: t.Any) -> t.Any:
|
|
29
|
+
if isinstance(o, dict):
|
|
30
|
+
sorted_items = sorted(o.items(), key=lambda x: str(x[0]))
|
|
31
|
+
return {k: _normalize_for_repr(v) for k, v in sorted_items}
|
|
32
|
+
if isinstance(o, (list, tuple)):
|
|
33
|
+
# Recursively normalize nested structures
|
|
34
|
+
normalized = [_normalize_for_repr(item) for item in o]
|
|
35
|
+
return type(o)(normalized)
|
|
36
|
+
return o
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
return repr(_normalize_for_repr(obj))
|
|
40
|
+
except Exception:
|
|
41
|
+
return repr(obj)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def migrate(state_sync, **kwargs): # type: ignore
|
|
45
|
+
import pandas as pd
|
|
46
|
+
|
|
47
|
+
engine_adapter = state_sync.engine_adapter
|
|
48
|
+
schema = state_sync.schema
|
|
49
|
+
snapshots_table = "_snapshots"
|
|
50
|
+
if schema:
|
|
51
|
+
snapshots_table = f"{schema}.{snapshots_table}"
|
|
52
|
+
|
|
53
|
+
migration_needed = False
|
|
54
|
+
new_snapshots = []
|
|
55
|
+
|
|
56
|
+
for (
|
|
57
|
+
name,
|
|
58
|
+
identifier,
|
|
59
|
+
version,
|
|
60
|
+
snapshot,
|
|
61
|
+
kind_name,
|
|
62
|
+
updated_ts,
|
|
63
|
+
unpaused_ts,
|
|
64
|
+
ttl_ms,
|
|
65
|
+
unrestorable,
|
|
66
|
+
) in engine_adapter.fetchall(
|
|
67
|
+
exp.select(
|
|
68
|
+
"name",
|
|
69
|
+
"identifier",
|
|
70
|
+
"version",
|
|
71
|
+
"snapshot",
|
|
72
|
+
"kind_name",
|
|
73
|
+
"updated_ts",
|
|
74
|
+
"unpaused_ts",
|
|
75
|
+
"ttl_ms",
|
|
76
|
+
"unrestorable",
|
|
77
|
+
).from_(snapshots_table),
|
|
78
|
+
quote_identifiers=True,
|
|
79
|
+
):
|
|
80
|
+
parsed_snapshot = json.loads(snapshot)
|
|
81
|
+
python_env = parsed_snapshot["node"].get("python_env")
|
|
82
|
+
|
|
83
|
+
if python_env:
|
|
84
|
+
for key, executable in python_env.items():
|
|
85
|
+
if isinstance(executable, dict) and executable.get("kind") == "value":
|
|
86
|
+
old_payload = executable["payload"]
|
|
87
|
+
try:
|
|
88
|
+
# Try to parse the old payload and re-serialize it deterministically
|
|
89
|
+
parsed_value = eval(old_payload)
|
|
90
|
+
new_payload = _deterministic_repr(parsed_value)
|
|
91
|
+
|
|
92
|
+
# Only update if the representation changed
|
|
93
|
+
if old_payload != new_payload:
|
|
94
|
+
executable["payload"] = new_payload
|
|
95
|
+
migration_needed = True
|
|
96
|
+
except Exception:
|
|
97
|
+
# If we still can't eval it, leave it as-is
|
|
98
|
+
pass
|
|
99
|
+
|
|
100
|
+
new_snapshots.append(
|
|
101
|
+
{
|
|
102
|
+
"name": name,
|
|
103
|
+
"identifier": identifier,
|
|
104
|
+
"version": version,
|
|
105
|
+
"snapshot": json.dumps(parsed_snapshot),
|
|
106
|
+
"kind_name": kind_name,
|
|
107
|
+
"updated_ts": updated_ts,
|
|
108
|
+
"unpaused_ts": unpaused_ts,
|
|
109
|
+
"ttl_ms": ttl_ms,
|
|
110
|
+
"unrestorable": unrestorable,
|
|
111
|
+
}
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
if migration_needed and new_snapshots:
|
|
115
|
+
engine_adapter.delete_from(snapshots_table, "TRUE")
|
|
116
|
+
|
|
117
|
+
index_type = index_text_type(engine_adapter.dialect)
|
|
118
|
+
blob_type = blob_text_type(engine_adapter.dialect)
|
|
119
|
+
|
|
120
|
+
engine_adapter.insert_append(
|
|
121
|
+
snapshots_table,
|
|
122
|
+
pd.DataFrame(new_snapshots),
|
|
123
|
+
columns_to_types={
|
|
124
|
+
"name": exp.DataType.build(index_type),
|
|
125
|
+
"identifier": exp.DataType.build(index_type),
|
|
126
|
+
"version": exp.DataType.build(index_type),
|
|
127
|
+
"snapshot": exp.DataType.build(blob_type),
|
|
128
|
+
"kind_name": exp.DataType.build("text"),
|
|
129
|
+
"updated_ts": exp.DataType.build("bigint"),
|
|
130
|
+
"unpaused_ts": exp.DataType.build("bigint"),
|
|
131
|
+
"ttl_ms": exp.DataType.build("bigint"),
|
|
132
|
+
"unrestorable": exp.DataType.build("boolean"),
|
|
133
|
+
},
|
|
134
|
+
)
|
sqlmesh/utils/metaprogramming.py
CHANGED
|
@@ -425,7 +425,9 @@ class Executable(PydanticModel):
|
|
|
425
425
|
|
|
426
426
|
@classmethod
|
|
427
427
|
def value(cls, v: t.Any, is_metadata: t.Optional[bool] = None) -> Executable:
|
|
428
|
-
return Executable(
|
|
428
|
+
return Executable(
|
|
429
|
+
payload=_deterministic_repr(v), kind=ExecutableKind.VALUE, is_metadata=is_metadata
|
|
430
|
+
)
|
|
429
431
|
|
|
430
432
|
|
|
431
433
|
def serialize_env(env: t.Dict[str, t.Any], path: Path) -> t.Dict[str, Executable]:
|
|
@@ -633,6 +635,38 @@ def print_exception(
|
|
|
633
635
|
out.write(tb)
|
|
634
636
|
|
|
635
637
|
|
|
638
|
+
def _deterministic_repr(obj: t.Any) -> str:
|
|
639
|
+
"""Create a deterministic representation by ensuring consistent ordering before repr().
|
|
640
|
+
|
|
641
|
+
For dictionaries, ensures consistent key ordering to prevent non-deterministic
|
|
642
|
+
serialization that affects fingerprinting. Uses Python's native repr() logic
|
|
643
|
+
for all formatting to handle edge cases properly.
|
|
644
|
+
|
|
645
|
+
Note that this function assumes list/tuple order is significant and therefore does not sort them.
|
|
646
|
+
|
|
647
|
+
Args:
|
|
648
|
+
obj: The object to represent as a string.
|
|
649
|
+
|
|
650
|
+
Returns:
|
|
651
|
+
A deterministic string representation of the object.
|
|
652
|
+
"""
|
|
653
|
+
|
|
654
|
+
def _normalize_for_repr(o: t.Any) -> t.Any:
|
|
655
|
+
if isinstance(o, dict):
|
|
656
|
+
sorted_items = sorted(o.items(), key=lambda x: str(x[0]))
|
|
657
|
+
return {k: _normalize_for_repr(v) for k, v in sorted_items}
|
|
658
|
+
if isinstance(o, (list, tuple)):
|
|
659
|
+
# Recursively normalize nested structures
|
|
660
|
+
normalized = [_normalize_for_repr(item) for item in o]
|
|
661
|
+
return type(o)(normalized)
|
|
662
|
+
return o
|
|
663
|
+
|
|
664
|
+
try:
|
|
665
|
+
return repr(_normalize_for_repr(obj))
|
|
666
|
+
except Exception:
|
|
667
|
+
return repr(obj)
|
|
668
|
+
|
|
669
|
+
|
|
636
670
|
def import_python_file(path: Path, relative_base: Path = Path()) -> types.ModuleType:
|
|
637
671
|
relative_path = path.absolute().relative_to(relative_base.absolute())
|
|
638
672
|
module_name = str(relative_path.with_suffix("")).replace(os.path.sep, ".")
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
sqlmesh/__init__.py,sha256=QjwaamJIdW7voXoS880yAx7tHm-Im4_mqGA-XJgafos,7631
|
|
2
|
-
sqlmesh/_version.py,sha256=
|
|
2
|
+
sqlmesh/_version.py,sha256=mhLkkuqXHHUBRO3JeIkm-hJxFF_R5LZxBqQaD28Md94,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
|
|
@@ -11,7 +11,7 @@ sqlmesh/cli/options.py,sha256=-4ZclMIeIg8tghLowtmQNmpEFlm0QtOVEh40NqRdFHA,2499
|
|
|
11
11
|
sqlmesh/cli/project_init.py,sha256=5JmDmUK0WJs39hM-p76uzHYdo1Hnx6fKuJg_pR3Hn5A,16419
|
|
12
12
|
sqlmesh/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
13
|
sqlmesh/core/_typing.py,sha256=e1f7xO2aZCy38M_3VoDy-XI3shyd99-IFctgIFSgXWM,497
|
|
14
|
-
sqlmesh/core/console.py,sha256=
|
|
14
|
+
sqlmesh/core/console.py,sha256=GE4V2sBOXasA3DPeIA9hUWYXS1uqY9ab9ZvTNdl9L98,160943
|
|
15
15
|
sqlmesh/core/constants.py,sha256=gUABXWYgH_XOSbaZAJsR5o1dmA61JDCvBDyxqqXX3LM,2630
|
|
16
16
|
sqlmesh/core/context.py,sha256=9a8RqBBHQXjH7nMYiTcQRtp5_NYpk_9EFpPoBfDx94o,124321
|
|
17
17
|
sqlmesh/core/context_diff.py,sha256=CeUmMBJzN__98YohrtAiIYPIZI9mrGBk6bVADWBLUw8,21692
|
|
@@ -24,7 +24,7 @@ sqlmesh/core/node.py,sha256=3ChBz1PIMJhp-jzed_GLBrtmEF2v_BVDEM5WNe0ssPk,14658
|
|
|
24
24
|
sqlmesh/core/notification_target.py,sha256=PPGoDrgbRKxr27vJEu03XqNTQLYTw0ZF_b0yAapxGeI,16158
|
|
25
25
|
sqlmesh/core/reference.py,sha256=k7OSkLqTjPR8WJjNeFj0xAJ297nZUMgb_iTVwKRRKjc,4875
|
|
26
26
|
sqlmesh/core/renderer.py,sha256=SVE1THHK1UVdPPHjmqNbBVIjmEYcK8tz5pWh1ss8xGs,26684
|
|
27
|
-
sqlmesh/core/scheduler.py,sha256=
|
|
27
|
+
sqlmesh/core/scheduler.py,sha256=I30K5NyeM5HuZxyZ62Vgs1VoMWPNA0gev0nveWugmLM,40544
|
|
28
28
|
sqlmesh/core/schema_diff.py,sha256=Sp2MoqAngp-yTYevkLaf9jb26SuAdGXoZ54g5MjWowU,30516
|
|
29
29
|
sqlmesh/core/schema_loader.py,sha256=lvrI9k7hr1P4X4E6t3U-KrcuvdQuw0UdNlN90P2s52w,3563
|
|
30
30
|
sqlmesh/core/selector.py,sha256=CBuCbaFzidinaoS66o4MY9F-1C3k9YddNMyUv-5Z2i8,12815
|
|
@@ -259,6 +259,7 @@ sqlmesh/migrations/v0081_update_partitioned_by.py,sha256=Rj9RDd7WBonbGfTJx3vAqSv
|
|
|
259
259
|
sqlmesh/migrations/v0082_warn_if_incorrectly_duplicated_statements.py,sha256=K-Z0ghTCFSZuAYzNSUXF4L8axihPemM15EOXHcqkK3s,2489
|
|
260
260
|
sqlmesh/migrations/v0083_use_sql_for_scd_time_data_type_data_hash.py,sha256=0r-SlncPec4TBpnQTeblPsiIjIOVKc10GjBVbFPGcFA,148
|
|
261
261
|
sqlmesh/migrations/v0084_normalize_quote_when_matched_and_merge_filter.py,sha256=w1TbhvB98czuq5VZxsfcQE2w7o-nd96aKEIG-M1dn6A,329
|
|
262
|
+
sqlmesh/migrations/v0085_deterministic_repr.py,sha256=gedfV5hoq62mp9HK3eiJ1p9aYAfJ4Cku_cnQHUrEinE,4388
|
|
262
263
|
sqlmesh/schedulers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
263
264
|
sqlmesh/utils/__init__.py,sha256=51VqA2etTZ6kX54250s1hN5ui7D89OeUTUQ9kgMze7s,11554
|
|
264
265
|
sqlmesh/utils/aws.py,sha256=krxyhrKtsMJDEjT567UbGZogjJ9JRHkvAV-Cg3FVndM,1062
|
|
@@ -274,7 +275,7 @@ sqlmesh/utils/errors.py,sha256=HtpLcs1IN0aq65G372flV9kqqJUULLC3Ci7wvgoBANk,5392
|
|
|
274
275
|
sqlmesh/utils/git.py,sha256=v1MD4Zwn52UBn_tTfoKn8SAPJVGC6SEFrJ4WEJFbgF0,1868
|
|
275
276
|
sqlmesh/utils/hashing.py,sha256=4Bi0NvRctBHzg58btNxXwSNgcvj8doIVVvOjJ40mHBg,512
|
|
276
277
|
sqlmesh/utils/jinja.py,sha256=zulSPIICdFOjN__xkAiMpxbCS7S0--xAFK9d8VG0KvU,27844
|
|
277
|
-
sqlmesh/utils/metaprogramming.py,sha256=
|
|
278
|
+
sqlmesh/utils/metaprogramming.py,sha256=5KW6LyjD509I2wi8pZmz2V0fXlzYq5EQ6C42ApWLJxc,24311
|
|
278
279
|
sqlmesh/utils/migration.py,sha256=R7Ck6FX-LfcujGy7sgS0kDWlK-xAEBODr3gqIQ8gC08,835
|
|
279
280
|
sqlmesh/utils/pandas.py,sha256=FytTSLcRNtO0-YMvpoDBkkut3yoQJR9mBSKpif8lxug,2497
|
|
280
281
|
sqlmesh/utils/process.py,sha256=vpXcpJ1eIbivs7gZdwTKSJI7OS6kKBebnaBzz75ykvs,2428
|
|
@@ -282,7 +283,7 @@ sqlmesh/utils/pydantic.py,sha256=o_NsXbIpDqNpUA1Uc5xF0ZzoXQYYB0DfHwdRxBwXPNk,120
|
|
|
282
283
|
sqlmesh/utils/rich.py,sha256=BpB47G0-JcU41LkGkeGKroexj4NOV5fox4-GOIXPgIc,3545
|
|
283
284
|
sqlmesh/utils/windows.py,sha256=r7Yin4WEwbvH7sKA3hOJtRsclmscNuBeCklCfVPvtQs,611
|
|
284
285
|
sqlmesh/utils/yaml.py,sha256=hvo5lmybYLcIx4p6CQwufS8X4MbwS60lEBnCmYJCXmU,2336
|
|
285
|
-
sqlmesh-0.200.
|
|
286
|
+
sqlmesh-0.200.1.dev2.dist-info/licenses/LICENSE,sha256=OlMefUjgWJdULtf84BLW0AZZcY8DwdgQqb_1j2862j8,11346
|
|
286
287
|
web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
287
288
|
web/client/dist/index.html,sha256=DAv6ABGogw4xRLb0T_92WP_S7XWyqVhwBgGKWtuQwU4,5472
|
|
288
289
|
web/client/dist/assets/Audits-BuHAmFO8.js,sha256=zbYUF6WdUGMbnMm01GMNPb7xAJwj-o5wMdL56vPo2qE,1041
|
|
@@ -400,8 +401,8 @@ web/server/api/endpoints/models.py,sha256=kwj0s7uve3iZSMfmjkoPVMFMeY1sD0peTeyrWf
|
|
|
400
401
|
web/server/api/endpoints/modules.py,sha256=8hqqgonGay_mJmpCw0IdbjsPhWlQH2VLdKAqha-myac,468
|
|
401
402
|
web/server/api/endpoints/plan.py,sha256=bbbY50W_2MsZSTxOHWMKz0tbIm75nsRSlPy8GI2fg9Q,9306
|
|
402
403
|
web/server/api/endpoints/table_diff.py,sha256=SCy3-pr5x6bEEiOaZGCDbiHQhpgxwmnz3Acqa2Ie6jI,2090
|
|
403
|
-
sqlmesh-0.200.
|
|
404
|
-
sqlmesh-0.200.
|
|
405
|
-
sqlmesh-0.200.
|
|
406
|
-
sqlmesh-0.200.
|
|
407
|
-
sqlmesh-0.200.
|
|
404
|
+
sqlmesh-0.200.1.dev2.dist-info/METADATA,sha256=CFUkcAF8Erp5XTDD_Da6jwijBXxI3V6hOqrwp2RZ9y4,26657
|
|
405
|
+
sqlmesh-0.200.1.dev2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
406
|
+
sqlmesh-0.200.1.dev2.dist-info/entry_points.txt,sha256=pIYKtg-u-uO7BK_Y0qrdmfyj0bYrcMc3Xiqr5WE3VFk,121
|
|
407
|
+
sqlmesh-0.200.1.dev2.dist-info/top_level.txt,sha256=bspjo5vjELQkuN0qKuTFIbsrUt3Zeo8D2mlKeHG1LdE,12
|
|
408
|
+
sqlmesh-0.200.1.dev2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|