WEBVTT

00:00:00.140 --> 00:00:04.760
Hello and welcome to Python Bytes, where we deliver Python news and headlines directly to your earbuds.

00:00:04.760 --> 00:00:10.380
This is episode 277, recorded March 28th, 2022.

00:00:10.380 --> 00:00:11.920
And I am Brian Okken.

00:00:11.920 --> 00:00:13.340
I am Michael Kennedy.

00:00:13.340 --> 00:00:14.800
And I'm Thomas Geiger.

00:00:14.800 --> 00:00:19.120
Welcome, Thomas. Welcome to the show. Thanks for coming on and being a guest.

00:00:19.120 --> 00:00:21.700
Can you tell us a little bit about you?

00:00:21.700 --> 00:00:25.600
Thanks, Brian. And thanks, Michael. Big fan, so it's an honor being here.

00:00:26.060 --> 00:00:31.620
I'm the creator and maintainer of the PyPro Task Runner, which it so happens you discussed last week.

00:00:31.620 --> 00:00:34.720
So I come in riding on AtWave.

00:00:34.720 --> 00:00:36.280
Yeah.

00:00:36.280 --> 00:00:39.080
Yeah, very cool projects. Congrats on it.

00:00:39.080 --> 00:00:39.740
Thank you very much.

00:00:39.740 --> 00:00:42.380
Well, so, Michael, it's March.

00:00:42.380 --> 00:00:46.000
It is March. It's like March Madness, right?

00:00:46.000 --> 00:00:46.580
Yeah.

00:00:46.580 --> 00:00:52.680
So Chris May sent in this thing that says, hey, Python Bytes people, here's a fun thing to cover.

00:00:52.680 --> 00:00:54.820
For March Madness, but for Python.

00:00:54.820 --> 00:01:05.340
And for those of you who are not college basketball fans and follow it carefully, March Madness is basically the playoffs for the college basketball.

00:01:05.340 --> 00:01:07.100
And it's single elimination.

00:01:07.100 --> 00:01:09.540
You start with 16, I think.

00:01:09.540 --> 00:01:11.680
And then every team plays another one.

00:01:11.680 --> 00:01:13.220
Then it's down to eight, then down to four, and so on.

00:01:13.220 --> 00:01:15.380
So that's the idea, but for Python.

00:01:15.380 --> 00:01:16.020
Oh.

00:01:16.380 --> 00:01:17.440
And check it here.

00:01:17.440 --> 00:01:18.380
We have round one.

00:01:18.380 --> 00:01:21.420
I guess it starts with 32 and then 16 and so on.

00:01:21.420 --> 00:01:23.280
So we've got these different rounds.

00:01:23.280 --> 00:01:28.960
And some of the rounds have already occurred, but the winner, the champion, is still yet to be crowned.

00:01:28.960 --> 00:01:31.280
So you all need to get out there and vote.

00:01:31.280 --> 00:01:32.480
I'll tell you how in a second.

00:01:32.480 --> 00:01:35.720
A bit amazed NumPy is outdoing pytest there.

00:01:37.220 --> 00:01:39.040
It's outdoing it pretty handily.

00:01:39.040 --> 00:01:40.460
I mean, it did outdo it, right?

00:01:40.460 --> 00:01:43.580
So if you go here, what you see is this tournament bracket.

00:01:43.580 --> 00:01:46.220
And the first ones were like NumPy versus Redis.

00:01:46.220 --> 00:01:48.780
And NumPy won.

00:01:48.780 --> 00:01:52.580
And then pytest versus LXML, Parser.

00:01:52.580 --> 00:01:54.260
And pytest won that one handily.

00:01:54.260 --> 00:01:58.360
And then NumPy and pytest had to face off.

00:01:58.660 --> 00:02:04.620
And as Thomas said, surprisingly, NumPy pretty badly beat up on pytest.

00:02:04.620 --> 00:02:06.060
Brian, are you okay with this?

00:02:06.060 --> 00:02:06.560
How are you feeling?

00:02:06.560 --> 00:02:10.060
I didn't get to vote, so I'm not sure how this was done.

00:02:10.060 --> 00:02:10.900
Yeah.

00:02:10.900 --> 00:02:16.000
This is going to be the start of a long blood feud between the NumPy community and pytest.

00:02:16.000 --> 00:02:23.260
Well, and the other part of this story I'm telling, the other side of the bracket was Psykit-learn versus Beautiful Soup.

00:02:23.260 --> 00:02:26.320
And Beautiful Soup, oh my gosh, I think it was a buzzer beater.

00:02:26.440 --> 00:02:31.260
It came in at the last second, and it's like 52% to 48%, Beautiful Soup won.

00:02:31.260 --> 00:02:35.440
And so now this week, we're in the Elite Eight.

00:02:35.440 --> 00:02:37.780
And so you can come and vote.

00:02:37.780 --> 00:02:38.380
I'm going to vote.

00:02:38.380 --> 00:02:43.520
Like my metric here is sort of how useful and how impactful is this thing?

00:02:43.520 --> 00:02:44.880
Not necessarily do I like it better.

00:02:44.880 --> 00:02:46.360
So I'm going to vote over here.

00:02:46.360 --> 00:02:48.980
I'm going to say for NumPy versus Beautiful Soup, NumPy.

00:02:48.980 --> 00:02:53.140
I actually would use Beautiful Soup probably more, but I think NumPy is more impactful.

00:02:53.140 --> 00:02:56.180
Pip versus Matplotlib, I'll pip all day long.

00:02:56.620 --> 00:02:57.200
Same reason.

00:02:57.200 --> 00:02:58.860
Pandas versus Docker.

00:02:58.860 --> 00:02:59.860
Ooh.

00:02:59.860 --> 00:03:01.780
Ooh, I do like me some Docker.

00:03:01.780 --> 00:03:02.640
I'm going with Pandas.

00:03:02.640 --> 00:03:04.520
And then Wheel versus Request.

00:03:04.520 --> 00:03:05.420
I'm going to go with Request.

00:03:05.420 --> 00:03:09.780
I know Wheel is important under the covers, but I don't see it, so I don't want to think about it.

00:03:09.780 --> 00:03:10.820
So Request, top of mind.

00:03:10.820 --> 00:03:11.380
I use that all the time.

00:03:11.680 --> 00:03:17.180
So here you can see I voted, and everyone else who would like to can just click the link in the show notes, and you can vote too.

00:03:17.180 --> 00:03:22.360
And these are basically open for a week, and then the elimination happens, and it moves on.

00:03:22.360 --> 00:03:24.320
So we're going to see what happens in the final four.

00:03:24.320 --> 00:03:25.960
Coming real soon, actually.

00:03:26.360 --> 00:03:34.000
Okay, we're going to have to highlight this earlier in the month next year so that people can vote.

00:03:34.000 --> 00:03:37.960
You want to create some voting blocks like in the reality TV shows.

00:03:37.960 --> 00:03:39.520
The one on the island?

00:03:39.520 --> 00:03:40.380
Survivor?

00:03:41.040 --> 00:03:42.240
Yeah, Survivor, exactly.

00:03:42.240 --> 00:03:47.800
Oh, you know, I'm sad to say scikit-learn's torch has been extinguished.

00:03:47.800 --> 00:03:48.280
Oh, no.

00:03:48.280 --> 00:03:49.820
You're going to have to leave the island.

00:03:49.820 --> 00:03:50.780
Yes, that's right.

00:03:50.780 --> 00:03:53.660
Anyway, thank you, Chris, for sending this in.

00:03:53.660 --> 00:03:57.100
This is fun, and it's very low stakes.

00:03:57.100 --> 00:04:00.160
It's just sort of, you know, people just enjoy this for what it is.

00:04:00.160 --> 00:04:01.660
Yeah, bragging rights and whatnot.

00:04:01.660 --> 00:04:06.020
So we'll send out a tweet or something about it.

00:04:06.020 --> 00:04:07.440
You can get in there and check this out.

00:04:07.440 --> 00:04:08.520
Definitely.

00:04:08.520 --> 00:04:10.020
Yeah.

00:04:10.020 --> 00:04:10.600
How about you, Brian?

00:04:10.780 --> 00:04:11.420
What's your next one?

00:04:11.420 --> 00:04:16.420
I'd like to talk about NB Preview, which actually I thought we covered, but I couldn't find it anywhere.

00:04:16.420 --> 00:04:22.580
So NB Preview is a notebook previewer, so IPython or Jupyter notebook.

00:04:22.580 --> 00:04:26.400
And it's kind of neat.

00:04:26.400 --> 00:04:30.080
It's a command line thing, and I like to spend a lot of time on the command line.

00:04:30.080 --> 00:04:38.000
So you just, once you pip install it, or since it's not really part of your project, I used pipx.

00:04:38.000 --> 00:04:39.340
pipx installed this.

00:04:40.200 --> 00:04:40.440
Oh, yeah.

00:04:40.440 --> 00:04:56.600
But it's so you say NB Preview, and then you can give it some options, but then a notebook file name, and it will, it just previews your notebook in ASCII, which is awesome.

00:04:57.880 --> 00:04:59.600
But it's not just ASCII.

00:04:59.600 --> 00:05:00.200
It's rich.

00:05:00.200 --> 00:05:04.300
So we've got colors and nice colors and tables and stuff.

00:05:04.300 --> 00:05:07.360
There's actually quite a few features that I want to run down.

00:05:07.360 --> 00:05:13.120
One of the things I loved right away was it's not just a file.

