Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Update the PEP to match the latest decisions, and reference implement…
…ation
  • Loading branch information
warsaw committed Dec 23, 2025
commit dfd56673c12e211c0fbb9a62b97b4efbe7cd45c7
123 changes: 83 additions & 40 deletions peps/pep-0813.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,23 @@ includes a class and APIs which users can invoke to format and print more readab
versus the standard ``repr()`` built-in function. Important use cases include pretty printing large
dictionaries and other complicated objects for debugging purposes.

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


Rationale
=========

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

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

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


Specification
Expand All @@ -52,33 +53,33 @@ There are several parts to this proposal.
``__pprint__()`` methods
------------------------

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

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

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

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

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

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


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

A custom ``__pprint__()`` method can be used to customize the representation of the object:
A custom ``__pprint__()`` method can be used to customize the representation of the object, such as with this
class:

.. code-block::
.. code-block:: python

>>> class Custom:
... def __str__(self): return 'my str'
... def __repr__(self): return 'my repr'
... def __pprint__(self, context, maxlevels, level):
... return 'my pprint', False, False
class Bass:
def __init__(self, strings: int, pickups: str, active: bool=False):
self._strings = strings
self._pickups = pickups
self._active = active

>>> pprint.pp(Custom())
my pprint
def __pprint__(self):
yield self._strings
yield 'pickups', self._pickups
yield 'active', self._active, False

Using the ``pretty`` argument to ``print()``:
Now let's create a couple of instances, and pretty print them:

.. code-block::
.. code-block:: pycon

>>> precision = Bass(4, 'split coil P', active=False)
>>> stingray = Bass(5, 'humbucker', active=True)

>>> pprint.pprint(precision)
Bass(4, pickups='split coil P')
>>> pprint.pprint(stingray)
Bass(5, pickups='humbucker', active=True)

Here's an example of using the ``pretty`` argument to built-in ``print()``:

.. code-block:: pycon

>>> import os
>>> print(os.pathconf_names)
{'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}

>>> print(os.pathconf_names, pretty=True)
{'PC_ALLOC_SIZE_MIN': 16,
'PC_ASYNC_IO': 17,
Expand Down Expand Up @@ -180,10 +197,36 @@ None at this time.
Open Issues
===========

TBD
The output format and APIs are heavily inspired by `Rich
<https://rich.readthedocs.io/en/latest/pretty.html#rich-repr-protocol>`_. The idea is that Rich could
implement an API compatible with ``print(..., pretty=RichPrinter)`` fairly easily. Rich's API is designed to
print constructor-like representations of instances, which means that it's not possible to control much of the
"class chrome" around the arguments. Rich does support using angle brackets (i.e. ``<...>``) instead of
parentheses by setting the attribute ``.angular=True`` on the rich repr method. This PEP does not support
that feature, although it likely could in the future.

This also means that there's no way to control the pretty printed format of built-in types like strings,
dicts, lists, etc. This seems fine as ``pprint`` is not intended to be as feature-rich (pun intended!) as
Rich. This PEP purposefully deems such fancy features as out-of-scope.

One consequence of ``print(..., pretty=True)`` is that it can be more less obvious if you wanted to print
multiple objects with, say a newline between the object representations. Compare these two outputs:

.. code-block:: pycon

>>> print(precision, '\n', stingray, pretty=True)
Bass(4, pickups='split coil P') '\n' Bass(5, pickups='humbucker', active=True)

>>> print(precision, stingray, sep='\n', pretty=True)
Bass(4, pickups='split coil P')
Bass(5, pickups='humbucker', active=True)

It's likely you'll want the second output, but more complicated multi-object displays could get even less
convenient and/or more verbose.


Acknowledgements
================
Acknowledgments
===============

TBD

Expand Down