WEBVTT

00:00:00.001 --> 00:00:04.520
Hello and welcome to Python Bytes, where we deliver Python news and headlines directly to

00:00:04.520 --> 00:00:12.320
your earbuds. This is episode 178, recorded April 15th, 2020. I am Brian Okken. I'm Michael

00:00:12.320 --> 00:00:17.980
Kennedy. And this episode is brought to you by DigitalOcean. Who's first? I think I got my notes

00:00:17.980 --> 00:00:21.740
wrong. Yeah. Well, I want to talk about something really quick before we actually get to the first

00:00:21.740 --> 00:00:26.020
one. So we'll see. Okay. I just want to tell people about the YouTube channel. And obviously,

00:00:26.020 --> 00:00:28.820
if people are watching on YouTube, they might know about the YouTube channel.

00:00:29.340 --> 00:00:35.580
But most people subscribe to our podcast and we are multicasting and repurposing what we're doing

00:00:35.580 --> 00:00:39.820
here on YouTube. We talked a little bit about it last time. So basically, each individual item

00:00:39.820 --> 00:00:46.300
is now a separate YouTube video. And you can watch Brian and me talk about it if you want to consume

00:00:46.300 --> 00:00:51.040
in that format and have a little bit of video and admire Brian's awesome shirts because he's got a

00:00:51.040 --> 00:00:54.220
bunch he's going to be wearing throughout these different shows and it's going to be awesome.

00:00:54.220 --> 00:00:58.320
Oh, you didn't have to set it up like that, man. I only have like one good shirt.

00:00:58.680 --> 00:01:03.400
People loved the shirt for the first video we shared. That was like several comments about,

00:01:03.400 --> 00:01:04.560
dude, your shirt is awesome.

00:01:04.560 --> 00:01:10.040
Yeah. Go figure. Okay. So we're trying to teach you about Python also, but...

00:01:10.040 --> 00:01:11.020
That's right. And fashion.

00:01:11.020 --> 00:01:11.500
Shirts.

00:01:11.500 --> 00:01:12.180
And fashion.

00:01:12.180 --> 00:01:12.440
Yeah.

00:01:12.440 --> 00:01:15.800
Yeah. It's pythonbytes.fm/YouTube. People could check that out.

00:01:15.800 --> 00:01:18.240
Well, tell me about strings, Python. I mean, Michael.

00:01:19.300 --> 00:01:22.820
I'll tell you about Python strings. You know what? Strings are confusing, man.

00:01:22.820 --> 00:01:30.120
Especially when they're about numbers and dates, especially dates. So this seems to be like a

00:01:30.120 --> 00:01:36.260
problem that vexes me permanently. And it's, you know, we talked about is programming Googling,

00:01:36.260 --> 00:01:42.260
right? Like in our consensus was, you know, maybe in the early stages of your career, there's a lot of

00:01:42.260 --> 00:01:47.400
Googling, but no, not really. You mostly just sit down and you think about the problems and you write

00:01:47.400 --> 00:01:52.440
the code and you evolve the code. Like there's a lot of reading code before you actually do much

00:01:52.440 --> 00:01:53.160
writing anyway.

00:01:53.160 --> 00:01:59.820
But this topic in particular, I'm all about Googling this all the time. So Python has a

00:01:59.820 --> 00:02:09.240
datetime.strptime for string pars time. You give it some piece of text like Wednesday, April 15th,

00:02:09.240 --> 00:02:16.040
comma 10 colon 30 a.m. without a space. I want to take that and turn it into a datetime so I can

00:02:16.040 --> 00:02:20.300
maybe compare it to something else, right? Like another time. How many days is that from now? Is

00:02:20.300 --> 00:02:24.180
that in the future is in the past. I just need to store it in the database as not a string,

00:02:24.180 --> 00:02:27.580
but a datetime because I want to order by it. I don't want it to be alphabetical, right? There's

00:02:27.580 --> 00:02:34.460
all sorts of reasons you need to get a datetime from strings or go in the reverse. And yet the format,

00:02:34.460 --> 00:02:42.280
you know, that's strptime has a, it has a format string that tells it how to look at the string and

00:02:42.280 --> 00:02:47.980
then pull the pieces out. So would you know about that example I told you about like the Wednesday,

00:02:48.120 --> 00:02:51.940
April 15th, 10 30 a.m.? That's definitely something I Google every single time.

00:02:51.940 --> 00:02:56.700
Every time. And it's never quite right. So just for those of you listening, you really want to know

00:02:56.700 --> 00:03:03.280
it's percent a space percent capital B space percent capital H comma space percent capital M colon percent

00:03:03.280 --> 00:03:06.340
S a.m. Woo. Who would ever come up with that?

00:03:06.340 --> 00:03:09.020
Well, I mean, these are intentionally short.

00:03:09.020 --> 00:03:09.640
Yes, I know.

00:03:09.720 --> 00:03:14.940
So that like they don't take up too much room, but they're and they sort of make sense. It's just

00:03:14.940 --> 00:03:19.680
it's arbitrary, whether it's a capital Y or a lowercase y or capital D or lowercase D.

00:03:19.680 --> 00:03:24.460
Right. And there's documentation you can go find. Like if you want the three letter date day of the

00:03:24.460 --> 00:03:28.120
week, that's a percent a lowercase and whatnot. But putting that all together can be tricky.

00:03:28.540 --> 00:03:36.280
So what I want to tell you about is this website by Lachlan Eaglin. And it's let me see what the URL is.

00:03:36.280 --> 00:03:42.000
It's high stir F time dot com, which, of course, is linked in the show notes.

00:03:42.540 --> 00:03:51.400
And the idea is you put the text you want to parse like Wednesday, April 15, April 2020 at the time or

00:03:51.400 --> 00:03:56.780
whatever. You put that in there and you hit go and it will tell you that complex string that I told you

00:03:56.780 --> 00:03:58.920
was the right answer to my parsing problem.

00:03:58.920 --> 00:04:00.460
Yeah, it's awesome.

00:04:00.460 --> 00:04:06.340
Yeah, you just put in like the output that you want it to have happen and it tells you the magical

00:04:06.340 --> 00:04:07.120
incantation.

00:04:07.120 --> 00:04:11.100
Right, right. Or the format of the thing you want to parse. And depending whether you're trying to go

00:04:11.280 --> 00:04:17.620
to that string or from that string. But yeah, super, super handy. This bad boy is bookmarked for

00:04:17.620 --> 00:04:22.820
me for sure, because this is way better than Googling. I can put it in there. It gives me a

00:04:22.820 --> 00:04:27.240
quick, quick answer. I can throw it into a Python REPL and see, hey, did it work or did it not work?

00:04:27.240 --> 00:04:28.020
It's really easy.

00:04:28.020 --> 00:04:29.060
Yeah, nice.

00:04:29.060 --> 00:04:34.800
Yeah. So not super complicated, but very handy. So people can bookmark that and try it out.

00:04:34.800 --> 00:04:39.500
Well, I want to tell you about something easier. Also, I got to kind of thank Jack.

00:04:40.020 --> 00:04:45.240
Jack McHugh has sent us a few suggestions and they're usually pretty darn nice. And here's this

00:04:45.240 --> 00:04:51.380
one's from Jack. Pandas dash bokeh. Bokeh? Oh, I forget how to say that.

00:04:51.380 --> 00:04:57.540
I love the logo. Pandas bokeh. I say bokeh. I don't know. You know, but it's like that F stop

00:04:57.540 --> 00:05:01.360
difference where like the person in a portrait is like crisp, but the background is faded.

00:05:01.360 --> 00:05:06.180
Yeah. And the logo is pandas clear bokeh, like in the background faded. It's beautiful.

00:05:06.180 --> 00:05:12.760
It's a pretty cool logo. So I'm going to quote some from their website or the readme. It says,

