Hello and welcome to Python Bytes where we deliver Python news and headlines directly to your earbuds.
This is episode 422 recorded March 3rd, 2025.
I am Michael Kennedy.
And I am Brian Okken.
And this episode is brought to you by us.
Check out Brian's pytest courses.
Check out the ones over at Talk Python Training.
We're up to almost 475 hours.
275 hours?
I mean, not that many.
275 hours of courses over at Talk Python.
There are many to choose from there.
and Ryan's book and Patreon supporters and all these things.
Thank you so much.
Also, we're continuing to improve and evolve our newsletter,
which gives you, I think, insights into the episode
that we maybe didn't explicitly call out
and certainly are not in the show notes.
So head over to pythonbytes.fm,
click on newsletter, put in your email.
We will be kind and gentle to it,
but we'll send you cool stuff,
usually the day of or after the day after the show.
Yeah, so with that said, Ryan,
how do we start our show today?
Let's start it with a video, kind of.
- Wait, isn't this already a video?
People want to watch it?
- Yeah, yeah.
- Very mad at you.
- Yeah, so I'm trying to add this to the stage.
What's going on?
Oh, the wrong, yeah, anyway.
There we go.
Technical difficulties that won't make any sense
to anybody listening.
So, we don't normally cover video because it's,
I don't know, I don't know why,
but I don't watch a lot of Python videos, I guess.
But this one is a do not miss.
So Henik put out a video called my 2025 uv based project,
Python project layout for production apps.
And I was paid attention to this
partly to see what he was up to and I like uv.
But also this, so this, when you watch it,
his example is a FastAPI app.
And in his world, an app is usually like,
really a website app.
And later he's gonna go on to talk about Docker, I think,
because this is a part one, part one of a series.
But this one's already enough
that I think it's really useful.
And especially in a lot of the, some of the stuff I deal with
I think of an app as anything that's packaged, kind of.
Like it's not a package, it's not something you put on PyPI,
but it's a bunch of your own code
that you normally would have used a requirements.txt file,
and I like his model better.
So I'm gonna jump in, I got a couple tabs
because it's kind of hard to like navigate.
Anyway, snapshot videos.
So I stopped them where I wanted to.
So the video is great, it's about 25 minutes long,
it's pretty quick to watch.
Here we've got the project layout.
So his project layout is using a source layout.
And really, there's no requirements file.
All of the requirements are in the pyproject.toml.
And instead of a custom lock file or one you manually do,
he's just recommending that you let
UV take care of a lot of the project stuff.
And actually, even with--
and we'll take a look at a little bit more
of what's in pyproject.toml.
But he's recommending that you go ahead and check in the UV
lock.
So if you're letting uv handle your virtual environment,
it's gonna create a lock file, and if you commit that,
then uv run later will use that
and use all of the stuff in the lock file,
and you, instead of running Python,
you clone the repo, run uv run on your project,
and it's gonna grab everything out of the lock file.
It's just like pin dependencies.
It's pretty sweet.
- Yep, I 100% agree with him.
Check in the uv lock file.
And then you don't also, you don't even have to do uv run if you don't want, you can just
do uv sync and it will also use the pin dependencies in the lock file.
And then, because some systems, they require to run kind of with their setup.
For example, Pyramid, you need to use PSERV and then it's like configuration file or flask,
you can do like flask run or Django.
Like, so if you still want to stick with that, you can just do uv sync.
So uv sync will grab all the, everything out of the lock file then.
Yes.
- Exactly.
- And--
- I think it might even create the virtual environment,
though I haven't actually tried that yet.
- Yeah, it does.
Yeah, if you don't have one already, it'll create it.
And also, if you already had one,
and it was out of sync, like uv sync,
that's kind of what the part of the sync does.
If somebody updated some of the requirements,
so the uv lock had changed,
then uv sync will rewrite the virtual environment.
So--
- Nice.
And so he's showing also that his version
of how to specify the Python version
is to just specify it within your pyproject.toml
and uv will grab that and install it if necessary.
And then also interesting discussion around version
because pyproject.toml requires a version
but with a lot of applications
we don't really utilize the version
because it's just code that you're pushing and running.
So he said, "Just set it, if you don't care about the version, just set it to zero,
and then people will realize you're not using it."
So...
The world's most common version.
Yeah.
And then also a discussion around the separation of dependency groups that came in recently
that uv handles nicely in PyProject TOML files.
And that allows you to separate your dependencies based on really what the application needs
versus what you need for development.
this will work then you can run. In production it won't install your like pytest and stuff,
but it'll install everything else. But when you're creating a virtual environment locally to develop,
it'll grab those also. So very cool to have all of this together. And then build system,
I didn't really realize that you could specify uv as a build backend. And I'm going to have to
hatchling in mind and, I believe several people have pointed out that hatchling is
the default. And the reason that we, when we played with this the very, very first time
it didn't show up with any build back in is because we created in, application mode,
but I think if we created a package mode, there's a way to say like, well, what really
kind of project are you creating? Then it specifies the build back in explicitly, I
think. So anyway, a lot of, a lot of options there, but yeah, very cool.
Yeah, and actually just an enjoyable video too.
I like what he's doing there.
So check it out.
Very nice.
Well, let's talk about async and await.
So there's this cool project called AIO Limiter,
an efficient implementation of a rate limiter for async I/O.
And this comes to us from Martin Peters.
Martin Peters, at least at one point,
was the most prolific Stack Overflow Python person.
period. So that was fun. And this project is a something that got created as a result
of an answer on Stack Overflow by him. So not a big surprise. I've, I'll beat on the
dead horse a little bit, Brian. I feel like there's a really, there's a big missing piece
for async and await in Python. And that is any sort of mechanism or control or, or understanding
or adjustment or whatever of the underlying running of async code in general.
Right?
If I call an async function and I say a way to thing, how does it run?
Well, you don't know.
It might be running in an event loop that you've created, it might be running in one
that you, a framework created.
You don't sometimes often, most of the time let's say, you don't get a choice on how that
loop is created.
For example, if you're using FastAPI, FastAPI creates a loop and says, "Here, you can use
this one.
like it. You know what I mean? Whereas systems like.NET, they've got thread pools and async
I/O pools and contexts and stuff that you can say, "Hey, on this one, I want you to
limit to 10. So if you're doing work, just do 10 at a time. When you're done with one,
allow the other ones to come in, otherwise queue them and just make them away." Right?
Stuff like that is kind of missing. So all these projects are trying to backfill that
kind of functionality into Python's async and await. And this is cool. So it does give
you like suppose you're working on a project and you're using an external API
and the API says you have a rate limit of five per second if you go over that
we're gonna start failing and telling you status code 429 too many requests
wait however long and try again but that becomes like really janky right so with
this thing what you can do is I can create a rate limiter and say I'm
willing to allow a hundred calls within a 30-second window or the example I gave
five calls within a one-second window or whatever, right?
Something like that.
And then you just put that into a async with block
and then stuff that happens in that window
will be limited by this rate limit.
- Okay.
- Cool, right?
So it makes it really easy to handle those kinds of things.
But often it's not like I'm going to make all of the calls here,
you know what I mean?
It's I want all the async calls in the system
to be limited in this way,
not the ones that I'm controlling the particular function of,
which is sort of the crux of my complaint that I started with.
But this is nice.
You create one of these somewhere,
and then anywhere you use this rate limit
as a context manager, it is subject to that rate limiting.
So it doesn't have to be the same function.
It doesn't have to be all the codes are happening
at the same time within the block.
So, you know, that's a pretty nice thing, right?
As long as you just put that in all the places you need it.
Like, for example, one of the problems you can do is
you're getting too many requests.
You can overwhelm your database,
and because you're awaiting it asynchronously,
you could just keep feeding it to the database,
even if the database is slowing down
and slowing down and slowing down.
So like in your data access layer,
you could just wrap all of your queries
in one of these things that say,
don't let more than, I don't know, 10 per second
or whatever is reasonable for your database.
That's kind of low, but you know what I mean.
Like you can sort of control that.
- So you might like have one of these rate limiter
for your database and then maybe one for an external API or-
- Yes, theoretically, and they could be different, right?
- Yeah, okay, that makes sense.
- Yeah, anyway, yeah, I thought this was kinda cool,
and people who are worried about trying to solve
that problem, then they can use this
as one of the tools there.
- Computers are so fast, sometimes we're like,
it's too fast, slow down a little bit.
- Yeah, it's like, let's make it allow it
to do all the work and not wait on any of it,
like, usually good, sometimes bad.
- Sometimes bad.
- But the thing on the end doesn't like it.
- Yep.
- Yeah, and out in the audience we got a,
"Wow, cool," says Aziz.
"I had this limit problem a lot."
Yeah, awesome.
Hope it helps.
- Yeah, hope it limits your problems.
- It does limit, it will limit your problems.
What's next?
- That was weak.
So, I wanna talk about SpyStuff.
So, Lucas Lange wrote an article about SpyStuff.
Actually, "A Peek into a Possible Future
"of Python in the Browser."
who, there's a, it's a kind of a fun article also,
but a great picture as well,
some cool picture of the mountains.
Anyway, and you know, he's,
I trust what he, I trust his opinion
because of his involvement with Python and everything,
but this is interesting about a lot of the core Python people
really involved with thinking about the web.
So there's a section about looking back on,
I haven't read this, or seen this,
but apparently there was a Gary Bernhardt talk
about the birth and death of JavaScript.
I'll have to go back and look at that.
And then, but basically talking about the history
of Python and--
- Wait, wait, wait, wait, wait.
If you have not seen the birth and death of JavaScript,
it needs to go to the top of your list.
- Okay.
- The birth and death of JavaScript is a seminal video
that is both hilarious and very insightful.
- Okay, well--
- And the JavaScript is part of the joke.
- Okay, JavaScript, all right.
Well, then he goes on to talk about Pyodide
other things and using NumPy and Cython and stuff. But the real thrust here is a new research
project called SPI. S, capital S, capital P, lower Y, I guess. So that's SPI stuff.
The article says the SPI is a research project in its early stages. At the moment, don't
attempt to use it yet unless you plan to contribute.
But maybe you do plan to contribute.
Both incomplete implementation-wise and design-wise,
but so early stages.
But it sounds pretty cool.
So there's this-- I like the idea.
So there's this-- I'm going to jump down to the demo,
see if we can get it to play.
So-- ooh, I had video sound too, but I
don't think you hear that.
But anyway, there's a demo of it working,
of some shapes shifting around.
And that's actually running in the browser already,
but you just can't, I guess it's not complete yet.
But this idea of having things that look like Python.
So when you're, there's like blue code and red code
is the idea.
And the blue code is stuff that just like acts like Python.
And that's great for debugging and stuff.
And because people are used to writing in Python.
And then there's a redshift model of,
'cause that's what we do a lot is like,
whether we should compile it or not.
But this will pre-compute a lot of the stuff
that's blue into a pre-compiled version.
Anyway, all the little compilation parts
to make things run faster.
But I really like the idea that you've got a level
where you're running it just as pure Python
and then you can deploy it and it runs as a compiled part.
So anyway, I'm probably getting this wrong at early stages,
but we've got links to this article and then to the Spy Project itself,
which a lot of activity just recently.
So anyway, I like that and mostly, I don't know why I brought this up.
The, the story of Python in the web browser, better and better.
So anyway,
I also bookmarked this article as something super interesting that should,
you know, might be worth talking and reading up on.
So thanks for covering it.
Yeah.
And if you've got a deeper,
- We're on the verge.
- You mentioned we could bring it up later again as well.
- Yeah, yeah, it's early days,
so maybe there'll be more news on it.
I'm very excited about the possibility
of Python in the browser.
It'll uncork some amazing stuff
if that really gets running seamlessly.
- And really, I'm saying the browser,
but really what we're also meaning is that
if we could not have different front-end
and back-end languages,
so if we do all the dynamic front-end stuff with Python,
be cool.
Exactly.
Like, so I think that the browser manufacturers could do significantly
more to make this better for, for example, every one of them ships a
JavaScript runtime that's optimized.
Right.
Not a single one of them ships the WebAssembly version of Ruby or the web
assembly version of CPython, you know, Pyodide or the WebAssembly version of
.NET for Blazor or all these things.
And so all of those projects are like, well, it'd be great to use this.
but it's really slow to download the whole runtime
on each page separately.
- Yeah.
- Every browser could say,
"We will provide and keep up to date
"as part of our binaries,"
or just off of the internet or whatever as you download it,
"a shared Python runtime, a shared Ruby runtime,
"a shared.NET runtime," and so on, and they don't.
- Yeah.
- Right, but all these complaints about,
"Well, the web frontend's too slow
"'cause you gotta download all this stuff,"
like, yes, you do now,
but it could theoretically be that they say, well, we're going to support like an
open sort of management of these, these binary, these WebAssembly runtimes that
you might need to download.
Sure, the extras you got to download every time like JavaScript, but the core
runtime of 10 megs, we'll like update that with our browser or just update it as it
changes on the web.
I wish they would do that.
Right.
I mean, you know, they do it for JavaScript.
I mean, come on now.
Right.
It's like, it sounds crazy, but at the same time they do it for JavaScript and
they write their own.
All right, they wouldn't even have to write their own.
They just got to allow the run of random others.
Okay, enough of that.
Let's talk about reloading stuff in the browser.
Instead, that sounds fun.
So there's two projects I want to tell you about.
One is the big heavyweight does so much stuff
to help you write web applications,
type in the editor, and have that stuff magically change.
For example, by default, if I run a Flask app
and I go over to the, I run it and I open it up in a browser,
and I see the page I'm working on,
and then I go over and I edit the Jinja template.
I hit save, and I refresh the browser, nothing happens.
I have to go back to Flask, restart Flask,
go back to the browser, reload the browser,
now I can see my changes.
You can level that up one by going to Flask
and say you're running in debug mode,
so if you see any changes, please rerun Flask
and reload the templates if I edit the templates.
Then you can just edit your thing, save it,
go over to your browser, hit refresh, see the changes.
But what would be nicer if I could have like two thirds
of my screen be my editor,
one third of my screen be the web browser.
And as I type, I see stuff just changing on the page.
So if I put a CSS class on a thing,
I don't have to go to the other app and do anything.
It just literally just the changes that apply
like every second or so, right?
So that's what this Relodium thing is, but it does a lot.
So I want to put this out there for people as a cool option.
I'm not sure I'm going to put it out there
as a recommendation yet.
So let me tell you.
So for example, it will not just do the experience I told you about, but it will
actually rerun every function.
If you make a change to a function, it will rerun it and you can actually
have it doing like live profiling.
So as you, as you type there, it'll give you a profiled output of the thing and so
on.
So if you kind of want to explore it, it gives you like that idea more broadly.
So it works there.
it comes with a PyCharm plugin which is what the little animation is so you can
actually see a visual representation of like the performance time and how it's
running and reworking and so on. Okay so that's pretty neat. Comes with an AI
thing I'm gonna skip that I don't know what that is or care. It has yeah so
generally if you make a change to a function it will re-execute the current
function providing immediate feedback and if there's an error it doesn't die
it just goes well okay once you fix it things are going to be good and it'll
start working again. So it's kind of durable to that, you know. And it'll
refresh files throughout the entire project, looking at dependencies. So if I
make a change to like one bit, then it'll change the others, you know, like with
new import or whatever. For Django, it does exactly what I was telling you, like
as you type, not just as you type HTML, but as you type Python. So the example
they have here is they, they're doing a query for all objects and then they
slice it to do a limit, paging and limiting type of business, and as they change the numbers
in the slice in Python, the web browser is automatically updating the results without
them touching it.
That's pretty cool.
Yeah, it's pretty cool, right?
Similarly for Flask, it automatically reloads Flask, but again, it says, look, it'll hot
reload the Flask app, but if you just set Flask debug to be true, Flask will already
do that, you know what I mean?
So the one thing it doesn't do is it doesn't refresh the page as you type on one side.
The stuff on the right doesn't change, right?
Another thing it does, it'll for SQLAlchemy because it's like running functions over and
over and over, it might start to do insert, insert, insert to the database.
So it does these auto runs and transactions that roll back so it doesn't tweak the database.
Oh, interesting.
Yeah.
And it also does hot reload for pandas.
So if you're messing with your data frame or things like that, it'll just automatically
be updating as you type.
- All right, pretty interesting, right, Brian?
- Yeah.
- Yeah, I don't know if I talked about it before,
but just since people might want
a less intrusive version of that.
So I have this project called
Server Hot Reload over on GitHub,
and it's a single JavaScript file.
And if you just include the JavaScript file in your page,
it will give you the same functionality
for web apps that will reload the template.
So for example, if you just include the JavaScript
at the top of the page,
and then Flask, if you run it with Flask debug,
or Pyramid automatically reloads in debug mode.
You can set that in the config file,
and I'm sure you can do similar stuff with Django.
And then you just browse on one side,
code on the other, and you just start typing,
and off it goes, and even detects if you set it up right,
or even like reload the page if you change an image
that was being used, and things like that.
So, super cool, but this one, it doesn't go all crazy.
It doesn't require an IDE plugin and all that kind of stuff.
Basically what it does is it looks at the response from the server and says, "Is the
hash of the HTML changed?
If yes, reload the page.
If it's not changed, then don't reload the page," that kind of thing.
So anyway, two ways to basically work in your editor, start typing, and having some kind
of output web or in Relodium, other places, just automatically changing as you type so
you don't have to manage that.
You're just like, "Oh, what's this class?
Oh, that looks really great.
No, we need more padding here, da-da-da," off it goes.
- So the server one probably doesn't do the,
like if you change Python or--
- Technically no, it doesn't do that.
However, if you set Flask to do that automatically
and then it re-requests the page, then yes it does.
You know what I mean?
- Okay, got it.
- So if you're willing to use the framework tools,
then it does.
- Okay, okay, very good, cool.
- Yeah, but it's nowhere near as intense,
which I think for some people is a drawback
and other people is a plus, depending on where you are.
- Okay, nice.
- All right, that's it for all of our items, isn't it?
- Yeah, it is.
- Well then, what have you got for extras?
- I got just a pet project of mine
that I wanted to talk about.
So the Complete pytest course has been out for a while,
and there's a couple things about it that are a little,
that I'd really kind of like to change,
so I'm working on some changes.
First of all, if you see, if you go to the,
and look at it, it says there's 162 lessons.
It seems a little scary and the reason is because I've chopped it all up into, so there's
16 chapters in the book, the course covers the entire book, 16 chapters, each video covers
a section of a chapter and that's where, plus welcome videos and stuff, that's where the
162 comes in.
But that's a little, there's actually 162 videos which is a little intimidating, especially
if you're looking at one and you kind of like,
there's a lot here.
But I mean, it's all good if you like to go
in just like a few minutes at a time, that's great.
But some people wanna just chunk through an entire chapter
in like a lunch break or something.
So the alternate version that I'm working on
is chopping this up into just chapters.
So most chapters will be one video.
And then you can just chunk through
like just watching one video, you can watch it in a weekend,
or not a weekend, in like, you know,
20 minutes or something like that.
There's a couple chapters, chapter two and chapter three
are pretty big, writing test functions,
and then fixtures, pretty big concepts.
So they're a little longer, so I'm chopping those
not into one video, but like three videos.
And so, when I get all done,
the new version will be not 162 lessons,
but like 20 lessons or something like that.
And then I'll probably make that the default
and I'll just have both of them available
because some people might like the little more granularity
and it's not more effort on me to have both of them around.
So they'll both be around.
Anyway, that's what I'm up to.
- Cool.
Yeah, I like the small little videos.
I think it's a way better reference material.
You don't wanna have to go like,
where in that 15 minute video was the thing I wanted?
- Yeah, that's the benefit.
The other thing is I like to, for videos,
I like to probably set them at like 1.2 speed
or 1.3 speed the first time, or 1.25, maybe 1.4,
to get an overview really quickly.
And you have to reset that for every video,
and that's somewhat a little annoying.
- That's a hassle.
- Yeah.
- That is a hassle.
All right, well let's see what I got for extra.
I got an oldie, something fun here.
So there was a Hacker News thread or Reddit thread.
I'm gonna go with Hacker News.
Pretty sure it was Hacker News talking about,
hey, could some people recommend
some cool, legit programmer fiction books?
Right, like I want a spy thriller
that has to do with programming but that's not stupid.
Right, it's not like, whoa, this is VB6, I know that.
I'm gonna track their IP, like, you know what?
That's not how it works.
More Mr. Robot, less Jurassic Park or whatever that was.
I can't remember.
So, the book that I thought was really cool
I'll give a shout out to is by Mark Russinovich
who is the CTO of Azure.
And apparently I bought this book in 2012
just to give you a sense.
So it's not brand new, but it is a super cool series
as long as you keep in mind like its computer world was 2012
so people can check that out if they're interested.
Also, Warp on Windows.
I'm a big fan of Warp, the terminal.
It's been working out super, super well.
I tried ghost TT or ghost DD or whatever,
however you say that.
Just, I cannot do it.
I can't do it.
Like, it doesn't even let you like select
text with hotkeys and stuff.
It just puts like control H and stuff in there.
And then until you can work with it as an editor,
no, I can't do it.
So, I mean, I know there's some way,
like you can hold shift and arrow,
but you can't do like control shift arrow to do
like word by word.
And you can't do, like you can do a home,
but you can't do like shift home.
These are like really weird, like editing and stuff
where like some of it just starts putting
escape characters into the thing.
I don't remember exactly what it was
'cause when I saw it, I'm like, okay,
we'll come back to this some other time.
Anyway, if you are on Windows
and you're looking for a better terminal,
and I know Windows has fewer options
and less good options than the other places
for a variety of terminals, like there's Windows Terminal,
and then, I don't know, is there anything else?
I'm not sure.
There's definitely Command Prompt.
- Well, PowerShell runs within Windows Terminal.
Like you can run Git Bash or PowerShell
or whatever the DOS-like stuff.
You can run all that in Windows Terminal.
- Oh, right, okay.
- Right?
You can do the same in Warp.
You can choose, do I want PowerShell,
do I want Git Bash or whatever.
But the thing that is the outer bit of it,
you know, the app itself, there's not many options.
So this is a cool thing that people can check out.
I'll link to the video 'cause it's fun,
but you can just go to warp.dev or wherever it is.
Okay.
Our friends over at Teaching Python Podcast, they are participating in being
part of the PyCon 2025 Education Summit.
And they're pointing out that, Hey, the applications are going to be, you know,
sending a proposal very, very soon.
So that was, I think last Friday and today is Monday.
So, just recently opened up and they said the main theme is,
in the age of AI, how do we maintain the creative,
empathetic, and critical thinking skills we need
to make us human and great coders?
We want to know, and so there's a whole bunch
of ideas around this.
So, we've got Kelly and Sean and a bunch of other people
participating in this, so if that resonates with you,
check it out.
- No, I was just chuckling because even before AI,
we hadn't figured that out as far as I could tell.
- Yeah, I don't really know the answer,
So I'm going to ask ChatGPT, I'll get back to you.
[laughing]
Okay.
[laughing]
Yeah, one more extra here real quick.
I just noticed that Granian, which is powering Python by ZFM, by the way, and many, many other things,
just came out with their 2.0 release right there, seven hours ago.
How's that for fresh, shocking news?
Breaking news.
[imitating drum roll]
As far as I can tell, there's a bunch of cool changes here.
One thing that's not cool is as far as I can tell it doesn't run FastAPI apps.
So if you have Gradient, powering your FastAPI app, you might test this before you just update.
There's also breaking changes in the CLI of like how you specify certain constraints and stuff.
That's easy enough to fix because it tells you this constraint such and such,
but I think there's something going on where at least all of my FastAPI apps stopped working when I switched to this,
but all the other ones like Cort and Flask and Pyramid all work fine.
- Interesting.
- Don't know why.
And Cort is async first just like FastAPI.
So I don't know what's going on, but they were not having it.
So I just pinned the version to less than two for those
until whatever happens here gets figured out.
So there's just a little PSA.
All right, with that.
- So seven hours ago, you already tried it?
- Not on purpose.
I tried it three hours after it was released.
I needed to ship something else,
but my deployment process is check something in the Git
and then have it go rebuild the Docker images
and restart them.
And that's all, check all the dependencies,
is there anything we can update?
Like, does Ubuntu have security fixes we need to apply?
Can we update the web server
in case there's a security fix for it?
And then we'll rerun the dependencies
and we'll restart it.
And then it didn't restart,
I'm like, wait a minute, what?
Why, what's going on here?
This is not good.
So that's how I learned
that there's a new release of "Granny."
- Okay.
- You know what I mean?
It's not like I was like, "Oh, I gotta try it that quick."
It tried itself on me and then it didn't go so well,
so I scrambled to fix it.
- Okay, got it.
- Yeah, yep.
Okay, joke?
- I'd love a joke.
- Tabs or spaces?
This one has to do with tabs or spaces.
I'll tell you a joke before the joke,
a pre-joke, if you will, to get everyone in the mood.
This is like the bad joke,
the bad comedian that shows up
before the one you actually came to see.
So we were at PyCon, I don't know.
I think this might've even been in Portland.
This was a while ago.
And there was some company that was clearly
not very tuned into Python.
They were just a coder company, right?
And they were like coming to sell their coder tools
to the Python people.
And so as they wanted to make a spicy t-shirt
and the spicy t-shirt said, "Tabs or spaces, fight."
Like this is the stupidest shirt I've seen
at the whole conference.
I mean, tabs are basically disallowed.
They're not exactly disallowed,
but they're pretty much disallowed.
- Like that's not an argument, it's over.
- And you're like, you're trying to set up as a debate,
like you could do two spaces, four spaces and fight,
but you can't do tabs versus spaces at a Python conference.
Anyway, but people are going around with shirts nonetheless.
I think I got one to cut the lawn in.
- Okay, well, on that topic, two spaces or four spaces?
- Four, unless I'm doing JavaScript then two,
'cause for some reason the tools seem to default
to two for JavaScript, you?
like four usually, but I'm noticing that I'm using two frequently as well.
So, okay.
- Very contrarian.
Okay.
You're an enigma wrapped in a fuzzy cloud.
Okay.
How about this for, this is the real joke.
So I don't know if this is better or worse, but this is what people came for.
Code puns.
You ready, Brian?
- Yeah.
- A Python programmer walks into a bar and opens a tab.
The bartender tells them to sit at the table since they will need four spaces.
That's what I got for y'all.
No it's hilarious, see?
That's why people listen.
Yeah, yeah, yeah.
Oh no, I'm like advertising it poorly.
That was hilarious, man.
Good joke.
Now, there's actually a bunch more here.
We've talked about this place before, right?
Yeah.
Let's see.
They're not all good.
Why did the four loops stop running?
It took a break.
Yeah.
How do you convert a JavaScript bug?
You console it, like it's console log and so on.
There we go.
- No, it's good, thanks.
- I think it was hilarious, I know.
I hear the flaws, no, not really.
But that's what I brought anyway.
- Good talking with you again,
and thanks everybody for listening.
- Yeah, you bet, bye all.