Python's new t-strings

Template strings, also known as t-strings, have been officially accepted as a feature in Python 3.14, which will ship in late 2025. 🎉

I’m excited; t-strings open the door to safer more flexible string processing in Python.

What’s the big idea with t-strings?

Since they were introduced in Python 3.6, f-strings have become a very popular way to format strings. They are concise, readable, and powerful.

In fact, they’re so delightful that many developers use f-strings for everything… even when they shouldn’t!

Alas, f-strings are often dangerously (mis)used to format strings that contain user input. I’ve seen f-strings used for SQL (f"SELECT * FROM users WHERE name = '{user_name}'") and for HTML (f"<div>{user_name}</div>"). These are not safe! If user_name contains a malicious value, it can lead to SQL injection or cross-site scripting.

Template strings are a generalization of Python’s f-strings. Whereas f-strings immediately become a string, t-strings evaluate to a new type, string.templatelib.Template:

from string.templatelib import Template
name = "World"
template: Template = t"Hello {name}!"

Importantly, Template instances are not strings. The Template type does not provide its own __str__() implementation, which is to say that calling str(my_template) does not return a useful value. Templates must be processed before they can be used; that processing code can be written by the developer or provided by a library and can safely escape the dynamic content.

We can imagine a library that provides an html() function that takes a Template and returns a safely escaped string:

evil = "<script>alert('bad')</script>"
template = t"<p>{evil}</p>"
safe = html(template)
assert safe == "<p>&lt;script&gt;alert('bad')&lt;/script&gt;</p>"

Of course, t-strings are useful for more than just safety; they also allow for more flexible string processing. For example, that html() function could return a new type, HTMLElement. It could also accept all sorts of useful substitutions in the HTML itself:

attributes = {"src": "roquefort.jpg", "alt": "Yum"}
template = t"<img {attributes} />"
element = html(template)
assert str(element) == "<img src='roquefort.jpg' alt='Yum' />"

If you’ve worked with JavaScript, t-strings may feel familiar. They are the pythonic parallel to JavaScript’s tagged templates.

How do I work with t-strings?

To support processing, Templates give developers access to the string and its interpolated values before they are combined into a final string.

The .strings and .values properties of a Template return tuples:

name = "World"
template = t"Hello {name}!"
assert template.strings == ("Hello ", "!")
assert template.values == (name,)

There is always one more (possibly empty) string than value. That is, t"".strings == ("",) and t"{name}".strings == ("", "").

As a shortcut, it’s also possible to iterate over a Template:

name = "World"
template = t"Hello {name}!"
contents = list(template)
assert contents[0] == "Hello "
assert contents[1].value == name
assert contents[2] == "!"

Developers writing complex processing code can also access the gory details of each interpolation:

name = "World"
template = t"Hello {name!s:>8}!"
assert template.interpolations[0].value == name
assert template.interpolations[0].expression == "name"
assert template.interpolations[0].conversion == "s"
assert template.interpolations[0].format_spec == ">8"

In addition to supporting the literal (t"foo") form, Templates can also be instantiated directly:

from string.templatelib import Template, Interpolation
template = Template(
	"Hello ",
	Interpolation(value="World", expression="name"),
	"!"
)

Strings and interpolations can be provided to the Template constructor in any order.

A simple t-string example

Let’s say we wanted to write code to convert all substituted words into pig latin. All it takes is a simple function:

def pig_latin(template: Template) -> str:
	"""Convert a Template to pig latin."""
	result = []
	for item in template:
		if isinstance(item, str):
			result.append(item)
		else:
			word = item.value
			if word and word[0] in "aeiou":
				result.append(word + "yay")
			else:
				result.append(word[1:] + word[0] + "ay")
	return "".join(result)

name = "world"
template = t"Hello {name}!"
assert pig_latin(template) == "Hello orldway!"

This is a goofy example; if you’d like to see some less silly examples, check out the PEP 750 examples repository.

What’s next once t-strings ship?

