Brought to you by Michael and Brian - take a Talk Python course or get Brian's pytest book


Transcript #422: You need 4 spaces

Return to episode page view on github
Recorded on Monday, Mar 3, 2025.

00:00 Hello and welcome to Python Bytes where we deliver Python news and headlines directly to your earbuds.

00:05 This is episode 422 recorded March 3rd, 2025.

00:09 I am Michael Kennedy.

00:10 And I am Brian Okken.

00:11 And this episode is brought to you by us.

00:14 Check out Brian's pytest courses.

00:16 Check out the ones over at Talk Python Training.

00:19 We're up to almost 475 hours.

00:22 275 hours?

00:24 I mean, not that many.

00:24 275 hours of courses over at Talk Python.

00:27 There are many to choose from there.

00:28 and Ryan's book and Patreon supporters and all these things.

00:31 Thank you so much.

00:32 Also, we're continuing to improve and evolve our newsletter, which gives you, I think, insights into the episode

00:39 that we maybe didn't explicitly call out and certainly are not in the show notes.

00:42 So head over to pythonbytes.fm, click on newsletter, put in your email.

00:46 We will be kind and gentle to it, but we'll send you cool stuff, usually the day of or after the day after the show.

00:53 Yeah, so with that said, Ryan, how do we start our show today?

00:57 Let's start it with a video, kind of.

00:59 - Wait, isn't this already a video?

01:01 People want to watch it?

01:01 - Yeah, yeah.

01:03 - Very mad at you.

01:04 - Yeah, so I'm trying to add this to the stage.

01:08 What's going on?

01:09 Oh, the wrong, yeah, anyway.

01:11 There we go.

01:13 Technical difficulties that won't make any sense to anybody listening.

01:16 So, we don't normally cover video because it's, I don't know, I don't know why,

01:22 but I don't watch a lot of Python videos, I guess.

01:25 But this one is a do not miss.

01:28 So Henik put out a video called my 2025 UV based project, Python project layout for production apps.

01:36 And I was paid attention to this partly to see what he was up to and I like UV.

01:43 But also this, so this, when you watch it, his example is a FastAPI app.

01:50 And in his world, an app is usually like, really a website app.

01:56 And later he's gonna go on to talk about Docker, I think, because this is a part one, part one of a series.

02:04 But this one's already enough that I think it's really useful.

02:07 And especially in a lot of the, some of the stuff I deal with I think of an app as anything that's packaged, kind of.

02:17 Like it's not a package, it's not something you put on PyPI, but it's a bunch of your own code

02:23 that you normally would have used a requirements.txt file, and I like his model better.

02:28 So I'm gonna jump in, I got a couple tabs because it's kind of hard to like navigate.

02:35 Anyway, snapshot videos.

02:37 So I stopped them where I wanted to.

02:39 So the video is great, it's about 25 minutes long, it's pretty quick to watch.

02:46 Here we've got the project layout.

02:49 So his project layout is using a source layout.

02:53 And really, there's no requirements file.

02:56 All of the requirements are in the pyproject.toml.

02:59 And instead of a custom lock file or one you manually do, he's just recommending that you let

03:06 UV take care of a lot of the project stuff.

03:09 And actually, even with--

03:11 and we'll take a look at a little bit more of what's in pyproject.toml.

03:15 But he's recommending that you go ahead and check in the UV lock.

03:18 So if you're letting UV handle your virtual environment, it's gonna create a lock file, and if you commit that,

03:25 then UV run later will use that and use all of the stuff in the lock file,

03:31 and you, instead of running Python, you clone the repo, run UV run on your project,

03:37 and it's gonna grab everything out of the lock file.

03:41 It's just like pin dependencies.

03:42 It's pretty sweet.

03:43 - Yep, I 100% agree with him.

03:46 Check in the UV lock file.

03:47 And then you don't also, you don't even have to do UV run if you don't want, you can just

03:51 do UV sync and it will also use the pin dependencies in the lock file.

03:55 And then, because some systems, they require to run kind of with their setup.

04:00 For example, Pyramid, you need to use PSERV and then it's like configuration file or flask,

04:07 you can do like flask run or Django.

04:09 Like, so if you still want to stick with that, you can just do UV sync.

