WEBVTT

00:00:00.100 --> 00:00:11.580
Hello and welcome to Python Bytes, where we deliver Python news and headlines directly to your earbuds. This is episode 445, can't believe that, recorded August 18th, 2025. I am Brian

00:00:11.740 --> 00:00:17.100
Aukin. And I'm Michael Kennedy. This episode is sponsored by Sentry, Python error and performance

00:00:17.340 --> 00:00:32.300
monitoring. Thank you, Sentry. And if you'd like to get a hold of us, maybe give us some topic ideas that you'd like us to cover on the show, that would be awesome. Or just comment on something or just say hi, you can reach us on both BlueSky and Mastodon, and the links are in the show notes.

00:00:32.880 --> 00:00:50.860
And if you'd like to join us live for the live performance, performance, pythonbytes.fm/live, or you can also use that link to find out when we're going to record next or just find out where the YouTube page is so that you can subscribe and watch them later.

00:00:51.220 --> 00:00:51.620
That'd be great.

00:00:52.200 --> 00:00:57.380
And finally, we'd like to get a hold of you later just to sell you stuff.

00:00:57.580 --> 00:00:59.740
No, just to give you links.

00:00:59.920 --> 00:01:01.860
So we cover a lot of stuff in the show.

00:01:02.160 --> 00:01:03.480
You don't have to keep track of the links.

00:01:03.660 --> 00:01:11.900
They're in the show notes, but they're also the links plus extra information and things you might need to know if you are new to Python or new to a topic.

00:01:12.580 --> 00:01:13.960
Those are all in the email.

00:01:14.460 --> 00:01:19.980
So you can go to pythonbytes.fm and sign up for the newsletter and we'll send that to you.

00:01:20.520 --> 00:01:22.320
And that's all the intro stuff.

00:01:22.600 --> 00:01:26.240
So, Michael, we got some exciting news for number one.

00:01:26.240 --> 00:01:27.700
We have very exciting news.

00:01:27.840 --> 00:01:32.740
And as part of this performance, Brian, I would like to recite The Raven by Edgar Allan Poe.

00:01:32.740 --> 00:01:33.760
Oh, no, wait, this is not a performance.

00:01:34.320 --> 00:01:34.860
And I don't want to do that.

00:01:35.160 --> 00:01:40.340
I want to talk about Astral, actually, because this is a really interesting announcement from them.

00:01:40.740 --> 00:01:42.820
Charlie and team are knocking stuff out of the park.

00:01:42.960 --> 00:01:49.020
They're delivering big time on the tooling for Python packaging, managing Python, right?

00:01:49.180 --> 00:01:52.820
all the layer that you build upon when you're writing applications, right?

00:01:53.200 --> 00:01:56.660
So first they came out with Ruff for formatting and fixing issues.

00:01:57.160 --> 00:02:05.440
Then they came out with uv, and then they upgraded uv to have its project management and Python management, not just alternate pip installs and so on.

00:02:05.660 --> 00:02:10.320
And along all of that time, people have been saying, well, this is so amazing.

00:02:10.539 --> 00:02:14.940
It's so fast and it does all of the things instead of piecing together tools.

00:02:15.500 --> 00:02:18.260
But what if they rug pull us and we slip and we hit our head?

00:02:18.660 --> 00:02:20.100
What if they go and do something else?

00:02:20.240 --> 00:02:25.300
What if they start saying it's a half a cent per pip install or whatever, you know?

00:02:25.720 --> 00:02:26.380
What are we going to do?

00:02:26.860 --> 00:02:32.760
And Charlie has said that he's not planning on monetizing those types of things.

00:02:33.340 --> 00:02:34.980
Instead, he wants to build on top of it.

00:02:35.100 --> 00:02:39.480
So with this announcement, we get our first look at what that might be.

00:02:39.710 --> 00:02:42.840
So it's interesting in and of itself, but I think it's also interesting in like,

00:02:43.260 --> 00:02:47.940
this could be the thing that supports the stuff that people are really starting to depend upon.

00:02:48.360 --> 00:02:50.960
And it's something called pyx, pyx.

00:02:51.400 --> 00:02:55.100
I'm going to be interviewing Charlie on Talk Python in a couple of days.

00:02:55.800 --> 00:02:57.300
By a couple of days, I think it's next week.

00:02:57.640 --> 00:03:00.940
But pretty soon, I put a link to the event on the show notes.

00:03:01.100 --> 00:03:01.740
People can check that out.

00:03:01.790 --> 00:03:03.100
So we'll get the pronunciation.

00:03:03.280 --> 00:03:06.380
I'm going to say pyx for now, like ty and uv and so on.

00:03:06.610 --> 00:03:08.100
Unlike Ruff, not R-U-F-F.

00:03:08.700 --> 00:03:12.660
So pyx, a Python native Python registry now in beta.

00:03:13.060 --> 00:03:15.180
So here's the deal with pyx.

00:03:15.620 --> 00:03:33.560
Think of this as an alternate PyPI, but not as a source of packages, not where, like when I publish something, I also have to publish the pyx, but more of a front end that adds a bunch of features or an intermediate layer, a middleware to PyPI itself.

00:03:34.210 --> 00:03:34.340
Okay.

00:03:34.760 --> 00:03:58.080
And at the moment, the plan is for this to be a full-on paid service for people that really need things like i really need my project to 100 be able to build some thing that's only available as a source distribution right how often have you pip installed something and most things just come down as a wheel and they come flying in but every now and then it'll stop and say

00:03:58.360 --> 00:04:08.879
building something for 10 seconds the very first time before it gets cached then it goes yeah or longer yeah definitely potentially longer like i don't use it anymore we've talked about why

00:04:09.020 --> 00:04:44.820
is micro whiskey because they said please stop using our project we're not going to support it go find something else and we talked about that but that thing took forever to build but also if you're doing a gpu aware types of things you're doing a lot of stuff with pytorch or machine learning more broadly a lot of those things are huge and having the right platform built version is really really tricky okay so the idea is that uv and pyx are going to go together hand in glove So uv can work even better by having complete control over the back end as well.

00:04:45.630 --> 00:04:54.200
They say there's some limitations that uv was able to solve, but not all of them because they don't control PyPI.org and its API and how things get built.

00:04:54.810 --> 00:05:01.280
So the idea is making it easier to install PyTorch or CUDA-based libraries, that kind of thing.

00:05:02.180 --> 00:05:03.360
It also solves the problem.

00:05:03.500 --> 00:05:07.040
Why is everyone rebuilding the same packages over and over on their machine?

00:05:07.320 --> 00:05:09.340
And what if those build tools are no longer the same?

00:05:09.800 --> 00:05:11.300
Why did setup tools break our recent release?

00:05:12.340 --> 00:05:14.540
How do we authenticate against our internal registry?

00:05:14.670 --> 00:05:18.900
The other thing this is going to do is it's going to be a first class private registry.

00:05:19.500 --> 00:05:28.680
So if you have a team, you're like, let's publish our data access layer, not to the world, but to our other people who are working on the projects, to our other applications, and so on.

00:05:29.020 --> 00:05:30.200
So pretty exciting.

00:05:30.430 --> 00:05:32.300
I think there's a lot of stuff going on here.

00:05:32.400 --> 00:05:32.980
They're in beta.

00:05:33.090 --> 00:05:34.120
You can join the waitlist.

00:05:34.350 --> 00:05:35.420
You can get in touch with them.

00:05:35.780 --> 00:05:40.780
It says, beyond the product itself, pyx is also an instantiation of our strategy.

00:05:40.890 --> 00:05:41.880
And this is what I opened with.

00:05:42.280 --> 00:05:47.000
Our tools, uv, Ruff, ty, et cetera, remain free, open source, and permissively licensed forever.

00:05:47.560 --> 00:05:53.600
And this project is pretty interesting because it's a glimpse into how they're planning to make that possible.

00:05:53.880 --> 00:05:56.200
Yeah, I'd be really curious to watch this.

00:05:56.420 --> 00:05:57.720
I'm excited for a lot of reasons.

00:05:57.960 --> 00:06:00.660
So let's say this is only a commercial offering.

00:06:01.780 --> 00:06:02.960
It's a corporate sort of thing.

00:06:02.970 --> 00:06:03.840
You have to pay to get it.

00:06:04.100 --> 00:06:10.040
I'd be still okay with that because the alternatives, there's alternatives out there like JFrog Artifactory is around.

00:06:10.760 --> 00:06:23.040
And there's other ways where you can, there's other products available to set up to mirror PyPI and do other things like as things come in, do like a security scan, your own security scans and things like that.

00:06:24.220 --> 00:06:30.460
And so a mirror in front end, but also something that you can publish to internal, publish internal things to.

00:06:31.200 --> 00:06:32.280
Those are really cool.

00:06:32.720 --> 00:06:34.400
They're a little hard to set up though.

00:06:34.520 --> 00:06:38.260
And I think I trust Astral to make this fairly easy for people.

00:06:38.980 --> 00:06:43.680
It also would be cool if you want to test things out locally.

00:06:43.920 --> 00:06:58.920
There's smaller businesses and smaller teams that aren't large corporations or even individuals that might have a need to try out what a repository might look like when you're doing those sorts of things or you're developing on an airplane or something, a local repo.

00:06:59.000 --> 00:07:05.020
So I don't know if they're going to get down to the point where it's a, like a local person, like a free thing that you can just run on your own.

00:07:06.100 --> 00:07:07.580
So it'll be interesting to watch.

00:07:07.590 --> 00:07:15.220
I guess I'm okay with either if they want to keep it like paid only or something that, you know, small fry can use as well,

00:07:15.400 --> 00:07:16.560
but I'm excited to watch.

00:07:16.880 --> 00:07:17.380
I am as well.

00:07:17.740 --> 00:07:17.860
Yeah.

00:07:17.920 --> 00:07:24.640
There's, I think somewhere Charlie said maybe possibly there's a free version, but right now the plan is to be a paid project.

00:07:25.040 --> 00:07:25.180
Yeah.

00:07:25.410 --> 00:07:25.540
Yep.

00:07:25.720 --> 00:07:25.900
All right.

00:07:26.020 --> 00:07:28.960
That's all I got to say about that for now until I talk to Charlie and

00:07:28.980 --> 00:08:21.440
more about i want to talk about lightstar a little bit there is an article called um uh where did i i missed it oh here it is sorry james bennett um has an article called lightstar is worth a look and i was looking through our past history a little bit and it looks like um we've talked about lightstar but it's been a while so you brought up um this was earlier this year i think talking about rewriting court um or rewriting talk python in court and lightstar is one of the things you looked at right so that was episode that was back oh that was last year november of 2024 so he asked client hello that was a good one um so we haven't talked about it a bit um so i was taking a look at it uh looking at Litestar i had never played with this and there is some interesting history around that it used to be uh star light like or something like that yeah it was not star