00:05:12.760 --> 00:05:19.400
pandas bokeh provides a bokeh plotting backend for pandas, geopandas, and PySpark dataframes,

00:05:19.400 --> 00:05:24.820
similar to the already existing visualization features of pandas. Importing the library adds

00:05:24.820 --> 00:05:32.100
a complimentary plotting method plot underscore bokeh on dataframes and series. Okay. So that's,

00:05:32.100 --> 00:05:38.880
I mean, it's already built in and all it provides is plot bokeh, another function on it. What's the

00:05:38.880 --> 00:05:44.780
big deal? Well, it's so cool. It's so easy. And I was, I tried out some of these examples this

00:05:44.780 --> 00:05:50.640
morning and it's just a little tiny bit of code and you call, like you've got a data frame and you

00:05:50.640 --> 00:05:56.660
call plot bokeh on it and it pops open like an interactive graph that you can look at everything.

00:05:56.660 --> 00:06:01.320
It's actually pretty incredible. You have to do something a little different. You can plot bokeh,

00:06:01.320 --> 00:06:07.660
but if you want the normal plotting to do the same awesome stuff that it's built in, you can set an

00:06:07.660 --> 00:06:14.360
option, one of the pandas options to switch out the plotting backend. So that's neat. So apparently

00:06:14.360 --> 00:06:20.500
what it's really doing is switching out the backend. And to me, I mean, it's plotting is not terribly

00:06:20.500 --> 00:06:26.320
difficult, but this interface, at least for me, it makes it a lot easier instead of having to work

00:06:26.320 --> 00:06:31.480
with frames and plots to just call this thing. And then all the different options you can have,

00:06:31.480 --> 00:06:36.520
you can, you know, different point, you know, want it to look like an asterisk instead of a point

00:06:36.520 --> 00:06:42.760
or something, all other different color, different scale or different titles. All that stuff is options

00:06:42.760 --> 00:06:47.980
you can pass into the plot function. And the other thing that I, that I like a few more things.

00:06:47.980 --> 00:06:54.440
One of them is you just, when you're pip install pandas dash bokeh, it pulls everything in because

00:06:54.440 --> 00:06:59.720
it's all the rest of the stuff is dependent on it. So you get all of it just for a simple install.

00:07:00.040 --> 00:07:05.500
And it also generates a general, it's able to do this interactively, but you can also generate

00:07:05.500 --> 00:07:11.200
notebooks. Yeah. Yeah. You can generate notebooks and you can also generate standalone HTML files

00:07:11.200 --> 00:07:12.140
with this in it.

00:07:12.140 --> 00:07:17.300
This is really cool. And yeah, the fact you can generate standalone HTML, there's probably ways

00:07:17.300 --> 00:07:22.680
to plug it into Flask sites, you know, Python websites and whatnot, pretty straightforward.

00:07:22.900 --> 00:07:29.740
And the interactive bit is super nice. I mean, this is not about pandas interaction per se. This is just

00:07:29.740 --> 00:07:35.500
bokeh, right? Being very cool and interactive, but you can zoom, you can pan as you move around,

00:07:35.500 --> 00:07:40.480
you know, like it'll show you the marks on the graph and you can hide, you know, and sort of hide and show

00:07:40.480 --> 00:07:46.520
elements. And there's even a cool example where they're showing the stock price of Apple versus Google.

00:07:46.680 --> 00:07:52.780
And as you put the cursor along, it has the Apple logo next to Apple and the information,

00:07:52.780 --> 00:07:57.960
like a little like card that talks about it over time, man, this is nice stuff. And all you got to

00:07:57.960 --> 00:08:00.300
do is point it at a data frame. Not bad.

00:08:00.300 --> 00:08:04.720
Yeah. And they've got a whole bunch of examples on there that GitHub repo with a bunch of working

00:08:04.720 --> 00:08:09.980
examples too. Obviously for the examples, the data is just sort of random data that they're

00:08:09.980 --> 00:08:14.580
throwing in there. But you know, once you know how to get your data, this does the rest of the work

00:08:14.580 --> 00:08:15.660
for you. So it's cool.

00:08:15.660 --> 00:08:19.120
Very cool. Yeah, it's just a great one. And thank you, Jack, for recommending it. And yeah,

00:08:19.120 --> 00:08:20.460
it's a good one, Brian, for pulling it out.

00:08:20.460 --> 00:08:24.600
We've had DigitalOcean as a sponsor for a while, and we really want to thank them. They've really

00:08:24.600 --> 00:08:29.720
helped us out a lot. And they're plus, they're pretty darn cool. So thank you, DigitalOcean for

00:08:29.720 --> 00:08:35.360
sponsoring this episode and many others. And in the past, we've told you about a lot of awesome things

00:08:35.360 --> 00:08:42.460
with DigitalOcean, like their one-click install Kubernetes cluster support, their amazing new support

00:08:42.460 --> 00:08:47.980
center and help documentation that's been around for a while. And our podcast runs on DigitalOcean,

00:08:47.980 --> 00:08:52.600
and we're thrilled with it. And so if your business or your side project deserves great

00:08:52.600 --> 00:08:59.080
hosting and that will grow with you and let you scale affordably, I really definitely want you to swing

00:08:59.080 --> 00:09:06.840
by pythonbytes.fm/DigitalOcean to grab the $100 credit for new users. But there's something else

00:09:06.840 --> 00:09:11.980
I want to tell you about DigitalOcean that's really cool. They've got something they've started recently

00:09:11.980 --> 00:09:19.220
that's called Hub for Good. And it's designed to support COVID-19 relief efforts where DigitalOcean

00:09:19.220 --> 00:09:26.400
through this is supplying $100,000 in infrastructure credits for new not-for-profit projects.

00:09:26.540 --> 00:09:34.180
They're also giving $50,000 to COVID-19 relief fund, their own relief fund, but still it's really cool.

00:09:34.180 --> 00:09:41.180
And they're also trying to raise awareness for COVID-19 related projects and provide learning for

00:09:41.180 --> 00:09:47.360
developers and also provide visibility for these projects. And so I headed over there this morning

00:09:47.360 --> 00:09:53.580
and checked it out. And there's a bunch of cool projects starting out that are related to COVID-19.

00:09:53.580 --> 00:09:58.320
It's not just this sort of stuff, but it's things like there's even a platform to help teachers

00:09:58.320 --> 00:10:04.640
interact with students during quarantine. A lot of cool projects through this. So thank you, DigitalOcean.

00:10:04.640 --> 00:10:08.600
Yeah, this is a great project. And obviously the infrastructure is great and we love it,

00:10:08.600 --> 00:10:10.860
but this is very cool too. I didn't know about this.

00:10:10.860 --> 00:10:11.620
Yeah, it's pretty neat.

00:10:11.780 --> 00:10:18.660
Yeah. So speaking of not knowing, I feel like I've been kind of exploring the cave of Python,

00:10:18.660 --> 00:10:24.640
which is large and vast. And I just come on like a whole nother area. I'm like, it opens up like,

00:10:24.640 --> 00:10:30.340
what is this? How have I not known about this? And this is NBDev. Have you heard of NBDev?

00:10:30.340 --> 00:10:30.800
No.

00:10:30.800 --> 00:10:37.200
Yeah. Okay. So let me tell you about it and I'll get your impressions later. So NBDev takes

00:10:37.200 --> 00:10:46.460
notebooks and basically makes them on par with writing proper Python packages and solves all

00:10:46.460 --> 00:10:50.540
these different problems. It lets you generate what's got to be some of the best documentation

00:10:50.540 --> 00:10:59.360
period for that library that is sort of backed by a notebook. So it lets you develop like full Python

00:10:59.360 --> 00:11:04.500
packages and libraries and notebooks where you can have all your code, your unit tests and your