04:11 So UV sync will grab all the, everything out of the lock file then.

04:15 Yes.

04:16 - Exactly.

04:17 - And--

04:18 - I think it might even create the virtual environment, though I haven't actually tried that yet.

04:21 - Yeah, it does.

04:22 Yeah, if you don't have one already, it'll create it.

04:24 And also, if you already had one, and it was out of sync, like UV sync, that's kind of what the part of the sync does.

04:32 If somebody updated some of the requirements, so the UV lock had changed,

04:37 then UV sync will rewrite the virtual environment.

04:41 So--

04:42 - Nice.

04:43 And so he's showing also that his version of how to specify the Python version

04:50 is to just specify it within your pyproject.toml and UV will grab that and install it if necessary.

04:57 And then also interesting discussion around version because pyproject.toml requires a version

05:04 but with a lot of applications we don't really utilize the version because it's just code that you're pushing and running.

05:12 So he said, "Just set it, if you don't care about the version, just set it to zero,

05:16 and then people will realize you're not using it." So...

05:20 The world's most common version.

05:22 Yeah.

05:22 And then also a discussion around the separation of dependency groups that came in recently

05:28 that UV handles nicely in PyProject TOML files.

05:33 And that allows you to separate your dependencies based on really what the application needs

05:39 versus what you need for development.

05:41 this will work then you can run. In production it won't install your like pytest and stuff,

05:49 but it'll install everything else. But when you're creating a virtual environment locally to develop,

05:54 it'll grab those also. So very cool to have all of this together. And then build system,

06:01 I didn't really realize that you could specify UV as a build backend. And I'm going to have to

06:11 hatchling in mind and, I believe several people have pointed out that hatchling is

06:16 the default. And the reason that we, when we played with this the very, very first time

06:20 it didn't show up with any build back in is because we created in, application mode,

06:25 but I think if we created a package mode, there's a way to say like, well, what really

06:29 kind of project are you creating? Then it specifies the build back in explicitly, I

06:32 think. So anyway, a lot of, a lot of options there, but yeah, very cool.

06:36 Yeah, and actually just an enjoyable video too.

06:40 I like what he's doing there.

06:41 So check it out.

06:42 Very nice.

06:44 Well, let's talk about async and await.

06:49 So there's this cool project called AIO Limiter, an efficient implementation of a rate limiter for async I/O.

06:56 And this comes to us from Martin Peters.

06:59 Martin Peters, at least at one point, was the most prolific Stack Overflow Python person.

07:06 period. So that was fun. And this project is a something that got created as a result

07:13 of an answer on Stack Overflow by him. So not a big surprise. I've, I'll beat on the

07:19 dead horse a little bit, Brian. I feel like there's a really, there's a big missing piece

07:23 for async and await in Python. And that is any sort of mechanism or control or, or understanding

07:30 or adjustment or whatever of the underlying running of async code in general.

07:36 Right?

07:36 If I call an async function and I say a way to thing, how does it run?

07:41 Well, you don't know.

07:43 It might be running in an event loop that you've created, it might be running in one

07:47 that you, a framework created.

07:49 You don't sometimes often, most of the time let's say, you don't get a choice on how that

07:53 loop is created.

07:54 For example, if you're using FastAPI, FastAPI creates a loop and says, "Here, you can use

07:58 this one.

07:59 like it. You know what I mean? Whereas systems like.NET, they've got thread pools and async

08:06 I/O pools and contexts and stuff that you can say, "Hey, on this one, I want you to

08:11 limit to 10. So if you're doing work, just do 10 at a time. When you're done with one,

08:15 allow the other ones to come in, otherwise queue them and just make them away." Right?

08:18 Stuff like that is kind of missing. So all these projects are trying to backfill that

08:23 kind of functionality into Python's async and await. And this is cool. So it does give

08:27 you like suppose you're working on a project and you're using an external API

08:32 and the API says you have a rate limit of five per second if you go over that

08:36 we're gonna start failing and telling you status code 429 too many requests

08:40 wait however long and try again but that becomes like really janky right so with

08:45 this thing what you can do is I can create a rate limiter and say I'm willing to allow a hundred calls within a 30-second window or the example I gave

08:54 five calls within a one-second window or whatever, right?

08:57 Something like that.

08:58 And then you just put that into a async with block and then stuff that happens in that window

09:03 will be limited by this rate limit.

09:05 - Okay.

09:06 - Cool, right?

09:06 So it makes it really easy to handle those kinds of things.

09:09 But often it's not like I'm going to make all of the calls here, you know what I mean?

09:15 It's I want all the async calls in the system to be limited in this way,

09:19 not the ones that I'm controlling the particular function of, which is sort of the crux of my complaint that I started with.

09:26 But this is nice.

09:26 You create one of these somewhere, and then anywhere you use this rate limit

09:30 as a context manager, it is subject to that rate limiting.

09:34 So it doesn't have to be the same function.

09:36 It doesn't have to be all the codes are happening at the same time within the block.

09:40 So, you know, that's a pretty nice thing, right?

09:43 As long as you just put that in all the places you need it.

09:45 Like, for example, one of the problems you can do is you're getting too many requests.

09:48 You can overwhelm your database, and because you're awaiting it asynchronously,

09:53 you could just keep feeding it to the database, even if the database is slowing down

09:56 and slowing down and slowing down.

09:57 So like in your data access layer, you could just wrap all of your queries

10:01 in one of these things that say, don't let more than, I don't know, 10 per second

10:05 or whatever is reasonable for your database.

10:08 That's kind of low, but you know what I mean.

10:10 Like you can sort of control that.

10:11 - So you might like have one of these rate limiter for your database and then maybe one for an external API or-

10:19 - Yes, theoretically, and they could be different, right?

10:22 - Yeah, okay, that makes sense.

10:24 - Yeah, anyway, yeah, I thought this was kinda cool, and people who are worried about trying to solve

10:29 that problem, then they can use this as one of the tools there.

10:35 - Computers are so fast, sometimes we're like, it's too fast, slow down a little bit.

10:38 - Yeah, it's like, let's make it allow it to do all the work and not wait on any of it,

10:42 like, usually good, sometimes bad.

10:45 - Sometimes bad.

10:47 - But the thing on the end doesn't like it.

10:49 - Yep.

10:50 - Yeah, and out in the audience we got a, "Wow, cool," says Aziz.

10:53 "I had this limit problem a lot." Yeah, awesome.

10:55 Hope it helps.

10:56 - Yeah, hope it limits your problems.

10:58 - It does limit, it will limit your problems.

11:01 What's next?

11:02 - That was weak.

11:02 So, I wanna talk about SpyStuff.

11:05 So, Lucas Lange wrote an article about SpyStuff.

11:10 Actually, "A Peek into a Possible Future "of Python in the Browser." who, there's a, it's a kind of a fun article also,

11:19 but a great picture as well, some cool picture of the mountains.

11:22 Anyway, and you know, he's, I trust what he, I trust his opinion because of his involvement with Python and everything,

11:30 but this is interesting about a lot of the core Python people really involved with thinking about the web.

11:38 So there's a section about looking back on, I haven't read this, or seen this,

11:44 but apparently there was a Gary Bernhardt talk about the birth and death of JavaScript.

11:48 I'll have to go back and look at that.

11:50 And then, but basically talking about the history of Python and--

11:53 - Wait, wait, wait, wait, wait.

11:54 If you have not seen the birth and death of JavaScript, it needs to go to the top of your list.

11:59 - Okay.

12:00 - The birth and death of JavaScript is a seminal video that is both hilarious and very insightful.

12:06 - Okay, well--

12:06 - And the JavaScript is part of the joke.

12:09 - Okay, JavaScript, all right.

12:11 Well, then he goes on to talk about Pyodide other things and using NumPy and Cython and stuff. But the real thrust here is a new research

12:27 project called SPI. S, capital S, capital P, lower Y, I guess. So that's SPI stuff.

12:36 The article says the SPI is a research project in its early stages. At the moment, don't

12:41 attempt to use it yet unless you plan to contribute.

12:44 But maybe you do plan to contribute.

12:47 Both incomplete implementation-wise and design-wise, but so early stages.

12:53 But it sounds pretty cool.

12:55 So there's this-- I like the idea.

