[Python-checkins] bpo-42914: add a pprint underscore_numbers option (GH-24864)

gpshead webhook-mailer at python.org
Wed Mar 24 04:23:35 EDT 2021


https://github.com/python/cpython/commit/3ba3d513b1e3c63d09cb798b982a9e6c369cea4c
commit: 3ba3d513b1e3c63d09cb798b982a9e6c369cea4c
branch: master
author: sblondon <sblondon at users.noreply.github.com>
committer: gpshead <greg at krypto.org>
date: 2021-03-24T01:23:20-07:00
summary:

bpo-42914: add a pprint underscore_numbers option (GH-24864)

pprint() gains a new boolean underscore_numbers kwarg to emit
integers with thousands separated by an underscore character
for improved readability (for example 1_000_000 instead of 1000000).

files:
A Misc/NEWS.d/next/Library/2021-03-14-21-47-28.bpo-42914.9U1o33.rst
M Doc/library/pprint.rst
M Lib/pprint.py
M Lib/test/test_pprint.py

diff --git a/Doc/library/pprint.rst b/Doc/library/pprint.rst
index 16256c549208f..b3b6ed56a5e17 100644
--- a/Doc/library/pprint.rst
+++ b/Doc/library/pprint.rst
@@ -36,7 +36,7 @@ The :mod:`pprint` module defines one class:
 .. index:: single: ...; placeholder
 
 .. class:: PrettyPrinter(indent=1, width=80, depth=None, stream=None, *, \
-                         compact=False, sort_dicts=True)
+                         compact=False, sort_dicts=True, underscore_numbers=False)
 
    Construct a :class:`PrettyPrinter` instance.  This constructor understands
    several keyword parameters.  An output stream may be set using the *stream*
@@ -55,7 +55,10 @@ The :mod:`pprint` module defines one class:
    will be formatted on a separate line.  If *compact* is true, as many items
    as will fit within the *width* will be formatted on each output line. If
    *sort_dicts* is true (the default), dictionaries will be formatted with their
-   keys sorted, otherwise they will display in insertion order.
+   keys sorted, otherwise they will display in insertion order.  If
+   *underscore_numbers* is true, integers will be formatted with
+   ```_``` character for a thousands separator, otherwise underscores are not
+   displayed (the default).
 
    .. versionchanged:: 3.4
       Added the *compact* parameter.
@@ -63,6 +66,8 @@ The :mod:`pprint` module defines one class:
    .. versionchanged:: 3.8
       Added the *sort_dicts* parameter.
 
+   .. versionchanged:: 3.10
+      Added the *underscore_numbers* parameter.
 
       >>> import pprint
       >>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni']
@@ -91,10 +96,10 @@ The :mod:`pprint` module defines one class:
 The :mod:`pprint` module also provides several shortcut functions:
 
 .. function:: pformat(object, indent=1, width=80, depth=None, *, \
-                      compact=False, sort_dicts=True)
+                      compact=False, sort_dicts=True, underscore_numbers=False)
 
    Return the formatted representation of *object* as a string.  *indent*,
-   *width*, *depth*, *compact* and *sort_dicts* will be passed to the
+   *width*, *depth*, *compact*, *sort_dicts* and *underscore_numbers* will be passed to the
    :class:`PrettyPrinter` constructor as formatting parameters.
 
    .. versionchanged:: 3.4
@@ -103,6 +108,9 @@ The :mod:`pprint` module also provides several shortcut functions:
    .. versionchanged:: 3.8
       Added the *sort_dicts* parameter.
 
+   .. versionchanged:: 3.10
+      Added the *underscore_numbers* parameter.
+
 
 .. function:: pp(object, *args, sort_dicts=False, **kwargs)
 
@@ -116,13 +124,13 @@ The :mod:`pprint` module also provides several shortcut functions:
 
 
 .. function:: pprint(object, stream=None, indent=1, width=80, depth=None, *, \
-                     compact=False, sort_dicts=True)
+                     compact=False, sort_dicts=True, underscore_numbers=False)
 
    Prints the formatted representation of *object* on *stream*, followed by a
    newline.  If *stream* is ``None``, ``sys.stdout`` is used.  This may be used
    in the interactive interpreter instead of the :func:`print` function for
    inspecting values (you can even reassign ``print = pprint.pprint`` for use
-   within a scope).  *indent*, *width*, *depth*, *compact* and *sort_dicts* will
+   within a scope).  *indent*, *width*, *depth*, *compact*, *sort_dicts* and *underscore_numbers* will
    be passed to the :class:`PrettyPrinter` constructor as formatting parameters.
 
    .. versionchanged:: 3.4
@@ -131,6 +139,9 @@ The :mod:`pprint` module also provides several shortcut functions:
    .. versionchanged:: 3.8
       Added the *sort_dicts* parameter.
 
+   .. versionchanged:: 3.10
+      Added the *underscore_numbers* parameter.
+
       >>> import pprint
       >>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni']
       >>> stuff.insert(0, stuff)