00:11:04.500 --> 00:11:09.700
documentation all in one place, but then you can take it and pip and you can upload it to pip and

00:11:09.700 --> 00:11:13.040
make it a pip and solve a library that people have no idea that it came from a notebook.

00:11:13.040 --> 00:11:13.520
Wow.

00:11:13.520 --> 00:11:15.000
Is that crazy or what?

00:11:15.000 --> 00:11:16.780
That's awesome. I got to check that out.

00:11:16.780 --> 00:11:17.060
Yeah.

00:11:17.060 --> 00:11:21.840
Yeah. And you know, you think about this idea of notebooks and to me, notebooks like burst on the

00:11:21.840 --> 00:11:30.080
scene in the 2010-ish era, maybe 2012, 2011, like that timeframe. But this project references

00:11:30.080 --> 00:11:37.120
this concept envisioned by Donald Knuth way back in 1983. And it says notebooks finally made literate

00:11:37.120 --> 00:11:43.040
programming, this concept by Donald Knuth, a thing. So, you know, the old is new again, but in a really

00:11:43.040 --> 00:11:49.180
cool way. And to me, this seems like just such a massive upgrade to notebooks. So notebooks have a

00:11:49.180 --> 00:11:54.060
bunch of challenges in my view. Like I can't use a proper editor with it. Like if I don't use PyCharm or

00:11:54.060 --> 00:12:00.060
VS Code and all of its navigation and it's cool, get blame and like history and just like all this

00:12:00.060 --> 00:12:06.300
stuff is just not present, right? Documentation. I think that actually it really works well there,

00:12:06.300 --> 00:12:12.520
right? But it's, it doesn't tie the documentation of the notebook to like parts of functionality that

00:12:12.520 --> 00:12:16.160
might be created by the notebook, which is cool. One of the biggest problems with notebooks,

00:12:16.380 --> 00:12:22.140
it's a benefit, but it's a big problem is if you run a notebook, it stores the output in the notebook.

00:12:22.140 --> 00:12:29.240
So if you had like a bokeh plot or you had like a print of a data frame, that is in there and now it's

00:12:29.240 --> 00:12:35.540
part of it. So if I'm working on a project and you're working on the same project and we both run the notebook

00:12:35.540 --> 00:12:40.860
at different times or the same time, but separately, and it for some reason generates different results,

00:12:41.440 --> 00:12:49.540
that's a merge conflict in Git, right? So basically you cannot use notebooks in like a sane way with Git

00:12:49.540 --> 00:12:54.360
because anytime you work with it, if you're not careful and like don't remove all the output before

00:12:54.360 --> 00:13:01.140
you save it, it's going to be a merge conflict. So this project has a Git pre-commit hook that will

00:13:01.140 --> 00:13:06.800
remove that problem. So right before it gets committed, it'll automatically do the cleaning of that

00:13:06.800 --> 00:13:12.920
metadata output. So it'll never have that as a conflict. It also has an ability to like a CLI go

00:13:12.920 --> 00:13:19.560
just accept it. I just accept all the metadata changes. Mine are just right or whatever, right?

00:13:19.560 --> 00:13:24.220
So it also has a CLI to automatically fix that. But if you do have those problems, but it also has this

00:13:24.220 --> 00:13:25.840
pre-commit hook to avoid them entirely.

00:13:25.840 --> 00:13:27.820
Nice. That's a nice use for pre-commit too.

00:13:27.980 --> 00:13:32.800
Yeah. It's super, super clever. So if I write a function in the notebook, I can put hash export

00:13:32.800 --> 00:13:37.380
in that cell and that becomes a public function in the package.

00:13:37.380 --> 00:13:37.940
Oh, cool.

00:13:37.940 --> 00:13:43.060
Right. So I write like documentation and pictures and I would say hash export. Now that's part of my

00:13:43.060 --> 00:13:48.880
library that I'm building. It also lets you create the structure for Python packages. So you have like

00:13:48.880 --> 00:13:55.840
the setup py and you can do the build wheels and whatnot automatically out of that. And it uses this

00:13:55.840 --> 00:14:01.700
exported stuff. You can have your unit test in your notebook, which is pretty cool for the things that are in

00:14:01.700 --> 00:14:06.960
there. And then finally you can edit it. You can take the edited library or the library that exported,

00:14:06.960 --> 00:14:14.380
sorry, and then edit it with PyCharm or VS Code and then reverse export it. So what you can do is like say

00:14:14.380 --> 00:14:19.780
push the changes that I've done with my editor back into the segments of the notebook where that code came from.

00:14:19.780 --> 00:14:23.620
Oh man. Okay. I'm a little confused, but I got to try it out.

00:14:23.740 --> 00:14:28.180
Yeah. You got to kind of read through it to get the sense, but there's just a bunch of stuff going on. Like all these things seem like,

00:14:28.180 --> 00:14:32.800
yes, you should have been able to do that with notebooks, but obviously, right. That's not their origins, right?

00:14:32.800 --> 00:14:36.340
They can't do everything at once, but all of these things seem awesome to me.

00:14:36.340 --> 00:14:41.920
Yeah. Yeah. So in order to get started, it's going to basically create a Git repo for you is my understanding,

00:14:41.920 --> 00:14:48.000
either on GitHub or GitLab. So you got to follow the getting started instructions and then you click a button and it'll like generate the

00:14:48.000 --> 00:14:56.040
repo in the right structure, or you can use the CLI tooling to generate like the right repo with things like the Git commit prehooks and whatnot.

00:14:56.040 --> 00:15:01.060
And if you're going to read the docs, check out nbdev.fast.ai.

00:15:01.060 --> 00:15:07.420
Cause this comes from a fast AI people, the same one as the build, the FastAPI framework.

00:15:07.420 --> 00:15:13.360
So some of the docs render better. There's certain things on GitHub that like it says, and here's a cool picture.

00:15:13.360 --> 00:15:21.660
And it's just like source code. It's not quite right. So, so maybe check out the final link at the bottom in this section to get to,

00:15:21.820 --> 00:15:25.780
if you're going to like browse through it, but it's basically a, you get the same thing out of GitHub.

00:15:25.780 --> 00:15:33.540
Anyway, this to me seems like a massive improvement for notebooks and sort of brings them more into,

00:15:33.540 --> 00:15:41.600
I can do things like, for example, you can now have your notebook and its tests running as part of continuous integration.

00:15:41.600 --> 00:15:49.680
Like, so these networks are now like full participants in CI, CD, you can upload, you can like create packages and put them on pipe.

00:15:49.720 --> 00:15:55.100
Yeah. There's all sorts of neat stuff. The documentation, like if you have a cool graph as part of your notebook,

00:15:55.100 --> 00:15:58.180
that can become the documentation on pipe.

00:15:58.180 --> 00:16:02.800
I or read the docs for those functions. I mean, it's crazy cool.

00:16:02.800 --> 00:16:09.200
How, how this is like taking some of the awesome parts of notebooks, like the doc side and turn that into the help docs.

00:16:09.200 --> 00:16:13.720
And then also letting you export the functionality still as a proper CS type thing.

00:16:13.720 --> 00:16:15.880
Yeah. I definitely got to check this out.

00:16:15.880 --> 00:16:18.060
How did I not even know this existed? Like, this is awesome.

00:16:18.160 --> 00:16:21.840
Well, I don't know how long, I mean, it looks like, it looks like five months to me is my guess.

00:16:21.840 --> 00:16:23.920
Okay. So we're not that behind the ball.

00:16:23.920 --> 00:16:25.560
No, we're not that behind. Yeah.

00:16:25.560 --> 00:16:26.440
But this looks neat.

00:16:26.440 --> 00:16:27.160
Yeah. It's very neat.

00:16:27.160 --> 00:16:30.960
Plus Fast AI is pretty cool. So I think this is probably pretty solid.

