From 424bf66f5a26a719d657c14fe5589082f6c5e867 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Fri, 23 Oct 2026 17:30:26 -0700 Subject: [PATCH 1/2] PEP 813: document the pretty print protocol Add a reference for the protocol to the pprint docs: Printer and Expand, the description stream vocabulary (the section markers, DELEGATE, Layout, Keyword, Entry, the marker classes and DescriptionType), decompose() and LEAF. Mark PrettyPrinter soft deprecated. Add object.__pprint__() to the data model reference. Describe !p in the f-string and format string docs, and add it to both grammars. Note the generated __pprint__() for dataclasses and named tuples. Add What's New entries for the protocol, the soft deprecation and PyObject_Pretty(). Co-Authored-By: Claude Opus 5.5 --- Doc/builtins/stdtypes.rst | 38 +++- Doc/library/collections.rst | 4 + Doc/library/dataclasses.rst | 11 + Doc/library/pprint.rst | 336 +++++++++++++++++++++++++++++ Doc/library/string.rst | 15 +- Doc/reference/datamodel.rst | 26 +++ Doc/reference/lexical_analysis.rst | 2 +- Doc/whatsnew/3.16.rst | 49 +++++ 8 files changed, 467 insertions(+), 14 deletions(-) diff --git a/Doc/builtins/stdtypes.rst b/Doc/builtins/stdtypes.rst index ef310348e74eb2..d85b47aa73146b 100644 --- a/Doc/builtins/stdtypes.rst +++ b/Doc/builtins/stdtypes.rst @@ -3242,15 +3242,6 @@ Each replacement field must contain an expression, optionally followed by: See the :ref:`Lexical Analysis section on f-strings ` for details on the syntax of these fields. -The ``!p`` conversion calls a printer with the value and joins the strings it -returns with newlines. Its format specifier is passed as the printer without -converting a replacement field to a string. The format specifier must be a -single replacement field whose value is callable. If it is omitted or empty, -a default printer is used. The default printer calls ``__pprint__()`` when -available and interprets its iterable as a description of the object's layout -and contents. If the method is absent, the default printer falls back to -:func:`repr`. - Debug specifier ^^^^^^^^^^^^^^^ @@ -3294,6 +3285,7 @@ The conversion can be specified explicitly using one of these specifiers: * ``!s`` for :func:`str` * ``!r`` for :func:`repr` * ``!a`` for :func:`ascii` +* ``!p`` for pretty printing, described below For example:: @@ -3312,6 +3304,34 @@ For example:: >>> f'{string = !a}' "string = '\\xa1ko\\u010dka \\U0001f638!'" +The ``!p`` conversion pretty prints the value with :class:`pprint.Printer`, +which uses the value's :meth:`~object.__pprint__` method (see +:ref:`pprint-protocol`). Unlike the other conversions, its format specifier +names the printer to use. It must be empty, or a single replacement field +with no conversion or format specifier of its own, whose value is called with +the value to print. The replacement field is not converted to a string. If +the specifier is empty or omitted, or its value is ``None``, the default +printer is used. The printer returns the lines of the pretty printed form, +which are joined with newlines, without a trailing newline: + +.. code-block:: pycon + :force: + + >>> import pprint + >>> basses = {'stingray': ['B', 'E', 'A', 'D', 'G'], 'jazz': ['E', 'A', 'D', 'G']} + >>> print(f'{basses!p:{pprint.Printer(width=50)}}') + { + 'jazz': ['E', 'A', 'D', 'G'], + 'stingray': ['B', 'E', 'A', 'D', 'G'], + } + +Any other format specifier after ``!p``, such as ``f'{basses!p:>40}'``, is a +:exc:`SyntaxError`. :exc:`TypeError` is raised if the printer returns a +:class:`str`, or if any line is not a :class:`str`. + +.. versionchanged:: next + Added the ``!p`` conversion. + Format specifier ^^^^^^^^^^^^^^^^ diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst index 40f780c7d049d4..311944132b5eb6 100644 --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -927,6 +927,10 @@ they add the ability to access fields by name instead of position index. Added the *defaults* parameter and the :attr:`~somenamedtuple._field_defaults` attribute. + .. versionchanged:: next + Named tuples have a :meth:`~object.__pprint__` method, so a + :class:`pprint.Printer` can wrap their fields to fit its width. + .. doctest:: :options: +NORMALIZE_WHITESPACE diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst index ec8c913072487a..a46eb2756330fd 100644 --- a/Doc/library/dataclasses.rst +++ b/Doc/library/dataclasses.rst @@ -99,6 +99,17 @@ Module contents If the class already defines :meth:`!__repr__`, this parameter is ignored. + When a :meth:`!__repr__` method is generated, a + :meth:`~object.__pprint__` method is generated too, unless the class + already defines one. It describes the same fields as the generated + repr, so a :class:`pprint.Printer` can wrap them to fit its width. If + the class defines its own :meth:`!__repr__`, no :meth:`!__pprint__` is + generated, and the hand-written repr is used for pretty printing too. + + .. versionchanged:: next + A :meth:`~object.__pprint__` method is generated with + :meth:`!__repr__`. + - *eq*: If true (the default), an :meth:`~object.__eq__` method will be generated. diff --git a/Doc/library/pprint.rst b/Doc/library/pprint.rst index 4f043fbb3a46df..b80f121894cd69 100644 --- a/Doc/library/pprint.rst +++ b/Doc/library/pprint.rst @@ -19,6 +19,10 @@ The formatted representation keeps objects on a single line if it can, and breaks them onto multiple lines if they don't fit within the allowed width, adjustable by the *width* parameter defaulting to 80 characters. +Classes can describe how their instances are pretty printed with a +:meth:`~object.__pprint__` method, and the :class:`Printer` class lays out +those descriptions. See :ref:`pprint-protocol` for details. + .. versionchanged:: 3.9 Added support for pretty-printing :class:`types.SimpleNamespace`. @@ -223,6 +227,11 @@ PrettyPrinter Objects .. versionchanged:: 3.15 Added the *expand* parameter. + .. soft-deprecated:: next + No new features will be added to :class:`!PrettyPrinter`. New code + should use :class:`Printer`, which supports the + :ref:`pretty print protocol `. + :class:`PrettyPrinter` instances have the following methods: @@ -514,3 +523,330 @@ Best results are achieved with a higher *indent* value:: 'yanked': False, 'yanked_reason': None, } + + +.. _pprint-protocol: + +The pretty print protocol +------------------------- + +.. versionadded:: next + +A class describes the pretty printed form of its instances with a +:meth:`~object.__pprint__` method. The method yields a *description stream*: +the object's items, optionally preceded by a :class:`Layout` and separated into +sections by the :data:`VALUES`, :data:`KWARGS` and :data:`ITEMS` markers. A +*printer* interprets the stream and decides where the line breaks go, so the +method never handles layout itself. + +For example: + +.. code-block:: pycon + :force: + + >>> import pprint + >>> class Bass: + ... def __init__(self, model, strings=4, tuning=('E', 'A', 'D', 'G')): + ... self.model = model + ... self.strings = strings + ... self.tuning = tuning + ... + ... def __pprint__(self): + ... yield self.model + ... yield pprint.KWARGS + ... yield 'strings', self.strings, 4 + ... yield 'tuning', self.tuning, ('E', 'A', 'D', 'G') + ... + >>> print(f'{Bass("jazz")!p}') + Bass('jazz') + >>> stingray = Bass('stingray', 5, ('B', 'E', 'A', 'D', 'G')) + >>> print(f'{stingray!p}') + Bass('stingray', strings=5, tuning=('B', 'E', 'A', 'D', 'G')) + >>> for line in pprint.Printer(width=30)(stingray): + ... print(line) + ... + Bass( + 'stingray', + strings=5, + tuning=( + 'B', + 'E', + 'A', + 'D', + 'G', + ), + ) + +Keyword items whose value equals their default are omitted. The ``!p`` +conversion in :ref:`f-strings ` and :meth:`str.format` pretty prints +a value with the default printer, or with a printer given as +``f'{obj!p:{printer}}'``. + +A *printer* is any callable that takes the object to print as its only +argument and returns an iterable of strings, one for each line of output, +without line endings. The built-in and standard library types implement +:meth:`~object.__pprint__`, as do classes made by :func:`dataclasses.dataclass` +and :func:`collections.namedtuple`. An object without a usable +:meth:`~object.__pprint__` is printed with :func:`repr`. + + +Printers +^^^^^^^^ + +.. class:: Printer(indent=4, width=78, depth=None, *, compact=False, \ + expand=Expand.FIT, sort_dicts=True, number_format=None) + + The default printer. Calling an instance with an object returns an + iterable of the lines of its pretty printed form. + + The arguments have the same meanings as for :class:`PrettyPrinter`, with + these differences: + + * *expand* takes a member of :class:`Expand`. + * *compact* packs positional items onto as few lines as possible with every + *expand* mode. An item that does not fit on one line gets lines of its + own, and with :attr:`Expand.ALWAYS` a non-empty container is never packed. + * *number_format* replaces *underscore_numbers*. It is a + :ref:`format specification ` that is passed to :func:`format` + for each :class:`FormattableNumber`, which includes every :class:`int` and + :class:`float`. For example, ``'_'`` groups digits as + ``underscore_numbers=True`` does, and ``','`` groups them with commas. If + :func:`format` raises an exception, or *number_format* is ``None``, the + number is printed with :func:`repr`. + * There is no *stream* argument, since a printer returns its lines. + + The default *width* of 78 keeps the output within the line length that + :pep:`8` recommends. + + The printer calls :func:`decompose` on every object it prints, including + each item, key and value, so nested objects wrap inside their containers at + any depth. When *sort_dicts* is true, the items of an object whose + :class:`Layout` is :attr:`~Layout.sortable` are sorted: key/value items by + key, positional items by value, and keyword items by name, after the others. + Items that cannot be compared with each other are sorted by their one-line + pretty printed form. + + :: + + >>> stuff = {'stingray': ['B', 'E', 'A', 'D', 'G'], + ... 'precision': ['E', 'A', 'D', 'G'], 'jazz': 1234567.5} + >>> for line in pprint.Printer(width=40, number_format=',')(stuff): + ... print(line) + ... + { + 'jazz': 1,234,567.5, + 'precision': ['E', 'A', 'D', 'G'], + 'stingray': [ + 'B', + 'E', + 'A', + 'D', + 'G', + ], + } + + .. versionadded:: next + + +.. class:: Expand + + An :class:`~enum.Enum` of the ways a :class:`Printer` lays out a container + that does not fit on one line. In every mode, an object that fits on one + line is printed on one line. + + .. attribute:: NEVER + + The items follow the open bracket and are aligned under it, as + :class:`PrettyPrinter` lays them out by default. *indent* is used only + for a value that starts on the line after a wrapped key. + + .. attribute:: FIT + + Each item is on its own line, indented by *indent*, with a trailing + separator, and the close bracket is on a line of its own. A nested + container is laid out this way only if it does not fit on one line + itself. This is the default. + + .. attribute:: ALWAYS + + The same as :attr:`FIT`, except that once a container does not fit, + every non-empty container inside it is laid out this way too. + + .. versionadded:: next + + +The description stream +^^^^^^^^^^^^^^^^^^^^^^ + +The items that a :meth:`~object.__pprint__` method yields are read in +sections. The stream starts in the :data:`VALUES` section, and a section +marker changes how the items that follow it are read, until the next marker. +Markers may appear in any order, any number of times, and items are printed in +the order they are yielded. + +.. data:: VALUES + + Each item that follows is a positional value, printed as ``value``. Tuples + are values too. + +.. data:: KWARGS + + Each item that follows is a ``(name, value)`` or ``(name, value, default)`` + tuple, printed as ``name=value``. *name* is a :class:`str`, printed as is. + An item is omitted when ``value == default`` is true. If that comparison + raises an exception, the item is shown with a placeholder, such as + ``arr=``. + +.. data:: ITEMS + + Each item that follows is a ``(key, value)`` tuple, printed as + ``key: value``. The key is pretty printed like any other value. + +.. data:: DELEGATE + + When it is the first item in the stream, the next item is printed in place + of the object. For example, :class:`collections.UserDict` delegates to its + underlying :class:`dict`. + +The section markers, :data:`DELEGATE` and :data:`LEAF` are :class:`sentinel` +objects. + +The default printer reads the stream permissively. An item that does not fit +its section, such as a 4-tuple under :data:`KWARGS`, is a value. Any object +that is not part of this vocabulary is a value too, so a marker that only +another printer understands is printed with its :func:`repr`. A +:class:`Layout` or :data:`DELEGATE` that is not the first item is a value. The +printer does not check that its output is valid Python. + +.. class:: Layout(*, name=None, open=None, close=None, sep=',', empty=None, \ + single_close=None, recursion='...', sortable=False, \ + hug=False, hints=None) + + Describes an object's *chrome*: the name and brackets around its items, the + separator between them, and a few special cases. A + :meth:`~object.__pprint__` method sets the chrome of its object by yielding + a :class:`!Layout` as the first item of the stream. All of the arguments + are optional, and are available as attributes of the same names. + + *name* is used in the default brackets, and is ``type(obj).__name__`` when + not given. *open* and *close* are the text before and after the items. + By default, the object is printed as its name followed by the items in + parentheses, or in ``({...})`` when every item is a key/value item, as in + ``Counter({'a': 1})``. + + *sep* is the separator between items. When the items fit on one line, a + space follows each separator. + + *empty* is the text printed when there are no items, *open* followed by + *close* by default. *single_close* replaces *close* when there is exactly + one item, as in the ``',)'`` of a one-element tuple. *recursion* is printed + for a reference cycle back to the object. + + .. attribute:: sortable + + Whether a printer may sort the items, because their order is not + significant. + + .. attribute:: hug + + Whether a printer keeps the other items on the opening and closing lines + when exactly one item is a container that does not fit. It affects + :attr:`Expand.FIT` and :attr:`Expand.ALWAYS`. For example, + :class:`collections.defaultdict` sets it, so that it prints as: + + .. code-block:: text + + defaultdict(, { + 'precision': ['E', 'A', 'D', 'G'], + 'stingray': ['B', 'E', 'A', 'D', 'G'], + }) + + .. attribute:: hints + + A mapping of hints for particular printers. By convention, each key + names the printer that reads it, as in ``'html.role'``. The default + printer ignores them. + + .. versionadded:: next + +.. class:: Keyword(name, value, default=) + + A keyword item, printed as ``name=value``, and omitted when *value* equals + *default*. It can be yielded in any section. + + .. versionadded:: next + +.. class:: Entry(key, value) + + A key/value item, printed as ``key: value``. It can be yielded in any + section. + + .. versionadded:: next + +.. class:: BreakableString(value) + BreakableBytes(value) + + A :class:`str` or :class:`bytes` value that a printer may split across + lines. The default printer prints its :func:`repr`, split into adjacent + literals to fit the width. :class:`str` and :class:`bytes` describe + themselves by delegating to these, and any other class can yield them to + get a wrappable string. + + .. versionadded:: next + +.. class:: FormattableNumber(value) + + A number that a printer may format. The default printer formats it with + its *number_format* option. :class:`int` and :class:`float` describe + themselves by delegating to it. + + .. versionadded:: next + +.. type:: DescriptionType + + A type alias for the result of a :meth:`~object.__pprint__` method, defined + as ``type DescriptionType = Iterable[object]``. + + .. versionadded:: next + + +Decomposing objects +^^^^^^^^^^^^^^^^^^^ + +.. function:: decompose(obj) + + Find the usable :meth:`~object.__pprint__` method of ``type(obj)``, run it, + and read one level of its stream. Return a 2-tuple: + + * ``(LEAF, None)`` if *obj* is a leaf, whose type has no usable + :meth:`~object.__pprint__` method. + * ``(DELEGATE, value)`` if the object delegates to *value*. + * Otherwise, a :class:`Layout` with every attribute filled in, and a list of + items, each a plain value, a :class:`Keyword` or an :class:`Entry`. + Keyword items equal to their defaults are removed, and the section + markers do not appear. + + :func:`!decompose` does not recurse into the items, and does not depend on + any printer setting. Other printers can call it to read a stream the same + way the default printer does:: + + >>> layout, items = pprint.decompose({'a': 1}) + >>> layout.open, layout.close, layout.sortable + ('{', '}', True) + >>> items + [Entry(key='a', value=1)] + >>> pprint.decompose(42) + (pprint.DELEGATE, FormattableNumber(42)) + >>> pprint.decompose(object()) + (pprint.LEAF, None) + + .. versionadded:: next + +.. data:: LEAF + + Returned by :func:`decompose` for an object whose type has no usable + :meth:`~object.__pprint__` method, including the marker classes + :class:`BreakableString`, :class:`BreakableBytes` and + :class:`FormattableNumber`. It is not part of the stream vocabulary. + + .. versionadded:: next diff --git a/Doc/library/string.rst b/Doc/library/string.rst index f1abed91d20ed5..ca8fb2481509bc 100644 --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -223,7 +223,7 @@ The grammar for a replacement field is as follows: attribute_name: `~python-grammar:identifier` element_index: `~python-grammar:digit`+ | `index_string` index_string: + - conversion: "r" | "s" | "a" + conversion: "r" | "s" | "a" | "p" format_spec: `format-spec:format_spec` In less formal terms, the replacement field can start with a *field_name* that specifies @@ -274,15 +274,22 @@ as a string, overriding its own definition of formatting. By converting the value to a string before calling :meth:`~object.__format__`, the normal formatting logic is bypassed. -Three conversion flags are currently supported: ``'!s'`` which calls :func:`str` -on the value, ``'!r'`` which calls :func:`repr` and ``'!a'`` which calls -:func:`ascii`. +Four conversion flags are currently supported: ``'!s'`` which calls :func:`str` +on the value, ``'!r'`` which calls :func:`repr`, ``'!a'`` which calls +:func:`ascii`, and ``'!p'`` which pretty prints the value with +:class:`pprint.Printer` (see :ref:`pprint-protocol`). As with the other +conversions, a *format_spec* after ``'!p'`` is applied to the pretty printed +string. Some examples:: "Harold's a clever {0!s}" # Calls str() on the argument first "Bring out the holy {name!r}" # Calls repr() on the argument first "More {!a}" # Calls ascii() on the argument first + "Pretty {!p}" # Pretty prints the argument first + +.. versionchanged:: next + Added the ``'!p'`` conversion. The *format_spec* field contains a specification of how the value should be presented, including such details as field width, alignment, padding, decimal diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index d2089724fa2957..1c7b2a5b3dd771 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -2172,6 +2172,32 @@ Basic customization than ``format(str(x), '')``. +.. method:: object.__pprint__(self) + + .. index:: + single: pretty printing + pair: module; pprint + + Called by :class:`pprint.Printer`, and so by the ``!p`` conversion in + :ref:`formatted string literals ` and :meth:`str.format`, to + describe the pretty printed form of an object. It returns an iterable, + usually by being a generator, of the object's items, optionally preceded by + a :class:`pprint.Layout` and divided into sections by + :data:`pprint.VALUES`, :data:`pprint.KWARGS` and :data:`pprint.ITEMS`. The + method describes the object's structure, and the printer decides how to lay + it out. See :ref:`pprint-protocol` for the full description. + + The method is optional, and :class:`object` does not define it. Without + it, printers use :meth:`__repr__`. An inherited :meth:`!__pprint__` is + used only if the class that provides it comes no later in the + :term:`method resolution order` than the class that provides + :meth:`__repr__`. So a subclass that overrides :meth:`__repr__` is printed + with its own :func:`repr` unless it also provides :meth:`!__pprint__`, for + example with ``__pprint__ = dict.__pprint__``. + + .. versionadded:: next + + .. _richcmpfuncs: .. method:: object.__lt__(self, other) object.__le__(self, other) diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst index 8779905c17a0e5..40427456cd3bfd 100644 --- a/Doc/reference/lexical_analysis.rst +++ b/Doc/reference/lexical_analysis.rst @@ -1270,7 +1270,7 @@ sequences (``f_quote``). | '{' `f_expression` [`f_debug_specifier`] [`fstring_conversion`] [`fstring_full_format_spec`] '}' fstring_conversion: - | "!" ("s" | "r" | "a") + | "!" ("s" | "r" | "a" | "p") fstring_full_format_spec: | ':' `fstring_format_spec`* fstring_format_spec: diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index 58f129bedcb371..d7c2d4d5476e1f 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -62,11 +62,50 @@ Summary -- Release highlights .. This section singles out the most important changes in Python 3.16. Brevity is key. +* :ref:`PEP 813: The pretty print protocol ` New features ============ +.. _whatsnew316-pep813: + +:pep:`813`: The pretty print protocol +------------------------------------- + +Classes can now describe the pretty printed form of their instances with a +:meth:`~object.__pprint__` method. The method yields the object's items, and +a printer decides how to lay them out:: + + import pprint + + class Bass: + def __init__(self, model, strings=4): + self.model = model + self.strings = strings + + def __pprint__(self): + yield self.model + yield pprint.KWARGS + yield 'strings', self.strings, 4 + +The new ``!p`` conversion pretty prints a value in :ref:`f-strings ` +and :meth:`str.format`, and an f-string can name the printer to use, as in +``f'{obj!p:{printer}}'``. T-strings record ``!p`` and its printer in the new +:attr:`Interpolation.printer ` +attribute. + +The new :class:`pprint.Printer` class is the default printer. Its defaults of +``width=78``, ``indent=4`` and ``expand=pprint.Expand.FIT`` give output close to +code formatted by tools such as Black and Ruff. The built-in and standard +library types, :func:`dataclasses.dataclass` classes and +:func:`collections.namedtuple` classes implement :meth:`!__pprint__`. +:class:`pprint.PrettyPrinter` is unchanged, and is now :term:`soft deprecated`. + +See :ref:`pprint-protocol` and :pep:`813` for details. + +(Contributed by Eric V. Smith and Barry Warsaw.) + Other language changes @@ -1029,6 +1068,12 @@ Deprecated New deprecations ---------------- +* :mod:`pprint`: + + * :class:`pprint.PrettyPrinter` is now :term:`soft deprecated`. It is not + scheduled for removal, but no new features will be added to it. Use + :class:`pprint.Printer` instead. (:pep:`813`.) + * :mod:`abc`: * :class:`abc.abstractclassmethod`, :class:`abc.abstractstaticmethod`, @@ -1202,6 +1247,10 @@ New features API. (Contributed by Nathan Goldbaum and Victor Stinner in :gh:`158842`.) +* Add :c:func:`PyObject_Pretty` to the limited C API, the function behind the + new ``!p`` conversion. See :pep:`813`. + (Contributed by Eric V. Smith.) + Porting to Python 3.16 ---------------------- From 17d709909503658b075a8b3422312875832a31d1 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Fri, 23 Oct 2026 17:31:21 -0700 Subject: [PATCH 2/2] PEP 813: add NEWS entries and link gh-145153 Add Library, Core and Builtins, and C API NEWS entries for the pretty print protocol, and reference gh-145153 in the What's New entries. Co-Authored-By: Claude Opus 5.5 --- Doc/whatsnew/3.16.rst | 7 ++++--- .../C_API/2026-10-24-00-31-06.gh-issue-145153.ZOfz7Q.rst | 2 ++ .../2026-10-24-00-31-05.gh-issue-145153.ScrlRw.rst | 3 +++ .../Library/2026-10-24-00-31-04.gh-issue-145153.ERgzDw.rst | 6 ++++++ 4 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/C_API/2026-10-24-00-31-06.gh-issue-145153.ZOfz7Q.rst create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-10-24-00-31-05.gh-issue-145153.ScrlRw.rst create mode 100644 Misc/NEWS.d/next/Library/2026-10-24-00-31-04.gh-issue-145153.ERgzDw.rst diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index d7c2d4d5476e1f..2a5ba2215467c5 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -104,7 +104,7 @@ library types, :func:`dataclasses.dataclass` classes and See :ref:`pprint-protocol` and :pep:`813` for details. -(Contributed by Eric V. Smith and Barry Warsaw.) +(Contributed by Eric V. Smith and Barry Warsaw in :gh:`145153`.) @@ -1072,7 +1072,8 @@ New deprecations * :class:`pprint.PrettyPrinter` is now :term:`soft deprecated`. It is not scheduled for removal, but no new features will be added to it. Use - :class:`pprint.Printer` instead. (:pep:`813`.) + :class:`pprint.Printer` instead. + (Contributed by Barry Warsaw and Eric V. Smith in :gh:`145153`.) * :mod:`abc`: @@ -1249,7 +1250,7 @@ New features * Add :c:func:`PyObject_Pretty` to the limited C API, the function behind the new ``!p`` conversion. See :pep:`813`. - (Contributed by Eric V. Smith.) + (Contributed by Eric V. Smith in :gh:`145153`.) Porting to Python 3.16 ---------------------- diff --git a/Misc/NEWS.d/next/C_API/2026-10-24-00-31-06.gh-issue-145153.ZOfz7Q.rst b/Misc/NEWS.d/next/C_API/2026-10-24-00-31-06.gh-issue-145153.ZOfz7Q.rst new file mode 100644 index 00000000000000..17fc95191de9e4 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2026-10-24-00-31-06.gh-issue-145153.ZOfz7Q.rst @@ -0,0 +1,2 @@ +Add :c:func:`PyObject_Pretty` to the limited C API, the function behind the +``!p`` conversion of :pep:`813`. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-10-24-00-31-05.gh-issue-145153.ScrlRw.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-24-00-31-05.gh-issue-145153.ScrlRw.rst new file mode 100644 index 00000000000000..e24251179aa5f0 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-24-00-31-05.gh-issue-145153.ScrlRw.rst @@ -0,0 +1,3 @@ +Add the ``!p`` conversion of :pep:`813` to f-strings, t-strings and +:meth:`str.format`. It pretty prints a value with :class:`pprint.Printer`, +and an f-string can name the printer to use, as in ``f'{obj!p:{printer}}'``. diff --git a/Misc/NEWS.d/next/Library/2026-10-24-00-31-04.gh-issue-145153.ERgzDw.rst b/Misc/NEWS.d/next/Library/2026-10-24-00-31-04.gh-issue-145153.ERgzDw.rst new file mode 100644 index 00000000000000..488ededfef473f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-10-24-00-31-04.gh-issue-145153.ERgzDw.rst @@ -0,0 +1,6 @@ +Add the pretty print protocol of :pep:`813`. Classes can describe their +pretty printed form with a :meth:`~object.__pprint__` method, and the new +:class:`pprint.Printer` class lays out those descriptions. The built-in and +standard library types, :func:`dataclasses.dataclass` classes and +:func:`collections.namedtuple` classes implement :meth:`!__pprint__`. +:class:`pprint.PrettyPrinter` is now :term:`soft deprecated`.