00:05:13.200 --> 00:05:19.820
I tried it out on some local files, but you can give it like a URL or something.

00:05:19.820 --> 00:05:22.700
There's a great way to, you can get a whole bunch of stuff.

00:05:22.700 --> 00:05:25.360
You don't have to have local notebook files to put it in.

00:05:25.360 --> 00:05:25.940
Oh, that's cool.

00:05:26.980 --> 00:05:27.420
Yeah.

00:05:27.420 --> 00:05:27.420
So I'm going to see.

00:05:27.420 --> 00:05:27.780
Yeah.

00:05:27.780 --> 00:05:27.820
Yeah.

00:05:27.820 --> 00:05:28.420
So I'm going to see.

00:05:28.420 --> 00:05:28.740
Yeah.

00:05:28.740 --> 00:05:32.340
Here it's showing even you can curl something and pipe it to it.

00:05:32.340 --> 00:05:34.180
So it'll take inputs as pipes.

00:05:34.320 --> 00:05:39.400
And the fact that it's a command line tool and it deals with pipes correctly is what

00:05:39.400 --> 00:05:40.500
I really like about it.

00:05:40.500 --> 00:05:42.180
So you can pipe a notebook to it.

00:05:42.180 --> 00:05:45.520
I don't know if you do that or not, but you might want to pipe output.

00:05:45.520 --> 00:05:51.700
So by default, you get these nice colors, but if you pipe it to an output, you can pipe it

00:05:51.700 --> 00:05:54.400
to grep or something and you can grep for things.

00:05:54.400 --> 00:05:56.520
So this is kind of great.

00:05:56.520 --> 00:06:01.240
I don't know if you've ever tried to grep for something in a notebook, but there's a lot

00:06:01.240 --> 00:06:02.260
of junk around it.

00:06:02.260 --> 00:06:05.980
There's a lot of formatting stuff that, and if that's not really what you're looking for,

00:06:05.980 --> 00:06:06.740
it's not helpful.

00:06:06.740 --> 00:06:08.820
So be having this tool to strip that out.

00:06:08.820 --> 00:06:09.500
It's pretty nice.

00:06:09.500 --> 00:06:10.200
Oh yeah.

00:06:10.200 --> 00:06:11.040
That's really nice.

00:06:11.040 --> 00:06:13.500
I love the ability to just pull this up and view them.

00:06:13.500 --> 00:06:18.200
And given that it's based on rich, like it has formatting for all the cells.

00:06:18.200 --> 00:06:24.840
I mean, Jupyter is like markdown plus code and rich as rich highlighting for both of those.

00:06:24.840 --> 00:06:25.280
So that's cool.

00:06:25.280 --> 00:06:25.540
Yeah.

00:06:25.540 --> 00:06:29.620
It looks like it's got some pigments under the hood also, which happens.

00:06:29.620 --> 00:06:31.200
Ian brought up last week, I think.

00:06:31.200 --> 00:06:31.880
Yeah.

00:06:31.880 --> 00:06:32.580
Yeah, exactly.

00:06:32.580 --> 00:06:34.920
So a lot of continuations said this week.

00:06:34.920 --> 00:06:37.880
So a lot of cool stuff that you would expect, like code highlighting and stuff.

00:06:37.880 --> 00:06:43.980
But the thing that like really stood out to me is what does it do with images like graphs

00:06:43.980 --> 00:06:44.620
and stuff?

00:06:44.620 --> 00:06:46.680
And the images are kind of amazing.

00:06:46.680 --> 00:06:55.860
They're like these, by default, these block things, which not that clear to use for utilities,

00:06:55.860 --> 00:06:58.240
but it kind of shows you what it's going to do.

00:06:58.240 --> 00:07:00.000
And there's a few options.

00:07:00.180 --> 00:07:04.720
You can do this block level thing.

00:07:04.720 --> 00:07:06.620
And I like the characters.

00:07:06.620 --> 00:07:10.580
So it does like the ASCII art stuff of your images.

00:07:10.580 --> 00:07:14.000
Or it uses the Braille stuff.

00:07:14.000 --> 00:07:19.780
I don't know if there's an example here, but you can do Braille for all the dots to show up,

00:07:19.780 --> 00:07:21.060
which is kind of neat.

00:07:21.060 --> 00:07:23.700
It even does like cool data frame rendering.

00:07:23.700 --> 00:07:31.200
So if you've got a data frame printed out there in your notebook, it'll format it nicely.

00:07:31.200 --> 00:07:36.540
So even LaTeX is formatted, which is kind of a surprise.

00:07:36.680 --> 00:07:37.560
I didn't expect that.

00:07:37.560 --> 00:07:38.760
So that's kind of neat.

00:07:38.760 --> 00:07:44.080
Anyway, specifically, oh, cool, hyperlinks too.

00:07:44.080 --> 00:07:46.340
So you can click on HTML that's in there.

00:07:46.340 --> 00:07:47.020
That's kind of neat.

00:07:47.020 --> 00:07:52.480
The thing that I really like that is the simple part, though, is to be able to strip stuff

00:07:52.480 --> 00:07:54.560
and pipe it to grip and things like that.

00:07:54.560 --> 00:07:55.660
So this is handy.

00:07:55.660 --> 00:07:57.160
Nice.

00:07:57.160 --> 00:07:58.360
Thomas, what do you think?

00:07:58.360 --> 00:07:59.840
Oh, this is great.

00:08:00.480 --> 00:08:03.700
I don't really use notebooks all that much, to be honest with you.

00:08:03.700 --> 00:08:04.980
So it's a little bit lost on me.

00:08:04.980 --> 00:08:07.700
But more command line is absolutely good.

00:08:07.700 --> 00:08:10.060
And it looks delicious.

00:08:10.060 --> 00:08:12.280
Yeah, it does.

00:08:12.280 --> 00:08:17.920
It's the terminal, the TUIs, the terminal user interfaces are definitely coming on strong

00:08:17.920 --> 00:08:18.380
these days.

00:08:18.380 --> 00:08:20.600
We forgot to ask you, what kind of Python do you do?

00:08:20.600 --> 00:08:22.220
What's your flavor of Python?

00:08:22.220 --> 00:08:23.960
Are you building APIs?

00:08:23.960 --> 00:08:25.800
Are you doing data science?

00:08:25.800 --> 00:08:26.460
What kind?

00:08:26.460 --> 00:08:29.940
Well, the Piper project is what consumes most of my hours.

00:08:30.340 --> 00:08:34.760
So I guess that's normal-ish Python as opposed to notebook-ish Python.

00:08:34.760 --> 00:08:39.960
Data science, I don't really do too much either.

00:08:39.960 --> 00:08:44.100
So it's mostly traditional style Python programming.

00:08:44.100 --> 00:08:45.280
Yeah, got it.

00:08:45.280 --> 00:08:45.900
All right.

00:08:45.900 --> 00:08:47.120
Well, your topic is up next.

00:08:47.120 --> 00:08:47.640
Tell us about it.

00:08:47.640 --> 00:08:50.680
Well, funnily enough, this is very traditional programming.

00:08:50.680 --> 00:08:59.940
What I bring for you for your delectation is PyFakeFS, which I think is a sadly relatively

00:09:00.200 --> 00:09:02.120
unknown open source library.

00:09:02.120 --> 00:09:06.080
And I'd like to give them some props and recognition because I think it's amazing.

00:09:06.080 --> 00:09:09.860
And it's made a huge difference to me and my own code and the Piper project.

00:09:09.860 --> 00:09:12.380
So hopefully this helps out some other people.

00:09:12.820 --> 00:09:16.400
Now, what it is, is a fake file system.

00:09:16.400 --> 00:09:22.900
So in a nutshell, it intercepts all calls from Python to the actual file system.

00:09:22.900 --> 00:09:29.920
So if you think of the open function, the built-in open, that is, or shutil or pathlib, all of

00:09:29.920 --> 00:09:35.260
those that might have real-world side effects in terms of the disk, the fake file system will

00:09:35.260 --> 00:09:36.100
intercept these.

00:09:36.100 --> 00:09:37.740
And this is completely transparent.

00:09:37.740 --> 00:09:42.280
And which is to say that your functional code doesn't need to know about this.

00:09:42.280 --> 00:09:48.160
So the patching happens without you needing to inject something or without you needing to go

00:09:48.160 --> 00:09:52.420
and alter your actual code to take countenance of the system.

00:09:52.420 --> 00:09:58.360
Now, what's great about this is the moment you start talking about testing a file system, you're

00:09:58.360 --> 00:10:01.660
almost by definition in integration testing or functional testing terrain.

00:10:01.660 --> 00:10:06.340
Like it's not a unit test anymore, which comes with its own disadvantages.

00:10:06.880 --> 00:10:12.000
So if you do want a unit test, then let's consider a simplistic example, right?

00:10:12.000 --> 00:10:16.440
If you want to, if your code under test writes an output file.

00:10:16.440 --> 00:10:20.820
So first of all, you need to patch out that if you're in your unit testing framework with

00:10:20.820 --> 00:10:21.780
something like mock open.

00:10:21.780 --> 00:10:27.380
But secondly, you probably have a pathlib in there somewhere where you're either creating

00:10:27.380 --> 00:10:31.860
the parent directories for the path to check that they exist before you try and write to

00:10:31.860 --> 00:10:32.440
that location.

00:10:32.440 --> 00:10:34.900
So now we already have two things we have to patch out.

00:10:35.320 --> 00:10:38.980
And then on top of that, you might be doing it in a loop.

