We're sunsetting PodQuest on 2025-07-28. Thank you for your support!
Export Podcast Subscriptions
cover of episode #422 You need 4 spaces

#422 You need 4 spaces

2025/3/3
logo of podcast Python Bytes

Python Bytes

AI Deep Dive AI Chapters Transcript
People
B
Brian
Python 开发者和播客主持人,专注于测试和软件开发教育。
M
Michael
帮助医生和高收入专业人士管理财务的金融教育者和播客主持人。
Topics
Brian: 我推荐使用Hynek Schlawack提出的基于`uv`的Python项目布局,它使用简单的`pyproject.toml`文件和`uv.lock`文件来管理依赖,替代传统的`requirements.txt`文件,并建议将`uv.lock`文件提交到版本控制中。这个方法简化了依赖管理,提高了项目可复用性。此外,我还讨论了如何使用`uv run`和`uv sync`命令来运行和同步项目依赖。在`pyproject.toml`文件中指定Python版本,并建议对于不需要版本控制的项目,将版本设置为0。最后,我还提到了`pyproject.toml`文件中依赖分组的用法,以及如何使用`uv`作为构建后端。 在Łukasz Langa的文章中,我看到了Python在浏览器端应用的未来展望,特别是SPy项目,这是一个用于在浏览器中运行Python的早期研究项目,旨在提供一种更流畅的Python在Web浏览器中的运行体验,未来可能消除前后端语言的差异。虽然目前该项目尚处于早期阶段,但其潜力巨大。 最后,我还简要介绍了我的一个个人项目:Server Hot Reload,这是一个单一的JavaScript文件,可以实现Web应用程序的模板热重载,无需IDE插件等复杂配置。 Michael: 我介绍了`aiolimiter`项目,这是一个高效的异步IO速率限制器,可以帮助开发者精确控制代码段的执行速率,避免因为过多请求而导致系统过载。它实现了漏桶算法,允许开发者设置请求速率,并通过`async with`块来限制代码段的执行速率。这个项目可以有效地解决与外部API或数据库交互时可能出现的速率限制问题。 我还介绍了Reloadium项目,这是一个热重载和性能分析工具,可以实现代码修改后浏览器页面的自动更新,并提供实时性能分析功能,提高开发效率。它支持多种框架和库,例如Flask、Django、SQLAlchemy和pandas,并具有错误处理和事务回滚等功能。

Deep Dive

Chapters
This chapter explores Hynek Schlawack's approach to Python project layout using pyproject.toml and the UV tool. It emphasizes the benefits of using UV.lock for dependency management and the simplification of the project structure.
  • UV-based project layout for production apps
  • ditch requirements.txt files
  • pyproject.toml for managing dependencies
  • UV.lock for dependency locking
  • using UV run and UV sync

Shownotes Transcript

Translations:
中文

Hello and welcome to Python Bytes, where we deliver Python news and headlines directly to your earbuds. This is episode 422, recorded March 3rd, 2025. I am Michael Kennedy. And I am Brian Ocken. And this episode is brought to you by us. Check out Brian's

PyTest courses. Check out the ones over at TalkPython Training. We're up to almost 475 hours. 275 hours. Not that many. 275 hours of courses over at TalkPython. There are many to choose from there. Amber writes book and Patreon supporters and all these things. Thank you so much.

Also, we're continuing to improve and evolve our newsletter, which gives you, I think, insights into the episode that we maybe didn't explicitly call out and certainly are not in the show notes. So head over to pythonbytes.fm, click on newsletter, put in your email. 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. Yeah. So with that said, Brian.

How do we start our show today? Let's start it with a video, kind of. Wait, isn't this already a video if people want to watch it? Yeah, yeah. Very meta of you. Yeah, so I'm trying to add this to the stage. What's going on? Oh, they're wrong. Anyway, there we go.

Technical difficulties that won't make any sense to anybody listening. We don't normally cover video because it's, I don't know why, but I don't watch a lot of Python videos, I guess. But this one is a do not miss. Hinnick put out a video called My 2025 UV-Based Python Project Layout for Production Apps.

And I was paid attention to this partly to see what he was up to, and I like UV. But also, when you watch it, his example is a fast API app. And

In his world, an app is usually really a website app. And later he's going to go on to talk about Docker, I think, because this is part one of a series. But this one's already enough that I think it's really useful. And especially in some of the stuff I deal with, I think of an app as anything that's packaged kind of.

Like it's not a package. It's not something you put on PyPI, but it's a bunch of your own code that you normally would have used a requirements.txt file. And I like his model better. So I'm going to jump in. I got a couple of tabs because it's kind of hard to like navigate. Anyway, snapshot videos. So I stopped them where I wanted to. So the video is great. It's about 25 minutes long. It's pretty quick to watch.

Here we've got the project layout. So his project layout is using a source layout and really there's no requirements file. All of the requirements are in the pyproject.toml and instead of a custom lock file or one you manually do,

he's just recommending that you let UV take care of a lot of the project stuff. And actually, even with so and we'll take a look a little bit more what's in PI project at Tamil, but he's recommending that you go ahead and check in the UV lock. So if you're letting UV handle your virtual environment, it's going to create a lock file. And if you commit that, then

UV run later will use that and use all of the stuff in the lock file. And you, instead of running Python, you just...

clone the repo, run UV run on your project, and it's going to grab everything out of the lock file. It's just like pin dependencies. It's pretty sweet. Yeah, I 100% agree with him. Check in the UV lock file. And then you don't also, you don't even have to do UV run if you don't want. You can just do UV sync, and it will also use the pin dependencies in the lock file. And then, because some systems...

they require you to run kind of with their setup. For example, Pyramid, you need to use PSERV and then it's like configuration file or Flask. You can do like Flask run or Django. So if you still want to stick with that, you can just do UvSync. So UvSync will grab everything out of the lock file then? Yes, exactly.

um and i think it might even create the virtual environment though i haven't actually tried that yet yeah it does yeah if you don't have one already it'll create it and also if you already had one and it was out of sync like uh uv sync that's kind of what the part of the sync does if somebody updated some of the requirements so the uv lock had changed then uh uv sync will um rewrite the virtual environment so

And so he's showing also that his version of how to specify the Python version is to just specify it within your pyproject.toml. And UV will grab that and install it if necessary.

And then also an interesting discussion around version because pyproject.toml requires a version, but with a lot of applications, we don't really utilize the version because it's just code that you're pushing and running. So he said, just set it. If you don't care about the version, just set it to zero and then people will realize you're not using it. The world's most common version. Yeah, and...

And then also a discussion around the separation of dependency groups that came in recently that UV handles nicely in PyProject Toml files. And that allows you to separate your dependencies based on really what the application needs versus what you need for development. And this will work, then you can run-- in production, it won't install your like PyTest and stuff.

but it'll install everything else. But when you're creating a virtual environment locally to develop, it'll grab those also. So very cool to have all of this together. And then build system, I didn't really realize that you could specify UV as a build backend. And I'm going to have to play with that. That's pretty cool. So are you muted?

I put Hatchling in mind and I believe several people pointed out that Hatchling is the default. And the reason that we, when we played with this the very, very first time it didn't show up with any build back in is because we created in application mode. But I think if we created in package mode, there's a way to say like, well, what really kind of project are you creating? Then it specifies the build back in explicitly, I think. So anyway. Yeah.

A lot of options there, but yeah, very cool. Yeah. Actually, just an enjoyable video too. I like what he's doing there. So check it out. Very nice. Well, let's talk about

Async and await. So there's this cool project called AIO limiter, an efficient implementation of a rate limiter for async IO. And this comes to us from Martin Peters. Martin Peters, at least at one point was the most prolific stack overflow Python person.

So that was fun. And this project is a, something that got created as a result of an answer on Stack Overflow by him. So not a big surprise. I've, I'll beat on the dead horse a little bit, Brian.

I feel like there's a really, there's a big missing piece for async and await in Python. And that is any sort of mechanism or control or understanding or adjustment or whatever of the underlying running of async code in general, right? If I call an async function and I say await a thing, how does it run? Well...

