I am pulling off a very, very cool trick.
I just want to point out before we get started.
Okay.
On the Talk Python channel,
I'm doing a podcast with Anthony Shaw and Shane from Microsoft
about Azure and Python and some CLI stuff they built and FastAPI.
And at the exact same time, I'm doing this one here.
They're both streaming live.
I don't know how that's happening.
The other one was recorded two months ago,
and we couldn't release it because some of the things weren't finished yet.
So I hit go on that.
The real one, if you're bouncing around, the real one is here.
Okay.
So a joint is here.
Anyway, with that, you ready to start a podcast?
Yeah, definitely.
Hello, and welcome to Python Bytes,
where we deliver Python news and headlines directly to your earbuds.
This is episode 294, recorded July 12th, 2022.
I'm Michael Kennedy.
And I am Brian Okken.
It's just us this weekend, or this today.
It's just us.
Yeah.
Yeah, it's, I don't know.
Dean out of the audience asks, is this a daily podcast show now?
I'm a little bit torn about it.
I feel like we almost could do a daily show.
But then I think what it might take to do a daily show,
knowing how much work a weekly show is.
No, it's not a daily podcast.
No.
It might be fun to do sometime.
Just do like a full week or something.
Right.
Exactly.
Just a super, there's so much news.
We're doing it every day for the week.
Cool.
But just like the same topics, like six days in a row.
Just do them over.
Yeah.
Exactly.
All right.
Am I up first this week?
You are.
Yes.
Right on.
Well, let me tell you about something special.
Specialist.
Okay.
Just last week, I believe it was, I interviewed Alex Waygood, who did the write-up for the Python
Language Summit.
And as part of the topics we were discovering, you know, the Python Language Summit and Python
this year is focusing a lot on performance and what's called the Shannon Plan.
So this is Mark Shannon's plan to make Python five times faster over five releases.
It's got a ton of support at Microsoft.
Peter Van Rossum is there working on it, but they've hired like five or six other people who
are full-time working on making Python faster now.
So awesome.
Awesome.
Thank you for that.
However, one of the things that made Python 3.11 fast is some of the early work they did.
And it comes down to PEP 659, a specializing adaptive interpreter.
So let me tell you about this feature, this performance improvement first, and then we'll
see what specialist is about because it's about understanding and visualizing this behavior.
Okay.
So one of the things that is a problem with Python, because it's dynamic and its types can change
and what can be passed could vary.
I mean, you could have type hints, but you can violate the type hints all day long and
it's fine.
So what the interpreter has to do is say, well, we're going to do all of our operations super
general.
So if I have a function and it's called add and it takes X and Y and it returns X plus Y
seems easy, but is that string addition?
Is that numerical addition?
Is that some custom operator overloading with a dunder add or whatever it is in some type?
If it fails in one way, you kind of got to reverse it.
Like there's all this unknown, right?
Yeah.
What if you knew, what if you knew those were integers and not classes or not strings?
You could run different code.
You wouldn't have to first figure out what they are.
Are they compatible?
Do you do the add in low level CPython internals?
Or do you go to like some Python class and do it?
Right.
You could be much more focused.
Yeah.
Additionally, if it was adding for a list, you could say, well, if I know their list,
what we just do is go list dot extend and we give it the other list, right?
We don't hunt around and figure out all this other stuff.
So that's the general idea of the specializing interpreter is it goes through and it says, look,
we don't know for sure what could be passed here.
But if it looks like over and over we're running the same code and it's always the same types,
is there a way we could specialize those types, right?
Is there a way that we could put specific code for adding numbers or specific code for combining lists?
And this is called adaptive and speculative specialization.
Okay.
And my favorite part of it, when it's performed, it's called the quickening.
Quickening is the process of replacing slow instructions with faster variants.
So kind of like I said, it has some advantages over immutable byte code.
It can be changed at runtime.
Like you see, we're always adding integers.
It can use super instructions that span lines or take multiple operands.
And it does not need to handle tracing as it can fall back to the original byte code for that.
Okay.
So there's a whole bunch of stuff going on here.
Like the example they give is you might want to specialize load adder.
So load adder is a way to say, give me the value that this thing contains.
But what is the thing?
One of the things you might do is you might realize it's an instance class.
And then you would call load adder instance value.
Okay.
You might realize it's a module and you might call load adder module or slot or so on, right?
But if you knew, you don't have to go through first the abstract step
and then figure out which of these it is.
You just do the thing that it is.
Okay.
So that's the idea of this PEP.
This is one of the things that's making Python 3.11 faster.
Awesome.
So to the main topic.
Okay.
And I'll just, just as a note, I'm saying, okay, as if I understand what you just said,
but most of it just went.
It's all right.
I think, well, let's, let's look at pictures.
Okay.
All right.
So this thing by Brant Boucher is called Specialist.
And it's about visualizing this specializing adaptive interpreter.
Okay.
Good.
Okay.
So it says Specialist uses fine-grained location information to create visual representations
of exactly where and how CPython 3.11's new specializing adaptive interpreter optimizes
your code.
And it's not just interesting.
It has actionable information.
So for example, see here, and if you've got to pull up this, the website, if you're just
listening, if you see in that website, you'll see some color.
You'll see green, less green, yellow, orange, and all the way to red.
So there's two aspects.
There's sort of a darkness as well as a color.
So the most, like where Python could take advantage of this feature, you see green
where it can't, you see red.
And imagine a spectrum.
It goes like green, yellow, orange, red.
So it's, it's not on or off.
It's how much could it specialize?
Okay.
So what you see here, for example, is it's able to take some numbers and an integer and
a string, and then use the fact that it knows what those are to make certain things like a
pending and output and doing some character operations on it.
Yeah.
Right.
It was able to replace that with a different runtime behavior because of this quickening.
All right.
So let's skip down here.
I gave you a bit of the background.
So it says, let's look at this example.
We have F to C, which converts Fahrenheit to Celsius.
And what it does is, okay, we're going to take an F and it has type hints that say float,
float.
Okay.
So, but those don't matter.
So it says, we're going to take an F and subtract 32 from it.
And then we're going to do simple math.
We're going to take that result, that range, that, that, size of temperature there based
on zero and then multiply it by five and divide it by nine.
And we all learned this in chemistry class or somewhere, or we talked about diverting different,
um, measurement.
Yeah, of course.
Yeah.
Right.
So these are straightforward, but there's actually problems in here that make it slower and prohibit
Python from quickening it as much as it can be quickened.
Okay.
So if we take this code, it just runs, F to C and C to F, and it gives it some test
values and says, just do it and tell us what happened.
We can run specialists on it.
And it says, okay, this X here is, the green areas indicate regions of code that were
successfully specialized where red areas are unsuccessful.
Like it tried and it failed.
So it says one of the problems is start out the X equals F minus 32.
It says, well, we can quicken operations on numerical types that are the same, but for now
there's not a float int and float variant of this.
It's got to be float float.
Oh, right.
So it says, right.
You, you could have gotten a faster operation there, but because the types didn't match,
you won't.
But then what it did get out is an X and that was great.
an X, which is a float and it's going to do some stuff and it could sort of make it
better, but it said, look, here's some multiplication again by an integer and a float.
So that's not quickened.
And this division division is apparently never quickened.
So what can we do?
Well, with that information to say, well, what's the problem with subtracting 32?
Well, it wasn't a float.
What if I said 32.0?
Oh, yes.
All right.
That gets replaced by faster code.
Oh, nice.
Right.
Yeah.
So that's pretty nice.
And if you want to return, it was adding like X plus 32 for the other direction.
And now it's 32.0.
That's faster.
Okay.
Well, what else?
What if we, now you can see when we did that part of the, conversion X times five divided
by nine, if we put a 5.0, that gets faster still, but the divide is never quickened.
Okay.
Well, what if we put the divide in parentheses?
It doesn't really matter if it's X times five divided by nine or X times five divided by
nine, right?
It's, these are mathematically equivalent, but they're not equivalent to Python because
that, that operation results in, it leverages constant folding, right?
Five divided by nine is pre-computed in Python to be a float.
Okay.
Right.
At parse time, right?
That's just how it works with constants.
If it says it can do math with constants ahead of time, it does it.
So that becomes a float.
And then float times float is now quickened.
Right.
Isn't this cool the way you can apply this and actually make your code faster, not just
go, Oh, it's interesting.
It must be quick in it there, but it's actionable.
It is really pretty cool.
And I'd really like to see this incorporated into an editor or something to say you, your
code will be faster if you just add a point zero here or something like that.
And it's going to become a float anyway.
It doesn't matter.
It just, why would you write 32.0 when you just meant 32 seems more precise to say 32.
Cause I'm used to doing that to thinking if it's okay.
Well, me personally, I, if I know it's going to be a float math, I usually do point zero,
but maybe, maybe that's not a normal thing.
You're such a C programmer.
All right.
Well, I think this is really cool.
This is a specialist.
And, you know, I don't know if I have any code that does math at that finer, greater level
that I really care, but maybe, you know, if you're in charge of a library where you've
got a tight loop or you do a lot of math science stuff where it matters, this can be really
useful.
And what's cool is it's not like, and switch to rust or switch to C or switch to Cython
and it'll take effect.
Like, no, this, this is like straight Python code.
This is just, how do I take most advantage of what is already happening for performance
boosts in 3.11 that we haven't had before?
I think, and I think it's going to be just one more workflow step.
So you've got, you profile your code, your whole thing is a little bit slower than you'd
like it to be.
You throw a profiler on it.
You see the bottleneck areas that you could improve.
And you think, should I like rewrite some of this in rust or C or, you know, what should
I do?
Well, first off, let's try doing this, like throw, throw, throw this at it and, and, and
have the optimizer from 3.11 help you out.
And, and yeah, so I think this, I can definitely see that this is going to be part of people's
workflow, but yeah.
I agree that you want to profile it.
Yes, exactly.
Cause while it's fun to do this.
Yeah.
Only focus where it's going to matter.
Don't, don't optimize a bunch of stuff that doesn't.
So Brian out in the audience says, different Brian, is there a plan to do lossless type
conversion or maybe flake eight can make this kind of suggestion?
Yeah, exactly.
That'd be fair.
Yeah.
I'm not really sure if you don't want to write the code where you get different outputs probably.
Right.
But everything that was happening here, you were, you ended up with the same outcome anyway.
It's just like, well, do I do the division first or the multiplication?
Or do I start with an ant that results after some addition subtraction with a float?
Or is I just make them all floats?
Right.
I feel like it's, in most cases, it shouldn't be changing the outcome.
So.
Okay.
Yeah.
Cool.
Anyway, that's, that's what I got for the first one.
How about you?
Well, we're kind of sticking with a 3.11 theme so far.
Well, we can use Toml now, but in 3.11, we are going to have a Toml that'd be part of
part of Python 3.11 with PEP 6.80.
And we covered that in episode 273.
But I, I, one of the things we didn't mention was that, was the Toml lib is, is,
and I think we did mention it, it's based on Tomly, but Tomly you can use right now.
So a lot of projects are switching to use Tomly as a, as their Toml, Toml parser, to, to
read, read, like pyproject.toml or, or read their own, config file.
And, and so I just wanted to highlight it.
It's a Tomly is the, a little Toml parser.
it's a cute little thing on the project.
It's cute.
But, but I was reminded of it because, real, the real Python people, put
out actually looks like gear.
Sorry, I'm not going to try to pronounce that name.
real Python, wrote an article called, Python and Toml new, new best friends.
And I really love it's a, it's a very comprehensive article.
but I really love at least the first three parts of it, using Toml as a config format,
uh, getting to know key value pairs and, load Toml with Python, because this is kind
of what you're going to do with it.
You're going to write config files for something.
And I just kind of, it's, this is a great introduction of Toml for Python.
And that's kind of what we care about.
Right.
So, it goes through like just getting, getting used to what Toml looks like, what a
config file looks like talking about how all the keys, even if you, it's like key value
stuff.
And even if you, you put a number there or something, it's going to be a string.
All the keys get converted to strings, even if they don't look like them.
and they are, they're, they're UTF eight.
So you can use, unit code in there as well, which is kind of neat.
put your emojis in there.
Yeah.
Well, can you, is, is our emojis UTF eight?
I think mostly, many of them are interesting.
That'd be fun to put, put emojis in your, I don't know.
What motor we were in.
Are we running in cow mode or lizard mode?
I'll do lizard.
Yeah.
Okay.
Well, if you're running in lizard mode.
Okay.
I got to try that to see.
I should have done that before.
Oh my gosh.
I think almost it's both horrible and amazing to imagine writing like config files to like
put it and put it in lizard mode.
Do it.
Yeah.
one of the things that I didn't before reading this article, one of the things I
didn't know you could do in Toml, because I just sort of cursory, I use it with pipe project
at Toml and that's about it, but you can do, so, talks about, normal, how
to read stuff.
But one of the things is, Oh, what was I going to talk about?
Arrays, and you can do arrays of things which are neat and tables and arrays of tables,
uh, which is like, so you have arrays of tables or these bracket bracket things.
And, and then you can do dot stuff.
So if you have like, was it user and user dot player, these will show up as,
as like, you know, sub dictionary key things.
and so one of the things that I, and I played with it this morning and, it really,
I should have had a something to show, but the thing I like to do is to just read it.
just like, this article talks about reading it, just read the Toml file into Python
and print it.
and then you can, and it'll print out as a dictionary and then you can create whatever
format you want for your Toml file.
And then you can just see what it's going to look like.
And then you know how to access it.
That's one of the best ways to do that.
That's awesome.
Yeah.
What an interesting format.
That's pretty, that's pretty in depth.
And, a blast from last week past Ashley.
Hey, Ashley says UTF eight can encode any Unicode character emoji, your heart emoji.
Heart out of it.
Very.
Oh yeah.
You could do like, you know, is it in heart mode?
Heart equals true.
Heart equals false.
oh, for optimize optimizer, you could do a flame emoji equals true.
exactly.
So I love it.
Yeah.
I think, look, we have not leveraged the configuration as emoji sufficiently.
Oh yeah.
I think, I think a pie test should rewrite all of its config figs as emoji items.
Just do a PR.
I'm sure we'll take it.
Yeah.
It'd be good.
All right.
Yeah.
All right.
Let me tell you about our sponsor for this week before we move on.
So this week is brought to you by Microsoft Founders Hub.
In fact, they are supporting a whole bunch of upcoming episodes.
So thank you a whole bunch to Microsoft for startups here.
Starting business is hard by some estimates.
Over 90% of startups go out of business within their first year.
With that in mind, Microsoft for startups set out to understand what startups need to be
successful and to create a digital platform to help overcome those challenges.
Microsoft for startups Founders Hub.
Their hub provides all founders at any stage with a bunch of free resources to help solve
challenges.
And you get technology benefits, but also really importantly, access to experts, guidance and
skilled resources, mentorship and networking connections and a bunch more.
So unlike a bunch of other similar projects in the industry, Microsoft for startup founders
hub does not require startups to be investor backed or third party validated to participate.
It's free to apply.
And if you apply, get in.
Then it's you're in.
It's open to all.
So what do you get if you join or apply and then get accepted?
So you can speed up your development with access to GitHub, Microsoft cloud, the ability to unlock
credits over time, as in it gets over a hundred thousand dollars worth of credits over time over
the first year.
If you meet a bunch of milestones, which is fantastic.
Help your startup innovate.
Founders Hub is partnering with companies like OpenAI, the global leader in AI research and
development to provide benefits and discounts too.
Yeah.
Through Microsoft startup founders hub, becoming a founder is no longer about who you know.
You'll have access to the mentorship network, giving you all access to a pool of hundreds of mentors across a range of disciplines.
Areas like idea, validation, fundraising, management, coaching, sales marketing, as well as specific technical technical stress points.
To me, that's actually the biggest value is the networking and mentor side.
So you'll be able to book a one-on-one meeting with these mentors, many of whom are founders themselves.
Make your idea a reality today with the critical support you'll get from Microsoft or startups founders hub.
Join the program at pythonbytes.fm/founders hub.
Link will be in your player's show notes.
Nice.
Yeah.
Cool.
Indeed.
All right.
I guess I'm up next with this order we got.
And oh my goodness, Samuel Colvin, take a bow.
Because he put out a plan for what's happening with Pydantic version two.
But the reason I say take a bow is this is one detailed plan that is really, really thought through, thought out, backed up with a bunch of GitHub discussions and so on.
Wow.
So the idea is Pydantic started out as an interesting idea.
And surprise, surprise, a bunch of people glommed onto it probably more than it was originally envisioned to be so.
So, for example, SQL model from Sebastian Ramirez is like, Pydantic models are now our ORM to the database with all the interesting stuff that ORMs have.
And Roman Wright said, guess what?
We could do that for MongoDB as well.
Same with the Pydastic thing we recently spoke about.
And then Sebastian Ramirez is like, also, like, hey, FastAPI, this can be both our data exchange as well as our documentation.
I was like, oh my goodness, what's going on here?
So there's a bunch of stuff on the insides that could be better, let's say, or maybe time to rethink this.
So in this plan, it talks about what they'll add, what they'll remove, what will change, some of the ideas for how long it will take, and so on.
Yeah.
Here's a pretty significant thing.
I'm currently taking a kind of sabbatical after leaving my last job to work on this, which goes until October.
So that's a big commitment to I'm going to help make Pydantic better.
Oh, wow.
It sounds familiar.
It sounds a bit like Rich and Textual and those types of things as well.
But this is a big, big commitment from Samuel, and he's really doing a ton of work.
It says, people seem to care about my project.
It's downloaded 26 million times a month.
Wow.
Which is insane.
Yeah, it's awesome.
That's kind of incredible.
It is.
And so it says, here's the basic roadmap.
Implement a few features in what's now called the Pydantic core.
We just had Ashley, who, as we saw, is out in the audience.
Hey, Ashley.
Who give a bit of a shout out to this feature.
And also, I do want to also credit a couple other people's because Douglas Nichols and John
Thagan also let me know that this was big news coming.
So thank you all for that.
The Pydantic core is being rewritten in Rust, which doesn't mean you have to know or do anything.
It just means you have to pip install something.
You get a binary compiled thing that runs a lot faster.
Okay, so more on that in a second.
First, they're working to get 110 out and basically merge every open PR that makes sense
and close every PR that doesn't make sense.
And then profusely apologize to why your PR that you've spent a long time making was closed
without merging.
Some other bookkeeping things.
Start tearing the Pydantic code apart and see how many existing tests can still be made
to pass and then release eventually Pydantic.
The goal is to have this done by October, probably by the end of the year for sure.
A couple of things worth paying attention to.
There are a bunch of breaking changes in here.
A lot of things are being cleaned up, reorganized, renamed, some removed.
Like from ORM, people might be using that with SQLAlchemy.
That's being removed, for example, and so on.
So there's, if you depend heavily on Pydantic, especially if you build a project like Beanie
that depends heavily on Pydantic, you're going to need to look at this because some of the
stuff won't work anymore.
But let's highlight a couple of things here.
Performance.
This one is really important because this is the data exchange level for FastAPI.
This is the database transformation level.
When I do a query from the database, what comes back comes back in some raw form and then is
turned into a Pydantic model.
And those are computationally expensive things that happen often.
And in general, Pydantic version 2 is about 17 times 1,700% faster than V1 when validating
models in a standard scenario.
It says between 4 to 50 times faster than Pydantic 1.
Hmm.
Wow.
That's cool, right?
Yeah.
That alone should make your ears perk up and go, excuse me, my ORM just got 17 times faster.
Wait a minute.
I'm liking this.
I know that this is not the only thing that happens at ORM level, but the ones that, the
ones I called out that depend heavily on it, like that's in the transformation path.
So this is important.
Yeah.
This is actually, I'm super impressed.
I have not, I normally don't even see this sort of advanced planning in commercial projects.
Yes.
Oh yeah.
You could do a whole business startup that doesn't have the amount of thought that went
into like what's happening in the next version of Pydantic.
It's ridiculous.
Yeah.
It's incredible.
I mean, I was serious when I said take a bow.
It really lays out, opens a discussion about certain things and so on.
So like another one is strict mode.
I think I even saw a comment in the chat about it.
So one of the things I actually like about Pydantic, but under certain circumstances,
I can see why you would not want it is if you have something you say is an integer field
and then you pass one, two, three, the number rate.
But if you also pass quote one, two, three, Pydantic will magically parse that for you.
Like this happens all the time on the internet.
Like a query string has a number, but query strings are always strings.
There's no way to have anything but strings.
Yeah.
So you got to convert them.
Right.
So this automatically does that.
But if you don't want that to happen, you say, you gave me a string.
It's invalid.
You can turn on strict mode, which is off by default, I believe.
There's also a bunch of plain.
Go ahead.
So strict mode does the conversion or strict mode?
Strict mode won't do the conversion.
It says, you said it's an int.
You gave me a string.
Nope.
Rather than, could it be an integer?
Let's try that first.
You know what I mean?
Yeah.
Maybe one of the things you do is, in the ORM level, one of those things, you might put it in strict mode so it doesn't do as much work trying to convert stuff.
I don't know if that actually would matter.
But formalizes a bunch of conversions.
It has built-in JSON support and different things.
Another big thing is this Pydantic core will be able to be used outside of Pydantic classes now.
So you can do a significant performance to improve stuff like adding validation to data classes or validating arguments and query strings or a type dick or a function argument or whatever.
Yeah.
Let's see.
Next up.
And let's see.
This one.
Strict mode.
We talked about strict mode.
Another one is required versus nullable.
There's a little bit of ambiguity of, you know, if you said something's a string, that means it's required and it can't be none.
If you say it's a string type none or it's an optional string or something like that, then basically the behaviors were a little bit different.
So originally, I think this is when typing was pretty new.
It said Pydantic previously had a confused idea of required versus nullable.
This mostly resulted from Sam's misgivings about marking a field as optional but requiring a value to be provided to it but allowing it to be set to none or something along those lines.
Anyway, there's minor changes around that.
Let's see.
Final one that I want to cover is namespace stuff.
And this is like a whole bunch of things are now getting renamed.
So for example, if you override, if you implemented or overrode validate JSON, it's now model underscore validate JSON.
If you had is instance, it's now model is instance.
Okay.
There's a bunch of these changes all over the place.
Yeah.
That look like they're going to cause breaking changes.
They're easy to fix.
Just change the name.
But, you know, it's not nothing.
Also, parse file.
I still love his hander here.
Pars file.
This was a mistake.
It should have never been in Pydantic.
We're removing it.
Okay.
Pars raw.
Partially replaced by this other thing.
Anything else it did was a mistake.
From ORM, this has been moved somewhere else.
Schema and so on.
So you just, like, there's a lot of stuff that people are using here.
So just have a look.
Try it out.
Don't just go, oh, then version 2 is out.
Is this going to work?
Like, this is going to have some significant changes.
And another reason why it's really awesome that he goes through so much detail is because
there's going to be stuff that breaks.
So it's a breaking interface change.
And so, yeah, it's cool that it's this detailed.
And a couple things to notice.
Let's see.
Somebody else in the chat mentioned.
Richard mentioned.
And he has emojis in the headers.
Yeah, there's emojis in the headers.
And I got to say, like, the navigation in the table of contents, very cool.
It goes to, like, light gray for areas you've already seen.
And then.
Oh, that's interesting.
It's a cool thing.
Yeah, it's quite cool.
I think it went on and on.
But two real quick things.
One, there'll be no pure Python implementation of the core.
It's always Rust.
But they list out the platforms where it'll be compiled to, including WebAssembly.
Oh, nice.
They previously had some Cython in what was supposed to be pure Python's Pydantic.
And so now a kind of bonus is the Pydantic model, the Pydantic package, becomes a pure Python package, whereas previously it wasn't.
So they've taken, like, all of that behavior and put it under this core thing that ships as a Rust binary.
And now instead of doing some Cython middle ground, it's pure Python again.
So that's interesting refactoring, I think.
Yeah.
And finally, documentation.
When you get a validation error, it gives you a link to the documentation in the JSON error message.
That's pretty cool.
Yeah.
That's nice.
All right.
Yeah.
Anyway, that's quite a plan, isn't it, Brian?
Yeah.
Quite a plan.
All right.
Well, I'm excited for it.
Okay.
Well, next topic is a little more lighthearted.
It's about fish.
Pike, to be specific.
No, it's about PDFs.
So it's just a cool project I noticed.
Pike PDF.
It's a Python library for reading and writing PDF files.
What's the big deal?
We've had these before.
But this is, it's based on QPDF, which is a C++-based library.
And it's presently continued being maintained.
So it's kind of pretty fast.
Well, actually, I'm assuming it's fast if it's C++ in the background.
Yeah.
But it's also pretty just nice and elegant to do things.
And the documentation has this nice fish, which is good.
I always like cool diagrams, cool logos.
But some of the neat things that you can do with it.
So it's recommending that you not use it if you're just writing PDF files.
That there's other things that you can use.
What was it?
Like Report Lab to write PDFs.
But if you're having to read or modify PDFs, then this is where it shines.
You can do things like copy pages from one PDF to another.
Split and merge PDFs.
Extract content out of PDFs.
Like if you're using it for data stuff.
You get a report in PDF and you're trying to pull the information out.
You can use it for that.
Or images.
You can pull all the images out of a PDF file.
Or this is kind of cool.
You can replace images in a PDF file and generate a new one without changing anything else about the file.
It's kind of neat.
So just kind of a neat, if people are working with reading or modifying PDF files, maybe check this one out.
Yeah, this looks great.
The fact that it's in C++, I'm guessing it's probably standalone.
I remember I've done some PDF things before and it felt like I had to install some OS level thing that it shelled out to.
So this is cool.
Nice on the ReadMe, it has a comparison of some of the different PDF libraries that you could use.
And some of the reasons why you might want this one, like it supports more versions.
I didn't realize that one of these libraries I've heard of before, PDF-RW, doesn't support the newer versions.
So bummer.
And then also password-protected files, it supports that.
Except for, but not public key ones, but just normal passwords.
Straight passwords, yeah.
Yeah.
That's great.
So it's kind of neat.
Also like the measure of actively maintained, the commit activity per year over the year or something like that.
Oh, right.
That's kind of interesting.
Yeah, it's an interesting metric.
It seems good.
I haven't really thought about it lately, but.
Yeah.
Nice.
All right, yeah, this is a great one.
Well, so that's it for our main items.
Yeah, what else you got?
Any extras?
Well, last week, we talked about the critical packages.
Critical packages.
Or at some recent.
Yeah, last week, we talked about critical packages.
Either yesterday or last week, depending on how you consume this material.
Exactly.
Yeah.
So I was surprised to find out that pytestCheck, the plugin I wrote, was one of those.
I'm like, really?
Because it's like the top 1%.
So if anybody's curious, I wanted to just highlight that a little bit.
So pytestCheck is a plugin that allows multiple failures per test.
And one of the best ways, it's a secondary way that one of the contributors added, is you
can use it as a context manager.
You can say, like, with check, and then do an assert.
And then you're going to have multiple of those within a.
I like the one-liner even.
That's pretty nice.
Yeah.
And this is totally, like, black will totally reformat this if you ran it through black.
But it's nice.
You'd have to block it out.
Anyway, I was like, how could it be?
Well, I'm curious what on the list it was.
So there's a place called, what, HugoVK.
Has a top PyPI packages list.
And it's updated.
I think it's just updated once a month or something.
But you can do the top 5.
You can do the top 5,000.
Yeah, it's the top 5,000 or 1,000 or 100.
And so I was curious about where on the list I was.
I'm number 1,677.
So kind of far down the list.
But hey, we're just talking.
It's still in the top third of the top 1%.
That's pretty awesome.
The pytest is number 72.
That was pretty neat.
And Pydantic, which we covered, was, I just checked, 117.
But there are 57 pytest plugins that show up in the top 3,500.
So that's pretty neat.
Wow.
Pretty neat.
That is pretty neat.
That's all I got for extras.
All right.
Well, I have zero extras.
So mine are finished as well.
How about a joke?
Yeah.
Great.
All right.
I told you we're coming back to it.
So this one comes from Netta.
Netta Code Girl at Netta.mk.
And let me just pull this one up here.
Right.
So this one is, there's this colleague here.
Can I make this?
There we go.
Make it a little bigger.
There's the two women who are developers, Netta and her unnamed friend who always has gotten
in trouble with the elevator last time, basically.
And there's this sort of weird manager looking guy that comes in and says, I tested your
chat bot, but some of its replies are really messed up.
Well, that's what testing is all about.
I'll go through the logs later, says one of the girls.
No, no, no.
No, no.
No need.
Right.
Check out the faces.
She's like, excuse me.
I'm not even sure I want to open the logs now.
Yeah.
Don't look at the logs.
That's what testing's for.
I'll go through the logs later.
Well, yeah, she's got some good ones in her list there.
So love it.
Yeah.
I like the art too.
Nice art.
I do too.
It is.
So also nice was our podcast.
Thanks for being here.
Thank you.
Yeah.
You bet.
See you next week.