Skip to content

PEP 750: restrict support for Template + str addition #4395

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 3 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
61 changes: 34 additions & 27 deletions peps/pep-0750.rst
Original file line number Diff line number Diff line change
Expand Up @@ -394,38 +394,41 @@ Template String Concatenation
-----------------------------

Template strings support explicit concatenation using ``+``. Concatenation is
supported for two ``Template`` instances as well as for a ``Template`` instance
and a ``str``:
supported for two ``Template`` instances via ``Template.__add__()``:

.. code-block:: python

name = "World"
template = t"{name}"

assert isinstance(t"Hello " + template, Template)
assert (t"Hello " + template).strings == ("Hello ", "")
assert (t"Hello " + template).interpolations[0].value == "World"
assert isinstance(t"Hello " + t"{name}", Template)
assert (t"Hello " + t"{name}").strings == ("Hello ", "")
assert (t"Hello " + t"{name}").values[0] == "World"

assert isinstance("Hello " + template, Template)
assert ("Hello " + template).strings == ("Hello ", "")
assert ("Hello " + template).interpolations[0].value == "World"
Concatenation of a ``Template`` and a ``str`` is not supported. This is because
it is ambiguous whether the ``str`` should be treated as a static string part
or as an interpolation. Developers can effectively mark a ``str`` by directly
constructing a ``Template`` instance:

Concatenation of templates is "viral": the concatenation of a ``Template`` and
a ``str`` always results in a ``Template`` instance.
.. code-block:: python

name = "World"

# Treat `name` as a static string part
template = t"Hello " + Template(name)

Python's implicit concatenation syntax is also supported. The following code
will work as expected:
# Treat `name` as an interpolation
template = t"Hello " + Template(Interpolation(name, "name"))

Python's implicit concatenation syntax is supported between any combination
of ``Template`` and ``str``:
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't know if it shouldn't be more explicit that the str is a literal string, not the result of an f-string expression? See this conversation:

sql_string = t"SELECT id,name "
                   t"FROM users "
                   f"WHERE name={col}"  # 1-chart typo causing injection

Copy link
Contributor Author

@davepeck davepeck May 20, 2025

Choose a reason for hiding this comment

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

The intent was to continue to allow t"" f"". We should definitely explicitly mention it in the PEP edit.

As mentioned in Python discuss, either we keep both t"" "" and t"" f"" implicit concatenation, or we drop both.

The proposed change to the PEP keeps them, with the view that t"" "" is plausibly useful, and t"" f"" is both rare and trivially lintable. It also acknowledges that there may be real implementation risk in removing some kinds of implicit concat while retaining others (aka ”” f”” should continue to work) — risk that may simply be beyond what is acceptable at this late stage.

An argument to instead drop both forms of implicit concatenation would be: "hey, why should any form of literal construction of t-strings, no matter how uncommon, lead to a plausible injection?"


.. code-block:: python

name = "World"
assert (t"Hello " t"World").strings == ("Hello World",)
assert (t"Hello " "World").strings == ("Hello World",)
assert ("Hello " t"World").strings == ("Hello World",)

The ``Template`` type supports the ``__add__()`` and ``__radd__()`` methods
between two ``Template`` instances and between a ``Template`` instance and a
``str``.


Template and Interpolation Equality
-----------------------------------
Expand Down Expand Up @@ -1349,11 +1352,12 @@ Developers who need to obtain the original template string literal can always
use ``inspect.getsource()`` or similar tools.


Disallowing String Concatenation
--------------------------------
Disallowing Template Concatenation
----------------------------------

Earlier versions of this PEP proposed that template strings should not support
concatenation. This was rejected in favor of allowing concatenation.
Earlier versions of this PEP proposed that ``Template`` instances should not
support concatenation. This was rejected in favor of allowing concatenating
multiple ``Template`` instances.

There are reasonable arguments in favor of rejecting one or all forms of
concatenation: namely, that it cuts off a class of potential bugs, particularly
Expand All @@ -1367,13 +1371,16 @@ return a type that supported concatenation.

In the end, we decided that the surprise to developers of a new string type
*not* supporting concatenation was likely to be greater than the theoretical
harm caused by supporting it. (Developers concatenate f-strings all the time,
after all, and while we are sure there are cases where this introduces bugs,
it's not clear that those bugs outweigh the benefits of supporting concatenation.)
harm caused by supporting it.

While concatenation of two ``Templates`` is supported by this PEP, concatenation
via ``+`` of a ``Template`` and a ``str`` is not supported. This is because it
is ambiguous whether ``str`` should be treated as a static string or an
interpolation. Developers must wrap the ``str`` in a ``Template`` instance before
concatenating it with another ``Template``, as described above.

While concatenation is supported, we expect that code that uses template strings
will more commonly build up larger templates through nesting and composition
rather than concatenation.
We expect that code that uses template strings will more commonly build up
larger templates through nesting and composition rather than concatenation.


Arbitrary Conversion Values
Expand Down