00:08:21.560 --> 00:08:22.840
let star light.

00:08:23.340 --> 00:08:25.080
And there was confusion, whatever.

00:08:25.500 --> 00:08:30.620
Anyway, so this is an interesting James Bennett brought up Litestar is worth a look.

00:08:31.070 --> 00:08:36.680
And he brought up like a lot of people do, if I'm going to do an API, why not FastAPI?

00:08:36.849 --> 00:08:42.940
I mean, that seems like the obvious choice now for setting up an API or something.

00:08:43.280 --> 00:08:46.960
And or a lightweight web framework. So why not?

00:08:47.940 --> 00:09:10.460
There are a few reasons that he brought up. So one things was in scaling and not scaling in traffic, but scaling in, I want more than one file. I want a bunch of, I want my application in a bunch of files. And there was some frustration that he talked about with trying to figure out how to do that within FastAPI because there's the app dot.

00:09:10.800 --> 00:10:11.380
And how do you have multiple routings in different files if you have one app? I don't know if this is easy or not. But he had some frustrations that it took him 40 pages into the documentation to the user guide to find that. However, it's kind of built in with Litestar is that you don't, it's not a top level app. You can, you can set it up, I guess, into multi-file, multiple files easier is one, one thing. The other thing was that FastAPI is tied to Pydantic. And I don't know if you can break that or not but um lightstar is not tied directly to pydantic and you can use it can use yeah it can use pydantic but it also has other options yeah uh um he he brings up um maybe attrs you could use attrs for validation which um some people forget that that's one of the cool things about attrs is it can validate things um or SQLAlchemy even can do um some of that so um Or a little combination of both, I guess.

00:10:11.860 --> 00:10:13.780
Anyway, so that's interesting.

00:10:14.020 --> 00:10:18.500
If you'd rather use SQLAlchemy for that or attrs, why not?

00:10:19.580 --> 00:10:23.460
The third option, what is the third thing he brought up?

00:10:23.760 --> 00:10:25.260
Is, I guess, just the architecture.

00:10:26.280 --> 00:10:27.140
I had another note.

00:10:27.460 --> 00:10:32.140
Anyway, it's interesting that there's another option out there.

00:10:32.440 --> 00:10:34.840
So do you know more about Litestar?

00:10:35.100 --> 00:10:37.240
I interviewed the guys from Litestar over on Talk Python,

00:10:37.310 --> 00:10:38.500
so I know a little bit more.

00:10:39.160 --> 00:11:25.760
not a ton more i would say one thing kind of a mental model i have about Litestar and i'm not sure how accurate this is but you know it's mine so i gotta have it is fast api is kind of flask esque in that it gives you enough to be have a bunch of cool building blocks but then you pick you build the other pieces and so on whereas Litestar seems to me a little bit more of the django philosophy where it comes with a bunch of batteries included like see all those little boxes down there look at all like the different pieces right it's got middleware it's got data stores it's got multiple it's got ORM integration caching like a lot of those things don't come off in that sort of stuff don't come with fast api which is both a good and a bad thing right like if it comes with

00:11:25.760 --> 00:11:29.800
it but it's not what you want then it's just a hassle to battle against all the time yeah but

00:11:29.940 --> 00:11:37.400
that's how i sort of perceive Litestars it's it's like fast api with more options and like more stuff included.

00:11:37.680 --> 00:11:37.940
- I know.

00:11:38.340 --> 00:11:38.860
- It is interesting.

00:11:39.100 --> 00:11:39.840
Yeah, it's definitely interesting.

00:11:40.140 --> 00:11:40.340
- Yeah.

00:11:41.120 --> 00:11:44.780
- All right, also, also interesting is our sponsor.

00:11:45.460 --> 00:11:48.160
Sentry is back and I want to tell you about them.

00:11:48.480 --> 00:11:51.600
So this episode is brought to you by Sentry, of course.

00:11:52.000 --> 00:12:06.120
It's been incredibly valuable for tracking down errors in our web apps, other code that we run, that's web apps, APIs, even the Talk Python mobile apps use it and send in errors when something goes wrong for somebody in some far flung place in the world.

00:12:06.540 --> 00:12:13.200
Ian, I've told you the story more than once about how at Talk Python, I learned one user was encountering a bug through Sentry.

00:12:13.430 --> 00:12:16.080
I fixed the bug and I let them know before they contacted me.

00:12:16.080 --> 00:12:17.440
It was pretty wild, right?

00:12:17.820 --> 00:12:17.960
Yeah.

00:12:18.240 --> 00:12:19.140
So how does this work?

00:12:19.740 --> 00:12:31.120
I'll walk you through a few simple steps on how you might add error monitoring and distributed tracing through some kind of e-commerce app that's got a JavaScript front end, Flask back end.

00:12:31.440 --> 00:12:35.740
So if it's Flask on the front, React, sorry, Flask on the back end, React on the front end.

00:12:36.480 --> 00:12:40.480
You wanna make sure there's no errors during some checkout process for an e-commerce page.

00:12:41.000 --> 00:12:45.060
For me, anytime money and payments are involved, I always get a little extra nervous writing that code.

00:12:45.520 --> 00:12:46.440
So here's what you do.

00:12:46.650 --> 00:12:51.320
You enable distributed tracing and error monitoring in both your Flask backend and your React frontend.