00:10:38.980 --> 00:10:43.340
You might be writing more than one file and the testing becomes very clumsy very quickly.

00:10:43.340 --> 00:10:51.320
Whereas once you use the PyFaEFS library, you can just write as normal, validate against

00:10:51.320 --> 00:10:53.540
that file system using the standard Python inputs.

00:10:53.540 --> 00:10:59.280
And what you end up with is, and once the test finishes, it all just goes out of scope and

00:10:59.280 --> 00:11:00.860
you don't even need to bother cleaning it up.

00:11:00.860 --> 00:11:01.840
What's...

00:11:01.840 --> 00:11:02.340
Yeah, that's cool.

00:11:02.340 --> 00:11:05.140
And you could specify the string that is the content to the file.

00:11:05.140 --> 00:11:07.440
So when the thing reads it, you can control the...

00:11:07.440 --> 00:11:08.140
Absolutely.

00:11:08.140 --> 00:11:08.580
What it sees, right?

00:11:08.580 --> 00:11:10.080
So it comes with a...

00:11:10.080 --> 00:11:11.440
And Brian, you're going to love this.

00:11:11.440 --> 00:11:14.300
It comes with a super handy pytest fixture.

00:11:14.300 --> 00:11:21.240
So if you are using pytest, which you should, you can just add the FS fixture to your unit test.

00:11:21.800 --> 00:11:27.900
And now everything in your unit test will be going to the fake file system rather than the

00:11:27.900 --> 00:11:29.640
real underlying fake file system.

00:11:29.640 --> 00:11:31.180
That's pretty cool.

00:11:31.180 --> 00:11:31.960
Yeah.

00:11:31.960 --> 00:11:37.980
And the helper functions allows you, like you were hinting at, Mike, you can specify encodings,

00:11:37.980 --> 00:11:38.920
you can write in binary.

00:11:38.920 --> 00:11:40.380
It's super useful.

00:11:40.600 --> 00:11:45.260
Something else that I use quite a lot is the ability to switch between Linux, Mac, and

00:11:45.260 --> 00:11:51.560
Windows file systems, which again, for Piper is such a boon to be able to test the cross-platform

00:11:51.560 --> 00:11:52.000
compatibility.

00:11:52.000 --> 00:11:52.740
Oh, interesting.

00:11:52.740 --> 00:11:58.260
So if it asks for like the representation from a pathlib thing, it'll do SQL and backslash

00:11:58.260 --> 00:11:59.320
instead of forward slash.

00:11:59.320 --> 00:12:00.700
Yeah, exactly right.

00:12:00.700 --> 00:12:07.160
So all of these things are, you know, I'm relatively conservative when it comes to pulling in new

00:12:07.160 --> 00:12:13.120
libraries because I'm, especially if the library feels heavy and I feel I can do it just using

00:12:13.120 --> 00:12:14.320
standard lib functionality.

00:12:14.320 --> 00:12:19.320
And also with some libraries, I'm a little bit worried that they might stop being maintained

00:12:19.320 --> 00:12:20.420
or something like that.

00:12:20.420 --> 00:12:25.800
But PyFakeFS has been around since 2006, developed by Google.

00:12:25.800 --> 00:12:28.400
It was open sourced in 2011.

00:12:29.180 --> 00:12:30.820
The maintainers are really on it.

00:12:30.820 --> 00:12:37.860
I submitted and had a PR merged earlier this year within an afternoon on a Saturday, which

00:12:37.860 --> 00:12:40.360
for open source is very quick.

00:12:40.360 --> 00:12:42.160
So they're on top of it.

00:12:42.160 --> 00:12:43.660
Great project.

00:12:43.660 --> 00:12:44.480
Check it out on GitHub.

00:12:44.480 --> 00:12:44.980
Check it.

00:12:44.980 --> 00:12:46.480
Check out the documentation too.

00:12:46.480 --> 00:12:49.460
It's well documented and it's super useful.

00:12:49.460 --> 00:12:51.260
And I was looking at the Toxinny.

00:12:51.260 --> 00:12:55.580
It looks like it's tested to be compatible with PyPy also, which is kind of nice.

00:12:55.580 --> 00:12:56.200
Yeah.

00:12:56.200 --> 00:12:57.420
Yeah, absolutely.

00:12:58.480 --> 00:13:03.800
Especially for what I'm doing in Piper, where wrangling configuration files is a lot of the

00:13:03.800 --> 00:13:05.340
functionality as a task runner.

00:13:05.340 --> 00:13:10.460
You're forever reading JSON, writing out YAML, converting between formats, converting between

00:13:10.460 --> 00:13:16.140
encodings, swapping out values inside configuration files, merging configuration files.

00:13:17.140 --> 00:13:25.780
And I'm now able to test all of this stuff without having to write integration tests for each and every permutation, which has been such a boon.

00:13:25.780 --> 00:13:28.480
This actually does way more than I thought it did.

00:13:28.480 --> 00:13:30.200
I'm going to check this out.

00:13:30.200 --> 00:13:30.700
This is neat.

00:13:30.700 --> 00:13:31.240
Yeah.

00:13:31.240 --> 00:13:32.460
There's a lot of cool stuff there.

00:13:32.460 --> 00:13:32.960
Absolutely.

00:13:33.740 --> 00:13:39.580
Chris and Alvaro both think pretty neat out there.

00:13:39.580 --> 00:13:40.400
They're digging it.

00:13:40.520 --> 00:13:40.660
Yeah.

00:13:40.660 --> 00:13:42.380
And I see the comment there.

00:13:42.380 --> 00:13:48.660
It is like temp path with the difference that it's not actually writing to the desk itself, of course.

00:13:48.660 --> 00:13:58.480
And what's also a little bit difficult when you're using the temp directory and the temp file modules is depending on how you're testing, it doesn't always help you very much.

00:13:58.480 --> 00:14:02.260
Because the thing that might be generating the file might be the code under test.

00:14:02.260 --> 00:14:07.380
So you're effectively going to have to intercept that and create a temp file to attach to it.

00:14:07.380 --> 00:14:09.240
And then the temp file will clean itself up.

00:14:09.240 --> 00:14:17.820
But that starts interrupting the flow of the functional code so much that I start questioning whether it's even a useful unit test anymore.

00:14:17.820 --> 00:14:19.560
Yeah, absolutely.

00:14:19.560 --> 00:14:20.900
Well, very, very cool.

00:14:20.900 --> 00:14:24.680
So, Brian, before we move on, let me tell you about our sponsor, all right?

00:14:24.680 --> 00:14:25.320
All right.

00:14:25.640 --> 00:14:30.640
This episode of Python Bytes is brought to you by Microsoft for Startups Founders Hub.

00:14:30.640 --> 00:14:32.660
Starting a business is hard.

00:14:32.660 --> 00:14:37.580
By some estimates, over 90% of startups will go out of business in just their first year.

00:14:37.580 --> 00:14:46.960
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.

00:14:46.960 --> 00:14:49.660
Microsoft for Startups Founders Hub was born.

00:14:49.660 --> 00:14:56.320
Founders Hub provides all founders at any stage with free resources to solve their startup challenges.

00:14:56.320 --> 00:15:04.940
The platform provides technology benefits, access to expert guidance and skilled resources, mentorship and networking connections, and much more.

00:15:04.940 --> 00:15:14.320
Unlike others in the industry, Microsoft for Startups Founders Hub doesn't require startups to be investor-backed or third-party validated to participate.

00:15:14.320 --> 00:15:17.040
Founders Hub is truly open to all.

00:15:17.040 --> 00:15:18.540
So what do you get if you join them?

00:15:18.540 --> 00:15:26.820
You speed up your development with free access to GitHub and Microsoft Cloud computing resources and the ability to unlock more credits over time.

00:15:26.820 --> 00:15:36.520
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.

00:15:36.520 --> 00:15:41.680
Through Microsoft for Startups Founders Hub, becoming a founder is no longer about who you know.

00:15:41.680 --> 00:15:55.220
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.

00:15:55.420 --> 00:16:00.480
You'll be able to book a one-on-one meeting with the mentors, many of whom are former founders themselves.

00:16:00.480 --> 00:16:05.580
Make your idea a reality today with the critical support you'll get from Founders Hub.

00:16:05.580 --> 00:16:10.040
To join the program, just visit pythonbytes.fm/foundershub.

00:16:10.040 --> 00:16:10.760
All one word.

00:16:10.760 --> 00:16:12.000
No links in your show notes.

00:16:12.000 --> 00:16:14.220
Thank you to Microsoft for supporting the show.

00:16:14.220 --> 00:16:15.000
Awesome.

00:16:15.000 --> 00:16:15.780
Thank you, Microsoft.

00:16:16.200 --> 00:16:24.280
Now, let me tell you about something that sounds incredibly simple, but as you kind of unwind it, you're like, wait, it does that too?

00:16:24.280 --> 00:16:25.320
Oh, it does that too?

00:16:25.320 --> 00:16:26.260
Oh, that's kind of cool.

00:16:26.260 --> 00:16:30.420
Pretty similar to the fake file system that Thomas was just telling us about.

00:16:30.420 --> 00:16:32.260
This thing called sternum.

00:16:32.260 --> 00:16:35.500
Sternum is a fantastic name.

00:16:35.940 --> 00:16:38.160
It's short for string enum, right?

00:16:38.160 --> 00:16:39.100
Enums.

00:16:39.100 --> 00:16:40.220
When were enums added?

00:16:40.220 --> 00:16:41.100
Was that three, four?