T-strings are a powerful new feature that will make Python string processing safer and more flexible. I hope to see them used in all sorts of libraries and frameworks, especially those that deal with user input.

In addition, I hope that the tooling ecosystem will adapt to support t-strings. For instance, I’d love to see black and ruff format t-string contents, and vscode color those contents, if they’re a common type like HTML or SQL.

It’s been fun to get to know and work with Jim, Paul, Koudai, Lysandros, and Guido on this project and to interact with many more members of the Python community online without whose input PEP 750 simply wouldn’t have come together. I can’t wait to see what developers build with t-strings once they ship!

Antirez is back with a short list of how we’re destroying software. A few excerpts:

We are destroying software with complex build systems.

We are destroying software pushing for rewrites of things that work.

We are destroying software trying to produce code as fast as possible, not as well designed as possible.

I dunno. It seems like it was ever thus. We’ve always layered on terrible leaky abstractions and built unfriendly brittle tools. We’ve always needlessly rewritten systems that work just fine. We’ve always rushed to get it out the door now, not out the door right.

But I do want to call this one out:

We are destroying software mistaking it for a purely engineering discipline.

So much this. People and politics and life are so much a part of software. The tools we build reflect our values and beliefs. They enable others to promote and entrench their values and beliefs, whether for good or for ill. Let’s work to make it for good.

Welp. He’s back.

Yesterday, like all incoming presidents, Trump signed a barrage of executive orders. Unlike other incoming presidents, many of his actions were bizarre, unlawful, or outright unconstitutional. Lawfare remains my go-to source for both cautious analysis and original documents.

From where I sit, the one truly terrifying action Trump took yesterday was pardoning or commuting the terms of every January 6th insurrectionist. What better way to buy the loyalty of his most violent supporters? What better way to ensure future violence should such violence serve his needs?

Small tech in 2025

Big tech can fend for itself. For me, small tech — home to all manner of creative computer weirdos — is where the fun is at. Here are some trends I’m keeping an eye on:

The open social web

The open social web hit its stride in 2024. Idealists and software nerds got organized: the Social Web Foundation emerged to steward the ActivityPub ecosystem, Free Our Feeds started holding ATProto’s feet to the decentralized fire, and A New Social began building bridges between open networks. Independent researchers brought focus to the challenges of decentralized governance while nonprofits developed new resources for federated moderation. And, in early 2025, Mastodon took big steps toward community ownership.

Creative tinkerers have leveraged the social web’s openness to build interesting indie businesses. Surf.social ships an innovative UI for exploring open social content. Murmel sends top stories from your feed directly to your inbox. Mastohost makes it easy to self-host Mastodon. And Micro.blog continues to thoughtfully explore new directions.

Novel use of large language models

While big tech spins its wheels on “agentic” AI hype, small tech is discovering creative and force-multiplying new uses for LLMs.

Researchers like Amelia Wattenberger, Linus Lee, Tony Beltramelli, Maggie Appleton, and Shawn Wang are all exploring LLM-powered user experiences built on tight feedback loops. My favorite of these interface prototypes avoid chat-like interactions entirely, instead hiding LLMs gently in the background. Gestures lead to LLM invocations, which lead to the further evolution of the interface.

Meanwhile, services like CityMeetings.nyc show the potential for LLMs to transmute piles of unstructured content into actionable insight. CityMeetings breaks down every New York City Council meeting into easily readable and linkable digests. It has become an essential tool for local journalists. Impressively, CityMeetings is a one-person project!

Small tech is (of course!) full of indie devs, who naturally experiment with LLMs for their own software development. AI code assistants like GitHub Copilot are now omnipresent, and editor workflow innovations from Cursor and Windsurf AI, along with chat UX features like Anthropic’s Artifacts, suggest where tools might go next. Small tech startups like Val Town have learned from these patterns and introduced their own bespoke AI tools for developers.

Experiments in local-first

The small tech community has a long history of building tools that prioritize user agency and privacy. That’s why, when Martin Kleppmann and Adam Wiggins introduced the idea of “local-first software” architecture, the community paid attention. Local-first applications store data locally, work offline, and sync with other devices when possible — aligning nicely with the ethos of small tech and the open social web.

In his fun-to-read predictions for 2025, Tom MacWright anticipates that “local-first will have a breakthrough moment”. The technical challenges — building sync engines, resolving conflicts, and managing schema migrations — remain substantial, so I don’t expect to see a true market breakthrough. That said, new frameworks like Zero, Electric, and Jazz show that indie devs will keep pushing the envelope.

Sustainable and small

I’m always drawn to indie software shops that eschew “traditional” VC financing in favor of a focus on sustainable growth and personal independence. I’m delighted by the sheer amount of technical depth, art, whimsy, and nerdy joy I’m seeing from today’s crop of small tech startups. Creative experimentation is alive and well. While big tech keeps embiggening, small tech is quietly shaping a more humane and thoughtful future.

Decompression

It was unexpectedly sunny in Seattle today. The trails and parks were full. Perhaps we were all decompressing.

Even with the ample sun and fresh air, it was impossible not to dwell:

We can say it was about the economy. We can say it was (sigh) about immigrants taking jobs and importing crime. We can say it was about misogyny and racism.

It was about these things, to some degree.

But I think they also miss the mark. As I write, the GOP looks poised to sweep it all: the popular vote, both houses of Congress, everything.

I see this election as a resounding affirmative vote for Trump and Trumpism. I see it as a strident repudiation of much that came before, the political order of America since at least the Reagan administration. I see it as a statement that our norms and our mores and our rule of law no longer matter except to a minority of us.

America is changed. Mending it will require the work not of another election, but of an entire generation.

If you’re a U.S. citizen: vote for Kamala Harris.

I don’t think I need to say more. Just vote.

PEP 750: Template Strings proposes a new addition to the Python programming language that generalizes f-strings. Unlike f-strings, t-strings evaluate to a new type, Template, that provides access to the string and its interpolated values before they are combined:

name = "World"
template: Template = t"Hello {name}"
assert template.args[0] == "Hello "
assert template.args[1].value == "World"

This opens the door to a variety of new use cases. The proposal is currently in the draft stage and open for feedback.

Took a four-day trip to Iceland. What a beautiful place. A quick photo summary:

Seljalandsfoss WaterfallSeljalandsfoss WaterfallSnowfall PeninsulaAurora in IcelandSnowfall PeninsulaSeljalandsfoss WaterfallKirkjufellsfoss WaterfallAurora in Iceland

I knew that Captain Grace Hopper was an early pioneer in computer programming who just so happened to discover and document the first ever computer bug — a literal moth!

But I’d never seen a video of her before.

Yesterday, the NSA declassified a lecture Hopper gave in 1982 at the age of 75.

It’s astonishingly prescient. She likens that moment to the days just after Ford introduced the Model T and changed the face of the country forever:

I can remember when Riverside Drive in New York City, along the Hudson River, was a dirt road. And on Sunday afternoons, as a family, we would go out on the drive and watch all the beautiful horses and carriages go by. In a whole afternoon, there might be one car.

Whether you recognize it or not, the Model Ts of the computer industry are here. We’ve been through the preliminaries of the industry. We are now at the beginnings of what will be the largest industry in the United States.

But with the Model T came unintended consequences; Hopper foresaw the same for the computer age:

I’m quite worried about something.

When we built all those roads, and the shopping centers, and all the other things, and provided for automobile transportation… we forgot something. We forgot transportation as a whole. We only looked at the automobile. Because of that, when we need them again, the beds of the railroads are falling apart. […] If we want to move our tanks from the center of the country to the ports to ship them overseas, there are no flat cars left. […] The truth of the matter is, we’ve done a lousy job of managing transportation as a whole.

Now as we come to the world of the microcomputer, I think we’re facing the same possibility. I’m afraid we will continue to buy pieces of hardware and then put programs on them, when what we should be doing is looking at the underlying thing, which is the total flow of information through any organization, activity, or company. We should be looking at the information flow and then selecting the computers to implement that flow.