diff --git a/sqlmesh/utils/jinja.py b/sqlmesh/utils/jinja.py index c9339cf404..508c6dce2d 100644 --- a/sqlmesh/utils/jinja.py +++ b/sqlmesh/utils/jinja.py @@ -206,6 +206,20 @@ def extract_macro_references_and_variables( return macro_references, variables +def sort_dict_recursive( + item: t.Dict[str, t.Any], +) -> t.Dict[str, t.Any]: + sorted_dict: t.Dict[str, t.Any] = {} + for k, v in sorted(item.items()): + if isinstance(v, list): + sorted_dict[k] = sorted(v) + elif isinstance(v, dict): + sorted_dict[k] = sort_dict_recursive(v) + else: + sorted_dict[k] = v + return sorted_dict + + JinjaGlobalAttribute = t.Union[str, int, float, bool, AttributeDict] @@ -440,7 +454,7 @@ def to_expressions(self) -> t.List[Expression]: d.PythonCode( expressions=[ f"{k} = '{v}'" if isinstance(v, str) else f"{k} = {v}" - for k, v in sorted(filtered_objs.items()) + for k, v in sort_dict_recursive(filtered_objs).items() ] ) ) diff --git a/tests/utils/test_jinja.py b/tests/utils/test_jinja.py index 5eb00aeb3c..1cf7c1bf95 100644 --- a/tests/utils/test_jinja.py +++ b/tests/utils/test_jinja.py @@ -302,3 +302,30 @@ def test_dbt_adapter_macro_scope(): rendered = registry.build_environment().from_string("{{ spark__macro_a() }}").render() assert rendered.strip() == "macro_a" + + +def test_macro_registry_to_expressions_sorted(): + refs = AttributeDict( + { + "payments": { + "database": "jaffle_shop", + "schema": "main", + "nested": {"foo": "bar", "baz": "bing"}, + }, + "orders": {"schema": "main", "database": "jaffle_shop", "nested_list": ["b", "a", "c"]}, + } + ) + + registry = JinjaMacroRegistry() + registry.add_globals({"sources": {}, "refs": refs}) + + # Ensure that the AttributeDict string representation is sorted + # in order to prevent an unexpected *visual* diff in ModelDiff + # (note that the actual diff is based on the data hashes, so this is purely visual) + expressions = registry.to_expressions() + assert len(expressions) == 1 + assert ( + expressions[0].sql(dialect="duckdb") + == "refs = {'orders': {'database': 'jaffle_shop', 'nested_list': ['a', 'b', 'c'], 'schema': 'main'}, 'payments': {'database': 'jaffle_shop', 'nested': {'baz': 'bing', 'foo': 'bar'}, 'schema': 'main'}}\n" + "sources = {}" + )