Skip to content

gh-132661: docs: update PEP 750 section of What's New in 3.14 #137289

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 70 additions & 36 deletions Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -251,64 +251,98 @@ Also added in 3.14: :ref:`concurrent.futures.InterpreterPoolExecutor
PEP 750: Template strings
-------------------------

Template string literals (t-strings) are a generalization of f-strings,
using a ``t`` in place of the ``f`` prefix. Instead of evaluating
to :class:`str`, t-strings evaluate to a new :class:`!string.templatelib.Template` type:
Template strings are a new mechanism for custom string processing. They share
the familiar syntax of f-strings but, unlike f-strings, return a
:class:`~string.templatelib.Template` instance instead of a simple ``str``.

.. code-block:: python
To write a t-string, use a ``'t'`` prefix instead of an ``'f'``:

from string.templatelib import Template
.. doctest::

name = "World"
template: Template = t"Hello {name}"
>>> variety = "Stilton"
>>> template = t"Try some {variety} cheese!"
>>> type(template)
<class 'string.templatelib.Template'>

The template can then be combined with functions that operate on the template's
structure to produce a :class:`str` or a string-like result.
For example, sanitizing input:
Templates provide access to the static and interpolated (in curly braces) parts
of a string *before* they are combined. Iterate over :class:`!Template`
instances to access their parts in order:

.. code-block:: python
.. testsetup::

variety = "Stilton"
template = t"Try some {variety} cheese!"

.. doctest::

evil = "<script>alert('evil')</script>"
template = t"<p>{evil}</p>"
assert html(template) == "<p>&lt;script&gt;alert('evil')&lt;/script&gt;</p>"
>>> list(template)
['Try some ', Interpolation('Stilton', 'variety', None, ''), ' cheese!']

As another example, generating HTML attributes from data:
It's easy to write (or call) code to process :class:`!Template` instances.
For example, here's a function that renders static parts lowercase and
:class:`~string.templatelib.Interpolation` instances uppercase:

.. code-block:: python

attributes = {"src": "shrubbery.jpg", "alt": "looks nice"}
template = t"<img {attributes}>"
assert html(template) == '<img src="shrubbery.jpg" alt="looks nice" />'
from string.templatelib import Template, Interpolation

def lower_upper(template: Template) -> str:
"""Render static parts lowercase and interpolations uppercase."""
parts: list[str] = []
for part in template:
if isinstance(part, Interpolation):
parts.append(str(part.value).upper())
else:
parts.append(part.lower())
return "".join(parts)

Compared to using an f-string, the ``html`` function has access to template attributes
containing the original information: static strings, interpolations, and values
from the original scope. Unlike existing templating approaches, t-strings build
from the well-known f-string syntax and rules. Template systems thus benefit
from Python tooling as they are much closer to the Python language, syntax,
scoping, and more.
name = "Wenslydale"
template = t"Mister {name}"
assert lower_upper(template) == "mister WENSLYDALE"

Writing template handlers is straightforward:
Because :class:`!Template` instances distinguish between static strings and
interpolations at runtime, they are useful for sanitizing user input. Here's
a simple example that escapes user input in HTML:

.. code-block:: python

from string.templatelib import Template, Interpolation
from html import escape

def lower_upper(template: Template) -> str:
"""Render static parts lowercased and interpolations uppercased."""
def html(template: Template) -> str:
"""Escape HTML in interpolations."""
parts: list[str] = []
for item in template:
if isinstance(item, Interpolation):
parts.append(str(item.value).upper())
for part in template:
if isinstance(part, Interpolation):
parts.append(escape(str(part.value)))
else:
parts.append(item.lower())
parts.append(part)
return "".join(parts)

name = "world"
assert lower_upper(t"HELLO {name}") == "hello WORLD"
user_supplied = "<script>alert('cheese')</script>"
template = t"<p>{user_supplied}</p>"
rendered = html(template)
assert rendered == "<p>&lt;script&gt;alert(&#x27;cheese&#x27;)&lt;/script&gt;</p>"

Beyond simply sanitizing input, template processing code can provide flexibility
and better developer experience. For instance, a more advanced ``html()``
implementation could accept a ``dict`` of HTML attributes directly in the
template:

.. code-block:: python

attributes = {"src": "limburger.jpg", "alt": "a cheese"}
template = t"<img {attributes}>"
rendered = html(template)
assert rendered == '<img src="limburger.jpg" alt="a cheese" />'

Of course, template processing code does not need to return a ``str`` or
string-like result. An even *more* advanced ``html()`` could return a custom ``Element``
type representing a DOM-like structure.

With this in place, developers can write template systems to sanitize SQL, make
safe shell operations, improve logging, tackle modern ideas in web development
(HTML, CSS, and so on), and implement lightweight, custom business DSLs.
With t-strings in place, developers can write systems that sanitize SQL,
make safe shell operations, improve logging, tackle modern ideas in web
development (HTML, CSS, and so on), and implement lightweight custom business DSLs.

(Contributed by Jim Baker, Guido van Rossum, Paul Everitt, Koudai Aono,
Lysandros Nikolaou, Dave Peck, Adam Turner, Jelle Zijlstra, Bénédikt Tran,
Expand Down
Loading