You don't know. It might be running in an event loop that you've created. It might be running in one that you, a framework created. You don't sometimes, often, most of the time, let's say you don't get a choice on how that loop is created. For example, if you're using fast API, fast API creates a loop and says, here, you can use this one. Hope you like it. You know what I mean? Whereas systems like .NET, they've got thread pools and async IO,

pools and contexts and stuff that you can say, hey, on this one, I want you to limit to 10. So if you're doing work, just do 10 at a time. When you're done with one, allow the other ones to come in. Otherwise, cue them and just make them wait, right? Stuff like that is kind of missing. So

So all these projects are trying to backfill that kind of functionality into Python's async and await. And this is cool. So it does give you, like suppose you're working on a project and you're using an external API. The API says you have a rate limit of five per second. If you go over that, we're going to start failing.

and telling you status code 429, too many requests, wait however long and try again. But that becomes like really janky, right? So with this thing, what you can do is I can create a rate limiter and say, I'm willing to allow 100 calls within a 30 second window or the example I gave, five calls within a one second window or whatever, right? Something like that.

And then you just put that into a async with block. And then stuff that happens in that window will be limited by this rate limit. Okay. Cool, right? So it makes it really easy to handle those kinds of things. But often it's not like I'm going to make all of the calls here. You know what I mean? It's I want all the async calls in the system to be limited in this way, not the ones that I'm controlling the particular function of, which is sort of the crux of my complaint that I started with.

But this is nice, you create one of these somewhere and then anywhere you use this rate limit as a context manager, it is subject to that rate limiting. So it doesn't have to be the same function, it doesn't have to be all the codes are happening at the same time within the block. So, you know, that's a pretty nice thing, right? As long as you just put that in all the places you need it. Like for example, one of the problems you can do is you're getting too many requests, you can overwhelm your database and because

you're awaiting and do it asynchronously, you could just keep feeding it to the database, even if the database is slowing down and slowing down and slowing down. So like in your data access layer, you could just wrap all of your queries in one of these things that say, don't let more than, I don't know, 10 per second or whatever is reasonable for your database. That's...

kind of low, but you know what I mean? Like you can sort of control that. So you might like have one of these rate limiter for your database and then maybe one for an external API or. Yes. Yeah. Yeah. Theoretically. And they could be different. Right. Yeah. Okay. That makes sense. Yeah. Anyway. Yeah. I thought this was kind of cool. And people who are, are worried about trying to solve that problem, then they can use this as one of the tools there. Yeah.

uh computers are so fast sometimes we're like it's too fast slow down a little bit you know it's like let's make it allow to do all the work and not wait on any of it like uh usually good sometimes bad sometimes it's bad but the thing on the end doesn't like it yeah out in the audience we got a wow cool says aziz i had this limit problem a lot yeah awesome hope it helps yeah hope it limits your problems it does love it it will limit your problems

What's next? That was weak. So I want to talk about spy stuff. So Lucas Langa wrote an article about spy stuff. Actually, a peek into a possible future of Python in the browser. So it's kind of a fun article also, but a great picture as well. Some cool picture of the mountains. Anyway. And, you know, he's...

I trust his opinion because of his involvement with Python and everything. But this is interesting about a lot of the core Python people really involved with thinking about the web. So there's a section about looking back on, I haven't read this or seen this, but apparently there was a Gary Bernhardt talk about the birth and death of JavaScript. I'll have to go back and look at that.

And then basically talking about the history of Python. Wait, wait, wait. If you have not seen the birth and death of JavaScript, it needs to go to the top of your list. The birth and death of JavaScript is a seminal video that is both hilarious and very insightful. Okay. And the JavaScript is part of the joke. Okay. JavaScript. JavaScript.

All right. Well, then he goes on to talk about pydide and other things and and, you know, using numpy and cython and stuff. But the real thrust here is a new a new research project called Spy S capital S capital P lower Y, I guess. So that's my stuff.

The article says the SPY is a research project in its early stages. At the moment, don't attempt to use it yet unless you plan to contribute. But maybe you do plan to contribute.

