-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
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
Conversation
…nce of `templatelib.Template`.
@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.) |
Added @AA-Turner's documentation for |
Co-authored-by: Loïc Simon <loic.pano@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 from me!
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. |
There was a problem hiding this 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.
Thanks @picnixz for the feedback! Think I took care of all your suggestions.
That would be really nice! |
There was a problem hiding this 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. |
There was a problem hiding this comment.
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.
There was a problem hiding this 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
f-string | |
f-string | |
f-strings |
@@ -1322,6 +1322,11 @@ Glossary | |||
|
|||
See also :term:`borrowed reference`. | |||
|
|||
t-string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
t-string | |
t-string | |
t-strings |
* 115 (``ord('s')``): ``!s`` string formatting | ||
* 114 (``ord('r')``): ``!r`` repr formatting | ||
* 97 (``ord('a')``): ``!a`` ASCII formatting |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* 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')``) |
.. class:: TemplateStr(values) | ||
|
||
A t-string, comprising a series of :class:`Interpolation` and :class:`Constant` | ||
nodes. |
There was a problem hiding this comment.
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
.. 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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.. class:: Interpolation(value, str, conversion, format_spec) | |
.. class:: Interpolation(value, str, conversion, format_spec=None) |
- Rather than evaluating to a ``str`` object, t-strings evaluate to a | ||
:class:`~string.templatelib.Template` object from the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- 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, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Format specifiers containing nested replacement fields are evaluated eagerly, | |
* Format specifiers containing nested replacement fields are evaluated eagerly, |
attribute of the resulting :class:`!Interpolation` object; if ``precision`` | ||
is (for example) ``2``, the resulting format specifier will be ``'.2f'``. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- When the equal sign ``'='`` is provided in an interpolation expression, the | |
* When the equals sign ``'='`` is provided in an interpolation expression, the |
@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 |
There was a problem hiding this 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>` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* :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>` | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* :pep:`750` | |
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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', ''),) | |
) |
The :class:`!Template` class describes the contents of a template string. | ||
|
||
:class:`!Template` instances are immutable: their attributes cannot be | ||
reassigned. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
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'> |
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A tuple of all interpolated values in the template. | |
A tuple of the values of every interpolation in the template. |
Iterate over the template, yielding each string and | ||
:class:`Interpolation` in order. |
There was a problem hiding this comment.
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
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 |
There was a problem hiding this comment.
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__()
* ``'s'`` which calls :func:`str` on the value, | ||
* ``'r'`` which calls :func:`repr`, and | ||
* ``'a'`` which calls :func:`ascii`. |
There was a problem hiding this comment.
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
* ``'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``). |
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 |
There was a problem hiding this comment.
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
Let's merge and add the updates in a followup. Thanks all! 🫖🧵📚🚀 |
(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>
GH-136974 is a backport of this pull request to the 3.14 branch. |
…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>
See #137020 for the promised followup. A |
This PR adds documentation for t-strings, including:
string.templatelib
in the Library reference sectionlexical-analysis.rst
ast
docsBUILD_INTERPOLATION
andBUILD_TEMPLATE
to thedis
docsTemplate strings
section ofDoc/library/string.rst
to clarify that this is unrelated to t-stringsWe also have an issue tracking our original list of PEP 750 documentation tasks.
📚 Documentation preview 📚: https://cpython-previews--135229.org.readthedocs.build/