Created
May 26, 2025 16:20
-
-
Save okken/7e49fa98ee7a08e4ce623e9cc5bfbef1 to your computer and use it in GitHub Desktop.
pytest versions of Brett's t-string tutorial
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import pytest | |
| import sys | |
| # shared by all examples | |
| name = "world" | |
| expected = f"Hello, {name}! Conversions like {name!r} and format specs like {name:<6} work!" | |
| def test_identity(): | |
| def f_yeah(t_string): | |
| """Convert a t-string into what an f-string would have provided.""" | |
| return t_string | |
| actual = f_yeah(expected) | |
| print('\nactual:', actual) | |
| assert actual == expected | |
| def test_parse_split_join(): | |
| def f_yeah(t_string): | |
| """Convert a t-string into what an f-string would have provided.""" | |
| return "".join(t_string) | |
| parsed = [ | |
| "Hello, ", | |
| "world", | |
| "! Conversions like ", | |
| "'world'", | |
| " and format specs like ", | |
| "world ", | |
| " work!", | |
| ] | |
| actual = f_yeah(parsed) | |
| assert actual == expected | |
| def test_parse_split_join_with_replacement(): | |
| def f_yeah(t_string): | |
| """Convert a t-string into what an f-string would have provided.""" | |
| return "".join(t_string) | |
| parsed = [ | |
| "Hello, ", | |
| name, | |
| "! Conversions like ", | |
| repr(name), | |
| " and format specs like ", | |
| format(name, "<6"), | |
| " work!", | |
| ] | |
| actual = f_yeah(parsed) | |
| assert actual == expected | |
| def test_parse_parts(): | |
| def f_yeah(t_string): | |
| """Convert a t-string into what an f-string would have provided.""" | |
| converters = {func.__name__[0]: func for func in (str, repr, ascii)} | |
| converters[None] = str | |
| parts = [] | |
| for part in t_string: | |
| match part: | |
| case (value, conversion, format_spec): | |
| parts.append(format(converters[conversion](value), format_spec)) | |
| case str(): | |
| parts.append(part) | |
| return "".join(parts) | |
| parsed = [ | |
| "Hello, ", | |
| (name, None, ""), | |
| "! Conversions like ", | |
| (name, "r", ""), | |
| " and format specs like ", | |
| (name, None, "<6"), | |
| " work!", | |
| ] | |
| actual = f_yeah(parsed) | |
| assert actual == expected | |
| def test_parse_with_string_rep(): | |
| def f_yeah(t_string): | |
| """Convert a t-string into what an f-string would have provided.""" | |
| converters = {func.__name__[0]: func for func in (str, repr, ascii)} | |
| converters[None] = str | |
| parts = [] | |
| for part in t_string: | |
| match part: | |
| case (value, _, conversion, format_spec): | |
| parts.append(format(converters[conversion](value), format_spec)) | |
| case str(): | |
| parts.append(part) | |
| return "".join(parts) | |
| parsed = [ | |
| "Hello, ", | |
| (name, "name", None, ""), | |
| "! Conversions like ", | |
| (name, "name", "r", ""), | |
| " and format specs like ", | |
| (name, "name", None, "<6"), | |
| " work!", | |
| ] | |
| actual = f_yeah(parsed) | |
| assert actual == expected | |
| def test_parse_with_interpolation(): | |
| class Interpolation: | |
| __match_args__ = ("value", "expression", "conversion", "format_spec") | |
| def __init__( | |
| self, | |
| value, | |
| expression, | |
| conversion=None, | |
| format_spec="", | |
| ): | |
| self.value = value | |
| self.expression = expression | |
| self.conversion = conversion | |
| self.format_spec = format_spec | |
| def f_yeah(t_string): | |
| """Convert a t-string into what an f-string would have provided.""" | |
| converters = {func.__name__[0]: func for func in (str, repr, ascii)} | |
| converters[None] = str | |
| parts = [] | |
| for part in t_string: | |
| match part: | |
| case Interpolation(value, _, conversion, format_spec): | |
| parts.append(format(converters[conversion](value), format_spec)) | |
| case str(): | |
| parts.append(part) | |
| return "".join(parts) | |
| parsed = [ | |
| "Hello, ", | |
| Interpolation(name, "name"), | |
| "! Conversions like ", | |
| Interpolation(name, "name", "r"), | |
| " and format specs like ", | |
| Interpolation(name, "name", format_spec="<6"), | |
| " work!", | |
| ] | |
| actual = f_yeah(parsed) | |
| assert actual == expected | |
| def test_parse_with_inetrpolation_and_template(): | |
| class Interpolation: | |
| __match_args__ = ("value", "expression", "conversion", "format_spec") | |
| def __init__( | |
| self, | |
| value, | |
| expression, | |
| conversion=None, | |
| format_spec="", | |
| ): | |
| self.value = value | |
| self.expression = expression | |
| self.conversion = conversion | |
| self.format_spec = format_spec | |
| class Template: | |
| def __init__(self, *args): | |
| # There will always be N+1 strings for N interpolations; | |
| # that may mean inserting an empty string at the start or end. | |
| strings = [] | |
| interpolations = [] | |
| if args and isinstance(args[0], Interpolation): | |
| strings.append("") | |
| for arg in args: | |
| match arg: | |
| case str(): | |
| strings.append(arg) | |
| case Interpolation(): | |
| interpolations.append(arg) | |
| if args and isinstance(args[-1], Interpolation): | |
| strings.append("") | |
| self._iter = args | |
| self.strings = tuple(strings) | |
| self.interpolations = tuple(interpolations) | |
| @property | |
| def values(self): | |
| return tuple(interpolation.value for interpolation in self.interpolations) | |
| def __iter__(self): | |
| return iter(self._iter) | |
| def f_yeah(t_string): | |
| """Convert a t-string into what an f-string would have provided.""" | |
| converters = {func.__name__[0]: func for func in (str, repr, ascii)} | |
| converters[None] = str | |
| parts = [] | |
| for part in t_string: | |
| match part: | |
| case Interpolation(value, _, conversion, format_spec): | |
| parts.append(format(converters[conversion](value), format_spec)) | |
| case str(): | |
| parts.append(part) | |
| return "".join(parts) | |
| parsed = Template( | |
| "Hello, ", | |
| Interpolation(name, "name"), | |
| "! Conversions like ", | |
| Interpolation(name, "name", "r"), | |
| " and format specs like ", | |
| Interpolation(name, "name", format_spec="<6"), | |
| " work!", | |
| ) | |
| actual = f_yeah(parsed) | |
| assert actual == expected | |
| @pytest.mark.skipif(sys.version_info < (3, 14, 0, 'beta', 1), reason="requires python3.14b1 or higher") | |
| def test_tstring(): | |
| from string import templatelib | |
| def f_yeah(t_string): | |
| """Convert a t-string into what an f-string would have provided.""" | |
| converters = {func.__name__[0]: func for func in (str, repr, ascii)} | |
| converters[None] = str | |
| parts = [] | |
| for part in t_string: | |
| match part: | |
| case templatelib.Interpolation(value, _, conversion, format_spec): | |
| parts.append(format(converters[conversion](value), format_spec)) | |
| case str(): | |
| parts.append(part) | |
| return "".join(parts) | |
| parsed = t"Hello, {name}! Conversions like {name!r} and format specs like {name:<6} work!" | |
| actual = f_yeah(parsed) | |
| print(f'\nversion: {sys.version_info}') | |
| assert actual == expected |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment