Hey, Brian. Hey, everyone. Hey. Happy summer. It's lovely. Been working in the garden. I know. Me too. I have six bags of leaves I've piled up outside. It's only a tiny corner of my yard that I... Yeah, there's a lot of leaves. Welcome to Oregon. Okay. Let's do it. Let's kick off the show. Hello and welcome to Python Bytes, where we deliver Python news and headlines directly to your earbuds. This is episode 428, recorded April 14th, 2025. I'm Michael Kennedy. And I am Brian Okken.
This episode is brought to you by Posit and Posit Connect. Thank you to Posit for supporting the show. We will tell you more about them later. If you're a social type and you want to connect with us socially, you can do so on Mastodon and Blue Sky. You can join us on YouTube at pythonbytes.fm/live, usually on Monday at 10, today a few minutes later, but generally around there. You can also catch the older episodes. Every episode page has YouTube trailer or poster you can click.
And finally, if you want our increasingly cool artisanal handcrafted digest of what is going on, put together by the one and only Brian Okken, join our friends of the show mailing list, go to the website, click newsletter, sign up. More and more people are writing in Brian and say they like the newsletter. That's great. Yeah, I think it's really good. I like it. I do too. I'm glad we're doing it. I wish maybe other people might learn how to write Git commit messages better. Well, honestly.
I'm trying. I'm learning. but let's get going uh so i'm going to cover a something by chris beams um how to write a get commit message and oh man i probably write like a dozen get commits commit messages a day maybe you know from one to a dozen um and uh so i was interested to see how to do it better so uh the there's an xkcd at the top which is you know just gibberish the first commit message is created main loop and timing control is pretty good.
And then by the end, like the most recent is like, hey, hands, just something. Here I have code, more code. Ah, my hands are typing words. And one of the things that, this isn't part of the article, but one of the things I enjoy is being able to be fun with my commit messages when I'm just doing, when I'm doing it on a branch, that I'm just doing it for local saves essentially.
And then I squash it into a main branch and I really want the squashed commit message because that's the one that'll stay there to be really good. So when you want to write a good commit message, here's what you have. And there's like seven tips or seven rules, but I was intrigued by like the first one. So like, for example, at the top, there's an example of kind of a run-on commit message that you have to kind of like scroll to the right to see all of it, huge commit message, not good.
And then some better ones that are shorter. So how do we get that? And having included, have like good information. Well, one of the things that I didn't really, I didn't know about, and I learned from reading this is that if you separate the subject and body with a blank line, so the top line is get will, or get and a lot of get tools recognize everything up to the first blank line as the title of your commit message.
So in the example, there's an example with like just one line, the short line, and then a blank line, and then the rest of it, that your log and everything will just show that one line. And then it doesn't show the rest of it unless you should like click for details or something. Really cool. I didn't know this did this. So that's great. So separate the subject and body with a blank line. Limit subject line to 50 characters. I think that's just to keep it because you're a lot.
We kind of do like the 80 character thing sometimes. And like a bunch of the characters are used for the actual like the timestamp and stuff like that. So or the hash, like the first few digits of the hash. So we want to leave some space for that. So 50 characters, subject, capitalize the subject line. Don't worry about a period because, you know, that's one of your characters. So don't worry about it. Use imperative mood in the subject line.
And if you don't know or don't remember what imperative mood is, which I didn't. So I'm glad there's a discussion later. There's a discussion about all of these in the article. Wrap the body at 72 characters. That was an interesting thing that I, it just is interesting. So I use tools that wrap it automatically, but a lot of people are using tools that don't. And so to store it in approximately 72 characters.
And I just think of this as keep lines short-ish and actually use new lines and don't depend on wrapping. And then the most important is number seven. I think this is the most important. Use the body to explain what and why and not how. The code changes how you did the change. So the commit message is what did you do and why did you do it? And I really kind of actually just focus on why. I don't even really do the what too much. So good information about commit messages.
I also love, there's a lot of people that have talked about this before. So he references a handful of this. It says, keep this in mind. This has all been said before. And each one of these words is like this and has are all different links to different articles. It's kind of a fun way to reference other people's work. So good job. Yeah, that's really interesting. And I not too long ago learned the thing about one sentence and then a paragraph or two being extra.
And I learned it from the JetBrains AI in PyCharm. Oh, really? Yeah, because it's actually really quite good at writing a commit message if you just press the AI summarize what I did. Okay. Provided that what you're doing is focused. So if what you did was run pip compile and update 20 dependencies and then you ran rough and reformatted it, never click that button.
But if you legitimately did something, you know, that is like a focus thing that it can look at and go not like you remove 700 spaces in these locations. And then it comes out really good. And it does that. It'll put like one sentence and then it'll summarize in detail what it's discovered below. Yeah. Yeah. So very cool. That's it. I don't use it that much. I probably should use it more, but sometimes end up in hands just work.
But usually for me, when I end up writing commit messages like that, I am frantically trying to fix something I just broke in production. And I'm like, oh, I got to put it back. Just take this. I just need you to be able to get pull on the server again and try again before it disrupts too much. You know what I mean?
Yeah. Well, I just realized that there's another thing that I do frequently as well is if I commit and then push everything and then CI breaks for some reason, like because I forgot something, like I forgot to add, like I added a file and I forgot to add it and push that.
I will, the second commit, I will try to have that, the message be identical to the first one so that when people are looking at, it will show up as a different commit, but then it makes it obvious that it's part of that same commit. It is intended to be together. Yeah, that makes sense. I agree with that. This looks really useful. Cool. Who knew writing a single sentence would be so interesting. Hands. All right. Let's talk about Caddy. Brian, are you familiar with Caddy? Just Caddy people?
I mean, it's Caddy Shack. What is that? Yeah, but this is not that. This is Caddy, the ultimate server, ultimate web server. So if people are thinking about how do I host my web apps with Python, there are a few now that the thing that runs your Python code could theoretically also be the thing that serves, that talks to the web browsers. But typically and certainly traditionally, there's been an interesting divide there. We've got static web servers and proxies and firewall type things.
That's like Nginx and others. Yeah. And then you've got the stuff that actually runs your Python code, probably scaled out to be like four of them or something in a web farm with UVicorn, Gunicorn, uWSGI, which don't use uWSGI anymore. We covered that, but, you know, Gradient, all those types of things, right?
So this one I want to cover, this thing I want to cover today called Caddy is actually sort of a parallel of Nginx. So this comes to us from Frederick L. Storm. And Storm, thank you so much for sending this in. But it's something I've been tracking as well. And I've wanted to switch over, but my world is just so complicated. I have every line of Nginx, you know, you've got to put like a little configuration YAML JSON-like combo file together, I have 2,200 lines of JSON or whatever, Nginx config files.
That's a problem. And I don't really want to mess with trying to move that, so it's going to stay. But if I were starting over, I believe I would be probably choosing Caddy. It's a super, super simple way to create web apps that you can run. It comes with automatic, internal, no action on your fault, your behalf, HTTPS through Let's Encrypt.
So for example, you set up a website, you say my website is like michaildeploys.com or whatever, and you don't have an SSL certificate, you start it up, and as long as it's running on the server that actually that domain resolves to, it will just automatically get you a Let's Encrypt certificate and keep it up to date. Oh, wow. That's really cool, right? It has 63,000 stars on GitHub. That's pretty awesome.
If you want to do development, sometimes you need to have HTTPS, and it will automatically do a local trusted certificate for you. If you want to run on localhost, it'll just do, like even localhost is over HTTPS, does clusters. It has a little test. You can test it out for yourself, like put your domain to this location or whatever and try it out. Let's see if I can find the config. The config is super, super simple. We just write a couple of lines.
If you've ever worked with HTTP files from PyCharm, It looks a little tiny bit like that. But yeah, it's like real simple. You just say handle slash blog slash star and put the details out of there. That's just how that processes that. But it can reverse proxy slash API, which actually goes over to another server. And it can reverse proxy another one, which actually does like a round robin load balancing to yet another cluster of servers. Isn't that cool? Just like all that stuff so simple.
Yeah, it's really cool. It still doesn't look simple to me. Well, you know, try the alternative, right? So people can check this out. I think it's really neat. The caddy files are super easy to work with here. What was I showing? I think, yeah. Anyway, there's a bunch of different examples. Some of them are simpler than others like this. No, this is cool.
Yeah, but one of the other things that's cool is if you're coming from somewhere else, like I was complaining that I have all this Nginx config, you can actually just pass it an Nginx configuration file and go, I'm not ready to rewrite this in your world, Caddy. Just run this Nginx configuration, but you'd be our server for that. So you could slowly migrate over into that.
Yeah. Anyway, you can even use apparently a MySQL database as a source of definition of your front end web server, which sounds kind of wild. But then again, you can write code and APIs and stuff to control it then, right? Just change the database and then you change the web server. So all pretty cool. Anyway, I think people, if they're thinking about Nginx or something like that, should maybe give this a look. I don't remember what it's getting.
Oh, it's written in Go. That's what it's written in. So it's pretty high performance. It does HTTP 1, 2, and 3. So the 2 is most important, but 3 is also interesting. Anyway, 98% Go, 2% HTML. Nice. Indeed. So if you ever got stuff to host and you're not doing platform as a service, there you go. Cool. Speaking of which, let's talk about, before we move on, Let's talk about our sponsor, huh? Yeah. Yeah, so a couple weeks ago, Brian, you told people about Posit Connect.
And I want to talk about it again, but for a slightly different reason. So you talked about how easy it was to use. I want to talk about how you can use it to share your data science projects and how you can do that securely with things like single sign-on and so on. So this episode is definitely brought to you by the folks at Posit.
They've made a huge investment in Python, originally known as being an R shop, making RStudio and others, they've been putting maybe the majority, certainly a ton of effort, into things for Python people these days. So if the mentions of words like HIPAA, GDPR, or other privacy policies make the hair on your neck stand up, you'll know you want a trusted partner to help your data become shareable, but also follow those safety rules that we all have to live by. So Posit Connect can help.
And Posit Connect lets you securely develop, deploy, and share what you build with Python. If you build it with Streamlit, Dash, Plotly, Bokeh, FastAPI, Shiny, Flask, Quarto, and other APIs. So here's how it works. You or your team set up Posit Connect on a secure server within your org or behind some VPN in the cloud amongst your cloud servers and using your existing authentication system.
Then when you publish a piece of content, Posit Connect lets you set user level permissions for that content, making it visible to some users, not others. But what's even more interesting, I think here, is that you can set credentials on a per user basis. So imagine you write code that then goes talks to a database that then accesses a bunch of data.
And depending on who is doing that, they can see some of the data, but not all of it are different things and so on, different team reports or whatever.
so in Posit Connect you can actually per user set how they can access other things like your database or your APIs or external APIs or whatever that's pretty cool so if you work on a data science team where security matters you owe it to you and your org to check out Posit Connect do that by going to pythonbytes.fm/connect today and get a three-month trial to see if it's a good fit that's pythonbytes.fm/connect the links in your podcast player show notes and yes we all know you can just Google AI, Bing, whatever, Posit Connect, but please use our link so they know that it came from us.
That way they will continue to support the show. Thanks to Posit for supporting Python Bytes. Yeah. All right, back to you. What's your third item? Well, not third item, your second item. I am going to talk about, let's see, I'm going to talk about peps. So we've got actually a couple of peps coming in. That's good because I need a pep talk. Sorry, go ahead. So a couple of peps that just recently got accepted. So one of the peps is for packaging and one is for Python 3.14.
So let's do the packaging topic first. PEP 770 is improving measurability of Python packages with software bill of materials. And that's a mouthful, but it's about SBOMs. And if you don't know about SBOMs, you probably ought to know a little bit. So this is a good thing to read. And if you do know about SBOMs, they're stressing you out, probably. So this is something that we're in the corporate world. A lot of people are trying to think about.
And SBOMs, I'm probably going to massacre this definition, but generally are a way for us to, because we're using a lot of open source projects and third-party libraries. And like a Python package isn't just the Python code. It's also possibly some Fortran code in it or whatever, and some other things inside or Rust that you want to try to track all those dependencies. And the SBOM system is a way to get that right so that you can make sure that you know where all of the code's coming from.
And this was, there were some different ideas about how to do this within Python. This 770 came from Seth Larson, sponsored by Brett Cannon. Really kind of a neat way to look at, Seth has looked at the different ways that we're already specifying a lot of this stuff with our packaging metadata. So how do we use that to try to fill out a lot of the SPOM fields automatically? And this is just really some great work. So I'm glad this is going in.
Again, since it's part of packaging, it doesn't really attach to a release. So I'm not sure when we'll get like, I didn't look through if this is something that's already implemented or not, but it's just accepted. So, and if, even if we did do get it, we'll get it through tools and stuff. We won't get it through the Python release versions. So next one that I'm, I'm also a little confused about, but excited about is PEP 750 template strings. So we've got f-strings.
These are like f-strings on steroids. The T strings will replace the, when you do a template string, you won't say F string, you'll say T string. And so it builds, so like, for example, if you had hello name with the name in curly braces with an F string, that would fill in the name with whatever variable. But we want it to be like, just to, to just hold that thought and we'll fill in the name later, sort of a thing. And I still like, I'm just sort of getting into this.
don't know really how to use these, but I'm really excited that a lot of this has been thought out.
Now there's a whole bunch of authors, Jim Baker, Greedan Van Rossum, Paul Everett, three other people, Dave Peck, Lissandro Nicolau, and Caudiano, I'm sorry about massacring your name, I'm sure, but a lot of people working on this. Really well thought out also some really cool stuff about being able to combine. They thought about like with fstrings, you can do math on it or, you know, sort of like adding and concatenating and stuff like that.
All that stuff's been thought out. How do we deal with like displaying them, using them, the whole shebang? This is going into Python 3.14 with 3.14. So that's just, you know, right around the corner. So really, really excited about this one. So many pi jokes are coming in that version.
I think this is really interesting. I talked to Paul a few times about this, and I know he's really excited from a web developer's perspective. So think about Jinja templates, Django templates, Chameleon templates, like that kind of thing. Yeah. But with more flexibility, and they're being supported by the Python runtime itself, not a third-party library that parses and processes it separately.
Well, that's what I was thinking. Like, would we need, with this in place, would you need Jinja templates, or could you just implement your stuff with this? I think you can just deal with this. I mean, I think it's somewhat inspired by components and stuff from the JavaScript libraries where you've got your JavaScript, but then there's a string in there, like some weird HTML fragment in there that's actually the template that you would use.
And they're just kind of interwoven so they can have a little bit more locality of behavior with each other. I think that is a part of the motivation here, I do believe. Yeah. I'll probably have to have Paul and maybe some of the other folks on Talk Python to talk about it. Yeah, I'm sure we're going to have lots of articles about it and everything. So we will talk about it more for sure. Indeed. Awesome. Indeed. All right. Well, let's round things out with a little data science.
Have we spoken about UV before? People out there, do you know UV? Have you heard of this? It's a library for managing dependencies and projects. Actually, I'm probably going to get my jacket signed by Charlie Marsh when I go to PyCon because that's how much we talk about it. No, definitely fanboy of UV. And I want to talk about a pretty new project called, you want to pronounce it as Juv, J-U-V, but I think it's J-U-V is probably the way to say it because it's based on UV.
And what this is, this is a toolkit for notebooks where the virtual environments and the dependencies and such of it are managed by UV, which is pretty cool. So what can you do? Hey, by the way, this is a pretty new project, 222 stars.
it's only been created six months ago, and it's not too well known, but I want to shine a light on it. You can create, manage, and run Jupyter Notebooks along with their dependencies, which is cool. You can pin the dependencies with the PEP 723 inline script metadata, which has been accepted. It must be, right? Yes, final. You can launch ephemeral sessions for multiple front ends like JupyterLab or Notebook or MB Classic, okay? And it's all powered by UV. So pretty cool.
You can, as you would expect, UV tool install JUV, or you can also pipx install it. And then once you've done that, you can just say UVX JUV and it'll run. But more importantly, if you look at the different things you can do to it, you can say things like JUV init some notebook, or you can init a notebook with Python 3 and give it a name, which is cool. You can go to that notebook and you can add a dependency for pandas and numpy to it.
That's not something you can normally do to notebooks, right? Or you can say I have a requirements.txt file I've created with pin versions using uvpip compile. Then I can say juv add --requirements and give it a full on requirements file. So in case you have a ton of requirements with versions and stuff, you want to manage separately. You don't have to keep typing them out.
You can also do interesting things like put a time stamp for reproducibility onto your dependency so i can say jv stamp this thing and then it won't get dependencies that are released after now which is pretty cool i think all right i don't know of anything else like that like i want to just have it whatever the latest of everything i'm using is as right now that's what i want they ship something new i don't want it until i change my mind that's pretty cool
but now here or now there anyway time yeah i know time zones, it'll make you want to cry. You can also say run
--with, and it'll run those even if you don't want to put them in as a particular dependency. And you can lock it to create a lock file, right? All sorts of the UV types of things, but you can have it run there. You can also say run notebook with like Jupyter Notebook rather than Jupyter Lab and give it a notebook, give it a version. Like there's a lot of different things you can do. So I think I've been talking enough, but there's like quite a bit more. You can go on here.
So this is a pretty comprehensive project for being six months old. Anyway, if you notebook and you like UV, consider giving JUV a look. It looks pretty cool. What else you got that's cool, Brian? That's it for our main items. I just have a couple extras and I have a feeling we've covered this, but I don't remember. So I'm going to go ahead and cover it anyway. So I'm going to take a look at the status of Python versions.
So this is on the Python Developers Guide, devguide.python.org. And I just, there was within the last couple of months, there was a reformatting of this, I think. This is my memory. So the big list is at the bottom with like the full chart of all of the, all the different versions and what's left. And what we see about the full chart is most of them are end of life because it starts at 2.6, 2.7, 3.0. And so that's not really that interesting. So the new format highlights the ones you might be caring about right now. So the last few end of life's, there's a two sevens end of life, but then three, six, seven, eight are all end of life. So hopefully you're not using Python 3.8 anymore. But one of the interesting things, so there's a couple of interesting things about here. So highlighting there's, there's where we're at with, so currently three nines is still getting security updates, three, nine, 10 and 11 are, and then like right now, as of, it looks like right, the, the, it's, it's a hairy, it's hard to tell where the green and yellow start with the blue line.
So there is, there's dates around, but there's a link to in here for endoflife.date.date slash Python. And so I took a look at that. And that is like very clear as to what the timeline, what we got left. So 3.13, the active support. So it was released six months ago. And it's all, so these relative times are really nice. It was released six months ago. We have a year and five months left in active support and then security updates for four more years, four years and six months.
So this, the timeline is really nice. This also highlights the, so in the first graph, we just had like this difference between green and yellow. So we got bug fix and security. Doesn't seem like that big of a deal, but when you look at it with the reality of it It is 3.12, which I'm using a lot of lately. That active support ended a week ago. We're not like right on the edge. We're past it. So active support ended for 3.12. We still have security supports. So there's security problems.
We still get three years of security. But we're not going to get like bug fixes and stuff. Like minor bug fixes are not going to go into 3.12. So 3.13 is where you probably ought to be. Anyway, so I like both these graphs. And these are really great graphs to pull out if you want to help convince your management chain that you can switch to a different version sort of thing. If you need that.
Actually, the second one that you linked to here, the end of life, date slash Python is really good for that sort of motivation. Yeah. Look, we've got one year and six months. How do you feel about that? Maybe we should change. In the part where if you pull up 2.7, it just goes, what are you reading this for? Stop right now and go back to migrating. And then 2.8 just says never. No, I'm just making it up. Really? It should say that. No, it should say that. I've never done it. Oh, okay.
It should though. Yeah, it should. Just go, stop, what are you doing? Stop. No, it has all the unsupported versions from 3.7 and older just collapsed saying like unsupported, go away. Yeah. Well, you can expand it, but it's collapsed. But having the relative time is really nice. How much time you have left? Yeah, I agree. I think that's very powerful as a mental model. Yeah. Anyway.
cool cool well let's carry on with that theme because i just want to point out that 3.13.3 is out and some of the changes don't matter too much to you oh if you use the mac installer this happens like okay well i install with ev so next and then windows has things like updated ssls tests have been updated a little bit but it's got a few security fixes here which is none of them are like run for your life sort of thing but avoid unbounded buffering that sounds like you want to avoid that and so on. If you don't see the word CVE, you're probably safe, but still it's good to have it fixed. And then a bunch of changes to the library thing is getting better. And so might as well upgrade, right? Might as well upgrade to the new one. I just have to rebuild our base Docker container and UV will find the new one, download it, and then all the websites, including Python Bytes, they'll be off to the races. I think I'm most excited about the update to TCLTK. I know.
All right, a couple, one more really quick. Siam Yalamarti, thank you so much for sending this in because somebody, I think in the comments mentioned, oh, just use.get-blame-ignore-revs for the Ruff format. And we were somehow complaining like, you're looking at diffs and bases, especially looking at blame. Whoever ran Ruff format, and you said, Brian, don't run format on this because you're going to own it then.
What you can do is you can create this.get blame ignore revs, put probably the SHA of the commit, the hash, and then that will not show up. And you're like, okay, that's, we're not going to consider that when we compute the blame. Oh, okay. So that's, you can use, in that file, you can do a list of revisions to not part of the import. That makes sense now. Yeah, and they also pointed out that get blame has a flag, dash, dash, ignore revs file if you want to pass another one.
Pass a different file. Oh, it's not automatic. Okay. Or use, yeah, I guess you got to use it with that probably. Maybe not automatically, but you can. So anyway, I am learning about this. This is all news to me. Yeah, interesting. Cool. Indeed. Thanks for sending that in. That's always appreciated. All right, so let's close this out with a joke.
Brian, you've heard about BC and AD and sometimes referred to as BCE before the common era and Western calendars, you know, so we don't have negative numbers because negative is hard in calendars, apparently. I never really thought, why don't we just have like negative 400, but whatever. BCE. So I want to introduce you to a different calendar. It's such an important epoch, a different thing here. There's BGPT and AGPT. So before GPT, ChatGPT, and after ChatGPT.
So before, if you're debugging a problem, the developers probably sitting there for two hours, working really hard and going, oh, okay, how's this going to work?
they finally think it's working and then hands to the face six hours of debugging yeah that's before that's b gpt a gpt is chat gpt generates code in five minutes 24 hours debugging even more tears yeah what do you think yeah well so 24 hours if you're if you're being good with your body and working three only eight hour days that's three days so yeah see it saves you time this is how we save time with it. Yeah. No, I've both saved time and lost time with this so far.
Yeah. I feel like that's more vibe coding than it is just like I asked GPT for a little help with a function. You know what I mean? It's like... I still haven't jumped on the vibe bandway and I haven't tried that yet. So I'll try that out. Neither have I. It's both amazing and terrifying all at the same time. But I haven't done it either. Yeah, it's like jumping off a cliff. Just do it. It'll be fun for a while. Yeah, and Ro out in the audience asks, where's the Stack Overflow step?
oh yeah yeah that's got to be in there somewhere probably you're like i'm sorry i left you chat stack overflow i will not stray from you again i will go back and maybe you can help me get out of this probably not you just find the same answer generated by chat gpt over there as well well stack overflow is changing their name right they're gonna go by uh training data no training under flow okay okay
you know what doesn't waste your time though what this show and us in a good way yeah so let's get out of here thanks everyone for listening thanks Brian for being here as always