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).
diff --git a/Lib/pprint.py b/Lib/pprint.py
index a8af50e..b45cfdd 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):