12:57 So there's this-- I'm going to jump down to the demo, see if we can get it to play.

13:02 So-- ooh, I had video sound too, but I don't think you hear that.

13:05 But anyway, there's a demo of it working, of some shapes shifting around.

13:09 And that's actually running in the browser already, but you just can't, I guess it's not complete yet.

13:15 But this idea of having things that look like Python.

13:20 So when you're, there's like blue code and red code is the idea.

13:25 And the blue code is stuff that just like acts like Python.

13:28 And that's great for debugging and stuff.

13:31 And because people are used to writing in Python.

13:34 And then there's a redshift model of, 'cause that's what we do a lot is like,

13:39 whether we should compile it or not.

13:40 But this will pre-compute a lot of the stuff that's blue into a pre-compiled version.

13:49 Anyway, all the little compilation parts to make things run faster.

13:53 But I really like the idea that you've got a level where you're running it just as pure Python

13:59 and then you can deploy it and it runs as a compiled part.

14:03 So anyway, I'm probably getting this wrong at early stages, but we've got links to this article and then to the Spy Project itself,

14:11 which a lot of activity just recently.

14:14 So anyway, I like that and mostly, I don't know why I brought this up.

14:20 The, the, the story of Python in the web browser, better and better.

14:24 So anyway, I also bookmarked this article as something super interesting that should,

14:31 you know, might be worth talking and reading up on.

14:33 So thanks for covering it.

14:34 Yeah.

14:34 And if you've got a deeper, - We're on the verge.

14:36 - You mentioned we could bring it up later again as well.

14:39 - Yeah, yeah, it's early days, so maybe there'll be more news on it.

14:42 I'm very excited about the possibility of Python in the browser.

14:47 It'll uncork some amazing stuff if that really gets running seamlessly.

14:52 - And really, I'm saying the browser, but really what we're also meaning is that

14:57 if we could not have different front-end and back-end languages, so if we do all the dynamic front-end stuff with Python,

15:04 be cool.

15:05 Exactly.

15:06 Exactly.

15:07 Like, so I think that the browser manufacturers could do significantly more to make this better for, for example, every one of them ships a

15:17 JavaScript runtime that's optimized.

15:19 Right.

15:19 Not a single one of them ships the WebAssembly version of Ruby or the web

15:25 assembly version of CPython, you know, Pyodide or the WebAssembly version of

15:29 .NET for Blazor or all these things.

15:32 And so all of those projects are like, well, it'd be great to use this.

15:35 but it's really slow to download the whole runtime on each page separately.

15:39 - Yeah.

15:40 - Every browser could say, "We will provide and keep up to date "as part of our binaries,"

15:46 or just off of the internet or whatever as you download it, "a shared Python runtime, a shared Ruby runtime,

15:52 "a shared.NET runtime," and so on, and they don't.

15:55 - Yeah.

15:56 - Right, but all these complaints about, "Well, the web frontend's too slow

16:00 "'cause you gotta download all this stuff," like, yes, you do now, but it could theoretically be that they say, well, we're going to support like an

16:08 open sort of management of these, these binary, these WebAssembly runtimes that

16:12 you might need to download.

16:13 Sure, the extras you got to download every time like JavaScript, but the core

16:17 runtime of 10 megs, we'll like update that with our browser or just update it as it

16:22 changes on the web.

16:23 I wish they would do that.

16:25 Right.

16:25 I mean, you know, they do it for JavaScript.

16:27 I mean, come on now.

16:29 Right.

16:29 It's like, it sounds crazy, but at the same time they do it for JavaScript and

16:32 they write their own.

16:33 All right, they wouldn't even have to write their own.

16:35 They just got to allow the run of random others.

16:38 Okay, enough of that.

16:39 Let's talk about reloading stuff in the browser.

16:41 Instead, that sounds fun.

16:42 So there's two projects I want to tell you about.

16:45 One is the big heavyweight does so much stuff to help you write web applications,

16:51 type in the editor, and have that stuff magically change.

16:55 For example, by default, if I run a Flask app and I go over to the, I run it and I open it up in a browser,

17:01 and I see the page I'm working on, and then I go over and I edit the Jinja template.

