From d0c35186a1e3bfe191bce6781f12bffc4dbe478c Mon Sep 17 00:00:00 2001 From: Waleed Khalid Date: Sun, 20 Jul 2025 17:25:53 +0500 Subject: [PATCH 1/3] Preserve dict insertion order in safeformat output (fixes #13503) --- src/_pytest/_io/saferepr.py | 2 +- testing/io/test_saferepr.py | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/_pytest/_io/saferepr.py b/src/_pytest/_io/saferepr.py index cee70e332f9..fab22f445cc 100644 --- a/src/_pytest/_io/saferepr.py +++ b/src/_pytest/_io/saferepr.py @@ -87,7 +87,7 @@ def safeformat(obj: object) -> str: with a short exception info. """ try: - return pprint.pformat(obj) + return pprint.pformat(obj, sort_dicts=False) except Exception as exc: return _format_repr_exception(exc, obj) diff --git a/testing/io/test_saferepr.py b/testing/io/test_saferepr.py index 075d40cdf44..4ddf72d4f69 100644 --- a/testing/io/test_saferepr.py +++ b/testing/io/test_saferepr.py @@ -192,3 +192,14 @@ def __repr__(self): assert saferepr_unlimited(A()).startswith( "<[ValueError(42) raised in repr()] A object at 0x" ) + + +def test_saferepr_dict_insertion_order(): + from _pytest._io.saferepr import safeformat + d = {} + d["z"] = 1 + d["a"] = 2 + d["m"] = 3 + output = safeformat(d) + # output should contain 'z', 'a', 'm' in this order (not 'a', 'm', 'z') + assert output.find("'z'") < output.find("'a'") < output.find("'m'") \ No newline at end of file From 671d583852b191d73d5a36406ec80d2f63b05a5d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 20 Jul 2025 12:29:44 +0000 Subject: [PATCH 2/3] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- testing/io/test_saferepr.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testing/io/test_saferepr.py b/testing/io/test_saferepr.py index 4ddf72d4f69..ec7f4480b1d 100644 --- a/testing/io/test_saferepr.py +++ b/testing/io/test_saferepr.py @@ -196,10 +196,11 @@ def __repr__(self): def test_saferepr_dict_insertion_order(): from _pytest._io.saferepr import safeformat + d = {} d["z"] = 1 d["a"] = 2 d["m"] = 3 output = safeformat(d) # output should contain 'z', 'a', 'm' in this order (not 'a', 'm', 'z') - assert output.find("'z'") < output.find("'a'") < output.find("'m'") \ No newline at end of file + assert output.find("'z'") < output.find("'a'") < output.find("'m'") From edfef01e92e7f9e479a9f8fd0c8d4c944fc93443 Mon Sep 17 00:00:00 2001 From: Waleed Khalid Date: Sun, 20 Jul 2025 17:32:24 +0500 Subject: [PATCH 3/3] Add changelog entry for #13503 --- changelog/13503.bugfix.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/13503.bugfix.rst diff --git a/changelog/13503.bugfix.rst b/changelog/13503.bugfix.rst new file mode 100644 index 00000000000..473a8b46e38 --- /dev/null +++ b/changelog/13503.bugfix.rst @@ -0,0 +1 @@ +Fixes dict output in assertion failures to preserve insertion order. (#13503)