00:16:41.100 --> 00:16:42.440
Something like that.

00:16:42.440 --> 00:16:43.560
A little while ago.

00:16:43.560 --> 00:16:46.480
So enums have been in Python for a while.

00:16:46.480 --> 00:16:51.260
Pretty much prehistory now that those are no longer supported.

00:16:51.660 --> 00:16:57.320
And with enums, you can write cool code that says this class, its fields are enumerations.

00:16:57.320 --> 00:17:01.120
And then you can say, you know, enum type dot enum value.

00:17:01.120 --> 00:17:03.640
And you can use that instead of magic words.

00:17:03.640 --> 00:17:08.580
So, for example, you might have HTTP method or something like that.

00:17:08.580 --> 00:17:10.120
Or let's say HTTP status.

00:17:10.120 --> 00:17:12.920
Start with that one because that's like a built-in type thing you could do easily.

00:17:12.920 --> 00:17:20.100
You could have a 200, a 201, a 400, a 500, a 404, those kinds of things.

00:17:20.100 --> 00:17:24.920
So, you could have like HTTP statuses dot and then those types with those numbers, right?

00:17:24.920 --> 00:17:27.640
But there's a couple of challenges to working with those.

00:17:27.640 --> 00:17:32.820
Their natural representation is a number, not a string.

00:17:32.820 --> 00:17:37.080
And I know you can derive from enum and then also derive from string.

00:17:37.080 --> 00:17:39.820
But like I said, more stuff happening than just that.

00:17:39.820 --> 00:17:48.020
So, this sternum allows you to create enums like that and use the enum auto, enum.auto field.

00:17:48.020 --> 00:17:52.100
So, I can say, here's an HTTP method with like verbs is really probably what it should be.

00:17:52.100 --> 00:17:55.440
So, you can have a get, you can have a head and a post and a put.

00:17:55.440 --> 00:17:56.880
And you just say auto, auto, auto, auto.

00:17:56.880 --> 00:18:02.420
But the actual representation is that the get is a string get.

00:18:02.420 --> 00:18:09.300
And the like put one or post is, you know, put or post.

00:18:09.820 --> 00:18:09.920
Yeah.

00:18:09.920 --> 00:18:15.220
And Alvaro is out there pointing out, thank you, that sternum was temporarily part of 3.10, but that it was dropped.

00:18:15.220 --> 00:18:16.380
So, there was.

00:18:16.380 --> 00:18:19.080
I saw a note that it might be included in 3.11 again.

00:18:19.080 --> 00:18:19.780
Okay.

00:18:19.780 --> 00:18:20.680
That'd be fantastic.

00:18:20.680 --> 00:18:21.280
It would be.

00:18:21.280 --> 00:18:21.960
Yeah.

00:18:22.060 --> 00:18:23.480
So, there's some really neat stuff in here.

00:18:23.480 --> 00:18:33.480
For example, one of the things that's nice is because this thing basically has the value string, where you're using it, you can actually use it where a string would be accepted.

00:18:33.480 --> 00:18:45.540
So, here if you're doing a request to a URL and you've got to say method equals, here you can say method equals HTTP method dot head or whatever from the enum and it directly passes just the string head to the method.

00:18:45.540 --> 00:18:51.460
So, it's a really nice way to like gather up string values that are like part of a group, right?

00:18:51.460 --> 00:18:53.700
Like HTTP verbs or something like that.

00:18:53.700 --> 00:18:54.260
Wow.

00:18:54.260 --> 00:18:55.660
So, that's pretty neat.

00:18:55.660 --> 00:18:56.040
Okay.

00:18:56.040 --> 00:18:59.880
The side question is I don't really use auto much.

00:18:59.880 --> 00:19:03.140
Is auto used anywhere else or is auto just an enum?

00:19:03.140 --> 00:19:04.840
It comes out of the enum module.

00:19:04.840 --> 00:19:05.100
Okay.

00:19:05.100 --> 00:19:06.420
So, it's part of this.

00:19:06.420 --> 00:19:08.560
So, it's part of the enum thing.

00:19:08.560 --> 00:19:08.880
All right.

00:19:08.880 --> 00:19:14.100
And one of the things I really like about this that is super tricky with enums is databases.

00:19:14.100 --> 00:19:20.400
So, for example, imagine we had like get head and post.

00:19:20.400 --> 00:19:22.520
So, we just had auto, but it was an integer based one.

00:19:22.520 --> 00:19:23.560
So, it was like one, two, three.

00:19:23.560 --> 00:19:26.320
And we store it in the database, right?

00:19:26.320 --> 00:19:28.240
As a one or two or three and then you parse it back.

00:19:28.240 --> 00:19:28.500
Fine.

00:19:28.920 --> 00:19:34.060
But then somebody adds another auto thing in there and they don't put it at the end.

00:19:34.060 --> 00:19:35.740
They're like, oh, this one starts with a D.

00:19:35.740 --> 00:19:36.860
So, it goes after delete.

00:19:36.860 --> 00:19:37.520
Yeah.

00:19:37.520 --> 00:19:42.740
Well, all the stuff after that one is now off by one in the database, right?

00:19:42.820 --> 00:19:46.620
Like, so this, if it goes into the database, it goes in as a string and it'll parse back

00:19:46.620 --> 00:19:47.260
as the string.

00:19:47.260 --> 00:19:53.220
It also has cool stuff like lowercase sternum and uppercase string enum.

00:19:53.220 --> 00:19:55.180
So, you can derive from that instead.

00:19:55.180 --> 00:20:00.820
And then no matter how you define your field, you get a lowercase string version or an uppercase

00:20:00.820 --> 00:20:01.620
string version.

00:20:01.620 --> 00:20:02.280
Okay.

00:20:02.620 --> 00:20:04.740
And there's other cases as well.

00:20:04.740 --> 00:20:10.280
There's pascal case, snake case, kebab case, macro case, and camel case.

00:20:10.280 --> 00:20:10.480
Woo!

00:20:10.480 --> 00:20:12.060
Go crazy on them, people.

00:20:12.060 --> 00:20:17.340
And you can have the same code, but then like the string representation varies.

00:20:17.340 --> 00:20:19.440
So, that's pretty awesome.

00:20:19.440 --> 00:20:22.560
I think I'm going to go with kebab case just because that's fun to say.

00:20:22.560 --> 00:20:23.620
It's so fun.

00:20:23.620 --> 00:20:23.940
I know.

00:20:23.940 --> 00:20:29.240
And then, yeah, you can also directly assign the value.

00:20:29.240 --> 00:20:34.140
So, you know, enum value equals some string and then it like, right, you don't have to

00:20:34.140 --> 00:20:34.860
worry about a casing.

00:20:34.860 --> 00:20:36.240
It's exactly the string that you put.

00:20:36.240 --> 00:20:37.240
Right?

00:20:37.240 --> 00:20:39.160
So, there it is.

00:20:39.160 --> 00:20:41.580
It's like regular enum, but strings.

00:20:41.580 --> 00:20:47.060
And as people pointed out that it's not that different from what people have been considering

00:20:47.060 --> 00:20:47.840
for CPython.

00:20:47.840 --> 00:20:52.180
I'm pretty sure I'd heard about it as well in being in there, but the fact that it's not

00:20:52.180 --> 00:20:53.620
there, maybe it'll be there, maybe not.

00:20:53.620 --> 00:20:54.040
We'll see.

00:20:54.040 --> 00:20:54.660
It's interesting.

00:20:54.660 --> 00:20:56.060
But this has a lot of cool features.

00:20:56.380 --> 00:21:00.840
And if you're not using 3.11 or want to depend upon it, you know, this is a small little

00:21:00.840 --> 00:21:01.360
project.

00:21:01.360 --> 00:21:02.000
Yeah.

00:21:02.000 --> 00:21:02.840
It's nice.

00:21:02.840 --> 00:21:03.520
Cool.

00:21:03.520 --> 00:21:03.680
Yeah.

00:21:03.680 --> 00:21:04.880
Thomas, what do you think?

00:21:04.880 --> 00:21:06.480
This is great.

00:21:06.480 --> 00:21:15.020
I especially like how it's smart enough to autocast so that when you use the enum, it will end

00:21:15.020 --> 00:21:18.800
up translating to a string when you're actually hitting the database or your underlying API.

00:21:19.600 --> 00:21:19.820
Yeah.

00:21:19.820 --> 00:21:22.580
It makes it actually usable in those situations just directly.

00:21:22.580 --> 00:21:23.140
Yeah.

00:21:23.140 --> 00:21:24.300
Which I think is great.

00:21:24.300 --> 00:21:28.640
And funnily enough, the example they chose is so great by way of great documentation because

00:21:28.640 --> 00:21:33.840
HTTP verbs are just almost the example of magic strings, right?

00:21:33.840 --> 00:21:35.380
Yeah, exactly.

00:21:35.380 --> 00:21:36.100
Exactly.

00:21:36.100 --> 00:21:36.720
Yeah.

00:21:36.720 --> 00:21:37.460
Quite cool.

00:21:37.460 --> 00:21:38.580
All right.

00:21:38.580 --> 00:21:39.680
Ryan, over to you.

00:21:39.680 --> 00:21:41.780
I'd like to review your code a little bit.

00:21:41.780 --> 00:21:42.240
No.

00:21:43.840 --> 00:21:44.540
I don't know.

00:21:44.540 --> 00:21:45.900
I was trying to do a transition thing.

00:21:45.900 --> 00:21:50.500
But so Tim Hopper wrote this article, which I absolutely love.