00:16:30.960 --> 00:16:34.740
Yeah, I agree. It's definitely got some solid people behind it. So very cool. Very cool.

00:16:34.740 --> 00:16:37.180
Anyway, NB Dev, quite neat.

00:16:37.280 --> 00:16:51.660
I want to talk about something a little not neat, a little lighthearted. So this is a sort of a serious topic, but this is a article from Sebastian entitled Stop Naming Your Python Modules Utils.

00:16:52.460 --> 00:17:06.480
And I don't think we've, I don't know if we've covered it before, but it's good advice. And it's something that happens. Basically, a lot of projects, public or private, will at some point end up having a utils.py or a utils package or something.

00:17:06.480 --> 00:17:22.620
And this article is just saying, resist the urge. Utils is arguably one of the worst names for modules because it's very blurry and imprecise. Some of the names did not say what such a name does not say what the purpose of the code inside is.

00:17:22.620 --> 00:17:37.520
And on the contrary, utils module can well contain almost anything. By naming a module utils, software developer lays down perfect conditions for an incohesive or uncohesive whatever code blob.

00:17:37.840 --> 00:17:49.060
And I have definitely seen this in action. I have been one of the culprits before of having a pulling out a little helper function that I had in one file.

00:17:49.060 --> 00:17:58.600
And I wanted to use it in a different module. So I didn't know where to put it. So I stuck it in a utils.py, added a couple more. So there's just a few methods.

00:17:58.600 --> 00:18:07.480
And I come back six months later and there's like a couple dozen just junk drawer functions from all over the place in there.

00:18:07.480 --> 00:18:15.880
So if you start, people will add junk to it. So Sebastian lists a few excuses. It's just one function, but it grows.

00:18:15.880 --> 00:18:21.760
There's no other place in the code to put it. Well, try harder. And I need a place for company comments.

00:18:21.760 --> 00:18:27.060
I don't even really know what that means, but name it company or something. And also Django does it.

00:18:27.060 --> 00:18:32.180
Well, I don't know if you're a, well, maybe they shouldn't have, but they have it now, so they're not going to change it.

00:18:32.580 --> 00:18:44.460
So the advice is to try name, try grouping your utility functions and naming them based on the role of how you're going to use it, or possibly group them in themes.

00:18:44.460 --> 00:18:54.560
And also, if you see a utils.py crop up in a code review, just request that the person rename it to something else, if possible.

00:18:54.560 --> 00:18:58.100
Just set up a CI rule to break the build if you see that file name.

00:18:59.300 --> 00:19:01.820
Yeah. So what are your thoughts on this, on the utils?

00:19:01.820 --> 00:19:03.980
See, I agree with Sebastian. Absolutely.

00:19:03.980 --> 00:19:12.780
I understand the challenge because naming things in software is hard, but naming things in software is super important.

00:19:12.780 --> 00:19:18.840
Because when you think about even just function names or class names or whatever,

00:19:19.300 --> 00:19:25.640
usually what will happen is they'll get like a crummy, vague name and then a comment describing what they are doing.

00:19:25.640 --> 00:19:30.380
And you're like, well, why don't you just make the name a little bit longer that says what it does?

00:19:30.380 --> 00:19:35.880
And utils is kind of like the generic catch-all of saying like, well, I couldn't come up with a name.

00:19:35.880 --> 00:19:36.860
So here it is.

00:19:36.860 --> 00:19:38.200
We're just going to drop it here.

00:19:39.200 --> 00:19:51.680
And in my code, I have like tons of different areas of which I organize it, you know, sort of like sub modules, I guess, if it's a, or sub packages, if it's a package, but not, sometimes it's not technically a package.

00:19:52.160 --> 00:19:55.280
And I try to come up with names that are meaningful, right?

00:19:55.280 --> 00:20:04.260
Like I have something called number converter that will like try to parse an integer or return a default value instead of throwing an exception or it'll try to parse some other thing.

00:20:04.260 --> 00:20:08.240
Or maybe it's called conversions.py or whatever, but it's not like utils, right?

00:20:08.240 --> 00:20:15.140
Like there's, there's usually some kind of a better structure you can find that will help you do this.

00:20:15.140 --> 00:20:20.820
But, you know, there's that joke that, you know, naming things in computer science, that's one of the hardest problems, right?

00:20:20.900 --> 00:20:25.060
And I do agree with that, but yeah, it's, it's worth the effort when you get it figured out.

00:20:25.060 --> 00:20:27.440
If you don't believe me, you can just try it sometime.

00:20:27.440 --> 00:20:32.380
If you're working on group project, just put one function in utils and you will see it grow.

00:20:32.380 --> 00:20:33.880
And you'll have to find it.

00:20:33.880 --> 00:20:37.200
Is this like the broken window theory of software?

00:20:37.200 --> 00:20:38.400
Yep.

00:20:38.400 --> 00:20:40.560
And MISC doesn't count either.

00:20:40.560 --> 00:20:42.420
If you'd name it MISC, it's just as bad.

00:20:42.420 --> 00:20:43.280
That's right.

00:20:43.280 --> 00:20:44.660
Yeah.

00:20:44.660 --> 00:20:48.300
There's probably some synonyms here in the code world that don't count.

00:20:48.300 --> 00:20:48.740
So yeah.

00:20:48.740 --> 00:20:49.020
Awesome.

00:20:49.020 --> 00:20:56.200
I want to tell you about this one next that helps with performance or understanding that performance more specifically of your code.

00:20:56.200 --> 00:21:00.860
So I don't know if you, how much profiling you guys do your work.

00:21:00.860 --> 00:21:02.820
How much does performance matter to you guys?

00:21:02.820 --> 00:21:03.800
It matters a lot.

00:21:03.800 --> 00:21:04.080
Yeah.

00:21:04.080 --> 00:21:04.440
Yeah.

00:21:04.440 --> 00:21:05.180
Yeah.

00:21:05.180 --> 00:21:09.920
I'm building things that go into testing in a production line.

00:21:09.920 --> 00:21:15.880
So every millisecond that it takes, takes a millisecond longer to get something shipped.

00:21:15.880 --> 00:21:16.600
So yes.

00:21:16.600 --> 00:21:17.360
It matters.

00:21:17.360 --> 00:21:17.840
Yeah.

00:21:17.840 --> 00:21:18.180
It matters.

00:21:18.180 --> 00:21:22.260
I'm supposed to mostly spend my time on the web and obviously it matters there, right?

00:21:22.260 --> 00:21:23.820
Like every hundred milliseconds.

00:21:23.820 --> 00:21:29.540
I think Amazon measured is like 1% loss of orders or something ridiculous like that, right?

00:21:29.540 --> 00:21:31.860
Like, so understanding your performance is good.

00:21:32.200 --> 00:21:37.040
We've had good, good in quotes, profilers for Python.

00:21:37.040 --> 00:21:42.220
And they typically tell you about this function spent this much time.

00:21:42.500 --> 00:21:47.620
But another challenge is my program is using too much memory or worse.

00:21:47.620 --> 00:21:50.880
It's something long running like a web app or some background process.

00:21:50.880 --> 00:21:52.300
And it's like growing.

00:21:52.300 --> 00:21:55.900
It's like sort of leaking memory.

00:21:55.900 --> 00:21:57.180
Why is that?

00:21:57.180 --> 00:22:06.920
So I came across this project called Scaling, which is a high performance and high precision CPU and memory profiler for Python.

00:22:06.920 --> 00:22:07.260
Cool.

00:22:07.260 --> 00:22:07.660
Yeah.

00:22:07.660 --> 00:22:15.760
So it lets you either analyze CPU time or it actually lets you on a line by line basis say, here's some memory.

00:22:15.760 --> 00:22:18.980
What line made this and where is it coming from?

