@@ -251,64 +251,98 @@ Also added in 3.14: :ref:`concurrent.futures.InterpreterPoolExecutor
251251PEP 750: Template strings
252252-------------------------
253253
254- Template string literals (t-strings) are a generalization of f-strings,
255- using a ``t `` in place of the ``f `` prefix. Instead of evaluating
256- to :class: `str `, t-strings evaluate to a new :class: `!string.templatelib.Template ` type:
254+ Template strings are a new mechanism for custom string processing. They share
255+ the familiar syntax of f-strings but, unlike f-strings, return a
256+ :class: `~string.templatelib.Template ` instance instead of a simple ``str ``.
257+ Templates provide access to the static and interpolated (in curly braces) parts
258+ of a string *before * they are combined.
257259
258- .. code-block :: python
260+ To write a t-string, use a `` 't' `` prefix instead of an `` 'f' ``:
259261
260- from string.templatelib import Template
262+ .. doctest ::
261263
262- name = " World"
263- template: Template = t" Hello {name} "
264+ >>> variety = " Stilton"
265+ >>> template = t" Try some {variety} cheese!"
266+ >>> type (template)
267+ <class 'string.templatelib.Template'>
264268
265- The template can then be combined with functions that operate on the template's
266- structure to produce a :class: `str ` or a string-like result.
267- For example, sanitizing input:
269+ Iterate over :class: `!Template ` instances to access their parts in order:
268270
269- .. code-block :: python
271+ .. testsetup ::
272+
273+ variety = "Stilton"
274+ template = t"Try some {variety} cheese!"
275+
276+ .. doctest ::
270277
271- evil = " <script>alert('evil')</script>"
272- template = t" <p>{evil} </p>"
273- assert html(template) == " <p><script>alert('evil')</script></p>"
278+ >>> list (template)
279+ ['Try some ', Interpolation('Stilton', 'variety', None, ''), ' cheese!']
274280
275- As another example, generating HTML attributes from data:
281+ It's easy to write (or call) code to process :class: `!Template ` instances.
282+ For example, here's a function that renders static parts lowercase and
283+ :class: `~string.templatelib.Interpolation ` instances uppercase:
276284
277285.. code-block :: python
278286
279- attributes = {" src" : " shrubbery.jpg" , " alt" : " looks nice" }
280- template = t" <img {attributes} >"
281- assert html(template) == ' <img src="shrubbery.jpg" alt="looks nice" />'
287+ from string.templatelib import Template, Interpolation
288+
289+ def lower_upper (template : Template) -> str :
290+ """ Render static parts lowercase and interpolations uppercase."""
291+ parts: list[str ] = []
292+ for part in template:
293+ if isinstance (part, Interpolation):
294+ parts.append(str (part.value).upper())
295+ else :
296+ parts.append(part.lower())
297+ return " " .join(parts)
282298
283- Compared to using an f-string, the ``html `` function has access to template attributes
284- containing the original information: static strings, interpolations, and values
285- from the original scope. Unlike existing templating approaches, t-strings build
286- from the well-known f-string syntax and rules. Template systems thus benefit
287- from Python tooling as they are much closer to the Python language, syntax,
288- scoping, and more.
299+ name = " Wenslydale"
300+ template = t" Mister {name} "
301+ assert lower_upper(template) == " mister WENSLYDALE"
289302
290- Writing template handlers is straightforward:
303+ Because :class: `Template ` instances distinguish between static strings and
304+ interpolations at runtime, they are useful for sanitizing user input. Here's
305+ a simple example that escapes user input in HTML:
291306
292307.. code-block :: python
293308
294309 from string.templatelib import Template, Interpolation
310+ from html import escape
295311
296- def lower_upper (template : Template) -> str :
297- """ Render static parts lowercased and interpolations uppercased ."""
312+ def html (template : Template) -> str :
313+ """ Escape HTML in interpolations."""
298314 parts: list[str ] = []
299- for item in template:
300- if isinstance (item , Interpolation):
301- parts.append(str (item .value).upper( ))
315+ for part in template:
316+ if isinstance (part , Interpolation):
317+ parts.append(escape( str (part .value)))
302318 else :
303- parts.append(item.lower() )
319+ parts.append(part )
304320 return " " .join(parts)
305321
306- name = " world"
307- assert lower_upper(t" HELLO {name} " ) == " hello WORLD"
322+ user_supplied = " <script>alert('cheese')</script>"
323+ template = t" <p>{user_supplied} </p>"
324+ rendered = html(template)
325+ assert rendered == " <p><script>alert('cheese')</script></p>"
326+
327+ Beyond simply sanitizing input, template processing code can provide flexibility
328+ and better developer experience. For instance, a more advanced ``html() ``
329+ implementation could accept a ``dict `` of HTML attributes directly in the
330+ template:
331+
332+ .. code-block :: python
333+
334+ attributes = {" src" : " limburger.jpg" , " alt" : " a cheese" }
335+ template = t" <img {attributes} >"
336+ rendered = html(template)
337+ assert rendered == ' <img src="limburger.jpg" alt="a cheese" />'
338+
339+ Of course, template processing code does not need to return a ``str `` or
340+ string-like result. For example, an even *more * advanced ``html() `` could
341+ return a custom ``Element `` type representing a DOM-like structure.
308342
309- With this in place, developers can write template systems to sanitize SQL, make
310- safe shell operations, improve logging, tackle modern ideas in web development
311- (HTML, CSS, and so on), and implement lightweight, custom business DSLs.
343+ With t-strings in place, developers can write systems that sanitize SQL,
344+ make safe shell operations, improve logging, tackle modern ideas in web
345+ development (HTML, CSS, and so on), and implement lightweight custom business DSLs.
312346
313347(Contributed by Jim Baker, Guido van Rossum, Paul Everitt, Koudai Aono,
314348Lysandros Nikolaou, Dave Peck, Adam Turner, Jelle Zijlstra, Bénédikt Tran,
0 commit comments