Skip to content

Commit 3ba3d51

Browse files
authored
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).
1 parent a02683a commit 3ba3d51

File tree

4 files changed

+48
-12
lines changed

4 files changed

+48
-12
lines changed

Doc/library/pprint.rst

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ The :mod:`pprint` module defines one class:
3636
.. index:: single: ...; placeholder
3737

3838
.. class:: PrettyPrinter(indent=1, width=80, depth=None, stream=None, *, \
39-
compact=False, sort_dicts=True)
39+
compact=False, sort_dicts=True, underscore_numbers=False)
4040

4141
Construct a :class:`PrettyPrinter` instance. This constructor understands
4242
several keyword parameters. An output stream may be set using the *stream*
@@ -55,14 +55,19 @@ The :mod:`pprint` module defines one class:
5555
will be formatted on a separate line. If *compact* is true, as many items
5656
as will fit within the *width* will be formatted on each output line. If
5757
*sort_dicts* is true (the default), dictionaries will be formatted with their
58-
keys sorted, otherwise they will display in insertion order.
58+
keys sorted, otherwise they will display in insertion order. If
59+
*underscore_numbers* is true, integers will be formatted with
60+
```_``` character for a thousands separator, otherwise underscores are not
61+
displayed (the default).
5962

6063
.. versionchanged:: 3.4
6164
Added the *compact* parameter.
6265

6366
.. versionchanged:: 3.8
6467
Added the *sort_dicts* parameter.
6568

69+
.. versionchanged:: 3.10
70+
Added the *underscore_numbers* parameter.
6671

6772
>>> import pprint
6873
>>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni']
@@ -91,10 +96,10 @@ The :mod:`pprint` module defines one class:
9196
The :mod:`pprint` module also provides several shortcut functions:
9297

9398
.. function:: pformat(object, indent=1, width=80, depth=None, *, \
94-
compact=False, sort_dicts=True)
99+
compact=False, sort_dicts=True, underscore_numbers=False)
95100

96101
Return the formatted representation of *object* as a string. *indent*,
97-
*width*, *depth*, *compact* and *sort_dicts* will be passed to the
102+
*width*, *depth*, *compact*, *sort_dicts* and *underscore_numbers* will be passed to the
98103
:class:`PrettyPrinter` constructor as formatting parameters.
99104

100105
.. versionchanged:: 3.4
@@ -103,6 +108,9 @@ The :mod:`pprint` module also provides several shortcut functions:
103108
.. versionchanged:: 3.8
104109
Added the *sort_dicts* parameter.
105110

111+
.. versionchanged:: 3.10
112+
Added the *underscore_numbers* parameter.
113+
106114

107115
.. function:: pp(object, *args, sort_dicts=False, **kwargs)
108116

@@ -116,13 +124,13 @@ The :mod:`pprint` module also provides several shortcut functions:
116124

117125

118126
.. function:: pprint(object, stream=None, indent=1, width=80, depth=None, *, \
119-
compact=False, sort_dicts=True)
127+
compact=False, sort_dicts=True, underscore_numbers=False)
120128

121129
Prints the formatted representation of *object* on *stream*, followed by a
122130
newline. If *stream* is ``None``, ``sys.stdout`` is used. This may be used
123131
in the interactive interpreter instead of the :func:`print` function for
124132
inspecting values (you can even reassign ``print = pprint.pprint`` for use
125-
within a scope). *indent*, *width*, *depth*, *compact* and *sort_dicts* will
133+
within a scope). *indent*, *width*, *depth*, *compact*, *sort_dicts* and *underscore_numbers* will
126134
be passed to the :class:`PrettyPrinter` constructor as formatting parameters.
127135

128136
.. versionchanged:: 3.4
@@ -131,6 +139,9 @@ The :mod:`pprint` module also provides several shortcut functions:
131139
.. versionchanged:: 3.8
132140
Added the *sort_dicts* parameter.
133141

142+
.. versionchanged:: 3.10
143+
Added the *underscore_numbers* parameter.
144+
134145
>>> import pprint
135146
>>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni']
136147
>>> stuff.insert(0, stuff)

Lib/pprint.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,19 @@
4545

4646

