@@ -37,12 +37,13 @@ content. However, the existing :mod:`pprint` module can only format builtin obj
3737By providing a way for classes to customize how their instances participate in pretty printing,
3838users have more options for visually improving the display of their complex data, especially for debugging.
3939
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.
40+ By adding a `` !p `` conversion specifier to f-strings and `` str.format() `` , debugging with user-friendly
41+ display is made even more convenient. Since no extra imports are required, users can easily just piggyback
42+ on well-worn "print debugging" patterns, at least for the most common use cases.
4343
4444These extensions work both independently and complimentary, to provide powerful new use cases.
4545
46+ .. _specification :
4647
4748Specification
4849=============
@@ -70,41 +71,56 @@ class name. The printed representation will usually look like a class construct
7071keyword, and default arguments. The values can be any of the following formats:
7172
7273* 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.
74+ * A 2-tuple of ``(name, value) `` representing a keyword argument. A
75+ representation of ``name=value `` is used. If ``name `` is "false-y", then
76+ ``value `` is treated as a positional argument. This is how you would print
77+ a positional argument with a tuple value. See :ref: `examples `. Otherwise,
78+ ``name `` **MUST ** exactly be a ``str ``.
7579* A 3-tuple of ``(name, value, default_value) `` representing a keyword argument with a default
7680 value. If ``value `` equals ``default_value ``, then this tuple is skipped, otherwise
77- ``name=value `` is used.
81+ ``name=value `` is used. `` name `` ** MUST ** exactly be a `` str ``.
7882
7983.. note ::
8084
8185 This protocol is compatible with the `Rich library's pretty printing protocol
8286 <https://rich.readthedocs.io/en/latest/pretty.html#rich-repr-protocol> `_.
8387
8488
85- A new argument to built-in `` print ``
86- ------------------------------------
89+ Additions to `` f-strings `` and `` str.format() ``
90+ -----------------------------------------------
8791
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:
92+ In addition to the existing ``!s ``, ``!r ``, and ``!a `` conversion specifiers, a new ``!p ``
93+ conversion specifier will be added. The effect of this specifier with an expression ``value `` will
94+ be to call :py:func: `python:pprint.pformat ` (importing the ``pprint `` module as needed), passing
95+ ``value `` as the only argument.
9096
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.
97+ For f-strings only, the ``!p `` conversion specifier accepts an optional "format spec" expression, after
98+ the normal separating ``: ``, for example: ``f'{obj!p:expression}' ``. Formally, the expression can
99+ be anything that evaluates to a callable accepting a single argument (the object to format), and
100+ returns a string which is used as the f-string substitution value. Also for f-strings, the ``!p ``
101+ specifier is fully compatible with the ``obj= `` form, e.g. ``f'{obj=!p:expression}' ``. If no format
102+ spec is given, as above :py:func: `python:pprint.pformat ` will be used.
99103
104+ Note that format specs are *not * allowed in ``str.format() `` calls, at least for the :ref: `initial
105+ implementation <deferred>` of this PEP.
100106
101- Additions to ``f-strings `` and ``str.format() ``
102- -----------------------------------------------
103107
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+ Additions to the C-API
109+ ----------------------
110+
111+ To support ``!p ``, a new function, ``PyObject_Pretty() `` is added to the
112+ `Limited C API <https://docs.python.org/3/c-api/stable.html#limited-c-api >`_.
113+ This function takes two arguments: a ``PyObject * `` for the object to pretty
114+ print, and an optional ``PyObject * `` for the formatter callable (which may be
115+ ``NULL ``). When the formatter is ``NULL ``, this function imports the ``pprint ``
116+ module and calls :func: `pprint.pformat ` with the object as its argument,
117+ returning the results. When the formatter is not ``NULL ``, it must be a
118+ callable that accepts the object as its single argument and returns a string;
119+ this is used to support the already-evaluated ``:expression `` in
120+ ``f'{obj!p:expression}' ``.
121+
122+
123+ .. _examples :
108124
109125Examples
110126========
@@ -125,7 +141,7 @@ class:
125141 yield ' pickups' , self ._pickups
126142 yield ' active' , self ._active, False
127143
128- Now let's create a couple of instances, and pretty print them:
144+ Now let's create a couple of instances and pretty print them:
129145
130146.. code-block :: pycon
131147
@@ -137,16 +153,28 @@ Now let's create a couple of instances, and pretty print them:
137153 >>> pprint.pprint(stingray)
138154 Bass(5, pickups='humbucker', active=True)
139155
140- Here's an example of using the `` pretty `` argument to built- in `` print () ``:
156+ The `` !p `` conversion specifier can be used in f-strings and `` str.format () `` to pretty print values :
141157
142158.. code-block :: pycon
159+ :force:
160+
161+ >>> print(f'{precision=!p}')
162+ precision=Bass(4, pickups='split coil P')
163+
164+ >>> print('{!p}'.format(precision))
165+ Bass(4, pickups='split coil P')
166+
167+ For more complex objects, ``!p `` can help make debugging output more readable:
168+
169+ .. code-block :: pycon
170+ :force:
143171
144172 >>> import os
145173 >>> print(os.pathconf_names)
146174 {'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}
147175
148- >>> print(os.pathconf_names, pretty=True )
149- {'PC_ALLOC_SIZE_MIN': 16,
176+ >>> print(f'{ os.pathconf_names = !p}' )
177+ os.pathconf_names = {'PC_ALLOC_SIZE_MIN': 16,
150178 'PC_ASYNC_IO': 17,
151179 'PC_CHOWN_RESTRICTED': 7,
152180 'PC_FILESIZEBITS': 18,
@@ -167,12 +195,38 @@ Here's an example of using the ``pretty`` argument to built-in ``print()``:
167195 'PC_SYNC_IO': 25,
168196 'PC_VDISABLE': 9}
169197
198+ For f-strings only, the ``!p `` conversion specifier also accepts a format spec expression, which must
199+ evaluate to a callable taking a single argument and returning a string:
200+
201+ .. code-block :: pycon
202+ :force:
203+
204+ >>> def slappa(da: Bass) -> str:
205+ ... return 'All about that bass'
206+
207+ >>> print(f'{precision=!p:slappa}')
208+ precision=All about that bass
209+
210+ Here's an example where a positional argument has a tuple value. In this case, you use the 2-tuple format,
211+ with the ``name `` being "false-y".
212+
213+ .. code-block :: pycon
214+
215+ >>> class Things:
216+ ... def __pprint__(self):
217+ ... yield (None, (1, 2))
218+ ... yield ('', (3, 4))
219+ ... yield ('arg', (5, 6))
220+ ...
221+ >>> from rich.pretty import pprint
222+ >>> pprint(Things())
223+ Things((1, 2), (3, 4), arg=(5, 6))
224+
170225
171226 Backwards Compatibility
172227=======================
173228
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.
229+ When none of the new features are used, this PEP is fully backward compatible.
176230
177231
178232Security Implications
@@ -184,7 +238,7 @@ There are no known security implications for this proposal.
184238How to Teach This
185239=================
186240
187- Documentation and examples are added to the ``pprint `` module and the `` print () `` function .
241+ Documentation and examples are added to the ``pprint `` module, f-strings, and `` str.format () ``.
188242Beginners don't need to be taught these new features until they want prettier representations of
189243their objects.
190244
@@ -199,16 +253,30 @@ branch <https://github.com/warsaw/cpython/tree/pprint>`__.
199253Rejected Ideas
200254==============
201255
202- None at this time.
256+ We considered an alternative :ref: `specification <specification >` of the ``__pprint__() `` return
257+ values, where either :func: `~collections.namedtuple `\s , :mod: `dataclasses `, or a duck-typed instance
258+ were used as the return types. Ultimately we rejected this because we don't want to force folks to
259+ define a new class or add any imports just to return values from this function.
260+
261+
262+ .. _deferred :
263+
264+ Deferred Ideas
265+ ==============
266+
267+ In the future, we could add support for ``!p `` conversions to t-strings. Addition of the ``:expression ``
268+ format for ``!p `` conversions on ``str.format() `` is also deferred.
203269
204270
205271Open Issues
206272===========
207273
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
274+ Rich compatibility
275+ ------------------
276+
277+ The output format and APIs are heavily inspired by `Rich <rich-repr-protocol _>`_. The idea is that Rich could
278+ implement a callable compatible with ``!p:callable `` fairly easily. Rich's API is designed to print
279+ constructor-like representations of instances, which means that it's not possible to control much of the
212280"class chrome" around the arguments. Rich does support using angle brackets (i.e. ``<...> ``) instead of
213281parentheses by setting the attribute ``.angular=True `` on the rich repr method. This PEP does not support
214282that feature, although it likely could in the future.
@@ -217,32 +285,34 @@ This also means that there's no way to control the pretty printed format of buil
217285dicts, lists, etc. This seems fine as ``pprint `` is not intended to be as feature-rich (pun intended!) as
218286Rich. This PEP purposefully deems such fancy features as out-of-scope.
219287
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-
235288
236289Acknowledgments
237290===============
238291
239- TBD
292+ Pablo Galindo Salgado for helping the PEP authors prototype the use of and prove the feasibility of
293+ ``!p:callable `` for f-strings.
240294
241295
242296Footnotes
243297=========
244298
245- TBD
299+ None at this time.
300+
301+
302+ Change History
303+ ==============
304+
305+ * `TBD <TBD >`__
306+
307+ * For f-strings only (not ``str.format() ``) the ``!p `` conversion specifier takes an optional "format spec".
308+ * The PEP no longer proposes a ``pretty `` argument to the ``print() `` built-in function. With the
309+ addition of ``!p:callable `` syntax for f-strings, the new argument is unnecessary.
310+ * Specify that to pretty print tuples as positional arguments, use the 2-tuple value format, passing
311+ a "false-y" value as the argument name.
312+ * Clarify that a truth-y ``name `` must be a ``str ``.
313+ * Specify that the ``!p `` conversion in f-strings and ``str.format() `` implicitly perform an
314+ import of the ``pprint `` module.
315+ * Describe the new Limited C API function ``PyObject_Pretty() ``, and add the optional argument.
246316
247317
248318Copyright
0 commit comments