Skip to content

Fix: Sort nested AttributeDict's to prevent visual diff#5397

Merged
erindru merged 1 commit intomainfrom
erin/fix-text-diff
Sep 23, 2025
Merged

Fix: Sort nested AttributeDict's to prevent visual diff#5397
erindru merged 1 commit intomainfrom
erin/fix-text-diff

Conversation

@erindru
Copy link
Collaborator

@erindru erindru commented Sep 17, 2025

Prior to this, on dbt projects, if a model had a change, often the text diff would show a diff for refs even though those didn't change at all. In this example, all I did was add a stamp, but the text diff shows a diff for refs:

Screenshot From 2025-09-18 09-58-54

The cause is that while the keys ("refs", "sources", "vars") were sorted - the values weren't. So calling model.render_definition() on the Snapshot in state, calling model.render_definition() the local Snapshot and comparing the output could result in a text diff, even though nothing had actually changed, because the values are output in a non-deterministic order.

After this PR, we no longer see the extra "change" and the text diff focuses on what actually got changed:

Screenshot From 2025-09-18 10-03-06

Note: if you try to repro this locally, you need to run sqlmesh clean to clear the cache inbetween plans otherwise a specific order gets cached and you never see the erroneous diff

return macro_references, variables


def sort_dict_recursive(
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldnt find an existing util function that would recurse into values and sort those too, let me know if it exists and i'm just blind

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eakmanrq did we end up removing the utility you implemented for python_env sorting?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you mean _dict_sort or sort_python_env? i'm not sure either of these would achieve the same, unless there is another one

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah sorry I'm bad with Github notification. I originally added a recrusive dict sort but rolled that back in this PR and just sort the top level: #4984

Copy link
Contributor

@georgesittas georgesittas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@erindru why is the inner dictionary order non-deterministic?

return macro_references, variables


def sort_dict_recursive(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eakmanrq did we end up removing the utility you implemented for python_env sorting?

@erindru
Copy link
Collaborator Author

erindru commented Sep 18, 2025

why is the inner dictionary order non-deterministic

We like to use sets. It's "deterministic" until the cache is busted and the project is re-loaded from disk.

I figured that it was easier to fix it once on output rather than trying to fix every call site now and also again in future when we inevitably make this mistake again and again

@erindru erindru merged commit 97c6a12 into main Sep 23, 2025
45 of 46 checks passed
@erindru erindru deleted the erin/fix-text-diff branch September 23, 2025 22:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants