From 31eca4ca1e32ed331e1e1053b2bb74119156b3a9 Mon Sep 17 00:00:00 2001 From: Stephane Blondon Date: Sat, 13 Mar 2021 23:44:22 +0100 Subject: [PATCH 01/12] pprint.pformat() displays big integer with underscores --- Lib/pprint.py | 17 +++++++++++++---- Lib/test/test_pprint.py | 8 ++++++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Lib/pprint.py b/Lib/pprint.py index a8af50e5a68611..9cdfc271ca773a 100644 --- a/Lib/pprint.py +++ b/Lib/pprint.py @@ -53,10 +53,11 @@ def pprint(object, stream=None, indent=1, width=80, depth=None, *, printer.pprint(object) def pformat(object, indent=1, width=80, depth=None, *, - compact=False, sort_dicts=True): + compact=False, sort_dicts=True, underscore_numbers=True): """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=True): """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): + if self._underscore_numbers: + return "{:_d}".format(object), 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 c4a8578a9fc8fb..abaacc37d1c7a8 100644 --- a/Lib/test/test_pprint.py +++ b/Lib/test/test_pprint.py @@ -245,12 +245,12 @@ def test_basic_line_wrap(self): 'write_io_runtime_us': 43690} exp = """\ {'RPM_cal': 0, - 'RPM_cal2': 48059, + 'RPM_cal2': 48_059, 'Speed_cal': 0, 'controldesk_runtime_us': 0, 'main_code_runtime_us': 0, 'read_io_runtime_us': 0, - 'write_io_runtime_us': 43690}""" + 'write_io_runtime_us': 43_690}""" for type in [dict, dict2]: self.assertEqual(pprint.pformat(type(o)), exp) @@ -323,6 +323,10 @@ def test_width(self): '1 ' '2']]]]]""") + def test_numbers(self): + self.assertEqual(pprint.pformat(1234567), '1_234_567') + self.assertEqual(pprint.pformat(1234567, underscore_numbers=False), '1234567') + def test_sorted_dict(self): # Starting in Python 2.5, pprint sorts dict displays by key regardless # of how small the dictionary may be. From 70b41a69f45163031c1a5c8b591de336c255c9e7 Mon Sep 17 00:00:00 2001 From: Stephane Blondon Date: Sun, 14 Mar 2021 10:56:59 +0100 Subject: [PATCH 02/12] add underscore_numbers parameter to pprint function --- Lib/pprint.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/pprint.py b/Lib/pprint.py index 9cdfc271ca773a..b807db61d131b7 100644 --- a/Lib/pprint.py +++ b/Lib/pprint.py @@ -45,11 +45,11 @@ def pprint(object, stream=None, indent=1, width=80, depth=None, *, - compact=False, sort_dicts=True): + compact=False, sort_dicts=True, underscore_numbers=True): """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=True) printer.pprint(object) def pformat(object, indent=1, width=80, depth=None, *, From 94bfc25706a849c0cec7938a45d05e2dfa757216 Mon Sep 17 00:00:00 2001 From: Stephane Blondon Date: Sun, 14 Mar 2021 15:11:23 +0100 Subject: [PATCH 03/12] add 'underscore_numbers' parameter documentation --- Doc/library/pprint.rst | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/Doc/library/pprint.rst b/Doc/library/pprint.rst index 16256c549208fc..a6a707e5819b1b 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=True) 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 (the default), integers will be formatted with + ```_``` character for a thousands separator, otherwise underscores are not + displayed. .. 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=True) 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=True) 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) From 4a86c50f2ad4f8e42ffed38110fae899a4cc7a84 Mon Sep 17 00:00:00 2001 From: Stephane Blondon Date: Sun, 14 Mar 2021 22:04:52 +0100 Subject: [PATCH 04/12] add news about pprint.pprint function use of the underscore character to display integer --- .../next/Library/2021-03-14-21-47-28.bpo-42914.9U1o33.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2021-03-14-21-47-28.bpo-42914.9U1o33.rst 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 00000000000000..ee71ecb3bdc86c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-03-14-21-47-28.bpo-42914.9U1o33.rst @@ -0,0 +1,2 @@ +pprint.pprint() displays integers with thousands separated by an underscore +character to improve readability (for example 1_000_000 instead of 1000000). From 8722112db23730cdbed9c929261144ce1f670ad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Blondon?= Date: Tue, 16 Mar 2021 10:05:28 +0100 Subject: [PATCH 05/12] replace str.format() call by builtins.format() call --- Lib/pprint.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/pprint.py b/Lib/pprint.py index b807db61d131b7..7b586bb488ec96 100644 --- a/Lib/pprint.py +++ b/Lib/pprint.py @@ -34,6 +34,7 @@ """ +import builtins import collections as _collections import re import sys as _sys @@ -530,7 +531,7 @@ def _safe_repr(self, object, context, maxlevels, level): if issubclass(typ, int): if self._underscore_numbers: - return "{:_d}".format(object), True, False + return builtins.format(object, "_d"), True, False else: return repr(object), True, False From b667e01a026aa97ac23430f34201a5a5450321c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Blondon?= Date: Tue, 16 Mar 2021 15:21:46 +0100 Subject: [PATCH 06/12] rename a test --- Lib/test/test_pprint.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py index abaacc37d1c7a8..fbf144a71fd860 100644 --- a/Lib/test/test_pprint.py +++ b/Lib/test/test_pprint.py @@ -323,7 +323,7 @@ def test_width(self): '1 ' '2']]]]]""") - def test_numbers(self): + def test_integer(self): self.assertEqual(pprint.pformat(1234567), '1_234_567') self.assertEqual(pprint.pformat(1234567, underscore_numbers=False), '1234567') From dd308b01779b3b29465e56304beddd49852412f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Blondon?= Date: Tue, 16 Mar 2021 16:56:48 +0100 Subject: [PATCH 07/12] use redefined __repr__ method for integer subclass if it exists --- Lib/pprint.py | 2 +- Lib/test/test_pprint.py | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Lib/pprint.py b/Lib/pprint.py index 7b586bb488ec96..5f83a03896dc12 100644 --- a/Lib/pprint.py +++ b/Lib/pprint.py @@ -529,7 +529,7 @@ def _safe_repr(self, object, context, maxlevels, level): r = getattr(typ, "__repr__", None) - if issubclass(typ, int): + if issubclass(typ, int) and r is int.__repr__: if self._underscore_numbers: return builtins.format(object, "_d"), True, False else: diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py index fbf144a71fd860..35b80fe8ee9122 100644 --- a/Lib/test/test_pprint.py +++ b/Lib/test/test_pprint.py @@ -327,6 +327,14 @@ def test_integer(self): self.assertEqual(pprint.pformat(1234567), '1_234_567') self.assertEqual(pprint.pformat(1234567, underscore_numbers=False), '1234567') + 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. From 57ff2b7ffd73cb89e7b29e0527bc210c2b358acd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Blondon?= Date: Mon, 22 Mar 2021 12:09:09 +0100 Subject: [PATCH 08/12] replace builtins.format() by f-string format --- Lib/pprint.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Lib/pprint.py b/Lib/pprint.py index 5f83a03896dc12..e5adb0817e00d7 100644 --- a/Lib/pprint.py +++ b/Lib/pprint.py @@ -34,7 +34,6 @@ """ -import builtins import collections as _collections import re import sys as _sys @@ -531,7 +530,7 @@ def _safe_repr(self, object, context, maxlevels, level): if issubclass(typ, int) and r is int.__repr__: if self._underscore_numbers: - return builtins.format(object, "_d"), True, False + return f"{object:_d}", True, False else: return repr(object), True, False From abbd11015ddf12cc04f30734a7ea3d3ee3bd83e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Blondon?= Date: Mon, 22 Mar 2021 14:52:17 +0100 Subject: [PATCH 09/12] underscore_numbers parameter is False by default to keep backward compatibility --- Doc/library/pprint.rst | 10 +++++----- Lib/pprint.py | 8 ++++---- Lib/test/test_pprint.py | 8 ++++---- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Doc/library/pprint.rst b/Doc/library/pprint.rst index a6a707e5819b1b..b3b6ed56a5e17e 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, underscore_numbers=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* @@ -56,9 +56,9 @@ The :mod:`pprint` module defines one class: 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. If - *underscore_numbers* is true (the default), integers will be formatted with + *underscore_numbers* is true, integers will be formatted with ```_``` character for a thousands separator, otherwise underscores are not - displayed. + displayed (the default). .. versionchanged:: 3.4 Added the *compact* parameter. @@ -96,7 +96,7 @@ 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, underscore_numbers=True) + compact=False, sort_dicts=True, underscore_numbers=False) Return the formatted representation of *object* as a string. *indent*, *width*, *depth*, *compact*, *sort_dicts* and *underscore_numbers* will be passed to the @@ -124,7 +124,7 @@ 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, underscore_numbers=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 diff --git a/Lib/pprint.py b/Lib/pprint.py index e5adb0817e00d7..b45cfdd99a8e11 100644 --- a/Lib/pprint.py +++ b/Lib/pprint.py @@ -45,15 +45,15 @@ def pprint(object, stream=None, indent=1, width=80, depth=None, *, - compact=False, sort_dicts=True, underscore_numbers=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, underscore_numbers=True) + 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, underscore_numbers=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, @@ -103,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, underscore_numbers=True): + compact=False, sort_dicts=True, underscore_numbers=False): """Handle pretty printing operations onto a stream using a set of configured parameters. diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py index 35b80fe8ee9122..8a6dc0278d248a 100644 --- a/Lib/test/test_pprint.py +++ b/Lib/test/test_pprint.py @@ -245,12 +245,12 @@ def test_basic_line_wrap(self): 'write_io_runtime_us': 43690} exp = """\ {'RPM_cal': 0, - 'RPM_cal2': 48_059, + 'RPM_cal2': 48059, 'Speed_cal': 0, 'controldesk_runtime_us': 0, 'main_code_runtime_us': 0, 'read_io_runtime_us': 0, - 'write_io_runtime_us': 43_690}""" + 'write_io_runtime_us': 43690}""" for type in [dict, dict2]: self.assertEqual(pprint.pformat(type(o)), exp) @@ -324,8 +324,8 @@ def test_width(self): '2']]]]]""") def test_integer(self): - self.assertEqual(pprint.pformat(1234567), '1_234_567') - self.assertEqual(pprint.pformat(1234567, underscore_numbers=False), '1234567') + 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): From 3f0ee71de60a68ccbb418de720439ef6ed363717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Blondon?= Date: Mon, 22 Mar 2021 15:00:59 +0100 Subject: [PATCH 10/12] update news to fit the backward compatibility behavior --- .../next/Library/2021-03-14-21-47-28.bpo-42914.9U1o33.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 index ee71ecb3bdc86c..40a5aed1be247a 100644 --- 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 @@ -1,2 +1,3 @@ pprint.pprint() displays integers with thousands separated by an underscore -character to improve readability (for example 1_000_000 instead of 1000000). +character to improve readability (for example 1_000_000 instead of 1000000) +if underscore_numbers parameter is enabled. From 0726e734694d5ea6abaefc991189b7ef329648de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Blondon?= Date: Wed, 24 Mar 2021 08:16:25 +0100 Subject: [PATCH 11/12] improve code coverage of underscore_numbers parameter --- Lib/test/test_pprint.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py index 8a6dc0278d248a..e5d2ac52d12836 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): From 4ff85035200e7e21b00c907c4913f2247f23e844 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Wed, 24 Mar 2021 01:03:19 -0700 Subject: [PATCH 12/12] Reword the news entry, attempt to use ReST --- .../next/Library/2021-03-14-21-47-28.bpo-42914.9U1o33.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 index 40a5aed1be247a..ae6ef2f0bfa424 100644 --- 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 @@ -1,3 +1,3 @@ -pprint.pprint() displays integers with thousands separated by an underscore -character to improve readability (for example 1_000_000 instead of 1000000) -if underscore_numbers parameter is enabled. +: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``).