It's both incomplete implementation-wise and design-wise, so early stages. But it sounds pretty cool. So there's this-- I like the idea. So there's this-- I'm going to jump down to the demo, see if we can get it to play. Ooh, had video sound too, but I don't think you hear that. But anyway, there's a demo of it working, of some shapes shifting around. And that's actually running in the browser already. But you just can't-- I guess it's not complete yet.

but this, this idea of having, having things that look like Python. So when you're, when you're there's like blue code and red code is the idea. And the blue code is stuff that just like acts like Python. And, and that's great for debugging and stuff. And because you can, people are used to writing in Python. And then there's a red shift model of, cause that's what we do a lot is like whether we should compile it or not, but this will, yeah,

like pre-compute a lot of the stuff that's blue into a pre-compiled version. Anyway, all the little compilation parts to make things run faster. But I really like the idea that you've got a level where you're running it just as pure Python and then you can deploy it and it runs as a compiled part. So anyway, I'm probably getting this wrong at early stages, but we've got links to this article and then to the SPI project itself.

which a lot of activity just recently. So anyway, I like that. And mostly, I don't know why I brought this up. The story of Python in the web browser better and better. So anyway.

I also bookmarked this article as something super interesting that should, you know, might be worth talking and reading up on. So thanks for covering it. Yeah. And if you've got a deeper, we're on the verge. We can bring it up later again as well. Yeah. Yeah. It's early days. So maybe there'll be more news on it. I'm very excited about the possibility of Python in the browser. It'll, it'll uncork some amazing stuff. If that really gets running seamlessly. Yeah.

And really, say in the browser, but really what we're also meaning is that if we could not have different front-end and back-end languages, so if we do all the dynamic front-end stuff with Python, it'd be cool. Yep, exactly. I think that the browser manufacturers could do significantly more to make this better. Yeah. For example...

Every one of them ships a JavaScript runtime that's optimized, right? Not a single one of them ships the WebAssembly version of Ruby or the WebAssembly version of CPython, you know, Pyodide, or the WebAssembly version of .NET for Blazor or all these things. And so all of those projects are like, well, it'd be great to use this, but it's really slow to download the whole runtime on each page separately.

Every browser could say, we will provide and keep up to date as part of our binaries or just off of the internet or whatever as you download it, a shared Python runtime, a shared Ruby runtime, a shared .NET runtime and so on. And they don't. Right? But...

All these complaints about, well, the web front end is too slow because you've got to 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 open sort of management of these binary, these WebAssembly runtimes that you might need to download. Sure, the extras you've got to download every time, like JavaScript, but the core runtime of 10 megs, we'll like update that with our browser or just update it as it changes on the web. I wish they would do that. Yeah, they would.

Right? They do it for JavaScript. I mean, come on now. It sounds crazy, but at the same time, they do it for JavaScript, and they write their own. All right. They wouldn't even have to write their own. They just got to allow the running of others. Okay.

Enough of that. Let's talk about reloading stuff in the browser. Instead, that sounds fun. So there's two projects I want to tell you about. One is the big heavyweight does so much stuff to help you write web applications. Type in the editor and have that stuff magically change. 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 and I see the page I'm working on. And then I go over and I edit the Jinja template. I hit save and I refresh the browser. Nothing happens. I have to go back to Flask and restart Flask.

go back to the browser, reload the browser. Now I can see my changes. You can level that up one by going to flask and say you're running into bug mode. So if you see any changes, please rerun flask and reload the templates. If I edit the templates, then you can just edit your thing, save it, go over to your browser, hit refresh, see the changes. But what would be nicer if I could have like two thirds of my screen, be my editor, one third of my screen, be the web browser. And as I type,

I see stuff just changing on the page. So if I put a CSS class on a thing, I don't have to go to the other app and do anything. It just literally just the changes that apply like every second or so. Right.

So that's what this reloading thing is, but it does a lot. So I want to put this out there for people as a cool option. I'm not sure I'm going to put it out there as a recommendation yet. So let me tell you. So for example, it will not just do the experience I told you about, but it will actually rerun every function. If you make a change to a function, it will rerun it and you can actually have it doing like live profiling. So as you,

As you type there, it'll give you a profiled output of the thing and so on. So if you kind of want to explore it, it gives you like that idea more broadly. So it works there. It comes with a PyCharm plugin, which is what the little animation is. So you can actually see a visual representation of like the performance time and how it's running and reworking and so on. Okay. So that's pretty neat. It comes with an AI thing. I'm going to skip that. I don't know what that is or care. It has...

Yeah, so generally if you make a change to a function, it will re-execute the current function providing immediate feedback. And if there's an error, it doesn't die, it just goes, well, okay, once you fix it, things are going to be good and it'll start working again. So it's kind of durable to that, you know? And it'll refresh files throughout the entire project, looking at dependencies. So if I make a change to like one bit, then it'll change the others, you know, like with do import or whatever. For Django,

It does exactly what I was telling you, like as you type, not just as you type HTML, but as you type Python. So the example they have here is they're doing a query for all objects and then they slice it to do a limit, paging limiting type of business. And as they change the numbers in the slice in Python, the web browser is automatically updating the results without them touching it.

That's pretty cool. Yeah, it's pretty cool, right? Similarly for Flask, it automatically reloads Flask. But again, it says, look, it'll hot reload the Flask app. But if you just set Flask debug to be true, Flask will already do that. You know what I mean? So the one thing it doesn't do is it doesn't refresh the page as you type on one side, the stuff on the right doesn't change, right? Another thing it does, it'll, for SQL Alchemy, because it's like running functions over and over and over, eh,

I started to insert, insert, insert to the database. So it does these auto runs and transactions that roll back so it doesn't tweak the database. Oh, interesting. Yeah, and it also does hot reload for pandas. So if you're messing with your data frame or things like that, it'll just automatically be updated as you type. All right, pretty interesting, right, Brian? Yeah. Yeah, I don't know if I talked about it before, but just since people might want a less intrusive version of that,

So I have this project called Server Hot Reload over on GitHub, and it's a single JavaScript file. And if you just include the JavaScript file in your page, it will give you the same functionality for web apps that will reload the template. So for example, if you just include the JavaScript at the top of the page, and then in Flask, if you run it with Flask Debug or Pyramid automatically reloads in debug mode, you can set that in the config file. And I'm sure you can do similar stuff with Django.

And then you just browse on one side, code on the other, and you just start typing. And off it goes. And even to text, if you set it up right, it'll even reload the page if you change an image that was being used, things like that.

Super cool. But this one, it doesn't go all crazy. It doesn't require an IDE plugin and all that kind of stuff. It basically, what it does is it looks at the response from the server and says, is the hash of the HTML changed? If yes, reload the page. If it's not changed, then don't reload the page and that kind of thing. So anyway, to,

two ways to basically work in your editor, start typing and having some kind of output web or in the reloading of other places. So it's automatically changing as you type. So you don't have to manage that. You're just like, Oh, what's this class? Oh, that looks really great. No, we need more padding here. Da da da. Off it goes. So the, the, the server one probably doesn't do the, like if you change Python, um,

Technically, no. It doesn't do that. However, if you set Flask to do that automatically and then it re-requests the page, then yes, it does. You know what I mean? Okay, got it. So if you're willing to use the framework tools, then it does. Okay.

Okay. Very good. Cool. Yeah. But it's nowhere near as intense, which I think for some people is a drawback and other people is a plus depending on where you are. Okay. Nice. All right. That's it for all of our items, isn't it? Yeah, it is. Well then, what have you got for extras? I got just a pet

pet project of mine that I wanted to talk about. So the complete PyTest course has been out for a while and there's a couple things about it that are a little, that I'd really kind of like to change. So I'm working on some changes. First of all, if you see, if you go to the and look at it, it says there's 162 lessons. That seems a little scary. And the reason is because I've chopped it all up into, so there's 16 chapters in the book. The course covers the entire book. 16 chapters and

i've each video covers a section of a chapter um and that's where plus welcome like you know welcome videos and stuff that's where the 162 comes in but um that's a little there's actually 162 videos which is a little intimidating um especially if if you're you're looking at one and you kind of like there's a lot here um uh but i mean it's all good if you if you like to go in just like a few minutes at a time that

That's great. But some people want to just chunk through an entire chapter and like a lunch break or something. So the alternate version that I'm working on is chopping this up into just chapters. So most chapters will be one video. And and then you can you can just, you know, chunk through like just watching one video. You can watch it in a weekend or not a weekend in like, you know, 20 minutes or something like that.

There's a couple chapters, chapter two and chapter three are pretty big writing test functions and then fixtures, pretty big concepts. So they're a little longer. So I'm chopping those not into one video, but like three videos. And so when we when I get all done this, the new version will be not 162 lessons, but like 20 lessons or something like that.

And then I'll probably make that the default and I'll just have both of them available because some people might like the little more granularity and doesn't, it's not more effort of me to have both of them around. So they'll be both be around. Anyway, that's what I'm up to. Cool.

Yeah, I like the small little videos. I think it's a way better reference material. You don't want to have to go like, where in that 18-minute video was the thing I wanted? Yeah, that's the benefit. The other thing is I like to, for videos, I like to probably set them at 1.2 speed or 1.3 speed the first time, or 1.25, maybe 1.4, to get an overview really quickly. And

You have to reset that for every video and that's somewhat a little annoying. That's a hassle. Yeah. Anyway. That is a hassle. All right. Well, let's see what I got for extras. I got an oldie. Something fun here. So there was a hacker news thread or Reddit thread. I'm going to go with hacker news. Pretty sure it was hacker news talking about, hey, could some people recommend...

some cool legit programmer fiction books. Right? Like I want a spy thriller that has to do with programming, but that's not stupid. Right? It's not like, whoa, this is VB6. I know that. I'm going to track their IP. Like, you know what? That's not how it works.

More Mr. Robot, less Jurassic Park or whatever that was. I can't remember. So the book that I thought was really cool, I'll give a shout out to is by Mark Russanovich, who is the CTO of Azure. And apparently I bought this book in 2012, just to give you a sense. So it's not brand new, but it is a super cool series. As long as you keep in mind that like its computer world was 2012. So people can check that out if they're interested. Also, Warp on Windows. I'm a big fan of Warp, the terminal.

It's been working out super, super well. I tried ghost TT or ghost TD or whatever you, however you say that just, I cannot do it. I can't do it. Like it doesn't even let you like select text with hotkeys and stuff. It just puts like control H and stuff in there. And until you can work with it as an editor,

I can't do it. 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 like word by word. And you can't do like, you can do a home, but you can do like shift. These are like really weird, like editing and stuff where like some of it just starts putting escape characters into the thing. I,

I don't remember exactly enough what it was because when I saw it, I'm like, okay, we'll come back to this some other time. Anyway, if you were on Windows and you're looking for a better terminal, and I know Windows has fewer options and less good options than the other places for a variety of terminals. Like there's Windows Terminal and then, I don't know,

Is there anything else? I'm not sure. There's definitely a command prompt. Well, PowerShell runs within Windows Terminal. You can run Git Bash or PowerShell or whatever the DOS-like stuff. You can run all that in Windows Terminal. Oh, right. Okay. Right? You can do the same in Warp. You can choose, do I want PowerShell, do I want Git Bash or whatever. But the thing that is the outer bit of it, you know, the app itself...

there's not many options so this is a cool thing that people can check out i'll link to the video because it's fun but you can just go to warp.dev or wherever it is okay our friends over at teaching python podcast um they are participating and being part of the pycon 2025 education summit and they're pointing out that hey hey the applications are going to be um

Or, you know, send in a proposal very, very soon. So that was, I think, last Friday and today is Monday. So it just recently opened up and they said the main theme is in the age of AI, how do we maintain the creative, empathetic, and critical thinking skills we need to make us human and great coders? We want to know. And so there's a whole bunch of

ideas around this. So we've got Kelly and Sean and a bunch of other people participating in this. So if that resonates with you, check it out. No, I was just chuckling because even before AI, we hadn't figured that out as far as I could tell. Yeah, I don't really know the answer. So I'm going to ask ChatGPT, I'll get back to you. Okay.

Yeah, one more extra here real quick. I just noticed that Graneon, which is powering Python by its set FM, by the way, and many, many other things just came out with their 2.0 release right there seven hours ago. How's that for French? Breaking news. Breaking news. Far as I can tell, there's a bunch of cool changes here. One thing that's not cool is as far as I can tell, it doesn't run fast API apps. So if you have Graneon,

powering your fast ap app api app you might test this before you just update there's also breaking changes in the cli of like how you specify certain constraints and stuff that's easy enough to fix because it tells you this constraint such and such but i think there's something going on where

At least all of my fast API apps stopped working when I switched to this, but all the other ones like court and flask and pyramid all work fine. Interesting. Weird. Don't know why. And court is async first, just like fast API. So I don't know what's going on, but they were, they were not having it. So I just pinned the version to less than two for the, for those until whatever happens here, it gets figured out. So there's just a little PSA. All right. With that. So seven hours ago, you've already tried it.

Not on purpose. I tried it three hours after it was released. I needed to ship something else, but my deployment process is check something into Git and then have it go rebuild the Docker images and restart them. And that's all. Check all the dependencies. Is there anything we can update? Like, does Ubuntu have security fixes we need to apply? Can we update the web server in case there's a security fix for it? And then we'll rerun the dependencies and we'll restart it. And then it didn't restart. I'm like, wait a minute. What? Why did?

what's going on here? This is not good. So that's how I learned that there's a new release of granular. Okay. You know what I mean? It's not like I was like, Oh, I got to try it that quick. It, it tried itself on me and then it didn't go so well. So I scrambled to fix it. Okay. Got it. Yeah. Yeah.

Okay, joke? - I'd love a joke. - Tabs or spaces. This one has to do with tabs or spaces. I'll tell you a joke before the joke, a pre-joke, if you will, to get everyone in the mood. This is like the bad joke, the bad comedian that shows up before the one you actually came to see. So we were at PyCon, I don't know,

I think this might have even been in Portland. This was a while ago. And there was some company that was clearly not very tuned into Python. They were just a coder company, right? And they were like coming to sell their coder tools to the Python people. And so as they wanted to make a spicy t-shirt and the spicy t-shirt said, tabs are spaces, fight. Like this is the stupidest shirt I've seen at the whole conference.

I mean, tabs are basically disallowed. They're not exactly disallowed, but they're pretty much disallowed. Like, that's not an argument. It's over. And you're like, you're trying to set up as a debate. I'm like, you could do two spaces, four spaces and fight, but you can't do tabs versus spaces at a Python conference. Yeah.

Anyway, but people are going around those shirts nonetheless. I think I got one to cut the lawn in. Okay. Well, let's, on that topic, two spaces or four spaces? Four. Unless I'm doing JavaScript then two, because for some reason the tool seemed to default to two for JavaScript. You? Like four usually, but I'm noticing that I'm using two frequently as well. Okay. Very contrarian. Okay. You're an enigma wrapped in a fuzzy cloud. Okay. Okay.

How about this for, this is the real joke. So I don't know if this is better or worse, but this is what people came for. Code puns. You ready, Brian? Yeah. A Python programmer walks into a bar and opens a tab. The bartender tells them to sit at the table since they will need four spaces. That's what I got for y'all. No, it's hilarious. See, this is why people listen. Yeah.

Yeah, yeah, yeah. Oh, no, I'm like advertising it poorly. That was hilarious, man. Good joke. Now, there's actually a bunch more here. We've talked about this place before, right? Yeah. Let's see. They're not all good. Why did the for loop stop running? It took a break. Yeah. How do you comfort a JavaScript bug? You console it, like console log and so on. There we go. No, it's good. Thanks. It was hilarious. I know. I hear the flaws. No, not really.

But that's what I brought anyway. Good talking with you again. And thanks everybody for listening. Yeah, you bet. Bye all.