Skip to content

Commit dfd5667

Browse files
committed
Update the PEP to match the latest decisions, and reference implementation
1 parent 93b0d6e commit dfd5667

File tree

1 file changed

+83
-40
lines changed

1 file changed

+83
-40
lines changed

peps/pep-0813.rst

Lines changed: 83 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,23 @@ includes a class and APIs which users can invoke to format and print more readab
2525
versus the standard ``repr()`` built-in function. Important use cases include pretty printing large
2626
dictionaries and other complicated objects for debugging purposes.
2727

28-
The ``pprint`` module is great as far as it goes. This PEP builds on the features of this module to provide
29-
more customization and convenience.
28+
This PEP builds on the features of the module to provide more customization and user convenience. It is also
29+
inspired by the `Rich library's pretty printing protocol
30+
<https://rich.readthedocs.io/en/latest/pretty.html#rich-repr-protocol>`_.
3031

3132

3233
Rationale
3334
=========
3435

3536
Pretty printing is very useful for displaying complex data structures, like dictionaries read from JSON
3637
content. By providing a way for classes to customize how their instances participate in pretty printing,
37-
users have more options for visually improving the display and debugging of their complex data.
38+
users have more options for visually improving the display of their complex data, especially for debugging.
3839

39-
By extending the built-in :func:`print` function to automatically pretty print its output, this feature is
40-
made even more convenient, since no extra imports are required, and users can easily just piggyback on
41-
well-worn "print debugging" patterns, at least for the most common use cases.
40+
By extending the built-in :func:`print` function to automatically pretty print its output, debugging with
41+
user-friendly display is made even more convenient. Since no extra imports are required, users can easily
42+
just piggyback on well-worn "print debugging" patterns, at least for the most common use cases.
4243

43-
These two extensions work independently, but hand-in-hand can provide a powerful and convenient new feature.
44+
These extensions work both independently and complimentary, to provide powerful new use cases.
4445

4546

4647
Specification
@@ -52,33 +53,33 @@ There are several parts to this proposal.
5253
``__pprint__()`` methods
5354
------------------------
5455

55-
Classes can implement a new dunder method, ``__pprint__()`` which if present, generates the pretty printed
56-
representation of their instances. This augments ``__repr__()`` which, prior to this proposal, was the only
57-
method used to generate a custom representation of the object. Since object reprs provide functionality
56+
Classes can implement a new dunder method, ``__pprint__()`` which if present, generates parts of their
57+
instance's pretty printed representation. This augments ``__repr__()`` which, prior to this proposal, was the
58+
only method used to generate a custom representation of the object. Since object reprs provide functionality
5859
distinct from pretty printing, some classes may want more control over their pretty display. The
5960
:py:class:`python:pprint.PrettyPrinter` class is modified to respect an object's ``__pprint__()`` method if
6061
present.
6162

62-
``__pprint__()`` is optional; if missing, the standard pretty printers fall back to ``__repr__()``
63-
for full backward compatibility (technically speaking, :py:func:`python:pprint.saferepr` is used).
64-
However, if defined on a class, ``__pprint__()`` has the same argument signature as
65-
:py:meth:`python:pprint.PrettyPrinter.format`, taking four arguments:
63+
``__pprint__()`` is optional; if missing, the standard pretty printers fall back to ``__repr__()`` for full
64+
backward compatibility (technically speaking, :py:func:`python:pprint.saferepr` is used). However, if defined
65+
on a class, ``__pprint__()`` takes a single argument, the object to be pretty printed (i.e. ``self``).
6666

67-
* ``self`` - this object (described in ``PrettyPrinter.format()`` method as ``object``)
68-
* ``context`` - a dictionary mapping the ``id()`` of objects which are part of the current presentation
69-
context
70-
* ``maxlevels`` - the requested limit to recursion
71-
* ``levels`` - the current recursion level
67+
The method is expected to return or yield a sequence of values, which are used to construct a pretty
68+
representation of the object. These values are wrapped in standard class "chrome", such as the
69+
class name. The printed representation will usually look like a class constructor, with positional,
70+
keyword, and default arguments. The values can be any of the following formats:
7271

73-
Similarly, ``__pprint__()`` returns three values:
72+
* A single value, representing a positional argument. The value itself is used.
73+
* A 2-tuple of ``(name, value)`` representing a keyword argument. A representation of
74+
``name=value`` is used.
75+
* A 3-tuple of ``(name, value, default_value)`` representing a keyword argument with a default
76+
value. If ``value`` equals ``default_value``, then this tuple is skipped, otherwise
77+
``name=value`` is used.
7478

75-
* the string to be used as the pretty printed representation
76-
* a boolean indicating whether the returned value is "readable" (defined by
77-
:py:meth:`python:pprint.PrettyPrinter.isreadable`, i.e. that the returned value can be used to reconstruct the
78-
original object using ``eval()``).
79-
* boolean indicating whether recursion has been detected.
79+
.. note::
8080

