Deploy Your App: Announcing the Talk Python in Production book.

t-strings in Python (PEP 750)

Episode #505, published Tue, May 13, 2025, recorded Tue, May 13, 2025

Guests and sponsors
Python has many string formatting styles which have been added to the language over the years. Early Python used the % operator to injected formatted values into strings. And we have string.format() which offers several powerful styles. Both were verbose and indirect, so f-strings were added in Python 3.6. But these f-strings lacked security features (think little bobby tables) and they manifested as fully-formed strings to runtime code. Today we talk about the next evolution of Python string formatting for advanced use-cases (SQL, HTML, DSLs, etc): t-strings. We have Paul Everitt, David Peck, and Jim Baker on the show to introduce this upcoming new language feature.

Watch this episode on YouTube
Play on YouTube
Watch the live stream version

Episode Deep Dive

Guests introduction and background

Paul Everett is the Head of Developer Advocacy at JetBrains. He has worked extensively with Python, is passionate about modern web development in Python, and was heavily involved in shaping t-strings.

Jim Baker is a longtime Python contributor and former lead developer of Jython. He has extensive experience in compilers, language internals, and has taught programming languages at the University of Colorado Boulder.

Dave Peck is a freelance software developer from Seattle. He worked on t-strings alongside Paul and Jim, bringing a deep interest in practical applications such as HTML templating, logging, and more.

What to Know If You're New to Python

If you're just starting your Python journey and want to follow this t-strings conversation closely, here are some considerations:

  • Even if you don't fully grasp advanced Python features yet, remember that f-strings and now t-strings are just ways of formatting or creating strings.
  • Basic Python scoping rules (what variables are accessible where) will help you understand why t-strings needed to be part of the language.
  • A key motivator for t-strings is preventing security pitfalls like SQL injection, so even learning a few fundamentals about strings and security will be beneficial.

Key points and takeaways

  1. t-strings: A New Evolution of Python String Interpolation t-strings (proposed in PEP 750 and scheduled for Python 3.14) build on the idea of f-strings to produce a template object rather than a standard string. This object retains the structure of static text plus code expressions. By not evaluating directly to a traditional string, t-strings provide a safe and robust way to handle advanced use cases like SQL, HTML, or other domains. This next step in string handling is meant to be intuitive while avoiding injection pitfalls.
  2. Differences from f-strings While f-strings generate fully formed strings at runtime, t-strings create a specialized template object that keeps static and dynamic parts separated. This separation allows libraries to see exactly which parts are literal text and which parts are code-injected fields. The outcome is more structured and less prone to hidden security issues, since t-strings don't automatically collapse into one big string.
  3. Focus on Security and Injection Prevention One major motivation behind t-strings is preventing vulnerabilities like SQL injection (the classic "little Bobby Tables" issue) and cross-site scripting. Because the template object can identify individual interpolations, libraries can apply escaping or parameterization to each injected value. This pattern helps keep advanced string usage safe by default.
  4. t-strings Enable Domain-Specific Languages (DSLs) Python's flexible syntax has always helped build mini-languages, but t-strings take it further by preserving the structure of the string and the placeholders. Whether you want to create a specialized language for robotics commands, chat prompts for an LLM, or HTML fragments, t-strings let you parse out the dynamic parts reliably. This is especially powerful when combined with libraries like PyParsing or custom DSL tooling.
    • Tools:
      • PyParsing – library for creating DSL parsers in Python
  5. HTML and Web Templating with t-strings A key topic was applying t-strings to HTML templating for better tooling and avoiding the typical separation of "template language" vs. "Python." By offering t-strings, frameworks can parse the literal HTML pieces and the code placeholders. This means robust HTML generation without dealing with many of the quirks of existing template engines, and it integrates easily with editors, linters, and type checkers.
    • Tools / Libraries:
  6. Structured Logging Use Cases The team mentioned that t-strings allow structured logging (logging both a human-readable message and the underlying data). Instead of merging everything into a single string, t-strings keep track of the placeholders separately, so logs can store the raw data for advanced analytics. This is particularly appealing for large applications that want to parse logs more systematically.
  7. Lazy vs. Eager Evaluation Originally, some T-string proposals looked at lazy evaluation but ran into practical issues with Python's scoping, type checking, and performance. The current approach evaluates placeholders eagerly (just like f-strings), but it only produces the template object rather than a plain string. This balanced design lets you still combine t-strings with other asynchronous or lazy techniques in Python without overcomplicating the language.
  8. IDE Integration and Tooling Because t-strings use the same bracket syntax as f-strings, it's straightforward for tools like PyCharm, Black, and other editors or formatters to support them. This means code completion, highlighting of placeholders, and quick fixes can apply to t-strings, helping ensure correctness and discoverability. Once library authors adopt t-strings, advanced refactorings or error checking become possible.
    • Tools:
      • PyCharm IDE – Paul's team at JetBrains
      • Black – Automatic Python code formatter
  9. MicroPython and Web Possibilities There was excitement around bringing t-strings into MicroPython, enabling small, client-side or embedded Python systems to share the same code patterns. This synergy might pave the way for more consistent usage of t-strings across front-end Python with PyScript or MicroPython-based approaches, bridging server and client.
    • Tools:
      • MicroPython – a compact Python implementation suitable for browsers or small devices
      • PyScript – run Python in the browser
  10. Long-Term Vision for t-strings The guests envision t-strings inspiring new frameworks and libraries that unify how Python developers do templating and domain-specific tasks. They stressed that t-strings are only a first step and more proposals will emerge to standardize shared data structures or node interfaces (think HTML DOM-like objects or AST transformations). This opens the door for more cross-library compatibility in Python's ecosystem.

Interesting quotes and stories

"f-strings are great, but they can be a trap if you accidentally pass them to your database without sanitizing." -- Jim Baker

"We had so many lines of discussion around lazy evaluation, hundreds of messages, and it turned out the easiest path was to keep t-strings eager." -- Dave Peck

"For me, Python templating feels stuck in the early 2000s. t-strings let us do modern web work with just Python." -- Paul Everett

Key definitions and terms

  • T-string: A Python 3.14 feature (PEP 750) that produces a template object instead of a standard string. Retains interpolation structure for downstream processing.
  • Injection Vulnerability: A security flaw where malicious input (e.g., SQL or HTML) is combined with intended code, often leading to data breaches or code execution.
  • DSL (Domain-Specific Language): A mini-language designed for a specific kind of task (e.g., SQL, HTML, robotics commands). t-strings help preserve placeholders in these DSLs.
  • Lexical Scope: The region in code where a variable is accessible. t-strings rely on Python's lexical scoping (same as f-strings), avoiding issues with dynamic scoping hacks.

Learning resources

Here are a few places to expand your Python skill set based on the themes in this episode:

Overall takeaway

t-strings represent a major shift in how Python can handle string interpolation. By generating specialized template objects rather than raw strings, t-strings make it easier to thwart injection attacks, build dynamic HTML components, log structured data, and create domain-specific languages. Expect to see library maintainers and framework authors adopt t-strings for safer and more powerful Python coding in the near future.

Guests:
Paul on X: @paulweveritt
Paul on Mastodon: @pauleveritt@fosstodon.org
Dave Peck on Github: github.com
Jim Baker: github.com

PEP 750 – Template Strings: peps.python.org
PEP 750: Tag Strings For Writing Domain-Specific Languages: discuss.python.org
How To Teach This: peps.python.org
PEP 501 – General purpose template literal strings: peps.python.org
Python's new t-strings: davepeck.org
PyFormat: Using % and .format() for great good!: pyformat.info
flynt: A tool to automatically convert old string literal formatting to f-strings: github.com
Examples of using t-strings as defined in PEP 750: github.com
htm.py issue: github.com
Exploits of a Mom: xkcd.com
pyparsing: github.com
Watch this episode on YouTube: youtube.com
Episode transcripts: talkpython.fm

--- Stay in touch with us ---
Subscribe to Talk Python on YouTube: youtube.com
Talk Python on Bluesky: @talkpython.fm at bsky.app
Talk Python on Mastodon: talkpython
Michael on Bluesky: @mkennedy.codes at bsky.app
Michael on Mastodon: mkennedy

Episode Transcript

Collapse transcript

00:00 Python has many string formatting styles, which have been added to the language over the years.

00:04 Early Python used the percent operator to inject formatted values into strings, and we have string.format, which offers several powerful styles.

00:14 Both were verbose and indirect, so fstrings were added in Python 3.6, but these fstrings lacked security features.

00:21 Think about little bobby tables.

00:22 And they manifested as fully formed strings to run timecode.

00:26 Today, we talk about the next evolution of Python string formatting for advanced use cases.

00:32 Think SQL, HTML, DSLs, and so on.

00:35 T-strings.

00:37 We have Paul Everett, Dave Peck, and Jim Baker on the show to introduce the upcoming language feature.

00:43 This is Talk Python to Me, episode 505, recorded May 13th, 2025.

00:49 Are you ready for your host, please?

00:52 You're listening to Michael Kennedy on Talk Python to Me.

00:55 Live from Portland, Oregon, and this segment was made with Python.

01:24 Subscribe to our YouTube channel over at talkpython.fm/youtube and get notified about upcoming shows.

01:31 This episode is sponsored by Posit Connect from the makers of Shiny.

01:35 Publish, share, and deploy all of your data projects that you're creating using Python.

01:40 Streamlit, Dash, Shiny, Bokeh, FastAPI, Flask, Quarto, Reports, Dashboards, and APIs.

01:47 Posit Connect supports all of them.

01:48 Try Posit Connect for free by going to talkpython.fm/Posit, P-O-S-I-T.

01:55 And it's brought to you by Auth0.

01:57 Auth0 is an easy-to-implement, adaptable authentication and authorization platform.

02:02 Think easy user logins, social sign-on, multi-factor authentication, and robust role-based access control.

02:09 With over 30 SDKs and quick starts, Auth0 scales with your product at every stage.

02:15 Get 25,000 monthly active users for free at talkpython.fm/auth0.

02:22 Dave, Jim, and Paul, welcome to all three of you to Talk Python to Me.

02:26 Paul, welcome back.

02:27 Dave and Jim, welcome for the first time.

02:29 Awesome to have you here.

02:30 Thanks.

02:31 Thanks.

02:31 We are going to carry on an amazing tradition of Python string formatting.

02:38 We've had the percent.

02:40 We've had the plus.

02:41 We've had the dot format.

02:44 We've had the dot join.

02:45 Everyone was very excited about fstrings back in 3.6 when they came out.

02:49 And now, after quite a bit of work from the three of you and others, we're going to be talking about PEP 750 T-strings.

02:58 Amazing.

02:59 So congratulations on all of that.

03:01 I think it's going to be a lot of fun.

03:02 People may be surprised to think that, oh, there's an entire episode with three whole people on string formatting.

03:10 Yes.

03:10 Yes, that's right.

03:11 There's actually a lot to it.

03:12 This is a pretty rich API and a pretty big advancement.

03:16 So we're going to dive into that.

03:18 But before we do, how about a round of introductions?

03:21 Dave?

03:21 Hey, I'm Dave Peck.

03:23 I'm a freelance software developer based in sunny Seattle, Washington.

03:28 A freelance software developer is a polite way of saying I'm a computer weirdo.

03:32 And I get to get into hopefully all kinds of good computer mischief, like working with Jim and Paul on new peps for Python.

03:39 Awesome.

03:39 Great to have you here.

03:40 And always good to have another person from the Pacific Northwest.

03:44 Jim, welcome.

03:45 Hi.

03:46 So, yeah, I'm a longtime Python user.

03:50 I used to be very actively involved in the Jython project, which let me really learn the internals of both Jython and CPython, since we had to maintain a compatible implementation.

04:01 So, you know, got deep into things like compilers and the standard library.

04:07 And, yeah, it's great to talk about template strings or T-strings with you today.

04:14 Paul, welcome back.

04:15 How many episodes have you been on? Many.

04:17 I don't know. Not enough, because Brett's ahead of me.

04:21 I know.

04:22 Brett Cannon, you're not allowed to be on Talk Python for five years until I catch up, and then you can come back.

04:28 Well, you should also send your message to Anthony Shaw, who I think is currently on the leaderboard, number one.

04:34 He's been on a lot.

04:34 Yeah, and then you were talking with Chris McDonough, who was like episode three or something

04:39 like that way back in the day.

04:41 Briefly, I'm Paul. Hi, I'm Paul.

04:44 I am now head of developer advocacy at JetBrains, the PieCharm people.

04:48 I make coffee for Jim and Dave on this project.

04:52 I let Jim do all the big thinking, and I let Dave go out and explain to complainers that we heard the same complaints for F-strings back in the day.

05:02 So this has been a super fun project to be on.

05:05 Yeah, it's very exciting, and I'm super interested to dive into it.

05:10 Something I didn't really know a lot about.

05:12 Let's dive into it, right?

05:14 what are T-strings and why do they exist?

05:20 Weren't F-strings good enough?

05:21 I mean, they look kind of like F-strings when we use them.

05:23 Yeah, that's a great part about them, right?

05:25 They look like F-strings.

05:27 They behave a lot like F-strings in terms of technical issues like the scoping of the interpolation expressions, but they're not F-strings in a very profound way.

05:40 One of the things that we wanted to prevent was stuff like, you know, the classic XKCD comic about the Bobby Tables sequel injection, okay, where it becomes a drop tables inadvertently.

05:54 And we can get, yeah, exactly.

05:56 The traditional exploits of a mom.

05:58 This is your son's skull calling.

06:00 Did he break something well in a way?

06:02 Yeah.

06:03 And so this is, you know, the original language of the PEP actually referenced directly Bobby Tables in this comic.

06:11 For whatever reason, we removed that, but we don't have to do that today in this conversation.

06:17 It was a big driver for this work.

06:20 And the reason is that F-strings are great.

06:23 They're great for formatting, but they're also sort of a trap, I think, for people to use because it's you're formatting things, everything is working.

06:33 and, oh, by the way, you just introduced the HTML injection or SQL injection, or you just happen to have something that doesn't format properly because you didn't consider a particular corner case.

06:46 What we really wanted to do was move a lot of that out of the usual user experience and into a library that could go, some library, something for HTML, something for SQL, something for some other domain-specific language that would allow it to go and handle that appropriately.

07:03 We'll get into more about what that means, I guess, throughout this conversation.

07:08 But that's really where we started.

07:09 We wanted the simplicity of using f-strings.

07:14 We can get into more about what that means, but without some of the hazards.

07:18 Excellent. Excellent introduction.

07:20 And it's important that this is part of the language.

07:23 It's officially accepted in Python 3.14.

07:27 Oh, will the jokes overflow about Py, this version of Python, when it comes

07:32 out in the fall?

07:33 It's a memorative edition of Python.

07:35 We're so glad to get into it.

07:36 That's right.

07:37 It's super cool.

07:39 So it's going to be part of the language.

07:41 And the reason I bring this up is it seems like it needs to be part of the language, not just an external library, to really take advantage of it and not be just some API.

07:51 You construct strings in some weird string builder way, but through literally just, quote, start typing stuff, that has to be part of the language, right?

08:00 Yeah, that's exactly right.

08:01 I mean, as Jim mentioned, F-strings are wonderful.

08:04 The syntax is powerful, it's robust.

08:06 It became very popular because of that.

08:09 But of course, there are these foot guns of using them for, you know, SQL and HTML where you might run into some injection problems.

08:17 With T-strings, the key difference is that while F-strings evaluate to the standard string type, T-strings evaluate to a new type that's shipping in Python 3.14 later this year called template.

08:29 And so while they look like the literal form looks like any other string, they're quite different in that respect.

08:37 And the key thing about the template type is it lets you, as a programmer, decide what parts of the string were statically authored and what parts of the string were dynamically substituted or interpolated.

08:49 And so just being able to do that as a language feature is a really big deal.

08:53 It's not something you can do with fstrings directly.

08:55 And once you know those things, you can start to say, okay, this is a SQL statement.

09:00 Maybe I need to do something with the interpolation like escape its value before I construct the final string that I'm going to send over to my database.

09:07 Yeah.

09:08 If somebody were to work with an F string, it does the cool interpolation at runtime.

09:14 However, the thing that your API or any sort of code gets access to is just the resulting string that comes out.

09:23 And I think this is probably the biggest piece of understanding that people need to wrap their heads around.

09:28 And we'll dive into some of the things people do need to wrap their heads around and how it's different.

09:31 But instead of getting just here's the string result, which who knows why it says --drop table there.

09:38 Maybe that's what they want.

09:40 You don't know.

09:41 Right?

09:42 But here you would have here's part of the string.

09:44 And then here's a place where a value goes with a name.

09:47 And that thing, if you look it up by name, its value is --drop tables.

09:53 well, maybe we'll escape that or whatever.

09:55 You know what I mean?

09:56 Right.

09:57 You and Brian covered it twice in Python Bytes.

10:01 And the first time, I'm going to exaggerate a little bit, but Brian was like, what is this?

10:08 Why do we need it?

10:09 We have enough, right?

10:11 The second time, Brian was like, oh, I get it now.

10:14 There's going to be a lot of that, Paul.

10:15 And we certainly will have some explaining to you.

10:17 Yeah, there's going to be a lot of this.

10:18 As Dave said, being able to get at this.

10:21 Sorry.

10:21 What's that?

10:21 Sorry, there's going to be a lot of that.

10:23 There's going to be a lot of like, we already have f-strings.

10:24 What is this?

10:25 Yep, sure.

10:26 An F string gives you a string.

10:28 A template string gives you a template.

10:30 And then later you will get a string.

10:32 Later means going through a function.

10:34 They can go and do cool things for you like escape values.

10:38 Or you're doing an HTML templating system.

10:41 Pass it a dictionary and it will generate a style attribute with some policies along the way.

10:48 pass it a false or a Boolean and it will elide the entire thing or do all kinds of other things.

10:54 Having the template structure that Dave described gives business value DSLs a chance to step in and operate on structure rather than strings.

11:05 So when I write this code, I say value equals T, some interpolated string sort of thing. Is it interoperable with a string in the sense that if I have a function that expects a string, could I pass it? Much like path from pathlib kind of goes where string file names go,

11:23 or does the thing working with it need to know, no, it needs to be transformed, like you say, like process this to a SQL statement or process this to an HTML fragment, and then you get a string.

11:34 Yeah, and for templates, the answer is, very intentionally, they are not the same as strings. And so library authors are going to have to update their SQL libraries and their HTML libraries to expect this new template type.

11:49 And that's very intentional.

11:50 The other thing I would say is that templates don't have a direct route to strings.

11:54 So if you call str of template, you just get the default repper back, right?

12:00 Which is probably not something you want to be showing your users or it's not HTML that you're trying to render.

12:06 And that, again, is very intentional.

12:08 It's also unlikely to cause injection attacks and whatnot as well.

12:12 you're getting that reference. So much, you know, all those parentheses and braces and whatnot, not likely to happen.

12:19 Yeah, absolutely. And so library authors will have to update their libraries to add new methods that expect this template type. And presumably those methods won't also take a string. You know, if you're concerned about injection vulnerabilities, presumably you want to take this new dynamic template type that tracks what parts of the string are interpolated and what parts came from the developer themselves.

12:41 Right. And treat them differently. Yeah. Yeah. Very interesting. So let's just talk about that a little bit. I see some use cases in the chat, but maybe we could list out some more. So for example, Nym4 says structured logging, preventing cross-site scripting, SQL injection. What are some of the motivations here?

13:01 Yeah, those are all great use cases. Any type of injection vulnerability. So SQL and HTML were obviously at the top of our minds.

13:09 But another one that, in fact, there's potentially a new PEP coming around for that's being discussed right now on the Python discussion boards has to do with command injection.

13:20 So when you shell out, you're worried about the user-provided values there as well.

13:26 Give me a sec.

13:27 I'll try and remember what the actual PEP number is.

13:29 There's os.system, and then you can give it a command like echo some string from the user.

13:35 But it could, of course, be some string, quote, ampersand, ampersand, rm-rf,

13:41 or something like that, right?

13:44 And of course, as Paul mentioned, once you have the tools to help you prevent injection vulnerabilities in sort of a more general way in this general purpose fashion, you also have the ability to do all kinds of other fun and powerful things like what Paul mentioned with HTML, which is, hey, I don't just want to write, you know, a single attribute.

14:02 I want to give you a dictionary and you write 20 attributes based on the contents of my Python dictionary.

14:08 And there's no reason you can't do that now, which is exciting.

14:11 Yeah, I would add to that if you wanted to, for example, do some interesting complex analytical SQL, where you're using common table expressions, or even you just want to go and have your analytical SQL.

14:27 I want to be able to do it on this column name versus some other column name.

14:30 We want to make it possible to do that in a safe fashion.

14:34 These are things that are difficult to express with some of the typical wrappers that we might use with SQL, like SQLAlchemy.

14:43 Maybe like, I don't think you can really do like CTEs and Django query sets and whatnot.

14:48 But what I'm trying to say is that both of those tools do allow you to access raw SQL.

14:53 But now you need to be able to compose that raw SQL in a way that's safe.

14:57 and uses the information about where this interpolation is happening in order to properly put it in place.

15:06 So if you are in a situation where maybe that CTE is something you can access, you can go and say, okay, I can insert it into the SQL or maybe a little more common usage here for a lot of people.

15:20 I don't know how many people use common table expressions.

15:22 I do.

15:22 is to go and, you know, I just want to, again, select from this particular table name or this particular column name in a safe fashion. Or I want to go and use values that can't be properly expressed with placeholders. But maybe if I use like a, you know, a temporary table to insert it in. These are all techniques that we use when we do this sort of work. But now we have this opportunity to bring it into directly in the library and then make it possible for users to use it without really having to think, where did this come from? How do I go and make this such that it can be used in a where in clause, for example, that sort of thing.

16:02 This portion of Talk Python to Me is brought to you by the folks at Posit. Posit has made a huge investment in the Python community lately. Known originally for our studio, they've been building out a suite of tools and services for Team Python. Today, I want to focus on hosting your Python-based data science workloads. This includes dashboards, reports, plots, interactive web apps, all the way to custom Flask and Django apps. Their service is Posit Connect. Posit Connect makes it easy for data scientists to share work built with Python code. If you have a Streamlit app, Dash, dashboard, Plotly interactive plot, a FastAPI service, or even a Quarto report, just give Posit Connect the code it needs to maintain the asset and Connect automatically does the rest. Connect will manage your APIs and serve your interactive apps for you. And if you want, you can update your reports and dashboards on a scheduled basis. That's right. No need to explain to the stakeholders why that dashboard or plot stopped updating last week. You get to focus on your data science and leveraging your skill set while Connect makes you look good, keeping your code running and private.

17:11 With Connect, you get a private URL on your Connect server, ensuring that your asset is continuously available to your shareholders. And you can control which users have access to the asset. Let Posit Connect handle the delivery and DevOps involved in sharing your work.

17:26 You focus on what you do best. So if you work on a data science team, you owe it to you and your org to check out Posit Connect. Visit talkpython.fm/connect today and get a three-month free trial to see if it's a good fit. That's talkpython.fm/connect. The link is in your podcast player show notes. Thank you, Deposit, for supporting Talk Python To Me.

17:50 If I may, real quick, I got to give Jim a lot of credit on this as we've gone through the years on this. And Jim taught programming languages at University of Colorado Boulder. And so he knows all these patterns and all these languages and the implementations from his Jython years and stuff. And even now, he's still talking in chat about, hey, you know, Last year he was talking about how domain-specific languages could apply to Pandas and other data science stuff.

18:18 And now he's talking about LLM interactions and chat and stuff like that, where you've got a little language, but it's got a little bit of structure.

18:27 And what if you could, and then 500, you know, Discord messages later, Jim has invented something new and interesting.

18:38 So it seems to me like there's also some interesting possibilities for like lazy evaluation for also some possibilities for like query optimization.

18:50 You know, Jim was talking about databases, but there's a lot of different things, both from a performance perspective, but also potentially just from a tightly versus loosely coupled systems.

19:01 Like maybe you could say something to the effect of like, and the username goes here, but that part of the system logging doesn't know what the username is.

19:08 But somehow as the template gets rendered, the additional pieces could get filled in with real details, like the IP and the username is actually this, because over here we know.

19:17 But when the logging happened, we got a template that just said, well, whatever you figure out, it goes here.

19:23 How much of those things are possible now?

19:24 Like, could you look at the structure bit of SQL and say, well, if we reorder this, or if we put something about, you know, some kind of SQL hint or something about indexes or other things in there, could you maybe get more from it?

19:38 I was thinking someone might else answer this, but I will go for this.

19:42 I mean, I think that's possible to do.

19:45 In terms, you know, often we, you know, again, if we're thinking about SQL, we would, you know, dispatch this to, you know, some sort of, you know, the internal optimizer and, you know, whatever database you're working with.

19:56 But, you know, again, the, you know, again, using the SQL example, you know, there's, there are multiple ways that you could potentially interface some, you know, more interesting, complicated ways of interacting with SQL that are kind of hard to, you know, either you can't express easily with placeholders, you know, the standard name placeholders or positional placeholders in SQL, or just, you know, basically you find people going composing SQL.

20:26 and, you know, doing it in a bad way.

20:28 But if you were to go and, you know, there's like a popular tool called SQL Glock, for example, that allows you to take SQL, re-express it as an abstract syntax tree, and then what can you do with that?

20:42 Well, you know, the interesting thing about, you know, what we do with T-Strings is it can be a front-end to such tools.

20:50 So T-Strings themselves are, you know, intentionally designed to have just this very limited, but at the same time, you know, let's say, you know, very powerful, you know, integration with Python, right? You have, you know, effectively an f-string specification of, you know, what's going to describe that template. You describe the interpolations, they can be nested and everything, but fundamentally at the end of the day, you get this template object out of it, which could be nested and whatnot, but it's still this simple, straightforward thing. And then you pass it to a function that can do interesting things with that. From a performance perspective, that's also something that we intentionally put together. I don't know, Dave, if you want to talk about that, what we did specifically for that, because I think that might be something you want to speak to.