00:22:18.980 --> 00:22:19.780
Yeah.

00:22:19.780 --> 00:22:20.960
And so that's cool.

00:22:20.960 --> 00:22:28.160
But one of the challenges for profiling is when you're profiling your code, you can make it, you don't get the same behavior.

00:22:28.160 --> 00:22:31.260
It's sort of like the Heisenberg uncertainty principle, right?

00:22:31.260 --> 00:22:35.120
It does one thing, but when you measure the profiler, you've changed it.

00:22:35.180 --> 00:22:43.160
So now you kind of got to say, well, that part where it was the network, that was 50%, but now you made the computational bits way slower.

00:22:43.160 --> 00:22:45.440
So that network part looks just like 20, right?

00:22:45.440 --> 00:22:46.540
Like you're affecting it.

00:22:46.540 --> 00:22:56.000
So for example, if you use profile, the built-in profile, it can make your code 30 times faster or a simple scenario than running it normally.

00:22:56.460 --> 00:22:59.800
But you can use C profile, which is the C based one that's built in.

00:22:59.800 --> 00:23:03.160
It only slows it down by 1.65 times.

00:23:03.160 --> 00:23:04.380
So that's not too bad.

00:23:04.380 --> 00:23:07.040
There's a line profiler that's 11 times slower.

00:23:07.040 --> 00:23:08.860
And there's a whole bunch of other ones.

00:23:08.860 --> 00:23:12.580
There's a memory profiler that's like over a thousand times slower.

00:23:12.920 --> 00:23:17.640
So the scaling thing has a nice comparison to all these things.

00:23:17.640 --> 00:23:19.500
It says, well, how does scaling do?

00:23:19.500 --> 00:23:23.200
And it claims that it's got this built-in library that's much faster.

00:23:23.200 --> 00:23:26.680
So for CPU stuff, it's 1.04 times the speed.

00:23:26.680 --> 00:23:28.300
So like 4% slower.

00:23:28.880 --> 00:23:31.040
And it does that through sampling, right?

00:23:31.040 --> 00:23:32.060
It doesn't do instrumentation.

00:23:32.060 --> 00:23:33.540
It doesn't rewrite the stuff.

00:23:33.540 --> 00:23:36.580
It actually just asks frequently like, hey, where are you in the code?

00:23:36.580 --> 00:23:40.480
But it still gets per line analysis of that, which is pretty cool.

00:23:40.480 --> 00:23:45.620
And then the memory one is like another 10% slower because analyzing memory is hard.

00:23:45.620 --> 00:23:49.160
But yeah, there's all sorts of cool stuff you can do with it.

00:23:49.160 --> 00:23:51.040
The overhead is not too bad.

00:23:51.040 --> 00:23:52.880
The precision is pretty good.

00:23:52.880 --> 00:23:58.760
So like I said, it gives you like line by line level of how much time you're spending in various places.

00:23:59.440 --> 00:24:04.520
It also is interesting in that it separates out the time spent running Python code from native code,

00:24:04.520 --> 00:24:06.860
including like the base libraries and stuff.

00:24:06.860 --> 00:24:11.260
So you can say like, I can only affect the Python stuff.

00:24:11.260 --> 00:24:14.380
The other stuff is not a thing I can deal with.

00:24:14.380 --> 00:24:18.200
So yeah, don't tell me about it or punish me for it.

00:24:18.200 --> 00:24:19.840
Or maybe I do want to look at it, right?

00:24:19.840 --> 00:24:20.600
Tell me about that.

00:24:20.600 --> 00:24:21.700
So that's pretty cool.

00:24:21.700 --> 00:24:25.480
And then also the memory stuff I think is pretty cool.

00:24:25.480 --> 00:24:28.700
So it says it points to specific lines of code responsible for memory.

00:24:28.700 --> 00:24:29.360
Memory growth.

00:24:29.360 --> 00:24:31.000
And it's important.

00:24:31.000 --> 00:24:35.440
It does this through a special memory allocator thing that comes with it.

00:24:35.440 --> 00:24:41.860
And so while you can pip install Scalene, you can't inspect the memory allocation that way.

00:24:41.860 --> 00:24:44.620
You have to go and install it directly and do some more setup.

00:24:44.620 --> 00:24:46.600
On macOS, you can do brew install.

00:24:46.600 --> 00:24:48.280
There's instructions in there on how to do that.

00:24:48.280 --> 00:24:50.340
On other OSes, I have no idea what you do.

00:24:50.880 --> 00:24:54.020
But you can't run the memory allocation directly.

00:24:54.020 --> 00:24:57.200
You can't just say pip install it and then do the memory allocator.

00:24:57.200 --> 00:25:00.600
There's some other lower subsystem that has to get installed for that to work.

00:25:00.600 --> 00:25:00.920
Yeah.

00:25:00.920 --> 00:25:06.520
And memory is an interesting one because it's a difficult one to chase down with Python.

00:25:06.520 --> 00:25:06.940
Yeah.

00:25:06.940 --> 00:25:09.480
It's very hard in Python because everything is a pointer.

00:25:09.480 --> 00:25:10.920
Everything is an indirection.

00:25:11.320 --> 00:25:16.820
It's not like, well, here's the block where we allocated this object or whatever, right?

00:25:16.820 --> 00:25:18.620
Like it's pretty indirect.

00:25:18.620 --> 00:25:25.820
And you don't typically have a hold of pointers in the memory address sense of it like you do in C or something, right?

00:25:25.820 --> 00:25:26.820
So yeah, it's challenging.

00:25:26.820 --> 00:25:30.000
I would love to see this integrated into PyCharm and VS Code.

00:25:30.000 --> 00:25:30.680
Oh, yeah.

00:25:31.020 --> 00:25:37.200
Right now, it just gives you a cool tabular text output or file output.

00:25:37.200 --> 00:25:41.940
But if you could just right click in PyCharm and say, analyze with scalene, that'd be sweet.

00:25:41.940 --> 00:25:42.440
Yeah, I wonder.

00:25:42.440 --> 00:25:45.420
And also, that would solve some of the install thing.

00:25:45.420 --> 00:25:50.160
So if you have to install it separately, some integration with PyCharm VS Code would be cool.

00:25:50.160 --> 00:25:50.420
Right.

00:25:50.420 --> 00:25:52.020
Like right now, you can do profiling.

00:25:52.020 --> 00:25:54.380
And it's really awesome in PyCharm.

00:25:54.380 --> 00:25:55.860
But I'm pretty sure it uses C profile.

00:25:55.860 --> 00:25:57.240
So yeah, who knows?

00:25:57.240 --> 00:25:57.880
Someday, baby.

00:25:58.540 --> 00:26:01.220
Hey, while we're talking about editors, I don't know about VS Code.

00:26:01.220 --> 00:26:06.680
But I do know, backing up a little bit, I do know that PyCharm does open notebooks okay.

00:26:06.680 --> 00:26:07.380
Awesome.

00:26:07.380 --> 00:26:07.980
Yeah.

00:26:07.980 --> 00:26:08.640
Just back there.

00:26:08.640 --> 00:26:09.040
Anyway.

00:26:09.040 --> 00:26:09.700
Yeah, yeah, nice.

00:26:09.700 --> 00:26:12.420
I want to tell you a little bit about testing.

00:26:12.420 --> 00:26:12.780
Awesome.

00:26:12.780 --> 00:26:15.320
I'm really surprised that you're covering this.

00:26:15.320 --> 00:26:15.980
But okay, yeah, go ahead.

00:26:15.980 --> 00:26:19.360
Yeah, it's interesting.

00:26:19.360 --> 00:26:21.440
Lately, you've been covering the testing articles.

00:26:21.440 --> 00:26:21.920
I know.

00:26:21.920 --> 00:26:23.040
Isn't that my role now?

