Skip to content
20 changes: 20 additions & 0 deletions mypyc/codegen/emit.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,17 @@ def object_annotation(self, obj: object, line: str) -> str:

If it contains illegal characters, an empty string is returned."""
line_width = self._indent + len(line)

# temporarily override pprint._safe_key
default_safe_key = pprint._safe_key # type: ignore [attr-defined]
pprint._safe_key = _mypyc_safe_key # type: ignore [attr-defined]

# pretty print the object
formatted = pprint.pformat(obj, compact=True, width=max(90 - line_width, 20))

# replace the _safe_key
pprint._safe_key = default_safe_key # type: ignore [attr-defined]

if any(x in formatted for x in ("/*", "*/", "\0")):
return ""

Expand Down Expand Up @@ -1226,3 +1236,13 @@ def c_array_initializer(components: list[str], *, indented: bool = False) -> str
# Multi-line result
res.append(indent + ", ".join(current))
return "{\n " + ",\n ".join(res) + "\n" + indent + "}"


def _mypyc_safe_key(obj: object) -> str:
"""A custom sort key implementation for pprint that makes the output deterministic
for all literal types supported by mypyc.

This is NOT safe for use as a sort key for other types, so we MUST replace the
original pprint._safe_key once we've pprinted our object.
"""
return str(type(obj)) + repr(obj)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Actually, isn't this still random? repr(obj) might not be a deterministic ordering? Or is it deterministic because maybe frozenset is the same repr based on the same input (I would check but... lazy).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's deterministic so long as the objects contained within the tuple are supported mypyc literal types, and this should have already been validated by this point in the code

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh wait, you're correct in one case: if the frozenset contains another frozenset

This can be mitigated by replacing repr with pformat (to ensure the frozenset goes thru the same ordering process)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've implemented this recursive pformatting, let me know if this works for you