From b11ec5db82e4a42f019a63b2a3f60d4d41f0912e Mon Sep 17 00:00:00 2001 From: Stefan Zetzsche Date: Sun, 22 Feb 2026 15:57:05 +0000 Subject: [PATCH 1/4] gh-145117: Fix pprint.isreadable() returning True for inf/nan inf, -inf, nan repr strings are not valid Python literals so eval() fails on them. Check repr string inside _builtin_scalars branch instead of using math.isinf/isnan. --- Lib/pprint.py | 5 ++++- Lib/test/test_pprint.py | 8 ++++++++ .../2026-02-22-00-00-00.gh-issue-145117.pPrint.rst | 5 +++++ 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-02-22-00-00-00.gh-issue-145117.pPrint.rst diff --git a/Lib/pprint.py b/Lib/pprint.py index e111bd59d4152c..80056642c4ba70 100644 --- a/Lib/pprint.py +++ b/Lib/pprint.py @@ -627,7 +627,10 @@ def _safe_repr(self, object, context, maxlevels, level): # Return triple (repr_string, isreadable, isrecursive). typ = type(object) if typ in _builtin_scalars: - return repr(object), True, False + rep = repr(object) + if typ is float and rep in ("inf", "-inf", "nan"): + return rep, False, False + return rep, True, False r = getattr(typ, "__repr__", None) diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py index f3860a5d511989..92818efce9bebf 100644 --- a/Lib/test/test_pprint.py +++ b/Lib/test/test_pprint.py @@ -182,6 +182,14 @@ def test_basic(self): self.assertTrue(pp.isreadable(safe), "expected isreadable for %r" % (safe,)) + def test_isreadable_float_specials(self): + # inf, -inf, nan are not valid Python literals so isreadable should be False + for v in (float("inf"), float("-inf"), float("nan")): + self.assertFalse(pprint.isreadable(v), + "expected not isreadable for %r" % (v,)) + self.assertFalse(pprint.PrettyPrinter().isreadable(v), + "expected not isreadable for %r" % (v,)) + def test_stdout_is_None(self): with contextlib.redirect_stdout(None): # smoke test - there is no output to check diff --git a/Misc/NEWS.d/next/Library/2026-02-22-00-00-00.gh-issue-145117.pPrint.rst b/Misc/NEWS.d/next/Library/2026-02-22-00-00-00.gh-issue-145117.pPrint.rst new file mode 100644 index 00000000000000..c5af010378af16 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-02-22-00-00-00.gh-issue-145117.pPrint.rst @@ -0,0 +1,5 @@ +Fix :func:`pprint.isreadable` to return ``False`` for ``float('inf')``, +``float('-inf')``, and ``float('nan')``. Their string representations +(``inf``, ``-inf``, ``nan``) are not valid Python literals and cannot +be reconstructed via :func:`eval`, violating the documented contract of +:func:`~pprint.isreadable`. From 56443e587a68b92f976760532dff36a95bb67541 Mon Sep 17 00:00:00 2001 From: Stefan Zetzsche Date: Tue, 24 Feb 2026 14:39:34 +0000 Subject: [PATCH 2/4] gh-145117: use cmath.isfinite() to also fix complex specials --- Lib/pprint.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/pprint.py b/Lib/pprint.py index 80056642c4ba70..6e9c09ba526158 100644 --- a/Lib/pprint.py +++ b/Lib/pprint.py @@ -34,6 +34,7 @@ """ +import cmath as _cmath import collections as _collections import sys as _sys import types as _types @@ -628,7 +629,7 @@ def _safe_repr(self, object, context, maxlevels, level): typ = type(object) if typ in _builtin_scalars: rep = repr(object) - if typ is float and rep in ("inf", "-inf", "nan"): + if (typ is float or typ is complex) and not _cmath.isfinite(object): return rep, False, False return rep, True, False From b39cad5c25f09c1985ad954864241d482b3c7865 Mon Sep 17 00:00:00 2001 From: Stefan Zetzsche Date: Tue, 24 Feb 2026 15:39:41 +0000 Subject: [PATCH 3/4] gh-145117: extend test_isreadable_float_specials to cover complex non-finite values --- Lib/test/test_pprint.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py index 92818efce9bebf..934aa74fa2924d 100644 --- a/Lib/test/test_pprint.py +++ b/Lib/test/test_pprint.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +import cmath import collections import contextlib import dataclasses @@ -184,7 +185,12 @@ def test_basic(self): def test_isreadable_float_specials(self): # inf, -inf, nan are not valid Python literals so isreadable should be False - for v in (float("inf"), float("-inf"), float("nan")): + # same applies to complex numbers with non-finite components + non_finite = (float("inf"), float("-inf"), float("nan")) + for v in (*non_finite, + *(complex(x, y) for x in (*non_finite, 0) + for y in (*non_finite, 0) + if not cmath.isfinite(complex(x, y)))): self.assertFalse(pprint.isreadable(v), "expected not isreadable for %r" % (v,)) self.assertFalse(pprint.PrettyPrinter().isreadable(v), From a0d1fffd4c4f602b005b20ac1bce1d997869b96a Mon Sep 17 00:00:00 2001 From: Stefan Zetzsche Date: Tue, 24 Feb 2026 15:41:00 +0000 Subject: [PATCH 4/4] gh-145117: update NEWS entry to mention complex non-finite values --- .../2026-02-22-00-00-00.gh-issue-145117.pPrint.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2026-02-22-00-00-00.gh-issue-145117.pPrint.rst b/Misc/NEWS.d/next/Library/2026-02-22-00-00-00.gh-issue-145117.pPrint.rst index c5af010378af16..30152de1bb0cda 100644 --- a/Misc/NEWS.d/next/Library/2026-02-22-00-00-00.gh-issue-145117.pPrint.rst +++ b/Misc/NEWS.d/next/Library/2026-02-22-00-00-00.gh-issue-145117.pPrint.rst @@ -1,5 +1,5 @@ -Fix :func:`pprint.isreadable` to return ``False`` for ``float('inf')``, -``float('-inf')``, and ``float('nan')``. Their string representations -(``inf``, ``-inf``, ``nan``) are not valid Python literals and cannot -be reconstructed via :func:`eval`, violating the documented contract of -:func:`~pprint.isreadable`. +Fix :func:`pprint.isreadable` to return ``False`` for non-finite :class:`float` +and :class:`complex` values (``inf``, ``-inf``, ``nan`` and complex numbers with +non-finite components). Their string representations are not valid Python +expressions and cannot be reconstructed via :func:`eval`, violating the +documented contract of :func:`~pprint.isreadable`.