00:21:50.500 --> 00:21:54.560
And it's called the Code Review Guidelines for Data Science Teams.

00:21:54.560 --> 00:21:57.880
And I just recommend everybody go read it.

00:21:57.880 --> 00:21:59.060
It's short.

00:21:59.060 --> 00:21:59.540
It's good.

00:21:59.540 --> 00:22:07.560
But one of the things I really like that he highlighted is before he got into the code review

00:22:07.560 --> 00:22:13.420
or the code review guidelines, he started with, why are we doing a code review?

00:22:13.860 --> 00:22:15.160
What is a code review for?

00:22:15.160 --> 00:22:20.680
And this is something I think that is important just to talk with whoever, whatever team is

00:22:20.680 --> 00:22:27.660
going on and talking, maybe even sticking it in a participation guideline in a project,

00:22:27.660 --> 00:22:34.340
open source project even, is that it's not just so that we can look at the code or check

00:22:34.340 --> 00:22:35.080
it to merge it.

00:22:35.080 --> 00:22:39.480
So his reasons for a code review are first code correctness.

00:22:39.480 --> 00:22:42.340
And that's what we think about is making sure the code's correct.

00:22:43.000 --> 00:22:45.560
But also code familiarity.

00:22:45.560 --> 00:22:47.220
Familiarity.

00:22:47.220 --> 00:22:52.380
So you might be the expert on a project and everybody else is only kind of new on it.

00:22:52.380 --> 00:22:58.580
You still should have code reviews for your code changes so that everybody else can watch also

00:22:58.580 --> 00:23:02.100
and get familiar with the changes going on.

00:23:02.100 --> 00:23:03.320
So that's nice.

00:23:03.320 --> 00:23:04.920
Design feedback, of course.

00:23:05.260 --> 00:23:10.700
mutual learning and regression protection are all the reasons why he did a code review.

00:23:10.700 --> 00:23:17.060
And the other thing I also love is what to leave out of a code review.

00:23:17.060 --> 00:23:22.160
So code reviews are not about trying to impose your guidelines on somebody else.

00:23:23.440 --> 00:23:29.220
And they're also not a reason to push off responsibility.

00:23:29.220 --> 00:23:32.060
So as long as your code's getting reviewed, it doesn't have to be correct, right?

00:23:32.060 --> 00:23:34.560
Because somebody will catch any problems.

00:23:34.560 --> 00:23:36.540
It's a bad thing to do in a code review.

00:23:36.540 --> 00:23:39.140
So make sure your code's correct.

00:23:39.500 --> 00:23:45.740
It's all cleaned up as soon as you, what you think is it's ready and then submit it, but

00:23:45.740 --> 00:23:46.940
then also be nice.

00:23:46.940 --> 00:23:49.560
So being nice is important.

00:23:49.560 --> 00:23:50.280
Yeah.

00:23:50.280 --> 00:23:50.880
Very cool.

00:23:50.880 --> 00:23:54.780
So then it goes, he goes through, I'm not going to go through all these here, but he goes through

00:23:54.780 --> 00:24:02.340
different things about what to think about before you do a, create a pull request and then what

00:24:02.340 --> 00:24:05.000
to do if you're reviewing a pull request.

00:24:05.000 --> 00:24:10.920
And a lot of these are just, they're just around being a kind human to the person on the other

00:24:10.920 --> 00:24:11.140
end.

00:24:11.140 --> 00:24:13.840
So that's really kind of what it's about.

00:24:13.840 --> 00:24:19.880
So I saw a mention in the summer that I really liked, which is, I mean, by nature, a code review

00:24:19.880 --> 00:24:21.060
is sort of nitpicky, right?

00:24:21.060 --> 00:24:24.480
You're paying attention to flaws, but it's nice to compliment.

00:24:24.480 --> 00:24:29.640
Also, like if there's something nifty or cool or cute, acknowledge compliment, call attention

00:24:29.640 --> 00:24:29.980
to it.

00:24:29.980 --> 00:24:32.260
Oh, that's a, that's a good point.

00:24:32.260 --> 00:24:33.220
And I really liked that.

00:24:33.220 --> 00:24:39.540
I also think, so one of the things that you don't want to do in a code review is like one

00:24:39.540 --> 00:24:42.560
of the guidelines is, is we're not looking for perfection.

00:24:42.560 --> 00:24:49.820
We're just, it's gotta, you know, that isn't one of the things we're looking for, but so what

00:24:49.820 --> 00:24:52.580
happens if you notice something and you're like, it's a little weird.

00:24:52.580 --> 00:24:53.300
It does it.

00:24:53.300 --> 00:24:56.240
I'd like to say something about it, but I don't know how to say that.

00:24:56.240 --> 00:25:01.880
His comment is to, to have, if you've got a minor thing that you want to comment on, go

00:25:01.880 --> 00:25:03.120
ahead and sort of tag it.

00:25:03.120 --> 00:25:07.980
He recommends tagging it with knit in it or a nitpick or something.

00:25:08.680 --> 00:25:14.860
Just to be clear that I'm, I don't know if I like the word knit, but to be clear, Hey,

00:25:14.860 --> 00:25:15.800
I noticed this.

00:25:15.800 --> 00:25:17.500
Maybe we want to change this in the future.

00:25:17.500 --> 00:25:22.520
Somehow indicate to the person that they don't need to fix this before the PR gets merged.

00:25:22.520 --> 00:25:23.880
You're just noticed it.

00:25:24.680 --> 00:25:29.820
So, and it might be something that the person that submitting the PR didn't realize in the

00:25:29.820 --> 00:25:31.760
first place and went, Oh yeah, I don't like that either.

00:25:31.760 --> 00:25:32.520
I'm going to fix it.

00:25:32.520 --> 00:25:34.760
Or yes, I do know about that.

00:25:34.760 --> 00:25:37.140
And I do plan on fixing it later or what, you know, whatever.

00:25:37.400 --> 00:25:40.280
So just an interesting guideline.

00:25:40.280 --> 00:25:46.180
And I think it can just, I'm kind of a, I've been on a kick lately of reading things about

00:25:46.180 --> 00:25:52.880
community and, and creating cohesive teams and the review process is definitely some somewhere

00:25:52.880 --> 00:25:56.380
to you need to have attention to for most teams.

00:25:56.380 --> 00:25:58.300
So anyway, that's it.

00:25:58.300 --> 00:25:58.940
Yeah.

00:25:58.940 --> 00:25:59.320
I like it.

00:25:59.320 --> 00:26:00.160
This is really handy.

00:26:00.160 --> 00:26:07.060
I love the idea of having as much as possible, have the automation, make the complaints.

00:26:07.360 --> 00:26:11.100
And like Thomas said, have the people give the compliments and the sort of interesting

00:26:11.100 --> 00:26:11.580
discussion.

00:26:11.580 --> 00:26:11.860
Right.

00:26:11.860 --> 00:26:14.860
But like if black can just take care of the formatting, like you shouldn't have to debate

00:26:14.860 --> 00:26:15.720
a formatting.

00:26:15.720 --> 00:26:16.220
Yeah.

00:26:16.220 --> 00:26:19.420
And if a linter can tell you, you know what, there's something wrong with this.

00:26:19.420 --> 00:26:21.400
Just like, let the linter be the bad guy.

00:26:21.400 --> 00:26:21.900
Yeah.

00:26:21.900 --> 00:26:25.960
It was one of the guidelines that he brought up, which is interesting is especially with CI

00:26:25.960 --> 00:26:32.140
and we're pushing a lot of things on black or, or linters that to wait.

00:26:32.140 --> 00:26:33.560
So wait a little bit.

00:26:33.560 --> 00:26:37.100
So don't, don't like review a code review right away.

00:26:37.320 --> 00:26:43.780
Especially not if the CI hasn't finished, let the CI finish and let the person creating

00:26:43.780 --> 00:26:46.300
it fix anything before you jump in.

00:26:46.300 --> 00:26:50.620
I also, that peeve of mine, don't comment on it right away.

00:26:50.620 --> 00:26:57.380
I might, one of the things I do frequently is I'll create a, a PR, especially for in a

00:26:57.380 --> 00:27:01.700
work setting, I'll create a PR and then I, there's some complicated things.

00:27:01.700 --> 00:27:07.000
So I plan on going through and writing some comments around some of the complicated bits.

00:27:07.000 --> 00:27:08.900
Like why did I do certain things?

00:27:08.900 --> 00:27:17.240
And, so if you see a PR right away, especially from me, wait 10 minutes or so before commenting

00:27:17.240 --> 00:27:17.620
on it.

00:27:17.620 --> 00:27:21.000
Cause I might, I might've answered your question before you get a chance to ask it.

00:27:21.000 --> 00:27:22.800
An exclamation might be coming.

00:27:22.800 --> 00:27:23.120
Yeah.

00:27:23.120 --> 00:27:23.640
Indeed.

00:27:23.640 --> 00:27:24.380
Anyway.

00:27:24.380 --> 00:27:25.860
Awesome.

00:27:25.860 --> 00:27:26.840
All right, Thomas.

00:27:26.840 --> 00:27:27.940
How are you?

00:27:28.060 --> 00:27:32.920
We're about to head into controversy because there's been, there's been some discord.

00:27:32.920 --> 00:27:34.640
Are you going to bash on something?

00:27:34.640 --> 00:27:35.060
Come on.

00:27:35.060 --> 00:27:39.380
I'm going to bash it over the head with a, like a caveman.

00:27:39.380 --> 00:27:40.280
Bash it with Python.

00:27:40.280 --> 00:27:47.000
So partly inspired on the continuation of last week's discussion, you had about running sub

00:27:47.000 --> 00:27:48.200
processes from Python.

00:27:48.200 --> 00:27:56.220
And, Itamar Turner-Trowing wrote an article this week called, please, please emphasis mine.

00:27:56.220 --> 00:27:58.040
Stop writing shell scripts.

00:27:58.040 --> 00:28:05.260
Now this, as you might imagine, raised a bit of questions on the usual places like Reddit

00:28:05.260 --> 00:28:12.480
and Twitter, but if nothing else, controversy aside, the article is a very good and succinct

00:28:12.480 --> 00:28:19.340
summary of the most common gotchas and problems with bash, which we can almost all summarize

00:28:19.340 --> 00:28:21.940
as that error handling is strange.

00:28:21.940 --> 00:28:27.920
If you're used to other programming languages, like bash is a kingdom unto its own when it

00:28:27.920 --> 00:28:29.460
comes to programming languages.

00:28:29.460 --> 00:28:35.760
So he also gives a great recommendation for if you really, really have to write in bash,

00:28:35.760 --> 00:28:37.640
uh, what you might want to do.

00:28:37.800 --> 00:28:45.020
And that would be to use the unofficial bash strict mode, which basically involves setting

00:28:45.020 --> 00:28:47.520
that bit of boilerplate on top of your bash.

00:28:47.520 --> 00:28:52.860
I'm not going to cover all the details, but basically the E and the U option will fail

00:28:52.860 --> 00:28:53.860
immediately on error.

00:28:53.860 --> 00:28:55.580
It will fail on unset variables.

00:28:55.580 --> 00:29:00.080
And if you add the pipe file option, errors won't pass between pipes.

00:29:00.080 --> 00:29:04.580
a pipe will actually fail immediately if there's an error process.

00:29:04.580 --> 00:29:05.580
Awesome.

00:29:05.580 --> 00:29:06.120
Like it should.

00:29:06.120 --> 00:29:08.120
Like it should indeed.

00:29:08.120 --> 00:29:14.300
But the point is there's batches on all technology and there's a lot of problems here.

00:29:14.300 --> 00:29:25.460
And let me add, although this article mostly aims at bash, I am very happy, including born and SSH and fish and take your pick underneath the same dictum.

00:29:25.840 --> 00:29:37.200
Now he goes on to talk about the typical reasons we hear of why we should be using bash of which the top one is, well, it's the most common.

00:29:37.200 --> 00:29:43.400
And you're guaranteed to have an SSH runtime, at least on any given machine that you're going to be using.

00:29:43.400 --> 00:29:55.300
But the point is not really because when we're doing code automation, almost by definition, the programming language or coding in its runtime is on the server.

00:29:55.300 --> 00:30:05.220
So this argument that somehow it's good to go to the lowest common denominator, AKA SH or bash, when you already have Python on the machine is sort of, well, why?

00:30:05.220 --> 00:30:12.540
And especially when we're talking about Python, which is so great at automation, it just baffles the mind.

00:30:12.540 --> 00:30:13.600
That's a good point there.

00:30:13.600 --> 00:30:16.540
You don't have to set up a compiler or any of that kind of business.

00:30:16.540 --> 00:30:17.940
I say the same thing about Golang.

00:30:17.940 --> 00:30:21.920
I mean, by definition, when you're compiling Go, the Go compiler is right there.

00:30:22.040 --> 00:30:26.360
You might as well be writing a Go script or whichever your programming language is.

00:30:26.360 --> 00:30:34.700
I mean, maybe if you're starting to talk about like C or C++, there's maybe a different argument that we can have there.

00:30:34.700 --> 00:30:47.460
The second point he brings up is what I'm going to paraphrase as get good, which is this bash guru response, which we saw a bit off in the last week, that you're just bad at bash.

00:30:47.880 --> 00:30:54.260
Like if you were better at bash, you wouldn't be complaining about these things, which is not a great reason.

00:30:54.260 --> 00:30:59.100
It's just because it's not better because it's hard, right?

00:30:59.100 --> 00:31:01.320
We have better tools available.

00:31:01.320 --> 00:31:04.640
We have tools that behave more responsibly.

00:31:04.640 --> 00:31:20.060
And something that I think is very important in line with what you've been talking about, Brian, about building teams is very often your automation activities start becoming this specialized zone that only two or three people on the team can even look at because they're the bash gurus.

00:31:20.060 --> 00:31:22.060
And everyone else is too afraid to touch it.

00:31:22.060 --> 00:31:29.180
Whereas if you keep your automation activities within the language you're coding in, suddenly everyone on the team can start carrying their weight, right?

00:31:30.280 --> 00:31:33.400
Yeah, I kind of relate to this a lot.

00:31:33.400 --> 00:31:40.400
I've been on projects where we've had a lot of our automation in bash and others that have been other languages.

00:31:41.680 --> 00:31:50.860
Right now, it was one of those things, especially if you're not looking on a Windows environment, bash isn't there all automatically.

00:31:50.860 --> 00:31:55.840
And a lot of the team members might not be familiar with it.

00:31:55.840 --> 00:32:04.420
So the thing that I don't know if he addresses this, the thing that I was thinking about was we all know Python if we're programming Python.

00:32:04.420 --> 00:32:13.700
But we might not all know the automation parts of it, the way to do like file manipulation or.

00:32:13.700 --> 00:32:14.100
Right.

00:32:14.100 --> 00:32:17.380
I say util and that kind of stuff.

00:32:17.380 --> 00:32:24.540
Stuff that we might be familiar with with bash because we, if we're using it all the time on the command line, I already know how to do it.

00:32:24.540 --> 00:32:30.920
But I might not know how to do that sort of stuff in Python because I'm not using Python like that.

00:32:31.140 --> 00:32:44.940
But anyway, well, my response to that would be that whatever the thing is that you don't know how to do in Python, your chances of running into trouble with bash are, to my mind, a lot higher than they are with Python.

00:32:45.420 --> 00:32:58.420
Or at least when things misbehave in Python, your control of flow is better so that you probably will have a, especially as the scripts start getting bigger, you will have better control over where the issues might be.

00:32:58.420 --> 00:33:03.200
Or you would be better able to isolate those areas that you're not exactly sure of.

00:33:03.800 --> 00:33:10.800
I saw someone in chat last week raise the specter of make files that call shell scripts that call make files.

00:33:10.800 --> 00:33:13.780
And I mean, this is not uncommon.

00:33:13.780 --> 00:33:15.460
I'm sure we've all seen these things.

00:33:15.460 --> 00:33:21.720
And I'm actually very interested in the psychology around this because we're all coders, right?

00:33:21.720 --> 00:33:24.700
I assume we're here because we enjoy automating things.

00:33:24.700 --> 00:33:26.200
We enjoy solving problems.

00:33:26.360 --> 00:33:33.240
We probably, you know, have a certain problem solving sort of mindset that got us into this to begin with.

00:33:33.240 --> 00:33:40.920
Yet, it seems like we spend so much time automating our customers' business processes that we forget to automate our own coding processes.

00:33:40.920 --> 00:33:43.960
Or when we do, we deallocate the priority.

00:33:43.960 --> 00:33:45.260
We de-budget it.

00:33:45.720 --> 00:33:49.660
We end up focusing on all sorts of other things other than this essential housekeeping.

00:33:49.660 --> 00:33:50.700
Yeah.

00:33:50.700 --> 00:33:55.200
Or treat it like a throwaway code instead of code that needs to be carefully factored.

00:33:55.200 --> 00:33:56.220
Exactly right.

00:33:56.220 --> 00:33:58.280
And I would argue it's a bit like housekeeping.

00:33:58.280 --> 00:33:59.980
You know, no one likes doing it.

00:33:59.980 --> 00:34:02.600
But if you don't want to live in a big star, you've got to do it.

00:34:02.600 --> 00:34:03.360
You know, instead.

00:34:03.360 --> 00:34:04.140
Yeah.

00:34:04.140 --> 00:34:10.980
Well, also, to be honest, I was there once of like, I don't know how to do this automation stuff in Python.

00:34:10.980 --> 00:34:13.580
But it bugged me that I didn't know how.

00:34:14.000 --> 00:34:16.720
So I'm like, okay, well, what do I need to learn?

00:34:16.720 --> 00:34:23.800
Like the few things like searching for stuff like I normally would have used Perl for Regex or something like that or said.

00:34:23.800 --> 00:34:25.940
All that stuff you can do with Python.

00:34:25.940 --> 00:34:27.780
And actually, there's tons of articles on it.

00:34:27.780 --> 00:34:32.780
It's really not that hard to go, okay, the pieces I'm missing, how do I do that?

00:34:32.780 --> 00:34:33.940
And just go learn it.

00:34:33.940 --> 00:34:38.200
And then it's not that hard to switch a lot of automation to Python.

00:34:38.200 --> 00:34:39.640
Yeah, definitely not.

00:34:39.640 --> 00:34:43.000
And I mean, so much other automation happens in Python anyway.

00:34:43.600 --> 00:34:48.980
I mean, in fact, kind of compiled programming languages will often use Python as an automation language.

00:34:48.980 --> 00:34:51.580
It's so handy for the automation process.

00:34:52.420 --> 00:35:04.020
There is another psychological thing, which I find, or I think psychological thing, that I find quite curious here, which is this dealing with complex shell scripts almost becomes this like technocratic rite of passage.