21:39 Yeah, absolutely. Well, if you take a look at what's inside the template type, there are basically two tuples that sit there. There's a tuple called strings and a tuple called values or interpolations.

21:51 You can kind of work both ways.

21:54 And so as you might expect, the strings are the static parts that are part of the literal string that you specify.

22:00 And the values or interpolations are the dynamic parts.

22:04 And we kind of made it so that no matter how you write your literal, it's always the case that there is at least one string in that strings tuple, even if it's the empty string.

22:14 So T quote, quote, gives you a template with no interpolations, with an empty tuple for interpolations, and with just a single quote for strings. And we ensure that there's always one more string than there are values or interpolations.

22:29 And the reason we do that is that allows you to basically, the string's tuple becomes a useful cache key in many cases for memorizing. So if you process a template once with your HTML function, you might sit back and say, okay, I've seen this structure of HTML before, and the next time I do it, all I need to do is fill in the gaps. And so that we think is just like a really basic optimization that you can use. And we're seeing that use, Paul, you might want to mention the TDOM library that I know you and others have been working on in the last little while. But it's just a basic optimization that we can offer. I think it is worth calling out, though, that, and I know we mentioned this earlier, but probably worth calling out once more just to make it explicit, that T strings like f strings are eagerly evaluated, right? So if you have hello,

23:22 curly braces name, and name isn't in scope, you will get a name error just like with an f string.

23:29 And so you might say, well, that feels a little weird to me because don't I want to reuse these things multiple times? And this is one of those cases where the word template is just an overloaded term in the computing world. And so if you're coming from the Jinja world or the Django templates world, you're probably used to the idea that I have this structure and I'm going to keep substituting values into it.

23:50 And that's a little bit different than the other use of the word template, which comes from, say, the JavaScript side of the world.

23:56 So JavaScript has tag template literals.

23:58 If you've written any JavaScript code, you've probably run across them before.

24:03 And there, like with T-strings, they're eagerly evaluated.

24:07 So, you know, of course, you have the full generality of Python available to you.

24:10 So you can just write a function that takes the parameters that you want to substitute and returns a T string, call it multiple times with different values, and you'll get different template instances out the other side.

24:20 Probably just worth calling that out so that it's clear to listeners that there is this kind of funny overloading the word template.

24:27 But yeah, back to the point about optimization.

24:30 We're pretty excited about just the basic opportunities for building optimized template processing code, like an HTML function or a SQL function that works on top of this basic structure that we provide in PEP 750.

24:45 Yeah, and I think one thing you can think about is, again, we may be getting a little too into the weeds here, but let's get into the weeds.

24:55 You can think about the template as basically providing this interesting way of describing your arguments.

25:03 And then you pass it to some sort of function, HTML, SQL, you name it.

25:09 And basically, it's going to evaluate with respect to those arguments.

25:13 But, you know, if you, so we basically, you know, if I have an HTML function, I'm going to want to look it up with that dot strings, template dot strings.

25:27 Say I parsed this and I know how to go and work with this fragment.

25:31 I already know where all the pieces need to go, the holes that need to be filled in by these interpolations, and it could be done very quickly.

25:41 And so we've put a lot of effort in terms of thinking about what is that optimization path.

25:46 And there's also related aspects.

25:48 Why is this another reason this is built into the language is because you can get lexical scope as opposed to dynamic scope.

25:56 You think that lexical, you know, you might think that dynamic scope is always the thing that's going to work for you.

26:01 But no, this is the thing that brought Paul and I together on this project.

26:04 It's exactly, you know, you can't use dynamic scope when you would expect it.

26:10 So, yeah, if we want to go to that scope issue when calling components from list comprehension.

26:16 So, Paul, if you want to speak to this a little bit, those are the problems you experienced.

26:21 Sure. And this is, oh, my gosh, Jim in the first round of this and Dave in the second round of this in the PEP and the comments.

26:31 This this damn thing had more comments on it than every other PEP in the history of civilization.

26:37 Almost it felt that way.

26:39 Major changes between the first draft and the second draft from lazy evaluation, tag template functions, all those things.

26:46 But one that comes up pretty frequently is I could just do this with this script frame.

26:52 And you can, but you can't and you shouldn't either way.

26:56 But there is a nuance about scoping that bit me right here on the screen in this ticket that was the origin story of Gemini talking to each other.

27:06 2020, a predecessor that mimicked T-strings in sysget frame from the people behind the JavaScript package called HTM. They did a port to Python called HTMPy for doing powerful template languages kind of closer to the language, something that in the JavaScript world, this is a replacement for JSX. It doesn't need tooling. And so they wanted to bring that kind of experience, language-centric templating. They wanted to bring it to Python, but hit this issue about scope.

27:39 Yeah. And it seems like it's just this obscure thing, but it isn't. You know, you use a nested function, it pops up. Use a generator expression, it pops up. Use a list comprehension, it pops up. So things that you might commonly want to use, now you need to know you shouldn't do that. So that's one thing. The second thing is it's slow. And it basically also breaks

27:59 a lot of optimizations that have been introduced into Python in recent years.

28:04 So you don't want to do that either.

28:06 By using...

28:07 And the creator of this hack, Barry said, don't use this hack.

28:10 Well, I mean, there are good reasons to go and use sysgift frame, and especially there are historical good reasons.

28:17 But I think we have, again, so it's something that comes up because, you know, if you have dug into the internals of Python, you've looked at the inspect, you know you can do certain things.

28:27 And I think that's a fantastic way to explore new capabilities.

28:32 But it is not necessarily what you want to go rely on because, again, the thing I would have taught in the class, what is the difference between dynamic and lexical scope?

28:42 Well, here's where it really bites you.

28:46 This portion of Talk Python to Me is brought to you by Auth0.

28:49 Do you struggle with authentication?

28:52 Sure, you can start with usernames and passwords.

28:54 But what about single sign-on, social auth, integration with AI agents?

28:59 It can quickly become a major time sink.

29:01 And rarely is authentication your core business.

29:05 It's just table stakes that you got to get right before you can move on to building your actual product.

29:10 That's why you should consider Auth0.

29:12 Auth0 is an easy to implement, adaptable authentication and authorization platform.

29:17 Think easy user logins, social sign-on, multi-factor authentication, and robust role-based access control.

29:24 With over 30 different SDKs and quick starts, Auth0 scales with your product at every stage.

29:31 Auth0 lets you implement secure authentication and authorization for your preferred deployment environment.

29:37 You can use all of your favorite tools and frameworks, whether it's Flask, Django, FastAPI, or something else, to manage user logins, roles, and permissions.

29:46 Leave authentication to Auth0 so that you can start focusing on the features your users will love.

29:51 Auth0's latest innovation, Auth4Gen AI, which is now available in developer preview.

29:56 Secure your agentic apps and integrate with the Gen AI ecosystem using features like user authentication for AI agents, token vault, async authorization, and FGA for RAG.

30:08 So if you're a Python developer or data scientist looking for an easy and powerful way to secure your applications, Get started now with up to 25,000 monthly active users for free at talkpython.fm/auth0.

30:22 That's talkpython.fm/auth0.

30:24 The link is in your podcast player's show notes.

30:26 Thank you to Auth0 for supporting the show.

30:29 Let's talk about HTML templates because I know, Paul, that was a lot of your interest in this, right?

30:34 Indeed.

30:35 Michael, you and I are like web originals, right?

30:39 You're a big fan of Chameleon.

30:41 Whenever you encounter a new web framework, the first thing you do is make a package for that that gives a

30:46 chameleon support.

30:47 That's right.

30:48 You want FastAPI, just put the FastAPI chameleon decorator on there and you're back to have proper language.

30:55 Yes.

30:56 But my feeling has been that Python web development, particularly templating, is stuck in the early 2000s.

31:05 I went and looked up recently.

31:06 I think Jinja was first released in 2008.

31:10 And there was a feeling back then that HTML and web design was something different than software.

31:17 Separation of concerns, but more importantly, separation of people.

31:21 You wanted to keep the templating people away from the software.

31:24 You've got your designers and you've got your developers and they exchanged

31:27 the CSS.

31:29 I'm going to give you this sandbox where you can't break things.

31:32 And it's going to be like Python, but not really Python.

31:36 And the world doesn't work that way anymore.

31:38 Front-end development is software.

31:41 In the JavaScript world, it's software.

31:44 It's components.

31:45 It's tooling.

31:46 It's testing.

31:48 It's all of these things where people expect powerful tooling as part of software.

31:54 We haven't.

31:54 And there have been some things starting to get into this area, but this was what I was originally interested in, what Jim and I had talked about quite a bit.

32:02 Dave comes from a similar background.