81-
See :py:meth:`python:pprint.PrettyPrinter.format` for details.
81+
This protocol is compatible with the `Rich library's pretty printing protocol
82+
<https://rich.readthedocs.io/en/latest/pretty.html#rich-repr-protocol>`_.
8283

8384

8485
A new argument to built-in ``print``
@@ -100,26 +101,42 @@ Built-in :func:`print` takes a new optional argument, appended to the end of the
100101
Examples
101102
========
102103

103-
A custom ``__pprint__()`` method can be used to customize the representation of the object:
104+
A custom ``__pprint__()`` method can be used to customize the representation of the object, such as with this
105+
class:
104106

105-
.. code-block::
107+
.. code-block:: python
106108
107-
>>> class Custom:
108-
... def __str__(self): return 'my str'
109-
... def __repr__(self): return 'my repr'
110-
... def __pprint__(self, context, maxlevels, level):
111-
... return 'my pprint', False, False
109+
class Bass:
110+
def __init__(self, strings: int, pickups: str, active: bool=False):
111+
self._strings = strings
112+
self._pickups = pickups
113+
self._active = active
112114
113-
>>> pprint.pp(Custom())
114-
my pprint
115+
def __pprint__(self):
116+
yield self._strings
117+
yield 'pickups', self._pickups
118+
yield 'active', self._active, False
115119
116-
Using the ``pretty`` argument to ``print()``:
120+
Now let's create a couple of instances, and pretty print them:
117121

118-
.. code-block::
122+
.. code-block:: pycon
123+
124+
>>> precision = Bass(4, 'split coil P', active=False)
125+
>>> stingray = Bass(5, 'humbucker', active=True)
126+
127+
>>> pprint.pprint(precision)
128+
Bass(4, pickups='split coil P')
129+
>>> pprint.pprint(stingray)
130+
Bass(5, pickups='humbucker', active=True)
131+
132+
Here's an example of using the ``pretty`` argument to built-in ``print()``:
133+
134+
.. code-block:: pycon
119135
120136
>>> import os
121137
>>> print(os.pathconf_names)
122138
{'PC_ASYNC_IO': 17, 'PC_CHOWN_RESTRICTED': 7, 'PC_FILESIZEBITS': 18, 'PC_LINK_MAX': 1, 'PC_MAX_CANON': 2, 'PC_MAX_INPUT': 3, 'PC_NAME_MAX': 4, 'PC_NO_TRUNC': 8, 'PC_PATH_MAX': 5, 'PC_PIPE_BUF': 6, 'PC_PRIO_IO': 19, 'PC_SYNC_IO': 25, 'PC_VDISABLE': 9, 'PC_MIN_HOLE_SIZE': 27, 'PC_ALLOC_SIZE_MIN': 16, 'PC_REC_INCR_XFER_SIZE': 20, 'PC_REC_MAX_XFER_SIZE': 21, 'PC_REC_MIN_XFER_SIZE': 22, 'PC_REC_XFER_ALIGN': 23, 'PC_SYMLINK_MAX': 24}
139+
123140
>>> print(os.pathconf_names, pretty=True)
124141
{'PC_ALLOC_SIZE_MIN': 16,
125142
'PC_ASYNC_IO': 17,
@@ -180,10 +197,36 @@ None at this time.
180197
Open Issues
181198
===========
182199

183-
TBD
200+
The output format and APIs are heavily inspired by `Rich
201+
<https://rich.readthedocs.io/en/latest/pretty.html#rich-repr-protocol>`_. The idea is that Rich could
202+
implement an API compatible with ``print(..., pretty=RichPrinter)`` fairly easily. Rich's API is designed to
203+
print constructor-like representations of instances, which means that it's not possible to control much of the
204+
"class chrome" around the arguments. Rich does support using angle brackets (i.e. ``<...>``) instead of
205+
parentheses by setting the attribute ``.angular=True`` on the rich repr method. This PEP does not support
206+
that feature, although it likely could in the future.
207+
208+
This also means that there's no way to control the pretty printed format of built-in types like strings,
209+
dicts, lists, etc. This seems fine as ``pprint`` is not intended to be as feature-rich (pun intended!) as
210+
Rich. This PEP purposefully deems such fancy features as out-of-scope.
211+
212+
One consequence of ``print(..., pretty=True)`` is that it can be more less obvious if you wanted to print
213+
multiple objects with, say a newline between the object representations. Compare these two outputs:
214+
215+
.. code-block:: pycon
216+
217+
>>> print(precision, '\n', stingray, pretty=True)
218+
Bass(4, pickups='split coil P') '\n' Bass(5, pickups='humbucker', active=True)
219+
220+
>>> print(precision, stingray, sep='\n', pretty=True)
221+
Bass(4, pickups='split coil P')
222+
Bass(5, pickups='humbucker', active=True)
223+
224+
It's likely you'll want the second output, but more complicated multi-object displays could get even less
225+
convenient and/or more verbose.
226+
184227

185-
Acknowledgements
186-
================
228+
Acknowledgments
229+
===============
187230

188231
TBD
189232

0 commit comments

Comments
 (0)