Hello and welcome to Python Bytes, where we deliver Python news and headlines directly to your earbuds.
This is episode 330, recorded April 4th, 2023.
I'm Michael Kennedy.
And I'm Brian Okken.
And you can connect with us over on Fostadon.
If you're on Mastodon, find us there.
I'm at mkennedy at Fostadon.org.
Brian's Brian Okken over there.
And the show is at Python Bytes at Fostadon.org.
And if you're interested in the video version, check out pythonbytes.fm/live.
Click that.
Go over to the YouTube channel.
Subscribe.
Get notified.
You'll get a little pop-up when we start streaming live.
It's always fun to be part of it.
We encourage people to check the show out that way as well.
So, Brian, let's start off with something that has been almost exactly one year in the works.
I was just going to ask you about that.
So, was this about a year ago we talked about this, Pydantic?
I think I saw something on Twitter, of all places, from Samuel Colvin saying it was April 4th, 2022, that I started working on Pydantic version 2.
So, that sounds like to the day.
Okay.
Well, it's not completely here yet, but it's here enough to try.
So, I'm pretty excited about it.
So, Pydantic V2 version 2 pre-release.
So, people can, it's available now.
So, people can install it.
You have to do the, like the install --pre Pydantic.
And then you can say Pydantic greater than or equal to 2.0 A1, I guess, if you want to get the alpha one or better.
So, the big news is alpha one's available.
And it's pretty exciting.
There's a whole bunch of great stuff changes.
We've talked, I think we talked about it.
You talked about it on your show, I think also.
Yeah.
But the headlines here is, well, one, it's not complete yet.
This is the alpha.
We're not even debated yet.
So, if you see, if you try it out and you see something, they've got a GitHub, created a GitHub issue.
And they want to have people use the bug V2 label to create issues around the version 2.
Because they want to hop on those right away.
Anyway, so, the big change was, one of the big changes was to move a lot of Pydantic and the rules and everything into a different module called Pydantic Core.
That one's mostly written in Rust.
And so, it's like 5 to 50 times faster overall for performance.
So, that's pretty exciting.
I mean, this is, when you're using Pydantic, it's hitting for every interaction, right?
So, as fast as possible is great.
And I do like the idea of the, like, the separating the Rust part out into a different module, a different package, Pydantic Core, so that they can have, kind of maintain it and have safety and maintenance around that a little separate.
I think that makes sense.
Yeah.
And people used to have to create their derived classes and put a lot of their customization and their, you know, what's called root level validators and things like that.
Where it's like, I want to validate the whole class, not just a certain field.
Or, you know, if this is set, then that has to be set that way.
Like, a lot of those things had to be done in an OOP way.
And I think with the Pydantic Core, you have more direct access to, like, a layer below.
So, it's not just faster, which is fantastic, but it also opens up, like, more ways to interact with Pydantic, which is cool.
Yeah.
So, they've got a lot of stuff working already.
They want people to be able to experiment and try out their base model changes.
A lot of the same features for validation, but there's new method names, and it is a change.
Data classes, serialization, strict mode, different schemas.
Lots of changes for V2.
So, I'd like people to try it out.
There is a lot of stuff still under construction, mostly documentation.
And some of the base settings have changed from there were base settings, and now they're going to be in Pydantic settings.
That's not quite ready.
So, there's still some work to do, even in the migration guide.
So, they've gotten a start on the migration guide, but it's not there.
As you see on, like, some of the links, there's changes to data classes, changes to base model.
Some of the stuff's already there, but it's still under construction.
So, pretty exciting.
I'm definitely excited, and the 5 to 50 times faster, that's no joke.
There's, you might think, okay, well, what are you doing?
I'm, like, parsing, like, a settings file, or I got a single JSON document, whatever.
All of FastAPI is deeply, not all, but much of FastAPI is deeply based on exchanging rich data with Pydantic, right?
So, your API layer could get much faster, right?
And you can also use this, people maybe don't realize it.
You can use this with other frameworks as well.
You could use it with Flask.
You could use it with Pyramid.
You know, FastAPI is cool, because you can put just, there's a argument of type Pydantic model, and it automatically fills it all in.
But all you've got to do is just take, here's the post dictionary, and feed it to a Pydantic model.
Like, just inside the function is the first line, and you're in the same place.
So, you can use this across all these areas.
Then, for example, Pythonbytes.fm is powered by Beanie, which is Pydantic plus MongoDB plus Async, which is awesome.
But every single database record comes back, goes through Pydantic.
And if you're using something like Beanie or SQL model, in FastAPI, your data layer goes through Pydantic, and your web layer goes through, there's like multi-layered Pydantic operations on every interaction.
And so, making that part five to 50 times faster is just huge, right?
That's a really big surface area to make a lot faster.
I got speedups as well to talk about later in the show, but it's not that much area.
That's awesome.
One of the things you bring up, which is interesting, is that a lot of people, I mean, there's tons of people that use Pydantic just by itself with their own code.
But the people that mostly touch it through FastAPI or Beanie or something, they may have to wait until those projects bring on the changes then,
unless those projects have branches for B2, which who knows?
I, yeah, yeah, I hope so.
And maybe there's a way, you know, I think the breaking changes in, say, base model, for example, are, I think they're kind of deprecated already.
And 1.10.7, just they're still there, right?
But I think they become breaking changes here.
If you're also, if you're doing model validation, a lot of the function names gets changed.
Yeah, like things like from RRM go away.
There's a bunch of little, I don't think they're big changes that are going to be a huge problem for people, but they are incompatibilities, as you point out.
Both Roman Wright and Sebastian Ramirez seem to be really on top of their projects, respectively, Beanie and FastAPI.
So I feel like by the time this becomes fully released, they'll be there.
Yeah. And what's one of the reasons why I covered is to try to like promote everybody.
Nudge, nudge. Hey, exactly.
Nudge, nudge.
Exactly.
Please.
So, yes, indeed.
Yeah, it would be awesome that when this comes out for just, boom, V2 is out, like you just update all the packages that depend upon it and you can adopt it right away.
That would be great.
But to be fair, like let's say I'm working on a side project that's using FastAPI or Beanie or something and I don't have it in production yet.
I'd be like, yeah, let's use V2 right away.
But if I've got a production system, I don't want to switch right away.
So I get that there's projects at different levels and group projects like FastAPI and Beanie have to keep that in mind.
So, yeah.
All right.
Well, this is exciting to me.
I know this has been coming for a long time.
So excellent work.
What you got for us?
Well, that's a quick real time follow up.
I interviewed Samuel Colvin.
He loves to do stuff on the fourth of months, apparently, on August 4th as well.
Last year called PyTanic V2, The Plan.
So people can check that out if they're interested.
But let's talk about something really small, okay?
Okay.
From a friend of the show, Miguel Grinberg.
And he created this thing called MicroDot.
MicroDot, it's very small.
It's bigger even than like the semi-dot or the regular dot.
Very small.
No, so what this is.
Yeah.
So back to web frameworks.
This is the impossibly small web framework for Python and MicroPython.
So it's, I believe it's reason for existence really is to basically bring something like Flask
to MicroPython and CircuitPython, which is cool.
However, it also runs under standard CPython, which opens up some interesting possibilities as well.
Cool.
So if we go down here.
So if you're familiar with the Flask API, you should be real familiar with MicroDot.
So app equals, instead of Flask, you say MicroDot.
Got a function.
It says, I want to do an app.route on it.
Or I don't know if he supports direct verb, HTTP verbs there, like app.get, app.post, like Flask
adopted recently, but app.route for sure.
And then one of the differences is you have to pass a request object into the functions
there.
Whereas Flask has this thread local ambient variation of this thing.
So you'll get like a 500 error if you try to, you know, just run this directly without adding
that request.
So it's easy to overlook.
But other than that, other than the fact that there's a request parameter to the views, basically
the same thing.
Okay.
So yeah, that's pretty interesting.
Now, there's a bunch of compromises that are made here because MicroPython doesn't support
Jinja.
It doesn't support Flask, all of these different things.
All right.
So there is a template language, but it's not Jinja, right?
So there's a bit of a migration if you were going to take this on, right?
So you can run it under CPython, but you can also run it under MicroPython.
There's the HTTP methods.
I think you see the old style.
No, no, there's an app.get.
You can do the old style where you pass the method names like get and post, or you can just
do an app.get.
But yeah, again, if you're familiar with Flask, the way you do routes, the way you pass data
into the functions, all those things are absolutely the same, which is pretty cool.
One thing you can do is you can return JSON responses, and you can even just return a dictionary,
which I don't think you can do in Flask.
Maybe you can, but I think you have to JSONify it.
I think you have to say Flask.jsonify.
So this is kind of an upgrade, I would say.
Okay.
So if you have a little tiny thing, like a little tiny thing like this, Brian.
Okay.
All right, here.
However big is that, you know, like not about the size of my hand, like the half the way
across the pole of my hand.
I got one of these little tiny MicroPython, CircuitPython things.
You can now put APIs on here, and you can put even really interesting things like it has support
for concurrency.
So Flask doesn't support directly having async and await, I don't believe.
Not fully, anyway.
You got to switch over to Quart to do that.
I think they partially support it, but not full async and await.
But you can use the MicroPython asyncio extension here and get APIs running with full async and
await concurrency support doing JSON or other things.
Maybe with Pydantic.
Not sure.
That's pretty cool.
Because a lot of the, I mean, that's just an easy, like throwing a REST API or some
sort of API on something to throw back JSON to, that would be really cool.
And you don't need, I mean, for applications like that, you don't need a lot of templating
around.
Yeah.
And so let's see, go to the core extensions here.
You can see there's actually a bunch of cool core extensions.
So got the async and await support.
So all you got to do is just, where I'm going to scroll, just write async def endpoint,
right?
Boom.
Off it goes.
Yeah.
Because you really want to async that hello world.
Yeah.
For hello world, not so much.
But if you're talking to, you know, files that's similar database or something.
Yeah.
You can use, what is that?
MicroTemplate.
It says U-Template, but I bet it's a micro.
I think it's pronounced template.
Template.
Yeah.
U-Template.
It's a lightweight and memory efficient template for Python, which it looks very, very
Jinja-like as well.
So that's a pretty straightforward thing, but it's not identical, right?
What else we got?
Ooh, this is Jinja, isn't it?
Oh, can you?
Oh, you.
But no, hold on.
It's CPython only.
Oh, okay.
Okay.
Got it.
So, because it's not supported in MicroPython.
Got it.
But if you're doing it on CPython, you can add those templates.
Yes.
This is actually why it's pretty interesting to me.
So you can do TLS, HTTPS support, right?
Which is pretty cool.
You have web sockets.
You have asynchronous web sockets.
You have cores, cross-origin, resource sharing settings.
And you can even deploy it.
So it comes with its own little web server, which you can run on your MicroPython daily,
right?
But if you were going to put this into a big data center on a huge rack of servers,
that might not be the best choice.
So you can run it on uWSGI, which is awesome.
You can run it on GUnicorn.
You can even run it on GUnicorn with UVicorn workers to get the awesome LibUV high-performance
async support, right?
So you can deploy it onto kind of the top-tier Python stuff, put Nginx in front of it and all
that.
It's pretty cool, right?
Yeah.
Now, one of the ways you run web apps on servers, especially in Python, because the threading
support is not as friction-free, I guess, you know, like the GIL and all that, is you'll
farm it out into multiple workers, right?
So I can't remember what we have for Python by it.
It's not too many.
So I can't remember what we have for Python.
It'll automatically send the request over to another one, right?
Now, usually there's maybe a couple of limits, but one of the limits you really want to consider
is I don't want to run the machine out of memory.
So I think the ones we use like 150 megs per worker process.
So at some point, they only create so many, and then the server's like, okay, I've had it.
But with this little thing that runs on MicroPython, you could scale the heck out of it.
You could have a ton of worker processes under MicroWSGI.
Oh, yeah.
Or under UVicorn, right?
And I actually did a little super simple test.
I wrote the Flask equivalent of Hello World, literally exactly the same code with the changes
I talked about.
And then the MicroPython version, sorry, the micro.version, and that one, both running on
CPython, nine megs for this framework, 25 megs for the Flask framework.
So maybe you can have twice as much processing horizontal scale with this thing, but deployed
to real servers.
So there might actually be some interesting advantages to having this really tight framework.
Like I want to run it in a bunch of Docker containers that are using the smallest amount of
memory.
I want to farm it out and say, no, I'll have 30 worker processes on the server, not five.
I don't know.
We'll see.
Yeah.
So Panful is pretty psyched about the memory saving out there as well.
So I think it's good.
Yeah.
And I mean, for lots of jobs where you don't need, if you don't need the power, don't use
the power.
So.
Yeah.
Pretty neat.
So well done, Miguel.
And yeah.
Now, Brian, let me take just a moment and tell everyone about our sponsor.
This episode of Python Bytes is brought to you by Influx Data, the makers of InfluxDB.
InfluxDB is a database purpose built for handling time series data at a massive scale for real
time analytics.
Developers can ingest, store, and analyze all types of time series data, metrics, events,
traces in a single platform.
So dear listener, let me ask you a question.
How would boundless cardinality and lightning fast SQL queries impact the way you develop
real time applications?
InfluxDB processes large time series data sets and provides low latency SQL queries, making
it a go-to choice for developers building real time applications and seeking crucial insights.
Optimized for developer efficiency, InfluxDB helps you create IoT, analytics, and cloud applications
using timestamped data rapidly and at scale.
It's designed to ingest billions of data points in real time with boundless cardinality.
InfluxDB streamlines building once and deploying across various products and environments from the
edge, on-premise, and to the cloud.
Try it for free at pythonbytes.fm/influxDB.
The links in your podcast show notes.
Thanks to Influx Data for supporting the show.
Over to you.
What's your next one?
I want to talk about GitHub Actions a bit.
So a lot of my workflows have moved over to GitHub Actions.
And so there's actually three projects that I wanted to talk about that I thought were neat.
And they're all kind of in the GitHub Action genre.
Whatcha got?
Whatcha got first?
Whatcha?
Watch GHA.
It comes from Ned Batchelder.
This is a, a, a, just a simple tool to, to watch your GitHub Action progress from a command line.
So, pretty, I think it's a command line thing.
Looks like command line.
Um, and so it looks, so you can, it has like a little progress bar thing, progress dots that go green.
And then they start out gray and then they go white and green and stuff.
Um, to see the, the different things you got like, you're running three, seven on Ubuntu.
By Pia.
So if you've got a big matrix, that's doing a lot of stuff, it's kind of hard to keep up with what, what all's going on.
So, this is kind of neat to watch just a little tool from Ned.
Thanks, Ned.
Um, one of the other things I, I, I was thinking about, so I just, my talk at PyCascades was talking about, that you can share, you can just, you can share packages without actually ever building it.
Uh, because pip install will build your wheel for you if, if it's not built already, but you probably, you probably should test that.
Um, and one of the ways you can test some of that building is with, with Enix, build and inspect Python package.
Um, so this is a GitHub action that, will, it does a lot of stuff, but it does, it does a build to make sure the build works.
Um, it also does, has a linter to, to lint the wheel contents.
Um, it also uploads the, wheel and the source distribution as GitHub action artifacts.
So it actually does generate the wheel for you, as an artifact, which is kind of neat.
Um, the, it also, one of the things that's, what's one of the things that's always a mystery to me is like the makes, making sure I have everything that I want in the S dist, the source distribution.
And, this, this will, lint that.
And also, well, I guess it doesn't lint the contents of the S dist, but it does print them out.
So, print does a tree of the S dist and the wheel in the output so that you, you don't have to download it to check it.
You can just look at it in your GitHub output.
Make sure all the files and resources you might need to send out come along.
Yeah.
Um, and this, yeah.
Um, I, I, I had recently made a change to a package and it took out the tests and I had somebody say, Oh, look, we, we want the tests back in.
So it's kind of nice.
Um, so, let's, I guess that's, that's it with that.
It's kind of a neat, GitHub action thing, that you just put it, put it in.
It's one of those actions.
So you just like specify it and it just works.
It's nice.
Uh, the, the third thing I wanted to bring up was, py test, GitHub actions, annotate failures.
Um, so this is a, one of the, just a nice extra thing that I hadn't heard about before.
Um, py test it's under the py test dev, umbrella, but it, it is a, it's a pip install sort of thing.
And what it does is it makes sure that the, the, all the, the proper stuff gets output, so that you can have nice annotated failure.
Your asserts, if there's failures, it's annotated nicely and github actions.
That's it.
Just some fun GitHub action stuff.
Yeah.
Once you really start getting into CI, CD, it's, it's fun.
And you're just like, oh, and now that it's automated, we could do this.
So we could do that.
Yeah.
And then, but when they automate all the things and then when things go wrong, you're like, oh God, then we have to pull it down and check it again.
But having, so having some of these debug stuff and things up, up in the cloud, it's good.
Yeah.
Very handy.
Excellent.
All right.
Well, I have a PEP for us to discuss.
Okay.
709 inlined comprehensions.
Now, this is a debate that I seem to have only on YouTube.
Um, if I'll do, like, I've done some videos about list comprehensions or other sort of design patterns.
You might involve comprehensions and people are like, oh, Michael, you said that a for loop is different than a list comprehension.
But look, it says for thing in collection.
And so they're the same.
And so I just don't know.
You just don't know what you're talking about.
Like, you know what?
Let's disassemble it.
Let's see what it does.
Is it the same disassembly?
No, it's completely different disassembly.
That means the implementation of list comprehensions are different.
I don't care if the word for appears in both of them.
They're not the same thing.
This PEP brings them, kind of tries to take the both, the best of both worlds, though.
And it says there are some things we do to make comprehensions work, but look like they're just right there in the same function or in line, even if you don't have a function.
But in fact, there's kind of this thing behind the scenes that's happening where we create a nested function that you never see, but the interpreter creates and then calls it.
And that's the interpreter.
OK.
The comprehension, rather.
So this PEP by Carl Meyer is basically saying we could get really good performance increases if we just change that implementation a little.
And the reason it's created as a nested function and not just some inline code is what if you have a variable X in your regular function and then you have X as a loop variable or as the item variable in your comprehension or things like that, right?
You want them to still be isolated.
So that's basically the idea here.
It says comprehensions are currently compiled as nested functions, which provides isolation of the comprehension's iteration variable, but is inefficient at runtime.
So PEP 709 proposes to inline list dictionary and set comprehensions into the code where they are defined and provide the expected isolation by looking at all the variables, creating a copy of them, running this in place.
And then if there was a variable for that loop variable, just put the old value back, right?
Kind of push and pop them there.
And the benefits here are up to two times as fast as comprehensions are today.
So then they said, this is translating to an 11% speed up in one sample benchmark derived from real world code that makes heavy use of comprehensions in the context of doing actual work.
That's pretty cool, right?
Yeah.
I believe comprehensions were in general slightly faster than four loops that would just do something and put it in a list.
So making it two times faster still is even better.
So if this gets adopted, it's in draft form right now.
I can go back to my YouTube comments and have even further nuanced discussions about like, here's yet again, how they are not the same thing, but they look similar.
So yeah.
I never would have thought that I should reuse a variable in a comprehension though.
I don't do that, but I guess.
No, I think it's like if, let's say you've got two list comprehensions, you know, X squared for X in first set.
Then X, two X plus one for X in other set.
Those are two separate list comprehensions.
You don't want like one of those variables too.
You want to keep them.
They want to be like, okay, this X is only for this comprehension.
That's what it's like.
So if you have an embedded comprehension, you might use X in both places.
Right.
Or if you have an X, X and Y equals something, and then you generate a comprehension, you say X in there.
Like there's a couple of, there's some weird.
Yeah.
I mean, I guess I was just thinking my own style.
The second one I would never do.
If I had, if I was already using X, I probably wouldn't use X in the comprehension.
But I'll often use I or X in a comprehension in embedded ones and don't even think about it.
So yeah.
Interesting.
Cool.
Yeah.
David Poole says, I'm sure there's good reasons for it, but I wonder why comprehensions don't use name mingling strategies for their var names.
Everyone's got to be named underscore underscore X.
That is a good question.
That reminds me of a joke.
Well, so what it's doing now is it basically says, we're going to create a function.
And so that variable is basically a local variable, that function, which has no influence on it.
Were you going to actually tell us the joke?
No, it's going to wait.
Okay.
All right.
Or should we do it now?
Oh, just, I think it was Ned Batchelor actually that mentioned that Dunder, we often talk about Dunder init instead of double underscore init.
But it's really underscore underscore init underscore underscore.
So it's really quunder.
Quunder.
And so I responded to him and said, I don't think so.
I think it's Dunder and Net Dunder is what it should be.
But that would be Redunderant.
It's pretty bad.
That's pretty much on par with the joke we got at the end.
So I'm preparing for people.
All right.
So basically the way to understand this, you can't look at the code and tell, right?
Which is why people incorrectly try to correct me on YouTube.
So you look at the code and it looks like, oh, it's just a for list and we took out the line breaks and put brackets.
So it's the same thing.
So if you look at it now, you can see if you create a function that creates a list comprehension, you'll see it creates what's called a code object of type list comprehension.
Then it calls make function.
Then it loads the list and then it does a bunch of stuff on it.
And then it actually, you can see there's like this sub function that gets disassembled and it says, we're going to build a list, load fast, iterate it.
So let's look at list append.
And what's really interesting, this is the part that differs from for loops.
There's a byte code called list underscore append.
If you do this with a for loop where you have a list and you call append, it loads the function append and then calls append on the operands.
But it's not in the runtime in a for loop.
In a comprehension, there's a special byte code that runs and that's like the primary difference.
So the benefit is list append is a byte code operation, not a function call.
But the drawback is there's this object created, there's a stack frame created, there's a function call over to this comprehension call.
There's an issue with all that stuff.
So the new one just says, what we're going to do is we're going to create a new op code called load fast and clear, which is like, I'm going to load the variable X.
And if there was one of those before, we're going to hang on to that just in case, you know, so we can put it back to avoid that.
And then it calls build list.
And like you can notice, there's no, there's no function call.
So no stack frame, no extra function call.
There's no list comprehension object, all those things.
And so this is the new byte code operation that manages that variable isolation.
And then you just do it directly, which saves you a bunch.
We talked about the 2x speed there.
So that's the, that's the, the pep.
People check it out.
See what you think.
That's really interesting, Michael, but you had me at it's faster.
I know exactly.
I just want people to kind of know what's, what's happening and why it might be faster and so on.
So pretty neat.
You can see it does have the, the only possible, I guess, concern or the reason they say, why is this even a pep?
Why is this not just, Hey, I made it faster.
Like, why do we need to discuss this?
Yeah.
Like you said, right?
Like it's faster.
We're done.
Let's go.
Is there are user observable changes?
If the user doesn't like themselves, basically.
For example, why would a user return locals as the item you want put into a list during a list comprehension?
Well, if you did do that, you would see that it's not the same as before.
I have no, no idea why you would ever try to do that, but that would technically would be a breaking change.
The other one was slightly more valid, perhaps is that if there's an exception inside the list comprehension, because it used to be in a separate function call.
It was, there's, it would show up in the actual traceback call stack, right?
But now you are not in another function.
It is on a line in the OG function.
So you, you don't have that.
Basically it's missing from there.
So you would have a slightly different traceback exception.
Well, traceback, the exception would be the same, but the traceback call stack listing would be different.
That potentially affects somebody, but not a lot.
I don't know.
It's a 2X, it's a trade-off.
I would totally think it's worth taking.
Yeah, but I, I see why that's a, it's a observable interface or an observable behavior change.
So yeah.
Yeah.
Although I learned from Brett Cannon just a couple of weeks ago that locals often has weird stuff in it.
If you look at locals a lot, sometimes there's stuff in there that you don't recognize.
Interesting.
Yeah.
The locals one seems like, you know what?
Don't do that.
But the traceback one, I can see, okay, we're always looking for this.
And like, if I get an error, I try to like, look at the traceback to figure out what to tell people.
Or I don't know.
Theoretically could have, it still seems unlikely.
I feel like you shouldn't depend upon what's listed there, but I'm sure somebody does somewhere.
Well, like IDE makers and things like that.
Yeah.
Cool.
All right.
Well, that's it for all of our items.
You got any extras?
I don't.
Do you?
I thought I didn't have any extras, but I think by the time, I'm going to try to predict the future a little bit because I have some control over it.
So I do have an extra.
I'm going to be releasing either today or tomorrow.
And by the time this podcast comes out, this is going to be released.
But if you're watching it live, it's not yet released.
So I'm going to be releasing a new course, Python Web Apps That Fly with CDNs.
It's just over a three-hour course that's all about taking CDNs and applying them to Flask web apps and also hosting video content and large files and how do you geo-replicate that.
We use a lot of these techniques in Python Bytes to make the website faster as well as to deliver terabytes of MP3s to people.
So check that out.
I will put a link in the show notes.
Again, if you're listening live, this is not out yet, but it will be out by the time the MP3 hits your podcast player.
So if you have the audio-only version, go check it out.
Link's in the show notes.
Nice.
Yeah, I think that's a really, really cool course.
I think there's so much people can get out of it in terms of like it's really easy.
You know, 30 minutes and you're like, oh, our app is so much faster and we can use smaller servers.
That's really great.
Well, three hours plus 30 minutes.
Yes.
Well, once you know the thing, it's probably 30 minutes to apply it to your app.
That's what I mean.
Yeah.
David Poole says, the traceback one could be worked around if the debug compiled used the old function style method,
like aggressive optimizations and GCC with inline functions.
Okay.
Possibly.
Interesting.
You would have to have people buy into that, but right.
I mean, I'm sure, Brian, you're very well aware of the debug versus release builds and optimization levels and all that stuff in C, right?
No.
I mean, yes, but I don't use them.
No, you don't use that.
Well, I don't, I personally don't like to, I don't like to test in something my user isn't going to see.
So I always test in optimized released.
Got it.
Yeah.
But it can make a big, it can make a big difference.
But in the Python world, we don't really discuss that so much.
Right.
Yeah.
And except for the, the, the comment, the one thing to be aware of that I would, while we're, while we're on it, we probably haven't mentioned this lately is asserts are awesome in your test code, but they're not that great in your, it actually, they're, they're pretty great in your function code also, but just don't depend on, on it.
Because assert lines could be completely removed if you have the optimization on.
So.
Absolutely.
Yeah.
All right.
You ready for a joke?
Yes.
You fan of movies?
Like watching, watching movies and stuff?
Yeah.
I just went to a great movie.
Yeah.
So.
Nice.
Well, as a software person, especially if you do a lot with Linux or macOS, you might not be able to watch the movies too much.
This one says, I can't watch movies on my computer.
All it does is bash scripts.
Bash on the scripts of the movie.
Oh.
Not plot.
Or, or run shelf scripts.
I'm not sure which.
Okay.
That's funny.
I think.
Sort of.
Yeah.
Somewhat.
I have an incredible one that I want to put up, but it's like only video that has music and no, no spoken word.
So I don't think it fits for this format, but I'll, you know what?
I'll throw it in.
People also check out the movie.
It's about releasing stuff to production.
So it's, it's pretty epic.
I'll put it in the list.
But the one we won't play is something that's like 30 seconds long that has nothing but music.
Cool.
Nice.
All right.
Is that all we got?
That's all we got.
It's a wrap.
Yeah.
Thanks as always.
Thank you.
See you later.