diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 269770261b8..f99fc66b933 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -687,6 +687,7 @@ peps/pep-0808.rst @FFY00 peps/pep-0809.rst @zooba peps/pep-0810.rst @pablogsal @DinoV @Yhg1s peps/pep-0811.rst @sethmlarson @gpshead +peps/pep-0813.rst @warsaw @ericvsmith peps/pep-0814.rst @vstinner @corona10 # ... peps/pep-2026.rst @hugovk diff --git a/peps/pep-0813.rst b/peps/pep-0813.rst new file mode 100644 index 00000000000..5da5a6e8bd3 --- /dev/null +++ b/peps/pep-0813.rst @@ -0,0 +1,201 @@ +PEP: 813 +Title: The Pretty Print Protocol +Author: Barry Warsaw , Eric V. Smith +Discussions-To: Pending +Status: Draft +Type: Standards Track +Created: 07-Nov-2025 +Python-Version: 3.15 +Post-History: Pending + + +Abstract +======== + +This PEP describes the "pretty print protocol", a collection of changes proposed to make pretty printing more +customizable and convenient. + + +Motivation +========== + +"Pretty printing" is a feature which provides a capability to format object representations for better +readability. The core functionality is implemented by the standard library :mod:`pprint` module. ``pprint`` +includes a class and APIs which users can invoke to format and print more readable representations of objects, +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. + + +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. + +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. + +These two extensions work independently, but hand-in-hand can provide a powerful and convenient new feature. + + +Specification +============= + +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 +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: + +* ``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 + +Similarly, ``__pprint__()`` returns three values: + +* 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. + +See :py:meth:`python:pprint.PrettyPrinter.format` for details. + + +A new argument to built-in ``print`` +------------------------------------ + +Built-in :func:`print` takes a new optional argument, appended to the end of the argument list, called +``pretty``, which can take one of the following values: + +* ``None`` - the default. No pretty printing is invoked. Fully backward compatible. +* ``True`` - use a temporary instance of the :py:class:`python:pprint.PrettyPrinter` class to get a + pretty representation of the object. +* An instance with a ``pformat()`` method, which has the same signature as + :py:meth:`python:pprint.PrettyPrinter.pformat`. When given, this will usually be an instance of a + subclass of ``PrettyPrinter`` with its ``pformat()`` method overridden. Note that this form + requires **an instance** of a pretty printer, not a class, as only ``print(..., pretty=True)`` + performs implicit instantiation. + + +Examples +======== + +A custom ``__pprint__()`` method can be used to customize the representation of the object: + +.. code-block:: + + >>> 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 + + >>> pprint.pp(Custom()) + my pprint + +Using the ``pretty`` argument to ``print()``: + +.. code-block:: + + >>> 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, + 'PC_CHOWN_RESTRICTED': 7, + 'PC_FILESIZEBITS': 18, + 'PC_LINK_MAX': 1, + 'PC_MAX_CANON': 2, + 'PC_MAX_INPUT': 3, + 'PC_MIN_HOLE_SIZE': 27, + 'PC_NAME_MAX': 4, + 'PC_NO_TRUNC': 8, + 'PC_PATH_MAX': 5, + 'PC_PIPE_BUF': 6, + 'PC_PRIO_IO': 19, + '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, + 'PC_SYNC_IO': 25, + 'PC_VDISABLE': 9} + + +Backwards Compatibility +======================= + +When none of the new features are used, this PEP is fully backward compatible, both for built-in +``print()`` and the ``pprint`` module. + + +Security Implications +===================== + +There are no known security implications for this proposal. + + +How to Teach This +================= + +Documentation and examples are added to the ``pprint`` module and the ``print()`` function. +Beginners don't need to be taught these new features until they want prettier representations of +their objects. + + +Reference Implementation +======================== + +The reference implementation is currently available as a `PEP author branch of the CPython main +branch `__. + + +Rejected Ideas +============== + +None at this time. + + +Open Issues +=========== + +TBD + +Acknowledgements +================ + +TBD + + +Footnotes +========= + +TBD + + +Copyright +========= + +This document is placed in the public domain or under the +CC0-1.0-Universal license, whichever is more permissive.