00:26:23.040 --> 00:26:24.020
No, go ahead.

00:26:24.020 --> 00:26:24.500
This is great.

00:26:24.500 --> 00:26:25.060
Tell us about it.

00:26:25.060 --> 00:26:25.400
Yeah.

00:26:25.700 --> 00:26:31.740
This is a person named Carolyn that wrote an article called From 1 to 10,000 Test Cases

00:26:31.740 --> 00:26:35.280
in Under an Hour, A Beginner's Guide to Proper...

00:26:35.280 --> 00:26:35.940
That's productive.

00:26:35.940 --> 00:26:39.520
And imagine if Carolyn was getting paid by the test, right?

00:26:39.520 --> 00:26:42.100
Like, we're evaluating your bonus for the year.

00:26:42.100 --> 00:26:45.540
Like, I wrote five times as many tests as anyone else, and I just started this month.

00:26:45.540 --> 00:26:46.840
Heck yeah.

00:26:47.360 --> 00:26:48.500
I would totally use...

00:26:48.500 --> 00:26:52.700
If I was paid by the test case, I would definitely use Hypothesis on every project.

00:26:52.700 --> 00:26:54.600
All right.

00:26:54.600 --> 00:26:55.560
So how did she do this?

00:26:55.560 --> 00:26:57.420
What is this property-based testing?

00:26:57.420 --> 00:26:57.940
Okay.

00:26:57.940 --> 00:27:00.940
So hopefully people have heard of property-based testing, but it is...

00:27:00.940 --> 00:27:01.940
So the...

00:27:01.940 --> 00:27:05.780
It's as opposed to, like, what do we call it?

00:27:05.780 --> 00:27:07.100
Example-based testing.

00:27:07.100 --> 00:27:07.780
So...

00:27:07.780 --> 00:27:10.480
And this is kind of how she goes through this discussion.

00:27:10.940 --> 00:27:11.300
It's...

00:27:11.300 --> 00:27:16.160
The article is really just a really excellent introduction to property-based testing and

00:27:16.160 --> 00:27:17.260
using Hypothesis.

00:27:17.260 --> 00:27:18.140
And it's...

00:27:18.140 --> 00:27:23.620
I mean, she's using Hypothesis in the example, but the intent is just property-based testing

00:27:23.620 --> 00:27:24.340
because you can...

00:27:24.340 --> 00:27:30.020
It's the same sort of strategy with every other type of property-based testing library.

00:27:30.020 --> 00:27:32.520
She just happens to be using Hypothesis and Python.

00:27:32.520 --> 00:27:34.060
So that's nice.

00:27:34.060 --> 00:27:34.860
But the...

00:27:34.860 --> 00:27:39.020
She starts off with a unit test example of just doing...

00:27:39.020 --> 00:27:41.140
She has, like, a string sort or a...

00:27:41.140 --> 00:27:42.560
Not a string sort, but a...

00:27:42.560 --> 00:27:42.900
List sort.

00:27:42.900 --> 00:27:44.560
A list sorting thing.

00:27:44.560 --> 00:27:49.540
And if you were doing example-based testing, you just pick a few example tests.

00:27:49.540 --> 00:27:55.200
Example test cases where you would take the input and you know what the sorted output should

00:27:55.200 --> 00:27:59.360
look like and you, you know, run it through the function and make sure the output sort that

00:27:59.360 --> 00:28:01.540
it's equal or equal to the expected one.

00:28:02.060 --> 00:28:04.560
How would you do this with property-based testing?

00:28:04.560 --> 00:28:06.860
And before she goes in...

00:28:06.860 --> 00:28:11.120
And she does give an example of how to write some sort of test like that in property-based

00:28:11.120 --> 00:28:11.500
testing.

00:28:11.500 --> 00:28:15.940
But she stops and pauses and talks about kind of the different mindset.

00:28:15.940 --> 00:28:20.220
You can't test against an exact example because you don't know what example is coming in.

00:28:20.220 --> 00:28:22.080
So you have to think about property.

00:28:22.080 --> 00:28:27.780
So like on a list sort thing, you don't have the exact answer, but you could check to make

00:28:27.780 --> 00:28:33.420
sure that the link should be the same and that you can use sets on both the input and output

00:28:33.420 --> 00:28:36.800
to make sure that the contents of the both are identical.

00:28:36.800 --> 00:28:42.340
And then you can go through the answer and make sure that element-wise, every element i is

00:28:42.340 --> 00:28:44.140
less than or equal to i plus one.

00:28:44.140 --> 00:28:49.140
You know, there's ways to test sort without, you know, without just knowing the answer.

00:28:49.620 --> 00:28:51.880
But it takes a mind shift a little bit.

00:28:51.880 --> 00:28:56.640
And I think actually that's one of the benefits of property-based testing is thinking in terms

00:28:56.640 --> 00:28:57.600
of that also.

00:28:57.600 --> 00:29:03.480
I also think it's nice that she talks about how this isn't a replacement for example-based

00:29:03.480 --> 00:29:03.880
testing.

00:29:03.880 --> 00:29:05.800
It is a complement to it.

00:29:06.320 --> 00:29:08.420
And so you can mix them together.

00:29:08.420 --> 00:29:12.460
Then she goes on to introduce some of the aspects of hypothesis.

00:29:12.460 --> 00:29:19.040
Like there's some cool strategies, like some lists and some integers and being able to set

00:29:19.040 --> 00:29:22.060
the max examples to, so you can set how many.

00:29:22.060 --> 00:29:27.640
And that's where you can just set it to 10,000 and wham, you have 10,000 test cases right away.

00:29:27.640 --> 00:29:31.080
But, and just let hypothesis come up with the examples.

00:29:31.280 --> 00:29:36.700
The real meat of the article, which I really appreciate is just the, how do you, the hard

00:29:36.700 --> 00:29:42.080
part of property-based testing isn't the, some of it's the syntax and she does cover the syntax

00:29:42.080 --> 00:29:42.920
and how to get this done.

00:29:42.920 --> 00:29:48.400
But it's also just how to think about the properties, how to, the coming up with what properties to

00:29:48.400 --> 00:29:49.980
test for is the hard part.

00:29:49.980 --> 00:29:54.540
And so taking a little time to talk about that, I think this is a, is a great thing.

00:29:54.540 --> 00:29:59.500
I'm also glad she threw in that one of the things you could, you should check for with

00:29:59.500 --> 00:30:05.900
tests, property-based testing is making sure exceptions that get raised are expected exceptions.

00:30:05.900 --> 00:30:11.060
So if you throw garbage in or different cases that don't make sense, you should know what

00:30:11.060 --> 00:30:15.600
kind of exceptions are going to come out and that this can be caught with your tests with

00:30:15.600 --> 00:30:16.140
hypothesis.

00:30:16.140 --> 00:30:22.360
And then also a great use for all of this is to implement whatever functionality you wanted

00:30:22.360 --> 00:30:27.720
in a very simplistic, but possibly slow or memory hoggy way or something.

00:30:27.720 --> 00:30:33.900
And then you can compare the elegant version and the slow version within the tests to make

00:30:33.900 --> 00:30:35.360
sure that they come up with the same answer.

00:30:35.360 --> 00:30:36.700
This is also great.

00:30:36.700 --> 00:30:41.660
If you're doing a refactoring, you can refactor part of your system and make sure that the

00:30:41.660 --> 00:30:43.440
old and new way act the same.

00:30:43.440 --> 00:30:46.000
So it's just a good introduction to all of this.

00:30:46.000 --> 00:30:46.220
Yeah.

00:30:46.220 --> 00:30:49.300
And a property-based testing is it's you're right.

00:30:49.340 --> 00:30:55.180
It's such a mind shift and it's, I don't know, I haven't fully embraced it yet, but I feel

00:30:55.180 --> 00:30:59.740
like there's probably some places where it would really be interesting and useful.

00:30:59.740 --> 00:31:01.100
And I probably should just look into it.

00:31:01.100 --> 00:31:04.720
You know, I don't know, I get stuck in my ways and then I just, I keep going that way.

00:31:04.720 --> 00:31:09.720
At the end, she talks about if you're not using Python, what options you have as well, which

00:31:09.720 --> 00:31:10.560
is kind of cool.

00:31:10.560 --> 00:31:11.180
Right.

00:31:11.180 --> 00:31:13.780
So it's like, hey, hypothesis is cool in Python.

00:31:13.780 --> 00:31:15.780
But if you're on TypeScript, we got fast check.

00:31:15.780 --> 00:31:16.840
We're on .NET.

00:31:16.840 --> 00:31:19.620
They don't have dashes or A's or T's.

00:31:19.620 --> 00:31:20.560
So there's FS check.

00:31:20.900 --> 00:31:24.940
And in Java, there's this and C++ and Rust and so on.

00:31:24.940 --> 00:31:31.060
So yeah, if it looks like you could use the same thinking and ideas across different parts

00:31:31.060 --> 00:31:33.720
of your stack, if you're having different technologies in there.

00:31:33.720 --> 00:31:39.600
This is another example of if it shows up in every language, it's probably something you

00:31:39.600 --> 00:31:40.700
should be paying attention to.

00:31:40.700 --> 00:31:43.320
So that's a really, that's a good rule of thumb.

00:31:43.320 --> 00:31:48.640
It's like, yeah, if I see it all over the place, right, this is a general CS sort of thing

00:31:48.640 --> 00:31:49.260
that's important.

00:31:49.260 --> 00:31:50.120
Yeah.

00:31:50.120 --> 00:31:50.400
Yeah.

00:31:50.400 --> 00:31:54.220
You know what else I like about going through stuff like this is you come across things

00:31:54.220 --> 00:31:56.060
that you didn't know about, right?

00:31:56.060 --> 00:31:58.480
For example, you'd think that I would know about JSON.

00:31:58.480 --> 00:32:01.900
It seems pretty simple, like the JavaScript object notation.

00:32:01.900 --> 00:32:08.140
But apparently there's like a JSON 5 as well, which allows things like comments and whatnot

00:32:08.140 --> 00:32:14.900
and multi-line strings and single quotes and elements that are not quoted for the keys

00:32:14.900 --> 00:32:15.540
and so on.

00:32:15.540 --> 00:32:19.900
And there's a whole cool library for JSON 5 support as if you want to have like a

00:32:19.900 --> 00:32:22.460
a little bit more human-friendly JSON.

00:32:22.460 --> 00:32:24.100
I had no idea that was a thing.

00:32:24.100 --> 00:32:24.460
Yeah.

00:32:24.460 --> 00:32:25.400
Neither did I.

00:32:25.400 --> 00:32:27.820
And I was just like, why can't I put a comment in JSON?

00:32:27.820 --> 00:32:28.820
This is driving me crazy.

00:32:28.820 --> 00:32:33.640
So what I do is I have like a field that says comment or like double slash in quotes.

00:32:33.840 --> 00:32:37.460
And then I have the string that is the comment because you can't actually have comments, but

00:32:37.460 --> 00:32:40.060
you can have ignored keys and values.

00:32:40.060 --> 00:32:41.880
So that's how I have comments in my JSON.

00:32:41.880 --> 00:32:46.560
But anyway, she talks about using the JSON 5 library that's part of Python to support that.

00:32:46.560 --> 00:32:46.860
Or not.

00:32:46.860 --> 00:32:48.520
It's not built in, but it's a Python library.

00:32:48.520 --> 00:32:49.240
You can use it to do that.

00:32:49.240 --> 00:32:49.700
Pretty cool.

00:32:49.700 --> 00:32:50.020
Yeah.

00:32:50.020 --> 00:32:50.360
Nice.

00:32:50.360 --> 00:32:50.760
Cool.

00:32:50.860 --> 00:32:51.020
Yeah.

00:32:51.020 --> 00:32:52.900
Well, I guess that's it for all of our items, huh, Brian?

00:32:52.900 --> 00:32:53.920
Yeah, it is.

00:32:53.920 --> 00:32:55.520
Got anything extra for us?

00:32:55.520 --> 00:32:56.500
Yeah, I totally did.

00:32:56.500 --> 00:32:58.480
But you nabbed it and put it in your section.

00:32:58.480 --> 00:32:59.680
So go for it.

00:32:59.680 --> 00:33:02.440
Tell us that you found a bunch of cool things there.

00:33:02.440 --> 00:33:02.800
Yeah.

00:33:02.800 --> 00:33:05.460
I want to get this one out of the way first.

00:33:05.460 --> 00:33:06.660
Some sad news.

00:33:06.660 --> 00:33:08.800
Have you, you've heard of Game of Life, right?

00:33:08.800 --> 00:33:09.240
Yes.

00:33:09.240 --> 00:33:09.800
Yeah.

00:33:09.800 --> 00:33:10.760
Conway's Game of Life.

00:33:10.760 --> 00:33:11.000
Yeah.

00:33:11.000 --> 00:33:12.260
Conway's Game of Life.

00:33:12.260 --> 00:33:20.360
Well, Conway, John Conway is, I'm going to link to an article that's a nice article talking about the Game of Life and John Conway.

00:33:20.360 --> 00:33:27.200
But just an announcement that he is one of the victims of COVID-19, died from it recently.

00:33:27.200 --> 00:33:28.360
So that's sad.

00:33:28.360 --> 00:33:30.340
Yeah, it's definitely sad news.

00:33:30.340 --> 00:33:34.460
Game of Life is kind of an excellent thing to have in the computer science realm.

00:33:34.460 --> 00:33:35.460
Pretty neat.

00:33:35.460 --> 00:33:36.820
So that's sad.

00:33:36.820 --> 00:33:41.840
Something that's happy is GitHub is now free for all teams and individuals.

00:33:42.460 --> 00:33:43.980
So that's a pretty cool announcement.

00:33:43.980 --> 00:33:44.720
That's really awesome.

00:33:44.720 --> 00:33:45.020
Yeah.

00:33:45.020 --> 00:33:50.300
So previously you had to pay to have collaborators on a private repo.

00:33:50.300 --> 00:33:53.780
I think maybe you could have some, but not a ton for private.

00:33:53.780 --> 00:33:54.280
I can't remember.

00:33:54.280 --> 00:33:55.420
Three, I think like that.

00:33:55.420 --> 00:33:55.760
Yeah.

00:33:55.760 --> 00:33:56.540
It's like evolving.

00:33:56.540 --> 00:34:00.780
First you had to pay for private repos, then you didn't, but then you had to for collaborators.

00:34:00.780 --> 00:34:02.200
And yeah, but that's awesome.

00:34:02.200 --> 00:34:03.360
So it's much more free.

00:34:03.360 --> 00:34:08.560
And then also for people who still pay GitHub, like me, it's half price.

00:34:08.560 --> 00:34:09.120
It's 40.

00:34:09.120 --> 00:34:11.720
It's, I don't know, whatever four divided by nine is.

00:34:12.220 --> 00:34:14.920
It's now 44% of what you're paying before.

00:34:14.920 --> 00:34:18.420
And people wonder like, why would you pay for GitHub organizations?

00:34:18.420 --> 00:34:24.700
If you have an organization, so like Talk Python and the related training authors and content,

00:34:24.700 --> 00:34:27.440
there's like a GitHub organization for Talk Python.

00:34:27.440 --> 00:34:30.100
Have people collaborate on that.

00:34:30.100 --> 00:34:32.920
You still have to pay, but it was $9 a month per user.

