What would a modern Python project look like? Maybe it would use poetry rather than pip directly for
its package management. Perhaps its test automation would be controlled by Nox.
You might automate its release notes with release drafter. The list goes on and on,
and that list is the topic of this episode. Join me and Claudio Jolovitz as we discuss
his hypermodern Python project and template. This is Talk Python to Me, episode 362,
recorded April 6th, 2022.
Welcome to Talk Python to Me, a weekly podcast on Python. This is your host, Michael Kennedy.
Follow me on Twitter where I'm @mkennedy and keep up with the show and listen to past episodes
at talkpython.fm and follow the show on Twitter via at talkpython.
We've started streaming most of our episodes live on YouTube. Subscribe to our YouTube channel over
at talkpython.fm/youtube to get notified about upcoming shows and be part of that episode.
This episode is sponsored by Microsoft for Startups Founders Hub. Check them out at
talkpython.fm/founders hub to get early support for your startup. And it's brought to you by
Compiler from Red Hat. Listen to an episode of their podcast as they demystify the tech industry.
over at talkpython.fm/compiler. Transcripts for this and all of our episodes are brought to
you by Assembly AI. Do you need a great automatic speech to text API? Get human level accuracy in
just a few lines of code. Visit talkpython.fm/assemblyai.
Claudio, welcome to Talk Python to Me.
So happy to be here.
I'm so happy to have you here. It's great to be talking to you. And this is one of those episodes
that's going to be so fun because what it's going to turn out to be, I'm pretty sure, is diving into
a ton of little tools. And I can tell you, just doing a little bit of research and putting together
some show notes for this, like, oh, there's that thing. And oh, look, this too. Oh, I didn't know
about this. So you've assembled this conglomeration of tools and techniques that you're putting under the
hyper modern banner. And I think it's going to be a lot of fun to talk about. So yeah, we're going to have a
good time. Looking forward. Indeed, same. Now, before we get into that, let's talk about your
story. How'd you get into programming and overhear to Python? I think one day my dad, that must have
been in the 80s, came back with and said, I bought a computer and I was really excited. I imagined,
you know, there's going to be a room filled with all these machines and ran down the corridor and
turned out to be like some kind of keyboard as it seemed to me. So there was a Commodore 64.
And initially we just, you know, played all those great 8-bit games. And eventually I started
programming a little bit in basic. And I think that's kind of when I really found out how much
fun this is. And, you know, then I think I was interested in a lot of other non-computer things
for a long while. I went to uni, I studied law.
As most programmers do, of course.
And, but somehow this, the interest in formal systems always stayed with me and law, especially
continental law, German law is very much like a little bit like a calculus tracing back to ancient
Rome. And I got interested in logic. And there's a small research community working on applying AI and
logics to legal theory. And that was really my gateway drug to, to get back into programming
really logics. I think I programmed this like a little flashcard system to help me prepare for the,
for the law exams. And yeah, eventually I decided I want to get really deep into this. And I started
studying computer science and pretty much never, never went back to law after that. So I have a law
degree, but yeah, working as a software engineer.
It's interesting. I hadn't really thought about it with law. I have a friend who's a lawyer and
in software. So I know it's, it's, it happens for sure, but thinking about the way you have to
mentally sort of solve the problems and the constraints of like legal contracts and laws
and stuff and how they apply. That's actually kind of a similar skill to thinking through solving a
computer programming problem with APIs and what the computer can do and stuff. Right.
And it's such a human way of thinking. So it's, it's really interesting from an AI point of view,
because it's not the kind of really clear logical deductions that you have, but there's a lot of
everyday knowledge that you need to have and the feasible rules. Yeah.
So it's quite exciting.
Yeah. Very neat. Now, what kind of a code and what kind of stuff are you doing these days?
I've been working mostly on a, on cybersecurity. So I'm working for a company almost 14 years,
that's doing cybersecurity as a service. So we're working mostly on C++ services or high performance,
data intensive services. We're using Python mostly for, to automate the build system, testing and releases,
processes, but also for prototyping. So algorithms, that's like really handy before you implement it in
a high performance way.
Yeah. I think Python is used frequently for that. Like let's prototype this. And then if
once we completely decide it works right, then we're going to write it in C++ or Rust. That's
not the most common use of Python, but it certainly is one that people have said, oh,
this is really good because you can prototype so quickly. Sometimes people just decide,
and also this will just work fine for what we're doing. It's actually, it's plenty fast. Or they
decide, you know, maybe not, right? Maybe they need C++, but it's still a cool use case.
Yeah.
Now let's kick off our conversation with some thoughts from a former guest, Mahmoud Hashemi. He had a
really interesting way of sort of presenting Python to people who are not deep in the Python language and
said, basically, it's actually, when people say Python is great for prototyping, for example,
well, they might be talking about one of three things or some combination of there. It could be
when people say, oh, Python is good for this, or Python is like that. They might be talking about the
language, or they might be talking about the standard library, or more and more these days,
they're talking about the third party ecosystem with, I don't even know how many libraries, but I
gotta look this up because it changes so fast. Right now at the time of recording, 368,000 libraries. So when
people mention Python, they often mean one or more of those different things. And we're going to talk about
hyper modern Python. So I think we should frame it a little bit in the sense of like, well, you know, what is
modern about the language? Or what is kind of modern about the standard library? And obviously, the ecosystem
where a lot of it's, it's happening. So from your point of view, what is modern Python?
Before we get to hyper modern?
Yeah, yeah, we definitely, we can talk about the language, the standard library, the ecosystem.
I'd also add the community. I think that's something that really defines Python.
Yeah, I agree.
Yeah. And all that tooling that evolved in the ecosystem. So about the language, what really,
because my, you know, my story is, I think I got into Python. Python was it like Python 2.3?
So you've been through the journey, you've been through the great split and the rejoining.
I pretty much missed a lot of the pain of the Python 2.3 transition. I've been busy with C++ and then
came back to Python. And for me, it was just the enthusiasm of rediscovering all the great,
like how expressive Python had become. One of the things that really get me excited about modern Python
is type annotations. I just find them so helpful to structure programs, to make APIs clear,
to help me think about my code and to keep it maintainable and readable. So I use them
pretty much always. And I always run my Pi in strict mode. Even I'd even use it in small scripts.
And it's, of course, very helpful in large systems. Absolutely. I don't know that I've,
in fact, I'm, I'm pretty sure I've never gone end to end and taken a large system and completely made it
100% my Pi checked, you know? Yeah. For me, I'm with you. I absolutely love
the types. And I use them a lot to sort of drive the, the tooling intelligence. For example, like if
you've got a data access layer, you could, you could talk about what is exchanged at the boundary there
so that your editors are all of a sudden super smart about autocomplete. And, you know, I was just doing
a massive overhaul to the course, Python courses website and change, change, like it was 110 commits
in this PR. It was like ridiculous. But before I checked them all in, I went through and I said, okay,
look for all the type warnings, look for anything that might've become like out of sync along the way.
And I, I caught like one or two things before I accepted the, or merged the PR back in. So it's
just, yeah, I absolutely think that's one of the most important additions.
And they also, it's so nice how you can leverage them at runtime as well. It's not only that they
allow you to check your code in a, in, in a way that doesn't require hitting every, every code path,
but you can build a data validation on top of it. And so many more.
Yeah, absolutely. I mean, look at libraries like Pydantic and FastAPI that are making interesting
runtime use out of it.
Absolutely.
And speaking of modern Python, like there's the, there was that proposed change to make
typing more efficient where it wouldn't actually import the things until really needed it. Or I
can't remember the exact PEP, but it was a way to sort of delay type information imports until you're
doing something like my PY and the Pydantic people and fast, you know, Sebastian and FastAPI. I was like,
wait, wait, wait, wait, wait, wait, we need this. Like, this is how our thing works. If you take away the
actual meaning other than for verification.
Yeah. I think the stringification of the, of the types that makes it really hard for these use cases. And, and
there's this other approach where they, where they basically lazily evaluate the, the types, I think, to avoid this
string problem. Yeah. I don't know if they've, I think it's still an open question of how to, how to proceed this. They, they, they,
we should have gotten the string types already and then decided to take some more time to,
to find a good solution for everybody. Yeah. I think that was, was sort of delayed. I can't
remember the total outcome, but I think it was like, we needed to think about this more and make sure all
the use cases are covered. Right. Yeah. Cool. Okay. Well, that's the language. One thing that we could
talk about real quick, that's pretty timely is this PEP. I just had Brett Cannon and Christian on
to talk about PEP 594, removing dead batteries from the standard library, which, you know,
it's pretty interesting. The idea is a lot of these libraries had been added. These core modules have
been added to the standard library in like 1992. And they've, they might not still be relevant.
For example, CGI is not the most common way to do web apps anymore. We've got micro whiskey and
the unicorn and all those things. Right. So does that still make sense to maintain them? Yeah.
I think that the set of libraries to remove them was pretty non-controversial because they're just
very, very old, obsolete, and also basically unmaintained. CPython is, has, I think like 90
core developers and they, they have like 1,600 open PRs right now. So it's very hard to maintain a huge
standard library with so little human resources. Yeah. So I think that was, yeah, pretty a good step.
What I really find interesting is, is the vision behind it. Like where, where, where should the, the standard library go?
How, what are the criteria in the future to, to include libraries? For example, we, I think usually,
recently we got a Tomlip into the, standard library. Right. Yeah. To join JSON and CSV and XML and all
those. Yeah. It's, it's, it started as a, as a PyPI library called Tomli and it's been adopted
quickly by a lot of the tools out there. And now it's part of the, or it will be a part of the standard
library. So this is, for example, this is something that is important to solve a, a bootstrapping
problem in the, the packaging ecosystem, because we have PyProject Toml now, and how is pip going to
pass the PyProject Toml file? For example, how are the other tools going to, to pass it? So it's,
it's very advantageous to have it in the standard lib, but we probably don't want to have passes for
every file format out there. I agree. So in fact, a lot of the ones that were removed
in PEP 594 are actually having to do with file formats. So you've got like AIFC, which is an audio
format. You have audio op, is it like the sun AU format? There's a bunch of, bunch of things like
that. Right. So yeah. I don't want to dive too much into that because we've done a whole show on it,
but I do think it's interesting to think about this as a modern, like the first step in a modernization
of the standard library. Right. Yeah. And then where it really blows open. And I think an
interesting inter, inter exchange sort of cross influence here is, as I already mentioned, the
368,000 external packages that are building on a lot of the new language features that I think are,
are super cool. And how much, you know, looking back, if that world existed already, how much smaller
would the standard library be? Right? Like, would your lib ever have to be in there? Well, we got requests.
I don't know. Maybe not. It could make a lot of sense for it actually to be there, like this
bootstrapping problem you talked about, but maybe it doesn't, right? Like, I think different choices
would be made, but yeah. What are your thoughts on the sort of ecosystem from the PYPI perspective?
Mm-hmm. So if we look at the, at the 30, the third party libraries, I think for me, modern Python is a
lot about expressive, expressive types, like Adhors for me is like the best example really to how to write
well-structured code using Adhors just got a new API, which is really, really nice. And I can definitely
recommend having a look at it. So it's become very easy to define immutable value objects, essentially,
that will allow you to basically structure your domain logic in a really expressive way.
Yeah, no, I was going to say that it did get a new API recently. I forgot that it,
it kind of inspired data classes and then it sort of turned the tables on it a bit, right? And sort of
rethought about how some of its stuff was offered as well, right?
I love that we have data classes in the standard library because it's like a mini Adhors that you
always have at your disposal, even when you don't want to take on third-party dependencies,
but it's definitely always worth looking at Adhors. It's very fast and has a lot of features and it
doesn't have this problem that you can only really update it once per year.
Yeah. And that's a super interesting point. You know, they considered putting requests in the standard
library for a while and requests is under the, I can't remember the exact organization,
but it's under an official PSF. Maybe it is, I think it is just the PSF organization now on GitHub,
right? It's sort of officially Python in a sense, but they decided not to put it into the standard
library, not because it didn't fit or it wasn't good enough, but because it would actually slow down
the development of requests and constrain it too much. And that's sort of similar here as well,
right? Adders can come out every day with new stuff and data classes yearly, right?
This portion of Talk Python to Me is brought to you by Microsoft for Startups Founders Hub.
Starting a business is hard. By some estimates, over 90% of startups will go out of business in just 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 them overcome those challenges. Microsoft for
Startups Founders Hub was born. Founders Hub provides all founders at any stage with free resources to
solve their startup challenges. The platform provides technology benefits, access to expert guidance and
skilled resources, mentorship and networking connections, and much more. Unlike others in the industry,
Microsoft for Startups Founders Hub doesn't require startups to be investor backed or third-party
validated to participate. Founders Hub is truly open to all. So what do you get if you join them?
You speed up your development with free access to GitHub and Microsoft Cloud computing resources
and the ability to unlock more credits over time. To help your startup innovate, Founders Hub is
partnering with innovative companies like OpenAI, a global leader in AI research and development,
to provide exclusive benefits and discounts. Through Microsoft for Startups Founders Hub,
becoming a founder is no longer about who you know. You'll have access to their mentorship network,
giving you a pool of hundreds of mentors across a range of disciplines and areas like idea validation,
fundraising, management and coaching, sales and marketing, as well as specific technical stress
points. You'll be able to book a one-on-one meeting with the mentors, many of whom are former founders
themselves. Make your idea a reality today with the critical support you'll get from Founders Hub.
To join the program, just visit talkpython.fm/foundershub, all one word, no links in your show notes.
Thank you to Microsoft for supporting the show.
I think that's an interesting aspect of like sort of modern Python as well, right? This ability to just
continually deliver new features and adapt it as needed.
I also really love C-Adder because you mentioned Pydantic before. What I really like about C-Adder, it has kind of a similar,
so you can serialize and deserialize data classes and adders. The difference between Pydantic and C-Adders is that
Pydantic uses inheritance to give you this functionality, whereas with C-Adders, you just have your pure Python classes
without any, they don't need to inherit from anything. You just have, you decouple serialization logic from
your domain logic. And I think that brings a lot of advantages in structuring software.
This is the right one I have on the screen here, this C-A-T-T-R-S.
Right. Yeah.
Yeah.
Yeah. Interesting. So you can do things like put a frozen decorator onto just a regular Python class and
hey, it's frozen. You can create an instance of it and you can say unstructure and you get a dictionary,
you can structure it back until it would type, it parses it back, which is quite neat.
Yeah.
This one's new to me. Like I said, we're going to go through a lot of those,
a lot of those different things. Anything else you want to like give a quick shout out to
into the broader ecosystem before, like we'll dig into your hypermodern ones that you're using as well.
If you haven't seen Rich and HTTPX, those are definitely some to check out. And HTTPX,
basically we talked about requests. HTTPX has a very similar interface, but gives you both async and
sync operations. Yeah.
That's definitely a wonderful project.
I use HTTPX a lot and it's really nice because it's so familiar if you know requests, but if you happen
to find yourself doing cool async stuff, you're not stuck not doing async for one of the most
important parts, which is calling services, right? So you can await doing a get or a post or whatever.
Yeah, it's really nice. I'm not 100% switched to it instead of requests, but it's definitely one of
my go-tos as well. Cool. All right. Well, so that's sort of some thoughts on modern Python and where things
are going. Then you created this series, which is almost like a little mini course on how should you,
from your perspective, how should you structure and build modern Python projects and what tools should you
bring in? Not just should you use HTTPX over requests, but should you use Knox for testing and things like that?
Yes, right.
You might say yes for Knox.
Given that you work on it, right? So you did this article, this six-part series article on it, which I'll definitely link to.
But then also you created a cookie cutter template that'll allow people to jump into it.
I find this to be really helpful. I do this sometimes with my classes. You're like, "Well, here's the thing we built at the end,
but if you just want to create your own version of it, here's a cookie cutter to actually just create it with your settings and your values,
so you don't have to go through rebuilding it from scratch." And cookie cutter has been really influential in that sense, don't you think?
Absolutely. When I wrote the articles, there was example code on GitHub and I saw people forking the repository and I was like, "Oh, no.
They're all going to end up with this example code that displays Wikipedia articles and you can so am I going to keep all the dependencies up to date?
And how do I even do that?" And I was like, "No, I have to find a better way." And cookie cutter was definitely a good way to set up a project template.
And also something that was much easier for me to keep up to date. So there's after two years, definitely quite a bit of drift between the article series, which is from January 2020,
and the cookie cutter as it is today.
Yeah.
It's hard to keep an article or a video or a talk or whatever as a living thing that evolves as we gain more experience and stuff.
But the cookie cutter template, that's like software.
Yeah.
Plastic.
You can make it open source and have
contributors that do some work for you, which is really, I'm extremely grateful for all the contributions I got there.
Yeah, that's great.
I see a bunch of contributors there.
Now, first, let's start with the, just the term, hypermodern Python.
What's the story with the naming here?
I actually brought you, now this is only for those that have a camera in front of them, that this is,
this is hypermodern Python.
So this is not Python.
This is a hypermodern chess game written in 1925.
Oh, interesting.
So this is where the name hypermodern really comes from.
It was meant a little bit tongue in cheek.
And also, I was very conscious that how's Python going to look like two years after I've written this article series.
Yeah.
The ecosystem evolves so quickly.
I decided to stick all these images in the blog that are basically past versions of the future.
It's a thing called retrofuturism.
So they're basically all like images from the 1920s and so on about how people in the future may be going to fly to the opera using planes that look like little birds.
Yeah.
It's sort of a steampunk mechanical bird.
People are cruising along in here.
It's, yeah, it's a, it's a cool picture.
It's a cool idea.
So what is hypermodern?
I think basically it's just whatever I was excited about and didn't know about beforehand.
I had used some tools, like more of the standard tools, like setup tools and pip-tools and talks.
And coming back to Python, I thought, wow, let's just check out all the things that have happened.
And let's see how maybe that might solve a few of the problems that I had.
Nice.
Okay.
So then you put together the article, which is, you know, it's a serious article.
It's not just a couple of paragraphs, right?
It's, it's quite a bit of writing.
Six articles.
Yeah.
Six articles.
And my little, or maybe it was your website.
It's like 11 minutes reading for this part, that kind of, kind of thing.
So it goes into pretty good detail with examples.
And then you captured it in this cookie cutter because you said that to put it into practice,
that's a pretty good way.
Now using cookie cutter is super easy.
You know, I'm sure people have, are familiar with this, but cookie cutter, give it the name.
It asks a bunch of questions, right?
Right.
I think maybe the right way to explore this would be to talk about the features and the
steps of the cutter that it does, right?
There's on the page for the cookie cutter GitHub repo, there's a big section that says features.
And that sort of talks about the different aspects and angles dimensions you decided to
bring in and the tooling there.
So how about we just go through these and sort of dive into them?
I think, I think people are going to discover some cool tools here.
So first of all, if you're going to build something meaningful, you've got to get some libraries off
PyPI.
Like there's very few projects that have no dependencies that are rich these days and not just rich the
package, but you know, feature rich.
Let's talk about the first one here.
Okay.
Take us through it.
Yeah.
So poetry really solved the problem for me because it's basically the one tool approach.
You have one tool that does everything for you.
It will allow you to define metadata for your package, build the package for you so you can
publish it on PyPI.
It can manage environments for you, install all the dependencies of your project and your project
itself.
And it can also manage the dependencies itself.
So it has a resolution mechanism and it has a log file, which is for me, a really important
feature because not only is it good for deploying services in a, in a reproducible and deterministic
way, but it's also for running the checks on your code and making sure that the checks run exactly
the same locally on your machine and CI with on and on the machines of your collaborators.
Yeah.
They're not as familiar with the poetry lock file as I should be, but basically it's like
hitting your versions in a requirements.txt.
Right.
But so often people just write, you know, here's my requirements.
I have requests or HCPX and I have FastAPI and I have SQLAlchemy or SQL model.
And you just type those out and you pip install dash R and you're good to go until you want
to go back to an old version that might have a bug that that's the one in production.
But the bug might be because it has the old library of whatever.
Right.
And you don't know.
Right.
So you want to be able to pin those versions.
And then does the lock file also put the hashes in so they can't be fiddled with?
It does.
Yeah.
So it has the hashes and it gives you all the, basically the, all the indirect dependencies
as well.
So much like pip compile would do from the tools.
Yeah.
So, and that is tremendously useful.
Yeah, it absolutely is.
I'm a big fan of the pip-tools and pip compile.
We'll get to that later when we talk.
Yeah.
When we get to, there's a section, a whole section in the cookie cutter about it.
All right.
So it starts by setting up with poetry, right?
Absolutely.
Yeah.
I called poetry though, the one tool approach, and there has been a lot of work in the packaging
community to introduce standards, packaging standards that make it easier for the tools to
interoperate.
And I think this is actually a very good way to approach things in an ecosystem like
Python's to, to make it possible that you can define your package metadata for one tool,
like flit, and then use poetry to build the package or PDM and so many others.
And there has been a lot of great work that has made the packaging ecosystem more diverse.
Yeah.
There was some separation of the architectures of certain responsibilities, right?
Yes.
Yeah.
So there's perhaps six to one, which defined the metadata.
There was also an attempt to, to standardize log files, which I think would be great, but
that I've unfortunately has been rejected for now.
So I'm hoping that there will be more attempts in the future, but so as great as it is to work
with poetry, I definitely hope for the ecosystem to become even more diverse and more standardized,
to really give us more flexibility and interoperability.
Yeah.
Yeah, that is great.
Definitely seems like a lot of options are coming out around that these days.
And then the next one here is test automation with Knox.
What's your relationship with Knox, by the way?
Are you the maintainer or are you just a contributor or where's this?
I'm co-maintaining Knox.
Okay.
It was written by, by Thea Flowers and it has a large maintainer team.
At the time that I wrote the article series, I was just a fan of Knox and I started contributing
to it and I kind of ended up co-maintaining it.
Whoops, I'm contributing more than anyone else.
Does that make me more involved?
All right.
Yeah.
So tell us what the role of Knox plays in this.
So Knox is a great tool.
It's not just test automation.
It's really, it lets you automate basically all the developer tasks you have.
So this might be tests.
Okay.
It might be the other checks you have like linting, or it could be building your documentation or
building wheels.
If that's complicated in, in any way you can just, the great thing about Knox is that it uses
Python to let you define your, the tasks rather than basically having something like a make file
where you use the shell or in talks, you, you have an any file where you enter your commands,
right?
At least talks three.
I think talks for is also going to add Python configuration.
So Knox, it's really, so it's really inspired by talks.
I think so if you know talks, talks allows you to run tests on multiple versions of Python.
Yeah.
And it's been around for much longer.
It's very mature tool.
Knox is inspired by that.
It also lets you have this matrix of Python versions or even other things.
So you can similar to a pytest, you can parameterize your session functions and pass in,
say like a specific dependency that you want to test against in different versions.
So Knox is, is, is really useful if you want to have a single entry point into your, your project
maintenance, running all the tasks that you have and running them the same locally and on CI.
Yeah, this looks great.
I hadn't really explored this, this Knox file thing where you have these different tasks,
like a task, you know, task basically being a function.
Like, so you say like tests or lint, and you can just put a session decorator on it and just
say session dot install pytest, session dot run pytest or session install flake 8 and run it with
the parameters.
It's really nice and clean and it's, it's way better than a shell script.
I think it keeps you in Python, right?
Right.
Which is probably where you want to be on Python project.
And it runs on all the platforms.
So at some point I use make files to automate these things.
So the non-tox related things, I guess, don't work very well on windows.
So you don't have this problem.
Yeah, that's for sure.
Cool.
And then we kind of saw an example of that there, but linting with pre-commit and flake 8.
Right.
So it's about these two libraries.
I love pre-commit.
I actually, it wasn't in the first draft of the, of the article series.
I got some reviewers who commented on that.
I think Oni Fanchmitt from the pytest project and, and Hinnik Schlawak both mentioned that,
you know, you have to cover pre-commit.
And I was really skeptical.
I had made bad experiences with these kinds of pre-commit hooks that run.
So you make a git commit and then it doesn't work because you had some wrong white space in it.
And I thought my, I want my commits to be really snappy.
I'll, I just use Knox for that.
But after hearing these comments, I thought I'm going to give it a try, you know, like it's a new
tool, maybe it solves these problems much better.
And it really does.
I would really recommend anybody to give a pre-commit a try.
Basically you drop a YAML config in your project that defines the hooks that you want to run.
So this might be a hook that formats your code using black or that, that lints your code using
flake eight or so much more there.
There's an abundance of pre-commit hooks out there.
Oh wow.
Yeah.
There's, there's probably 20 pages in the list of pre-commit hooks that are at the top.
You click on supported hooks and pre-commit.com.
Right.
Pre-commit it's, so it's a git hook manager, but it's not just a git hook manager.
It's also a, a linter framework and a multi-linter multi-language linter framework.
So you can have your hooks written in, you know, Ruby, C++, you name it.
And it's very easy to use them in a Python project or basically any, any language project.
It works using git.
So basically installs the tools from their git repository and you can run them as part of your
git commits or all the other hook points that git offers, but you can also run it just in CI on your
entire code base.
And that's really what I, what I love about it is that it has this fail early philosophy.
So you really get very early feedback, but it also works to, as a gatekeeper for your default
branch and make sure that the, all the commits that go into your main branch are well-formed.
This is interesting.
I did have creator of pre-commit on the show quite a while ago.
I talked about it, but I hadn't, I think maybe some of these are new or I hadn't really appreciated
them before.
Like one that's really cool here is check JSON as a pre-commit and it checks JSON files for
parsable syntax.
So basically as part of your commits, it says, well, here's, I'm guessing here's a changed
JSON file.
Is this, you know, can it just basically be loaded with, you know, JSON.loadf or load, give it a
file.
Right. And another one is, yes, you're supposed to have unit tests, but you might not have unit
tests for everything.
So check AST just means like, can Python parse the files?
That's the word of like the compile, right?
In a sense.
Yeah.
I mean, those are just like the first couple out of this 20 pages.
So I'm, I need to come back to this and check Toml was another sort of similar to the check
JSON, check YAML, check up XML and so on.
Yes.
There's a, this repository called pre-commit hooks, and that has lots of very small hooks that
are tremendously useful.
And then you have larger tools that also offer integration with pre-commit like flake eight,
for example.
This portion of Talk Python to me is brought to you by the compiler podcast from Red Hat.
Just like you, I'm a big fan of podcasts, and I'm happy to share a new one from a highly
respected and open source company compiler and original podcast from Red Hat.
With more and more of us working from home, it's important to keep our human connection
with technology.
With compiler, you'll do just that.
The compiler podcast unravels industry topics, trends, and things you've always wanted to know
about tech through interviews with people who know it best.
I was a guest on Red Hat's previous podcast, Command Line Heroes, and compiler follows along in that
excellent and polished style we came to expect from that show.
I just listened to episode 12 of compiler, how should we handle failure?
I really valued their conversation about making space for developers to fail so that they can learn
and grow without fear of making mistakes or taking down the production website.
It's a conversation we can all relate to, I'm sure.
Listen to an episode of compiler by visiting talkpython.fm/compiler.
The link is in your podcast player's show notes.
You can listen to compiler on Apple Podcasts, Overcast, Spotify, Pocket Cast, or anywhere you listen to your
podcasts.
And yes, of course, you could subscribe by just searching for it in your podcast player,
But do so by following talkpython.fm/compiler so that they know that you came from Talk Python to me.
My thanks to the compiler podcast for keeping this podcast going strong.
On to continuous integration.
I feel like GitHub Actions has really sort of taken hold in the Python space as a way a lot of people are doing stuff there.
Absolutely. It feels like there was some kind of mass exodus from Travis CI to GitHub Actions.
It's so flexible and it goes way beyond just running tests and like the normal, what you'd normally
think of as CI. So you can automate a lot of your developer workflows centered around the collaboration with others.
Nice. The type of stuff I work on doesn't super lend itself well to GitHub Actions.
It does. It probably does somewhat, but it's not something I use that much.
But it seems like if you had a package that had maybe complicated builds or something like that, you could even use it to build your wheels and stuff like that, right?
Sure. Yeah. I mean, my the way I like to use it is to have most of the logic in Knox,
because that means I can always just test it locally and see if everything, you know, debug it easily.
And then I try to keep the GitHub Actions workflows pretty lightweight and just let them invoke Knox.
I usually have a matrix with that contains the Knox sessions.
So this might be the testing or running pre-commit or to lint the code or to build the documentations.
If that that's all valid, then the matrix has the Python versions that I want to test on.
Yeah.
If I'm working on a library, it's important to support not just the latest Python version, but probably Python 3.6 onwards, maybe even the upcoming Python version.
And then obviously platforms. So always, if you're, unless you're only working on one platform, try to have at least Linux and Windows, and then maybe, maybe macOS as well.
Yeah. Yeah. Yeah. This is neat. You know, people talk about, well, we can't really test this on Windows because I don't have a Windows machine or vice versa. Can't test it on Mac or so easy.
Yeah. So this here's your three platforms right here. Right.
I'm not saying it's easy to debug it. If something goes wrong and you're only working on macOS or Linux, you probably at some point want to have a virtual machine with the running windows.
If you don't have a physical Windows machine, but it's also not hard to get one these days, too. But otherwise, you know, it's very easy.
To integrate Windows in your CI.
Yeah, very cool. And then the next one has to do with documentation here.
Right there.
Sphinx, Mist, and Read the Docs. And one of the themes. So yeah, pretty.
When I wrote the articles, it was just Sphinx and Read the Docs. Mist hadn't happened yet. So, well, Mist, maybe let's start with Sphinx, because I guess many people will already be familiar with it. It's a Python documentation generator. It's also used for Python's own.
So for example, the library docs. It's been around for a long time.
It's a very expressive language to write technical documentation.
Sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too, sometimes too expressive. It's not the lightweight language that we know Markdown to be.
Right.
And Markdown has really conquered the world. And when I wrote the documentation chapter, I think I linked to an article by Eric Holcher from Read the Docs, comparing the two formats. And that was before, before Mist happened. And he said, you know, there's use restructured text. It's just so much more expressive. And it lets you have cross references. And all of these things has the powerful directives.
Anyway, now we have Mist. And Mist allows you to do essentially the same thing in Markdown. There's an extension syntax, and you can have directives, you can have cross references. And it's a lot of fun to write documentation in Mist. So this was a recent addition to the project template to support Markdown documentation.
And for those who don't know, I also I did have a show recently with the Mist folks, about Sphinx and Mist and so on. And there I learned that one of the things that's cool is you can inline restructured text. So if you get to a section, you're like, this is just Markdown. I want to do this. Do a little tiny bit of restructured text instead of living in it.
You actually need to do that.
You actually need to do that still for your generated API documentation. So Sphinx has this extension called AutoDoc that will take all the doc strings in your code and transform that into API documentation.
And that still doesn't have a replacement. What you do is you write your doc strings, you know, using restructured text, maybe using Google style doc strings or NumPy style doc strings. And then you use the AutoDoc directive to basically quote it in line in your Markdown documentation.
So that's a little bit of restructured text there. I think I'm working on filling this gap somewhere going on and I'm really looking forward to that feature coming because then everything will be just marked down.
Yeah, that'd be great for sure. I do want to give a quick shout out to Paul Everett's course that he wrote over at Doc Python on Sphinx. And listen, if you're interested, check out this free course that he put together for us over there. So that's worth checking out. Now I'll put a link in the show notes.
Now, if you're building a Python package that goes on PyPI, like not everything people build with Python goes on PyPI or even should be structured in the shape of a package potentially. But a lot of them are right. A lot of libraries are. So you talk about automating uploads to PyPI and test PyPI. Want to talk about the story there?
Yeah. So PyPI, the Python package index there actually has a sibling called test PyPI, which is just a separate instance. It's very useful to upload your wheels and sdiscs to test PyPI before you actually do a release because you can check them and see if everything is the way you expect it to be.
Yeah.
And basically install the package end to end. And in CI, what I like to do is I have the switch where if it's an actual release, I upload to PyPI. But in all the other cases, I just upload to test PyPI. So every commit that goes into the main branch is going to be built and uploaded to test PyPI.
You can't change what you put into PyPI. You can add new versions that replace it, but you can't change a version really.
The best you can do is yank the release. It's still going to be there for those who have pinned the version, but otherwise it'll be invisible to those who just want to get the latest release. But yeah, there's no replacing.
Yeah. So it's a nice reminder and automation to set up to remember there's test PyPI and automatically sort of have your project know and use it.
All right. Here's another one. I want to talk about stuff I was learning. This one is definitely new to me. And this is cool. Automate release notes with release drafter.
What's about release drafter? This is cool.
So release drafter takes the titles of your merged PRs and it creates a draft release. So the release in this sense is the GitHub release. That is something that you can see on the right hand side of the GitHub repo page.
You have this releases link and that basically gets you to either a list of tags or you can describe the changes. So it's essentially release notes on GitHub.
So I think the release drafter is really handy for that. Now actually you can, so GitHub releases have an auto generate button. So some of this functionality you will actually get even without using the release drafter action.
So I think the release drafter action is somewhat more flexible, what it gives you and basically means you're going to have to add a GitHub actions workflow for it and the configuration file.
So you can provide a template for your release notes and some, you know, replacement marker that a placeholder that where all the PR titles go.
I think it's cool. And it even has a draft, like you, you can see the draft release notes as well.
Yeah.
You can see it. And then you have a button to publish the draft release. And if you don't have a tag yet, that's also going to add a git tag to your repository.
So that's a really lightweight approach to the release notes question.
So I see that it has a what's changed, but I also saw in the release drafter had like bug fixes and stuff. Is there a way to teach it? Like these PRs are related to bugs and these are additions and stuff like that?
Yes. You can do that using labels on your PRs. So if it's a bug fix and you have a label, you know, then you can put it under a separate section.
Well, so basically just drive it with GitHub labels. Cool. All right. We got a lot to go through here. So maybe these next two are pretty quick here. Actually, the next three here.
You talked about this sort of article and the cookie cutter drifting quite a bit apart because so many things have changed. One thing that seems to be pretty stable is like since black came out, people are all about just black.
It hasn't seemed to gone out of style at all. I think that's pretty, pretty stable one, right?
It really makes a huge difference for productivity. And I feel if I'm contributing to somebody else's project, it makes things so much easier to know that there's a consistent style.
I don't need to be afraid to destroy somebody's, you know, well-crafted, handcrafted, formatted code. I can just run black. And it's also great, really helps readability. It's basically the style becomes invisible. So I love black. And black now, better status in January. So we now have like...
Official black.
Finally.
Well known as hash 000000. There's no more debate.
So yeah, I'm definitely, definitely a big fan of black.
Indeed. I also give a shout out to Predeer as well. And then sort of related, you have import sorting with iSort.
I've been using reorder Python imports for a long time, which is also a tool by Anthony Sotile, who wrote Precommit.
Yes. I wanted to give Anthony a shout out, but I wasn't 100% sure that I had the name just right in my memory. So I didn't want to like misattribute it. But yeah, he also did Precommit, which I had him on the show for.
Right. So these days, I actually like to use iSort, which is what everybody uses. It's since iSort 5, it's become much nicer to use. It uses the AST more. It has no trouble figuring out what your third party dependencies are.
And it has an option. It has these profiles to make it really easy to be compatible with black style.
And what I like to do is I like to put each import on a single line, which is actually what reorder Python imports does as well. And it greatly reduces the chance of merge conflicts.
Oh, right. Okay. Yeah, of course. Cool. A quick question, stepping back to the release drafter. Michael out in the audience says his biggest hurdle is for doing regular and good release for doing regular and good releases are change logs.
How does release drafter sort of fit into that? Basically, if you structure everything as a PR, it'll capture it?
Yes. So release drafter only drafts the GitHub release for you. If you want to have, say, a page in your Sphinx documentation, you're going to need to pull that out. There's actually a...
I'm sorry. That's his GitHub handle. I'm sure we should put a link later, but there's a tool that will pull the GitHub release and insert it into your Sphinx documentation. So you can do that.
And there's also TownCryer, which really should be mentioned, and Scriv, which was written by Ned Batchelder. Those are tools that allow you to add release notes to your PRs as snippets or fragments. And that scales very well if you have an open source project with many contributors. So yeah, it's still figuring out the best way to maybe integrate all of these in some way.
Sure. You can overdo it for sure. All right. I think a quick, just a quick shout out. Speaking of Ned Batchelder, we have pytest, Coverage.py, and CodeCov all in there is neat. And then CLI interface with Click. That's an interesting one, a popular one as well.
Absolutely. So that's from the Palace project. So the same family of projects like Flask. There's also a nice wrapper for Click called Typer.
Yes.
It's written by the FastAPI author.
Yeah. When I saw that using Click, I'm like, hmm, you're such a fan of types. Maybe Typer is also relevant here.
Actually, I just had another look at Typer and I think I do like it after all. I actually really like it. Initially, I was like, well, it's actually not so. I kind of like how Click gives you these decorators and separates your option help texts from the actual function.
But it is true that Typer really reduces duplication because you don't have to repeat the types of your options. They're just type annotations of your parameters. So that's really neat.
Nice. Continuing with the typing story, we've got two things here. A static type checking with mypy. I suspect a lot of people who are really into typing know about this.
Like the CLI, you run against your code and it'll make sure everything hangs together. If this function is calling that function with that variable, and you said that variable is one of the things that make sure that all is going to fit together.
And if you get that working, then you might be open to having something like mypyC for optimizations and so on, which is also interesting.
But one that maybe people haven't heard about is runtime type checking with Typeguard.
Right. I think it's really one of the most undervalued projects out there in the typing space. Typeguard is so useful.
When I first heard about it, I was like, why would you want to runtime type check your code?
If you have a static type checker, you know why?
Then you need to hit all the code paths.
Static type checking is great because it can just basically deduce the type correctness.
Typeguard is really useful if you're, for example, if you're interfacing with third-party libraries who may or may not have type annotations.
If they do, great.
But you know, how much do you trust them?
Right.
Yeah.
Just because it says it, nothing enforces that where it said it returns an int.
It could return none.
Yeah.
And it should have said optional int, but it didn't.
Your code can absolutely have type correctness as far as mypyC is concerned.
But that might be just because there are some any types or it's just kind of a loosey type because there's no way to be stricter about the actual types.
And Typeguard will check that.
So the way I like to use Typeguard is as a pytest plugin.
So you're basically running your test suite.
And if you have complete code coverage, that should give you a good chance to catch any type.
Oh, interesting.
So you can turn it on while your tests are running and it will runtime check everything.
But then in production, not turn it on?
Exactly.
You basically specify it.
So you install it next to pytest and then you pass an option.
I think it's Typeguard packages and pass the name of your package.
And then Typeguard is going to wrap every function in your code and check the parameter types and the return type.
So that's really useful.
It's also a library.
So if you want to explicitly check in production, you can also use Typeguard for that.
Nice.
Yeah, it's got the type checked decorator, which probably you can just put that on stuff you want to make sure it's checked.
Exactly.
Okay.
Well, that's a good one to learn.
Another one is you create your project.
You start building it.
Two years later, you know, some feature is added.
Some other language feature might be not the way to do things.
So you talk about automated Python syntax upgrades with PyUp upgrade.
Yeah.
That's another Anthony Sotile tool.
So it's also, you can run it from pre-commit.
It's going to essentially pass the AST of your, so the abstract syntax tree of your code and look for things that have better ways to express them in your versions of Python.
So basically what you say, you drop Python 3.6 and automatically you get unions like the pipe.
Right, right.
Like int pipe none versus optional bracket int.
Something like that, right?
Yeah.
These kinds of things.
Or yeah.
Giving you nice set comprehensions.
Yeah.
Kind of like calls to the set built in.
Those of these.
And it's very nice if you're supporting multiple Python versions and you've been waiting to use this feature.
And now finally you can drop the last Python version that didn't support it and you get this for free.
I just run.
Yeah, that is interesting.
I hadn't really thought about that.
You know, some of these are not language features in the sense that people are thinking, oh, well now I can use async and await, which would take like a real important, significant change.
But it's just like, oh, you, you know, now you're able to, because of PEP 289, pass a generator directly to the min function or max or sum rather than a list comprehension, which then gets processed, right?
And that would just be more efficient across the board.
And so that just happens automatically, right?
Cool.
Yeah.
Very neat one.
All right.
Next.
Security audits.
There's Bandit.
Bandit is a tool that looks at your Python code and figures out if there are any things that may or may not give you a security vulnerability or any kind of security issue.
It flags some things like just importing a subprocess and you can no QA it.
I still find that useful because it just gives me a moment to think about all the implications of spawning other processes from our Python code.
And, but it, it has a lot of checks in your, in your Python code base.
So it's, it's very nice to use it to guard yourself against some.
Right.
Like it'll detect things like YAML dot load should be YAML dot safe load.
And I bet there's something there about pickling.
Yeah, for sure.
It's caught of me.
Could be.
All right.
Yeah, exactly.
Safety is the other one.
Yeah.
That basically just checks your dependencies.
So there's a, there's a curated database of security vulnerabilities and it's going to see if you have any dependency in a version that was vulnerable.
Nice.
And just stepping back to some moment, Nick Ma points out that hyper is amazing when it comes to the documentation in the --help option.
Yeah.
Pretty cool.
Let's see.
Going back to, yeah.
Checking the documentation with xdoc test.
So xdoc test is essentially a rewrite of a standard library or utility.
It's called doc test.
And what does it do?
So suppose you have a doc string with an example code that shows how you, how you're supposed to use a library or a function.
And you commonly write these with a, the Python interpreter prompt to give you like, what, what does the user type import my package?
And underneath you have the output of whatever, you know, functions you call it and so on.
So doc test runs these examples and sees if they produce the expected output, they don't throw a raise exceptions and so on.
xdoc test is a rewrite that uses the AST more than regular expressions, which is nice.
And it's also a bit more flexible.
So has a few nice features compared to doc test.
Right.
Cool.
So if you have an example in your documentation, here's a way to automatically make sure it's all good.
Also another audience question, follow up here.
Vasil asks, what do you think about services like Sink, S-N-Y-K, S-N-Y-K, S-N-Y-K, to check dependencies, like for security, right?
So you depend on Flask, Flask depends on it's dangerous, it's dangerous.
Who knows?
Theoretically could have some issue like that kind of check.
I'm thinking he's asking.
I haven't used S-N-Y-K yet.
So I'm only familiar with, with safety.
Nice.
Okay.
Cool.
Getting close to the end.
Then I have a question about all of these taken as a whole.
All right.
Generating API documentation with Autodoc and Napoleon.
Right.
So we talked about this before.
This takes, it takes your doc strings and generates API documentation.
Right.
And this is not a RESTful API, like Swagger, OpenAPI.
This is, this is like my Python libraries function documentation, right?
Exactly.
Yeah.
That's so the reference for your, the functions in your, in your package.
Got it.
Right.
And Napoleon is a tool that will add support for doc strings that are written Google style,
for example, or some other conventions for doc strings.
So Google style is pretty lightweight, which I'm a fan of that as well.
Yeah.
Declaring your arguments and, and returns.
Okay.
Nice.
Generate command line reference with Sphinx click.
So I'm guessing if you're using click might be relevant.
Right.
So you already have all your option help texts and, you know, command descriptions in, in click.
So why not just use them to generate the documentation.
And that's basically what Sphinx click does.
So it takes, so you, when you build your documentation and you use things like auto doc or Sphinx click,
you have to remember to install your own package.
And then these tools can just import it and read the, read all the documentation that you have inline in your code,
including click option up text.
Yeah.
Very cool.
All right.
You've done all the work documented it.
You've tested it.
It's good to go.
How are you going to release it?
Put it on GitHub.
And the last one is managed project labels with GitHub labeler.
So the, the idea of labeler is that you, instead of going through the web interface and then typing in all the,
color codes and hacks and so on, you, you can just use, a file that you put in your repository to manage all your,
all your labels for your PRs and for your issues.
So that's really helpful and makes it really easy if you're collaborating with other people.
Nice.
Yeah.
That's great.
Okay.
Well, that's your cookie cutter.
And in one fail swoop, in one single CLI cookie cutter command, you get all of these.
So when this runs, I should have just run it and played with it.
But does it give you an option to say, you know, don't install my pie or does it just kind of give it all to you?
What's the, I know cookie cutter has a lot of conditional behaviors and stuff.
Like what's the experience of using this to create a project?
I have personally resisted putting in too many options.
It's kind of, I try to find, to kind of show one way that works and also keep it maintainable.
So I don't have a lot of, I don't want the combinatorial explosion.
There's a little bit of options that it gives you.
So you can choose the license, for example, and cookie cutter allows you to hide or show parts of your file tree, depending on what the user chose.
But basically it's not meant to be the, all the different packaging tools, all the different ways like talks, knocks, the different CIs that there was a conscious decision to basically say, okay, here's one way to do it.
And I can really curate it and make sure that it all works.
Sure.
Keep it opinionated and straightforward and whatnot, right?
I suppose if people really wanted to use talks instead of knocks and they wanted to use typer instead of click, they could fork the repo, create their own template, right?
And roll with that.
Yeah.
Cool.
All right.
Well, very interesting.
One more quick audience question here from Michael says, can labeler, as in GitHub labeler, export existing settings?
It'd be great to unify labels across repos.
Any idea?
Right.
I think there is a separate tool to do that.
So I don't think that GitHub labeler does it, but I remember that that was actually a community contribution.
And I remember that the contributor who added this feature first went and exported the existing configuration from whatever we had in the repository.
Okay.
Yeah, cool.
So.
Yeah, very nice.
All right.
Well, we are just tiny bit out of time here.
So unfortunately, even though there's a bunch of other stuff I wanted to cover, I don't think we're going to be able to because we cover so many cool things.
You know, I did want to just give a quick shout out to your music.
And in addition to being a lawyer and a software developer and open source person, you also do like compositional stuff.
Right.
So you've got on your website, you've got a whole section.
How many videos here?
Like 10 different music videos that you've put together that are pretty neat.
You want to just give a quick shout out to that?
Yeah.
So I spent, I think, 10 years working both as a software engineer and a touring and recording musician.
Also as an arranger.
So I arranged some string quartets.
So I did arrangements for Naima Hussaini, who's a German indie singer.
Definitely check her.
Jack E.
I've been on tour with her already across all of Europe and wonderful reggae inspired singer.
And there are so many more.
Yeah.
It's, yeah.
I'm very grateful for the musicians I've been able to play with.
Yeah.
That's fantastic.
I listened to a bunch of them.
My favorite is Immer Alles Kustisch im Deutschen Theater.
That's the one with Naima Hussaini.
That was a really good one.
They're all good.
But that one was really excellent.
And then Michael also thinks that we should have a whole podcast about your compositional tools.
Do you use Python for any of this stuff?
Or is it kind of a separate world?
Sadly, it's pretty much a separate word.
I've been using Ableton a lot.
And we didn't really get into automating all of this with Python yet.
Not yet.
Also.
I think Lucas Lange does this kind of stuff, though.
Yeah.
Cool.
It can be done.
Yeah.
People should check out Fox.
Are you familiar with Fox.
And that whole programming with composition, building up music with Python?
Have you seen this?
I know.
Oh, my gosh.
I've got to check this out.
Every time I search for it, Fox.
I think it's Fox.
Python.
I think that's what it is.
Check out the videos.
There's some neat live coding music with Fox.
And Python.
Every time I just randomly pick one of these videos, it's not really necessarily the best one.
But there's some really neat ones of sort of like adding instruments in with Python.
It's cool.
People should check that out.
Yeah.
All right.
Well, we are out of time.
Really quickly.
Final two questions.
You're going to write some Python code.
What editor are you using these days?
I use Space Max.
I've been using Emacs for a long time and use it with VI bindings now.
I like it.
Right on.
And I'm almost hesitant to ask you for a notable PyPI package because we covered so many.
But maybe just like, you know, what one stands out to you?
Like you want to just give a shout out to either one we covered or...
I just named TypeGuard because it really deserves...
Okay.
TypeGuard 3 is going to come out hopefully soon, bringing new features.
Cool.
All right.
Well, final call to action.
People want to get started.
This hypermodern project idea that you've created, what do they do?
So just go to the cookie cutter hypermodern Python repo.
Check out the contributor guide and the code of conduct.
And we love contributors.
So...
Hold on.
How relevant is going back and reading the article?
Has it drifted too far or is it enough to get like some of the zen?
Or if you've listened to this, are you kind of good to go?
I think the article series is still fun to read.
I think these days what I would recommend is that you don't just take the example code.
Maybe just generate a default project from the cookie cutter and then take a look at that as well.
Because some things have changed in the two years.
But the article series kind of gives you the motivation for everything.
And it's probably also more fun to read than the user guide for the project template, which is also there and very detailed.
But yeah.
Yeah.
Fantastic.
All right.
Well, thank you so much for being on the show.
And congrats on the cool project.
Thank you very much.
You bet.
Bye.
Bye-bye.
This has been another episode of Talk Python to Me.
Thank you to our sponsors.
Be sure to check out what they're offering.
It really helps support the show.
Starting a business is hard.
Microsoft for Startups, Founders Hub, provides all founders at any stage with free resources and connections to solve startup challenges.
Apply for free today at talkpython.fm/foundershub.
Listen to an episode of Compiler, an original podcast from Red Hat.
Compiler unravels industry topics, trends, and things you've always wanted to know about tech through interviews with the people who know it best.
Subscribe today by following talkpython.fm/compiler.
Want to level up your Python?
We have one of the largest catalogs of Python video courses over at Talk Python.
Our content ranges from true beginners to deeply advanced topics like memory and async.
And best of all, there's not a subscription in sight.
Check it out for yourself at training.talkpython.fm.
Be sure to subscribe to the show, open your favorite podcast app, and search for Python.
We should be right at the top.
You can also find the iTunes feed at /itunes, the Google Play feed at /play, and the direct RSS feed at /rss on talkpython.fm.
We're live streaming most of our recordings these days.
If you want to be part of the show and have your comments featured on the air, be sure to subscribe to our YouTube channel at talkpython.fm/youtube.
This is your host, Michael Kennedy.
Thanks so much for listening.
I really appreciate it.
Now get out there and write some Python code.
I'll see you next time.
Thank you.