From f519d3492c189c2480cd5d7880ce197e3484ec04 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Sat, 21 Feb 2026 19:10:02 -0800 Subject: [PATCH 01/10] Address feedback so far in the DPO thread --- peps/pep-0813.rst | 80 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 71 insertions(+), 9 deletions(-) diff --git a/peps/pep-0813.rst b/peps/pep-0813.rst index f582710c0ed..75240c8e20f 100644 --- a/peps/pep-0813.rst +++ b/peps/pep-0813.rst @@ -71,7 +71,9 @@ keyword, and default arguments. The values can be any of the following formats: * 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. + ``name=value`` is used. If ``name`` is ``None`` or the empty string, then ``value`` is treated as a + positional argument. This is how you would print a positional argument with a tuple value. See + :ref:`examples`. * 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. @@ -85,8 +87,8 @@ keyword, and default arguments. The values can be any of the following formats: 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: +Built-in :func:`print` gains a new optional keyword-only argument 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 @@ -106,6 +108,8 @@ will be added. The effect of this specifier with an expression ``value`` will b :py:func:`python:pprint.pformat`, passing ``value`` as the only argument. In this initial specification, it will be an error to provide any format specifier if ``!p`` is used. +.. _examples: + Examples ======== @@ -167,6 +171,21 @@ Here's an example of using the ``pretty`` argument to built-in ``print()``: 'PC_SYNC_IO': 25, 'PC_VDISABLE': 9} +Here's an example where a positional argument has a tuple value. In this case, you use the 2-tuple format, +with the ``name`` being ``None`` or the empty string. + +.. code-block:: pycon + + >>> class Things: + ... def __pprint__(self): + ... yield (None, (1, 2)) + ... yield ('', (3, 4)) + ... yield ('arg', (5, 6)) + ... + >>> from rich.pretty import pprint + >>> pprint(Things()) +Things((1, 2), (3, 4), arg=(5, 6)) + Backwards Compatibility ======================= @@ -205,13 +224,18 @@ None at this time. Open Issues =========== +Rich compatibility +------------------ + The output format and APIs are heavily inspired by `Rich -`_. 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. +`_. 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 @@ -232,6 +256,32 @@ multiple objects with, say a newline between the object representations. Compar It's likely you'll want the second output, but more complicated multi-object displays could get even less convenient and/or more verbose. +print's pretty argument could just take a callable +-------------------------------------------------- + +There was [a suggestion](https://discuss.python.org/t/pep-813-the-pretty-print-protocol/106242/2) in the DPO +thread that the third form of ``print(..., pretty=not_none_or_true)`` could generalize to any +callable taking a single argument, rather than requiring it to be an instance with a +``pformat()``-compatible method. We don't need both, but the suggested generalization could be useful. I.e. + +.. code-block:: python + + pprint(myobj, pretty=MyPrinter()) + +vs. + +.. code-block:: python + + pprint(myobj, pretty=MyPrinter().pformat) + + +Deferred Ideas +============== + +Possibly add support for ``!p`` conversions to t-strings. + +``!p`` conversions could include format specifiers. + Acknowledgments =============== @@ -245,6 +295,18 @@ Footnotes TBD +Change History +============== + +* `TBD `__ + + * Specify that to pretty print tuples as positional arguments, use the 2-tuple value format, passing + ``None`` or the empty string as the argument name. + * Specify that the ``!p`` conversion in f-strings and ``str.format()`` implicitly perform an + import of the ``pprint`` module. + * Clarify the language around the new optional keyword-only argument ``pretty`` to ``print()``. + + Copyright ========= From 39ce8b3ad4c4551981d3c95a3b5c1fac49a05141 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Sat, 21 Feb 2026 19:14:31 -0800 Subject: [PATCH 02/10] Fix the indentation --- peps/pep-0813.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/peps/pep-0813.rst b/peps/pep-0813.rst index 75240c8e20f..25509824254 100644 --- a/peps/pep-0813.rst +++ b/peps/pep-0813.rst @@ -1,4 +1,4 @@ -PEP: 813 +813: PEP Title: The Pretty Print Protocol Author: Barry Warsaw , Eric V. Smith Discussions-To: https://discuss.python.org/t/pep-813-the-pretty-print-protocol/106242 @@ -184,7 +184,7 @@ with the ``name`` being ``None`` or the empty string. ... >>> from rich.pretty import pprint >>> pprint(Things()) -Things((1, 2), (3, 4), arg=(5, 6)) + Things((1, 2), (3, 4), arg=(5, 6)) Backwards Compatibility From 842d3250f207d7502418cc2b91b4776958fe7fc7 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Sat, 21 Feb 2026 19:23:39 -0800 Subject: [PATCH 03/10] How'd that happen? --- peps/pep-0813.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/peps/pep-0813.rst b/peps/pep-0813.rst index 25509824254..5a7959d8c59 100644 --- a/peps/pep-0813.rst +++ b/peps/pep-0813.rst @@ -1,4 +1,4 @@ -813: PEP +PEP: 813 Title: The Pretty Print Protocol Author: Barry Warsaw , Eric V. Smith Discussions-To: https://discuss.python.org/t/pep-813-the-pretty-print-protocol/106242 From dbbe148039394310562f70a3d89e6fe4049e6ef4 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Sun, 22 Feb 2026 18:52:39 -0800 Subject: [PATCH 04/10] Rich treats any false-y name in the 2-tuple form as a positional argument --- peps/pep-0813.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/peps/pep-0813.rst b/peps/pep-0813.rst index 5a7959d8c59..de14f1c9b43 100644 --- a/peps/pep-0813.rst +++ b/peps/pep-0813.rst @@ -70,10 +70,10 @@ class name. The printed representation will usually look like a class construct keyword, and default arguments. The values can be any of the following formats: * 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. If ``name`` is ``None`` or the empty string, then ``value`` is treated as a - positional argument. This is how you would print a positional argument with a tuple value. See - :ref:`examples`. +* A 2-tuple of ``(name, value)`` representing a keyword argument. A + representation of ``name=value`` is used. If ``name`` is "false-y", then + ``value`` is treated as a positional argument. This is how you would print + a positional argument with a tuple value. See :ref:`examples`. * 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. @@ -172,7 +172,7 @@ Here's an example of using the ``pretty`` argument to built-in ``print()``: 'PC_VDISABLE': 9} Here's an example where a positional argument has a tuple value. In this case, you use the 2-tuple format, -with the ``name`` being ``None`` or the empty string. +with the ``name`` being "false-y". .. code-block:: pycon @@ -301,7 +301,7 @@ Change History * `TBD `__ * Specify that to pretty print tuples as positional arguments, use the 2-tuple value format, passing - ``None`` or the empty string as the argument name. + a "false-y" value as the argument name. * Specify that the ``!p`` conversion in f-strings and ``str.format()`` implicitly perform an import of the ``pprint`` module. * Clarify the language around the new optional keyword-only argument ``pretty`` to ``print()``. From 1dc78572afe51a10b495db2611bd8cd29fc24b94 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Sun, 22 Feb 2026 19:05:20 -0800 Subject: [PATCH 05/10] Describe the new PyObject_Pretty() function --- peps/pep-0813.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/peps/pep-0813.rst b/peps/pep-0813.rst index de14f1c9b43..d25d73c12ea 100644 --- a/peps/pep-0813.rst +++ b/peps/pep-0813.rst @@ -108,6 +108,15 @@ will be added. The effect of this specifier with an expression ``value`` will b :py:func:`python:pprint.pformat`, passing ``value`` as the only argument. In this initial specification, it will be an error to provide any format specifier if ``!p`` is used. +Additions to the C-API +---------------------- + +To support ``!p``, a new function, ``PyObject_Pretty()`` is added to the +`Limited C API `_. +This function takes a single ``PyObject *``, the object to pretty print. This +function imports the ``pprint`` module and calls :func:`pprint.pformat` with +this object as its argument, returning the results. + .. _examples: Examples @@ -305,6 +314,7 @@ Change History * Specify that the ``!p`` conversion in f-strings and ``str.format()`` implicitly perform an import of the ``pprint`` module. * Clarify the language around the new optional keyword-only argument ``pretty`` to ``print()``. + * Describe the new Limited C API function ``PyObject_Pretty()``. Copyright From 332c4d7a626e051d999ae81e59e77da7e4201608 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Mon, 23 Feb 2026 16:32:10 -0800 Subject: [PATCH 06/10] Clarify `name` must be a `str` --- peps/pep-0813.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/peps/pep-0813.rst b/peps/pep-0813.rst index d25d73c12ea..6d5937e16d5 100644 --- a/peps/pep-0813.rst +++ b/peps/pep-0813.rst @@ -73,7 +73,8 @@ keyword, and default arguments. The values can be any of the following formats: * A 2-tuple of ``(name, value)`` representing a keyword argument. A representation of ``name=value`` is used. If ``name`` is "false-y", then ``value`` is treated as a positional argument. This is how you would print - a positional argument with a tuple value. See :ref:`examples`. + a positional argument with a tuple value. See :ref:`examples`. Otherwise, + ``name`` **MUST** exactly be a ``str``. * 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. @@ -311,6 +312,7 @@ Change History * Specify that to pretty print tuples as positional arguments, use the 2-tuple value format, passing a "false-y" value as the argument name. + * Clarify that a truth-y ``name`` must be a ``str``. * Specify that the ``!p`` conversion in f-strings and ``str.format()`` implicitly perform an import of the ``pprint`` module. * Clarify the language around the new optional keyword-only argument ``pretty`` to ``print()``. From f30ad2a505620c12c53873731ab3d57c5dedee9b Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Tue, 3 Mar 2026 13:20:09 -0800 Subject: [PATCH 07/10] More updates based on feedback. * For f-strings only (not ``str.format()``) the ``!p`` conversion field takes an optional "format spec". * The PEP no longer proposes a ``pretty`` argument to the ``print()`` built-in function. With the addition of ``!p:callable`` syntax for f-strings, the new argument is unnecessary. * Specify that to pretty print tuples as positional arguments, use the 2-tuple value format, passing a "false-y" value as the argument name. * Clarify that a truth-y ``name`` must be a ``str``. * Specify that the ``!p`` conversion in f-strings and ``str.format()`` implicitly perform an import of the ``pprint`` module. * Describe the new Limited C API function ``PyObject_Pretty()``, and add the optional argument. --- peps/pep-0813.rst | 164 +++++++++++++++++----------------------------- 1 file changed, 60 insertions(+), 104 deletions(-) diff --git a/peps/pep-0813.rst b/peps/pep-0813.rst index 6d5937e16d5..c256c96d39b 100644 --- a/peps/pep-0813.rst +++ b/peps/pep-0813.rst @@ -37,9 +37,9 @@ content. However, the existing :mod:`pprint` module can only format builtin obj By providing a way for classes to customize how their instances participate in pretty printing, 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, 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. +By adding a ``!p`` conversion specifier to f-strings and ``str.format()``, 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 extensions work both independently and complimentary, to provide powerful new use cases. @@ -85,38 +85,38 @@ keyword, and default arguments. The values can be any of the following formats: `_. -A new argument to built-in ``print`` ------------------------------------- - -Built-in :func:`print` gains a new optional keyword-only argument called ``pretty``, which can take -one of the following values: +Additions to ``f-strings`` and ``str.format()`` +----------------------------------------------- -* ``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. +In addition to the existing ``!s``, ``!r``, and ``!a`` conversion specifiers, a new ``!p`` +conversion specifier will be added. The effect of this specifier with an expression ``value`` will +be to call :py:func:`python:pprint.pformat` (importing the ``pprint`` module as needed), passing +``value`` as the only argument. +For f-strings only, the ``!p`` conversion field accepts an optional "format spec" expression, after +the normal separating ``:``, for example: ``f'{obj!p:expression}'``. Formally, the expression can +be anything that evaluates to a callable accepting a single argument (the object to format), and +returns a string which is used as the f-string substitution value. Also for f-strings, the ``!p`` +specifier is fully compatible with the ``obj=`` form, e.g. ``f'{obj=!p:expression}'``. -Additions to ``f-strings`` and ``str.format()`` ------------------------------------------------ +Note that ``:expression`` format specs are *not* allowed in ``str.format()`` calls, at least for the +initial implementation of this PEP. -In addition to the existing ``!s``, ``!r``, and ``!a`` conversion specifiers, an additional ``!p`` conversion -will be added. The effect of this specifier with an expression ``value`` will be to call -:py:func:`python:pprint.pformat`, passing ``value`` as the only argument. In this initial specification, it -will be an error to provide any format specifier if ``!p`` is used. Additions to the C-API ---------------------- To support ``!p``, a new function, ``PyObject_Pretty()`` is added to the `Limited C API `_. -This function takes a single ``PyObject *``, the object to pretty print. This -function imports the ``pprint`` module and calls :func:`pprint.pformat` with -this object as its argument, returning the results. +This function takes two arguments: a ``PyObject *`` for the object to pretty +print, and an optional ``PyObject *`` for the formatter callable (which may be +``NULL``). When the formatter is ``NULL``, this function imports the ``pprint`` +module and calls :func:`pprint.pformat` with the object as its argument, +returning the results. When the formatter is not ``NULL``, it must be a +callable that accepts the object as its single argument and returns a string; +this is used to support the already-evaluated ``:expression`` in +``f'{obj!p:expression}'``. + .. _examples: @@ -139,7 +139,7 @@ class: yield 'pickups', self._pickups yield 'active', self._active, False -Now let's create a couple of instances, and pretty print them: +Now let's create a couple of instances and pretty print them: .. code-block:: pycon @@ -151,35 +151,26 @@ Now let's create a couple of instances, and pretty print them: >>> pprint.pprint(stingray) Bass(5, pickups='humbucker', active=True) -Here's an example of using the ``pretty`` argument to built-in ``print()``: +The ``!p`` conversion specifier can be used in f-strings and ``str.format()`` to pretty print values: + +.. code-block:: pycon + + >>> print(f'{precision=!p}') + precision=Bass(4, pickups='split coil P') + + >>> print('{!p}'.format(precision)) + Bass(4, pickups='split coil P') + +For f-strings only, the ``!p`` conversion field also accepts a format spec expression, which must +evaluate to a callable taking a single argument and returning a string: .. 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, - '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} + >>> def slappa(da: Bass) -> str: + ... return 'All about that bass' + + >>> print(f'{precision=!p:slappa}') + precision=All about that bass Here's an example where a positional argument has a tuple value. In this case, you use the 2-tuple format, with the ``name`` being "false-y". @@ -200,8 +191,7 @@ with the ``name`` being "false-y". 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. +When none of the new features are used, this PEP is fully backward compatible. Security Implications @@ -213,7 +203,7 @@ 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. +Documentation and examples are added to the ``pprint`` module, f-strings, and ``str.format()``. Beginners don't need to be taught these new features until they want prettier representations of their objects. @@ -237,72 +227,36 @@ Open Issues Rich compatibility ------------------ -The output format and APIs are heavily inspired by `Rich -`_. 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. +The output format and APIs are heavily inspired by `Rich `_. The idea is that Rich could +implement a callable compatible with ``!p:callable`` 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. - -print's pretty argument could just take a callable --------------------------------------------------- - -There was [a suggestion](https://discuss.python.org/t/pep-813-the-pretty-print-protocol/106242/2) in the DPO -thread that the third form of ``print(..., pretty=not_none_or_true)`` could generalize to any -callable taking a single argument, rather than requiring it to be an instance with a -``pformat()``-compatible method. We don't need both, but the suggested generalization could be useful. I.e. - -.. code-block:: python - - pprint(myobj, pretty=MyPrinter()) - -vs. - -.. code-block:: python - - pprint(myobj, pretty=MyPrinter().pformat) - Deferred Ideas ============== -Possibly add support for ``!p`` conversions to t-strings. - -``!p`` conversions could include format specifiers. +In the future, we could add support for ``!p`` conversions to t-strings. Addition of the ``:expression`` +format for ``!p`` conversions on ``str.format()`` is also deferred. Acknowledgments =============== -TBD +Pablo Galindo Salgado for helping the PEP authors prototype the use of and prove the feasibility of +``!p:callable`` for f-strings. Footnotes ========= -TBD +None at this time. Change History @@ -310,13 +264,15 @@ Change History * `TBD `__ + * For f-strings only (not ``str.format()``) the ``!p`` conversion field takes an optional "format spec". + * The PEP no longer proposes a ``pretty`` argument to the ``print()`` built-in function. With the + addition of ``!p:callable`` syntax for f-strings, the new argument is unnecessary. * Specify that to pretty print tuples as positional arguments, use the 2-tuple value format, passing a "false-y" value as the argument name. * Clarify that a truth-y ``name`` must be a ``str``. * Specify that the ``!p`` conversion in f-strings and ``str.format()`` implicitly perform an import of the ``pprint`` module. - * Clarify the language around the new optional keyword-only argument ``pretty`` to ``print()``. - * Describe the new Limited C API function ``PyObject_Pretty()``. + * Describe the new Limited C API function ``PyObject_Pretty()``, and add the optional argument. Copyright From fe057ad286766c674b00dd28202f46da7b866fd6 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Tue, 3 Mar 2026 15:05:27 -0800 Subject: [PATCH 08/10] The pygments parser doesn't know about !p --- peps/pep-0813.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/peps/pep-0813.rst b/peps/pep-0813.rst index c256c96d39b..adc304e82c9 100644 --- a/peps/pep-0813.rst +++ b/peps/pep-0813.rst @@ -154,6 +154,7 @@ Now let's create a couple of instances and pretty print them: The ``!p`` conversion specifier can be used in f-strings and ``str.format()`` to pretty print values: .. code-block:: pycon + :force: >>> print(f'{precision=!p}') precision=Bass(4, pickups='split coil P') @@ -165,6 +166,7 @@ For f-strings only, the ``!p`` conversion field also accepts a format spec expre evaluate to a callable taking a single argument and returning a string: .. code-block:: pycon + :force: >>> def slappa(da: Bass) -> str: ... return 'All about that bass' From 72bb6b153f408dc31b73662388a5ac44d7a1a3f8 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Wed, 4 Mar 2026 09:56:00 -0800 Subject: [PATCH 09/10] Respond to review feedback --- peps/pep-0813.rst | 62 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/peps/pep-0813.rst b/peps/pep-0813.rst index adc304e82c9..838511968b4 100644 --- a/peps/pep-0813.rst +++ b/peps/pep-0813.rst @@ -43,6 +43,7 @@ on well-worn "print debugging" patterns, at least for the most common use cases. These extensions work both independently and complimentary, to provide powerful new use cases. +.. _specification: Specification ============= @@ -77,7 +78,7 @@ keyword, and default arguments. The values can be any of the following formats: ``name`` **MUST** exactly be a ``str``. * 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. + ``name=value`` is used. ``name`` **MUST** exactly be a ``str``. .. note:: @@ -93,11 +94,12 @@ conversion specifier will be added. The effect of this specifier with an expres be to call :py:func:`python:pprint.pformat` (importing the ``pprint`` module as needed), passing ``value`` as the only argument. -For f-strings only, the ``!p`` conversion field accepts an optional "format spec" expression, after +For f-strings only, the ``!p`` conversion specifier accepts an optional "format spec" expression, after the normal separating ``:``, for example: ``f'{obj!p:expression}'``. Formally, the expression can be anything that evaluates to a callable accepting a single argument (the object to format), and returns a string which is used as the f-string substitution value. Also for f-strings, the ``!p`` -specifier is fully compatible with the ``obj=`` form, e.g. ``f'{obj=!p:expression}'``. +specifier is fully compatible with the ``obj=`` form, e.g. ``f'{obj=!p:expression}'``. If no format +spec is given, as above :py:func:`python:pprint.pformat` will be used. Note that ``:expression`` format specs are *not* allowed in ``str.format()`` calls, at least for the initial implementation of this PEP. @@ -162,7 +164,38 @@ The ``!p`` conversion specifier can be used in f-strings and ``str.format()`` to >>> print('{!p}'.format(precision)) Bass(4, pickups='split coil P') -For f-strings only, the ``!p`` conversion field also accepts a format spec expression, which must +For more complex objects, ``!p`` can help make debugging output more readable: + +.. code-block:: pycon + :force: + + >>> 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(f'{os.pathconf_names = !p}') + os.pathconf_names = {'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} + +For f-strings only, the ``!p`` conversion specifier also accepts a format spec expression, which must evaluate to a callable taking a single argument and returning a string: .. code-block:: pycon @@ -220,7 +253,17 @@ branch `__. Rejected Ideas ============== -None at this time. +We considered an alternative :ref:`specification ` of the ``__pprint__()`` return +values, where either :func:`~collections.namedtuple`\s, :mod:`dataclasses`, or a duck-typed instance +were used as the return types. Ultimately we rejected this because we don't want to force folks to +define a new class or add any imports just to return values from this function. + + +Deferred Ideas +============== + +In the future, we could add support for ``!p`` conversions to t-strings. Addition of the ``:expression`` +format for ``!p`` conversions on ``str.format()`` is also deferred. Open Issues @@ -241,13 +284,6 @@ dicts, lists, etc. This seems fine as ``pprint`` is not intended to be as featu Rich. This PEP purposefully deems such fancy features as out-of-scope. -Deferred Ideas -============== - -In the future, we could add support for ``!p`` conversions to t-strings. Addition of the ``:expression`` -format for ``!p`` conversions on ``str.format()`` is also deferred. - - Acknowledgments =============== @@ -266,7 +302,7 @@ Change History * `TBD `__ - * For f-strings only (not ``str.format()``) the ``!p`` conversion field takes an optional "format spec". + * For f-strings only (not ``str.format()``) the ``!p`` conversion specifier takes an optional "format spec". * The PEP no longer proposes a ``pretty`` argument to the ``print()`` built-in function. With the addition of ``!p:callable`` syntax for f-strings, the new argument is unnecessary. * Specify that to pretty print tuples as positional arguments, use the 2-tuple value format, passing From ab893bb3e0e4808454ed5347b8cb62157546e736 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Wed, 4 Mar 2026 10:26:57 -0800 Subject: [PATCH 10/10] Clean up the format-specs-for-f-strings-only language and add a cross reference --- peps/pep-0813.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/peps/pep-0813.rst b/peps/pep-0813.rst index 838511968b4..42ab489824a 100644 --- a/peps/pep-0813.rst +++ b/peps/pep-0813.rst @@ -101,8 +101,8 @@ returns a string which is used as the f-string substitution value. Also for f-s specifier is fully compatible with the ``obj=`` form, e.g. ``f'{obj=!p:expression}'``. If no format spec is given, as above :py:func:`python:pprint.pformat` will be used. -Note that ``:expression`` format specs are *not* allowed in ``str.format()`` calls, at least for the -initial implementation of this PEP. +Note that format specs are *not* allowed in ``str.format()`` calls, at least for the :ref:`initial +implementation ` of this PEP. Additions to the C-API @@ -259,6 +259,8 @@ were used as the return types. Ultimately we rejected this because we don't wan define a new class or add any imports just to return values from this function. +.. _deferred: + Deferred Ideas ==============