-
-
Notifications
You must be signed in to change notification settings - Fork 8.3k
py: Add PEP 750 template strings support #17557
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
base: master
Are you sure you want to change the base?
py: Add PEP 750 template strings support #17557
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #17557 +/- ##
==========================================
- Coverage 98.44% 98.44% -0.01%
==========================================
Files 171 174 +3
Lines 22192 22771 +579
==========================================
+ Hits 21847 22416 +569
- Misses 345 355 +10 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Code size report:
|
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.
Thanks for the contribution! This will be nice to have for the webassembly port.
I didn't do a review yet, but there will need to be tests to get full coverage of the new code.
@dpgeorge Thank you for the feedback and for taking time to look at this! I'm glad this will be useful for the webassembly port. I'll add more tests to ensure full coverage when I find time. |
@koxudaxi slightly off topic - but I notice you'll be at EuroPython in Prague, as will I. We should look out for each other and have a coffee or lunch together! 🇪🇺 🐍 |
@ntoll Sounds good! See you in Prague. ☕ |
7a1dc11
to
50dd4d1
Compare
I tried really hard to make 100% coverage but some code is never called and I cannot cover it. Do you know how to fix this? |
|
||
A flag for `keys()`, `values()`, `items()` methods to specify that | ||
A flag for :meth:`btree.keys`, :meth:`btree.values`, :meth:`btree.items` methods to specify that | ||
scanning should be inclusive of the end key. | ||
|
||
.. data:: DESC | ||
|
||
A flag for `keys()`, `values()`, `items()` methods to specify that | ||
A flag for :meth:`btree.keys`, :meth:`btree.values`, :meth:`btree.items` methods to specify that |
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 faced an error when building with Sphinx because it conflicted with string.templatelib.Template.values
. To solve this problem, I renamed the values attribute in btree to be more explicit.
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.
It seems like a useful change, then --- it's just not a change related to PEP-750 t-string support, so it needs to be a separate commit and separate PR.
Git cherry-pick
and rebase -i
are your friends!
@dpgeorge |
py/objtype.c
Outdated
@@ -542,7 +542,18 @@ const byte mp_binary_op_method_name[MP_BINARY_OP_NUM_RUNTIME] = { | |||
}; | |||
|
|||
static mp_obj_t instance_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { | |||
#if MICROPY_PY_TSTRINGS | |||
if (op == MP_BINARY_OP_ADD || op == MP_BINARY_OP_INPLACE_ADD) { |
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 whole bit can be removed, it's not needed. There is already a check in template_binary_op()
.
ports/unix/coverage.c
Outdated
@@ -822,6 +847,356 @@ static mp_obj_t extra_coverage(void) { | |||
MICROPY_STACK_CHECK == 0 || old_stack_limit == new_stack_limit); | |||
} | |||
|
|||
|
|||
#if MICROPY_PY_TSTRINGS |
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'm surprised all of this coverage code is needed here, in C.
You should be able to move most (if not all) of this to pure Python tests. Did you have trouble doing that?
py/modtstring.c
Outdated
mp_print_t repr_print; | ||
vstr_init_print(&repr_vstr, 16, &repr_print); | ||
mp_obj_print_helper(&repr_print, value, PRINT_REPR); | ||
conv_value = mp_obj_new_str_from_vstr(&repr_vstr); |
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.
These 3 cases for r/s/a all look the same. Can you factor the code to reduce code duplication?
py/modtstring.c
Outdated
} | ||
dest[0] = mp_obj_new_tuple(interps->len, values); | ||
} else { | ||
mp_obj_t *values = m_new(mp_obj_t, interps->len); |
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.
You can simplify the code here and not have any temporary memory by the following:
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(interps->len, NULL));
for (size_t i = 0; i < interps->len; i++) {
tuple->items[i] = interp->value;
}
dest[0] = MP_OBJ_FROM_PTR(tuple);
py/modtstring.c
Outdated
return MP_OBJ_FROM_PTR(result); | ||
} | ||
|
||
case MP_BINARY_OP_REVERSE_ADD: { |
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.
You can just remove this case
, it's not needed.
py/parse.c
Outdated
est_bytes += est_seg_cnt * sizeof(mp_parse_node_t) * 2; // Assume some growth | ||
est_bytes += est_interp_cnt * sizeof(mp_parse_node_t) * 2; | ||
|
||
if (est_bytes > MICROPY_PY_TSTRING_MAX_BYTES) { |
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 don't think this test is needed, what's wrong with the tstring growing large?
Change t-strings from being automatically enabled at EXTRA_FEATURES level to opt-in only. This prevents token number shifts in lexer that were causing CI test failures for ports that don't need t-strings. T-strings are now explicitly enabled only for: - Unix/macOS port - Windows port - WebAssembly port This keeps t-strings available for desktop environments while avoiding memory overhead and test conflicts in embedded ports. Signed-off-by: Koudai Aono <koxudaxi@gmail.com>
e5f68df
to
8ecf945
Compare
Signed-off-by: Koudai Aono <koxudaxi@gmail.com>
Change t-strings from being automatically enabled at EXTRA_FEATURES level to opt-in only. This prevents token number shifts in lexer that were causing CI test failures for ports that don't need t-strings. T-strings are now explicitly enabled only for: - Unix/macOS port - Windows port - WebAssembly port This keeps t-strings available for desktop environments while avoiding memory overhead and test conflicts in embedded ports. Signed-off-by: Koudai Aono <koxudaxi@gmail.com>
The token number changed from 16 to 17 due to t-strings being made opt-in, which shifted the token numbering scheme. Signed-off-by: Koudai Aono <koxudaxi@gmail.com>
20fbafe
to
9e6fa7d
Compare
Change {expr=:fmt} to use conversion=None instead of 's' to match the updated PEP-750 specification. Signed-off-by: Koudai Aono <koxudaxi@gmail.com>
Add tests for t-string debug specifier (=) to verify compliance with updated PEP-750 specification: - {expr=} uses conversion='r' - {expr=:fmt} uses conversion=None - {expr=!s} preserves explicit conversion Signed-off-by: Koudai Aono <koxudaxi@gmail.com>
3b55c40
to
966c931
Compare
- Make t-strings conditional on ROM_LEVEL for Unix port - Add skip_tstring check to run-tests.py Fixes test failures on minimal builds and embedded ports. Signed-off-by: Koudai Aono <koxudaxi@gmail.com>
Replace math.pi/e/sqrt(2) with integer values to avoid precision differences between single and double precision builds. Also show interpolation count and format specs instead of actual float values in the output. Signed-off-by: Koudai Aono <koxudaxi@gmail.com>
79f6712
to
51d8c21
Compare
T-strings use recursive parsing that requires significant stack space. In constrained builds (standard/standard_v2), thread tests create threads with small 2KB stacks which overflow when t-strings are enabled. This changes MICROPY_PY_TSTRINGS to only be enabled when MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES. Signed-off-by: Koudai Aono <koxudaxi@gmail.com>
5601a24
to
29245de
Compare
T-strings were failing in threads because __template__ is not in the thread's global namespace. Add special handling in mp_load_global to return the builtin __template__ directly when not found in globals, similar to how __build_class__ is handled. This fixes NameError when using t-strings in threads and also resolves the select_poll_eintr.py test failure. Signed-off-by: Koudai Aono <koxudaxi@gmail.com>
Signed-off-by: Koudai Aono <koxudaxi@gmail.com>
This commit implements PEP-750 compliant format specification evaluation for t-strings. Format specs containing expressions (e.g., {width}) are now evaluated at template creation time, matching Python 3.14 behavior. Signed-off-by: Koudai Aono <koxudaxi@gmail.com>
This commit adds extensive test coverage for escape sequence handling in t-strings to improve lexer.c coverage Signed-off-by: Koudai Aono <koxudaxi@gmail.com>
adb0c30
to
08697eb
Compare
When running in a thread context, __template__ was not being found if it wasn't in the thread's local globals. This adds a fallback to check the main thread's globals dictionary when __template__ is not found in the current globals, ensuring t-strings work correctly in threaded environments. Signed-off-by: Koudai Aono <koxudaxi@gmail.com>
__template__ is already registered as a builtin, so special handling in mp_load_global() is redundant. The select_poll_eintr.py test failure that this code was trying to fix is actually a pre-existing issue unrelated to t-strings. Signed-off-by: Koudai Aono <koxudaxi@gmail.com>
T-strings use recursive parsing which requires significant stack space. This causes thread initialization failures in constrained environments when threads create small stacks (e.g., 8-16KB). The failure manifests as NameError when accessing variables in thread functions. Signed-off-by: Koudai Aono <koxudaxi@gmail.com>
This commit fixes a critical GC vulnerability in modtstring.c where temporary arrays were allocated but not protected from garbage collection. The issue manifested as random thread initialization failures in CI environments. Signed-off-by: Koudai Aono <koxudaxi@gmail.com>
e0a7b89
to
e28b3d9
Compare
- Test empty and whitespace-only expressions in t-strings - Test format spec and conversion specifier ordering validation - Test integer overflow protection in template size calculation - Test Unicode/octal escape sequences and invalid escape handling - Test high byte values (0x80-0xFF) and lexer error states - Test memory allocation failures in expression parser - Test debug format with invalid conversion syntax - Add coverage for all error branches in t-string implementation Signed-off-by: Koudai Aono <koxudaxi@gmail.com>
e28b3d9
to
198a846
Compare
Summary
Implements PEP 750 template strings for MicroPython.
Started in discussion #17497. Template strings (t-strings) are new in Python 3.14 - they return Template objects instead of strings, so you can access the literal parts and expressions separately.
Changes:
Usage:
Testing
Tested on unix port with both MICROPY_PY_TSTRINGS enabled and disabled.
Test coverage:
All existing tests continue to pass. New tests added in
tests/basics/string_template*.py
.Ports tested: Unix (other ports need testing)
Trade-offs and Alternatives
Adds ~240 bytes when enabled on unix port. When disabled, no impact.
Worth it because:
Config: Enabled by default when MICROPY_CONFIG_ROM_LEVEL >= EXTRA_FEATURES.
Needs MICROPY_PY_FSTRINGS=1.
To disable:
make CFLAGS_EXTRA=-DMICROPY_PY_TSTRINGS=0