Skip to content

py: Implement PEP 750 t-strings using existing f-string parser (WIP)#18650

Draft
dpgeorge wants to merge 20 commits intomicropython:masterfrom
dpgeorge:py-implement-tstrings
Draft

py: Implement PEP 750 t-strings using existing f-string parser (WIP)#18650
dpgeorge wants to merge 20 commits intomicropython:masterfrom
dpgeorge:py-implement-tstrings

Conversation

@dpgeorge
Copy link
Member

@dpgeorge dpgeorge commented Jan 6, 2026

Summary

This is an alternative to #17557 which aims to implement t-strings in a more efficient way (less code size), leveraging the existing f-string parser in the lexer. It includes:

  • t-string parsing in py/lexer.c
  • new built-in __template__() function to construct t-string objects
  • new built-in Template and Interpolation classes which implement all the functionality from PEP 750
  • new built-in string module with templatelib sub-module, which contains the classes Template and Interpolation

This PR is built upon #18588.

The way it works is that an input t-string like:

t"hello {name:5}"

is converted character-by-character by the lexer/tokenizer to:

__template__(("hello ", "",), name, "name", None, "5")

(For reference, if it were an f-string it would be converted to "hello {:5}".format(name).)

Compared to #17557 which costs about +7400 bytes on stm32, this implementation costs +2844 bytes.

This is still a work-in-progress. It implements most of the t-string functionality including nested t-strings and f-strings, but there are a few corner cases yet to tidy up. I don't see any show stoppers though, and code size should hopefully not grow much more either.

Testing

All 16 tests from #17557 have been added here. So far 11 of them pass, and 1 is no longer relevant (testing runtime overflow limit which is no longer there).

Trade-offs and Alternatives

Being an alternative to #17557, it shows a different way to achieve the same end result. #17557 starts up a new parser instance each time a t-string is encountered and recursively parses the t-string, whereas the implementation here just transforms the input characters. After all, t-strings (and f-strings) are really just syntactic sugar.

This adds code size, but if t-strings are not used then there is very little execution overhead, all of which is contained to the lexer.

The changes to py/lexer.c are mildly complex, but not really much more complex than the existing f-string logic. It's just a different way of transforming the input stream.

@dpgeorge dpgeorge added the py-core Relates to py/ directory in source label Jan 6, 2026
@dpgeorge dpgeorge force-pushed the py-implement-tstrings branch 2 times, most recently from 9395826 to 7c6e8e2 Compare January 6, 2026 13:26
@codecov
Copy link

codecov bot commented Jan 6, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.45%. Comparing base (a8b7155) to head (66a56cb).

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #18650      +/-   ##
==========================================
+ Coverage   98.42%   98.45%   +0.03%     
==========================================
  Files         174      175       +1     
  Lines       22333    22639     +306     
==========================================
+ Hits        21982    22290     +308     
+ Misses        351      349       -2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@dpgeorge dpgeorge force-pushed the py-implement-tstrings branch from f103117 to 9916c48 Compare January 7, 2026 01:00
@github-actions
Copy link

github-actions bot commented Jan 7, 2026

Code size report:

Reference:  shared/readline: Handle \r and \n correctly as a newline. [a8b7155]
Comparison: docs: Document template strings module. [merge of 66a56cb]
  mpy-cross: +1864 +0.495% [incl +96(data)]
   bare-arm:    +0 +0.000% 
minimal x86:    +0 +0.000% 
   unix x64: +5848 +0.683% standard[incl +416(data)]
      stm32: +2936 +0.744% PYBV10
      esp32: +2936 +0.168% ESP32_GENERIC[incl +480(data)]
     mimxrt: +2960 +0.786% TEENSY40
        rp2: +2792 +0.304% RPI_PICO_W
       samd: +2928 +1.077% ADAFRUIT_ITSYBITSY_M4_EXPRESS
  qemu rv32: +2970 +0.651% VIRT_RV32

@dpgeorge dpgeorge force-pushed the py-implement-tstrings branch 2 times, most recently from ac21499 to e61ae6d Compare January 9, 2026 03:34
@dpgeorge dpgeorge force-pushed the py-implement-tstrings branch from e61ae6d to 4deb1fb Compare January 23, 2026 03:58
@dpgeorge dpgeorge force-pushed the py-implement-tstrings branch from 4deb1fb to 3522298 Compare February 5, 2026 00:55
koxudaxi and others added 19 commits February 16, 2026 22:34
Signed-off-by: Koudai Aono <koxudaxi@gmail.com>
Signed-off-by: Koudai Aono <koxudaxi@gmail.com>
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
This now works in MicroPython.

Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
Now OK in MicroPython.

Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
Not worth supporting.

Signed-off-by: Damien George <damien@micropython.org>
Not worth supporting.

Signed-off-by: Damien George <damien@micropython.org>
Reusing the existing f-string parser in the lexer.

Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
Should be enough for full coverage testing of `__template__()`.

Signed-off-by: Damien George <damien@micropython.org>
All the limitation tests no longer apply to the new parser.  All that's
left here are whitespace and unicode tests for the lexer, which match
CPython.  They should go in tests/basics/...

Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Koudai Aono <koxudaxi@gmail.com>
@dpgeorge dpgeorge force-pushed the py-implement-tstrings branch from 3522298 to 66a56cb Compare February 16, 2026 11:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

py-core Relates to py/ directory in source

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments