1 00:00:05,239 --> 00:00:07,259 [music] 2 00:00:09,825 --> 00:00:11,845 [music] 3 00:00:15,120 --> 00:00:17,440 So our next talk is called disentangling 4 00:00:17,440 --> 00:00:20,080 formatted strings with T-strings. So if 5 00:00:20,080 --> 00:00:21,199 you could put your hands together and 6 00:00:21,199 --> 00:00:25,600 give Simon a warm welcome. [applause] 7 00:00:33,040 --> 00:00:35,440 Kira Brisben and Pyon Au. I'm delighted 8 00:00:35,440 --> 00:00:38,239 to be here with you this afternoon. 9 00:00:38,239 --> 00:00:40,640 My name is Simon. Uh I live in Otahi 10 00:00:40,640 --> 00:00:42,480 Christ Church in the South Island of New 11 00:00:42,480 --> 00:00:44,559 Zealand where you will find me up a 12 00:00:44,559 --> 00:00:46,879 mountain or down a white water river. 13 00:00:46,879 --> 00:00:48,719 And when I'm not hiking and paragliding 14 00:00:48,719 --> 00:00:50,800 or navigating whitewater rapids, I serve 15 00:00:50,800 --> 00:00:52,640 as a deputy chair of Python New Zealand 16 00:00:52,640 --> 00:00:55,920 and core team organizer for Kiwi Pyon. 17 00:00:55,920 --> 00:00:57,520 With the rest of my time, I work as a 18 00:00:57,520 --> 00:00:59,840 senior site reliability engineer for a 19 00:00:59,840 --> 00:01:01,840 fintex startup where I spend a lot a lot 20 00:01:01,840 --> 00:01:03,840 of my time thinking about security of my 21 00:01:03,840 --> 00:01:07,040 platform and our applications. 22 00:01:07,040 --> 00:01:09,600 So, let's talk about strings. 23 00:01:09,600 --> 00:01:11,119 If you've been writing Python since the 24 00:01:11,119 --> 00:01:14,000 good old days where we wrote our print 25 00:01:14,000 --> 00:01:16,960 statements without uh parenthesis, you 26 00:01:16,960 --> 00:01:19,360 may recognize this uh as the C inspired 27 00:01:19,360 --> 00:01:21,759 print style syntax for uh string 28 00:01:21,759 --> 00:01:24,759 interpolation. 29 00:01:27,840 --> 00:01:30,960 In 2008, PIP 3101 gave us an advanced 30 00:01:30,960 --> 00:01:33,360 string formatting and the format 31 00:01:33,360 --> 00:01:35,040 function and with it format 32 00:01:35,040 --> 00:01:36,799 specification mini language. And that 33 00:01:36,799 --> 00:01:39,439 mini language was really quite a beast. 34 00:01:39,439 --> 00:01:40,880 You can do quite a lot of powerful 35 00:01:40,880 --> 00:01:44,240 things with it. 36 00:01:44,240 --> 00:01:45,759 It's got this whole separate grammar and 37 00:01:45,759 --> 00:01:48,880 it really is quite advanced. 38 00:01:48,880 --> 00:01:52,399 In 2016, PEP 498 gave us a more concise 39 00:01:52,399 --> 00:01:54,560 and readable syntax for instantiation of 40 00:01:54,560 --> 00:01:56,640 formatted strings with all the all of 41 00:01:56,640 --> 00:01:59,040 the power of advanced string formatting, 42 00:01:59,040 --> 00:02:02,560 uh, but with an inline syntax. 43 00:02:02,560 --> 00:02:04,240 Just be mindful not to go overboard. 44 00:02:04,240 --> 00:02:06,240 readability counts, but if strings are 45 00:02:06,240 --> 00:02:08,399 wonderful and we're all excited to run 46 00:02:08,399 --> 00:02:10,399 around and put them everywhere in uh our 47 00:02:10,399 --> 00:02:14,680 code base, for example, 48 00:02:17,680 --> 00:02:19,840 hopefully by relatively uneventful means 49 00:02:19,840 --> 00:02:22,000 we come to understand that in cautious 50 00:02:22,000 --> 00:02:23,680 use of formatted strings can lead to 51 00:02:23,680 --> 00:02:26,640 security vulnerabilities. 52 00:02:26,640 --> 00:02:29,440 On the happy path, this is neat. Um, we 53 00:02:29,440 --> 00:02:31,920 get a username like John Smith. it goes 54 00:02:31,920 --> 00:02:34,160 into our query and we get the resulting 55 00:02:34,160 --> 00:02:36,879 SQL out the other end. 56 00:02:36,879 --> 00:02:40,080 Um, in the bad case, someone comes along 57 00:02:40,080 --> 00:02:42,560 and uh provides a cleverly crafted 58 00:02:42,560 --> 00:02:45,920 payload and that ends up in our SQL and 59 00:02:45,920 --> 00:02:47,920 all of a sudden uh our control flow 60 00:02:47,920 --> 00:02:49,840 becomes something entirely different. 61 00:02:49,840 --> 00:02:52,000 This is always true. They've changed the 62 00:02:52,000 --> 00:02:54,239 control of our program. 63 00:02:54,239 --> 00:02:56,400 This vulnerability of manipulating the 64 00:02:56,400 --> 00:02:58,879 SQL query by injecting cleverly crafted 65 00:02:58,879 --> 00:03:01,360 values is creatively and obviously 66 00:03:01,360 --> 00:03:04,560 called SQL injection. It's so common it 67 00:03:04,560 --> 00:03:07,040 got its own issue of the XKCD web comic 68 00:03:07,040 --> 00:03:09,599 appearing in issue number 327 titled 69 00:03:09,599 --> 00:03:13,760 exploits of a mom. Uh the OWOP top 10 is 70 00:03:13,760 --> 00:03:15,680 the open web application security 71 00:03:15,680 --> 00:03:17,599 project list of the top 10 security 72 00:03:17,599 --> 00:03:20,720 mistakes developers are making. It's 73 00:03:20,720 --> 00:03:23,360 revised every 5 years or so and since 74 00:03:23,360 --> 00:03:26,720 its inception in 2001, SQL injection has 75 00:03:26,720 --> 00:03:28,720 been included in the list uh in some 76 00:03:28,720 --> 00:03:31,200 shape or form. 77 00:03:31,200 --> 00:03:33,360 These days it's scripted with an entire 78 00:03:33,360 --> 00:03:34,560 class of similar injection 79 00:03:34,560 --> 00:03:36,080 vulnerabilities including cross-sight 80 00:03:36,080 --> 00:03:37,599 scripting, serverside template 81 00:03:37,599 --> 00:03:40,640 injection, OS command injection and many 82 00:03:40,640 --> 00:03:42,400 more. 83 00:03:42,400 --> 00:03:46,640 The naive advice uh to remediate SQLI is 84 00:03:46,640 --> 00:03:48,640 that you should sanitize your inputs to 85 00:03:48,640 --> 00:03:51,040 remove dangerous control characters. 86 00:03:51,040 --> 00:03:53,440 This advice is technically correct, but 87 00:03:53,440 --> 00:03:55,280 it fails to communicate the reality and 88 00:03:55,280 --> 00:03:57,920 deceptive complexity of what that means. 89 00:03:57,920 --> 00:04:00,239 Implementing sanitization is fraught 90 00:04:00,239 --> 00:04:02,319 with edge cases and it's not code that 91 00:04:02,319 --> 00:04:05,599 you should roll yourself. 92 00:04:05,599 --> 00:04:07,439 A deeper and more underlying issue is 93 00:04:07,439 --> 00:04:09,360 that flattening untrusted user input 94 00:04:09,360 --> 00:04:11,439 data and control code together makes it 95 00:04:11,439 --> 00:04:13,360 impossible to delineate where control 96 00:04:13,360 --> 00:04:16,079 code ends and user input begins. At a 97 00:04:16,079 --> 00:04:18,400 more basic level, moving from uh inband 98 00:04:18,400 --> 00:04:20,880 to out of band handling of user data 99 00:04:20,880 --> 00:04:22,800 allows us to treat the respective parts 100 00:04:22,800 --> 00:04:24,960 of the string uh with the appropriate 101 00:04:24,960 --> 00:04:28,240 level and care. 102 00:04:28,240 --> 00:04:30,400 Mainstream SQL libraries achieve this 103 00:04:30,400 --> 00:04:32,479 through the use of prepared statements 104 00:04:32,479 --> 00:04:34,479 providing interfaces with the ability to 105 00:04:34,479 --> 00:04:37,520 separate uh to sorry separately provide 106 00:04:37,520 --> 00:04:40,240 a template uh of the query itself and 107 00:04:40,240 --> 00:04:42,800 also separately uh provide the data that 108 00:04:42,800 --> 00:04:44,720 goes into the template keeping them 109 00:04:44,720 --> 00:04:47,199 apart. 110 00:04:47,199 --> 00:04:49,440 Uh then the battle hardened SQL library 111 00:04:49,440 --> 00:04:51,199 can take care of sanitizing the data 112 00:04:51,199 --> 00:04:53,360 appropriately and securely interpolating 113 00:04:53,360 --> 00:04:56,400 it into the query itself. Now, while 114 00:04:56,400 --> 00:04:58,320 experienced developers in the room might 115 00:04:58,320 --> 00:04:59,600 be thoroughly bored of the somewhat 116 00:04:59,600 --> 00:05:01,840 contrived SQLI example, these are 117 00:05:01,840 --> 00:05:03,520 concepts that new developers still need 118 00:05:03,520 --> 00:05:05,199 to grapple with. And the fact that 119 00:05:05,199 --> 00:05:07,680 injection bugs are still after all the 120 00:05:07,680 --> 00:05:10,160 all these years in the OAS top 10 tells 121 00:05:10,160 --> 00:05:11,840 us that while education and 122 00:05:11,840 --> 00:05:13,840 documentation are necessary, they are 123 00:05:13,840 --> 00:05:16,880 absolutely not sufficient. 124 00:05:16,880 --> 00:05:18,880 to borrow some ideas from Chris Noyabau 125 00:05:18,880 --> 00:05:21,360 at this talk um at Pyon AU last year. 126 00:05:21,360 --> 00:05:23,280 The consequence of not understanding how 127 00:05:23,280 --> 00:05:26,080 to use the function uh to mitigate SQLI 128 00:05:26,080 --> 00:05:29,280 or even that there is a uh SQLI risk 129 00:05:29,280 --> 00:05:31,840 here that needs mitigation are warned by 130 00:05:31,840 --> 00:05:34,479 the user of the function. 131 00:05:34,479 --> 00:05:36,560 Chris talks about how Python is becoming 132 00:05:36,560 --> 00:05:38,639 a language with constructs that show you 133 00:05:38,639 --> 00:05:40,720 how to safely use them which he refers 134 00:05:40,720 --> 00:05:43,280 to as guardrails. Guardrails use 135 00:05:43,280 --> 00:05:45,039 structure to show you what is possible 136 00:05:45,039 --> 00:05:47,680 and safe. uh limit and communicate 137 00:05:47,680 --> 00:05:49,759 undesirable consequences and also help 138 00:05:49,759 --> 00:05:53,039 programmers write more correct programs. 139 00:05:53,039 --> 00:05:55,120 A triumph of this way of thinking uh 140 00:05:55,120 --> 00:05:57,520 that you may already be familiar with 141 00:05:57,520 --> 00:05:59,520 are context managers or the west 142 00:05:59,520 --> 00:06:01,520 keyword. 143 00:06:01,520 --> 00:06:03,360 Context managers allow programmers to 144 00:06:03,360 --> 00:06:05,199 focus on writing code that communicates 145 00:06:05,199 --> 00:06:08,400 our intent and unbburden us from uh much 146 00:06:08,400 --> 00:06:09,600 of the boiler plate required to 147 00:06:09,600 --> 00:06:11,120 defensively and correctively handle 148 00:06:11,120 --> 00:06:13,199 unexpected errors. for example, 149 00:06:13,199 --> 00:06:14,720 correctly and consistently closing our 150 00:06:14,720 --> 00:06:18,560 file handlers in case of a problem. 151 00:06:18,560 --> 00:06:21,360 Template strings or T-strings are a 152 00:06:21,360 --> 00:06:22,880 guardrail which aim to address 153 00:06:22,880 --> 00:06:24,560 shortcomings of the way in which if 154 00:06:24,560 --> 00:06:27,120 strings are misused. 155 00:06:27,120 --> 00:06:29,840 They were released in October 2025 as 156 00:06:29,840 --> 00:06:34,400 part of the Python 3.14 release. 157 00:06:34,400 --> 00:06:36,960 Template strings are a generalization of 158 00:06:36,960 --> 00:06:39,360 strings using a T in place of the if 159 00:06:39,360 --> 00:06:41,039 prefix. 160 00:06:41,039 --> 00:06:43,600 The promise of T-strings are that well 161 00:06:43,600 --> 00:06:45,360 as we've just seen how code like this 162 00:06:45,360 --> 00:06:47,919 can be a recipe for disaster. With a 163 00:06:47,919 --> 00:06:50,160 T-string instead potentially this code 164 00:06:50,160 --> 00:06:53,840 could be just fine. But why? How do 165 00:06:53,840 --> 00:06:58,440 T-strings make this potentially safe? 166 00:06:59,199 --> 00:07:01,520 According to the paper itself, T-strings 167 00:07:01,520 --> 00:07:03,520 have several audiences. The first one 168 00:07:03,520 --> 00:07:05,120 we're going to talk about is uh the 169 00:07:05,120 --> 00:07:08,000 developers who use template strings uh 170 00:07:08,000 --> 00:07:10,000 and processing functions. So these are 171 00:07:10,000 --> 00:07:12,160 the consumers of functions that expect 172 00:07:12,160 --> 00:07:14,639 T-strings. 173 00:07:14,639 --> 00:07:17,440 Let's unpack a T-string and have a look 174 00:07:17,440 --> 00:07:19,440 at what it looks like. So this is a 175 00:07:19,440 --> 00:07:21,599 little sample program we have. We're 176 00:07:21,599 --> 00:07:23,599 instantiating a T-string. Looks very 177 00:07:23,599 --> 00:07:25,440 much like the familiar syntax of an F 178 00:07:25,440 --> 00:07:27,120 string, 179 00:07:27,120 --> 00:07:29,360 but when we print it out, we get this 180 00:07:29,360 --> 00:07:32,639 template object that's not a string. All 181 00:07:32,639 --> 00:07:34,240 right, I'm going to pad this out a 182 00:07:34,240 --> 00:07:35,520 little bit so that we can read it a bit 183 00:07:35,520 --> 00:07:37,520 easier. 184 00:07:37,520 --> 00:07:40,080 So instead of evaluating to a string, 185 00:07:40,080 --> 00:07:42,240 t-strings evaluate to a new type 186 00:07:42,240 --> 00:07:45,240 template. 187 00:07:46,880 --> 00:07:48,720 Templates provide developers with access 188 00:07:48,720 --> 00:07:50,720 to both the strings themselves, the 189 00:07:50,720 --> 00:07:53,039 original strings, and an interpolation 190 00:07:53,039 --> 00:07:55,919 object. The template is a simple type 191 00:07:55,919 --> 00:07:57,599 intended to be used by template 192 00:07:57,599 --> 00:07:59,599 processing code. It's not until 193 00:07:59,599 --> 00:08:01,440 developers call a processing function 194 00:08:01,440 --> 00:08:05,639 that they get a usable string. 195 00:08:06,800 --> 00:08:08,560 uh that will normally be a function 196 00:08:08,560 --> 00:08:10,080 written either by uh one of these 197 00:08:10,080 --> 00:08:12,160 audiences. So that's authors of uh 198 00:08:12,160 --> 00:08:14,000 template processing code or framework 199 00:08:14,000 --> 00:08:17,360 authors themselves. It's a low-level uh 200 00:08:17,360 --> 00:08:20,479 language feature um written normally not 201 00:08:20,479 --> 00:08:22,720 by application developers themselves but 202 00:08:22,720 --> 00:08:24,319 by the authors of the libraries that 203 00:08:24,319 --> 00:08:27,360 those developers will use. 204 00:08:27,360 --> 00:08:28,720 When we think about the guardrails 205 00:08:28,720 --> 00:08:30,639 t-strings enable and what adopting 206 00:08:30,639 --> 00:08:32,800 t-strings in the codebase looks like the 207 00:08:32,800 --> 00:08:34,719 changes that are happening here in the 208 00:08:34,719 --> 00:08:36,080 code written by the application 209 00:08:36,080 --> 00:08:38,399 developer uh are sort of putting the 210 00:08:38,399 --> 00:08:41,440 card before the horse. 211 00:08:41,440 --> 00:08:43,120 What's really interesting about what's 212 00:08:43,120 --> 00:08:45,040 going on is inside the function that 213 00:08:45,040 --> 00:08:47,920 actually uh takes that uh string and 214 00:08:47,920 --> 00:08:50,800 does does something with it. 215 00:08:50,800 --> 00:08:53,279 So while our original hypothetical 216 00:08:53,279 --> 00:08:56,720 simplified SQL query function uh does 217 00:08:56,720 --> 00:09:00,000 provide an interface uh to the user to 218 00:09:00,000 --> 00:09:01,839 provide the template itself and the 219 00:09:01,839 --> 00:09:04,240 value separately. Um there's nothing 220 00:09:04,240 --> 00:09:05,920 that actually requires the consumer of 221 00:09:05,920 --> 00:09:07,600 the function to engage with this best 222 00:09:07,600 --> 00:09:10,320 practice. Ignorance, apathy or 223 00:09:10,320 --> 00:09:12,000 inattention on the part of the consumer 224 00:09:12,000 --> 00:09:14,000 of the function all result in potential 225 00:09:14,000 --> 00:09:16,080 disaster. 226 00:09:16,080 --> 00:09:17,680 There's no real way for the author of 227 00:09:17,680 --> 00:09:19,279 this function to reliably validate 228 00:09:19,279 --> 00:09:21,839 whether the caller of the function has 229 00:09:21,839 --> 00:09:23,600 understood and engaged with the security 230 00:09:23,600 --> 00:09:25,600 best practices provided or has 231 00:09:25,600 --> 00:09:27,600 completely ignored them. Has the user 232 00:09:27,600 --> 00:09:29,440 simply not provided any values to this 233 00:09:29,440 --> 00:09:30,959 function because the query does not 234 00:09:30,959 --> 00:09:33,680 require any dynamic customization or has 235 00:09:33,680 --> 00:09:35,279 the user done some inadvisable 236 00:09:35,279 --> 00:09:37,120 interpolation prior to passing the query 237 00:09:37,120 --> 00:09:40,440 to our function 238 00:09:43,040 --> 00:09:44,959 by expecting a template instead. The 239 00:09:44,959 --> 00:09:46,640 guardrails of the construct allow the 240 00:09:46,640 --> 00:09:48,959 user to construct the input data using 241 00:09:48,959 --> 00:09:51,440 the familiar syntax of an ifstring while 242 00:09:51,440 --> 00:09:52,959 allowing the processing function to 243 00:09:52,959 --> 00:09:54,800 clearly delineate between the string and 244 00:09:54,800 --> 00:09:57,360 the interpolated data. And then they can 245 00:09:57,360 --> 00:09:59,040 perform any checks or required 246 00:09:59,040 --> 00:10:01,519 processing such as sanitization of SQL 247 00:10:01,519 --> 00:10:03,600 escaping of HTML according to the 248 00:10:03,600 --> 00:10:05,360 context of the processing function and 249 00:10:05,360 --> 00:10:07,120 how the resulting string will be used 250 00:10:07,120 --> 00:10:10,440 further downstream. 251 00:10:11,040 --> 00:10:13,200 Uh the author of the function can also 252 00:10:13,200 --> 00:10:15,360 type check that. So if the user has 253 00:10:15,360 --> 00:10:17,760 passed them an F string um they can 254 00:10:17,760 --> 00:10:20,480 simply reject it, crash or handle the 255 00:10:20,480 --> 00:10:23,760 error appropriately. Um but now this 256 00:10:23,760 --> 00:10:25,600 function author can start guiding the 257 00:10:25,600 --> 00:10:28,160 user towards more safe and correct 258 00:10:28,160 --> 00:10:30,720 behavior. 259 00:10:30,720 --> 00:10:33,040 Um, so at this point, uh, the consumer 260 00:10:33,040 --> 00:10:34,480 of the function would get a type error 261 00:10:34,480 --> 00:10:36,160 if they passed if string instead of a 262 00:10:36,160 --> 00:10:38,079 T-string and they hopefully realize that 263 00:10:38,079 --> 00:10:39,760 they need to go and update, uh, their 264 00:10:39,760 --> 00:10:42,760 code. 265 00:10:43,680 --> 00:10:45,440 At this point, I want to point out that 266 00:10:45,440 --> 00:10:46,720 unless you're one of these two 267 00:10:46,720 --> 00:10:49,040 audiences, uh, the content covered up to 268 00:10:49,040 --> 00:10:50,640 this point of the talk is really kind of 269 00:10:50,640 --> 00:10:52,560 the extent to which most developers will 270 00:10:52,560 --> 00:10:54,160 really likely engage with template 271 00:10:54,160 --> 00:10:55,600 strings. And that's the point of the 272 00:10:55,600 --> 00:10:58,560 construct. But what if say you do want 273 00:10:58,560 --> 00:11:00,800 to process a string template? How do you 274 00:11:00,800 --> 00:11:04,160 go about doing that? 275 00:11:04,160 --> 00:11:06,079 Um, so from here on out, we're going to 276 00:11:06,079 --> 00:11:08,560 build up our own string uh template 277 00:11:08,560 --> 00:11:10,880 processing uh function. Uh, so we can 278 00:11:10,880 --> 00:11:13,360 really get under the hood of how it 279 00:11:13,360 --> 00:11:15,360 works. 280 00:11:15,360 --> 00:11:17,200 So the first thing that we want to do is 281 00:11:17,200 --> 00:11:18,640 import the template type from the 282 00:11:18,640 --> 00:11:21,360 string.late lib library. I want to 283 00:11:21,360 --> 00:11:23,120 highlight that this is not string. 284 00:11:23,120 --> 00:11:24,720 template that is something completely 285 00:11:24,720 --> 00:11:26,959 different, a much older standard and uh 286 00:11:26,959 --> 00:11:29,920 confused me like crazy when I uh started 287 00:11:29,920 --> 00:11:33,360 playing with it. 288 00:11:33,360 --> 00:11:35,600 Um and we can use that template object 289 00:11:35,600 --> 00:11:37,600 to uh type annotate our function cuz 290 00:11:37,600 --> 00:11:41,920 we're kind Python developers. 291 00:11:41,920 --> 00:11:43,519 Um we're going to iterate and build it 292 00:11:43,519 --> 00:11:45,839 up very simply. So for starters, let's 293 00:11:45,839 --> 00:11:47,680 just look uh at iterating over the 294 00:11:47,680 --> 00:11:51,519 template uh object itself. Um so we'll 295 00:11:51,519 --> 00:11:53,920 write a little sample program 296 00:11:53,920 --> 00:11:57,040 uh and we can see how this uh string 297 00:11:57,040 --> 00:11:59,360 gets broken down. So the first thing 298 00:11:59,360 --> 00:12:01,839 that gets or the first item in our uh 299 00:12:01,839 --> 00:12:03,839 template object is the first part of the 300 00:12:03,839 --> 00:12:06,320 string the hello. And then we get an 301 00:12:06,320 --> 00:12:08,639 actual interpolation object with the uh 302 00:12:08,639 --> 00:12:10,720 interesting dynamic data nicely 303 00:12:10,720 --> 00:12:13,279 separated out from the raw string. And 304 00:12:13,279 --> 00:12:14,720 of course we get the final part of the 305 00:12:14,720 --> 00:12:16,639 string which is the exclamation mark. 306 00:12:16,639 --> 00:12:18,399 This is a very trivial example, but it 307 00:12:18,399 --> 00:12:21,680 will help us understand as we go. 308 00:12:21,680 --> 00:12:23,680 Um, so let's start stitching the parts 309 00:12:23,680 --> 00:12:26,320 of our template together into a string. 310 00:12:26,320 --> 00:12:29,279 Uh, we want to collect them in an array. 311 00:12:29,279 --> 00:12:31,040 Um, and as we iterate through them, 312 00:12:31,040 --> 00:12:32,800 instead of just printing them out, we'll 313 00:12:32,800 --> 00:12:34,399 add them to the array. And then at the 314 00:12:34,399 --> 00:12:35,920 end, we're going to join them all 315 00:12:35,920 --> 00:12:40,839 together uh, and print them out. 316 00:12:42,959 --> 00:12:44,399 For now, we'll just worry about the 317 00:12:44,399 --> 00:12:47,360 string parts of the template. Um, how 318 00:12:47,360 --> 00:12:49,200 many people have played with the Python 319 00:12:49,200 --> 00:12:51,200 structural pattern matching before or 320 00:12:51,200 --> 00:12:53,760 the match statement? 321 00:12:53,760 --> 00:12:55,760 A few. Does anyone know when it was 322 00:12:55,760 --> 00:13:00,959 introduced? I think it was 3 39 323 00:13:00,959 --> 00:13:02,959 310. 324 00:13:02,959 --> 00:13:05,440 So, this is perfectly valid code. Uh, 325 00:13:05,440 --> 00:13:09,120 you can use if is instant. uh but the 326 00:13:09,120 --> 00:13:11,279 idiomatic way that uh the pep recommends 327 00:13:11,279 --> 00:13:13,360 interacting with templates is to use the 328 00:13:13,360 --> 00:13:15,920 Python uh structural pattern matching 329 00:13:15,920 --> 00:13:18,480 pattern with the match keyword and we'll 330 00:13:18,480 --> 00:13:21,440 see why that's important in a moment. So 331 00:13:21,440 --> 00:13:22,800 let's start with the easy part the 332 00:13:22,800 --> 00:13:24,800 strings. 333 00:13:24,800 --> 00:13:26,720 Um as we go through we'll just append 334 00:13:26,720 --> 00:13:30,480 the strings to uh to our parts and again 335 00:13:30,480 --> 00:13:32,079 we can write a little test program and 336 00:13:32,079 --> 00:13:34,560 we just get the string parts out of it. 337 00:13:34,560 --> 00:13:36,639 So that's a okay start and now we can 338 00:13:36,639 --> 00:13:37,920 figure out what we want to do with the 339 00:13:37,920 --> 00:13:41,120 interpolation object. 340 00:13:41,120 --> 00:13:43,200 So first we need to import the 341 00:13:43,200 --> 00:13:45,120 interpolation object uh from the 342 00:13:45,120 --> 00:13:48,320 standard library. And if we look at our 343 00:13:48,320 --> 00:13:50,720 little previous uh test program we can 344 00:13:50,720 --> 00:13:54,399 see how that object gets broken down. 345 00:13:54,399 --> 00:13:57,920 So um the interpolation class has a 346 00:13:57,920 --> 00:14:00,240 value, an expression, a conversion and 347 00:14:00,240 --> 00:14:03,279 uh a format spec. Uh the first part of 348 00:14:03,279 --> 00:14:04,959 the interpolation object is the value 349 00:14:04,959 --> 00:14:07,519 that we've passed to it. 350 00:14:07,519 --> 00:14:10,079 Um and remember we get each one of these 351 00:14:10,079 --> 00:14:12,320 for each values that needs to get inter 352 00:14:12,320 --> 00:14:16,240 interpolated. We get an expression. Um 353 00:14:16,240 --> 00:14:18,079 so in our example we've passed a 354 00:14:18,079 --> 00:14:21,600 name.title and we get that out. Uh it's 355 00:14:21,600 --> 00:14:23,199 useful to know how the string has been 356 00:14:23,199 --> 00:14:24,720 pre-processed but we don't necessarily 357 00:14:24,720 --> 00:14:27,920 need need to do anything with it. Uh we 358 00:14:27,920 --> 00:14:29,600 haven't used the conversion in this 359 00:14:29,600 --> 00:14:30,959 example. I don't know if that's a 360 00:14:30,959 --> 00:14:32,639 mechanic that anyone's engaged with. It 361 00:14:32,639 --> 00:14:34,160 was a surprise to me once I lifted the 362 00:14:34,160 --> 00:14:36,480 hood. But if we did have a conversion, 363 00:14:36,480 --> 00:14:38,079 uh the syntax for that would look like 364 00:14:38,079 --> 00:14:41,760 this. Uh it tells um the processing 365 00:14:41,760 --> 00:14:44,240 function that we want to use the repper 366 00:14:44,240 --> 00:14:46,720 uh double underscore function d method 367 00:14:46,720 --> 00:14:49,440 to represent the string and it appears 368 00:14:49,440 --> 00:14:51,600 in our interpolation as the letter R. So 369 00:14:51,600 --> 00:14:55,360 that's useful context for uh the uh 370 00:14:55,360 --> 00:14:57,519 processor of the interpolation object to 371 00:14:57,519 --> 00:15:00,480 make decisions about how to process it. 372 00:15:00,480 --> 00:15:02,639 And finally the format spec which again 373 00:15:02,639 --> 00:15:04,480 we haven't passed on but we should be 374 00:15:04,480 --> 00:15:05,920 very familiar with it because it's just 375 00:15:05,920 --> 00:15:11,519 our standard uh format string uh syntax. 376 00:15:11,519 --> 00:15:14,240 Cool. 377 00:15:14,240 --> 00:15:17,519 So we can very simply um 378 00:15:17,519 --> 00:15:19,360 start handling the interpolation object 379 00:15:19,360 --> 00:15:21,120 again using the structural pattern 380 00:15:21,120 --> 00:15:24,480 matching pattern. Um and this is the 381 00:15:24,480 --> 00:15:26,560 entire point of T-strings. It exposes 382 00:15:26,560 --> 00:15:28,720 the internal intermediary stages of 383 00:15:28,720 --> 00:15:31,279 rendering an F string uh to the library 384 00:15:31,279 --> 00:15:33,199 authors such that they may apply their 385 00:15:33,199 --> 00:15:35,680 own processing uh such as sanitizing 386 00:15:35,680 --> 00:15:37,760 inputs before outputting the final 387 00:15:37,760 --> 00:15:40,639 string. 388 00:15:40,639 --> 00:15:43,760 So uh what would that look like? Um, in 389 00:15:43,760 --> 00:15:45,199 our trivial example, we're not going to 390 00:15:45,199 --> 00:15:47,040 dive into how to actually sanitize the 391 00:15:47,040 --> 00:15:49,040 string. Um, again, I highly recommend 392 00:15:49,040 --> 00:15:50,560 you don't write that unless you're a 393 00:15:50,560 --> 00:15:52,880 very experienced uh, framework author. 394 00:15:52,880 --> 00:15:54,720 Um, but if we wanted to take the format 395 00:15:54,720 --> 00:15:56,079 spec and do something interesting with 396 00:15:56,079 --> 00:15:57,600 that, we can do all of our 397 00:15:57,600 --> 00:16:00,240 pre-processing in this stage. 398 00:16:00,240 --> 00:16:01,920 Um, and for that we can just call the 399 00:16:01,920 --> 00:16:04,320 format function for uh, built built-in 400 00:16:04,320 --> 00:16:07,880 built-in function. 401 00:16:08,959 --> 00:16:10,639 Cool. Uh so now if we want to test it 402 00:16:10,639 --> 00:16:13,040 out uh we'll write ourselves a little 403 00:16:13,040 --> 00:16:14,959 mini program again. We'll put a sample 404 00:16:14,959 --> 00:16:19,440 formatting string and great 405 00:16:19,440 --> 00:16:22,240 uh so at this stage we've uh sort of 406 00:16:22,240 --> 00:16:25,120 reimplemented what if string is itself. 407 00:16:25,120 --> 00:16:28,720 Um but what I want to drive home is that 408 00:16:28,720 --> 00:16:32,000 uh in in this step here you can do you 409 00:16:32,000 --> 00:16:34,160 can add as much complexity as you need 410 00:16:34,160 --> 00:16:36,240 to properly handle and sanitize the 411 00:16:36,240 --> 00:16:39,240 strings. 412 00:16:43,040 --> 00:16:45,920 So 413 00:16:45,920 --> 00:16:48,880 again what what I want people to take 414 00:16:48,880 --> 00:16:51,360 away from this is that uh t-strings are 415 00:16:51,360 --> 00:16:53,360 not about updating your code from using 416 00:16:53,360 --> 00:16:55,680 f to t. There's nothing magic about the 417 00:16:55,680 --> 00:16:58,800 t prefix. What it allows is for that 418 00:16:58,800 --> 00:17:00,560 string to not get uh immediately 419 00:17:00,560 --> 00:17:02,639 collapsed down into a flat string. It 420 00:17:02,639 --> 00:17:05,360 keeps all of the parts separate. uh and 421 00:17:05,360 --> 00:17:07,679 whichever function such as the execute 422 00:17:07,679 --> 00:17:10,240 function here uh receives that template 423 00:17:10,240 --> 00:17:12,559 object it can then appropriately handle 424 00:17:12,559 --> 00:17:16,319 the uh static and dynam dynamic parts of 425 00:17:16,319 --> 00:17:19,120 that template. 426 00:17:19,120 --> 00:17:21,760 Key takeaways uh t-strongs are not about 427 00:17:21,760 --> 00:17:25,120 the syntactic sugar here um 428 00:17:25,120 --> 00:17:26,959 implementation of t-strings will be 429 00:17:26,959 --> 00:17:29,280 driven by uh the library authors and not 430 00:17:29,280 --> 00:17:31,120 consumers. you won't be able to go 431 00:17:31,120 --> 00:17:33,760 around and uh like I said just uh 432 00:17:33,760 --> 00:17:36,000 replace all of your ifs with these and 433 00:17:36,000 --> 00:17:38,559 be magically safe. Um the way this will 434 00:17:38,559 --> 00:17:40,640 be rolled out will be your libraries 435 00:17:40,640 --> 00:17:42,880 will start demanding templates of you. 436 00:17:42,880 --> 00:17:45,360 Um it will probably be a breaking change 437 00:17:45,360 --> 00:17:48,960 when it arrives. Um and I think that's a 438 00:17:48,960 --> 00:17:50,960 good thing for the safety of all of our 439 00:17:50,960 --> 00:17:52,799 code. 440 00:17:52,799 --> 00:17:54,720 Um, 441 00:17:54,720 --> 00:17:58,000 if you want to learn more about, uh, all 442 00:17:58,000 --> 00:18:00,160 of these classes of bugs, um, get 443 00:18:00,160 --> 00:18:01,600 hands-on experience finding and 444 00:18:01,600 --> 00:18:03,200 exploiting vulnerabilities like these 445 00:18:03,200 --> 00:18:04,799 and many more, there are loads of great 446 00:18:04,799 --> 00:18:06,240 ways to get involved through online 447 00:18:06,240 --> 00:18:08,400 platforms like Hack the Box, who also 448 00:18:08,400 --> 00:18:09,840 have a network of volunteer-led 449 00:18:09,840 --> 00:18:11,919 in-person meetups, or you can start your 450 00:18:11,919 --> 00:18:14,400 own. 451 00:18:14,400 --> 00:18:16,559 Uh, you can also learn more by joining 452 00:18:16,559 --> 00:18:18,320 your local information security meetup 453 00:18:18,320 --> 00:18:20,640 group or attend a security conference. 454 00:18:20,640 --> 00:18:22,640 And I want to shout out to uh Carrot 455 00:18:22,640 --> 00:18:24,400 from NZ for maintaining down 456 00:18:24,400 --> 00:18:26,559 undercons.nz. 457 00:18:26,559 --> 00:18:28,640 Uh it's a it's a website with a list of 458 00:18:28,640 --> 00:18:30,400 all of the security conferences across 459 00:18:30,400 --> 00:18:32,640 Australia and New Zealand. Uh when their 460 00:18:32,640 --> 00:18:35,360 uh CFPs open and close, uh where their 461 00:18:35,360 --> 00:18:37,600 tickets are. Um it's a fantastic 462 00:18:37,600 --> 00:18:41,600 resource for both countries. 463 00:18:41,600 --> 00:18:44,000 Um that's really it for me. Uh just a 464 00:18:44,000 --> 00:18:45,520 relatively short talk. You can find me 465 00:18:45,520 --> 00:18:48,799 at diviccops.com or simon.com. 466 00:18:48,799 --> 00:18:53,520 Um, I'm happy to answer any questions. 467 00:18:53,520 --> 00:18:55,783 Right. Round of applause for Simon. 468 00:18:55,783 --> 00:18:57,803 [applause] 469 00:19:00,368 --> 00:19:02,388 [applause] 470 00:19:04,320 --> 00:19:06,480 Thanks. That was really interesting. Um, 471 00:19:06,480 --> 00:19:09,360 with fstring interpolation, um, it 472 00:19:09,360 --> 00:19:11,200 presumably stringifies the object right 473 00:19:11,200 --> 00:19:13,360 then and there. But with the T-string 474 00:19:13,360 --> 00:19:14,960 one, it sounds like it's going to just 475 00:19:14,960 --> 00:19:16,480 be a reference to the object, which 476 00:19:16,480 --> 00:19:18,640 means that if I change it in between 477 00:19:18,640 --> 00:19:20,640 creating the T-string and using the 478 00:19:20,640 --> 00:19:23,200 T-string, is there a problem there? 479 00:19:23,200 --> 00:19:25,360 No. Uh, it's not a problem. If you read 480 00:19:25,360 --> 00:19:28,240 the uh actual pip, one of the use cases 481 00:19:28,240 --> 00:19:31,039 proposed is to be able to pass around uh 482 00:19:31,039 --> 00:19:33,200 for example enriched logs with 483 00:19:33,200 --> 00:19:34,960 additional context as part of the 484 00:19:34,960 --> 00:19:38,160 object. Um yeah, that's totally a valid 485 00:19:38,160 --> 00:19:40,240 use case. Uh one interesting thing about 486 00:19:40,240 --> 00:19:43,120 t-strings is that uh they were actually 487 00:19:43,120 --> 00:19:45,760 proposed at the same time as if strings. 488 00:19:45,760 --> 00:19:49,120 uh the the pips were or early versions 489 00:19:49,120 --> 00:19:50,480 of the pips were written at the same 490 00:19:50,480 --> 00:19:52,880 time and the core team decided that um 491 00:19:52,880 --> 00:19:56,080 it's not a bad idea but we'll adopt if 492 00:19:56,080 --> 00:19:59,039 strings we'll let those stabilize and 493 00:19:59,039 --> 00:20:01,600 then we'll re-evaluate and if it's still 494 00:20:01,600 --> 00:20:04,080 a good idea we'll do tings. So this is 495 00:20:04,080 --> 00:20:06,240 actually the logical conclusion of like 496 00:20:06,240 --> 00:20:08,160 multiple years of thinking about the 497 00:20:08,160 --> 00:20:09,840 problem knowing it's the direction that 498 00:20:09,840 --> 00:20:12,160 the language would probably go and uh 499 00:20:12,160 --> 00:20:16,640 finally actually implementing the spec. 500 00:20:16,640 --> 00:20:19,840 What is there actual validation uh that 501 00:20:19,840 --> 00:20:22,240 would prevent somebody from uh say just 502 00:20:22,240 --> 00:20:24,799 have a ting that just contains a string 503 00:20:24,799 --> 00:20:26,320 like how do you actually enforce that 504 00:20:26,320 --> 00:20:29,520 you have uh you know certain keywords or 505 00:20:29,520 --> 00:20:30,960 something that are in the in the string 506 00:20:30,960 --> 00:20:32,480 that need to be validated? Is there 507 00:20:32,480 --> 00:20:35,200 typing behind it or something? 508 00:20:35,200 --> 00:20:37,600 Um, 509 00:20:37,600 --> 00:20:40,400 so in terms of like you can type check 510 00:20:40,400 --> 00:20:42,960 that you're getting a template string if 511 00:20:42,960 --> 00:20:45,760 your users is really determined to uh 512 00:20:45,760 --> 00:20:48,400 fully compact everything into a string 513 00:20:48,400 --> 00:20:50,559 and then wrap it as a template. There's 514 00:20:50,559 --> 00:20:51,840 not really that much you can do about 515 00:20:51,840 --> 00:20:55,360 it. But um the the value the value of it 516 00:20:55,360 --> 00:20:58,320 being a construct is that uh the default 517 00:20:58,320 --> 00:21:00,240 behavior that it steers people towards 518 00:21:00,240 --> 00:21:02,400 is more likely to be correct. Someone is 519 00:21:02,400 --> 00:21:04,640 more likely to naively want to uh use 520 00:21:04,640 --> 00:21:06,880 the if string to construct the string 521 00:21:06,880 --> 00:21:08,640 that is not appropriate for that use 522 00:21:08,640 --> 00:21:11,600 case. Um and this is a very familiar 523 00:21:11,600 --> 00:21:14,240 syntax and very easy way to guide them 524 00:21:14,240 --> 00:21:16,960 towards the right behavior. Um but if if 525 00:21:16,960 --> 00:21:18,480 someone's determined to do the wrong 526 00:21:18,480 --> 00:21:20,400 thing, there's not that much you can do 527 00:21:20,400 --> 00:21:22,880 about it. 528 00:21:22,880 --> 00:21:25,520 you you had the name.apper 529 00:21:25,520 --> 00:21:29,200 um um expression in there in all of 530 00:21:29,200 --> 00:21:31,360 them, but you never evaluated it. And 531 00:21:31,360 --> 00:21:33,280 what I saw on your slides was it gave 532 00:21:33,280 --> 00:21:36,240 the raw value. What What's up with that? 533 00:21:36,240 --> 00:21:38,159 Uh title. 534 00:21:38,159 --> 00:21:40,159 That may be a slight transcription error 535 00:21:40,159 --> 00:21:43,520 on my part. So uh 536 00:21:43,520 --> 00:21:46,640 so it it was it was using the title case 537 00:21:46,640 --> 00:21:52,960 uh method um and the final output uh 538 00:21:52,960 --> 00:21:55,440 yeah the the the final the final output 539 00:21:55,440 --> 00:21:59,520 uh would would be titleized um that may 540 00:21:59,520 --> 00:22:02,080 be a slight trans uh transcription error 541 00:22:02,080 --> 00:22:06,240 on my part but uh yes uh you can see all 542 00:22:06,240 --> 00:22:08,400 the intermediary parts of of how you get 543 00:22:08,400 --> 00:22:10,480 from the original string uh to the final 544 00:22:10,480 --> 00:22:11,679 string. and you have a lot of 545 00:22:11,679 --> 00:22:15,520 opportunity to uh interject into that 546 00:22:15,520 --> 00:22:17,919 process and uh change it as needed for 547 00:22:17,919 --> 00:22:19,200 your use case. 548 00:22:19,200 --> 00:22:21,200 So you can get the raw value out but if 549 00:22:21,200 --> 00:22:23,760 you go 550 00:22:23,760 --> 00:22:25,679 stir 551 00:22:25,679 --> 00:22:27,760 um interpolation it'll give you the 552 00:22:27,760 --> 00:22:30,000 processed value. 553 00:22:30,000 --> 00:22:30,320 Yes. 554 00:22:30,320 --> 00:22:33,880 Yeah. Okay. Thanks. 555 00:22:37,600 --> 00:22:39,679 Uh thank you very much uh for the great 556 00:22:39,679 --> 00:22:42,159 talk. Um, are there any other I know you 557 00:22:42,159 --> 00:22:43,760 briefly just mentioned something, but 558 00:22:43,760 --> 00:22:46,320 any other cool uses for template strings 559 00:22:46,320 --> 00:22:48,480 that you've seen outside of just doing 560 00:22:48,480 --> 00:22:52,080 validation and uh protecting against uh 561 00:22:52,080 --> 00:22:55,039 SQLI and maybe like XSS and stuff. 562 00:22:55,039 --> 00:22:56,960 I've not I've not seen it in the wild at 563 00:22:56,960 --> 00:22:59,360 all yet. Um, 564 00:22:59,360 --> 00:23:02,000 as part of preparing for this talk and 565 00:23:02,000 --> 00:23:04,799 updating specific slides like a lot of 566 00:23:04,799 --> 00:23:06,720 even the Python interpreters online 567 00:23:06,720 --> 00:23:09,600 because I was I was being lazy. um 568 00:23:09,600 --> 00:23:11,840 they're still using 312. So like you 569 00:23:11,840 --> 00:23:14,640 have to be on Python 3.14 uh at least to 570 00:23:14,640 --> 00:23:17,440 be able to use them at all. Um the 571 00:23:17,440 --> 00:23:19,520 proposed use cases if you refer to the 572 00:23:19,520 --> 00:23:23,039 PIP are almost entirely around um 573 00:23:23,039 --> 00:23:25,840 preventing any kind of injection. Um and 574 00:23:25,840 --> 00:23:28,000 the key part there is that the person 575 00:23:28,000 --> 00:23:30,080 processing the template understands the 576 00:23:30,080 --> 00:23:31,840 context where the final string will be 577 00:23:31,840 --> 00:23:35,200 used and is the person best place to do 578 00:23:35,200 --> 00:23:36,640 the appropriate sanitization whether 579 00:23:36,640 --> 00:23:38,480 it's going to be put into a ginger 580 00:23:38,480 --> 00:23:41,840 template or like an HTML page or or like 581 00:23:41,840 --> 00:23:44,480 into a database. um that's up to the 582 00:23:44,480 --> 00:23:47,360 person uh processing the template to 583 00:23:47,360 --> 00:23:49,440 figure out how to do properly which is 584 00:23:49,440 --> 00:23:51,440 why I don't recommend anyone go enroll 585 00:23:51,440 --> 00:23:53,360 their own unless for learning purposes 586 00:23:53,360 --> 00:23:56,400 or uh you're experienced at framework 587 00:23:56,400 --> 00:23:59,679 development other use cases um like I 588 00:23:59,679 --> 00:24:02,640 said uh enriching logs and passing like 589 00:24:02,640 --> 00:24:04,400 logs around with additional context 590 00:24:04,400 --> 00:24:07,280 about the process uh that was uh one 591 00:24:07,280 --> 00:24:10,559 proposed use case in the pit um but 592 00:24:10,559 --> 00:24:13,600 really really the point is like 593 00:24:13,600 --> 00:24:16,880 it it's it's just uh opening up if 594 00:24:16,880 --> 00:24:19,039 strings to let you do whatever you need 595 00:24:19,039 --> 00:24:20,559 to do in the middle. Obviously, there's 596 00:24:20,559 --> 00:24:22,559 like some really unpythonic things you 597 00:24:22,559 --> 00:24:24,320 could do with that and I don't recommend 598 00:24:24,320 --> 00:24:25,840 it. Uh everyone should use their best 599 00:24:25,840 --> 00:24:30,919 judgment, but um yeah. 600 00:24:33,520 --> 00:24:36,320 Uh thank you. Uh I'd like to ask about 601 00:24:36,320 --> 00:24:39,279 the SQL example in the previous slide 602 00:24:39,279 --> 00:24:44,480 where um where I think there 603 00:24:44,480 --> 00:24:48,880 are the two lines of code defining SQL 604 00:24:48,880 --> 00:24:51,520 in the first line you yeah like the 605 00:24:51,520 --> 00:24:53,760 first line is string literal and the 606 00:24:53,760 --> 00:24:56,960 second line is t string and how what 607 00:24:56,960 --> 00:24:58,159 happens in this the kind of 608 00:24:58,159 --> 00:25:01,120 concatenation like is it some special 609 00:25:01,120 --> 00:25:03,840 rule is defined where like some concaten 610 00:25:03,840 --> 00:25:05,520 Definition of string and t string 611 00:25:05,520 --> 00:25:08,720 generates the what is 612 00:25:08,720 --> 00:25:10,720 t string object or template object I 613 00:25:10,720 --> 00:25:12,000 mean 614 00:25:12,000 --> 00:25:14,159 so here uh it should just be a 615 00:25:14,159 --> 00:25:16,320 multi-line string it will ultimately 616 00:25:16,320 --> 00:25:19,679 just get uh combined into 617 00:25:19,679 --> 00:25:22,400 into one line of python um nothing to do 618 00:25:22,400 --> 00:25:26,880 with f or t the the if there so uh 619 00:25:26,880 --> 00:25:28,559 because it's been split over two lines 620 00:25:28,559 --> 00:25:31,279 here the if uh needs to go below the 621 00:25:31,279 --> 00:25:32,559 second line you could put it on the 622 00:25:32,559 --> 00:25:34,799 first line as well But uh it has to be 623 00:25:34,799 --> 00:25:39,799 there on on the second line. Um 624 00:25:40,240 --> 00:25:44,200 uh okay, thank you. 625 00:25:45,360 --> 00:25:47,360 Hello. And to just to clarify, I think 626 00:25:47,360 --> 00:25:49,360 you nearly answered it earlier. If you 627 00:25:49,360 --> 00:25:52,960 pass in an a mutable string into the 628 00:25:52,960 --> 00:25:54,720 template string, it doesn't get um 629 00:25:54,720 --> 00:25:56,960 evaluated until it's finally printed or 630 00:25:56,960 --> 00:26:00,080 resolved or whatever. 631 00:26:00,080 --> 00:26:03,360 Uh I I think it it does get it does get 632 00:26:03,360 --> 00:26:05,840 evaluated. So if you if you've called 633 00:26:05,840 --> 00:26:08,000 like python.title that should get 634 00:26:08,000 --> 00:26:10,240 evaluated on the way in. But you can see 635 00:26:10,240 --> 00:26:12,720 the evaluations that have been done on 636 00:26:12,720 --> 00:26:15,919 it. Um those appear in the in the 637 00:26:15,919 --> 00:26:18,799 expression uh attribute of that 638 00:26:18,799 --> 00:26:20,880 interpolation object. Um so you can see 639 00:26:20,880 --> 00:26:23,440 the evaluations that have been done. Um, 640 00:26:23,440 --> 00:26:25,520 but I think you should get the evaluated 641 00:26:25,520 --> 00:26:27,919 string in the in the value attribute of 642 00:26:27,919 --> 00:26:31,480 the template class. 643 00:26:34,000 --> 00:26:36,480 Any other questions? 644 00:26:36,480 --> 00:26:38,320 All right. Thank you very much, Simon. 645 00:26:38,320 --> 00:26:42,203 Awesome. Hang on. Yeah. [applause]