4747
def pprint(object, stream=None, indent=1, width=80, depth=None, *,
48-
compact=False, sort_dicts=True):
48+
compact=False, sort_dicts=True, underscore_numbers=False):
4949
"""Pretty-print a Python object to a stream [default is sys.stdout]."""
5050
printer = PrettyPrinter(
5151
stream=stream, indent=indent, width=width, depth=depth,
52-
compact=compact, sort_dicts=sort_dicts)
52+
compact=compact, sort_dicts=sort_dicts, underscore_numbers=False)
5353
printer.pprint(object)
5454

5555
def pformat(object, indent=1, width=80, depth=None, *,
56-
compact=False, sort_dicts=True):
56+
compact=False, sort_dicts=True, underscore_numbers=False):
5757
"""Format a Python object into a pretty-printed representation."""
5858
return PrettyPrinter(indent=indent, width=width, depth=depth,
59-
compact=compact, sort_dicts=sort_dicts).pformat(object)
59+
compact=compact, sort_dicts=sort_dicts,
60+
underscore_numbers=underscore_numbers).pformat(object)
6061

6162
def pp(object, *args, sort_dicts=False, **kwargs):
6263
"""Pretty-print a Python object"""
@@ -102,7 +103,7 @@ def _safe_tuple(t):
102103

103104
class PrettyPrinter:
104105
def __init__(self, indent=1, width=80, depth=None, stream=None, *,
105-
compact=False, sort_dicts=True):
106+
compact=False, sort_dicts=True, underscore_numbers=False):
106107
"""Handle pretty printing operations onto a stream using a set of
107108
configured parameters.
108109
@@ -143,6 +144,7 @@ def __init__(self, indent=1, width=80, depth=None, stream=None, *,
143144
self._stream = _sys.stdout
144145
self._compact = bool(compact)
145146
self._sort_dicts = sort_dicts
147+
self._underscore_numbers = underscore_numbers
146148

147149
def pprint(self, object):
148150
self._format(object, self._stream, 0, 0, {}, 0)
@@ -525,6 +527,13 @@ def _safe_repr(self, object, context, maxlevels, level):
525527
return repr(object), True, False
526528

527529
r = getattr(typ, "__repr__", None)
530+
531+
if issubclass(typ, int) and r is int.__repr__:
532+
if self._underscore_numbers:
533+
return f"{object:_d}", True, False
534+
else:
535+
return repr(object), True, False
536+
528537
if issubclass(typ, dict) and r is dict.__repr__:
529538
if not object:
530539
return "{}", True, False
@@ -592,7 +601,7 @@ def _safe_repr(self, object, context, maxlevels, level):
592601
rep = repr(object)
593602
return rep, (rep and not rep.startswith('<')), False
594603

595-
_builtin_scalars = frozenset({str, bytes, bytearray, int, float, complex,
604+
_builtin_scalars = frozenset({str, bytes, bytearray, float, complex,
596605
bool, type(None)})
597606

598607
def _recursion(object):

Lib/test/test_pprint.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ def test_same_as_repr(self):
206206
self.assertEqual(pprint.pformat(simple), native)
207207
self.assertEqual(pprint.pformat(simple, width=1, indent=0)
208208
.replace('\n', ' '), native)
209+
self.assertEqual(pprint.pformat(simple, underscore_numbers=True), native)
209210
self.assertEqual(pprint.saferepr(simple), native)
210211

211212
def test_container_repr_override_called(self):
@@ -323,6 +324,18 @@ def test_width(self):
323324
'1 '
324325
'2']]]]]""")
325326

327+
def test_integer(self):
328+
self.assertEqual(pprint.pformat(1234567), '1234567')
329+
self.assertEqual(pprint.pformat(1234567, underscore_numbers=True), '1_234_567')
330+
331+
class Temperature(int):
332+
def __new__(cls, celsius_degrees):
333+
return super().__new__(Temperature, celsius_degrees)
334+
def __repr__(self):
335+
kelvin_degrees = self + 273.15
336+
return f"{kelvin_degrees}°K"
337+
self.assertEqual(pprint.pformat(Temperature(1000)), '1273.15°K')
338+
326339
def test_sorted_dict(self):
327340
# Starting in Python 2.5, pprint sorts dict displays by key regardless
328341
# of how small the dictionary may be.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:func:`pprint.pprint` gains a new boolean ``underscore_numbers`` optional
2+
argument to emit integers with thousands separated by an underscore character
3+
for improved readability (for example ``1_000_000`` instead of ``1000000``).

0 commit comments

Comments
 (0)