diff --git a/Lib/pprint.py b/Lib/pprint.py
index a8af50e5a6861..b45cfdd99a8e1 100644
--- a/Lib/pprint.py
+++ b/Lib/pprint.py
@@ -45,18 +45,19 @@
 
 
 def pprint(object, stream=None, indent=1, width=80, depth=None, *,
-           compact=False, sort_dicts=True):
+           compact=False, sort_dicts=True, underscore_numbers=False):
     """Pretty-print a Python object to a stream [default is sys.stdout]."""
     printer = PrettyPrinter(
         stream=stream, indent=indent, width=width, depth=depth,
-        compact=compact, sort_dicts=sort_dicts)
+        compact=compact, sort_dicts=sort_dicts, underscore_numbers=False)
     printer.pprint(object)
 
 def pformat(object, indent=1, width=80, depth=None, *,
-            compact=False, sort_dicts=True):
+            compact=False, sort_dicts=True, underscore_numbers=False):
     """Format a Python object into a pretty-printed representation."""
     return PrettyPrinter(indent=indent, width=width, depth=depth,
-                         compact=compact, sort_dicts=sort_dicts).pformat(object)
+                         compact=compact, sort_dicts=sort_dicts,
+                         underscore_numbers=underscore_numbers).pformat(object)
 
 def pp(object, *args, sort_dicts=False, **kwargs):
     """Pretty-print a Python object"""
@@ -102,7 +103,7 @@ def _safe_tuple(t):
 
 class PrettyPrinter:
     def __init__(self, indent=1, width=80, depth=None, stream=None, *,
-                 compact=False, sort_dicts=True):
+                 compact=False, sort_dicts=True, underscore_numbers=False):
         """Handle pretty printing operations onto a stream using a set of
         configured parameters.
 
@@ -143,6 +144,7 @@ def __init__(self, indent=1, width=80, depth=None, stream=None, *,
             self._stream = _sys.stdout
         self._compact = bool(compact)
         self._sort_dicts = sort_dicts
+        self._underscore_numbers = underscore_numbers
 
     def pprint(self, object):
         self._format(object, self._stream, 0, 0, {}, 0)
@@ -525,6 +527,13 @@ def _safe_repr(self, object, context, maxlevels, level):
             return repr(object), True, False
 
         r = getattr(typ, "__repr__", None)
+
+        if issubclass(typ, int) and r is int.__repr__:
+            if self._underscore_numbers:
+                return f"{object:_d}", True, False
+            else:
+                return repr(object), True, False
+
         if issubclass(typ, dict) and r is dict.__repr__:
             if not object:
                 return "{}", True, False
@@ -592,7 +601,7 @@ def _safe_repr(self, object, context, maxlevels, level):
         rep = repr(object)
         return rep, (rep and not rep.startswith('<')), False
 
-_builtin_scalars = frozenset({str, bytes, bytearray, int, float, complex,
+_builtin_scalars = frozenset({str, bytes, bytearray, float, complex,
                               bool, type(None)})
 
 def _recursion(object):
diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py
index c4a8578a9fc8f..e5d2ac52d1283 100644
--- a/Lib/test/test_pprint.py
+++ b/Lib/test/test_pprint.py
@@ -206,6 +206,7 @@ def test_same_as_repr(self):
             self.assertEqual(pprint.pformat(simple), native)
             self.assertEqual(pprint.pformat(simple, width=1, indent=0)
                              .replace('\n', ' '), native)
+            self.assertEqual(pprint.pformat(simple, underscore_numbers=True), native)
             self.assertEqual(pprint.saferepr(simple), native)
 
     def test_container_repr_override_called(self):
@@ -323,6 +324,18 @@ def test_width(self):
      '1 '
      '2']]]]]""")
 
+    def test_integer(self):
+        self.assertEqual(pprint.pformat(1234567), '1234567')
+        self.assertEqual(pprint.pformat(1234567, underscore_numbers=True), '1_234_567')
+
+        class Temperature(int):
+            def __new__(cls, celsius_degrees):
+                return super().__new__(Temperature, celsius_degrees)
+            def __repr__(self):
+                kelvin_degrees = self + 273.15
+                return f"{kelvin_degrees}°K"
+        self.assertEqual(pprint.pformat(Temperature(1000)), '1273.15°K')
+
     def test_sorted_dict(self):
         # Starting in Python 2.5, pprint sorts dict displays by key regardless
         # of how small the dictionary may be.
diff --git a/Misc/NEWS.d/next/Library/2021-03-14-21-47-28.bpo-42914.9U1o33.rst b/Misc/NEWS.d/next/Library/2021-03-14-21-47-28.bpo-42914.9U1o33.rst
new file mode 100644
index 0000000000000..ae6ef2f0bfa42
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2021-03-14-21-47-28.bpo-42914.9U1o33.rst
@@ -0,0 +1,3 @@
+:func:`pprint.pprint` gains a new boolean ``underscore_numbers`` optional
+argument to emit integers with thousands separated by an underscore character
+for improved readability (for example ``1_000_000`` instead of ``1000000``).



More information about the Python-checkins mailing list