|
3 | 3 | and therefore this migration applies deterministic sorting to the keys of the dictionary. |
4 | 4 | """ |
5 | 5 |
|
6 | | -import ast |
7 | 6 | import json |
8 | 7 | import typing as t |
| 8 | +from dataclasses import dataclass |
9 | 9 |
|
10 | 10 | from sqlglot import exp |
11 | 11 |
|
12 | 12 | from sqlmesh.utils.migration import index_text_type, blob_text_type |
13 | 13 |
|
14 | 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 | + |
15 | 23 | def _deterministic_repr(obj: t.Any) -> str: |
16 | 24 | """ |
17 | 25 | This is a copy of the function from utils.metaprogramming |
@@ -75,33 +83,16 @@ def migrate(state_sync, **kwargs): # type: ignore |
75 | 83 | old_payload = executable["payload"] |
76 | 84 | try: |
77 | 85 | # Try to parse the old payload and re-serialize it deterministically |
78 | | - parsed_value = ast.literal_eval(old_payload) |
| 86 | + parsed_value = eval(old_payload) |
79 | 87 | new_payload = _deterministic_repr(parsed_value) |
80 | 88 |
|
81 | 89 | # Only update if the representation changed |
82 | 90 | if old_payload != new_payload: |
83 | 91 | executable["payload"] = new_payload |
84 | 92 | migration_needed = True |
85 | | - except (ValueError, SyntaxError): |
86 | | - # Special handling for dictionaries containing SqlValue objects |
87 | | - # These can't be parsed by ast.literal_eval but we can still make them deterministic |
88 | | - if old_payload.startswith("{") and "SqlValue(" in old_payload: |
89 | | - try: |
90 | | - # Use eval in a safe context to parse SqlValue objects |
91 | | - # This is safe because we're only running this on our own serialized data |
92 | | - from sqlmesh.utils.metaprogramming import SqlValue |
93 | | - |
94 | | - safe_globals = {"SqlValue": SqlValue} |
95 | | - parsed_value = eval(old_payload, safe_globals, {}) |
96 | | - new_payload = _deterministic_repr(parsed_value) |
97 | | - |
98 | | - # Only update if the representation changed |
99 | | - if old_payload != new_payload: |
100 | | - executable["payload"] = new_payload |
101 | | - migration_needed = True |
102 | | - except (ValueError, SyntaxError, NameError): |
103 | | - # If we still can't parse it, leave it as-is |
104 | | - pass |
| 93 | + except Exception: |
| 94 | + # If we still can't eval it, leave it as-is |
| 95 | + pass |
105 | 96 |
|
106 | 97 | new_snapshots.append( |
107 | 98 | { |
|
0 commit comments