32:04 And we want, in a general sense, we want DSLs, domain-specific languages, that are closer to Python.

32:12 So when you say, here's a symbol, it's a symbol.

32:15 And you know the scoping rules because it's just Python.

32:18 It isn't some invented scoping rule.

32:20 And you can use your formatter on it.

32:23 And you can use mypy on it.

32:24 And you can use all blah, blah, blah.

32:26 You can get IDE assistance on it because it's just Python.

32:31 And so that, from an HTML perspective and a web perspective, we're trying to move from PSP, JSP, PHP-style templating as a separate non-Python concern over into this new world.

32:46 Dave, how did I do on that?

32:47 Do you buy what I just said?

32:48 I absolutely buy it.

32:49 And like Paul mentioned, that's sort of how I came into this crazy rollercoaster ride, too, which is I had been working with a number of nonprofits over the last couple of years, building Python backends, doing a lot of front-end development with Python code.

33:02 and feeling like, and in particular, one of the projects I worked on a couple years ago used HTMX.

33:08 I think it was one of my first experiences with HTMX.

33:10 And for those who haven't used it, you often write big templates and then occasionally you need to send lots of little blobs of HTML back.

33:18 And it really starts to get difficult to use a tool like Jinja or a tool like Django templates to produce lots of little blobs of HTML while still keeping everything cleanly organized.

33:28 You end up with lots of sort of include statements or Jinja macros.

33:33 And those are great, powerful features, but they aren't quite as powerful as what Paul was saying, which is the full generality of the Python programming language to begin with.

33:41 And so, you know, we started resorting to using HTML builders like HTTPY in my case, but there are a few others, Dominic and others.

33:51 And those felt great, but they also felt to me like what building web stuff felt like in the JavaScript ecosystem circa 2010, right?

34:00 Before tag template strings came along and ultimately in the JavaScript world before JSX came along as well.

34:07 And so it did feel like there was really an opportunity to revisit that question.

34:10 And that's sort of how I found Jim and Paul, who were thinking about this stuff and have been thinking about this stuff for far longer than I in the Python ecosystem.

34:19 Yeah, very neat.

34:19 I pulled up an example from Vue.js.

34:22 And Dave, you mentioned HTMX.

34:25 And one of the big ideas that Carson Gross from HTMX promotes is locality of behavior.

34:32 Like I should be able to look kind of here on my editor and see all the stuff's going on.

34:37 There shouldn't be four different places and then a convention that pulls in a fifth place that then makes a thing happen.

34:42 And there's a lot of that in the JavaScript world of like, well, here's your behavior.

34:47 And literally, here's the fragment of HTML that we're going to work on with capturing values and different substitutions and stuff.

34:55 And it feels like new templating, and by templating, you're the one who said this silver letter, right?

35:00 Yeah.

35:00 New templating options like Chameleon 2 or Jinja 3 or whatever could come along and build on the ideas using some of the things here.

35:11 Yeah, absolutely.

35:12 And I'm really hoping we see an explosion of that as after Python 3.14 ships out the door.

35:18 So a lot of this work that the three of you plus others, I want to be super clear that there are other folks at the top of this PEP here.

35:26 Yes.

35:27 About this who have also put a lot of work into it.

35:30 Yeah, not just at the top of the pep, but also, of course, the broader Python community in the discussions without which.

35:37 And then Paul mentioned the discussions are longer than for any pep.

35:41 But without that community feedback, I don't think we have landed where we are now.

35:45 So if I print this, how long would this be?

35:49 How many pages?

35:51 206 pages to print the discussion of the TagStrings announcement.

35:56 And that was the first.

35:57 There were two discussions.

35:59 Even better than Novella.

36:02 Yeah, that's incredible.

36:03 Also great feedback in other locations as well that we were also really trying to respond to.

36:10 They were talking about Reddit or Hacker News.

36:14 And a lot of credit to Jim on this.

36:17 in the first round, Jim was really about lazy evaluation.

36:23 And it was part of bigger ideas about inside out or outside in rendering and streaming and generators and a lot of things connected in his brain about it.

36:34 And there was a lot of practical pushback, including Astral, about, hey, we're going to struggle to statically analyze that for Ruff.

36:41 And Jim thought about it pretty hard and talked with Dave a lot and talked with others about

36:47 rolled that back. Wow. So there's a difference between, there's a difference here between lazy, which is they're evaluated eagerly, these T-strings, but maybe, and async, right? So can we do async stuff on our strings? Like you have to call a function given a template to render text. That seems like you could just write that, yeah?

37:08 Let me unmute myself. So yeah, I mean, the basic thing here is that these are expressions that can be evaluated, right? And so just because you have a, you know, I'll go for something that's even, you know, broader than this. You look at something like, you know, common pattern like Django's query set, right? So it's lazily evaluated until you actually go and actually look at its contents. A query doesn't even happen, right? In terms of against the underlying SQL engine that you're using.

37:43 And in any event, the point is that we can have laziness where we Lambda wrap it.

37:49 That was the original idea, and there's a lot of potential value in that.

37:54 But there's also this aspect that, in general, the Python community has come up with a number of ways to incorporate laziness.

38:02 And specifically through maybe it's an interval, Maybe it's a query set that is also inevitable.

38:09 Maybe it's through the use of async expressions.

38:12 These are all expressions that can be passed around and then used by, you know, something that is evaluating with respect to that.

38:21 So T-strings don't change any of that, right?

38:24 Because, you know, if you have that expression and it's been evaluated, but it's lazily, it's been lazily so, it can still be used for however you're going to work with that template in the function that operates on it.

38:39 And I think this is just going to get at most of the things that I was thinking about when we were originally looking at this from this more lazily done way without the typing issues that ultimately we decided would make it too difficult to work with.

39:01 So I think this is just something where we looked at what is the Python ecosystem?

39:07 How have we solved these problems?

39:09 and even though there was, you know, I really wanted to go and have something that basically would allow for maybe some greater functionality along, you know, doing like a deferred or lazy type capability implicitly, you know, that can be something else.

39:26 We can bring, you know, there are discussions around like bringing in macros.

39:30 It's, you know, you could implement that using coding on your file.

39:39 I don't know where that goes.

39:40 It might even interface with what we've done with T-strings.

39:43 But the important thing is that you don't have to bring all that in in order to go and benefit from what we're doing with this.

39:52 And by simplifying what we've done, I think we've, you know, come up with something that works a lot better. And I really valued the great feedback we had from the community as far as that was concerned.

40:02 Yeah, thanks. One of the things I hear a lot mentioned throughout the conversations and the PEP and stuff is DSLs. So a domain specific language and SQL is kind of a domain specific language. But I think a lot of times people are thinking something I make that is really simple, right? Maybe I want to make a language to talk to simple robots, right? And I want to use this to construct maybe a way to talk to it that's way simpler, but easier to parse because you can say, well, here's where the where piece went or whatever, right?

40:33 You can pull them out of the interpolations and the values and stuff.

40:36 Can you guys talk to maybe some examples of what you had in mind or what might be possible there?

40:40 This is good to me.

40:41 So the Python has been a very popular tool for constructing two types of DSLs.

40:49 One would be like the internal DSL that you see in Pydantic or SymPy, that sort of thing, where it's basically taking advantage of operator overloading.

41:00 So let's put that aside.

41:02 We'll look at the other version, which is this external DSL, where we think about, again, canonically HTML, SQL being pretty large targets.

41:12 But if you look at the PyParsing project, you'll see, I don't know, how many dozens of languages it supports.

41:18 Not to mention the fact that it's straightforward to write your own grammar in it and parse it into an abstract syntax tree.

41:30 Yeah, I mean, it's just like, as it says here, the use of parsing expression grammars, you know, really makes it very straightforward to write a cursor.

41:42 So I highly recommend anyone who's like interested in writing their own toy language or maybe have greater ambitions, look into tools like this, because I think this is one of the fantastic advantages we have in the Python community is we have really great libraries like this that are widely used.

41:59 And so for your example of writing something that would interface with a robot, absolutely, absolutely.

42:06 That's something that you could express.

42:09 And you think about, would that potentially be even something where it could be useful for education, for example?

42:17 And how would it work with, again, T-strings?

42:20 Well, again, you would basically say there's this domain of things that we know from the Python space.

42:25 We're computing maybe some velocity that we want the robot to move at.

42:31 We're computing which color of brick that we want to pick up or whatever it happens to be.

42:40 And we can basically say that that's something that's happening in our Python code directly.

42:46 And then there's this language that we're using to talk to the robot.

42:50 Okay. And what it looks like in terms of the T strings is you basically are saying, okay, I'm going to go and parse this language fragment with some parser that can be made to use placeholders that will work with interpolations.

43:06 And I'm going to parse it. I'm going to get an abstract syntax tree out of that. I'm going to use that to then evaluate how I'm going to go and say, you know, send in a number or color or other information to that toy language or more ambitious language.

43:23 and then send out whatever is necessary in order to complete that communication with the system that's implementing that.

43:32 So it's going to be great for people who really love languages and want to play with them.

43:38 And again, I would start with something like PyParsing.

43:40 That was a great example of the type of tool you could use here.

43:43 Excellent.

43:44 Yeah, I'll put that link in the show notes so people can check it out.

43:47 Yeah, maybe bringing it all back home for a second or maybe just because I've got my head wrapped in building slide deck for a lightning introduction, lightning talk introduction to T-strings.

43:57 But, you know, a common use case here when you're writing code that takes a template is not returning a string, but as Jim is kind of deeply hinting at here, parsing and returning some kind of abstract syntax tree.

44:09 So in the HTML case, and you can actually find examples of this, for example, in the PEP 750 examples repository, there's an HTML function there and it has a bunch of nice features, but you're returning an HTML element back from the code that processes the T-string, you don't, in fact, have to grab a string out of a T-string right away or ever if you don't want to.

44:30 So there's an immense amount of flexibility here that we're excited to see people use.

44:35 Yeah. Dave, under your account on GitHub, Dave Peck.

44:39 Needs to move.

44:40 You know what? It's fine. It's just as good as anywhere.

44:44 You have a bunch of examples of things you might do with these.

44:49 and one of them is HTML.

44:51 People can see how that might work and so on.

44:54 And what are some of the other notable ones in here?

44:56 I know I was looking through this earlier.

44:57 Well, we wanted to show some basic examples like, hey, T-strings have a syntax that looks a lot like F-strings.

45:03 How could you build F-strings on top of T-strings?

45:05 So there is an F paren-paren method that's implemented here that just kind of helps you understand, okay, I'm writing dynamic code to do the thing that F-strings would have done at compile time anyway.

45:17 We also have a structured logging example.

45:20 And I'm excited about this, you know, structured logging that Python has shipped a logging cookbook for a long time since the Python 2.something era.

45:29 And one of the examples in that logging cookbook is structured logging, by which we mean like, hey, I want to write out a sentence or two that people can understand, that humans can read.

45:39 But I also have some values that I'm substituting in that sentence.

45:42 And I'd really like that to be written out in some schema compliant way.

45:46 And with T-strings, you can kind of do that in a really elegant way, which is to say you write the T-string once, you send it to some kind of method that expects T-strings on logging, and it emits basically the equivalent of an F-string.

46:01 So that's the human readable bit.

46:03 And then maybe it uses JSON or something to emit a structured output to a different log stream entirely.

46:09 So one of the examples in the PEP and also in this PEP 750 repo is, you know, we send the human readable stuff to standard out and we send the machine readable stuff to standard error.

46:20 And you can imagine, you know, your logging system is going to redirect those somewhere else over

46:24 time.

46:24 Yeah.

46:25 I mean, the example here, you got standard error, but you could easily do a document database with JSON as well.

46:30 And then put an index on action and say, show me all the actions taken that have this commonality in it.

46:36 Right.

46:37 and do a querying, oh, bam, rather than really error-prone, like substring matching of text or whatever, right?

46:43 Yeah, and I'm really excited about it.

46:45 You write the T-string once, and you get the benefit of both the human readable and the structured schema-compliant output, and that's really exciting to me.

46:54 Yeah, and I guess if you use Postgres, you could just put it in a JSON field as well.

46:58 Oh, yeah, we call that mullet schema, right?

47:01 It's a business up front and partying back where the last column on every table is a JSON field.

47:07 I've never heard that.

47:07 That's incredible though.

47:09 It's like, yeah, we look real formal, but don't look back there.

47:14 Got it in the ponytail today.

47:15 Yeah.

47:16 Amazing.

47:18 Okay.

47:19 One thing I wanted to cover, there's a really interesting thing from somewhere in here.

47:24 I have pulled this up, I believe.

47:26 I'll just go to the PEP.

47:27 And the PEP, there's a section that talks about how to teach this.

47:31 And I think that that's, there's just a couple of ideas here that I think would make it really interesting for helping people understand better, right?

47:39 Speaking to developers or maybe people who build libraries like web frameworks or logging libraries or something.

47:45 Who wants to kind of give us a few of the ideas here that just maybe like, I know we touched on some of them a little bit.

47:52 Yeah, I mean, I'm happy that I kind of stepped through the basics here, which is, you know, we touched on the fact that the syntax of T strings and f-strings is essentially identical.

48:01 Anytime you have an F, you can substitute with a T, but the result, the evaluated result is entirely different.

48:07 You get a string or a template, and we've kind of talked about all the reasons why you might want to do that.

48:12 I guess the key thing for developers to understand, and I'm going to divide developers into two groups here, those who use T strings and pull in like an HTML or a SQL library, for example, and don't really think much about what's going on under the hood.

48:29 For them, all they need to know is, hey, you write T of something and you send it to your SQL library and it's safe.

48:35 And you don't really need to think much more about it than that.

48:38 And then, of course, we had, sorry, but we had things like literal strings and other stuff in the type system that kind of tried to make type checkers check and

48:47 catch when that would happen.

48:49 Right. But this is more runtime catching because of the way it operates rather than, hey, it's a bad idea to do that.

48:56 But, you know, Python typing can be ignored.

48:58 So, yeah, it's probably worth mentioning the limits of that.

49:01 I mean, template and interpolation, which are new types that ship with Python 3.14, are ones that you can cons up at runtime directly.

49:09 You don't need to start with a literal.

49:11 And so you can, of course, as a developer, do all kinds of goofy stuff and cons up all sorts of malicious templates if you want to.

49:18 But generally speaking, if you're working from literals, which we sort of expect is the very common case, and you're using libraries that know about this new feature when Python 3.14 ships, generally speaking, you're staying on the safe side.

49:31 You're staying in the bright, well-lit path.

49:33 Yeah.

49:33 One of the ideas I like to think about in APIs and design of software is like falling into the pit of success or falling into the pit of despair.

49:44 You want to make it so the natural action is to fall into the pit of success and you've got to work your way out of there.

49:49 You know what I mean?

49:50 Yeah, you have to work hard to get there.

49:51 Yeah, hopefully we've found a nice balance there.

49:53 Yeah, it seems like it has.

49:55 Yeah, I mean, I think from a teaching it perspective, you know, the pit of despair is so easy to fall into with F-strings, right?

50:02 You know, so your structure logging, you know, I'm sorry, using F-strings in your logging is like, oh, I inadvertently log some passwords.

50:09 Well, that's unfortunate, right?

50:10 Or I, you know, I'm using F-strings with a SQL statement.

50:14 It's like, oh, that really worked until it didn't.

50:17 And so it's very easy to go down that into that pit of despair as you're describing.

50:21 Whereas we're hopefully making it, you know, something where you have to work a little bit, know what you're doing, in fact, in order to go and actually do something that's bad.

50:31 So, you know, I'm sure that, you know, someone can show me, you know, a couple steps that, you know, make it straightforward to get into that pit of despair.

50:42 But I don't think it would be still the most obvious thing to do.

50:45 So from a teaching perspective, we want to ensure that the most obvious thing to do is the right thing to do.

50:50 And, you know, people can build libraries, you know, an HTML function or whatever in order to ensure that is, you know, going to work with that right path.

51:01 But there's more.

51:01 I think, Paul, you know, if you wanted to go and just how to teach this, I think part of this is just like, again, things like IDE integration and things like, you know, working with lenders and whatnot.

51:13 That's also very exciting in terms of what can be done.

51:16 And for me, that's kind of the exciting part.

51:17 but there's a side about really lowering the bar for writing these functions that handle a template.

51:25 You're not going to do anything with a template yourself.

51:28 You're going to hand it to a function that's going to do something.

51:30 And it's going to return a stringable, not a string, something that can be made later into a string.

51:36 But it's the people on the other side that are going to be creating the values and the content and all that kind of stuff.

51:43 And we have a real chance here to help them.

51:45 We're not going to talk about double curly braces or single curly braces for the rest of time.

51:50 It's single curly, just that alone.

51:53 And what goes in there isn't going to be some invented language with a pipe that you send to safe or whatever.

51:59 And you got to go memorize all these rules about how do I call a macro.

52:03 It's just Python, which then means IDEs and tools and linters and formatters and type checkers all get to play a game.

52:12 Go to mypy and file a ticket asking for type checking on Jinja.

52:17 There is a ticket already and you can see their comments.

52:19 They're not that interested.

52:21 Same thing for a lot of other tools.

52:23 But if they support 3.14, they support template strings and they support f-strings and they support this kind of everything because everything is just where it's supposed to be.

52:34 And if I can go a little bit, Dave, is it okay if I go a little bit further on this riff about tooling?

52:39 Let's see, you've got some points to make.

52:41 Sorry, I'm on a roll.

52:43 I'll try to wrap it up, I promise.

52:46 This idea of a big ecosystem of tooling and all of that will give us a developer experience that's competitive again.

52:56 All of these tools can start pitching in.

52:59 I'm with the PyCharm team.

53:00 Because this is f-strings with a T, they did it just like that.

53:05 Dave did a fork of black where he got T string support basically just like that because it was a T instead of an F.

53:14 Then we can get into some more interesting things like an HTML templating library.

53:18 We are very fortunate in the world of Python to have Andrea over from JavaScript on the PyScript team.

53:25 He's written 400,000 variations of JavaScript templating engines including tag template literals.

53:32 He knows everything.

53:33 He contributed a lot to this PEP such as that alternating thing.

53:37 He's creating an HTML templating language that is browser first.

53:43 Michael, you had a Vue.js up earlier that had like at click.

53:49 There's going to be a lightning talk at PyCon about showing this in PyScript where something can run on the server and in the client and it's

53:58 nuts.

53:58 The whole thing is just...

54:00 Server rendered templates, but also client-side stuff.

54:03 Yeah, yeah, yeah, yeah.

54:05 So there is a chance for us in the world of Python, it doesn't have to be our spelling, but if we can agree to structure and intermediate representations, Dave has ideas about how HTTPY could play ball.

54:19 They can make components that we can consume.

54:21 We can make components that they can consume.

54:23 I'm really bullish on how we can change the developer experience in web development and more to be modern Python with tooling.

54:34 Dave.

54:35 I'm here for it. I'm here for it, Paul.

54:36 Yeah, I'm just going to give you a what what here.

54:39 Yeah.

54:41 Yeah.

54:41 I think if we really can unlock a language that works well on the front end, I know PyScript's come a long way, but I feel like we need a view-like thing, right?

54:52 And it sounds like work is being done.

54:54 I mean, if that comes along, there's going to be a lot of people that go, wait, we don't have to do JavaScript?

55:00 Are you serious here?

55:01 That would be pretty amazing.

55:02 Just throw in your 100K MicroPython implementation of PyScript and go off

55:07 to the races.

55:08 Go ahead, Jim.

55:09 Yeah, I was just going to say, and one other nice thing about T-strings and the fact that they look a lot like F-strings is that it's going to be a straightforward thing for us to, or I shouldn't say for us, but I think the community.

55:24 I think there will be plenty of people who can work on this, fortunately, to incorporate T-strings into MicroPython.

55:33 And now you, instead of having something that requires a somewhat heavier download in terms of CPython on the client side with PyScript, you can use MicroPython for that.

55:46 I looked into it.

55:47 It looks straightforward.

55:48 I hope that we will see that development happen sooner than later.

55:52 So a lot of opportunities to go and mix together client side and server side in some really interesting and very cool ways going forward with this work.

56:04 What an interesting angle to say, we'll add T-strings to MicroPython.

56:09 Yep, and keep that.

56:10 So that it round trips to the front end of the browser in an efficient way.

56:14 Yeah.

56:14 Yeah.

56:15 We've got a bunch of sprint days coming up with PyCon, so you never know.

56:21 Okay.

56:21 But Michael, when you mentioned that MicroPython is about 100K, which to my ears as an old school web person sounds huge, but also really tiny these days.

56:32 Like when you build, when you do the default Next.js app install, which literally does nothing but ship a static looking page to you.

56:40 Although, of course, static includes a whole bundle of React and other stuff with Next.js these days.

56:45 That's about 130K.

56:47 And that doesn't include an implementation of Python.

56:50 Yeah.

56:50 It's kind of amazing.

56:52 Yeah, and I think it's pretty comparable to other things.

56:56 I'm trying to poke around and find some examples.

56:59 But yeah, I think 100K is certainly doable on a CDN and so on.

57:04 It's a sweet spot.

57:05 Yeah.

57:06 Hey, Michael, I got one for you.

57:08 And this is one that Jim and I started talking about and others piped in.

57:12 Kudai, who's also working on this project, is doing stuff in this field.

57:17 LLMs and code that needs to generate good LLM-generated results.

57:24 If you had a template language that was closer to the language of Python and could be analyzed as such, and all the LLM and RAG tricks that people are applying to not just get code, but to get good quality code.

57:38 Is this a moment where we could invent a web development story for Python that wasn't just cool because it was browser first?

57:48 It was cool because it anticipates AI and generated code.

57:54 You know, if you can infer types and things like that because you can look into the structure of the template.

58:01 Yeah.

58:01 and know things and they are Python rules inside the curly braces instead of invented stuff, you might have a better shot at machinery.

58:10 Jim, what do you think?

58:11 You had a lot to say on this.

58:12 Yeah, I mean, I think a lot of people are looking at stuff around like in-context learning with how they work with prompts and everything.

58:22 I do think that if I'm going to send a bunch of examples to like some sort of, you know, a mini shot, but I guess a few number of shots learning, it would be really nice to do it in a very structured way and really have good support for that.

58:39 And so if you look at, you know, how people typically do this, well, they emit f-strings.

58:45 And I'm sure it works most of the time.

58:46 I just want it to work all the time.

58:49 And so I think, you know, having something that can, you know, taint that structure, maybe even do some interesting, you know, like there's some stuff around like DSPY or whatever.

59:00 I'm not certain actually how it's pronounced, but it basically does additional rounds of optimizing your in-context learning, prompting in general.

59:12 Having access to that structure might be very helpful for it.

59:15 Who knows?

59:16 I think that there's a lot of interesting opportunities in this space where we maintain this structure, we're able to reflect on it, And then use that for whatever sort of interaction we have with other systems.

59:30 And fundamentally, that's what this supports.

59:33 Because you have access to those Python structures.

59:36 You can figure out what that's supposed to be before you go and send it off to somewhere else.

59:40 So what does that mean in terms of capabilities?

59:43 It's very interesting.

59:44 Paul, when you were talking about typing earlier and then talking about mypy, it just made me realize or think, I guess I thought about it before, But reemphasize that for me, the typing is a communication tool to me, mostly through things like PyCharm, but not 100%, but mostly through the editor saying, here's what it's supposed to be here.

01:00:05 Here's what this is supposed to do.

01:00:06 So I don't have to go to definition and try to decipher it.

01:00:10 And I almost never use mypy or one of these PyRite or Pyre or, you know, you name it, because that's not my goal.

01:00:16 My goal is to add typing so that I can stay out of the docs, except when I really must.

01:00:21 And the same applies to what you share with chat and agenda code generators.

01:00:26 They can look at those types and they can see much more information and it can make them way more accurate and productive, right?

01:00:33 And I feel like this could communicate more information to them, like you were saying, so they have more structure to work with rather than just, here's a string, I don't know what it is.

01:00:43 Can I riff on that for a second?

01:00:44 Yes, riff.

01:00:45 This is all not news to Dave, who he and I are writing our lightning talks and FlaskCon talk together.

01:00:54 You're around on Friday afternoon.

01:00:56 Come see Dave.

01:00:57 Come see me.

01:00:57 It's going to be mind -blowing.

01:00:59 Lightning talks are going to be mind-blowing, too.

01:01:01 Don't they normally publish those videos from FlaskCon as well?

01:01:04 I think they do.

01:01:05 Maybe.

01:01:06 He needs help.

01:01:06 Okay.

01:01:07 Well, I'm hoping.

01:01:08 Poor David is doing 500 jobs at once.

01:01:11 Everyone support David Lord.

01:01:13 I'm going to be giving a demo in PyCharm, at least, of T-String support with interpolation autocomplete and navigation and all the PyCharm tricks, but also a experimental plugin that does component support with TDOM.

01:01:30 So it looks just like JSX, where you pass props to something and it obeys the can do not just autocomplete of the props, But if you're missing a required prop, it will know that because it looks at the function signature of the component.

01:01:46 And it will match the types of the prop.

01:01:48 If you pass a string for an int, it will squiggle you.

01:01:51 In the future, we can go further like a lot of IDs can do and extract components to be standalone, to get big components into small components, all kinds of things.

01:02:02 Once you get into the world of tooling, you know, you've got typing, you've got signatures, you've got all of these great things.

01:02:09 mouse over for doc strings and doc hints and help.

01:02:14 Lots of help.

01:02:14 That's awesome.

01:02:15 Well, I'm looking forward to it.

01:02:16 Guys, we're about out of time.

01:02:18 I want to wrap this up with one final thought here.

01:02:21 So speaking to several audiences, let's say two audiences at the moment, give us some advice for potential adopters.

01:02:28 So if I'm Sebastian from FastAPI or David from FlaskCourt or I'm some other library adopter, SQL, MicroSQLAlchemy, right?

01:02:38 Or that's audience one.

01:02:40 Audience two would just be people who thought f-strings were awesome and this is even more awesome.

01:02:45 They want to try it in their code.

01:02:46 What are some pitfalls and best practices for these folks?

01:02:49 And what are the opportunities there?

01:02:51 Well, I mean, I think, you know, in general, the fact that T strings exist doesn't mean that f-strings need to disappear tomorrow.

01:02:58 So I guess that would be the first thought I'd have for the community that isn't actively building libraries that might benefit from T string functionality, which is that the

01:03:06 tool is still useful.

01:03:07 And in fact, there are many cases where probably what you really want is an f-string rather than a t-string.

01:03:12 It's exactly these cases where you want the interpolations to do something special, whether that's prevent injunction vulnerabilities or, you know, transliterate, you know, a single dictionary into a bunch of attributes in HTML where you might want to start playing with t-strings.

01:03:29 And there, you know, I think if you're a library developer and you happen to be at PyCon, come say hello.

01:03:35 we'd love to talk to you and kind of figure out how you're thinking about adopting these.

01:03:39 I think the biggest one that came up in discussion amongst library developers that I saw was just, wait, how do I type my function?

01:03:46 So if I'm writing a SQL layer and I've got an execute method, right now that takes a string or maybe it takes, you know, Michael, you mentioned a little string.

01:03:53 It takes some variety of some special type that my library supports.

01:03:58 Should I also take a template there?

01:04:00 Should I allow a union of both?

01:04:02 Probably that's a foot gun.

01:04:03 you probably really want to think about separating these things out.

01:04:06 And so I think we'll see best practices like that kind of emerge over time.

01:04:10 Yeah, I would add a couple things.

01:04:12 One, we actually love f-strings.

01:04:16 When you look at the actual code that implements the t-string functionality in terms of like a library, like an HTML function or whatever, what do you find in there?

01:04:26 Lots of uses of f-strings to actually go and pump out the actual string that you need.

01:04:33 It's just done in this, you know, disciplined fashion that we can do because we have carefully separated out when the interpolations are being actually evaluated in that context, right?

01:04:45 Second thing to think about is in terms of like a good best practice would be, you know, if you have a T-string, you know, and you say HTML, well, I don't think HTML should just like do something there or SQL or whatever.

01:05:01 It should go and allow it to prepare, you know, a document object model or, you know, prepare a SQL query or whatever.

01:05:10 And then you execute it or render it or whatever.

01:05:14 So I would differentiate this sort of setup versus, you know, some final rendering would be a typical best practice that certainly I would recommend.

01:05:24 And there are obviously more, you know, another best practice definitely is at some point, you probably want to think about the optimization of these things, right?

01:05:33 And so we really put in some thought into how the template strings can be used as a memorization key efficiently.

01:05:43 So you can look it up in terms of an LRU cache.

01:05:46 Now, this is no different than if you looked at the internals of, say, the RE module, you know, sports regular

01:05:52 expressions.

01:05:53 Yeah.

01:05:54 You know, there is this, at one point, you actually had to go into RE compile.

01:06:00 And it's not a bad practice to do it, but if you look internally at it, it actually does the RE compile for you.

01:06:06 So you don't pay the overhead of running through this Python parse every single time.

01:06:13 Interesting. I didn't know that.

01:06:15 Yeah.

01:06:15 Yeah.

01:06:16 But the actual implementation of that in terms of running the regular expression is done through this bytecode virtual machine that's specific to regular expressions.

01:06:30 and can be very efficient.

01:06:31 So again, we'll see some of these sorts of separations where we'll think about what it means to go and have a fast path where you actually are evaluating this HTML fragment or whatever, or working with SQL.

01:06:45 And then there's some sort of, well, you have to pay the parse penalty at some point.

01:06:49 But part of paying that parsing penalty is ensuring that things are done in a safe fashion, being written out in a structured way.

01:06:58 So that's, you know, more than makes up for it compared to, again, just, you know, just using F-strings and hoping that your SQL statement didn't include, you know, in that interpolation, the Bobby tables evil injection.

01:07:13 Yeah, excellent.

01:07:14 For me, I'd say first a shout out to our PEP sponsor and the hero for the second half of all this, Lissandros, has been marvelous.

01:07:25 getting the implementation and shaping in our interface to the rest of the core team and all that kind of stuff.

01:07:30 Really fast turnaround, really joy to work with.

01:07:34 Dave and Lissandro spent a lot of time ironing out all the little things.

01:07:38 I think about this whole path since Guido and Jim sat down at a PyCon like three years ago on the implementation.

01:07:44 I think it's been, this will be like the fourth PyCon since this whole thing first started.

01:07:50 And Jim and Guido kind of laid the groundwork for where we are right now, which is T-strings is just the start.

01:07:58 T-strings by itself ain't that much.

01:08:01 And I think, Jim, you made some decisions to intentionally defer to future PEPs some of the things.

01:08:08 Jim just said about these functions that don't immediately render.

01:08:14 They prepare an intermediate representation that might later render.

01:08:18 For me, that's my interest in this PyCon.

01:08:21 Let's build a community.

01:08:22 Let's build a community around interoperability so HTPy doesn't have to spell things our way, but we can talk to each other because we agree on a node interface or something like that for a DOM representation.

01:08:34 The front-end world has gotten great value out of pluggability.

01:08:38 The Vite system, for example, is a processing chain with a documented intermediate representation.

01:08:45 It's easy to write a plug-in to go grab that and hack on it.

01:08:48 You want to turn everything into a relative URL?

01:08:51 Write a little plug-in, put it in the chain, and you'll be handed something that lets you operate on things.

01:08:57 We can do something great together.

01:08:59 We don't all have to do the XKCD to invent a new standard to replace all the other standards.

01:09:06 We can still work with Jinja.

01:09:08 We could still work with HTTPY and some of these other things, and hopefully we'll see some of that at PyCon.

01:09:14 Awesome. Thank you, guys.

01:09:16 And we're specifically recording this on a time frame that hopefully...

01:09:21 Thank you so much, Michael.

01:09:22 If people are dutiful and on top of their listening, we'll listen to this right before they go to PyCon.

01:09:28 So I would like to encourage them to reach out to all of you and maybe go to some of the lightning talks.

01:09:34 And if they have ideas, participate.

01:09:35 Because now is the time.

01:09:36 Thanks, Michael, for doing this.

01:09:38 And we're excited to meet everybody at PyCon who's heading out that way.

01:09:40 Yeah.

01:09:41 Paul, you're welcome.

01:09:41 And you too, Dave.

01:09:43 Jim, Dave, and Paul, thank you all for being here.

01:09:46 See you later.

01:09:47 All right.

01:09:47 Thanks for having us.

01:09:48 Thank you.

01:09:49 Bye-bye.

01:09:50 This has been another episode of Talk Python to Me.

01:09:54 Thank you to our sponsors.

01:09:55 Be sure to check out what they're offering.

01:09:56 It really helps support the show.

01:09:59 This episode is sponsored by Posit Connect from the makers of Shiny.

01:10:03 Publish, share, and deploy all of your data projects that you're creating using Python.

01:10:07 Streamlit, Dash, Shiny, Bokeh, FastAPI, Flask, Quarto, reports, dashboards, and APIs.

01:10:14 Posit Connect supports all of them.

01:10:16 Try Posit Connect for free by going to talkpython.fm/posit, B-O-S-I-T.

01:10:23 And it's brought to you by Auth0.

01:10:25 Auth0 is an easy-to-implement, adaptable authentication and authorization platform.

01:10:30 Think easy user login, social sign-on, multi-factor authentication, and robust role-based access control.

01:10:37 With over 30 SDKs and quick starts, Auth0 scales with your product at every stage.

01:10:43 Get 25,000 monthly active users for free at talkpython.fm/auth0.

01:10:49 Want to level up your Python?

01:10:51 We have one of the largest catalogs of Python video courses over at Talk Python.

01:10:55 Our content ranges from true beginners to deeply advanced topics like memory and async.

01:11:00 And best of all, there's not a subscription in sight.

01:11:03 Check it out for yourself at training.talkpython.fm.

01:11:05 Be sure to subscribe to the show, open your favorite podcast app, and search for Python.

01:11:10 We should be right at the top.

01:11:12 You can also find the iTunes feed at /itunes, the Google Play feed at /play, and the direct RSS feed at /rss on talkpython.fm.

01:11:21 We're live streaming most of our recordings these days.

01:11:24 If you want to be part of the show and have your comments featured on the air, be sure to subscribe to our YouTube channel at talkpython.fm/youtube.

01:11:32 This is your host, Michael Kennedy.

01:11:34 Thanks so much for listening.

01:11:35 I really appreciate it.

01:11:36 Now get out there and write some Python code.

Talk Python's Mastodon Michael Kennedy's Mastodon