Hello and welcome to Python Bytes, where we deliver news and headlines directly to your earbuds.
This is episode 321, recorded January 30th, almost the end of January.
And I am Brian Okken.
And I am Michael Kennedy.
Hey, Michael.
Hey, hey.
Excited to be here today again.
Absolutely.
Before we jump too far into it, I want to thank Microsoft for Startup Founders Hub.
Please listen to their spot later in the show.
How are we going to start the show?
What do you have for us, Michael?
You may wonder, some folks have publicly expressed the bewildering thought that maybe we live in a simulation.
I don't think so.
Do you think we live in a simulation, Brian?
Sometimes, yeah.
No, I don't.
When I'm playing a game, maybe.
But what if you were working on Git and you wanted to see how things were working, simulate some operations,
and try to understand how Git works without actually making those changes?
Because there's always the, you know, Git is full of good jokes, right?
Like, in case of fire, Git commit, Git push, run.
You know, things like that.
Yeah.
Those jokes.
But the other one is, you know, you don't need to know Git that well.
If you mess it up, you just delete the repository and clone it again and start over, right?
So, you know, ideally, you would be able to run some operations to help you understand what Git is going to do without consequence.
Okay.
And so I introduced to you this tool called GitSim.
And GitSim will visually simulate Git operations in your repos with a single command.
So what it is, is instead of saying, like, Git merge branch, you would say Git-Sim merge branch.
Now, how best to explain what's going to happen?
Like, if it just says, we would have merged this branch into that branch with seven changes.
You're like, okay, maybe that's fine for merge.
But there are many other things that are more complicated.
And so, as you and I are fans of, this will simulate, it will show you the visual behavior changes that are going to happen.
Isn't that cool?
Yeah.
So, by default, you get a JPEG image.
And the top one you see here, you can see all the commits, their SHAs and their message.
And you can see two branches.
It'll see where head and main are and where dev is.
And it'll show you, if you do a commit or actually a merge, you're going to take these changes from dev, push them forward, right?
And the resulting shape or behavior of the repository.
Yeah.
So, that one's pretty straightforward.
I'll show you some really cool ones in a minute.
So, use cases include visualizing Git commands to understand them.
It's kind of what I was talking about.
Also, my joke, prevent unexpected working directory and repository states by trying it out first.
But there's also a whole, I'm creating blog posts, tutorials, courses, whatever.
So, sharing visualizations of your Git commands with your team, maybe for documentation, right?
In our wiki, like, this is our workflow.
You probably don't understand what this weird Git thing is that we're doing because it's non-standard.
Please watch this little animation so you know why we're doing it or something like that, right?
Yeah.
Internal documentation, that's a great use for that.
Yeah, absolutely.
So, basically, the supported commands at the moment are log, status, add, restore, commit, stash, branch, tag, reset, revert, merge, rebase, and cherry pick.
And then sub commands of those, right?
Install.
It's got some steps to install it, some ways to run it.
But then you can see, if you scroll down far enough, you'll start to see some of the examples.
So, there's a bunch of examples that are pictures, like a git sim-log.
It'll simulate the output showing the most recent five commits on the active branch.
Yeah?
And it sort of shows you the tags and various things.
You can see status, and it does like a rich style sort of tree, not tree, a table view.
Really nice there.
You can see a lot of the different, almost Kanban flow of your files going from untracked to tracked and modified locally and staged and all that.
Which is, actually, I think it's pretty helpful.
Even with little arrows showing, you know, it moved from here in this one of those columns to this other column.
Yeah.
I don't think I've ever used git restore.
I don't think so.
I don't make mistakes, so it's fine.
Isn't that delete and reclone?
Yeah, exactly.
Oh, my God.
Don't commit that.
Don't push that.
Please.
Just delete it.
Let's see.
But if we go down further, you'll get more interesting examples.
The merge one is there.
Let's keep going.
But we get to the video one.
This is where it gets to be pretty awesome and pretty unique.
Animate.
We could do a git sim reset.
So, check this out.
So, over here, you have this visual diagram showing how this stuff is changing over time.
So, it's like, all right, what we're going to do is we're going to reset this and you'll see, like, the head pointer and the branch pointer move over.
And what do you think, Brian?
Isn't this cool?
This is really neat.
Yeah.
I'll just pick one or two more.
So, we got merge.
That's pretty straightforward.
Rebase.
Let's animate a cherry pick.
So, you'll see it coming along here, building up the git repo status.
And then what's going to happen?
It's going to show us a branch.
And we want to take some of those changes and cherry pick them over to the main.
Yeah.
Anyway.
If you trained on that one, but that's okay.
I am too.
That's not a great animation, to be honest.
Anyway, it shows you a bunch of examples, a bunch of cool things.
I think this is really nice.
It's like I said, primarily documentation internally, like your internal wiki, your onboarding docs, or for, say, blog posts.
You want to talk about what something looks like, then run this.
And it's not just what does a git merge look like.
It is, what does the git merge look like on this repo in this state, right?
Yeah.
It applies to your working repo, which is cool.
Yeah.
The applying to the working one, that's really cool.
I mean, you said that mergers are pretty easy, but actually, I think I'll probably use this for mergers the most.
Because there's a lot of times where I have a mental model of what my repo looks like.
And a merge shows a conflict or something.
And I'm like, why would it be a conflict?
That's a good point, actually.
And it's probably because my mental image of what the repo looks like right now is wrong.
That something has moved forward since I branched off of it or something.
Yeah.
Very good point.
Actually, I end up confused sometimes.
That should have gone a clean merge.
No problem.
And now I'm in some situation where it's asking me to describe the changes, and I actually don't know what they are.
So let's start digging in.
And then sometimes you've got to like, manual merge?
What is this?
1980?
Exactly.
What are we using?
CVS?
Come on.
Let's go.
Anyway, this is what I got.
Git.
Git Sim.
Nice.
Well, so I guess we're kind of doing a tools thing, at least for now.
I'd like to talk about Nox.
So have you used Nox?
I have not.
Okay.
So there's Nox, and then there's Tox.
And I have used Tox a lot.
So both of them, I guess, they do have different things that you can use them for and stuff.
What do I use them for?
I use them primarily to run pytest on multiple versions.
So the general, one of the workflows that works on both of them is I want to create a virtual
environment with like Python 310, 311, 39, a bunch of different Pythons, create a virtual
environment, install my package that I am trying to test, and then run that, and then all the
dependencies, and then run that test suite within that environment.
So that's kind of a standard thing.
So my first thought, first when I saw Nox was, so one of the benefits of Nox, Tox uses
any files for the settings.
You can also use, it supports Toml now, I think, maybe.
I think you can do it in PyProject Toml also.
If not, sorry.
But the Nox uses just a Python file.
So you have a Python, I think it's Nox file.py or something like that.
But it just uses, I could use the example.
Anyway, it does similar things.
So Hynek, I'm going to get it wrong, sorry.
Hynek wrote an article called Why I Like Nox, and he specifically calls out of like, I'm not
bashing Tox.
Tox is still awesome, a great team supporting it, and I agree.
I know a lot of the people that support it.
But Nox's might be for you as well.
So here's a person that likes both tools, comparing them, and it's refreshing.
So first off, it's the file format.
So Any, Tox uses AnyFiles, Nox uses Python.
And I got to admit, even for a simple example like this, then the example I'm showing is
running Python 3.10 and 3.11 and being able to pass in arguments to pytest.
Both are not terrible, but I think maybe the Nox one's a little bit more readable just because
it's Python.
It's definitely more flexible because you could run arbitrary Python code in addition to
some sort of setup, teardown, beyond pytest itself.
Similar.
And then he gets into another example, which is a little bit more involved, which is I've
got a test matrix, but I also, different Pythons, but I want to be able to run the oldest adder's
version against whatever Python environment I'm running.
And he claims that he, and I haven't tried this out, that it's actually, he doesn't know why
it isn't working, but it's just, it doesn't work.
And I'm, you know, I can't help him out there.
But then he switches to Nox and it's a lot longer example, but it works great.
And the, the longerness, the longerness I kind of like, and Hinnick points out in terms of
number of lines, it's longer than the Tox equivalent, but that's because it's more explicit.
And anyone with a passing understanding of Python can deduce what's happening here, including
myself a year from now.
Explicit can be good actually.
So I kind of like that, that the, it's okay that it's longer.
You're not reading it all the time and having it more verbose might help.
So I like that.
And then of course you brought this up, the power of the snake.
You can run, you can run anything you want.
It's Python code.
So that's nice.
And then one bonus thing is apparently it's a little easier to specify versions that Nox has
a --Python and you can pick the version you want to use like that.
And it just looks normal.
You can do that with Tox too, but the normal way to do it is to say what, like PI 310, which
you just have to know the syntax.
It's not terrible, but whatever.
Yeah.
So good, good overview of Nox.
Yeah.
It didn't really, I guess I didn't realize that Nox was playing Python.
I'm sure that I knew that at one point, but forgot about it.
That looks, that is an interesting advantage.
Yeah.
So I think I want to play it with a little bit more.
And I, the, he points out as also that he's not switching completely over to Nox,
but he does have some projects using Tox and some using Nox.
It's good.
There's two.
Yeah.
And they rhyme.
All right.
How about our sponsor this week?
Oh, yes.
Thank you to Python.
This episode of Python Bytes is brought to you by Microsoft for Startups.
Microsoft for Startups has built Founders Hub to help startups be successful.
Founders Hub provides founders at any stage with free resources to help solve startup challenges.
The digital platform provides technology benefits, access to expert guidance, skilling resources, mentorship, networking connections, and so much more.
It is truly open to all.
Along with free access to GitHub and Microsoft Cloud, with the ability to unlock credits over time, Founders Hub has also partnered with other innovative companies to provide exclusive benefits and discounts, including OpenAI.
And we've heard from one of our listeners that he's taken advantage of this already, and the discounts are awesome.
You'll also have access to their mentorship network, giving you access to a pool of hundreds of mentors across a range of disciplines.
You'll be able to book a one-on-one meeting with the mentors, many of whom are former founders themselves.
Make your ideas a reality today with the critical support you'll get from Microsoft for Startups, Founders Hub.
To join the program, visit pythonbytes.fm/foundershub 2022.
The link is in your show notes.
Ooh.
Indeed.
Indeed, indeed.
Thank you, Microsoft.
All right.
Ready for the next one?
Yes.
Not that one.
So this comes from Tom's corner of the internet.
Tom's got his own corner.
Yeah, got a very own corner.
There's a lot of corners of the internet, to be honest.
I don't know how many dimensions that is, but many, many corners exist in the internet.
And here's one of them from Tom.
And Tom says, don't think the tools he's using here are exactly about Python, but what he is.
applying them to certainly is.
It says, I scanned every package on PyPI and found 57 live AWS keys.
Not just, oh, that looks like a string that could be an AWS key.
He logged in as that person.
Oh.
This is not on GitHub.
I want to emphasize, this is on PyPI.
So pip install.
Hey, look, thanks for shipping me a version of your keys.
Weird.
Weird indeed.
So it says, after I inadvertently found that Infosys leaked AWS keys on PyPI, I have thought,
well, if it's once, it's probably many times, right?
They're probably not the only one.
So after scanning, get this, all 430,000 published.
Well, no, actually, I think that's releases.
There's 430,000 packages, but there's 4.1 million releases.
So I think he scanned all the version history as well.
Okay.
Somebody found them and took them out.
Anyway, after scanning those, I found 57 valid access keys from, you know, organizations.
I'm sure that they're new at working with the cloud and especially AWS.
It is tricky.
So these organizations may not be familiar with the rules, but Amazon leaked their own AWS keys.
That was the joke.
The rest, not so much.
But Intel, Stanford, Portland, and Louisiana universities, keeping it local.
The Australian government.
Thank you for that.
General Atomics Fusion Development, Teradata, Data Lake.
And yes, your gloves too have been leaked.
Top Glove, the world's largest glove manufacturer.
I love the emoji.
A little glove.
There's a glove emoji at the end of that title.
So here, like, check this out.
If I click on Australian government, it takes us to inspector.pypi.io, which I didn't really know anything about.
Then it links to data cube dash OWS version 186.
And pulls it down into WSGI local PyPI.
Brian, what does the comment say?
Do not commit.
AWS Qs do not commit.
Not only are they committed.
You know what?
Here's the thing that's interesting, okay?
They may not be committed to GitHub, but they may have forgotten to take them out when they did the build step to build the wheel.
And then they comment them out or somehow remove them from going to GitHub.
And that's...
Oh, I could totally see how this could be easily done.
Because you have to go through an extra step to push from GitHub to PyPI.
A more natural beginner state is you publish to GitHub and you publish to PyPI.
Yeah, exactly.
It's very...
If you haven't set up full end-to-end automation that does the publish for you, which I think a lot of people haven't.
Yeah.
You know, it's easy to have this happen.
All right.
So let's go through this real quick here.
So how do we do this?
Detecting AWS keys is actually pretty simple.
Did you know that there's a regular expression that is a valid match for AWS keys?
I thought there was kind of random business, but no.
There's a certain format that they take.
So you can tell this is not just A key.
It is an AWS key ID.
Oh, cool.
So now I know how to search for them in other people's repos.
I feel like this would be a pretty awesome pre-commit hook.
And, you know, there's tools like Twine and others that people use to build their packages that get shipped to PyPI.
Yeah.
And PyPI itself.
All of those could start applying checks for this kind of stuff, right?
Because GitHub access keys have a certain pattern now.
I don't remember.
There's like, there's some prefix that they seem to have that looks like it's predictable.
I feel like maybe, maybe this could be put into the supply chain pipeline, as they call it.
But anyway, there's a regular expression you can run against to find them.
And here we go.
So we can use the amazing ripgrep to search packages for this pattern.
And look at that.
Here we go.
You pull down this, this gzip file, and then you ripgrep it.
And boom, out comes the access keys.
Whoopsie.
Apparently Amazon pay at this point here.
But just because the keys are present, are they valid?
I don't know.
So the next step shows you how to execute the AWS CLI command to get the caller identity to see if it's actually valid.
Right?
Okay.
So it says, now the devil's in the details.
The Z dash Z flag doesn't support searching zips.
So let's go.
Let's go and tear this up.
And points out, you can get the entire over at github.com or F PyPI dash data.
You get the entire static dump of PyPI data.
Oh, nice.
Did you know this existed?
I had no idea.
So I'm like, wait a minute.
Let's go check this out.
PyPI dash data.
This is automatically updated.
PyPI API data available in bulk.
So the contents of the entire.
How big is this?
It's not small.
See the shallow checkout, perhaps.
The contents of the entire PyPI JSON API for all packages updated every 12 hours.
Wow.
Yeah.
So it says, for example, here's the JSON for Django.
So anyway, I didn't know that exists.
That's pretty awesome.
Then he set up a GitHub action to pull those down.
Then GitHub actions.
Let's see.
GitHub secret scanning service will kick in and let AWS know that the keys are leaked.
This will cause AWS to open a support ticket with you to notify that your keys are leaked,
which is kind of an interesting chain of events that happens here.
But it talks about how old the keys might be.
The oldest one is from 10 years old from 2013.
And different reasons this happens.
It's hard, for example, to test against AWS.
Another reason that they say is like there's legitimate and quote uses.
One of the things they talk about is, you know, why is this happening?
And Python being super heavily used in data science and ML, a lot of folks come from that
side of the world without super strong software engineering practices.
And so maybe, you know, coming from economy and being an economist, you're like, oh, I got
this thing working.
Let me publish this up to help people.
Right.
It's really easy that you didn't really think about some of these things.
Right.
But basically, don't put your secrets in your source code.
Don't put them in GitHub.
And, you know, don't buy the transitive property.
Put them in PyPI either.
Yeah.
So anyway, what do you think?
I think it's a head shaker, but interesting.
We need like stickers made up for laptops.
Do you know where your keys are?
Exactly.
It's 10 p.m.
Do you know where your keys are?
Yes.
They said they're sleeping at their friend's house.
They're actually at a frat party.
Okay.
Yeah.
So the article is like missing one step and that's how to how to set up a Bitcoin miner
on all these keys that you.
That's left as an exercise to the user.
By the way, nice little Hugo website here.
Got to give a little shout out to that.
And I know we both like our Hugo.
Okay.
That's it for this one.
Okay.
What's your final one for us?
I've got a hypothesis.
So I get actually asked this a lot.
I do like hypothesis, but it's a little overwhelming.
I get asked, so what do you think about hypothesis or something like that?
Or do whatever?
Yes.
I use hypothesis.
I do like it, but it is, it can be overwhelming.
So we're going to take a look at an article called getting started with property based testing
in Python with hypothesis and py test.
And this is from Rodrigo and I'm not going to try the rest of the name.
Rodrigo.
Maybe.
Yeah, I'm not.
Sorry.
Cool name.
Saro.
Yeah.
Anyway, it's on the semaphore blog.
And there's a lot of what I like about this article.
And the, well, first off, what I really like about property based testing is not that, I
mean, it can find some bugs in your code and that's, that's kind of what it's for.
And it's good, but it also makes you think about it.
So thinking about a few examples to test your code and corner cases and all that stuff is
good to say, you know, how do I, how do I know if my code's working, but with property
based testing, especially, and I, I think a good place to focus this on is algorithmic
stuff.
So you've got like some type of some algorithm and insider in a function, and you really want
to make sure that that's just solid, no matter what you throw at it.
And so that's a great place for property based testing.
But how, what you do is you think about, you have to think about what properties are true
because what hypothesis is going to do is it going to throw a bunch of input at your function.
And you, so you have to think, how do I tell if I don't know what the input is, if the answer
is correct?
Because if you know the input, you, you can like calculate it yourself, whether the answer
is correct or not or something.
But without that, you're thinking in properties.
And so I love this article.
The first, the script, the example, it goes through two examples.
The first example is a greatest common denominator in math problem of like thinking about, I mean,
you can just like have some known problems that you know the answer to and pull those out.
That's great.
But how would you test like for every number?
And so going through a couple, thinking about what to test is great.
What did he talk about?
For greatest common denominator, your answer is going to be positive.
And the answer needs to divide both, both of the numbers, right?
That's kind of the point of it.
But then how do you know if it's the right one?
Well, no other number larger than your answer is going to be able to divide N and M.
So it's kind of you're going to end up doing kind of an exhaustive search a little bit.
But that's OK.
It's it's it's source code.
It'll run.
Shouldn't be too long.
And the other thing hypothesis do does, which I didn't know at first, is it's pretty good
at picking numbers that will probably break your code.
And by default, it only picks 100 numbers.
It only picks up 100 test cases.
And the limit is important because often your your sample size that you could test is infinite.
So you don't want it to just run forever.
You want it to be some constraints on it.
So the it goes through this example coming up with how to test that.
So it writes a test and then how to plug.
How do you plug hypothesis into it?
So you've got given and strategies is often used.
And so you you put a decorator on your test, say, given strategy integers for both the input
and of N and M test to make sure.
And then you run you run your your function and then test stuff around it.
And the test is listed up higher in the code.
And then quickly, you're going to find problems.
And I like I like the greatest common divisor because there are test cases that you that don't
work, which is great.
Like zero zero, you know, by definition, we don't if both of them are zero, it's undefined.
And if one of them zero, it's defined to be the other one, which I actually didn't know.
I'm like, really, is that true?
I looked it up.
And I didn't think about that either.
Yeah.
So apparently, if you the greatest common divisor of zero and five is five, which who knew?
But aside from that, so coming up with edge cases is probably good for algorithmic type
of code anyway.
And then the example of zero zero, how do you get rid of that?
So in this, I guess this is one of my caveats about this article.
He talks about limiting the range, which it's good.
It's a good example, because you're going to want to do this in a lot of your test cases
is limit the range.
So you can put a min and max on different things.
And there's a lot more than numbers.
You can do text and you can do all sorts of stuff with hypothesis.
But I think good starting with numbers is a good one.
I just don't like the solution that he came up with.
The solution he came up with is limit one of them from one to 100 so that you're never
going to have zero zero.
And I'm like, I personally would have used a different mechanism.
So my recommendation is a there's a strategy called.
So, oh, not strategies, making assumptions.
So there's a thing in hypothesis called assume.
And you can say within a test, you can say assume something.
Assume it's just like an assert, but it doesn't fail your test.
If it fails, the it rejects the test case is how it works.
So you can say for the zero zero case, you can say assume n equals is not equal to or assume
not n equals m equals zero.
It's hard to do this without code.
But you can make an assumption there so that it'll kick that one out.
That's how I would have done that.
But other than that, it's a really great introduction to the how to work with property based testing.
So I give it a thumbs up.
Then there's a second example, which is nice, too.
So that's cool.
I didn't know about assume.
So I'm very good to know about that.
The other thing that I think is a good thing to know about is example.
So like the example zero zero.
We specifically don't want to test that because we know it's broken or it's not defined.
But there are lots of cases where you're like, you know, somebody you're doing property based
testing on something and you get a defect of like, well, if I run these numbers, it fails.
And you're like, oh, well, we want to make sure we always run that.
So with example, you can say hypothesis.
You get to come up with the examples, except for always run this one also.
So and you can just kind of stack them up.
That's good.
Yeah.
And so for people listening, example is a decorator you put on your test at example and you put
a certain set of parameters that get called there.
Yeah, I just I kind of don't like that.
So examples is a decorator that you put on the outside to say, run this one always.
I'd like the reverse also to say this particular example, don't run it.
Because I know it's broken.
And the I mean, we get around it with the assume part, but it would be cool if there
was like a don't run this example.
Yeah.
It looks very helpful.
And I learned some things.
So excellent.
How about you?
What's next?
We got extras, extras, extras.
Are we done with our normal ones?
Wow.
Yeah.
Time flies when you're having fun, you know?
Yeah.
All right.
When we go first, you want to do yours?
I got a short one.
All right.
Go for it.
OK.
So my let's let's get rid of that.
We don't need that.
My example, my extra is just that this came in the mail and I'm really excited about
it.
So it's the Japanese version of Python testing with pytest.
It's been out for a little while in, I assume, Japan.
But it got translated.
I was in touch with the translator and they asked me a few questions.
Very respectful, dude.
And I'm glad.
And I'm like, can I get a copy?
And they sent me a few copies, actually.
So pretty exciting.
Fantastic.
Oh, that's really cool.
It's neat to see it.
It's neat to be reminded of the global reach.
Yeah.
And not just the cover.
The insides are there, too.
Amazing.
So you're going to learn Japanese?
Are you going to figure this out?
I do have a friend that speaks Japanese, so I'm going to go and see.
But they don't code.
Yeah.
It's all right.
I'm sure they'll find it riveting anyway.
Yeah, that's awesome.
What are your extras?
Well, a couple of things.
So it seems like I have survived the very first Python bytes on my new Mac Mini.
I just got, you know, Apple released the Mac Mini Pro M2, and I got that.
And so far, super, super neat.
I can recommend it.
It's a lot faster than the previous Mini.
So I mentioned that I used to have money, and then I had a Mini on order.
And now I actually have a Mini.
A new Mini.
It looks identical to the other, but it goes way faster, which is great.
Maybe I'll have more to say about that later.
All right.
So have you heard that Twitter is going through some turmoils?
I'm not sure.
I think something's going on over there.
The latest turmoil is that they decided to unceremoniously, unprofessionally cancel all the third-party Twitter apps.
That's just insane.
It's pretty insane.
I think it's, honestly, I think it's fine within Twitter's right to say, look, we don't want to have third-party apps.
We have a business model that doesn't work well.
There's not third-party Facebook apps.
There's not third-party Instagram apps, are there?
I don't think so.
Anyway, I think it's fine.
But the way that it was done was, oh, we're just going to cut them off.
And then in a few days, maybe somebody will say something.
What they said was, the reason we cut off things like TweetBot and other ones is because they violated the terms of service.
Like, wait, we've been doing this for 10 years.
What do you mean?
The reason they violated them is they went back and updated the terms of service to say we don't allow third-party apps.
That's the human violation of it.
I mean, it was just really weird.
Anyway, I want to just direct people who want to, you know, enjoy the moment technically and socially to tapbots.com slash TweetBot, where they put up a memorial to TweetBot.
Brian, isn't this a fantastic picture?
It really is.
There's this little elephant.
But it's all, like, 3D-looking, like claymation or something.
Yeah, it does look a little claymation-y.
And, you know, the mastodon elephant is at the gravestone of TweetBot.
And it has the life from April 2011 to January 2023 on the gravestone of TweetBot.
And it's just, anyway, it's pretty interesting.
The reason, partly I bring this up, not just for the picture, is if you're into mastodon, the same company decided, well, we're doubling down on mastodon and creating ivory,
which there's been a ton of talk about ivory being a really cool app for if you want something better than, say, the progressive web app for mastodon.
I know there are others out there as well, but a lot of people are really big fans of TweetBot and TapBot's the company.
And so you can now, this is now publicly available.
So there's that.
And anyway, I started using it.
I like it really well.
I don't use it exclusively over just using the progressive web app because the progressive web app has the advanced view where you have multiple columns.
You can create searches for hashtags and pin those as columns.
And it's really nice.
But this is quite a nice, nice app if you're not kind of doing that advanced view.
Oh, and by the way, Christopher Tyler has caught something incredible.
Yeah.
I have missed this.
This gravestone in the memorial happens to be on Mars, I think.
Yeah, it kind of looks like that.
Right.
That's awesome.
Why do you think it's on Mars?
I don't know.
Same thing in the simulation.
We're not sure about that.
Anyway, check out Ivory.
People can try that.
If you're in iOS, that's pretty good.
One more quick extra.
PyCon, PyCon, PyCon.
Yay.
I'm looking forward to this.
I got my tickets, Brian.
I'm going to be there for a week.
I'm going to try to be cruising around the sprints.
I might even take a day and try to go skiing.
I haven't decided.
We'll see what the weather's like out there.
But it's in Salt Lake City, of course.
However, I have news for you.
I haven't even told you this officially.
Okay.
But I have gotten us an official time and place at PyCon to do a live Python Bytes show.
Yay.
Awesome.
Yeah.
So we've previously kind of run around the first day and looked for somewhere where we
might be able to do something.
But we're supposed to have an official room and a time where we could actually live stream
it.
We can talk to people ahead of time if they really want, they're going to be there and
they want to come.
So we should be able to have a cool event at PyCon.
That's why I bring this up.
Yeah.
And it won't be on Tuesday then.
No, it won't be on Tuesday because it's Thursday night, Friday, Saturday, Sunday is the conference.
So it's going to be one of those days.
Awesome.
I'm looking forward to that.
I'll be there too.
Neither of us are speaking, but we'll do the live event.
And then Michael's going to probably interview absolutely everybody at the conference.
Yeah.
I'm trying something different this year.
You know, PacPython, primarily for the courses side of things, has had a booth on the expo
floor hall where I'll set up and meet people and show off the things we're doing.
And, you know, Brian, you've come a couple of years and hung out there.
We talked about Python Bytes and that booth as well, which is fantastic.
This year, I'm not doing that.
I just want to try to be around, have more, interact with more people and try to maybe do
some more on the spot shows and some other stuff like that.
Right.
So absolutely, we're going to be at PyCon.
We're going to be doing fun stuff, just not at a booth this time.
I'm going to try some variations on it this year.
Yeah.
And I think a lot of people, I think they should hit us up.
So especially if you thought about maybe asking to be on one of our shows, either yours or mine
or this one.
But you're a little nervous, then this is a great opportunity.
One, you don't have to be.
You could just contact us anyway.
But at PyCon, you can hit us up and say, hey, I was curious if this would fit.
And in person, sometimes it's easier to talk.
And I'll be bringing stickers, of course, to promote the book.
And I'm excited.
And also, I'll be at PyCascades before PyCon.
PyCascades is there.
It's coming up in March.
And I'm speaking there, too.
That's in Vancouver, right?
Yep.
Vancouver, BC.
Lovely.
I've been to the one in Vancouver.
I think the inaugural one was there.
And it's really, really nice there.
So excellent, excellent commerce.
I told my daughter I'm going and she's like, what's the big deal?
Vancouver's like 20 minutes away.
No, different Vancouver.
For those of you who don't know, the people who explored, the Europeans who explored the
Pacific Northwest, they didn't have a lot of creativity.
There's multiple Vancouver's.
There's like one just by Portland.
There's one up in BC.
Mount Hood, one of the most awesome mountains around here.
It's just named for the friend of some guy back in England who never even was here or looked
upon the mountain.
Really?
Oh, yeah.
It's awesome in a bad way.
Okay.
But yeah, the other, the northern, the Canadian Vancouver is a really nice place to go.
All right.
You ready for our joke, Brian?
Yeah.
So I feel like you and I can relate to this given our age here.
There's a post here that says from somebody named Mark the Cat Whisperer, but re-shared
by Rob Isaac.
Mark says, I'm a Gen Xer, so I adapt to new technology like a millennial, but I get angry about it like
a boomer.
I get that.
I get that too.
I'm definitely in the Gen X space and oh my gosh, I have more than one time yelled
at my, yelled at my computer.
I find personally the way, like the reason I connected with this joke so well is I get
mad at other people's technology because I'm like, I know this could be better.
Why have you not put an index here?
Why have you not auto-filled this?
You know, like, just like, I know you could make it better so easily.
What is wrong with you?
And then I guess the boomer side.
Yeah.
But the joke is Rob says, I didn't come here to be called out like this.
Funny.
All right.
Well, that's what I got for us.
Nice.
Well, thanks a lot, Michael, for joining us again today.
And on this 232, wait, 321st episode.
Wow.
Yeah.
It's like the amazing countdown.
We just don't know to what.
Three, two, one.
Contact.
It's the future.
Well, thanks everybody for joining.
And thanks, Michael.
And talk to everybody next week.