00:12:51.640 --> 00:12:54.360
Then you want to add enough context

00:12:54.700 --> 00:12:57.080
to that frontend and backend action so they can be correlated.

00:12:57.560 --> 00:13:02.940
And to do that, you enrich the spans, a Sentry concept with business context.

00:13:03.260 --> 00:13:07.920
So in your React checkout, You wrap the submit handler in a start span and add information to that.

00:13:08.320 --> 00:13:09.700
Then you want to see the requests.

00:13:09.810 --> 00:13:11.460
You build a real-time Sentry dashboard.

00:13:11.710 --> 00:13:21.560
You spin up one using span metrics to track key attributes, part size, checkout duration, and so on, giving you a single place to see both performance and error data.

00:13:21.880 --> 00:13:22.240
That's it.

00:13:22.390 --> 00:13:29.200
When an error happens, you open up the entry on the error on Sentry and you get end-to-end requests and error tracebacks and so on.

00:13:29.200 --> 00:13:32.740
They also have a new product called Seer, which is C-E-E-R.

00:13:33.060 --> 00:14:03.100
is a thing that looks at your app and uses LLMs to understand what's going wrong and possibly even suggesting, you know, here's actually what's causing that bug and it could even potentially do a PR and help you fix it, things like that. Really cool. So it's not just looking at the error, but even, you know, going further than that. So if your apps and your customers matter to you, you'll definitely want to set up Sentry like I have over at Talk Python and Python Bytes and so So visit pythonbytes.fm/sentry and use the code pythonbytes, all caps, just in a word.

00:14:03.280 --> 00:14:05.000
That's pythonbytes.fm/sentry.

00:14:05.380 --> 00:14:06.540
Use the code pythonbytes.

00:14:06.960 --> 00:14:08.760
The link is in your podcast player show notes.

00:14:08.960 --> 00:14:10.300
Thank you to Sentry for supporting the show.

00:14:10.560 --> 00:14:10.720
Awesome.

00:14:10.820 --> 00:14:11.160
Over to you, Ryan.

00:14:11.420 --> 00:14:11.520
Yeah.

00:14:12.800 --> 00:14:13.620
Sleeping on the job.

00:14:13.880 --> 00:14:13.980
Sorry.

00:14:16.140 --> 00:14:19.400
So for the next topic, I want to follow up from last week.

00:14:19.680 --> 00:14:22.460
So just last week, I think it was last week.

00:14:22.660 --> 00:14:22.960
Yeah.

00:14:23.540 --> 00:14:25.420
444, Be Gone Python of Yore.

00:14:25.640 --> 00:14:26.480
Two thirds of a beast.

00:14:28.840 --> 00:14:30.960
That took me too long to figure that out.

00:14:31.800 --> 00:14:37.000
So one of the things we talked about was an article called Stop Using Django's Squash Migrations.

00:14:37.520 --> 00:14:38.940
And we had some feedback.

00:14:39.340 --> 00:14:45.560
So from Bruno Alla said, hey, just a follow up and a plug for one of my own projects.

00:14:46.240 --> 00:14:49.040
There is a project called Django Remake Migrations.

00:14:49.460 --> 00:14:51.300
So that's really kind of what I want to talk about.

00:14:52.040 --> 00:14:52.960
This looks pretty cool.

00:14:53.180 --> 00:14:55.080
So it sort of does a lot of the stuff.

00:14:55.380 --> 00:15:00.140
But one of the things that I like isn't just there's a tool that you can use to do a lot of this work for you.

00:15:00.230 --> 00:15:01.800
You don't have to follow the step by step.

00:15:02.460 --> 00:15:04.740
However, it's cool that it talked about the problem.

00:15:04.950 --> 00:15:08.460
So it says a Django admin command.

00:15:08.820 --> 00:15:11.640
There's a Django admin command to recreate all migrations in a project.

00:15:13.260 --> 00:15:16.920
This new one is like squash migrations, but it's on steroids.

00:15:17.400 --> 00:15:30.240
So it says the built in squash migrations command is great, but it only works on a single app at a time, which means that you need to run it for each app in your project and on a project with enough cross app dependencies that can be tricky.

00:15:30.660 --> 00:15:31.540
Yeah, that sounds tricky.

00:15:31.940 --> 00:15:41.000
So this command aims to solve this problem by recreating all the migration files in the whole project from scratch and mark them as applied by using the replaces attribute.

00:15:41.270 --> 00:15:48.640
I don't know what that does, but there's some caveats like all migrations are marked as one as replaced once.

00:15:49.420 --> 00:15:55.300
So I'm glad I'm using Git when I'm using any of this stuff so I could try it.

00:15:55.600 --> 00:15:57.600
And if it doesn't work, roll it back.

00:15:57.840 --> 00:15:59.380
But this looks pretty cool.

00:15:59.510 --> 00:16:08.240
So I wanted to just shout out to people to maybe try this as well, if you want to try to remake your migrations easier.

00:16:09.000 --> 00:16:54.240
While I was looking at this, I was like scrolling down, and it says the package was created with the copier template, and that rung a bell and it looked down and this was a while ago so michael brought up on this show talked about copier but that was back in 2021 so i'm going to go ahead and do a shout out to copier again because it looks pretty cool um copier is a is something like cookie cutter uh but it it's a cli app for rendering project templates but it looks kind of fun um uh so i'm going to check this out. I've got, I have some sort of project template needs coming up. And so I might take a look at this. They have a comparison too. So they're like, this is kind of like cookie cutter.