17:05 I hit save, and I refresh the browser, nothing happens.

17:09 I have to go back to Flask, restart Flask, go back to the browser, reload the browser,

17:15 now I can see my changes.

17:17 You can level that up one by going to Flask and say you're running in debug mode,

17:21 so if you see any changes, please rerun Flask and reload the templates if I edit the templates.

17:27 Then you can just edit your thing, save it, go over to your browser, hit refresh, see the changes.

17:33 But what would be nicer if I could have like two thirds of my screen be my editor,

17:37 one third of my screen be the web browser.

17:39 And as I type, I see stuff just changing on the page.

17:43 So if I put a CSS class on a thing, I don't have to go to the other app and do anything.

17:47 It just literally just the changes that apply like every second or so, right?

17:52 So that's what this Relodium thing is, but it does a lot.

17:56 So I want to put this out there for people as a cool option.

17:59 I'm not sure I'm going to put it out there as a recommendation yet.

18:01 So let me tell you.

18:02 So for example, it will not just do the experience I told you about, but it will

18:07 actually rerun every function.

18:10 If you make a change to a function, it will rerun it and you can actually

18:13 have it doing like live profiling.

18:16 So as you, as you type there, it'll give you a profiled output of the thing and so

18:24 on.

18:24 So if you kind of want to explore it, it gives you like that idea more broadly.

18:27 So it works there.

18:29 it comes with a PyCharm plugin which is what the little animation is so you can

18:33 actually see a visual representation of like the performance time and how it's

18:37 running and reworking and so on. Okay so that's pretty neat. Comes with an AI

18:41 thing I'm gonna skip that I don't know what that is or care. It has yeah so

18:47 generally if you make a change to a function it will re-execute the current

18:51 function providing immediate feedback and if there's an error it doesn't die

18:55 it just goes well okay once you fix it things are going to be good and it'll

18:58 start working again. So it's kind of durable to that, you know. And it'll

19:03 refresh files throughout the entire project, looking at dependencies. So if I

19:07 make a change to like one bit, then it'll change the others, you know, like with

19:10 new import or whatever. For Django, it does exactly what I was telling you, like

19:15 as you type, not just as you type HTML, but as you type Python. So the example

19:20 they have here is they, they're doing a query for all objects and then they

19:24 slice it to do a limit, paging and limiting type of business, and as they change the numbers

19:30 in the slice in Python, the web browser is automatically updating the results without

19:35 them touching it.

19:35 That's pretty cool.

19:37 Yeah, it's pretty cool, right?

19:39 Similarly for Flask, it automatically reloads Flask, but again, it says, look, it'll hot

19:44 reload the Flask app, but if you just set Flask debug to be true, Flask will already

19:50 do that, you know what I mean?

19:52 So the one thing it doesn't do is it doesn't refresh the page as you type on one side.

19:57 The stuff on the right doesn't change, right?

19:58 Another thing it does, it'll for SQLAlchemy because it's like running functions over and

20:03 over and over, it might start to do insert, insert, insert to the database.

20:07 So it does these auto runs and transactions that roll back so it doesn't tweak the database.

20:12 Oh, interesting.

20:13 Yeah.

20:13 And it also does hot reload for pandas.

20:16 So if you're messing with your data frame or things like that, it'll just automatically

20:20 be updating as you type.

20:21 - All right, pretty interesting, right, Brian?

20:23 - Yeah.

20:24 - Yeah, I don't know if I talked about it before, but just since people might want

20:27 a less intrusive version of that.

20:29 So I have this project called Server Hot Reload over on GitHub, and it's a single JavaScript file.

20:34 And if you just include the JavaScript file in your page, it will give you the same functionality

20:40 for web apps that will reload the template.

20:43 So for example, if you just include the JavaScript at the top of the page,

20:48 and then Flask, if you run it with Flask debug, or Pyramid automatically reloads in debug mode.

20:54 You can set that in the config file, and I'm sure you can do similar stuff with Django.

20:59 And then you just browse on one side, code on the other, and you just start typing,

21:03 and off it goes, and even detects if you set it up right, or even like reload the page if you change an image

21:08 that was being used, and things like that.

21:11 So, super cool, but this one, it doesn't go all crazy.

21:14 It doesn't require an IDE plugin and all that kind of stuff.

21:18 Basically what it does is it looks at the response from the server and says, "Is the

21:22 hash of the HTML changed?

21:24 If yes, reload the page.

21:26 If it's not changed, then don't reload the page," that kind of thing.

21:29 So anyway, two ways to basically work in your editor, start typing, and having some kind

21:36 of output web or in Relodium, other places, just automatically changing as you type so

21:41 you don't have to manage that.

21:42 You're just like, "Oh, what's this class?

21:43 Oh, that looks really great.

21:44 No, we need more padding here, da-da-da," off it goes.

21:47 - So the server one probably doesn't do the, like if you change Python or--

21:53 - Technically no, it doesn't do that.

21:55 However, if you set Flask to do that automatically and then it re-requests the page, then yes it does.

22:01 You know what I mean?

22:01 - Okay, got it.

22:02 - So if you're willing to use the framework tools, then it does.

22:06 - Okay, okay, very good, cool.

22:08 - Yeah, but it's nowhere near as intense, which I think for some people is a drawback

22:12 and other people is a plus, depending on where you are.

22:16 - Okay, nice.

22:17 - All right, that's it for all of our items, isn't it?

22:19 - Yeah, it is.

22:21 - Well then, what have you got for extras?

22:24 - I got just a pet project of mine that I wanted to talk about.

22:30 So the Complete pytest course has been out for a while, and there's a couple things about it that are a little,

22:36 that I'd really kind of like to change, so I'm working on some changes.

22:40 First of all, if you see, if you go to the, and look at it, it says there's 162 lessons.

22:45 It seems a little scary and the reason is because I've chopped it all up into, so there's

22:51 16 chapters in the book, the course covers the entire book, 16 chapters, each video covers

22:57 a section of a chapter and that's where, plus welcome videos and stuff, that's where the

23:04 162 comes in.

23:06 But that's a little, there's actually 162 videos which is a little intimidating, especially

23:12 if you're looking at one and you kind of like, there's a lot here.

23:17 But I mean, it's all good if you like to go in just like a few minutes at a time, that's great.

23:23 But some people wanna just chunk through an entire chapter in like a lunch break or something.

23:28 So the alternate version that I'm working on is chopping this up into just chapters.

23:35 So most chapters will be one video.

23:37 And then you can just chunk through like just watching one video, you can watch it in a weekend,

23:43 or not a weekend, in like, you know, 20 minutes or something like that.

23:47 There's a couple chapters, chapter two and chapter three are pretty big, writing test functions,

23:53 and then fixtures, pretty big concepts.

23:56 So they're a little longer, so I'm chopping those not into one video, but like three videos.

24:03 And so, when I get all done, the new version will be not 162 lessons, but like 20 lessons or something like that.

24:13 And then I'll probably make that the default and I'll just have both of them available

24:17 because some people might like the little more granularity and it's not more effort on me to have both of them around.

24:24 So they'll both be around.

24:26 Anyway, that's what I'm up to.

24:29 - Cool.

24:30 Yeah, I like the small little videos.

24:31 I think it's a way better reference material.

24:34 You don't wanna have to go like, where in that 15 minute video was the thing I wanted?

24:38 - Yeah, that's the benefit.

24:39 The other thing is I like to, for videos, I like to probably set them at like 1.2 speed

24:45 or 1.3 speed the first time, or 1.25, maybe 1.4, to get an overview really quickly.

24:53 And you have to reset that for every video, and that's somewhat a little annoying.

24:57 - That's a hassle.

24:58 - Yeah.

24:59 - That is a hassle.

25:00 All right, well let's see what I got for extra.

25:01 I got an oldie, something fun here.

25:04 So there was a Hacker News thread or Reddit thread.

25:08 I'm gonna go with Hacker News.

25:09 Pretty sure it was Hacker News talking about, hey, could some people recommend

25:13 some cool, legit programmer fiction books?

25:18 Right, like I want a spy thriller that has to do with programming but that's not stupid.

25:24 Right, it's not like, whoa, this is VB6, I know that.

25:27 I'm gonna track their IP, like, you know what?

25:29 That's not how it works.

25:31 More Mr. Robot, less Jurassic Park or whatever that was.

25:34 I can't remember.

25:35 So, the book that I thought was really cool I'll give a shout out to is by Mark Russinovich

25:40 who is the CTO of Azure.

25:41 And apparently I bought this book in 2012 just to give you a sense.

25:44 So it's not brand new, but it is a super cool series as long as you keep in mind like its computer world was 2012

25:51 so people can check that out if they're interested.

25:53 Also, Warp on Windows.

25:56 I'm a big fan of Warp, the terminal.

25:59 It's been working out super, super well.

26:01 I tried ghost TT or ghost DD or whatever, however you say that.

26:06 Just, I cannot do it.

26:07 I can't do it.

26:08 Like, it doesn't even let you like select text with hotkeys and stuff.

26:11 It just puts like control H and stuff in there.

26:14 And then until you can work with it as an editor, no, I can't do it.

26:19 So, I mean, I know there's some way, like you can hold shift and arrow, but you can't do like control shift arrow to do

26:26 like word by word.

26:27 And you can't do, like you can do a home, but you can't do like shift home.

26:30 These are like really weird, like editing and stuff where like some of it just starts putting

26:33 escape characters into the thing.

26:36 I don't remember exactly what it was 'cause when I saw it, I'm like, okay,

26:39 we'll come back to this some other time.

26:40 Anyway, if you are on Windows and you're looking for a better terminal, and I know Windows has fewer options

26:46 and less good options than the other places for a variety of terminals, like there's Windows Terminal,

26:52 and then, I don't know, is there anything else?

26:54 I'm not sure.

26:54 There's definitely Command Prompt.

26:56 - Well, PowerShell runs within Windows Terminal.

26:58 Like you can run Git Bash or PowerShell or whatever the DOS-like stuff.

27:03 You can run all that in Windows Terminal.

27:05 - Oh, right, okay.

27:06 - Right?

27:08 You can do the same in Warp.

27:10 You can choose, do I want PowerShell, do I want Git Bash or whatever.

27:13 But the thing that is the outer bit of it, you know, the app itself, there's not many options.

27:20 So this is a cool thing that people can check out.

27:21 I'll link to the video 'cause it's fun, but you can just go to warp.dev or wherever it is.

27:25 Okay.

27:27 Our friends over at Teaching Python Podcast, they are participating in being

27:33 part of the PyCon 2025 Education Summit.

27:37 And they're pointing out that, Hey, the applications are going to be, you know,

27:45 sending a proposal very, very soon.

27:48 So that was, I think last Friday and today is Monday.

27:52 So, just recently opened up and they said the main theme is, in the age of AI, how do we maintain the creative,

27:58 empathetic, and critical thinking skills we need to make us human and great coders?

28:02 We want to know, and so there's a whole bunch of ideas around this.

28:05 So, we've got Kelly and Sean and a bunch of other people participating in this, so if that resonates with you,

28:12 check it out.

28:13 - No, I was just chuckling because even before AI, we hadn't figured that out as far as I could tell.

28:18 - Yeah, I don't really know the answer, So I'm going to ask ChatGPT, I'll get back to you.

28:22 [laughing]

28:22 Okay.

28:23 [laughing]

28:26 Yeah, one more extra here real quick.

28:28 I just noticed that Granian, which is powering Python by ZFM, by the way, and many, many other things,

28:33 just came out with their 2.0 release right there, seven hours ago.

28:37 How's that for fresh, shocking news?

28:39 Breaking news.

28:39 Breaking news.

28:42 [imitating drum roll]

28:43 As far as I can tell, there's a bunch of cool changes here.

28:46 One thing that's not cool is as far as I can tell it doesn't run FastAPI apps.

28:50 So if you have Gradient, powering your FastAPI app, you might test this before you just update.

28:58 There's also breaking changes in the CLI of like how you specify certain constraints and stuff.

29:03 That's easy enough to fix because it tells you this constraint such and such,

29:06 but I think there's something going on where at least all of my FastAPI apps stopped working when I switched to this,

29:12 but all the other ones like Cort and Flask and Pyramid all work fine.

29:16 - Interesting.

29:17 - Don't know why.

29:18 And Cort is async first just like FastAPI.

29:21 So I don't know what's going on, but they were not having it.

29:24 So I just pinned the version to less than two for those until whatever happens here gets figured out.

29:29 So there's just a little PSA.

29:31 All right, with that.

29:32 - So seven hours ago, you already tried it?

29:35 - Not on purpose.

29:36 I tried it three hours after it was released.

29:38 I needed to ship something else, but my deployment process is check something in the Git

29:44 and then have it go rebuild the Docker images and restart them.

29:47 And that's all, check all the dependencies, is there anything we can update?

29:50 Like, does Ubuntu have security fixes we need to apply?

29:54 Can we update the web server in case there's a security fix for it?

29:57 And then we'll rerun the dependencies and we'll restart it.

30:01 And then it didn't restart, I'm like, wait a minute, what?

30:03 Why, what's going on here?

30:05 This is not good.

30:07 So that's how I learned that there's a new release of "Granny." - Okay.

30:11 - You know what I mean?

30:12 It's not like I was like, "Oh, I gotta try it that quick." It tried itself on me and then it didn't go so well,

30:17 so I scrambled to fix it.

30:19 - Okay, got it.

30:20 - Yeah, yep.

30:21 Okay, joke?

30:23 - I'd love a joke.

30:24 - Tabs or spaces?

30:25 This one has to do with tabs or spaces.

30:27 I'll tell you a joke before the joke, a pre-joke, if you will, to get everyone in the mood.

30:31 This is like the bad joke, the bad comedian that shows up before the one you actually came to see.

30:36 So we were at PyCon, I don't know.

30:39 I think this might've even been in Portland.

30:40 This was a while ago.

30:42 And there was some company that was clearly not very tuned into Python.

30:46 They were just a coder company, right?

30:48 And they were like coming to sell their coder tools to the Python people.

30:51 And so as they wanted to make a spicy t-shirt and the spicy t-shirt said, "Tabs or spaces, fight."

30:58 Like this is the stupidest shirt I've seen at the whole conference.

31:01 I mean, tabs are basically disallowed.

31:03 They're not exactly disallowed, but they're pretty much disallowed.

31:06 - Like that's not an argument, it's over.

31:08 - And you're like, you're trying to set up as a debate, like you could do two spaces, four spaces and fight,

31:13 but you can't do tabs versus spaces at a Python conference.

31:17 Anyway, but people are going around with shirts nonetheless.

31:19 I think I got one to cut the lawn in.

31:21 - Okay, well, on that topic, two spaces or four spaces?

31:25 - Four, unless I'm doing JavaScript then two, 'cause for some reason the tools seem to default

31:29 to two for JavaScript, you?

31:32 like four usually, but I'm noticing that I'm using two frequently as well.

31:38 So, okay.

31:40 - Very contrarian.

31:41 Okay.

31:42 You're an enigma wrapped in a fuzzy cloud.

31:45 Okay.

31:46 How about this for, this is the real joke.

31:47 So I don't know if this is better or worse, but this is what people came for.

31:51 Code puns.

31:52 You ready, Brian?

31:53 - Yeah.

31:53 - A Python programmer walks into a bar and opens a tab.

31:56 The bartender tells them to sit at the table since they will need four spaces.

32:04 That's what I got for y'all.

32:10 No it's hilarious, see?

32:11 That's why people listen.

32:13 Yeah, yeah, yeah.

32:14 Oh no, I'm like advertising it poorly.

32:17 That was hilarious, man.

32:18 Good joke.

32:19 Now, there's actually a bunch more here.

32:20 We've talked about this place before, right?

32:22 Yeah.

32:23 Let's see.

32:24 They're not all good.

32:25 Why did the four loops stop running?

32:27 It took a break.

32:28 Yeah.

32:29 How do you convert a JavaScript bug?

32:31 You console it, like it's console log and so on.

32:34 There we go.

32:38 - No, it's good, thanks.

32:39 - I think it was hilarious, I know.

32:41 I hear the flaws, no, not really.

32:43 But that's what I brought anyway.

32:47 - Good talking with you again, and thanks everybody for listening.

32:50 - Yeah, you bet, bye all.

Back to show page