|
| 1 | +PEP: 813 |
| 2 | +Title: The Pretty Print Protocol |
| 3 | +Author: Barry Warsaw <barry@python.org>, Eric V. Smith <eric@trueblade.com> |
| 4 | +Discussions-To: https://discuss.python.org/t/pep-813-the-pretty-print-protocol/106242 |
| 5 | +Status: Draft |
| 6 | +Type: Standards Track |
| 7 | +Created: 07-Nov-2025 |
| 8 | +Python-Version: 3.15 |
| 9 | +Post-History: `21-Feb-2026 <https://discuss.python.org/t/pep-813-the-pretty-print-protocol/106242>`__ |
| 10 | + |
| 11 | + |
| 12 | +Abstract |
| 13 | +======== |
| 14 | + |
| 15 | +This PEP describes the "pretty print protocol", a collection of changes proposed to make pretty printing more |
| 16 | +customizable and convenient. |
| 17 | + |
| 18 | + |
| 19 | +Motivation |
| 20 | +========== |
| 21 | + |
| 22 | +"Pretty printing" is a feature which provides a capability to format object representations for better |
| 23 | +readability. The core functionality is implemented by the standard library :mod:`pprint` module. ``pprint`` |
| 24 | +includes a class and APIs which users can invoke to format and print more readable representations of objects, |
| 25 | +versus the standard ``repr()`` built-in function. Important use cases include pretty printing large |
| 26 | +dictionaries and other complicated objects for debugging purposes. |
| 27 | + |
| 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 <rich-repr-protocol_>`_. |
| 30 | + |
| 31 | + |
| 32 | +Rationale |
| 33 | +========= |
| 34 | + |
| 35 | +Pretty printing is very useful for displaying complex data structures, like dictionaries read from JSON |
| 36 | +content. However, the existing :mod:`pprint` module can only format builtin objects that it knows about. |
| 37 | +By providing a way for classes to customize how their instances participate in pretty printing, |
| 38 | +users have more options for visually improving the display of their complex data, especially for debugging. |
| 39 | + |
| 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. |
| 43 | + |
| 44 | +These extensions work both independently and complimentary, to provide powerful new use cases. |
| 45 | + |
| 46 | + |
| 47 | +Specification |
| 48 | +============= |
| 49 | + |
| 50 | +There are several parts to this proposal. |
| 51 | + |
| 52 | + |
| 53 | +``__pprint__()`` methods |
| 54 | +------------------------ |
| 55 | + |
| 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 |
| 59 | +distinct from pretty printing, some classes may want more control over their pretty display. The |
| 60 | +:py:class:`python:pprint.PrettyPrinter` class is modified to respect an object's ``__pprint__()`` method if |
| 61 | +present. |
| 62 | + |
| 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``). |
| 66 | + |
| 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: |
| 71 | + |
| 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. |
| 78 | + |
| 79 | +.. note:: |
| 80 | + |
| 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>`_. |
| 83 | + |
| 84 | + |
| 85 | +A new argument to built-in ``print`` |
| 86 | +------------------------------------ |
| 87 | + |
| 88 | +Built-in :func:`print` takes a new optional argument, appended to the end of the argument list, called |
| 89 | +``pretty``, which can take one of the following values: |
| 90 | + |
| 91 | +* ``None`` - the default. No pretty printing is invoked. Fully backward compatible. |
| 92 | +* ``True`` - use a temporary instance of the :py:class:`python:pprint.PrettyPrinter` class to get a |
| 93 | + pretty representation of the object. |
| 94 | +* An instance with a ``pformat()`` method, which has the same signature as |
| 95 | + :py:meth:`python:pprint.PrettyPrinter.pformat`. When given, this will usually be an instance of a |
| 96 | + subclass of ``PrettyPrinter`` with its ``pformat()`` method overridden. Note that this form |
| 97 | + requires **an instance** of a pretty printer, not a class, as only ``print(..., pretty=True)`` |
| 98 | + performs implicit instantiation. |
| 99 | + |
| 100 | + |
| 101 | +Additions to ``f-strings`` and ``str.format()`` |
| 102 | +----------------------------------------------- |
| 103 | + |
| 104 | +In addition to the existing ``!s``, ``!r``, and ``!a`` conversion specifiers, an additional ``!p`` conversion |
| 105 | +will be added. The effect of this specifier with an expression ``value`` will be to call |
| 106 | +:py:func:`python:pprint.pformat`, passing ``value`` as the only argument. In this initial specification, it |
| 107 | +will be an error to provide any format specifier if ``!p`` is used. |
| 108 | + |
| 109 | +Examples |
| 110 | +======== |
| 111 | + |
| 112 | +A custom ``__pprint__()`` method can be used to customize the representation of the object, such as with this |
| 113 | +class: |
| 114 | + |
| 115 | +.. code-block:: python |
| 116 | +
|
| 117 | + class Bass: |
| 118 | + def __init__(self, strings: int, pickups: str, active: bool=False): |
| 119 | + self._strings = strings |
| 120 | + self._pickups = pickups |
| 121 | + self._active = active |
| 122 | +
|
| 123 | + def __pprint__(self): |
| 124 | + yield self._strings |
| 125 | + yield 'pickups', self._pickups |
| 126 | + yield 'active', self._active, False |
| 127 | +
|
| 128 | +Now let's create a couple of instances, and pretty print them: |
| 129 | + |
| 130 | +.. code-block:: pycon |
| 131 | +
|
| 132 | + >>> precision = Bass(4, 'split coil P', active=False) |
| 133 | + >>> stingray = Bass(5, 'humbucker', active=True) |
| 134 | +
|
| 135 | + >>> pprint.pprint(precision) |
| 136 | + Bass(4, pickups='split coil P') |
| 137 | + >>> pprint.pprint(stingray) |
| 138 | + Bass(5, pickups='humbucker', active=True) |
| 139 | +
|
| 140 | +Here's an example of using the ``pretty`` argument to built-in ``print()``: |
| 141 | + |
| 142 | +.. code-block:: pycon |
| 143 | +
|
| 144 | + >>> import os |
| 145 | + >>> print(os.pathconf_names) |
| 146 | + {'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} |
| 147 | +
|
| 148 | + >>> print(os.pathconf_names, pretty=True) |
| 149 | + {'PC_ALLOC_SIZE_MIN': 16, |
| 150 | + 'PC_ASYNC_IO': 17, |
| 151 | + 'PC_CHOWN_RESTRICTED': 7, |
| 152 | + 'PC_FILESIZEBITS': 18, |
| 153 | + 'PC_LINK_MAX': 1, |
| 154 | + 'PC_MAX_CANON': 2, |
| 155 | + 'PC_MAX_INPUT': 3, |
| 156 | + 'PC_MIN_HOLE_SIZE': 27, |
| 157 | + 'PC_NAME_MAX': 4, |
| 158 | + 'PC_NO_TRUNC': 8, |
| 159 | + 'PC_PATH_MAX': 5, |
| 160 | + 'PC_PIPE_BUF': 6, |
| 161 | + 'PC_PRIO_IO': 19, |
| 162 | + 'PC_REC_INCR_XFER_SIZE': 20, |
| 163 | + 'PC_REC_MAX_XFER_SIZE': 21, |
| 164 | + 'PC_REC_MIN_XFER_SIZE': 22, |
| 165 | + 'PC_REC_XFER_ALIGN': 23, |
| 166 | + 'PC_SYMLINK_MAX': 24, |
| 167 | + 'PC_SYNC_IO': 25, |
| 168 | + 'PC_VDISABLE': 9} |
| 169 | +
|
| 170 | +
|
| 171 | +Backwards Compatibility |
| 172 | +======================= |
| 173 | + |
| 174 | +When none of the new features are used, this PEP is fully backward compatible, both for built-in |
| 175 | +``print()`` and the ``pprint`` module. |
| 176 | + |
| 177 | + |
| 178 | +Security Implications |
| 179 | +===================== |
| 180 | + |
| 181 | +There are no known security implications for this proposal. |
| 182 | + |
| 183 | + |
| 184 | +How to Teach This |
| 185 | +================= |
| 186 | + |
| 187 | +Documentation and examples are added to the ``pprint`` module and the ``print()`` function. |
| 188 | +Beginners don't need to be taught these new features until they want prettier representations of |
| 189 | +their objects. |
| 190 | + |
| 191 | + |
| 192 | +Reference Implementation |
| 193 | +======================== |
| 194 | + |
| 195 | +The reference implementation is currently available as a `PEP author branch of the CPython main |
| 196 | +branch <https://github.com/warsaw/cpython/tree/pprint>`__. |
| 197 | + |
| 198 | + |
| 199 | +Rejected Ideas |
| 200 | +============== |
| 201 | + |
| 202 | +None at this time. |
| 203 | + |
| 204 | + |
| 205 | +Open Issues |
| 206 | +=========== |
| 207 | + |
| 208 | +The output format and APIs are heavily inspired by `Rich |
| 209 | +<rich-repr-protocol_>`_. The idea is that Rich could |
| 210 | +implement an API compatible with ``print(..., pretty=RichPrinter)`` fairly easily. Rich's API is designed to |
| 211 | +print constructor-like representations of instances, which means that it's not possible to control much of the |
| 212 | +"class chrome" around the arguments. Rich does support using angle brackets (i.e. ``<...>``) instead of |
| 213 | +parentheses by setting the attribute ``.angular=True`` on the rich repr method. This PEP does not support |
| 214 | +that feature, although it likely could in the future. |
| 215 | + |
| 216 | +This also means that there's no way to control the pretty printed format of built-in types like strings, |
| 217 | +dicts, lists, etc. This seems fine as ``pprint`` is not intended to be as feature-rich (pun intended!) as |
| 218 | +Rich. This PEP purposefully deems such fancy features as out-of-scope. |
| 219 | + |
| 220 | +One consequence of ``print(..., pretty=True)`` is that it can be more less obvious if you wanted to print |
| 221 | +multiple objects with, say a newline between the object representations. Compare these two outputs: |
| 222 | + |
| 223 | +.. code-block:: pycon |
| 224 | +
|
| 225 | + >>> print(precision, '\n', stingray, pretty=True) |
| 226 | + Bass(4, pickups='split coil P') '\n' Bass(5, pickups='humbucker', active=True) |
| 227 | +
|
| 228 | + >>> print(precision, stingray, sep='\n', pretty=True) |
| 229 | + Bass(4, pickups='split coil P') |
| 230 | + Bass(5, pickups='humbucker', active=True) |
| 231 | +
|
| 232 | +It's likely you'll want the second output, but more complicated multi-object displays could get even less |
| 233 | +convenient and/or more verbose. |
| 234 | + |
| 235 | + |
| 236 | +Acknowledgments |
| 237 | +=============== |
| 238 | + |
| 239 | +TBD |
| 240 | + |
| 241 | + |
| 242 | +Footnotes |
| 243 | +========= |
| 244 | + |
| 245 | +TBD |
| 246 | + |
| 247 | + |
| 248 | +Copyright |
| 249 | +========= |
| 250 | + |
| 251 | +This document is placed in the public domain or under the |
| 252 | +CC0-1.0-Universal license, whichever is more permissive. |
| 253 | + |
| 254 | + |
| 255 | +.. _rich-repr-protocol: https://rich.readthedocs.io/en/stable/pretty.html#rich-repr-protocol |
0 commit comments