Skip to content

Add inference for t-strings - #3120

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

Add inference for t-strings#3120
Pierre-Sassoulas wants to merge 3 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 (631a3aa) with main (da4a8cf)

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.74%. Comparing base (da4a8cf) to head (631a3aa).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #3120      +/-   ##
==========================================
+ Coverage   93.67%   93.74%   +0.07%     
==========================================
  Files          93       94       +1     
  Lines       11645    11760     +115     
==========================================
+ Hits        10908    11024     +116     
+ Misses        737      736       -1     
Flag Coverage Δ
linux 93.60% <100.00%> (+0.07%) ⬆️
pypy 93.74% <100.00%> (+0.07%) ⬆️
windows 93.71% <100.00%> (+0.07%) ⬆️

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.30% <100.00%> (+0.16%) ⬆️
astroid/nodes/as_string.py 97.37% <100.00%> (ø)
astroid/nodes/node_classes.py 95.37% <100.00%> (+0.04%) ⬆️
astroid/objects.py 95.87% <100.00%> (+1.35%) ⬆️

... and 1 file with indirect coverage changes

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

Pierre-Sassoulas and others added 2 commits July 4, 2026 14:03
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