Skip to content

Add inference for t-strings#3120

Draft
Pierre-Sassoulas wants to merge 2 commits into
mainfrom
template-string-inference-2789
Draft

Add inference for t-strings#3120
Pierre-Sassoulas wants to merge 2 commits into
mainfrom
template-string-inference-2789

Conversation

@Pierre-Sassoulas

Copy link
Copy Markdown
Member

Type of Changes

Type
✨ New feature

Description

A t-string is now inferred as an instance of
string.templatelib.Template, and an interpolation field as an instance of string.templatelib.Interpolation, rather than raising or inferring as str (unlike f-strings / JoinedStr).

The Template/Interpolation members are reconstructed from the actual template contents, mirroring the PEP 750 runtime semantics: Template.strings/values/interpolations and
Interpolation.value/expression/conversion/format_spec infer to the same values produced at runtime. This is implemented with dedicated TemplateStrInstance / InterpolationInstance objects backed by TemplateStrModel / InterpolationModel object models, in the same way DictInstance/ExceptionInstance expose synthetic members.

The standard library defines Template and Interpolation via type(t"..."), which is not statically inferable. A new brain plugin (brain_string) rebuilds the real classes from the live objects via InspectBuilder, so they resolve to ClassDef nodes with the genuine PEP 750 API instead of a hand-written stub.

Also fix as_string for TemplateStr to double literal braces and use repr-based escaping in the constant parts, mirroring JoinedStr, so the rendered code round-trips.

Closes #2789

A t-string is now inferred as an instance of
string.templatelib.Template, and an interpolation field as an instance
of string.templatelib.Interpolation, rather than raising or inferring
as str (unlike f-strings / JoinedStr).

The Template/Interpolation members are reconstructed from the actual
template contents, mirroring the PEP 750 runtime semantics:
Template.strings/values/interpolations and
Interpolation.value/expression/conversion/format_spec infer to the same
values produced at runtime. This is implemented with dedicated
TemplateStrInstance / InterpolationInstance objects backed by
TemplateStrModel / InterpolationModel object models, in the same way
DictInstance/ExceptionInstance expose synthetic members.

The standard library defines Template and Interpolation via
type(t"..."), which is not statically inferable. A new brain plugin
(brain_string) rebuilds the real classes from the live objects via
InspectBuilder, so they resolve to ClassDef nodes with the genuine
PEP 750 API instead of a hand-written stub.

Also fix as_string for TemplateStr to double literal braces and use
repr-based escaping in the constant parts, mirroring JoinedStr, so the
rendered code round-trips.

Closes #2789
@Pierre-Sassoulas Pierre-Sassoulas added the Enhancement ✨ Improvement to a component label Jun 28, 2026
@codspeed-hq

codspeed-hq Bot commented Jun 28, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 3 untouched benchmarks
⏩ 1 skipped benchmark1


Comparing template-string-inference-2789 (38be72a) with main (fe29fb1)

Open in CodSpeed

Footnotes

  1. 1 benchmark was skipped, so the baseline result was used instead. If it was deleted from the codebase, click here and archive it to remove it from the performance reports.

@codecov

codecov Bot commented Jun 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.68%. Comparing base (279500b) to head (38be72a).
⚠️ Report is 7 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #3120      +/-   ##
==========================================
+ Coverage   93.60%   93.68%   +0.08%     
==========================================
  Files          92       93       +1     
  Lines       11381    11496     +115     
==========================================
+ Hits        10653    10770     +117     
+ Misses        728      726       -2     
Flag Coverage Δ
linux 93.55% <100.00%> (+0.08%) ⬆️
pypy 93.68% <100.00%> (+0.08%) ⬆️
windows 93.65% <100.00%> (+0.08%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
astroid/brain/brain_string.py 100.00% <100.00%> (ø)
astroid/brain/helpers.py 100.00% <100.00%> (ø)
astroid/interpreter/objectmodel.py 96.28% <100.00%> (+0.16%) ⬆️
astroid/nodes/as_string.py 97.05% <100.00%> (ø)
astroid/nodes/node_classes.py 95.32% <100.00%> (+0.17%) ⬆️
astroid/objects.py 95.87% <100.00%> (+1.35%) ⬆️

... and 4 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

The generator pauses at yield util.Uninferable, so the tests
exhaust it with list() to also execute the return lines.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Enhancement ✨ Improvement to a component

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TemplateString: Proper inference similar to JoinedStr._infer and additional tests for the as_string()

1 participant