00:16:54.460 --> 00:17:16.760
Yeah. They know it's kind of like cookie cutter. There's some differences here. They've got a table in the documentation. One of the things I kind of like is that the configuration files in YAML format instead of Jason for cookie cutter. I don't, I'm not really a fan of either, but if I got to handwrite stuff, I'd probably rather handwrite YAML files. So anyway, interesting to take a look

00:17:16.860 --> 00:17:40.760
at. Nice. I think the biggest difference, other than I think being a little more maintained these days, is that it has, like with cookie cutter, you run a template, it generates a thing, and then you make changes to it, and that's it. With copier, you can apply, if there's a new version of the template, you can theoretically, at least, it has the option to try to apply a migration from the old version the new version.

00:17:41.120 --> 00:17:42.400
Oh, that's cool.

00:17:42.660 --> 00:17:44.360
Yeah, I think that's its biggest selling point.

00:17:44.600 --> 00:17:45.840
Template updates, yeah.

00:17:46.280 --> 00:17:47.220
That's actually awesome.

00:17:47.620 --> 00:17:47.740
Yeah.

00:17:48.180 --> 00:17:50.100
And it looks like it's composable too.

00:17:50.260 --> 00:17:57.920
So you can like, if you might have different, like say for instance in a Django, you might have several applications that you would add.

00:17:58.080 --> 00:18:03.760
You could use multiple copiers to pull an app, different apps into one application.

00:18:04.400 --> 00:18:06.980
Right, add a CRM action or something, yeah.

00:18:07.240 --> 00:18:08.440
Yeah, so interesting.

00:18:08.820 --> 00:18:10.000
Very interesting indeed.

00:18:10.440 --> 00:18:10.500
Cool.

00:18:11.000 --> 00:18:11.260
All right.

00:18:11.560 --> 00:18:12.120
On to the next one.

00:18:12.300 --> 00:18:13.460
This is kind of like the Django show.

00:18:13.700 --> 00:18:16.240
And one more Django shout out on top of this, by the way.

00:18:16.400 --> 00:18:25.960
I'm going to be doing a happy birthday, happy 20th birthday Django panel with a bunch of the creators in an hour and a half, two hours from now.

00:18:26.280 --> 00:18:26.500
Neat.

00:18:26.580 --> 00:18:29.940
Now, if you're listening to the audio version, there's a good chance that's already over.

00:18:30.480 --> 00:18:35.680
However, you can still either check out the live stream or in a few weeks, check out the Talk Python episode on it.

00:18:35.840 --> 00:18:39.060
So keeping with that theme, Django Kronos.

00:18:39.350 --> 00:18:42.020
This one's a quick little topic, but it's really cool.

00:18:42.270 --> 00:18:45.240
So I want to know how fast my page is loading.

00:18:45.590 --> 00:18:52.880
And I know there's the Django toolbar and all that, but here's a nice way to add more information about performance right into your browser.

00:18:53.100 --> 00:18:57.760
So it's Django Middleware that shows you how fast your pages load right in your browser.

00:18:58.050 --> 00:19:01.100
You simply add it as the first and last thing.

00:19:02.280 --> 00:19:06.440
You know, the quick start says add it as your last installed app.

00:19:06.720 --> 00:19:10.540
And it has a start and an end that has to be the first and last middleware.

00:19:10.840 --> 00:19:14.860
So it gets the full picture of all the middleware actions and all that kind of thing.

00:19:15.800 --> 00:19:23.140
I also would recommend saying probably show in production false, unless you really, really want to show in production, something like that.

00:19:24.040 --> 00:19:27.540
But the idea is it just shows you how long did your middleware take to run?

00:19:27.900 --> 00:19:29.480
How long did your view take to run?

00:19:29.660 --> 00:19:34.940
How long did your SQL queries and commands take as part of the middleware, as part of the view?

00:19:35.400 --> 00:19:37.020
And then how long did it take total?

00:19:37.580 --> 00:19:38.560
And how many queries?

00:19:39.100 --> 00:19:43.720
If you see the little screenshots of 7Q, 5Q, 12Q total, I'm guessing those are the number of queries.

00:19:44.320 --> 00:19:53.080
One of the really big problems when you're working with ORMs, like Django has, but many, is they have lazy evaluation for relationships.

00:19:54.080 --> 00:20:01.540
That can be tremendously slow because the programming model doesn't change if you do an eager query and join two things or you just use it.

00:20:02.060 --> 00:20:05.080
It's really just about how the query was structured, not how you program against it.

00:20:05.460 --> 00:20:14.340
So you might have, hey, I got a hundred things back from the list as one query, and then I loop over it and I interact with a field where each one of those is doing another query, a hundred more.

00:20:14.680 --> 00:20:18.440
So 101 queries, hence they typically called the N plus one.

00:20:18.540 --> 00:20:19.460
So you would see something like that.

00:20:19.500 --> 00:20:22.000
You'd be like, whoa, the view is doing 107 queries.

00:20:22.090 --> 00:20:23.540
I think I got two things, what's happening?

00:20:23.960 --> 00:20:26.400
Well, N plus one, some version there probably.

00:20:26.800 --> 00:20:33.620
Anyway, if this is interesting to you, It's not super big in terms of popularity, but it's also pretty straightforward and simple.

00:20:33.990 --> 00:20:35.000
And yeah, people might like it.

00:20:35.200 --> 00:20:37.440
- Remind me, where does the information pop up?

00:20:37.580 --> 00:20:41.000
Is it in the browser when you're developing or something?

00:20:41.090 --> 00:20:43.800
- I think it's at the bottom of the page.

00:20:43.930 --> 00:20:47.880
I haven't installed it and tried it, but it's somewhere in the page as part of it.

00:20:47.920 --> 00:20:48.080
- Okay.

00:20:48.390 --> 00:20:48.500
- Yeah.

00:20:49.340 --> 00:20:57.120
So basically, I believe what it does, it actually gives your template, your Django template, these pieces of information and you show them how you want.

00:20:57.220 --> 00:21:01.900
So it gives you middleware CPU time, SQL time, view, count total time.

00:21:02.080 --> 00:21:03.760
Basically the stuff that was on the screen.

00:21:04.020 --> 00:21:05.140
So you can put it in.

00:21:05.520 --> 00:21:09.920
It provides it as data values, and then you would put it into your view as you see fit.

00:21:10.200 --> 00:21:10.280
Right.

00:21:10.450 --> 00:21:11.240
I believe that's how it works.

00:21:11.500 --> 00:21:11.700
Okay.

00:21:12.100 --> 00:21:12.180
Cool.

00:21:12.560 --> 00:21:12.840
That's neat.

00:21:14.320 --> 00:21:14.500
Indeed.

00:21:14.690 --> 00:21:16.700
Well, those are our topics.

00:21:17.820 --> 00:21:20.260
I have a little bit of an extra.

00:21:20.710 --> 00:21:21.100
Go for it.

00:21:21.240 --> 00:21:21.580
All right.

00:21:23.140 --> 00:21:24.600
I'm going to go back in time a little bit.

00:21:24.860 --> 00:21:30.320
And so Test and Code is a podcast I started in August of 2015.

00:21:31.160 --> 00:21:32.180
So it's August.

00:21:32.680 --> 00:21:35.040
So it's now, it's August 20.

00:21:35.040 --> 00:21:36.060
It's almost two days.

00:21:36.580 --> 00:21:38.640
In two days, it'll be like 10 years.

00:21:39.680 --> 00:21:40.760
I think that's enough.

00:21:40.880 --> 00:21:42.520
I'm looking at like episode two.

00:21:42.960 --> 00:21:43.900
Episode one was terrible.

00:21:43.960 --> 00:21:45.180
So I deleted it a long time ago.

00:21:45.460 --> 00:21:48.940
So episode two is a pytest versus UnitTest versus Nose.

00:21:48.940 --> 00:21:51.120
And I didn't even capitalize pytest correctly.

00:21:51.740 --> 00:21:52.220
That's bad.

00:21:52.280 --> 00:21:57.900
And Nose is just, if I were to redo this, it would just say, don't, just pick by test.

00:21:59.260 --> 00:22:00.360
There's one option, really.

00:22:00.780 --> 00:22:03.760
Anyway, unit test is fine also, but let's get real.

00:22:04.020 --> 00:22:04.920
Don't use Nose.

00:22:06.100 --> 00:22:07.360
So what is this?

00:22:07.720 --> 00:22:08.740
Why am I bringing this up?

00:22:08.900 --> 00:22:17.180
Well, I just released on Friday, episode 238, So Long and Thanks for All the Fish, where I announced that I am no longer doing testing code.

00:22:17.440 --> 00:22:19.100
So closing the book on that chapter.

00:22:19.560 --> 00:22:24.380
I listened to that episode and yeah, I think what I'll say is congratulations.

00:22:24.640 --> 00:22:29.160
10 years and 238 episodes is quite a run and those things will be around.

00:22:29.300 --> 00:22:30.860
People can listen to them and enjoy them.

00:22:31.080 --> 00:22:31.280
Yeah.

00:22:31.420 --> 00:22:34.360
So that's another thing is I'm seeing.

00:22:34.620 --> 00:22:40.200
I'm not sure how long I'll leave it live because podcast hosting is something you have to pay for.

00:22:40.400 --> 00:22:41.820
So I am.

00:22:42.000 --> 00:22:42.700
You know what?

00:22:42.820 --> 00:22:48.600
I say you take it, write a little web scraper and just generate a static site and just leave it there.

00:22:48.660 --> 00:22:54.960
that's not something I might be able to give you work how about that actually so that yeah but the

00:22:55.140 --> 00:23:07.360
point was to remove work from my plate but you know we'll see all right can't leave that up in the air um all right what you got for us do you have any extras yes I have some extras let me get it ready

00:23:07.940 --> 00:23:19.080
so we have python 3 13 6 big question will this be the final 3 13 before 3 14 probably not but It's plausible, right?

00:23:19.360 --> 00:23:23.140
We're talking October, which is sadly not that far away.

00:23:23.530 --> 00:23:24.380
Not ready for rain.

00:23:24.670 --> 00:23:25.400
Not ready for it.

00:23:26.360 --> 00:23:28.740
Anyway, 3.13.6 is out.

00:23:28.740 --> 00:23:30.680
And there's actually a lot of changes.

00:23:30.910 --> 00:23:35.980
If you flip through the library, I don't know how many pages that is, but we're talking a lot of pages.

00:23:36.270 --> 00:23:42.180
So there's actually a ton of changes here that you might want to check out, you know, like little security fixes and other stuff.

