From d91d6fc5d67e7101a9025b4069993d9400109f9e Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Fri, 6 Jun 2025 15:27:44 +0100 Subject: [PATCH 1/4] Add ``string.templatelib.convert()`` --- Doc/library/string.rst | 2 ++ Doc/library/string.templatelib.rst | 46 ++++++++++++++++++++++++ Doc/library/text.rst | 1 + Lib/string/templatelib.py | 17 ++++++--- Lib/test/test_string/test_templatelib.py | 20 ++++++++++- 5 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 Doc/library/string.templatelib.rst diff --git a/Doc/library/string.rst b/Doc/library/string.rst index 23e15780075435..6b4d7571e5fea6 100644 --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -264,6 +264,8 @@ Some simple format string examples:: "Weight in tons {0.weight}" # 'weight' attribute of first positional arg "Units destroyed: {players[0]}" # First element of keyword argument 'players'. +.. _formatstrings-conversion: + The *conversion* field causes a type coercion before formatting. Normally, the job of formatting a value is done by the :meth:`~object.__format__` method of the value itself. However, in some cases it is desirable to force a type to be formatted diff --git a/Doc/library/string.templatelib.rst b/Doc/library/string.templatelib.rst new file mode 100644 index 00000000000000..1e936bc8caa175 --- /dev/null +++ b/Doc/library/string.templatelib.rst @@ -0,0 +1,46 @@ +:mod:`!string.templatelib` --- Support for template string literals +=================================================================== + +.. module:: string.templatelib + :synopsis: Support for template string literals. + +**Source code:** :source:`Lib/string/templatelib.py` + +-------------- + +.. versionadded:: 3.14 + +.. seealso:: + + :pep:`750` -- Template Strings + +Types +----- + +.. class:: Template + +.. class:: Interpolation + +Helper functions +---------------- + +.. function:: convert(obj, /, conversion) + + Applies formatted string literal :ref:`conversion ` + semantics to the given object *obj*. + This is frequently useful for custom template string processing logic. + + Three conversion flags are currently supported: + + * ``'!s'`` which calls :func:`str` on the value, + * ``'!r'`` which calls :func:`repr`, and + * ``'!a'`` which calls :func:`ascii`. + + If the conversion flag is ``None``, *obj* is returned unchanged. + +.. _template-strings: + +Template String Syntax +---------------------- + +.. TODO: Add section similar to :ref:`formatstrings`. diff --git a/Doc/library/text.rst b/Doc/library/text.rst index 47b678434fc899..92e7dd9a53b80d 100644 --- a/Doc/library/text.rst +++ b/Doc/library/text.rst @@ -16,6 +16,7 @@ Python's built-in string type in :ref:`textseq`. .. toctree:: string.rst + string.templatelib.rst re.rst difflib.rst textwrap.rst diff --git a/Lib/string/templatelib.py b/Lib/string/templatelib.py index 14b40e1e36e30b..c77291afff27ca 100644 --- a/Lib/string/templatelib.py +++ b/Lib/string/templatelib.py @@ -1,15 +1,22 @@ """Support for template string literals (t-strings).""" -__all__ = [ - "Interpolation", - "Template", -] - t = t"{0}" Template = type(t) Interpolation = type(t.interpolations[0]) del t +def convert(obj, /, conversion): + """Implements formatted string literals conversion semantics.""" + if conversion is None: + return obj + if conversion == 'r': + return repr(obj) + if conversion == 's': + return str(obj) + if conversion == 'a': + return ascii(obj) + raise ValueError(f'invalid conversion specifier: {conversion!r}') + def _template_unpickle(*args): import itertools diff --git a/Lib/test/test_string/test_templatelib.py b/Lib/test/test_string/test_templatelib.py index 85fcff486d6616..5270e2ce0251a8 100644 --- a/Lib/test/test_string/test_templatelib.py +++ b/Lib/test/test_string/test_templatelib.py @@ -1,7 +1,7 @@ import pickle import unittest from collections.abc import Iterator, Iterable -from string.templatelib import Template, Interpolation +from string.templatelib import Template, Interpolation, convert from test.test_string._support import TStringBaseCase, fstring @@ -156,5 +156,23 @@ def test_exhausted(self): self.assertRaises(StopIteration, next, template_iter) +class TestFunctions(unittest.TestCase): + def test_convert(self): + for obj in ('Café', None, 3.14, b'bytes'): + with self.subTest(f'{obj=}'): + self.assertEqual(convert(obj, None), obj) + self.assertEqual(convert(obj, 's'), str(obj)) + self.assertEqual(convert(obj, 'r'), repr(obj)) + self.assertEqual(convert(obj, 'a'), ascii(obj)) + + # Invalid conversion specifier + with self.assertRaises(ValueError): + convert(obj, 'z') + with self.assertRaises(ValueError): + convert(obj, 1) + with self.assertRaises(ValueError): + convert(obj, object()) + + if __name__ == '__main__': unittest.main() From 321164a01ad9eb563ed789ac9530f80426f8bfbf Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Tue, 15 Jul 2025 09:43:11 +0200 Subject: [PATCH 2/4] Remove documentation --- Doc/library/string.rst | 2 -- Doc/library/string.templatelib.rst | 46 ------------------------------ Doc/library/text.rst | 1 - 3 files changed, 49 deletions(-) delete mode 100644 Doc/library/string.templatelib.rst diff --git a/Doc/library/string.rst b/Doc/library/string.rst index 6b4d7571e5fea6..23e15780075435 100644 --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -264,8 +264,6 @@ Some simple format string examples:: "Weight in tons {0.weight}" # 'weight' attribute of first positional arg "Units destroyed: {players[0]}" # First element of keyword argument 'players'. -.. _formatstrings-conversion: - The *conversion* field causes a type coercion before formatting. Normally, the job of formatting a value is done by the :meth:`~object.__format__` method of the value itself. However, in some cases it is desirable to force a type to be formatted diff --git a/Doc/library/string.templatelib.rst b/Doc/library/string.templatelib.rst deleted file mode 100644 index 1e936bc8caa175..00000000000000 --- a/Doc/library/string.templatelib.rst +++ /dev/null @@ -1,46 +0,0 @@ -:mod:`!string.templatelib` --- Support for template string literals -=================================================================== - -.. module:: string.templatelib - :synopsis: Support for template string literals. - -**Source code:** :source:`Lib/string/templatelib.py` - --------------- - -.. versionadded:: 3.14 - -.. seealso:: - - :pep:`750` -- Template Strings - -Types ------ - -.. class:: Template - -.. class:: Interpolation - -Helper functions ----------------- - -.. function:: convert(obj, /, conversion) - - Applies formatted string literal :ref:`conversion ` - semantics to the given object *obj*. - This is frequently useful for custom template string processing logic. - - Three conversion flags are currently supported: - - * ``'!s'`` which calls :func:`str` on the value, - * ``'!r'`` which calls :func:`repr`, and - * ``'!a'`` which calls :func:`ascii`. - - If the conversion flag is ``None``, *obj* is returned unchanged. - -.. _template-strings: - -Template String Syntax ----------------------- - -.. TODO: Add section similar to :ref:`formatstrings`. diff --git a/Doc/library/text.rst b/Doc/library/text.rst index 92e7dd9a53b80d..47b678434fc899 100644 --- a/Doc/library/text.rst +++ b/Doc/library/text.rst @@ -16,7 +16,6 @@ Python's built-in string type in :ref:`textseq`. .. toctree:: string.rst - string.templatelib.rst re.rst difflib.rst textwrap.rst From 9d59705b73572744090a813a8950f5036bf7dbe4 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Tue, 15 Jul 2025 09:50:08 +0200 Subject: [PATCH 3/4] Avoid BytesWarning --- Lib/test/test_string/test_templatelib.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_string/test_templatelib.py b/Lib/test/test_string/test_templatelib.py index 5270e2ce0251a8..81222da8e886d8 100644 --- a/Lib/test/test_string/test_templatelib.py +++ b/Lib/test/test_string/test_templatelib.py @@ -158,7 +158,9 @@ def test_exhausted(self): class TestFunctions(unittest.TestCase): def test_convert(self): - for obj in ('Café', None, 3.14, b'bytes'): + from fractions import Fraction + + for obj in ('Café', None, 3.14, Fraction(1, 2)): with self.subTest(f'{obj=}'): self.assertEqual(convert(obj, None), obj) self.assertEqual(convert(obj, 's'), str(obj)) From 125ce4e885fcef00dc848bff712af8d28ac312fe Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Tue, 15 Jul 2025 09:51:11 +0200 Subject: [PATCH 4/4] Imperative mood --- Lib/string/templatelib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/string/templatelib.py b/Lib/string/templatelib.py index c77291afff27ca..8164872432ad09 100644 --- a/Lib/string/templatelib.py +++ b/Lib/string/templatelib.py @@ -6,7 +6,7 @@ del t def convert(obj, /, conversion): - """Implements formatted string literals conversion semantics.""" + """Convert *obj* using formatted string literal semantics.""" if conversion is None: return obj if conversion == 'r': @@ -15,7 +15,7 @@ def convert(obj, /, conversion): return str(obj) if conversion == 'a': return ascii(obj) - raise ValueError(f'invalid conversion specifier: {conversion!r}') + raise ValueError(f'invalid conversion specifier: {conversion}') def _template_unpickle(*args): import itertools pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy