diff --git a/Doc/glossary.rst b/Doc/glossary.rst index c5c7994f1262a9..fad892998480d3 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -1304,6 +1304,11 @@ Glossary See also :term:`borrowed reference`. + t-string + String literals prefixed with ``'t'`` or ``'T'`` are commonly called + "t-strings" which is short for + :ref:`template string literals `. See also :pep:`750`. + text encoding A string in Python is a sequence of Unicode code points (in range ``U+0000``--``U+10FFFF``). To store or transfer a string, it needs to be diff --git a/Doc/library/string.rst b/Doc/library/string.rst index 23e15780075435..614b714c2baf52 100644 --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -198,8 +198,9 @@ Format String Syntax The :meth:`str.format` method and the :class:`Formatter` class share the same syntax for format strings (although in the case of :class:`Formatter`, subclasses can define their own format string syntax). The syntax is -related to that of :ref:`formatted string literals `, but it is -less sophisticated and, in particular, does not support arbitrary expressions. +related to that of :ref:`formatted string literals ` and +:ref:`template string literals `, but it is less sophisticated +and, in particular, does not support arbitrary expressions. .. index:: single: {} (curly brackets); in string formatting @@ -306,7 +307,7 @@ Format Specification Mini-Language "Format specifications" are used within replacement fields contained within a format string to define how individual values are presented (see -:ref:`formatstrings` and :ref:`f-strings`). +:ref:`formatstrings`, :ref:`f-strings`, and :ref:`t-strings`). They can also be passed directly to the built-in :func:`format` function. Each formattable type may define how the format specification is to be interpreted. @@ -972,3 +973,9 @@ Helper functions or ``None``, runs of whitespace characters are replaced by a single space and leading and trailing whitespace are removed, otherwise *sep* is used to split and join the words. + + + +.. toctree:: + + string.templatelib.rst diff --git a/Doc/library/string.templatelib.rst b/Doc/library/string.templatelib.rst new file mode 100644 index 00000000000000..8b9fed96008e71 --- /dev/null +++ b/Doc/library/string.templatelib.rst @@ -0,0 +1,184 @@ +:mod:`!string.templatelib` --- Templates and Interpolations for t-strings +========================================================================= + +.. module:: string.templatelib + :synopsis: Support for t-string literals. + +**Source code:** :source:`Lib/string/templatelib.py` + +-------------- + + +.. seealso:: + + :ref:`Format strings ` + + +.. _templatelib-template: + +Template +-------- + +The :class:`!Template` class describes the contents of a template string. + +The most common way to create a new :class:`!Template` instance is to use the t-string literal syntax. This syntax is identical to that of :ref:`f-strings`, except that the string is prefixed with a ``t`` instead of an ``f``. For example, the following code creates a :class:`Template` that can be used to format strings: + + >>> name = "World" + >>> greeting = t"Hello {name}!" + >>> type(greeting) + + >>> print(list(greeting)) + ['Hello ', Interpolation('World', 'name', None, ''), '!'] + +It is also possible to create a :class:`!Template` directly, using its constructor. This takes an arbitrary collection of strings and :class:`Interpolation` instances: + + >>> from string.templatelib import Interpolation, Template + >>> name = "World" + >>> greeting = Template("Hello, ", Interpolation(name, "name"), "!") + >>> print(list(greeting)) + ['Hello, ', Interpolation('World', 'name', None, ''), '!'] + +.. class:: Template(*args) + + Create a new :class:`!Template` object. + + :param args: A mix of strings and :class:`Interpolation` instances in any order. + :type args: str | Interpolation + + If two or more consecutive strings are passed, they will be concatenated into a single value in the :attr:`~Template.strings` attribute. For example, the following code creates a :class:`Template` with a single final string: + + >>> from string.templatelib import Template + >>> greeting = Template("Hello ", "World", "!") + >>> print(greeting.strings) + ('Hello World!',) + + If two or more consecutive interpolations are passed, they will be treated as separate interpolations and an empty string will be inserted between them. For example, the following code creates a template with a single value in the :attr:`~Template.strings` attribute: + + >>> from string.templatelib import Interpolation, Template + >>> greeting = Template(Interpolation("World", "name"), Interpolation("!", "punctuation")) + >>> print(greeting.strings) + ('', '', '') + + .. attribute:: strings + :type: tuple[str, ...] + + A :ref:`tuple ` of the static strings in the template. + + >>> name = "World" + >>> print(t"Hello {name}!".strings) + ('Hello ', '!') + + Empty strings *are* included in the tuple: + + >>> name = "World" + >>> print(t"Hello {name}{name}!".strings) + ('Hello ', '', '!') + + .. attribute:: interpolations + :type: tuple[Interpolation, ...] + + A tuple of the interpolations in the template. + + >>> name = "World" + >>> print(t"Hello {name}!".interpolations) + (Interpolation('World', 'name', None, ''),) + + + .. attribute:: values + :type: tuple[Any, ...] + + A tuple of all interpolated values in the template. + + >>> name = "World" + >>> print(t"Hello {name}!".values) + ('World',) + + .. method:: __iter__() + + Iterate over the template, yielding each string and :class:`Interpolation` in order. + + >>> name = "World" + >>> print(list(t"Hello {name}!")) + ['Hello ', Interpolation('World', 'name', None, ''), '!'] + + Empty strings are *not* included in the iteration: + + >>> name = "World" + >>> print(list(t"Hello {name}{name}")) + ['Hello ', Interpolation('World', 'name', None, ''), Interpolation('World', 'name', None, '')] + + :returns: An iterable of all the parts in the template. + :rtype: typing.Iterator[str | Interpolation] + +.. class:: Interpolation(*args) + + Create a new :class:`!Interpolation` object. + + :param value: The evaluated, in-scope result of the interpolation. + :type value: object + + :param expression: The original *text* of the interpolation's Python :ref:`expressions `. + :type expression: str + + :param conversion: The optional :ref:`conversion ` to be used, one of r, s, and a,. + :type value: Literal["a", "r", "s"] | None + + :param format_spec: An optional, arbitrary string used as the :ref:`format specification ` to present the value. + + The :class:`!Interpolation` type represents an expression inside a template string. It is shallow immutable -- its attributes cannot be reassigned. + + >>> name = "World" + >>> template = t"Hello {name}" + >>> template.interpolations[0].value + 'World' + >>> template.interpolations[0].value = "Galaxy" + Traceback (most recent call last): + File "", line 1, in + AttributeError: readonly attribute + + While f-strings and t-strings are largely similar in syntax and expectations, the :attr:`~Interpolation.conversion` and :attr:`~Interpolation.format_spec` behave differently. With f-strings, these are applied to the resulting value automatically. For example, in this ``format_spec``: + + >>> value = 42 + >>> f"Value: {value:.2f}" + 'Value: 42.00' + + With a t-string :class:`!Interpolation`, the template function is expected to apply this to the value: + + >>> value = 42 + >>> template = t"Value: {value:.2f}" + >>> template.interpolations[0].value + 42 + + .. property:: __match_args__ + + :returns: A tuple of the attributes to use for structural pattern matching. + :rtype: (Literal["value"], Literal["expression"], Literal["conversion"], Literal["format_spec"]) + + + .. property:: value + + :returns: The evaluated value of the interpolation. + :rtype: object + + .. property:: expression + + :returns: The original text of the interpolation's Python expression if the interpolation was created from a t-string literal + :rtype: str + + The :attr:`~Interpolation.expression` is the original text of the interpolation's Python expression, if the interpolation was created from a t-string literal. Developers creating + interpolations manually should either set this to an empty + string or choose a suitable valid python expression. + + .. property:: conversion + + :returns: The conversion to apply to the value, one of "a", "r", or "s", or None. + :rtype: Literal["a", "r", "s"] | None + + The :attr:`~Interpolation.conversion` is the optional conversion to apply to the value. This is one of "a", "r", or "s", or None if no conversion is specified. + + .. property:: format_spec + + :returns: The format specification to apply to the value. + :rtype: str + + The :attr:`~Interpolation.format_spec` is an optional, arbitrary string used as the format specification to present the value. This is similar to the format specification used in :ref:`format strings `, but it is not limited to a specific set of formats. diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index e95fa3a6424e23..a416cbb4cc8eab 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -852,8 +852,8 @@ A literal pattern corresponds to most The rule ``strings`` and the token ``NUMBER`` are defined in the :doc:`standard Python grammar <./grammar>`. Triple-quoted strings are -supported. Raw strings and byte strings are supported. :ref:`f-strings` are -not supported. +supported. Raw strings and byte strings are supported. :ref:`f-strings` +and :ref:`t-strings` are not supported. The forms ``signed_number '+' NUMBER`` and ``signed_number '-' NUMBER`` are for expressing :ref:`complex numbers `; they require a real number diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst index b22eb4db7945d1..a6936b1d36a6de 100644 --- a/Doc/reference/lexical_analysis.rst +++ b/Doc/reference/lexical_analysis.rst @@ -913,6 +913,31 @@ See also :pep:`498` for the proposal that added formatted string literals, and :meth:`str.format`, which uses a related format string mechanism. +.. _t-strings: +.. _template-string-literals: + +t-strings +--------- + +.. versionadded:: 3.14 + +A :dfn:`template string literal` or :dfn:`t-string` is a string literal +that is prefixed with ``'t'`` or ``'T'``. These strings follow the same +syntax and evaluation rules as :ref:`formatted string literals `, with +the following differences: + +- Rather than evaluating to a ``str`` object, t-strings evaluate to a + :class:`~string.templatelib.Template` object from the + :mod:`string.templatelib` module. + +- The :func:`format` protocol is not used. Instead, the format specifier and + conversions (if any) are passed to a new :class:`~string.templatelib.Interpolation` + object that is created for each evaluated expression. + +- Format specifiers containing nested replacement fields are evaluated eagerly, + prior to being passed to the :class:`~string.templatelib.Interpolation` object. + + .. _numbers: Numeric literals diff --git a/Doc/sphinx-warnings.txt b/Doc/sphinx-warnings.txt new file mode 100644 index 00000000000000..e69de29bb2d1d6