00:35:04.720 --> 00:35:15.440
Where when you couple that with imposter syndrome, you know, it's very easy to be intimidated by the bash bros when they do these really clever one-liner bashisms that you can't make head or tail off.

00:35:15.700 --> 00:35:17.700
And it's like, yeah, look how clever this is.

00:35:17.700 --> 00:35:19.540
But it's very hard to maintain.

00:35:19.540 --> 00:35:23.880
You don't, you know, and it's almost hard to call that to account unless you're very sure of yourself.

00:35:24.520 --> 00:35:28.260
Because you almost have to justify yourself as to why you dislike it.

00:35:28.260 --> 00:35:29.880
Like you first have to prove your bona fides.

00:35:31.320 --> 00:35:42.720
I think it's sort of the tech equivalent of, you know, back in my day, like we didn't have X, you know, like whatever X is, shoes or toilet paper or like whatever.

00:35:43.300 --> 00:35:48.280
Just because something used to be difficult doesn't mean it needs to be difficult forevermore, right?

00:35:48.280 --> 00:35:48.680
Yeah.

00:35:48.680 --> 00:35:51.720
Like the extra difficulty doesn't make it better.

00:35:51.720 --> 00:36:02.440
It's not a video game like Elden Ring, you know, like the easier this is, the more quickly and effectively you can do the housekeeping, the more you can get up with the features that actually pay the bills.

00:36:02.440 --> 00:36:07.340
Which is to say the shiny functional stuff that you can demo and put in front of customers.

00:36:07.340 --> 00:36:08.740
Yeah, absolutely.

00:36:08.740 --> 00:36:12.200
I have some real-time feedback and also a comment for you.

00:36:12.540 --> 00:36:17.740
Alvaro says there's a VS Code plugin called Shellshock, if he's remembering it correctly.

00:36:17.740 --> 00:36:20.300
Tells me when I'm doing something wrong or it might blow up.

00:36:20.300 --> 00:36:21.740
There's also a plugin for PyCharm.

00:36:21.740 --> 00:36:24.480
So if you're going to do it, you know, have those things for sure.

00:36:24.480 --> 00:36:35.780
Yeah, funnily enough, we've got immediate feedback to that, which is the author of the original article mentions Shellshock, which is effectively, like the commentator mentioned, a linter for Bash.

00:36:35.780 --> 00:36:40.500
But the article also mentions that it doesn't actually catch all things either.

00:36:40.780 --> 00:36:49.080
So like all linterers, it can very easily lull you into a false sense of security, while it's not really necessarily addressing the underlying problems.

00:36:49.080 --> 00:36:57.860
And I almost feel like I don't even need to say this because anyone who's ever tried to debug a long Bash script should know this.

00:36:57.860 --> 00:36:59.080
They're tricky.

00:36:59.400 --> 00:37:03.420
They fail in mysterious places, and it's very hard to figure out why and how.

00:37:04.220 --> 00:37:12.920
Yeah, but I do like this article pointing out how, if you have to, to set up those flags to make it, you know, fail quicker.

00:37:12.920 --> 00:37:13.120
Yeah.

00:37:13.120 --> 00:37:14.180
Because that helps a lot.

00:37:14.180 --> 00:37:15.520
So that's nice.

00:37:15.520 --> 00:37:16.060
Yeah.

00:37:16.060 --> 00:37:16.820
Yeah, for sure.

00:37:17.380 --> 00:37:21.100
And also, just to give the author massive amounts of credit, this isn't clickbait.

00:37:21.100 --> 00:37:24.820
He didn't position this as never, ever use Bash.

00:37:24.820 --> 00:37:35.680
In fact, he explicitly says that, okay, if you're doing something super simplistic, like the typical sort of things that goes into a get hook, a pre-commit hook, where you're just running a command or two, then yeah, sure.

00:37:35.800 --> 00:37:37.180
Of course, shell script's fine.

00:37:37.180 --> 00:37:46.360
But I would say as soon as you're running loops, as soon as you're doing conditional branching, as soon as you're worried about retries, as soon as you're doing...

00:37:46.360 --> 00:37:47.360
Oh, yeah, definitely.

00:37:47.360 --> 00:37:48.380
Switch to Python.

00:37:48.380 --> 00:37:48.960
Absolutely.

00:37:48.960 --> 00:37:50.060
Yeah.

00:37:50.060 --> 00:37:50.620
Yeah.

00:37:50.620 --> 00:37:53.260
And then another quick question, just a quick follow-up.

00:37:53.260 --> 00:37:55.740
Have you considered Conch?

00:37:55.740 --> 00:37:57.320
I've not even heard of Conch.

00:37:57.320 --> 00:37:58.440
I never mind considering it.

00:37:58.440 --> 00:38:02.900
So it's, I haven't done much, but I've sort of looked at it.

00:38:02.900 --> 00:38:13.740
It is a shell, like a competitor to Bash or ZShell or something like that, where it's a proper Python environment directly in the shell.

00:38:13.740 --> 00:38:15.880
That's almost PowerShell-esque.

00:38:15.880 --> 00:38:22.060
Yeah, it's a little bit like PowerShell, where PowerShell is like kind of .NET, C-sharp-like, kind of, but not really.

00:38:22.060 --> 00:38:24.500
I suspect it's similar here, but...

00:38:24.500 --> 00:38:30.540
And I know it's supposed to be pronounced Conch, but my brain says Zaunch, because it's funner to say.

00:38:30.540 --> 00:38:30.860
Zaunch.

00:38:30.860 --> 00:38:32.480
I know, but it has the shell.

00:38:32.640 --> 00:38:34.800
It has the shell, so you know that's how you got to say it.

00:38:34.800 --> 00:38:37.540
Yeah, they even have the Asgard going on for the logo.

00:38:37.540 --> 00:38:38.400
That's interesting.

00:38:38.400 --> 00:38:39.960
They do indeed.

00:38:39.960 --> 00:38:40.540
They do indeed.

00:38:40.540 --> 00:38:41.940
All right.

00:38:41.940 --> 00:38:42.760
Well, cool, Thomas.

00:38:42.760 --> 00:38:43.660
That was a good conversation.

00:38:43.660 --> 00:38:43.880
That was good.

00:38:43.880 --> 00:38:46.180
So do we have any extras?

00:38:46.180 --> 00:38:48.080
Michael, do you have any extras?

00:38:48.080 --> 00:38:50.380
You know I got extras, right?

00:38:50.380 --> 00:38:55.240
I also, first, real quick follow-up, a real-time follow-up from Henry Scheiner in the audience,

00:38:55.240 --> 00:38:59.560
that pep663 was the PEP around string enum.

00:38:59.560 --> 00:39:00.040
Oh, okay.

00:39:00.040 --> 00:39:05.300
And he's not sure if removing the support for that PEP means removing string enum from the standard lib or not, though.

00:39:05.300 --> 00:39:10.780
Doesn't do all the other stuff like the casing and the various other things that that cool package I talked about does.

00:39:10.900 --> 00:39:16.480
So maybe that package is, no matter what, relevant still or inspiration for the next one or whatever, right?

00:39:16.480 --> 00:39:19.560
In terms of extras, I do have some extras.

00:39:19.560 --> 00:39:22.360
Let me see what order I wanted to cover them in.

00:39:22.360 --> 00:39:24.600
I had two, but then one got rescheduled.

00:39:25.140 --> 00:39:33.260
This is supposed to be the transformation from bugs.python.org over to GitHub, but that got pushed back a week, so I'm not going to talk about that.

00:39:33.260 --> 00:39:34.720
You just did.

00:39:34.720 --> 00:39:38.020
Well, I was going to say it's happening.

00:39:38.020 --> 00:39:39.620
It should have happened by the time you hear this.

00:39:39.620 --> 00:39:40.100
Go check it out.

00:39:40.100 --> 00:39:41.420
No, it's not true anymore.

00:39:41.420 --> 00:39:42.780
No, okay.

00:39:42.780 --> 00:39:49.260
Just if you're curious, supposedly it's moved to April 1st, but it's April Fool's Day, so I'm not sure if it's really going to happen or not.

00:39:50.260 --> 00:39:54.340
Maybe it's a long con where the joke is being set up for in advance.

00:39:54.340 --> 00:39:55.680
Yeah, exactly.

00:39:55.680 --> 00:39:57.020
Oh, we're actually never doing this.

00:39:57.020 --> 00:39:57.260
No.

00:39:57.260 --> 00:39:58.840
I'm looking forward to that happening.

00:39:58.840 --> 00:39:59.240
That's great.

00:39:59.240 --> 00:39:59.820
All right.

00:39:59.820 --> 00:40:06.940
I just have like a general theme of sort of stuff that's like thrown all together, kind of a changing of the guard, if you will.

00:40:06.940 --> 00:40:07.360
Okay.

00:40:07.360 --> 00:40:08.560
Let's see here.

00:40:08.560 --> 00:40:12.280
So I have been switching so much of my software stuff around.

00:40:12.280 --> 00:40:13.560
I've started using Vivaldi.

00:40:13.560 --> 00:40:18.900
Now I've been using Firefox for a long time, but I started using Vivaldi, which I think is a really neat take on a browser.

00:40:19.620 --> 00:40:22.460
So I switched over to Vivaldi and started using that.

00:40:22.460 --> 00:40:24.820
You know, there's a bunch of different things.

00:40:24.820 --> 00:40:28.720
Like Mozilla laid off 250 people recently.

00:40:28.720 --> 00:40:31.660
They're axing the developer tools team too, which is just tragic.

00:40:31.660 --> 00:40:31.920
Exactly.

00:40:31.920 --> 00:40:33.580
Cut the developer tools team.

00:40:33.580 --> 00:40:38.820
They cut the threat team, the team that looks for like a tactic.

00:40:38.820 --> 00:40:41.580
It's like, I don't know.

00:40:41.580 --> 00:40:42.900
It's starting to make me a little nervous.

00:40:42.900 --> 00:40:44.100
So I'm trying out Vivaldi.

00:40:44.100 --> 00:40:47.740
I've been doing that for like a month or so, and I'm enjoying that.

00:40:47.960 --> 00:40:54.200
Mike, you said it's a different take on a browser or like, so it sounds like there's something conceptually different about it.

00:40:54.200 --> 00:40:56.160
It's just super customizable.

00:40:56.160 --> 00:40:57.380
I think that's the thing.

00:40:57.380 --> 00:40:59.660
It's like, there's just all sorts of stuff.

00:40:59.660 --> 00:41:01.980
It comes with a built-in ad blockers and tracker blockers.

00:41:01.980 --> 00:41:04.560
I know some of them do tracker blockers, but built-in ad blockers.

00:41:04.560 --> 00:41:04.880
Nice.

00:41:04.880 --> 00:41:06.740
I mean, Brave is the other one that kind of does that.

00:41:06.800 --> 00:41:11.580
But Brave is like, well, let's just trade those ads for our cryptocurrency ads that we'll put in there for you.

00:41:11.580 --> 00:41:12.800
And you get a little bit of cryptocurrency.

00:41:12.800 --> 00:41:14.560
This is like, no, we'll just block the ads.

00:41:15.440 --> 00:41:22.740
So anyway, I switched over to that, partly motivated by just concern around this, but also just wanted to try some stuff out.

00:41:22.740 --> 00:41:27.380
From Google Docs over to Zoho for other stuff and for like business email.

00:41:27.380 --> 00:41:29.000
There's so interesting stuff going on there.

00:41:29.000 --> 00:41:30.580
And then like also DuckDuckGo.

00:41:30.920 --> 00:41:33.680
I've been using that for a while and I tried that a while ago.

00:41:33.680 --> 00:41:35.840
It just, I didn't feel like you switched.

00:41:35.840 --> 00:41:41.860
To me now, there's just like almost no difference in the quality compared to Google these days.

00:41:41.860 --> 00:41:44.940
Where it used to be, I'd try and like, I might have to go to Google for that.

00:41:44.940 --> 00:41:46.760
Like, you know, several times a day.

00:41:46.760 --> 00:41:47.440
No, I don't really.

00:41:47.440 --> 00:41:51.580
If I get stuck here, usually I try to go to Google and get it and I get still stuck.

00:41:51.580 --> 00:41:53.540
So just got to deal with it.

00:41:53.540 --> 00:41:55.620
So that's it for all my items.

00:41:55.620 --> 00:41:56.900
I'm just down to telling a joke.

00:41:56.900 --> 00:42:00.080
Thomas, you got anything extra you want to share throughout the area of the world?

00:42:00.320 --> 00:42:01.000
Not particularly.

00:42:01.000 --> 00:42:02.500
I'm looking forward to your joke.

00:42:02.500 --> 00:42:03.700
Give a quick shout out to Piper real quick.

00:42:03.700 --> 00:42:04.060
Oh yeah.

00:42:04.060 --> 00:42:06.140
Check out last week's episode.

00:42:06.140 --> 00:42:07.760
I know we covered it last week, but yeah.

00:42:07.760 --> 00:42:11.060
Michael actually did as good an introduction to Piper as I could give.

00:42:11.060 --> 00:42:13.440
So congratulations and well done.

00:42:13.440 --> 00:42:14.260
Thank you.

00:42:14.260 --> 00:42:16.560
If you do want to check it out, support open source software.

00:42:16.560 --> 00:42:20.340
Do the usual share, like, subscribe, all the rest of it.

00:42:20.340 --> 00:42:21.540
You can check it out on GitHub.

00:42:21.540 --> 00:42:25.360
It is the Piper Task Corner, P-Y-P-Y-R.

00:42:25.360 --> 00:42:29.460
And incidentally, if you don't want to run Bash scripts,

00:42:29.720 --> 00:42:34.960
then a Task Corner might be a good way of not doing so.

00:42:34.960 --> 00:42:36.240
Yeah.

00:42:36.240 --> 00:42:39.600
I was thinking about your project while you were talking about this.

00:42:39.600 --> 00:42:41.440
I don't want to shill too horribly.

00:42:41.440 --> 00:42:44.520
So I try to keep that to the end.

00:42:44.520 --> 00:42:45.900
That's our job.

00:42:45.900 --> 00:42:46.480
We only shill.

00:42:46.480 --> 00:42:49.280
We basically just shill cool stuff all week.

00:42:49.280 --> 00:42:50.000
That's our podcast.

00:42:50.000 --> 00:42:51.160
Ryan, how about you?

00:42:51.160 --> 00:42:52.920
Got anything extra you want to shout out there?

00:42:53.200 --> 00:42:55.960
I've got some stuff, but there's nothing I can share right now.

00:42:55.960 --> 00:42:56.900
So, yeah.

00:42:56.900 --> 00:42:57.280
All right.

00:42:57.280 --> 00:42:58.620
Well, we'll be waiting.

00:42:58.620 --> 00:43:00.360
How about we share a joke then and wrap it up?

00:43:00.360 --> 00:43:00.780
Sounds good.

00:43:00.780 --> 00:43:06.700
So I feel like this is a missed opportunity because we had Ian on last week and he was all about

00:43:06.700 --> 00:43:10.400
cybersecurity and using notebooks to track threats and stuff.

00:43:10.940 --> 00:43:13.040
Well, has he considered this?

00:43:13.040 --> 00:43:19.160
That was in a James Bond movie, right?

00:43:19.160 --> 00:43:21.240
It's been several.

00:43:21.240 --> 00:43:22.540
It could have been.

00:43:22.820 --> 00:43:27.360
So here is like a big server rack with just, you know, like a hundred Ethernet cables.

00:43:27.360 --> 00:43:32.580
And in a big printed sign on it says, in case of cyber attack, break glass, pull cables.

00:43:32.580 --> 00:43:35.920
I'll also say what surprises me.

00:43:35.920 --> 00:43:42.900
The Internet is going soft in its old age because back in my day, the first comments would have

00:43:42.900 --> 00:43:44.700
been complaining that the cables aren't tidy enough.

00:43:44.700 --> 00:43:47.160
Wow.

00:43:47.160 --> 00:43:48.540
You got to get a good grip on it.

00:43:48.540 --> 00:43:48.760
Yeah, exactly.

00:43:48.760 --> 00:43:52.360
There's one zippy move with your arm and you give it a yank.

00:43:52.360 --> 00:43:53.360
You need good cable management.

00:43:53.360 --> 00:43:54.240
This is exactly why.

00:43:54.240 --> 00:43:55.420
There's a lot of cables.

00:43:55.420 --> 00:43:58.980
They should put like orange tags on the ones that are important to pull or something.

00:43:58.980 --> 00:43:59.740
Yeah.

00:43:59.740 --> 00:44:00.820
Exactly.

00:44:00.820 --> 00:44:02.840
This is the sort of criticism that I would have expected.

00:44:02.840 --> 00:44:09.140
Actually, the entire thing has a power switch just to power off the whole thing.

00:44:09.140 --> 00:44:10.600
You don't want to lose data.

00:44:10.600 --> 00:44:11.480
I mean, come on.

00:44:11.480 --> 00:44:12.000
No, just kidding.

00:44:12.000 --> 00:44:13.840
Also, where's the axe?

00:44:13.840 --> 00:44:15.360
How do you break the glass?

00:44:15.360 --> 00:44:16.560
Exactly.

00:44:16.560 --> 00:44:19.480
Oh, or just open the door handle.

00:44:19.480 --> 00:44:21.840
Very, not very thought through.

00:44:21.900 --> 00:44:23.340
It reminds me a little bit of that.

00:44:23.340 --> 00:44:25.860
In case fire, git commit, git push, run.

00:44:25.860 --> 00:44:31.840
I mean, you know, also we're talking about IT people who generally probably aren't, you

00:44:31.840 --> 00:44:33.440
know, that much into the pushing regime.

00:44:33.440 --> 00:44:34.840
So, you know.

00:44:34.840 --> 00:44:36.280
Or lifting axes.

00:44:36.280 --> 00:44:38.680
You know, that might be a strain.

00:44:38.680 --> 00:44:40.400
Sorry.

00:44:40.400 --> 00:44:41.820
I'm going to get hate mail for that.

00:44:41.820 --> 00:44:42.340
Oh, we are.

00:44:43.600 --> 00:44:44.280
Yes, indeed.

00:44:44.280 --> 00:44:47.220
Well, I thought it was fun, Brian.

00:44:47.220 --> 00:44:52.180
So, well, thanks everybody for having a fun episode again.

00:44:52.180 --> 00:44:54.160
Thank you, Thomas, for showing up.

00:44:54.160 --> 00:44:54.960
Thanks, Michael.

00:44:54.960 --> 00:44:57.520
And thank you, everybody in the chat for showing up.

00:44:57.520 --> 00:44:58.920
So, we'll see you all next week.

00:44:58.920 --> 00:44:59.680
Bye, everyone.