00:34:32.920 --> 00:34:34.320
Now it's $4 a month per user.

00:34:34.320 --> 00:34:35.400
So that's also bonus.

00:34:35.400 --> 00:34:35.780
Yeah.

00:34:35.780 --> 00:34:36.360
Yeah.

00:34:36.360 --> 00:34:36.760
Pretty cool.

00:34:37.180 --> 00:34:37.340
Yeah.

00:34:37.340 --> 00:34:37.800
That's happy.

00:34:37.800 --> 00:34:38.220
Yeah.

00:34:38.220 --> 00:34:45.060
So last thing I wanted to bring up is that the PyCon US 2020 online is now live.

00:34:45.060 --> 00:34:49.200
So there's a welcome video and more.

00:34:49.200 --> 00:34:51.680
There's some talks linked and there's more on the way.

00:34:51.820 --> 00:34:51.920
Yeah.

00:34:51.920 --> 00:34:57.180
There's a nice welcome video from Emily Morehouse that she basically kicks off the virtual conference.

00:34:57.180 --> 00:35:00.200
And this conference, I don't know if that's the right word for it.

00:35:00.200 --> 00:35:06.400
This thing, this event is not like a lot of online virtual conferences.

00:35:06.400 --> 00:35:08.060
Like on Saturday, we're all going to meet.

00:35:08.160 --> 00:35:10.680
And then the talks are going to be these three hours and whatnot.

00:35:10.680 --> 00:35:17.620
It's like, it's like a rolling release of information and videos that then you get to consume over the next couple of weeks.

00:35:17.620 --> 00:35:22.440
So yeah, you're linking to the, basically the landing page for like stuff as it happens.

00:35:22.440 --> 00:35:22.680
Right.

00:35:22.680 --> 00:35:23.000
Yeah.

00:35:23.000 --> 00:35:29.460
And I recommend, so also recommend checking out the, so if you go to any of the, like the welcome video,

00:35:29.580 --> 00:35:39.420
and then go up and find the PyCon US 2020 top page and look at the videos there, then you can see them all listed as well.

00:35:39.420 --> 00:35:41.820
but they're, they're rolling out.

00:35:41.820 --> 00:35:44.560
There's, and I know that they're not all recorded.

00:35:44.560 --> 00:35:45.940
So some will come later.

00:35:45.940 --> 00:35:54.560
For instance, I am still, I don't know if I will, but I'm still planning on recording my talk and posting it, just trying to figure out when to do that.

00:35:54.560 --> 00:35:54.900
So.

00:35:54.900 --> 00:35:55.160
Yeah.

00:35:55.160 --> 00:35:55.720
Yeah.

00:35:55.720 --> 00:35:55.960
Cool.

00:35:55.960 --> 00:35:58.840
Anyway, I'm definitely looking forward to checking it out and see what comes along.

00:35:58.840 --> 00:36:02.600
There's also, it's worth mentioning that they're at that link.

00:36:02.600 --> 00:36:14.800
There's a place that has like the virtual expo and the expo hall is actually my favorite part of the conference is because you get to walk around and meet people and just, you know, see what's going on and you see all the companies and what they're doing.

00:36:14.800 --> 00:36:25.980
But one of the things that happens there on Sunday in normal times is there's the like hiring job fair thing and all the job fair stuff is already up there.

00:36:25.980 --> 00:36:32.640
So if people are looking for a Python job, there's like many, many links of this company's hiring for these four positions.

00:36:32.640 --> 00:36:33.200
Click here.

00:36:33.200 --> 00:36:34.580
This company's hiring for this position.

00:36:34.580 --> 00:36:40.280
So if you're looking for a job, you want to get in there quick and, grab the good ones and apply to them.

00:36:40.280 --> 00:36:40.600
Yeah.

00:36:40.600 --> 00:36:46.520
One of the things that that's missing is how am I going to last an entire year with no new t-shirts?

00:36:46.740 --> 00:36:47.240
I know.

00:36:47.240 --> 00:36:52.520
Well, you're going to have to be up in your game there in this video version here.

00:36:52.520 --> 00:36:53.620
I know.

00:36:53.620 --> 00:36:55.860
I love all the conference swag.

00:36:55.860 --> 00:36:56.780
Yeah, exactly.

00:36:56.780 --> 00:36:58.160
Like, how do you even do that?

00:36:58.160 --> 00:36:59.540
How do you even find a good tech shirt?

00:36:59.540 --> 00:37:00.660
Like that you buy?

00:37:00.660 --> 00:37:04.120
I know that there, but it'll be different.

00:37:04.120 --> 00:37:09.240
Well, you want to know something that wasn't funny is I almost forgot to put a joke in our show notes here.

00:37:09.380 --> 00:37:09.740
Oh no.

00:37:09.740 --> 00:37:15.800
So I pulled up the terminal and I typed pie joke because I've pipX installed pie joke.

00:37:15.800 --> 00:37:18.560
So it's, it's right there in the command line.

00:37:18.560 --> 00:37:19.560
Anytime you need a laugh.

00:37:19.560 --> 00:37:22.600
And this one is about QA software quality folks.

00:37:22.600 --> 00:37:25.580
And, it's a take on a traditional one.

00:37:25.580 --> 00:37:26.580
So here, I'll hit you with this.

00:37:26.580 --> 00:37:27.000
See what you think.

00:37:27.000 --> 00:37:29.380
How many QAs does it take to change a light bulb?

00:37:29.380 --> 00:37:30.100
I don't know.

00:37:30.100 --> 00:37:31.560
They noticed the room was dark.

00:37:31.560 --> 00:37:32.940
They don't fix problems.

00:37:32.940 --> 00:37:33.900
They find them.

00:37:33.900 --> 00:37:37.600
Oh dear.

00:37:37.600 --> 00:37:38.620
That's bad, right?

00:37:38.800 --> 00:37:39.000
Yeah.

00:37:39.000 --> 00:37:41.700
That's definitely why QA and development should be one team.

00:37:41.700 --> 00:37:42.680
Absolutely.

00:37:42.680 --> 00:37:43.180
Yeah.

00:37:43.180 --> 00:37:43.600
All right.

00:37:43.600 --> 00:37:44.800
Well, a good joke.

00:37:44.800 --> 00:37:46.620
Nonetheless, a good pie joke.

00:37:46.620 --> 00:37:47.100
Thanks.

00:37:47.100 --> 00:37:49.260
Well, this was lovely today.

00:37:49.260 --> 00:37:50.620
So thanks for talking with me.

00:37:50.620 --> 00:37:51.240
Yeah, absolutely.

00:37:51.240 --> 00:37:51.880
Thanks.

00:37:51.880 --> 00:37:52.460
As always.

00:37:52.460 --> 00:37:53.100
Great to chat with you.

00:37:53.100 --> 00:37:53.700
See you later.

00:37:53.700 --> 00:37:53.940
Bye.

00:37:53.940 --> 00:37:55.960
Thank you for listening to Python Bytes.

00:37:55.960 --> 00:37:58.420
Follow the show on Twitter at Python Bytes.

00:37:58.420 --> 00:38:01.440
That's Python Bytes as in B-Y-T-E-S.

00:38:01.440 --> 00:38:04.340
And get the full show notes at Pythonbytes.fm.

00:38:04.340 --> 00:38:08.540
If you have a news item you want featured, just visit Pythonbytes.fm.

00:38:08.540 --> 00:38:09.420
and send it our way.

00:38:09.420 --> 00:38:11.460
We're always on the lookout for sharing something cool.

00:38:11.460 --> 00:38:12.620
This is Brian Okken.

00:38:12.620 --> 00:38:16.720
And on behalf of myself and Michael Kennedy, thank you for listening and sharing this podcast

00:38:16.720 --> 00:38:17.940
with your friends and colleagues.