Skip to content

gh-132661: Document t-strings and templatelib #135229

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 57 commits into from
Jul 22, 2025

Conversation

davepeck
Copy link
Contributor

@davepeck davepeck commented Jun 6, 2025

This PR adds documentation for t-strings, including:

  • Document string.templatelib in the Library reference section
  • Add new t-string details to lexical-analysis.rst
  • Add AST nodes to the ast docs
  • Add BUILD_INTERPOLATION and BUILD_TEMPLATE to the dis docs
  • Update the PEP 292 section Template strings section of Doc/library/string.rst to clarify that this is unrelated to t-strings
  • Add a t-strings section to "fancier input/output formatting", after the f-strings section
  • Glossary

We also have an issue tracking our original list of PEP 750 documentation tasks.


📚 Documentation preview 📚: https://cpython-previews--135229.org.readthedocs.build/

@davepeck
Copy link
Contributor Author

@hugovk Thank you for the review and the helpful early feedback! Useful to know about linking.

(FWIW this is very early stage still, so I expect plenty more linting and other issues that we'll eventually resolve.)

@davepeck
Copy link
Contributor Author

davepeck commented Jul 15, 2025

Added @AA-Turner's documentation for string.templatelib.convert().

Co-authored-by: Loïc Simon <loic.pano@gmail.com>
Copy link
Member

@encukou encukou left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 from me!

@hugovk
Copy link
Member

hugovk commented Jul 20, 2025

At EuroPython sprints, @AA-Turner says he still wants to review this.

As release manager, I've given him until the first release candidate on Tuesday when I'll merge this. We can always make further updates, but let's at least have something for RC1.

@picnixz picnixz self-requested a review July 20, 2025 10:44
Copy link
Member

@picnixz picnixz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would adivse against using !class.attr in Sphinx roles as this would also make class being rendered, and instead, I suggest using regular double-backticks instead or use attr + ~, although this would create a link that we may not want it.

On Sphinx' side, I think we should really do something for supporting !~ because it becomes annoying to lose semantics.

@davepeck
Copy link
Contributor Author

Thanks @picnixz for the feedback! Think I took care of all your suggestions.

On Sphinx' side, I think we should really do something for supporting !~ because it becomes annoying to lose semantics.

That would be really nice!

Copy link
Member

@picnixz picnixz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a sphinx maintainer I'm happy to see that directives are used but I fear that it could make the text a bit too "heavy to read". My main concern is that the theme we use actually creates lots of boxes and only a few online pages relies on directives, and prefer indicating the parameter type or the attribute type in the text directly (for instance for "expression", we would rather say "The text of a valid Python expression as a str, possibly empty".

I won't block this PR because of this choice as it's an entirely new page but in the future we may want to remove parameter boxes from the documentation.

If we don't have time until the RC release to fix the links/refs/inline code, we can do it later. For the content itself, I'm mostly good.


.. attribute:: expression

:returns: The text of a valid Python expression, or an empty string.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for :returns: You can write the attribute directive body the same way you did for Template.interpolations for instance.

Copy link
Member

@AA-Turner AA-Turner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay, I abandoned my review and started over as various things had gotten out of date. I'll apply the simple fixes manually for time.

A

@@ -462,7 +462,7 @@ Glossary
core and with user code.

f-string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
f-string
f-string
f-strings

@@ -1322,6 +1322,11 @@ Glossary

See also :term:`borrowed reference`.

t-string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
t-string
t-string
t-strings

Comment on lines +292 to +294
* 115 (``ord('s')``): ``!s`` string formatting
* 114 (``ord('r')``): ``!r`` repr formatting
* 97 (``ord('a')``): ``!a`` ASCII formatting
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* 115 (``ord('s')``): ``!s`` string formatting
* 114 (``ord('r')``): ``!r`` repr formatting
* 97 (``ord('a')``): ``!a`` ASCII formatting
* 97: ``!a`` :func:`ASCII <ascii>` formatting (``ord('a')``)
* 114: ``!r`` :func:`repr` formatting (``ord('r')``)
* 115: ``!s`` :func:`string <str>` formatting (``ord('s')``)

Comment on lines +328 to +331
.. class:: TemplateStr(values)

A t-string, comprising a series of :class:`Interpolation` and :class:`Constant`
nodes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a note on AST node ordering

Suggested change
.. class:: TemplateStr(values)
A t-string, comprising a series of :class:`Interpolation` and :class:`Constant`
nodes.
.. class:: TemplateStr(values, /)
Node representing a template string literal, comprising a series of
:class:`Interpolation` and :class:`Constant` nodes.
These nodes may be any order, and do not need to be interleaved.

.. versionadded:: 3.14


.. class:: Interpolation(value, str, conversion, format_spec)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.. class:: Interpolation(value, str, conversion, format_spec)
.. class:: Interpolation(value, str, conversion, format_spec=None)

Comment on lines +929 to +930
- Rather than evaluating to a ``str`` object, t-strings evaluate to a
:class:`~string.templatelib.Template` object from the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Rather than evaluating to a ``str`` object, t-strings evaluate to a
:class:`~string.templatelib.Template` object from the
* Rather than evaluating to a ``str`` object, template string literals evaluate
to a :class:`~string.templatelib.Template` object from the

:class:`~string.templatelib.Template` object from the
:mod:`string.templatelib` module.

- The :func:`format` protocol is not used. Instead, the format specifier and
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- The :func:`format` protocol is not used. Instead, the format specifier and
* The :func:`format` protocol is not used. Instead, the format specifier and

processes the resulting :class:`~string.templatelib.Template` object to
decide how to handle format specifiers and conversions.

- Format specifiers containing nested replacement fields are evaluated eagerly,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Format specifiers containing nested replacement fields are evaluated eagerly,
* Format specifiers containing nested replacement fields are evaluated eagerly,

Comment on lines +943 to +944
attribute of the resulting :class:`!Interpolation` object; if ``precision``
is (for example) ``2``, the resulting format specifier will be ``'.2f'``.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
attribute of the resulting :class:`!Interpolation` object; if ``precision``
is (for example) ``2``, the resulting format specifier will be ``'.2f'``.
attribute of the resulting :class:`!Interpolation` object.
For example, if ``precision`` is ``2``, the resulting format specifier
will be ``'.2f'``.

attribute of the resulting :class:`!Interpolation` object; if ``precision``
is (for example) ``2``, the resulting format specifier will be ``'.2f'``.

- When the equal sign ``'='`` is provided in an interpolation expression, the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- When the equal sign ``'='`` is provided in an interpolation expression, the
* When the equals sign ``'='`` is provided in an interpolation expression, the

@AA-Turner
Copy link
Member

@davepeck @lysnikolaou this PR is from an organisation fork (@t-strings), so we can't apply suggestions or push commits. Please would you be able to do so? Hugo wants to get this PR in before starting RC1 later today.

A

Copy link
Member

@AA-Turner AA-Turner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Part 2 (briefer as we can't apply suggestions)

.. seealso::

* :ref:`Format strings <f-strings>`
* :ref:`T-string literal syntax <t-strings>`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* :ref:`T-string literal syntax <t-strings>`
* :ref:`Template string literal (t-string) syntax <t-strings>`


* :ref:`Format strings <f-strings>`
* :ref:`T-string literal syntax <t-strings>`

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* :pep:`750`

Comment on lines +24 to +30
Template strings are a formatting mechanism that allows for deep control over
how strings are processed. You can create templates using
:ref:`t-string literal syntax <t-strings>`, which is identical to
:ref:`f-string syntax <f-strings>` but uses a ``t`` instead of an ``f``.
While f-strings evaluate to ``str``, t-strings create a :class:`Template`
instance that gives you access to the static and interpolated (in curly braces)
parts of a string *before* they are combined.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Template strings are a formatting mechanism that allows for deep control over
how strings are processed. You can create templates using
:ref:`t-string literal syntax <t-strings>`, which is identical to
:ref:`f-string syntax <f-strings>` but uses a ``t`` instead of an ``f``.
While f-strings evaluate to ``str``, t-strings create a :class:`Template`
instance that gives you access to the static and interpolated (in curly braces)
parts of a string *before* they are combined.
Template strings are a mechanism for custom string processing.
They have the full flexibility of Python's :ref:`f-strings`,
but return a :class:`Template` instance that gives access
to the static and interpolated (in curly braces) parts of a string
*before* they are combined.
To write a t-string, use a ``'t'`` prefix instead of an ``'f'``, like so:
.. code-block:: pycon
>>> pi = 3.14
>>> t't-strings are new in Python {pi!s}!'
Template(
strings=('t-strings are new in Python ', '!'),
interpolations=(Interpolation(3.14, 'pi', 's', ''),)
)

Comment on lines +38 to +42
The :class:`!Template` class describes the contents of a template string.

:class:`!Template` instances are immutable: their attributes cannot be
reassigned.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The :class:`!Template` class describes the contents of a template string.
:class:`!Template` instances are immutable: their attributes cannot be
reassigned.
The :class:`!Template` class describes the contents of a template string.
It is immutable, meaning that attributes of a template cannot be reassigned.

Comment on lines +45 to +57
Create a new :class:`!Template` object.

:param args: A mix of strings and :class:`Interpolation` instances in any order.
:type args: str | Interpolation

The most common way to create a :class:`!Template` instance is to use the
:ref:`t-string literal syntax <t-strings>`. This syntax is identical to that of
:ref:`f-strings <f-strings>` except that it uses a ``t`` instead of an ``f``:

>>> name = "World"
>>> template = t"Hello {name}!"
>>> type(template)
<class 'string.templatelib.Template'>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be moved later; most users won't need to create Template objects by calling the class, but will need to know what the class is for and does. Perhaps you could separately document Template.__init__()?

.. attribute:: values
:type: tuple[Any, ...]

A tuple of all interpolated values in the template.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
A tuple of all interpolated values in the template.
A tuple of the values of every interpolation in the template.

Comment on lines +162 to +163
Iterate over the template, yielding each string and
:class:`Interpolation` in order.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"in order" here I think could do with more exposition, or reference to the "proper" order of a Template

Comment on lines +205 to +217
Create a new :class:`!Interpolation` object.

:param value: The evaluated, in-scope result of the interpolation.
:type value: object

:param expression: The text of a valid Python expression, or an empty string.
:type expression: str

:param conversion: The optional :ref:`conversion <formatstrings>` to be used, one of r, s, and a.
:type conversion: ``Literal["a", "r", "s"] | None``

:param format_spec: An optional, arbitrary string used as the :ref:`format specification <formatspec>` to present the value.
:type format_spec: str
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As with Template, I think direct construction should be moved to Interpolation.__init__()

Comment on lines +309 to +311
* ``'s'`` which calls :func:`str` on the value,
* ``'r'`` which calls :func:`repr`, and
* ``'a'`` which calls :func:`ascii`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the exclamation-mark forms for people doing a Ctrl-F search

Suggested change
* ``'s'`` which calls :func:`str` on the value,
* ``'r'`` which calls :func:`repr`, and
* ``'a'`` which calls :func:`ascii`.
* ``'s'`` which calls :func:`str` on the value (like ``!s``),
* ``'r'`` which calls :func:`repr` (like ``!r``), and
* ``'a'`` which calls :func:`ascii` (like ``!a``).

Comment on lines +286 to +295
Interpolations support pattern matching, allowing you to match against
their attributes with the :ref:`match statement <match>`:

>>> from string.templatelib import Interpolation
>>> interpolation = Interpolation(3.0, "1 + 2", None, ".2f")
>>> match interpolation:
... case Interpolation(value, expression, conversion, format_spec):
... print(value, expression, conversion, format_spec)
...
3.0 1 + 2 None .2f
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be moved up into the main body description of Interpolation

@hugovk
Copy link
Member

hugovk commented Jul 22, 2025

Let's merge and add the updates in a followup. Thanks all! 🫖🧵📚🚀

@hugovk hugovk merged commit 22c8658 into python:main Jul 22, 2025
25 checks passed
@github-project-automation github-project-automation bot moved this from Todo to Done in Docs PRs Jul 22, 2025
@hugovk hugovk added the needs backport to 3.14 bugs and security fixes label Jul 22, 2025
@miss-islington-app
Copy link

Thanks @davepeck for the PR, and @hugovk for merging it 🌮🎉.. I'm working now to backport this PR to: 3.14.
🐍🍒⛏🤖

miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Jul 22, 2025
(cherry picked from commit 22c8658)

Co-authored-by: Dave Peck <davepeck@gmail.com>
Co-authored-by: Petr Viktorin <encukou@gmail.com>
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Co-authored-by: Loïc Simon <loic.pano@gmail.com>
Co-authored-by: pauleveritt <pauleveritt@me.com>
@bedevere-app
Copy link

bedevere-app bot commented Jul 22, 2025

GH-136974 is a backport of this pull request to the 3.14 branch.

@bedevere-app bedevere-app bot removed the needs backport to 3.14 bugs and security fixes label Jul 22, 2025
hugovk added a commit that referenced this pull request Jul 22, 2025
…136974)

Co-authored-by: Dave Peck <davepeck@gmail.com>
Co-authored-by: Petr Viktorin <encukou@gmail.com>
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Co-authored-by: Loïc Simon <loic.pano@gmail.com>
Co-authored-by: pauleveritt <pauleveritt@me.com>
Co-authored-by: Lysandros Nikolaou <lisandrosnik@gmail.com>
@AA-Turner
Copy link
Member

See #137020 for the promised followup.

A

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs Documentation in the Doc dir skip news
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

10 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy