Hello and welcome to Python Bytes, where we deliver Python news and headlines directly to
your earbuds. This is episode 444, recorded August 11th, 2025. I am Michael Kennedy.
And I'm Brian Okken.
And this episode is brought to you by DigitalOcean and their generative AI features and tools,
and DigitalOcean more generally, but specifically by their gen AI tools,
which we're going to talk about. Brian's going to tell you about them.
So check that out at pythonbytes.fm/digitalocean-gen-ai and use the code DO4bytes, all caps, and get a $200 credit.
So if you're looking to try out Digital Ocean, you might as well use our code and get plenty of credits.
Also connect with us on the socials, Mastodon, Bluesky, YouTube, all of those things.
Links are in the show notes at the top.
And I highly recommend that you subscribe to our newsletter, which Brian sends out a really nice email pretty soon after the show.
is out. Diving further into the stuff that we talked about, maybe some additional resources
and links and insights and tools and all that. It's not just a email version of the show notes.
It's really cool. I enjoy getting it as well. Thanks, Ryan. I enjoy putting it together.
I enjoy hearing about whatever you've got to cover first. So let's, yeah, let's jump in there.
Speaking of coverage, let's talk about coverage. Ned Batchelder released,
I guess this was in July, but just recently,
a blog post called coverage.py regex pragmas.
So that seems like a mouthful.
And probably, please don't run away because this is powerful.
I know that pragmas and regex isn't everybody's favorite topic.
I'm feeling like C++ is back again.
So what does pragma mean?
It's the pound thing.
So let's say if you say like pragma exclude or something like that to say or no cov to say, hey, for coverage for this particular line of code, don't worry about measuring the coverage on that.
However, so this is a great article and I did not realize I've been using coverage for years and I did not realize it was this powerful.
So, coverage uses regexes to define pragma syntax.
And you don't really have to care about it if you just want to just for each individual thing you want to pop in.
And there is a way to say particular files, just ignore the whole file.
However, this is pretty cool.
So, what is he talking about?
He's talking about a couple things around it that allow you can extend it using regular expressions.
And you don't necessarily have to figure this out.
other people have figured it out for you. For instance, there are plugins for coverage that do
a lot of this. So there's cov defaults. And this one's brought to us by, oh, Anthony Satili. Cool.
So Anthony has cov defaults. And so there's a whole bunch of defaults already in there to do
things like exclude your dundermain.py file. Because if you're distributing a package,
that might be just so you can test things.
You're probably not going,
it's okay if coverage doesn't hit it.
A lot of stuff like that.
And then a whole bunch of regular expressions
for things like type relating,
typing relating code and excluding that.
That's pretty cool.
I didn't know that was there.
That's neat.
Another one is coverage conditional plugin,
which does things like if you've got certain,
what does it do?
He talks about it.
It gives you a way to create common syntaxes
for entire files or entire packages,
whether a package is installed
or different operating systems, things like that.
That's pretty neat also.
But a change happened apparently recently,
this was, well, recently for me, last year,
but a change to coverage that allowed multi-line,
and this was contributed by Daniel Diniz,
multi-line fragments or multi-line regular expressions
so that it like compares it for the whole file.
So one of the neat things about this is you can do things like,
with this regular expression that you can put in your no coverage stuff,
you can pop in pragma exclude file and define a file there.
Instead of trying to figure out how to find the file in your directory structure,
you can just pop this in and say,
this particular file, I don't want to delete it yet,
but don't worry about this for testing.
That's pretty cool.
Right. My boss has been on me about getting that code coverage percentage up.
So I wouldn't do it for that.
And that's not what it's for. Okay. No, I like that. I'm just teasing. I like the idea.
I actually like, I mean, I've heard a lot of people say hitting a hundred percent isn't,
isn't worthwhile, but I think it is because coverage is so powerful. You can, with all of
this stuff, you can say, I want to hit a hundred percent of the code that I care about, not the
stuff I don't care about but the things that the problem area is you can define this so that you
can just focus on the files and areas where you really want coverage and that needs to be 100%
so that's where that's where that's my caveat for why I like 100% a couple other cool pragmas
start and stop so you can just say at the start and stop like add a comment to the top of
a code block to say yeah this junk we're not I'm leaving it in here but it's not it's not running
during testing so don't cover it um so really powerful i really love a couple all of these um
they're pretty great oh this is a neat one so have you ever had like um these uh uh default like a
placeholder method where you just uh use three dots or something i'm using three dots a lot better
more than pass because um it kind of does the same thing um and you can just say yeah this is here
because it has to for some structural reason,
but it's never going to run.
So don't worry about trying to cover it.
So that's pretty neat.
Yeah, that's cool.
Yeah, very cool.
Anyway, thanks, Ned,
for teaching us how to use regular expressions for coverage.
Yeah, that's very neat.
All right.
I want to take you back to the times of knights, maidens,
to the land of yore.
No, this is totally different.
This comes to us from Matthias.
It is a package called yore, however.
Okay.
It's quite new.
It's like an undiscovered gem sort of thing.
So when I first saw this, I'm like, huh, do I care about this?
I don't know if I care about this.
And then I looked more carefully.
That is kind of interesting.
It starts with a quote from ChatGPT, the sage, which is always good.
But it's more productive to just jump down to some examples.
So basically what this is, is it is a tool a little bit like Ruff or Flint
or one of those things that works on--
basically, it looks at your code, tells you if there are issues.
But this one is focused specifically on have you previously supported unsupported versions of Python by doing stuff the old way, you know, be that typing or example is the abstract, the ASTune parser.
I don't know what that is.
Or the AST parser.
Yeah, abstracts and text tree.
If you want to use that and you're using 3.8 or before, you had to use the astune parse, I guess, from unparse.
Or if you're in 3.9 or above, you can use AST from unparse.
So, right, you probably have this comment, like, if the version of Python that I'm running on is less than this, I'm going to do this one thing.
Otherwise, I'm going to do the other.
And so what you do here is you still write that code because that's how it is.
However, you put a comment kind of like, you know, PyCharm and VS Code, if you put a capital
to-do colon as a comment, I don't know if you've noticed this, but probably.
If you say capital to-do colon and you write something, that shows up in a separate window,
at least in PyCharm, you say, show me my to-dos.
And when you try to do a commit, it'll say, hey, you added some new to-dos that are not
done.
You sure you want to commit?
There's a whole integration with the tooling like that.
So this is the same type of deal.
So you say, put a comment that is capital your colon, and then you say EOL, in this case, EOL 3.8, and you put a comment.
Oh.
And then a thing like replace block with line four.
Okay.
So you say, once 3.8 is gone and we stop supporting it, just do the straight import.
We don't have to do this test.
We don't have to do anything.
And then later, you can run in your code, you say, your check EOL within five months.
And it says, whenever you run it at the right time,
Python 3, it will reach its end of life approximately four months.
So it uses the comments to say,
you've got sections of your code that depend,
are complicated because of Python versioning breaking changes.
Oh, cool.
Here they are, right?
And you can look for them much like you can use rough check to say,
show me issues with my code.
But what's even better, rough check has a --fix.
And so does yours.
You can say your fix, EOL, within five months,
It'll actually rewrite that code and replace the block with line four and just go back to the straight import.
Remove the your comment, remove the version checks, all that.
Hmm.
What do you think?
Okay, I like it.
For such a simple idea, I like it too.
Now, I'll have to play with this a little bit because it totally makes sense for Python deprecating Python versions and stuff.
And the reason one of the cool things about like looking into the future is you might be working on a you might be working on a release that you're not planning on releasing for another month.
So you're getting started cleaning those up.
But that might be your own stuff.
You might be like you might be deprecating your own features.
So you might I'm wondering if you can put like your for your own features or is it just a Python EOL thing?
Yeah, that's what I've been thinking about as well.
I was like, I would like it not just necessarily for my features, but hey,
Pydantic went from V1 to V2 and that had super big deprecations for
certain really common functions, right?
Like dumping to JSON and so on.
Yeah.
Is it just the Python release cycle?
I don't know, I'll have to look into that.
Yeah, I think it's just Python version itself, but who knows?
Okay.
Neat, yeah, very, very neat.
All right, also neat is DigitalOcean.
Yeah, let me tell you about DigitalOcean.
This episode of Python Bytes is brought to you by DigitalOcean.
DigitalOcean is a comprehensive cloud infrastructure
that's simple to spin up even for the most complex workloads.
And it's a way better value than most cloud providers.
At DigitalOcean, companies can save up to 30% off their cloud bill.
DigitalOcean boasts 99.99% uptime SLAs
and industry-leading pricing on bandwidth.
It's built to be the cloud backbone of businesses small and large.
And with GPU-powered virtual machines plus storage databases and network capabilities
all in one platform, AI developers can confidently create apps using a platform that the users love.
Devs have access to the complete set of infrastructure tools they need for both training and inference
so they can build anything they dream up.
DigitalOcean provides full-service cloud infrastructure that's simple to use, reliable, no matter the use case, scalable for any size business, and affordable at any budget.
VMs start at just $4 a month and GPUs under $1 per hour.
Wow.
Easy to spin up infrastructure built to simplify even the most intense business demands.
That's DigitalOcean.
And if you use DO4bytes, DO the number four and BYTES, you get $200 in free credit to get started.
DigitalOcean is the cloud that's got you covered.
Please use our link when checking out their offer.
You'll find it in the podcast player show notes.
And it's a clickable chapter URL as you're hearing this segment.
And it's also at the top of the episode page in pythonbytes.fm.
And why wouldn't you?
It's $200 credit.
Thank you to DigitalOcean for supporting Python Bytes.
Indeed, indeed.
Thank you.
Over to you.
What's next?
Wait, no, over to me.
Over to me.
Sorry, I'm retracting that statement.
I got the order wrong, Brian.
So we've talked about Nox before, right?
Yeah.
You're a fan of Nox, aren't you?
Yeah.
So Nox is a command line tool like pytest or Tox that allows you to test against multiple
versions of Python, right?
So super cool.
You can run it.
You can say like this might depend on whatever particular version of Python or whatever, right?
So the thing I want to tell you about is something called uv.
No, sorry, Knox-UV.
And this comes to us from John Hagen.
And this facilitates Knox integration with uv for Python projects.
So remember, uv is awesome at installing different versions of Python rapidly.
Like you can install, go to a machine that has no Python whatsoever, and you can pick your version of Python and have it installed and ready to use in under two seconds versus PyMV, which builds it and takes minutes or downloading the installer and making sure you have all the versions you're going to test with or whatever.
Right.
Yeah.
So that's really awesome.
And then also installing the dependencies for these different versions of Python, uv is ultra fast at that as well.
So there's huge advantages to speeding up testing and CI with uv.
And if you're using Knox to create a combinatorial matrix
of all the different versions of Python you might work with,
well, then uv speed is only going to multiply across that, right?
Yeah.
Yeah, so super cool.
So you can just say uv add group Knox and Knox uv,
and it'll add that in there.
And then within your Knox file, you import the session.
Instead of from Knox, you do it from Knox uv,
set the backend to be uv.
And then for your session, you specify which versions of Python, which groups, et cetera.
Off it goes.
I feel like this should be your topic, honestly, Brian.
I think I stole it from you somehow, effectively.
Why is that?
Just because you're so into testing.
And this is like right at the heart of it.
Okay.
What do you think?
Cool?
I think this is neat.
Yeah, I'm using like uv almost everywhere now.
And I actually, I used to recommend people like just average folks that are just starting Python
or they just need it for work,
I would recommend them just go to python.org and download it.
And I'm still kind of doing that,
but I'm leaning towards trying to teach people
how to use uv in virtual environments
because it's not going to be that long
after they start using Python
that they're going to want to use that anyway.
So, yeah.
Yeah, and recently we just covered this,
that one of the main things uv did
is now there's a Python version in your path
if you install a Python via uv,
which it used to just be in like some obscure place
hidden in like your user profile sort of thing.
It was hard to run it outside of a virtual environment.
Yeah.
Anyway.
Okay.
Cool.
Yeah.
Very cool.
Thanks, John, for sending that in.
Now over to you, Brian.
All right.
So let's take a look.
I've got a couple short-ish Django items.
So I thought I'd cover them together.
So the first comes from Johnny Metz.
And it's stop using Django's squash migrations.
There's a better way.
And actually, I didn't know about squash migrations.
I'm kind of new to Django, the Django world, new-ish.
But I like this article because I watched a pro, kind of an old hat,
when I was doing a session with somebody that knows Django way better than I do.
And I had a whole bunch of migrations because I was fiddling with
the database structure and everything.
And I was going back and forth, changing things.
And I had a bunch of migrations.
And he said, wait a second, just a second.
Let me do something.
And he just like, he did this.
So what am I doing?
What am I talking about?
So this is Johnny Metz.
He was recommending doing a clean reset.
So you fully migrate all your environments,
make sure everything's running well.
And then you delete all your migration files.
Seems crazy.
but you delete them all and generate a fresh migrations.
And then you've got just a new one.
So this creates a new 0001 initial for each app,
and then some apps might get a 002 or higher.
So you do this on different, it's going to do it on different apps.
But then you, so, okay, I'll just walk through it.
Fully migrate all your environments, delete all your migrations,
generate fresh migrations, then add data migrations,
temporarily disable automatic migrations during deployment,
reset migrations.
Okay, so it's not trivial.
Then re-enable automatic migrations.
So why would you do all of this?
This seems more complicated.
However, you end up with a really clean set.
So you've got a very clean migrations set at the end.
And I think, I don't know if this is, I'm not a Django pro, but so I'm not, I'm not sure if this is appropriate later on, but especially after you've like hashed through the initial development, this is a great time to start clean and then, and then work from there.
So interesting Django article.
It is an interesting idea.
And certainly, I think if you've not pushed it to production, you know, you just like,
instead of having the 100 migrations you may have built over time as you built up the app
before you push it out live, like just get that down to a single migration, get the database
up and running, go from there.
Yeah.
I'm not sure if it mentions it in here too, but I have been, guess, yeah, I think it sets
it up in here, but having migrations per application.
Anyway.
The other one is this comes from Adam Hill is DJ light.
And this is a fairly new project.
And it is how to use SQLite in production with Django.
So yes, you can use SQLite with Django, but there's some tricks.
So he wrote an article called the definitive guide to using Django with SQLite in production.
And then he decided to go ahead and he's still recommending that,
but there's this plugin to make it easier.
So with this plugin, you got a couple settings that you can change,
and it just runs with it.
So it's way easier setup if you want to use SQLite with Django.
And this little blurb here at the top says that
simplify deploying and maintaining production Django websites
using SQLite in production.
DJ Lite helps enable the best performance for SQLite for small to medium-sized projects.
It requires Django 5.1 or above, but I think SQLite is appropriate for a lot of Django.
A lot of people just start with Postgres, but anyway.
Yeah, definitely.
I think there's certainly defaults you can change or behaviors you can change about SQLite to make it way more high performance,
especially with concurrent read-write sort of things.
Yeah.
So, yeah, very cool.
And following up on the squash migrations,
Pat Decker says,
sounds like a similar familiar to Git Rebase maybe.
Yeah, it does to me for sure.
Yeah.
Squashing.
Yeah, very similar.
Okay.
While you have the stage,
how extra do you feel?
I got a couple extras,
so we can just cover them.
So the first up is I've got a testing code episode
in the queue.
It's in draft mode currently.
FastAPI cloud with Sebastian Ramirez.
and it was a real fun talk with Sebastian.
This was recorded.
I can't even remember when it was recorded.
Maybe it was a few weeks ago at least.
I feel bad getting so slow to get it out.
But a really interesting article about FastAPI
and about FastAPI Cloud.
And Sebastian's just a joy to talk with.
So that'll be out later today.
I only have to rerecord the ad for it,
but not much left to do.
And then next up, pythontest.com,
a couple things.
I released a, I had a fixture.
When was this?
2013 that I started.
So this is what, over 10 years ago?
That I wrote a four-part series on pytest fixtures.
And I had been talking that I was looking at analytics.
And some of this stuff is still getting hit.
So I went and reviewed it.
And this series was a mess.
And I went ahead and like re, I didn't rewrite it,
But I went through everything and split it up into a more multi-part series.
A lot of these are really short.
I just wanted to keep one topic per blog post and make sure that it runs.
A lot of the stuff didn't even run on current pytest and current Python.
Now it all runs with current pytest and Python.
So there's a nice fixture tutorial there.
The other thing I wanted to bring up with Python Test is there is a bunch of stuff.
So 2013 up through this year, there was a bunch of stuff that was like formatted badly.
And I have gone through and made sure everything is mostly correct.
So if you see any, I think everything's working now.
So if you see anything weird, let me know.
I just, as I was reviewing this morning, I realized that in this particular post, I
refer to a fixture as fixture B and it's really resource B.
So I'll have to fix that.
But, you know, things like that shouldn't be too bad.
Anyway, that's all up to date.
Do you have any updates?
I have three extras, and I think they're really exciting.
They're going to be really cool for people.
So let me tell you about it.
First, brand new course over at Talk Python.
I'm really excited about this one.
Some of the most impactful courses that we create there are ones that take people from
like zero to one or one and 1.5 to two, like the first sort of steps, right?
And so this new course is called Just Enough Python for Data Scientists.
Oh, nice.
Python is kind of a stand-in for software engineering with Python, right?
So the idea of this course is if you've done work in Jupyter notebooks, but you kind of feel like, well, I just learned notebooks and a little bit of Python because I was at this research lab or in this course I took.
But I don't really know Git very well.
I don't know refactoring super well.
Reproducibility is still an issue.
Those kinds of things.
So it covers like what do you need to pay attention to in the dev world or the software world?
And what can you safely ignore?
Right.
Like don't try to boil the ocean when you're getting started.
What can you just not pay attention to?
How do you write functions?
Create importable modules and packages to split up notebooks
from like one large notebook cell into a bunch of usable, testable, more readable pieces.
Debugging, reproducibility with like Docker and uv,
and even a little bit of agentic AI for like data analysis to like jumpstart your work.
So if people are interested in this, I highly recommend it.
It's an awesome course that I wrote over the last three or four weeks.
and I'm really happy to have it out.
That's pretty exciting.
I like the topic.
Yeah, thanks.
Yeah.
All right.
Speaking of uv,
I was just on with Will Vincent from Django Chat.
When was this?
This was live streamed four days ago.
And we did a whole one hour paired presenting sort of thing on uv,
why people might use it, compatibility, what's new.
I even did a thing like how to make your Docker builds
five times faster sort of thing,
or 30 times faster, depending on what you're using.
If you're using pip, it'll be 30 times faster.
So super neat, super neat stuff that people can check out.
And that's just on YouTube.
So I'm going to link to that.
And then last is I'm a fan of cursor
when I'm doing like super heavy AI programming.
Obviously a big fan of PyCharm
when I'm doing like focused development work, right?
But if I'm just like, I just need some heavy duty AI tools,
cursor and Claude Code has been getting a lot of traction lately
because it's like this terminal based thing.
You can use it anywhere.
Well, Cursor just came out with a Cursor CLI that you could set up.
That's pretty neat.
So use it in your IDE or any terminal.
Cursor, JetBrains, Android Studio, Xcode, whatever.
So pretty neat.
If you kind of like Cursor, but you also kind of prefer the terminal side of things, check this out.
It's in beta, but so far it seems pretty neat.
If you have a subscription, it just integrates with that.
Neat.
Yeah, those are my extras.
I have a joke for us as well.
Oh, good.
Yes.
And I think this AI thing I just gave a shout out to perfectly, perfectly blends into this.
Okay.
Control C, Control V remains eternal.
But what kind of dev are you?
This means something different, Brian.
If you're a new school developer, you copy and paste from ChatGPT.
If you're old school, you copy and paste from Stack Overflow.
And if you're ancient like you and me, you copy and paste from the documentation.
Wait, how do I copy and paste from a book?
Okay, I guess I'm so ancient that I'm not even on the chart.
Oh, that one takes a while because that's when you remember people talk about,
oh, I saw that code in the magazine that I typed it in.
Yeah, that was me.
That's how you do it.
You copy and paste with the fingers one character at a time.
Yeah.
Anyway, copy, control Z, control V, still important, but changing over time.
Yeah.
All right.
Well, thanks for the episode.
Thanks for being here.
And thanks everyone else for listening.
Thanks.
Bye.