diff --git a/Doc/library/pprint.rst b/Doc/library/pprint.rst index 6d751ab04b49dd..2c35efd47d74f0 100644 --- a/Doc/library/pprint.rst +++ b/Doc/library/pprint.rst @@ -36,7 +36,7 @@ Functions --------- .. function:: pp(object, stream=None, indent=1, width=80, depth=None, *, \ - block_style=False, compact=False, sort_dicts=False, \ + compact=False, expand=False, sort_dicts=False, \ underscore_numbers=False) Prints the formatted representation of *object*, followed by a newline. @@ -75,6 +75,13 @@ Functions each item of a sequence will be formatted on a separate line, otherwise as many items as will fit within the *width* will be formatted on each output line. + Incompatible with *expand*. + + :param bool expand: + If ``True``, + opening parentheses and brackets will be followed by a newline and the + following content will be indented by one level, similar to block style + JSON formatting. Incompatible with *compact*. :param bool sort_dicts: If ``True``, dictionaries will be formatted with @@ -86,12 +93,6 @@ Functions integers will be formatted with the ``_`` character for a thousands separator, otherwise underscores are not displayed (the default). - :param bool block_style: - If ``True``, - opening parentheses and brackets will be followed by a newline and the - following content will be indented by one level, similar to block style - JSON formatting. This option is not compatible with *compact*. - >>> import pprint >>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni'] >>> stuff.insert(0, stuff) @@ -107,7 +108,7 @@ Functions .. function:: pprint(object, stream=None, indent=1, width=80, depth=None, *, \ - block_style=False, compact=False, sort_dicts=True, \ + compact=False, expand=False, sort_dicts=True, \ underscore_numbers=False) Alias for :func:`~pprint.pp` with *sort_dicts* set to ``True`` by default, @@ -116,11 +117,11 @@ Functions .. function:: pformat(object, indent=1, width=80, depth=None, *, \ - block_style=False, compact=False, sort_dicts=True, \ + compact=False, expand=False, sort_dicts=True, \ underscore_numbers=False) Return the formatted representation of *object* as a string. *indent*, - *width*, *depth*, *compact*, *sort_dicts*, *underscore_numbers* and *block_style* are + *width*, *depth*, *compact*, *expand*, *sort_dicts* and *underscore_numbers* are passed to the :class:`PrettyPrinter` constructor as formatting parameters and their meanings are as described in the documentation above. @@ -164,7 +165,7 @@ PrettyPrinter Objects .. index:: single: ...; placeholder .. class:: PrettyPrinter(indent=1, width=80, depth=None, stream=None, *, \ - block_style=False, compact=False, sort_dicts=True, \ + compact=False, expand=False, sort_dicts=True, \ underscore_numbers=False) Construct a :class:`PrettyPrinter` instance. @@ -189,7 +190,7 @@ PrettyPrinter Objects 'knights', 'ni'], 'spam', 'eggs', 'lumberjack', 'knights', 'ni'] - >>> pp = pprint.PrettyPrinter(width=41, block_style=True, indent=3) + >>> pp = pprint.PrettyPrinter(width=41, expand=True, indent=3) >>> pp.pprint(stuff) [ [ @@ -225,7 +226,7 @@ PrettyPrinter Objects No longer attempts to write to :data:`!sys.stdout` if it is ``None``. .. versionchanged:: next - Added the *block_style* parameter. + Added the *expand* parameter. :class:`PrettyPrinter` instances have the following methods: @@ -450,10 +451,10 @@ cannot be split, the specified width will be exceeded:: 'summary': 'A sample Python project', 'version': '1.2.0'} -Lastly, we can achieve block style formatting with the *block_style* parameter. +Lastly, we can achieve block style formatting with the *expand* parameter. Best results are achieved with a higher *indent* value:: - >>> pprint.pp(project_info, indent=4, block_style=True) + >>> pprint.pp(project_info, indent=4, expand=True) { 'author': 'The Python Packaging Authority', 'author_email': 'pypa-dev@googlegroups.com', diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 881c5827b78164..b911b1c3a88a06 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -411,7 +411,7 @@ platform pprint ------ -* Add a *block_style* keyword argument for :func:`pprint.pprint`, +* Add an *expand* keyword argument for :func:`pprint.pprint`, :func:`pprint.pformat`, :func:`pprint.pp`. If true, the output will be formatted in a block style similar to pretty-printed :func:`json.dumps` when *indent* is supplied. diff --git a/Lib/pprint.py b/Lib/pprint.py index 79711f601b0514..76ce87b6eb0342 100644 --- a/Lib/pprint.py +++ b/Lib/pprint.py @@ -44,24 +44,23 @@ def pprint(object, stream=None, indent=1, width=80, depth=None, *, - block_style=False, compact=False, sort_dicts=True, + compact=False, expand=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=underscore_numbers, block_style=block_style) + compact=compact, expand=expand, sort_dicts=sort_dicts, + underscore_numbers=underscore_numbers) printer.pprint(object) def pformat(object, indent=1, width=80, depth=None, *, - block_style=False, compact=False, sort_dicts=True, + compact=False, expand=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, - underscore_numbers=underscore_numbers, - block_style=block_style).pformat(object) + compact=compact, expand=expand, sort_dicts=sort_dicts, + underscore_numbers=underscore_numbers).pformat(object) def pp(object, *args, sort_dicts=False, **kwargs): @@ -114,7 +113,7 @@ def _safe_tuple(t): class PrettyPrinter: def __init__(self, indent=1, width=80, depth=None, stream=None, *, - block_style=False, compact=False, sort_dicts=True, + compact=False, expand=False, sort_dicts=True, underscore_numbers=False): """Handle pretty printing operations onto a stream using a set of configured parameters. @@ -134,6 +133,12 @@ def __init__(self, indent=1, width=80, depth=None, stream=None, *, compact If true, several items will be combined in one line. + Incompatible with expand mode. + + expand + If true, the output will be formatted in a block style similar to + pretty-printed json.dumps() when ``indent`` is supplied. + Incompatible with compact mode. sort_dicts If true, dict keys are sorted. @@ -141,11 +146,6 @@ def __init__(self, indent=1, width=80, depth=None, stream=None, *, underscore_numbers If true, digit groups are separated with underscores. - block_style - If true, the output will be formatted in a block style similar to - pretty-printed json.dumps() when ``indent`` is supplied. - Incompatible with compact mode. - """ indent = int(indent) width = int(width) @@ -155,8 +155,8 @@ def __init__(self, indent=1, width=80, depth=None, stream=None, *, raise ValueError('depth must be > 0') if not width: raise ValueError('width must be != 0') - if compact and block_style: - raise ValueError('compact and block_style are incompatible') + if compact and expand: + raise ValueError('compact and expand are incompatible') self._depth = depth self._indent_per_level = indent self._width = width @@ -165,9 +165,9 @@ def __init__(self, indent=1, width=80, depth=None, stream=None, *, else: self._stream = _sys.stdout self._compact = bool(compact) + self._expand = bool(expand) self._sort_dicts = sort_dicts self._underscore_numbers = underscore_numbers - self._block_style = bool(block_style) def pprint(self, object): if self._stream is not None: @@ -218,12 +218,12 @@ def _format(self, object, stream, indent, allowance, context, level): stream.write(rep) def _format_block_start(self, start_str, indent): - if self._block_style: + if self._expand: return f"{start_str}\n{' ' * indent}" return start_str def _format_block_end(self, end_str, indent): - if self._block_style: + if self._expand: return f"\n{' ' * indent}{end_str}" return end_str @@ -232,7 +232,7 @@ def _pprint_dataclass(self, object, stream, indent, allowance, context, level): from dataclasses import fields as dataclass_fields cls_name = object.__class__.__name__ - if self._block_style: + if self._expand: indent += self._indent_per_level else: indent += len(cls_name) + 1 @@ -246,9 +246,9 @@ def _pprint_dataclass(self, object, stream, indent, allowance, context, level): def _pprint_dict(self, object, stream, indent, allowance, context, level): write = stream.write write(self._format_block_start('{', indent)) - if self._indent_per_level > 1 and not self._block_style: + if self._indent_per_level > 1 and not self._expand: write((self._indent_per_level - 1) * ' ') - if self._indent_per_level > 0 and self._block_style: + if self._indent_per_level > 0 and self._expand: write(self._indent_per_level * ' ') length = len(object) if length: @@ -268,7 +268,7 @@ def _pprint_ordered_dict(self, object, stream, indent, allowance, context, level return cls = object.__class__ stream.write(cls.__name__ + '(') - if self._block_style: + if self._expand: recursive_indent = indent else: recursive_indent = indent + len(cls.__name__) + 1 @@ -349,7 +349,7 @@ def _pprint_set(self, object, stream, indent, allowance, context, level): else: stream.write(self._format_block_start(typ.__name__ + '({', indent)) endchar = '})' - if not self._block_style: + if not self._expand: indent += len(typ.__name__) + 1 object = sorted(object, key=_safe_key) self._format_items(object, stream, indent, allowance + len(endchar), @@ -420,7 +420,7 @@ def _pprint_bytes(self, object, stream, indent, allowance, context, level): return parens = level == 1 if parens: - if self._block_style: + if self._expand: indent += self._indent_per_level else: indent += 1 @@ -440,7 +440,7 @@ def _pprint_bytes(self, object, stream, indent, allowance, context, level): def _pprint_bytearray(self, object, stream, indent, allowance, context, level): write = stream.write write(self._format_block_start('bytearray(', indent)) - if self._block_style: + if self._expand: write(' ' * self._indent_per_level) recursive_indent = indent + self._indent_per_level else: @@ -453,7 +453,7 @@ def _pprint_bytearray(self, object, stream, indent, allowance, context, level): def _pprint_mappingproxy(self, object, stream, indent, allowance, context, level): stream.write('mappingproxy(') - if self._block_style: + if self._expand: recursive_indent = indent else: recursive_indent = indent + 13 @@ -470,7 +470,7 @@ def _pprint_simplenamespace(self, object, stream, indent, allowance, context, le cls_name = 'namespace' else: cls_name = object.__class__.__name__ - if self._block_style: + if self._expand: indent += self._indent_per_level else: indent += len(cls_name) + 1 @@ -493,7 +493,7 @@ def _format_dict_items(self, items, stream, indent, allowance, context, rep = self._repr(key, context, level) write(rep) write(': ') - if self._block_style: + if self._expand: recursive_indent = indent else: recursive_indent = indent + len(rep) + 2 @@ -516,7 +516,7 @@ def _format_namespace_items(self, items, stream, indent, allowance, context, lev # recursive dataclass repr. write("...") else: - if self._block_style: + if self._expand: recursive_indent = indent else: recursive_indent = indent + len(key) + 1 @@ -529,9 +529,9 @@ def _format_namespace_items(self, items, stream, indent, allowance, context, lev def _format_items(self, items, stream, indent, allowance, context, level): write = stream.write indent += self._indent_per_level - if self._indent_per_level > 1 and not self._block_style: + if self._indent_per_level > 1 and not self._expand: write((self._indent_per_level - 1) * ' ') - if self._indent_per_level > 0 and self._block_style: + if self._indent_per_level > 0 and self._expand: write(self._indent_per_level * ' ') delimnl = ',\n' + ' ' * indent delim = '' @@ -591,7 +591,7 @@ def _pprint_default_dict(self, object, stream, indent, allowance, context, level return rdf = self._repr(object.default_factory, context, level) cls = object.__class__ - if self._block_style: + if self._expand: stream.write('%s(%s, ' % (cls.__name__, rdf)) else: indent += len(cls.__name__) + 1 @@ -608,12 +608,12 @@ def _pprint_counter(self, object, stream, indent, allowance, context, level): return cls = object.__class__ stream.write(self._format_block_start(cls.__name__ + '({', indent)) - if self._indent_per_level > 1 and not self._block_style: + if self._indent_per_level > 1 and not self._expand: stream.write((self._indent_per_level - 1) * ' ') - if self._indent_per_level > 0 and self._block_style: + if self._indent_per_level > 0 and self._expand: stream.write(self._indent_per_level * ' ') items = object.most_common() - if self._block_style: + if self._expand: recursive_indent = indent else: recursive_indent = indent + len(cls.__name__) + 1 @@ -630,7 +630,7 @@ def _pprint_chain_map(self, object, stream, indent, allowance, context, level): cls = object.__class__ stream.write(self._format_block_start(cls.__name__ + '(', indent + self._indent_per_level)) - if self._block_style: + if self._expand: indent += self._indent_per_level else: indent += len(cls.__name__) + 1 @@ -650,7 +650,7 @@ def _pprint_deque(self, object, stream, indent, allowance, context, level): return cls = object.__class__ stream.write(self._format_block_start(cls.__name__ + '([', indent)) - if not self._block_style: + if not self._expand: indent += len(cls.__name__) + 1 if object.maxlen is None: self._format_items(object, stream, indent, allowance + 2, @@ -660,7 +660,7 @@ def _pprint_deque(self, object, stream, indent, allowance, context, level): self._format_items(object, stream, indent, 2, context, level) rml = self._repr(object.maxlen, context, level) - if self._block_style: + if self._expand: stream.write('%s], maxlen=%s)' % ('\n' + ' ' * indent, rml)) else: stream.write('],\n%smaxlen=%s)' % (' ' * indent, rml)) diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py index 24914e9c35c498..ea375aa3ffb3b8 100644 --- a/Lib/test/test_pprint.py +++ b/Lib/test/test_pprint.py @@ -157,7 +157,7 @@ def test_init(self): self.assertRaises(ValueError, pprint.PrettyPrinter, depth=0) self.assertRaises(ValueError, pprint.PrettyPrinter, depth=-1) self.assertRaises(ValueError, pprint.PrettyPrinter, width=0) - self.assertRaises(ValueError, pprint.PrettyPrinter, compact=True, block_style=True) + self.assertRaises(ValueError, pprint.PrettyPrinter, compact=True, expand=True) def test_basic(self): # Verify .isrecursive() and .isreadable() w/o recursion @@ -1479,7 +1479,7 @@ def test_user_string(self): 'jumped over a ' 'lazy dog'}""") - def test_block_style_dataclass(self): + def test_expand_dataclass(self): @dataclasses.dataclass class DummyDataclass: foo: str @@ -1499,7 +1499,7 @@ class DummyDataclass: garply=(1, 2, 3, 4), ) self.assertEqual(pprint.pformat(dummy_dataclass, width=40, indent=4, - block_style=True), + expand=True), """\ DummyDataclass( foo='foo', @@ -1511,7 +1511,7 @@ class DummyDataclass: garply=(1, 2, 3, 4) )""") - def test_block_style_dict(self): + def test_expand_dict(self): dummy_dict = { "foo": "bar", "baz": 123, @@ -1520,7 +1520,7 @@ def test_block_style_dict(self): "corge": 7, } self.assertEqual(pprint.pformat(dummy_dict, width=40, indent=4, - block_style=True, sort_dicts=False), + expand=True, sort_dicts=False), """\ { 'foo': 'bar', @@ -1530,7 +1530,7 @@ def test_block_style_dict(self): 'corge': 7 }""") - def test_block_style_ordered_dict(self): + def test_expand_ordered_dict(self): dummy_ordered_dict = collections.OrderedDict( [ ("foo", 1), @@ -1539,7 +1539,7 @@ def test_block_style_ordered_dict(self): ] ) self.assertEqual(pprint.pformat(dummy_ordered_dict, width=20, indent=4, - block_style=True), + expand=True), """\ OrderedDict([ ('foo', 1), @@ -1547,7 +1547,7 @@ def test_block_style_ordered_dict(self): ('baz', 123) ])""") - def test_block_style_list(self): + def test_expand_list(self): dummy_list = [ "foo", "bar", @@ -1555,7 +1555,7 @@ def test_block_style_list(self): "qux", ] self.assertEqual(pprint.pformat(dummy_list, width=20, indent=4, - block_style=True), + expand=True), """\ [ 'foo', @@ -1564,7 +1564,7 @@ def test_block_style_list(self): 'qux' ]""") - def test_block_style_tuple(self): + def test_expand_tuple(self): dummy_tuple = ( "foo", "bar", @@ -1574,7 +1574,7 @@ def test_block_style_tuple(self): 6, ) self.assertEqual(pprint.pformat(dummy_tuple, width=20, indent=4, - block_style=True), + expand=True), """\ ( 'foo', @@ -1585,7 +1585,7 @@ def test_block_style_tuple(self): 6 )""") - def test_block_style_set(self): + def test_expand_set(self): dummy_set = { "foo", "bar", @@ -1594,7 +1594,7 @@ def test_block_style_set(self): (1, 2, 3), } self.assertEqual(pprint.pformat(dummy_set, width=20, indent=4, - block_style=True), + expand=True), """\ { 'bar', @@ -1604,7 +1604,7 @@ def test_block_style_set(self): (1, 2, 3) }""") - def test_block_style_frozenset(self): + def test_expand_frozenset(self): dummy_set = { (1, 2, 3), } @@ -1618,7 +1618,7 @@ def test_block_style_frozenset(self): } ) self.assertEqual(pprint.pformat(dummy_frozenset, width=40, indent=4, - block_style=True), + expand=True), """\ frozenset({ frozenset({(1, 2, 3)}), @@ -1628,10 +1628,10 @@ def test_block_style_frozenset(self): (1, 2, 3) })""") - def test_block_style_bytes(self): + def test_expand_bytes(self): dummy_bytes = b"Hello world! foo bar baz 123 456 789" self.assertEqual(pprint.pformat(dummy_bytes, width=20, indent=4, - block_style=True), + expand=True), """\ ( b'Hello world!' @@ -1639,18 +1639,18 @@ def test_block_style_bytes(self): b' 123 456 789' )""") - def test_block_style_bytearray(self): + def test_expand_bytearray(self): dummy_bytes = b"Hello world! foo bar baz 123 456 789" dummy_byte_array = bytearray(dummy_bytes) self.assertEqual(pprint.pformat(dummy_byte_array, width=40, indent=4, - block_style=True), + expand=True), """\ bytearray( b'Hello world! foo bar baz 123 456' b' 789' )""") - def test_block_style_mappingproxy(self): + def test_expand_mappingproxy(self): dummy_dict = { "foo": "bar", "baz": 123, @@ -1660,7 +1660,7 @@ def test_block_style_mappingproxy(self): } dummy_mappingproxy = types.MappingProxyType(dummy_dict) self.assertEqual(pprint.pformat(dummy_mappingproxy, width=40, indent=4, - block_style=True), + expand=True), """\ mappingproxy({ 'baz': 123, @@ -1670,7 +1670,7 @@ def test_block_style_mappingproxy(self): 'qux': {'baz': 123, 'foo': 'bar'} })""") - def test_block_style_namespace(self): + def test_expand_namespace(self): dummy_namespace = types.SimpleNamespace( foo="bar", bar=42, @@ -1682,7 +1682,7 @@ def test_block_style_namespace(self): ) self.assertEqual(pprint.pformat(dummy_namespace, width=40, indent=4, - block_style=True), + expand=True), """\ namespace( foo='bar', @@ -1694,21 +1694,21 @@ def test_block_style_namespace(self): ) )""") - def test_block_style_defaultdict(self): + def test_expand_defaultdict(self): dummy_defaultdict = collections.defaultdict(list) dummy_defaultdict["foo"].append("bar") dummy_defaultdict["foo"].append("baz") dummy_defaultdict["foo"].append("qux") dummy_defaultdict["bar"] = {"foo": "bar", "baz": None} self.assertEqual(pprint.pformat(dummy_defaultdict, width=40, indent=4, - block_style=True), + expand=True), """\ defaultdict(, { 'bar': {'baz': None, 'foo': 'bar'}, 'foo': ['bar', 'baz', 'qux'] })""") - def test_block_style_counter(self): + def test_expand_counter(self): dummy_counter = collections.Counter("abcdeabcdabcaba") expected = """\ Counter({ @@ -1719,7 +1719,7 @@ def test_block_style_counter(self): 'e': 1 })""" self.assertEqual(pprint.pformat(dummy_counter, width=40, indent=4, - block_style=True), expected) + expand=True), expected) expected2 = """\ Counter({ @@ -1730,9 +1730,9 @@ def test_block_style_counter(self): 'e': 1 })""" self.assertEqual(pprint.pformat(dummy_counter, width=20, indent=2, - block_style=True), expected2) + expand=True), expected2) - def test_block_style_chainmap(self): + def test_expand_chainmap(self): dummy_dict = { "foo": "bar", "baz": 123, @@ -1747,7 +1747,7 @@ def test_block_style_chainmap(self): ) dummy_chainmap.maps.append({"garply": "waldo"}) self.assertEqual(pprint.pformat(dummy_chainmap, width=40, indent=4, - block_style=True), + expand=True), """\ ChainMap( {'foo': 'bar'}, @@ -1767,7 +1767,7 @@ def test_block_style_chainmap(self): {'garply': 'waldo'} )""") - def test_block_style_deque(self): + def test_expand_deque(self): dummy_dict = { "foo": "bar", "baz": 123, @@ -1790,7 +1790,7 @@ def test_block_style_deque(self): dummy_deque.extend(dummy_list) dummy_deque.appendleft(dummy_set) self.assertEqual(pprint.pformat(dummy_deque, width=40, indent=4, - block_style=True), + expand=True), """\ deque([ {(1, 2, 3)}, @@ -1808,7 +1808,7 @@ def test_block_style_deque(self): 'baz' ], maxlen=10)""") - def test_block_style_userdict(self): + def test_expand_userdict(self): class DummyUserDict(collections.UserDict): """A custom UserDict with some extra attributes""" @@ -1822,7 +1822,7 @@ def __init__(self, *args, **kwargs): dummy_userdict.access_count = 5 self.assertEqual(pprint.pformat(dummy_userdict, width=40, indent=4, - block_style=True), + expand=True), """\ { 'baz': 123, @@ -1832,7 +1832,7 @@ def __init__(self, *args, **kwargs): 'qux': {'baz': 123, 'foo': 'bar'} }""") - def test_block_style_userlist(self): + def test_expand_userlist(self): class DummyUserList(collections.UserList): """A custom UserList with some extra attributes""" @@ -1843,7 +1843,7 @@ def __init__(self, *args, **kwargs): [4, 5, 6]]) self.assertEqual(pprint.pformat(dummy_userlist, width=40, indent=4, - block_style=True), + expand=True), """\ [ 'first', diff --git a/Misc/NEWS.d/next/Library/2025-02-07-00-48-07.gh-issue-112632.95MM0C.rst b/Misc/NEWS.d/next/Library/2025-02-07-00-48-07.gh-issue-112632.95MM0C.rst index ba3fe9de81225a..0842c8e3a04627 100644 --- a/Misc/NEWS.d/next/Library/2025-02-07-00-48-07.gh-issue-112632.95MM0C.rst +++ b/Misc/NEWS.d/next/Library/2025-02-07-00-48-07.gh-issue-112632.95MM0C.rst @@ -1,3 +1,3 @@ -Add a *block_style* keyword argument for :func:`pprint.pprint`, +Add an *expand* keyword argument for :func:`pprint.pprint`, :func:`pprint.pformat`, :func:`pprint.pp` by passing on all *kwargs* and :class:`pprint.PrettyPrinter`. Contributed by Stefan Todoran and Semyon Moroz.