00:23:42.460 --> 00:23:43.400
Does it have that zip?

00:23:44.000 --> 00:23:50.060
There was some kind of zip issue where you could trick it into do.

00:23:50.120 --> 00:23:51.560
And I don't think that was in Python.

00:23:51.780 --> 00:23:53.280
I think that was in pip.

00:23:53.660 --> 00:23:55.180
And uv also had it.

00:23:55.280 --> 00:23:58.940
So update your uv, by the way, folks, as well, which is uv self-update.

00:23:59.160 --> 00:23:59.460
Easy enough.

00:23:59.700 --> 00:24:00.620
Anyway, this is out.

00:24:00.860 --> 00:24:04.900
Because of our sweet Docker setup, I just did a rebuild on Python Bytes.m.

00:24:05.260 --> 00:24:07.240
And it said uv install Python.

00:24:07.860 --> 00:24:11.080
And we have 3.13.6 powering everything all of a sudden.

00:24:11.320 --> 00:24:11.580
Very nice.

00:24:12.020 --> 00:24:12.960
Anyway, quick and easy.

00:24:13.340 --> 00:24:13.440
Yeah.

00:24:13.620 --> 00:24:19.660
on top of that the final 13 the final countdown i was just listening to that song uh i have this

00:24:19.730 --> 00:25:31.800
really cool script and i think this is kind of it's kind of interesting and please don't write me and tell me other things are out there that do this because i know there are some that sort of do this but it's interesting in and of itself but it's also interesting as we get better and better llm and agentic coding tools i just say instead of just like depending on something that has 100 features and I'm going to take one or two of them and then deal with that. I just want this one thing. Could I just ask to have that one thing created? The answer is probably yes. So I wanted something that would auto activate Python virtual environments built with uv, named like I like, exactly as I navigate around my shell. So I asked Claude, I think, something like that. And it said, sure, here's a cool little bash script that as you enter a folder that either itself has a virtual environment or somewhere up in the higher hierarchy of it as a virtual environment it'll just activate it and if you leave that portion of the directory tree it'll go back and unactivate it and i know that dur env does some things along these lines but like i said i just like i think it's really cool you can just say really all that needs to be is like 35 lines of bash and then it never changes so i put up i decided someone was like oh that's really cool is that happening i'm like i'll just

00:25:31.880 --> 00:25:39.840
put that up as a gist and people can check it out i like it also something small that you can change if it's not quite what you want, change it.

00:25:40.090 --> 00:25:40.200
Exactly.

00:25:40.640 --> 00:25:44.160
I'm not looking for something that solves every problem for every programming language

00:25:44.550 --> 00:25:45.320
in the most.

00:25:45.900 --> 00:25:47.840
I just want this one little feature.

00:25:48.290 --> 00:25:52.760
And I don't really, to be honest, I don't know enough Bash to do this really well.

00:25:53.040 --> 00:25:53.920
But guess what?

00:25:54.230 --> 00:25:55.680
Either chat or cloud sure knows it.

00:25:55.850 --> 00:25:56.560
And it took care of it.

00:25:57.160 --> 00:25:58.440
So I'm really enjoying that.

00:25:58.700 --> 00:26:06.660
Yeah, I'm totally going to use this, although I'm going to change venv to.venv because Brett - The Canon convinced me that the dot is good.

00:26:06.840 --> 00:26:09.580
- I got tons of respect for Brett, but not my thing.

00:26:10.420 --> 00:26:17.460
I want to be able to look either via LS or in the macOS Finder and see that it has a virtual environment.

00:26:18.280 --> 00:26:19.660
And you can if it's a dot, right?

00:26:19.930 --> 00:26:21.300
So anyway, fair enough.

00:26:21.500 --> 00:26:25.140
I want to be able to look at it and go, yep, it absolutely has a virtual environment, right?

00:26:25.240 --> 00:26:27.760
'Cause that tells me what my next action needs to be.

00:26:28.000 --> 00:26:32.500
All right, I just, I spent a long time this summer writing up this huge long post.

00:26:32.760 --> 00:26:36.700
I don't know if it'll actually tell us how many minutes of reading time it is, if I ask.

00:26:37.260 --> 00:26:41.160
24 to 34 minutes of reading time for this article that I wrote.

00:26:41.480 --> 00:26:41.700
Okay.

00:26:41.860 --> 00:26:44.560
And it's called The State of Python 2025.

00:26:45.030 --> 00:26:46.960
I wrote this in partnership with JetBrains.

00:26:47.460 --> 00:26:59.940
And it takes the PSF JetBrains survey results and does like a ton of analysis on it and predictions and concrete actions people could take based on the trends that we're seeing and so on.

00:27:00.220 --> 00:27:01.680
So I'll put that here now.

00:27:01.840 --> 00:27:08.660
I think I might make this one of next week's items and we can dive into some of the trends and recommendations and you can tell me how I'm wrong or right.

00:27:10.040 --> 00:27:14.380
But it just came out this morning, so I thought I'd go ahead and just throw it out there as an extra for now.

00:27:14.640 --> 00:27:14.800
Cool.

00:27:15.080 --> 00:27:15.220
Yeah.

00:27:15.560 --> 00:27:24.720
Next, if you run local LLMs, as I do, and there's a really interesting option, you can now run OpenAI's.

00:27:25.100 --> 00:27:26.200
Well, first of all, hey, guess what?

00:27:26.400 --> 00:27:31.640
OpenAI has a public open weights model you can use and you can run it locally.

00:27:31.820 --> 00:27:39.680
So I'm running here in LM studio in developer mode and programming against the GPT OSS 20 billion parameter model.

00:27:40.040 --> 00:27:40.560
How cool is that?

00:27:40.880 --> 00:27:41.320
That's pretty cool.

00:27:41.640 --> 00:27:41.700
Yeah.

00:27:41.940 --> 00:27:42.300
So I have some,

00:27:42.460 --> 00:27:43.100
maybe, I don't know.

00:27:43.820 --> 00:27:44.300
It's super cool.

00:27:44.300 --> 00:27:47.140
I have some other things that I created, like little utilities.

00:27:47.210 --> 00:27:49.620
I'm like, Hey, I want this utility to work and it needs an LM.

00:27:50.080 --> 00:27:53.520
And I knocked it out real quick in combo with some agentic coding.

00:27:54.000 --> 00:27:57.180
And it was using when, which was pretty good.

00:27:57.210 --> 00:28:00.640
But then when this came out, I'm like, let me try this and see if it'll give me better answers.

00:28:01.160 --> 00:28:01.340
Sure enough.

00:28:01.660 --> 00:28:04.900
So now I'm just running this locally on my Mac mini and talking to it.

00:28:04.900 --> 00:28:05.780
And it's pretty good.

00:28:06.000 --> 00:28:06.920
So that's a cool option.

00:28:06.930 --> 00:28:09.420
You run it in Olama or other places as well.

00:28:09.720 --> 00:28:17.760
And finally, just remind people that we just released the Just Enough Python for Data Scientists course for $29 over at Talk Python.

00:28:18.060 --> 00:28:27.380
So you're getting started in your data science journey or you feel like you've been doing it for a long time, but you just don't quite have the software engineering techniques and tools and so on.

00:28:27.620 --> 00:28:28.140
Check this out.

00:28:28.390 --> 00:28:29.460
Just talkpython.fm.

00:28:29.570 --> 00:28:30.020
Click on courses.

00:28:30.460 --> 00:28:30.780
Be right there.

00:28:31.220 --> 00:28:31.860
That's it from extras.

00:28:32.410 --> 00:28:32.500
Awesome.

00:28:33.860 --> 00:28:34.600
That's all over extras.

00:28:34.920 --> 00:28:36.740
Do we have, do you have something funny for us?

00:28:36.850 --> 00:28:39.320
I have a quick follow-up before we do from Pat Decker says,

00:28:39.430 --> 00:28:40.520
I saw your post on Bluesky.

00:28:40.820 --> 00:28:41.900
Listen to 238.

00:28:41.930 --> 00:28:42.580
I agree with Michael.

00:28:42.800 --> 00:28:44.240
Congratulations on 10 years, Brian.

00:28:44.590 --> 00:28:44.940
Thank you.

00:28:45.330 --> 00:28:45.660
Thanks, Pat.

00:28:46.020 --> 00:28:46.200
Indeed.

00:28:46.700 --> 00:28:46.820
Okay.

00:28:47.040 --> 00:28:47.900
Yes, we have a joke.

00:28:48.460 --> 00:28:48.940
Let's check it out.

00:28:48.970 --> 00:28:54.700
This one, you know, people don't like if I, they don't like generally when, when one language bashes on another.

00:28:54.710 --> 00:28:56.580
Well, some of them do, but not, not generally.

00:28:56.870 --> 00:29:00.080
So keep folks, before I show you this joke, it's supposed to be lighthearted.

00:29:00.400 --> 00:29:01.740
Please don't, Don't email us, tell me.

00:29:02.160 --> 00:29:05.900
So the joke is, Python is better than Java, says someone.

00:29:06.340 --> 00:29:07.600
Another person says, prove it.

00:29:08.400 --> 00:29:19.820
So the original person fires up Python, creates two strings, one named Python, one named Java, and then asks, as writing in the interpreter, Python greater than Java as strings?

00:29:20.240 --> 00:29:20.400
True.

00:29:20.900 --> 00:29:21.480
True, says Python.

00:29:22.820 --> 00:29:23.560
It's greater.

00:29:23.880 --> 00:29:24.440
Yeah, sure.

00:29:25.840 --> 00:29:26.020
Truth.

00:29:26.300 --> 00:29:26.540
It's true.

00:29:27.220 --> 00:29:27.600
There you have it.

00:29:27.680 --> 00:29:28.760
Anyway, I just thought that was funny.

00:29:29.100 --> 00:29:29.340
Yeah.

00:29:29.620 --> 00:29:31.780
It's too bad that Python doesn't have a better operator.

00:29:32.340 --> 00:29:34.000
Not necessarily greater, but just better.

00:29:34.440 --> 00:29:34.680
Exactly.

00:29:36.640 --> 00:29:37.540
Well, there it is.

00:29:38.120 --> 00:29:39.000
Yeah, that's the joke.

00:29:39.600 --> 00:29:39.980
All right.

00:29:40.320 --> 00:29:40.380
Cool.

00:29:40.740 --> 00:29:41.880
Well, thanks again.

00:29:42.180 --> 00:29:43.040
Thanks, everybody, for listening.

00:29:43.660 --> 00:29:44.660
And see you next time.

00:29:44.900 --> 00:29:45.040
Yep.

00:29:45.260 --> 00:29:45.540
See you later.

00:29:45.880 --> 00:29:46.020
Bye, all.

