sqlmesh 0.199.1.dev45__py3-none-any.whl → 0.200.1.dev1__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/migrations/v0085_deterministic_repr.py +134 -0
- sqlmesh/utils/metaprogramming.py +35 -1
- {sqlmesh-0.199.1.dev45.dist-info → sqlmesh-0.200.1.dev1.dist-info}/METADATA +1 -1
- {sqlmesh-0.199.1.dev45.dist-info → sqlmesh-0.200.1.dev1.dist-info}/RECORD +9 -8
- {sqlmesh-0.199.1.dev45.dist-info → sqlmesh-0.200.1.dev1.dist-info}/WHEEL +0 -0
- {sqlmesh-0.199.1.dev45.dist-info → sqlmesh-0.200.1.dev1.dist-info}/entry_points.txt +0 -0
- {sqlmesh-0.199.1.dev45.dist-info → sqlmesh-0.200.1.dev1.dist-info}/licenses/LICENSE +0 -0
- {sqlmesh-0.199.1.dev45.dist-info → sqlmesh-0.200.1.dev1.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.
|
|
21
|
-
__version_tuple__ = version_tuple = (0,
|
|
20
|
+
__version__ = version = '0.200.1.dev1'
|
|
21
|
+
__version_tuple__ = version_tuple = (0, 200, 1, 'dev1')
|
|
@@ -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=KslZWeWoEUEoAhNTAI5BzM2M3yOb3IJN3RCD9jDFfNY,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
|
|
@@ -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.
|
|
286
|
+
sqlmesh-0.200.1.dev1.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.
|
|
404
|
-
sqlmesh-0.
|
|
405
|
-
sqlmesh-0.
|
|
406
|
-
sqlmesh-0.
|
|
407
|
-
sqlmesh-0.
|
|
404
|
+
sqlmesh-0.200.1.dev1.dist-info/METADATA,sha256=zG4lNQXIkIYODLR_cZogwPgZhYbu8g67qxsqQLTIo2Y,26657
|
|
405
|
+
sqlmesh-0.200.1.dev1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
406
|
+
sqlmesh-0.200.1.dev1.dist-info/entry_points.txt,sha256=pIYKtg-u-uO7BK_Y0qrdmfyj0bYrcMc3Xiqr5WE3VFk,121
|
|
407
|
+
sqlmesh-0.200.1.dev1.dist-info/top_level.txt,sha256=bspjo5vjELQkuN0qKuTFIbsrUt3Zeo8D2mlKeHG1LdE,12
|
|
408
|
+
sqlmesh-0.200.1.dev1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|