diff --git a/Lib/pprint.py b/Lib/pprint.py index e111bd59d4152c..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 @@ -627,7 +628,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 or typ is complex) and not _cmath.isfinite(object): + 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..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 @@ -182,6 +183,19 @@ 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 + # 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), + "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..30152de1bb0cda --- /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 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`.