WEBVTT
00:00:00.001 --> 00:00:06.160
Hello and welcome to Python Bytes, Python news and headlines delivered directly to your earbuds.
00:00:06.160 --> 00:00:11.400
It's Wednesday, April 12th, 2017, and this is episode 21.
00:00:11.400 --> 00:00:13.200
Here, I'm Michael Kennedy.
00:00:13.200 --> 00:00:14.040
And I'm Brian Okken.
00:00:14.040 --> 00:00:17.780
And we're going to tell you about all the cool things we found this week in the Python
00:00:17.780 --> 00:00:18.180
ecosystem.
00:00:18.180 --> 00:00:20.660
But before we get to that, Brian, let's say thanks.
00:00:20.660 --> 00:00:21.780
Well, thank you, Michael.
00:00:21.780 --> 00:00:22.480
Yes, you're welcome.
00:00:22.480 --> 00:00:23.720
Thanks to Rollbar, actually.
00:00:23.720 --> 00:00:24.880
Oh, yeah, yeah, definitely.
00:00:24.880 --> 00:00:25.760
Thank you, Rollbar.
00:00:25.760 --> 00:00:26.420
Yeah, thanks.
00:00:26.420 --> 00:00:27.300
Thank you, Rollbar.
00:00:27.800 --> 00:00:29.500
They're sponsoring this episode again.
00:00:29.500 --> 00:00:32.080
And if you want to check out Rollbar, get some special deals.
00:00:32.080 --> 00:00:33.780
It's rollbar.com slash Python Bytes.
00:00:33.780 --> 00:00:34.860
We'll talk more about them later.
00:00:34.860 --> 00:00:38.160
Brian, let's talk about some profiling.
00:00:38.160 --> 00:00:43.440
Doug Hellman, he's the guy that did the Python module of the week.
00:00:43.440 --> 00:00:46.820
I don't even know when that started for Python 2.
00:00:46.820 --> 00:00:50.060
But he has, and I can't remember when he started the third one.
00:00:50.060 --> 00:00:52.260
But I don't know if we've mentioned it on the show yet.
00:00:52.260 --> 00:00:55.440
But it's a really good resource.
00:00:55.440 --> 00:00:59.820
It's P-Y-M-O-T-W dot com Python module of the week.
00:00:59.820 --> 00:01:06.680
And he goes through a lot of the standard library and just does a little page on how to use
00:01:06.680 --> 00:01:08.780
different bits of the standard library.
00:01:08.780 --> 00:01:12.400
And this recently put up profile and p stats.
00:01:12.400 --> 00:01:19.680
And it talks about profile and cprofile for basically just for taking, if you have a piece
00:01:19.680 --> 00:01:23.760
of your code that you think might be slow, how to profile that and figure it out.
00:01:23.760 --> 00:01:25.320
So I wanted to highlight that.
00:01:25.320 --> 00:01:26.280
Yeah, I definitely.
00:01:26.280 --> 00:01:27.220
I think this is awesome.
00:01:27.220 --> 00:01:28.500
You know, Doug, way to go.
00:01:28.500 --> 00:01:29.260
Very, very cool.
00:01:29.260 --> 00:01:31.000
And keep going with that.
00:01:31.000 --> 00:01:34.360
We're going to be checking out, of course, as you roll out new ones.
00:01:34.360 --> 00:01:37.680
I definitely want to encourage people to think about profiling.
00:01:37.680 --> 00:01:44.200
I've been doing a lot of work recently on certain parts of my web app where performance is somewhat
00:01:44.200 --> 00:01:47.080
important and things have changed, right?
00:01:47.160 --> 00:01:49.340
So, for example, I switched out the database backend.
00:01:49.340 --> 00:01:54.500
And depending on how that was working, like it used to be really fast, became slow in some
00:01:54.500 --> 00:01:54.940
situations.
00:01:54.940 --> 00:01:58.400
Maybe I needed to restructure the way my data was stored.
00:01:58.400 --> 00:02:00.860
Maybe I needed new indexes or whatever.
00:02:01.000 --> 00:02:06.400
Even just profiling the web application itself actually can tell you a lot about not just
00:02:06.400 --> 00:02:11.200
where your Python is slow, but where the web services you're connecting to are slow or the
00:02:11.200 --> 00:02:12.560
databases you're talking to are slow.
00:02:12.560 --> 00:02:18.480
Or you can see something like, you made 600 requests to the database during this page load.
00:02:18.720 --> 00:02:23.020
You can really bet there's probably some sort of lazy loading problem going on, right?
00:02:23.020 --> 00:02:30.200
And so sometimes just a cursory glance at profiling stats will tell you, like, oh, I didn't realize I was
00:02:30.200 --> 00:02:30.860
doing that wrong.
00:02:30.860 --> 00:02:31.900
And you quickly fix it.
00:02:31.900 --> 00:02:33.220
So definitely check that out.
00:02:33.220 --> 00:02:41.800
So the built-in profile stuff and C-profile works great for a lot of the stuff I work on, but I'm not
00:02:41.800 --> 00:02:43.300
often working on web stuff.
00:02:43.560 --> 00:02:48.860
Are those the right tools for something like web applications or are there other things that you
00:02:48.860 --> 00:02:49.460
search for?
00:02:49.460 --> 00:02:54.140
One of the things that can be challenging about profiling web apps is there's a lot of startup
00:02:54.140 --> 00:02:55.560
code that runs.
00:02:55.560 --> 00:02:57.060
And that can be, like, computational.
00:02:57.060 --> 00:03:02.340
So you can, like, if you try to profile your app as it starts up, it could be swamped with
00:03:02.340 --> 00:03:07.560
actual, like, just getting the thing going traffic.
00:03:07.560 --> 00:03:10.960
And then you hit a request for a page and it's small enough it doesn't show up.
00:03:10.960 --> 00:03:14.100
So maybe you've got to hit it 100 times or, you know, something to get it to happen.
00:03:14.100 --> 00:03:17.340
So what I do, I don't know about the other frameworks.
00:03:17.340 --> 00:03:19.540
Pretty sure they must have something like this.
00:03:19.540 --> 00:03:26.260
But in Pyramid, by default, there's a little red box on the right side in development mode.
00:03:26.260 --> 00:03:27.640
And you can click on it.
00:03:27.640 --> 00:03:30.040
It'll take you to, it's, like, called the Pyramid Debug Toolbar.
00:03:30.040 --> 00:03:31.380
It takes you, you go to the back there.
00:03:31.380 --> 00:03:34.900
And one of the options is to turn on profiling per page request.
00:03:35.020 --> 00:03:39.080
So you just check a box and then request a page and you can, it'll tell you how many
00:03:39.080 --> 00:03:40.100
milliseconds it took.
00:03:40.100 --> 00:03:43.320
And if you click on it, it'll give you the output from this just for that page.
00:03:43.320 --> 00:03:44.480
Automatically.
00:03:44.480 --> 00:03:45.860
So you don't have to do anything.
00:03:45.860 --> 00:03:46.580
Yeah, it's super cool.
00:03:46.580 --> 00:03:46.960
All right.
00:03:46.960 --> 00:03:47.480
Well, thanks.
00:03:47.480 --> 00:03:48.060
Yeah, sure.
00:03:48.060 --> 00:03:49.540
Speaking of the web.
00:03:49.540 --> 00:03:54.780
So we have a new project coming out that I wanted to bring everyone's attention to.
00:03:54.780 --> 00:03:56.140
I don't know how old it is.
00:03:56.140 --> 00:03:58.600
It's like weeks, maybe months.
00:03:58.600 --> 00:03:59.000
I'm not sure.
00:03:59.060 --> 00:03:59.640
It's not very old.
00:03:59.640 --> 00:04:00.860
By Tom Christie.
00:04:00.860 --> 00:04:04.500
So you may know Tom Christie from the Django REST framework.
00:04:04.500 --> 00:04:07.740
And he came up with something called API Star.
00:04:07.740 --> 00:04:11.740
And this is an alternate REST framework.
00:04:11.740 --> 00:04:12.280
Okay.
00:04:12.280 --> 00:04:14.840
So Django REST framework's been around for, like, five years.
00:04:14.840 --> 00:04:16.940
And it's very popular.
00:04:16.940 --> 00:04:17.760
It's well-known.
00:04:17.760 --> 00:04:19.020
It's highly used.
00:04:19.020 --> 00:04:25.700
But it's also very much wedded with the Python 2 prior web world.
00:04:25.700 --> 00:04:26.580
Right?
00:04:26.580 --> 00:04:28.600
I mean, it's from five years ago, right?
00:04:28.660 --> 00:04:32.060
And it's based on stuff that was, you know, sort of put in a motion before then.
00:04:32.060 --> 00:04:33.560
So it's not...
00:04:33.560 --> 00:04:36.280
If you want to explore some new and interesting ideas, you can't really do it.
00:04:36.280 --> 00:04:37.360
And that's what Tom was saying.
00:04:37.360 --> 00:04:41.120
So he actually came up with this thing called API Star.
00:04:41.120 --> 00:04:46.680
And it has got some slick features that are really worth looking at.
00:04:46.680 --> 00:04:47.400
It's really new.
00:04:47.400 --> 00:04:49.380
So I don't know if it's quite ready for primetime.
00:04:49.380 --> 00:04:50.280
I just honestly don't know.
00:04:50.280 --> 00:04:51.060
I'm not saying it's not.
00:04:51.060 --> 00:04:56.280
But the idea is he calls it a smart web API framework designed specifically for Python 3.
00:04:57.480 --> 00:04:58.860
And it's super easy to get start.
00:04:58.860 --> 00:05:01.080
Just start to just pip install API Star.
00:05:01.080 --> 00:05:05.080
And you can say API Star-new and template-minimal or dash-template-minimal.
00:05:05.080 --> 00:05:05.300
Right?
00:05:05.300 --> 00:05:05.900
That'll get one.
00:05:05.900 --> 00:05:07.840
You can either run it or you can run the test straight away.
00:05:07.840 --> 00:05:10.220
So I thought you would like that little API Star space test.
00:05:10.220 --> 00:05:11.500
That's pretty cool.
00:05:11.500 --> 00:05:11.900
Yeah.
00:05:12.260 --> 00:05:13.820
And nice interface, too.
00:05:13.820 --> 00:05:15.300
It looks really clean.
00:05:15.300 --> 00:05:15.540
Yeah.
00:05:15.540 --> 00:05:17.420
So here's where the magic comes in.
00:05:17.420 --> 00:05:20.280
It's all about the type annotations.
00:05:20.280 --> 00:05:25.540
So in Python 3, you can say, like, I could define a function called, like, show query parameters.
00:05:25.540 --> 00:05:27.380
And I could have a thing called query parameters.
00:05:27.520 --> 00:05:34.740
If I wanted it to be of type HTTP.queryparams, I would say colon HTTP.queryparams.
00:05:34.740 --> 00:05:43.460
And that tells Python, not at runtime, but at design time or development time, hey, this thing's supposed to be a query params instance, right?
00:05:43.460 --> 00:05:43.800
Yeah.
00:05:43.800 --> 00:05:44.680
Okay.
00:05:44.680 --> 00:05:45.080
That's cool.
00:05:45.180 --> 00:05:45.360
Okay.
00:05:45.360 --> 00:05:46.520
So now here, check this out.
00:05:46.520 --> 00:05:57.860
If you put a parameter on that API method and you say it is one of those and it's available as part of the request, it will automatically come into your system regardless of what you call it and where you put it.
00:05:57.860 --> 00:05:58.480
Oh, nice.
00:05:58.480 --> 00:06:00.980
It looks at the type hints, the type parameters.
00:06:00.980 --> 00:06:04.900
So the thing you're saying, this thing called query params, you want the query params?
00:06:04.900 --> 00:06:06.080
I have one of those in the request.
00:06:06.080 --> 00:06:13.700
And similarly, if you return something from there, by default, you return dictionaries like all these web frameworks in Python do.
00:06:14.160 --> 00:06:19.220
But you can also use type annotations to say, no, this returns a response and then return something else.
00:06:19.220 --> 00:06:26.140
Like actually using the type annotation to control how the processing of the request is done.
00:06:26.140 --> 00:06:29.900
Similarly, you can put things in like your URL.
00:06:29.900 --> 00:06:34.320
So write like slash slash users slash seven, right?
00:06:34.320 --> 00:06:36.600
And normally that would all just come in as a string.
00:06:37.380 --> 00:06:48.660
But in this API, you can say like as a function on your REST method, you can say like user ID colon int and it will take that thing and convert it to an int out of the URL and pass it in.
00:06:48.660 --> 00:06:51.960
So there's all this really cool stuff around type hinting that I just type annotations.
00:06:51.960 --> 00:06:52.600
I really love.
00:06:53.060 --> 00:06:55.420
And not only that, it's faster than Sanic.
00:06:55.420 --> 00:06:56.340
Okay.
00:06:56.340 --> 00:06:58.300
So very, very cool.
00:06:58.300 --> 00:06:58.860
Good job, Tom.
00:06:58.860 --> 00:06:59.160
Yeah.
00:06:59.160 --> 00:07:05.680
And now that I know you said that already and I kind of went past me without me recognizing it.
00:07:05.680 --> 00:07:07.460
But the built in testing with pytest.
00:07:07.460 --> 00:07:07.740
Yay.
00:07:07.740 --> 00:07:08.560
Yay.
00:07:08.560 --> 00:07:09.260
It's awesome, right?
00:07:09.260 --> 00:07:10.180
Yeah, definitely.
00:07:10.180 --> 00:07:10.720
Cool.
00:07:10.920 --> 00:07:11.040
Yeah.
00:07:11.040 --> 00:07:12.380
So it's a really new framework.
00:07:12.380 --> 00:07:13.180
Check it out.
00:07:13.180 --> 00:07:15.160
It's already got quite a few stars on GitHub.
00:07:15.160 --> 00:07:16.520
But yeah, API star.
00:07:16.520 --> 00:07:17.480
There's a link in the notes.
00:07:17.480 --> 00:07:19.100
And there's a little example code as well.
00:07:19.100 --> 00:07:19.580
All right.
00:07:19.580 --> 00:07:22.100
But that's about fast web frameworks.
00:07:22.100 --> 00:07:23.920
But sometimes we don't care if things are fast, right?
00:07:23.920 --> 00:07:24.340
Yeah.
00:07:24.340 --> 00:07:28.640
So actually, we're kicking around the idea of talking about this last week and decided not to.
00:07:28.640 --> 00:07:29.900
But we're putting it in now.
00:07:29.900 --> 00:07:34.420
It's an article called, Yes, Python is slow and I don't care.
00:07:34.900 --> 00:07:39.720
And, you know, actually, I've never really noticed that being slow for what I have it for.
00:07:39.720 --> 00:07:46.800
But basically, that's kind of the point of the article is that fast is great.
00:07:46.800 --> 00:07:50.000
Having Sanic and API star be super fast.
00:07:50.000 --> 00:07:51.060
Of course, that's wonderful.
00:07:51.060 --> 00:07:59.600
But there's a lot of Python uses for Python and for other programming that the most expensive resource is not your CPU.
00:07:59.600 --> 00:08:02.460
Actually, it's very seldom your CPU anymore.
00:08:02.760 --> 00:08:07.660
So therefore, you usually don't really have to care about the speed of Python.
00:08:07.660 --> 00:08:09.080
And I'd have to agree.
00:08:09.080 --> 00:08:15.320
And a big chunk of this article is you should be optimizing for your most expensive resource.
00:08:15.320 --> 00:08:16.520
And that's your people.
00:08:16.520 --> 00:08:19.600
Your people are way more expensive than your computer time.
00:08:19.600 --> 00:08:20.460
So are bugs.
00:08:20.460 --> 00:08:22.500
Yes, and definitely.
00:08:22.500 --> 00:08:23.240
And so are bugs.
00:08:23.240 --> 00:08:29.060
I know that myself, we have at work, we use Python for testing.
00:08:29.060 --> 00:08:31.980
And it's because we can write smaller test code.
00:08:31.980 --> 00:08:36.080
And the time our tests run is all in IO time.
00:08:36.080 --> 00:08:37.980
It's communicating with instruments.
00:08:37.980 --> 00:08:40.240
It's not sitting in our computer.
00:08:40.240 --> 00:08:48.440
And so I can have small, elegant tests that I can read well is way more important than how fast Python is.
00:08:48.440 --> 00:08:48.720
Yeah.
00:08:48.720 --> 00:08:52.000
You want to, you know, you're talking about testing devices and hardware.
00:08:52.000 --> 00:08:53.380
Same thing applies to the web, right?
00:08:53.380 --> 00:08:56.620
Usually waiting on either a database, a web surface, or a socket somewhere.
00:08:57.260 --> 00:09:00.520
And the timing usually doesn't matter, right?
00:09:00.520 --> 00:09:00.800
Yeah.
00:09:00.800 --> 00:09:02.720
Well, I mean, of course you want it to be fast.
00:09:02.720 --> 00:09:05.320
But that's not the slow part isn't the Python.
00:09:05.320 --> 00:09:11.880
So actually, I guess that ties in with the other articles we've had so far.
00:09:12.440 --> 00:09:17.840
Developing an API quickly and elegantly is going to eliminate mistakes better.
00:09:17.840 --> 00:09:19.740
If you can do that with less code, great.
00:09:19.740 --> 00:09:20.340
Yeah, absolutely.
00:09:20.340 --> 00:09:22.020
Well, and if things are slow, right?
00:09:22.020 --> 00:09:23.060
There's always options, right?
00:09:23.060 --> 00:09:24.140
You could write it in C.
00:09:24.140 --> 00:09:25.240
You could write it in Rust.
00:09:25.240 --> 00:09:26.280
You could write it in Cython.
00:09:26.280 --> 00:09:28.660
Like, you could take that little bit and do something.
00:09:28.880 --> 00:09:32.460
Or just like you started at the beginning, profile it and change your algorithm.
00:09:32.460 --> 00:09:35.980
It very well may be that that makes a huge difference.
00:09:35.980 --> 00:09:36.320
Yeah.
00:09:36.320 --> 00:09:38.560
And it might be that you think it's Python.
00:09:38.560 --> 00:09:43.440
But like you said, it might be your database or you're accessing some resource or something.
00:09:43.440 --> 00:09:44.420
Figure that out.
00:09:44.420 --> 00:09:49.420
And then if it really is Python, which I think there's rare cases where it really is.
00:09:49.420 --> 00:09:53.420
But if it is, there's options with Cython and such.
00:09:53.420 --> 00:09:57.740
Or taking a look at Intel's offering or PyPy or something.
00:09:58.200 --> 00:09:58.780
Yeah, exactly.
00:09:58.780 --> 00:10:03.140
I just heard, saw some stuff that PyPy is supposed to be getting quite a bit faster still.
00:10:03.140 --> 00:10:06.560
And of course, they got that big grant from Mozilla to make Python 3 work much better.
00:10:06.560 --> 00:10:08.300
So all sorts of goodness there.
00:10:08.300 --> 00:10:09.060
Yeah, definitely.
00:10:09.060 --> 00:10:12.560
Now, before we get to the next item, let me tell you about Rollbar.
00:10:12.560 --> 00:10:16.660
You guys probably heard me talk about it before, but I've been using Rollbar for a long time.
00:10:16.660 --> 00:10:22.140
And the idea is you basically put a few lines of code into your web application.
00:10:22.140 --> 00:10:27.440
And if ever there's an error, it will automatically capture all the information that you need about it
00:10:27.440 --> 00:10:33.080
and ship that over to Rollbar and then send you a notification, all sorts of different ways you can get notifications.
00:10:33.080 --> 00:10:37.140
And it comes with almost all the context you need to actually solve the problem.
00:10:37.140 --> 00:10:46.000
So, for example, it might have the stack trace and the local variables and the URL and all those sorts of things that you might not even have to debug your code.
00:10:46.000 --> 00:10:51.180
You can just look at and go, oh, dear, I need to check for this or make sure that's not done or whatever, right?
00:10:51.540 --> 00:10:57.080
So if you want more reliable web apps, just be sure to check out rollbar.com slash pythonbytes.
00:10:57.180 --> 00:10:57.660
Wonderful.
00:10:57.660 --> 00:10:57.800
Wonderful.
00:10:57.800 --> 00:10:58.600
Thank you, Rollbar.
00:10:58.600 --> 00:11:03.780
And we have Rollbar to thank for why Python Bytes' website is always up.
00:11:03.780 --> 00:11:04.580
Yeah, that's right.
00:11:04.580 --> 00:11:05.200
Absolutely.
00:11:05.200 --> 00:11:07.640
It's integrated in all the sites.
00:11:07.640 --> 00:11:08.040
It's beautiful.
00:11:08.040 --> 00:11:12.680
So one of the things that I kind of want to take us back to the basics for a minute, okay?
00:11:13.520 --> 00:11:19.900
So one of the things that I think people, many people know about, but a lot of people don't, is hashing.
00:11:19.900 --> 00:11:23.320
When to use hashing, how to use hashing, and things like that.
00:11:23.320 --> 00:11:28.440
So there's a nice article called A Quick Introduction to Hashing by Gerald Nash.
00:11:28.440 --> 00:11:31.480
And this is specifically for Python developers.
00:11:31.480 --> 00:11:40.800
And has some nice examples of, like, if I want to hash a string, you know, using, say, SHA-256 or something like that for the hash, how do I do that?
00:11:40.800 --> 00:11:41.620
What does that look like?
00:11:41.700 --> 00:11:44.480
Can we back up a second in what is a hash?
00:11:44.480 --> 00:11:45.000
Sure.
00:11:45.000 --> 00:11:53.360
So a hash is a little bit like encryption in that you can look at the hash and you basically, it's obfuscated, right?
00:11:53.360 --> 00:11:54.300
You don't really know what it is.
00:11:54.300 --> 00:11:56.960
But unlike encryption, it doesn't, it can't be reversed.
00:11:56.960 --> 00:11:58.640
It can't be unhashed, right?
00:11:58.640 --> 00:12:06.480
You might take a 10 megabyte set of data and hash that into 256 characters or something like that, right?
00:12:06.500 --> 00:12:13.760
The idea is if you have the same input and you run the hash over and over again, you should get the same output.
00:12:13.760 --> 00:12:14.260
Okay.
00:12:14.260 --> 00:12:18.180
But even if it varies slightly, you'll get a totally different output.
00:12:18.180 --> 00:12:22.260
Not a little bit different, but dramatically, like unrelated sort of type of thing.
00:12:22.820 --> 00:12:27.960
And so it's used for verifying messages, verifying like download files are not tampered with.
00:12:27.960 --> 00:12:30.220
But most importantly, it's used for passwords, right?
00:12:30.220 --> 00:12:32.960
Storing raw passwords in a database, not the best.
00:12:33.360 --> 00:12:35.480
So we typically hash them.
00:12:35.480 --> 00:12:38.800
But there's all sorts of other interesting uses you can use for hashing.
00:12:38.800 --> 00:12:47.900
So like in my websites, I have the static files, JavaScript, CSS, images, et cetera, basically cached like super hard.
00:12:47.900 --> 00:12:52.760
So they're cached for a year at least, I think, maybe possibly longer.
00:12:52.760 --> 00:12:57.680
So if you go to the site and you like come back later, it's not going to go back and look again.
00:12:57.680 --> 00:13:11.220
And so what I do, the technique to make sure that nothing ever shows up stale on the site, right, you don't have to wait a year for it to like come back together, is I put a little hash of the raw files at the end of the URL of every bit of static content that I have.
00:13:11.220 --> 00:13:16.480
And so it caches it, but it caches it with the like the fingerprint of it embedded.
00:13:16.480 --> 00:13:21.500
So if the file ever changes, it instantly generates a new file and it pulls it out.
00:13:21.500 --> 00:13:23.680
So hashing is used for all sorts of good stuff.
00:13:23.680 --> 00:13:23.960
Okay.
00:13:23.960 --> 00:13:24.280
Yeah.
00:13:24.280 --> 00:13:25.720
So anyway, it's a great little article.
00:13:25.720 --> 00:13:26.680
I'll show you guys how to do that.
00:13:26.680 --> 00:13:30.280
So if you're not, if you're not taking advantage of hashes, they're super easy.
00:13:30.280 --> 00:13:31.640
Here's a nice way to see how to do it.
00:13:31.640 --> 00:13:32.040
Wonderful.
00:13:32.040 --> 00:13:34.320
This is a very fun article.
00:13:34.320 --> 00:13:42.780
I forgot to write this person's name, but there's an article called Wedding at Scale, How I Used Twilio, Python, and Google to Automate My Wedding.
00:13:42.780 --> 00:13:45.780
I feel like I missed this opportunity when I got married.
00:13:45.780 --> 00:13:46.120
Yeah.
00:13:46.120 --> 00:13:47.460
And this is just fun.
00:13:47.460 --> 00:13:52.800
And actually, the modern person's problem with like how to invite people.
00:13:52.800 --> 00:13:56.140
And I love this article.
00:13:56.140 --> 00:13:58.300
I'm just, you know, the nerd in me likes it.
00:13:58.300 --> 00:14:02.460
There's no way I would have had time to figure this out when I was trying to plan my wedding.
00:14:02.600 --> 00:14:04.740
But if you got the time, it's great.
00:14:04.740 --> 00:14:20.200
So through all of all the potential guests and their phone numbers into Google Spreadsheet and then used Python and a Python package called G Spread to access Google Spreadsheets and pull that out.
00:14:20.200 --> 00:14:25.380
And with Python used Twilio and SMS people and invitation to the wedding.
00:14:25.380 --> 00:14:30.740
And then not only that, left URLs for people to get back to him.
00:14:30.740 --> 00:14:41.240
I guess there's URLs and there's also like replies to have a set up a Flask app to collect everything of all the replies to that.
00:14:41.240 --> 00:14:48.380
And then even goes on to sending out reminder texts and having people select which food option they wanted.
00:14:49.180 --> 00:14:51.360
And it's pretty incredible, this story.
00:14:51.360 --> 00:14:53.760
Yeah, a real mashup of a bunch of cool technologies.
00:14:53.760 --> 00:14:54.440
That's awesome.
00:14:54.440 --> 00:14:55.980
Yeah, it's cool.
00:14:55.980 --> 00:14:56.280
Nice.
00:14:56.280 --> 00:14:59.560
I have another fun one for us for our last item here today.
00:14:59.560 --> 00:15:07.840
And I've got to be careful about how I speak about this device because my understanding is speaking of it causes it to do things.
00:15:07.840 --> 00:15:13.140
So let's call it the Amazon virtual assistant thing that sits on your desk.
00:15:13.140 --> 00:15:13.500
All right?
00:15:13.500 --> 00:15:13.780
Okay.
00:15:13.780 --> 00:15:14.080
Okay.
00:15:14.080 --> 00:15:21.040
So there's a guy who created a framework for creating what are called skills on this assistant.
00:15:21.040 --> 00:15:22.060
Right?
00:15:22.060 --> 00:15:23.920
So you can teach it to do new things.
00:15:23.920 --> 00:15:27.000
And the guy who wrote this article is Neil Stewart.
00:15:27.420 --> 00:15:31.560
And what I thought was really interesting was he was like visiting a friend or something like that.
00:15:31.560 --> 00:15:34.200
And they had one of these assistants.
00:15:34.200 --> 00:15:36.800
And he thought it was really cool.
00:15:36.800 --> 00:15:37.720
He's like, I'm ordering one.
00:15:37.720 --> 00:15:42.900
But he decided like, I'm going to challenge myself to build a new skill for it before it even arrives.
00:15:43.760 --> 00:15:49.700
So as developing for hardware, that's a pretty interesting idea, like to develop for it before it exists, you know, in your hands, right?
00:15:49.700 --> 00:15:50.800
Yeah, we do it all the time.
00:15:50.800 --> 00:15:51.320
Yeah, right.
00:15:51.320 --> 00:15:53.920
So the thing that he came up with is something called VoiceOps.
00:15:53.920 --> 00:15:56.480
So he has a bunch of AWS accounts and whatnot.
00:15:56.480 --> 00:16:01.520
And he can ask it things like, how's the status of his AWS servers and whatnot.
00:16:01.520 --> 00:16:08.100
And he'll tell him how many running and stopped instances there are, what RDS databases are on his account, and things like that.
00:16:08.820 --> 00:16:11.980
So that's a pretty fun skill to add to this assistant.
00:16:11.980 --> 00:16:14.360
Yeah, I didn't know you could do that, add skills to it.
00:16:14.360 --> 00:16:15.020
That's pretty cool.
00:16:15.020 --> 00:16:17.800
Yeah, and apparently you can do it in Python, which is even cooler.
00:16:17.800 --> 00:16:21.400
So he looked around and saw that there's a few things, but he wasn't really happy with it.
00:16:21.400 --> 00:16:26.040
So he decided to create a new framework called Python, the name of the thing.
00:16:26.040 --> 00:16:27.960
And it's open source on GitHub.
00:16:27.960 --> 00:16:34.460
The article here that we have linked, this one actually has a bunch of cool examples on how to affectionate.
00:16:34.460 --> 00:16:36.520
He has a hello world type of thing.
00:16:36.840 --> 00:16:39.540
And he also linked to something called Echo Shim.
00:16:39.540 --> 00:16:48.420
And Echo Shim allows you to create one of these skills, put it into AWS and run it on their Lambda system on Python,
00:16:48.420 --> 00:16:52.620
and then test it in the browser without even having hardware.
00:16:52.620 --> 00:16:53.160
Oh, cool.
00:16:53.160 --> 00:16:55.140
Yeah, so pretty fun project.
00:16:55.140 --> 00:16:59.480
So if people are into that assistant thing in Python, check it out.
00:16:59.480 --> 00:17:00.460
I will check it out.
00:17:00.460 --> 00:17:00.900
That's neat.
00:17:00.900 --> 00:17:01.740
Yeah, I haven't gotten more.
00:17:01.740 --> 00:17:02.980
Do you have one of those things?
00:17:02.980 --> 00:17:05.820
Any of those, like a Google Home or those types of things?
00:17:06.000 --> 00:17:11.480
No, actually that whole concept of like letting some other company just listen to my house.
00:17:11.480 --> 00:17:12.940
I don't like the idea.
00:17:12.940 --> 00:17:14.480
So anyway.
00:17:14.480 --> 00:17:15.620
Yeah, I'm not there yet either.
00:17:15.620 --> 00:17:19.700
I, I, I'm not super crazy about privacy and whatnot.
00:17:19.700 --> 00:17:20.800
Like, no, I'm not.
00:17:20.800 --> 00:17:22.420
Locations on my smartphone and stuff.
00:17:22.420 --> 00:17:25.400
But that somehow like crosses a little bit of a line to me.
00:17:25.400 --> 00:17:26.100
I don't know.
00:17:26.100 --> 00:17:27.460
I'm sure I'll be over it someday.
00:17:27.460 --> 00:17:28.640
Plus, I don't really.
00:17:28.640 --> 00:17:33.640
Yeah, I don't trust my kids to not just order a bunch of stuff all the time just by talking to it.
00:17:33.860 --> 00:17:34.120
Yeah.
00:17:34.120 --> 00:17:38.280
Like after what happened the first time I got an iPhone that had Siri on it.
00:17:38.280 --> 00:17:41.000
I know what the kids did to that thing.
00:17:41.000 --> 00:17:43.420
This is even more accessible to them.
00:17:43.420 --> 00:17:45.260
So I'm not sure I want that anywhere near my kids.
00:17:45.260 --> 00:17:47.100
Awesome.
00:17:47.100 --> 00:17:48.880
So that's it for the week.
00:17:48.880 --> 00:17:50.820
Brian, what do you got going on with you personally?
00:17:50.820 --> 00:18:01.700
I had an interview with Casey Rosenthal from Netflix on chaos engineering that I finally got edited and out last week on testing code.
00:18:01.700 --> 00:18:03.220
So that's out there.
00:18:03.220 --> 00:18:06.540
Oh, like chaos monkey, chaos gorilla, all that kind of stuff they do at Netflix.
00:18:06.720 --> 00:18:06.940
Yeah.
00:18:06.940 --> 00:18:22.220
And basically, we tried to talk about not just what they're doing there, but the concept of taking steady state measurements and doing experiments that might change the steady state on a system as opposed to traditional testing methods.
00:18:22.220 --> 00:18:23.120
It's pretty interesting.
00:18:23.120 --> 00:18:24.260
Yeah, nice.
00:18:24.260 --> 00:18:25.380
Oh, very cool.
00:18:25.380 --> 00:18:26.420
I'm definitely going to listen to that.
00:18:26.420 --> 00:18:26.780
That's great.
00:18:26.780 --> 00:18:27.240
How about you?
00:18:27.240 --> 00:18:34.680
So I spent the weekend reworking a bunch of my web stuff around the training course, training courses, training site, and so on.
00:18:34.680 --> 00:18:41.960
So I rebuilt a new player because I wanted to surface the closed captioning a little bit better for people, things like that.
00:18:41.960 --> 00:18:44.100
So I did a bunch of JavaScript and whatnot.
00:18:44.100 --> 00:18:48.480
And the other thing I did is I added full text search to the whole site.
00:18:48.480 --> 00:18:54.840
So you go there and you can search like into the videos even, into the text of the videos.
00:18:54.840 --> 00:18:56.160
So it's beautiful.
00:18:56.160 --> 00:18:56.860
Nice.
00:18:56.860 --> 00:19:01.440
This is what I was actually, yeah, this is actually what I was thinking about when we were talking about profiling.
00:19:01.440 --> 00:19:04.780
So when I first wrote this, I wrote it like what you might think of as like naively.
00:19:04.780 --> 00:19:09.460
I wrote it and it's all backed by like a bunch of text data in MongoDB.
00:19:09.460 --> 00:19:10.800
It's not using full text in Mongo.
00:19:10.800 --> 00:19:12.860
It's using something else that I've done.
00:19:12.860 --> 00:19:18.220
But basically, the backend is Mongo and there's a bunch of data in there, like 10 megs, 20 megs.
00:19:18.220 --> 00:19:21.440
I'm not sure exactly how much of text that I wanted to search.
00:19:21.440 --> 00:19:22.440
And I ran this.
00:19:22.440 --> 00:19:23.580
Oh, this would be nice and fast.
00:19:23.620 --> 00:19:29.060
And it was like 600 milliseconds a page, which like is acceptable maybe for other people.
00:19:29.060 --> 00:19:30.560
But for me, this is not acceptable.
00:19:30.560 --> 00:19:32.040
I'm like, oh, no way.
00:19:32.040 --> 00:19:33.080
This is not going to stand.
00:19:33.080 --> 00:19:34.080
Like, what is wrong with this?
00:19:34.080 --> 00:19:39.220
So I spent a lot of time in the profiler and I've gotten it down to 47 milliseconds.
00:19:39.220 --> 00:19:40.000
Oh, okay.
00:19:40.000 --> 00:19:40.340
Cool.
00:19:40.500 --> 00:19:43.220
So it's more than 10 times faster, right?
00:19:43.220 --> 00:19:45.860
That's like 10.5 times faster by using the profiler.
00:19:45.860 --> 00:19:47.880
And it was just, you know, this part's slow.
00:19:47.880 --> 00:19:48.780
How can I do this differently?
00:19:48.780 --> 00:19:49.480
This part's slow.
00:19:49.480 --> 00:19:50.420
How can I do this differently?
00:19:50.420 --> 00:19:52.000
So just, you know, very neat.
00:19:52.000 --> 00:19:56.240
If you want to see the fruits of that profiling, you can click the link at the bottom.
00:19:56.240 --> 00:19:56.660
Cool.
00:19:56.660 --> 00:19:59.900
Can we get a text search on Python Bytes?
00:20:00.080 --> 00:20:02.100
Yes, absolutely.
00:20:02.100 --> 00:20:04.200
We're getting full text search on Python Bytes soon.
00:20:04.200 --> 00:20:04.620
Okay.
00:20:04.620 --> 00:20:04.980
Yes.
00:20:04.980 --> 00:20:05.920
I think we need it though.
00:20:05.920 --> 00:20:08.840
I mean, we have a bunch of transcripts that we have interesting stuff in.
00:20:08.840 --> 00:20:11.760
We've got our pretty solid show notes for this podcast.
00:20:11.760 --> 00:20:13.380
I think we need a full text search.
00:20:13.380 --> 00:20:15.280
So yeah, we'll be sure to announce it shortly.
00:20:15.280 --> 00:20:16.100
Okay, great.
00:20:16.100 --> 00:20:16.780
Cool.
00:20:16.780 --> 00:20:18.040
I need one more weekend, I guess.
00:20:18.040 --> 00:20:20.660
Yeah, like adding work to you on air.
00:20:20.660 --> 00:20:21.480
Sorry about that.
00:20:21.480 --> 00:20:22.520
That's all right.
00:20:22.520 --> 00:20:22.840
It's good.
00:20:22.840 --> 00:20:23.200
No, no.
00:20:23.200 --> 00:20:23.840
It's on the roadmap.
00:20:23.840 --> 00:20:24.440
It's on the roadmap.
00:20:24.440 --> 00:20:25.220
All right.
00:20:25.220 --> 00:20:28.160
Well, Brian, thanks so much for finding these things and sharing them with everyone.
00:20:28.160 --> 00:20:28.860
Thank you.
00:20:28.860 --> 00:20:29.260
You bet.
00:20:29.260 --> 00:20:30.080
Catch you next time.
00:20:30.080 --> 00:20:33.860
Thank you for listening to Python Bytes.
00:20:33.860 --> 00:20:36.420
Follow the show on Twitter via at Python Bytes.
00:20:36.420 --> 00:20:39.300
That's Python Bytes as in B-Y-T-E-S.
00:20:39.300 --> 00:20:42.720
And get the full show notes at pythonbytes.fm.
00:20:42.720 --> 00:20:47.080
If you have a news item you want featured, just visit pythonbytes.fm and send it our way.
00:20:47.080 --> 00:20:49.800
We're always on the lookout for sharing something cool.
00:20:49.800 --> 00:20:53.160
On behalf of myself and Brian Okken, this is Michael Kennedy.
00:20:53.160 --> 00:20:56.780
Thank you for listening and sharing this podcast with your friends and colleagues.
00:00:00.001 --> 00:00:06.160
Hello and welcome to Python Bytes, Python news and headlines delivered directly to your earbuds.
00:00:06.160 --> 00:00:11.400
It's Wednesday, April 12th, 2017, and this is episode 21.
00:00:11.400 --> 00:00:13.200
Here, I'm Michael Kennedy.
00:00:13.200 --> 00:00:14.040
And I'm Brian Okken.
00:00:14.040 --> 00:00:17.780
And we're going to tell you about all the cool things we found this week in the Python
00:00:17.780 --> 00:00:18.180
ecosystem.
00:00:18.180 --> 00:00:20.660
But before we get to that, Brian, let's say thanks.
00:00:20.660 --> 00:00:21.780
Well, thank you, Michael.
00:00:21.780 --> 00:00:22.480
Yes, you're welcome.
00:00:22.480 --> 00:00:23.720
Thanks to Rollbar, actually.
00:00:23.720 --> 00:00:24.880
Oh, yeah, yeah, definitely.
00:00:24.880 --> 00:00:25.760
Thank you, Rollbar.
00:00:25.760 --> 00:00:26.420
Yeah, thanks.
00:00:26.420 --> 00:00:27.300
Thank you, Rollbar.
00:00:27.800 --> 00:00:29.500
They're sponsoring this episode again.
00:00:29.500 --> 00:00:32.080
And if you want to check out Rollbar, get some special deals.
00:00:32.080 --> 00:00:33.780
It's rollbar.com slash Python Bytes.
00:00:33.780 --> 00:00:34.860
We'll talk more about them later.
00:00:34.860 --> 00:00:38.160
Brian, let's talk about some profiling.
00:00:38.160 --> 00:00:43.440
Doug Hellman, he's the guy that did the Python module of the week.
00:00:43.440 --> 00:00:46.820
I don't even know when that started for Python 2.
00:00:46.820 --> 00:00:50.060
But he has, and I can't remember when he started the third one.
00:00:50.060 --> 00:00:52.260
But I don't know if we've mentioned it on the show yet.
00:00:52.260 --> 00:00:55.440
But it's a really good resource.
00:00:55.440 --> 00:00:59.820
It's P-Y-M-O-T-W dot com Python module of the week.
00:00:59.820 --> 00:01:06.680
And he goes through a lot of the standard library and just does a little page on how to use
00:01:06.680 --> 00:01:08.780
different bits of the standard library.
00:01:08.780 --> 00:01:12.400
And this recently put up profile and p stats.
00:01:12.400 --> 00:01:19.680
And it talks about profile and cprofile for basically just for taking, if you have a piece
00:01:19.680 --> 00:01:23.760
of your code that you think might be slow, how to profile that and figure it out.
00:01:23.760 --> 00:01:25.320
So I wanted to highlight that.
00:01:25.320 --> 00:01:26.280
Yeah, I definitely.
00:01:26.280 --> 00:01:27.220
I think this is awesome.
00:01:27.220 --> 00:01:28.500
You know, Doug, way to go.
00:01:28.500 --> 00:01:29.260
Very, very cool.
00:01:29.260 --> 00:01:31.000
And keep going with that.
00:01:31.000 --> 00:01:34.360
We're going to be checking out, of course, as you roll out new ones.
00:01:34.360 --> 00:01:37.680
I definitely want to encourage people to think about profiling.
00:01:37.680 --> 00:01:44.200
I've been doing a lot of work recently on certain parts of my web app where performance is somewhat
00:01:44.200 --> 00:01:47.080
important and things have changed, right?
00:01:47.160 --> 00:01:49.340
So, for example, I switched out the database backend.
00:01:49.340 --> 00:01:54.500
And depending on how that was working, like it used to be really fast, became slow in some
00:01:54.500 --> 00:01:54.940
situations.
00:01:54.940 --> 00:01:58.400
Maybe I needed to restructure the way my data was stored.
00:01:58.400 --> 00:02:00.860
Maybe I needed new indexes or whatever.
00:02:01.000 --> 00:02:06.400
Even just profiling the web application itself actually can tell you a lot about not just
00:02:06.400 --> 00:02:11.200
where your Python is slow, but where the web services you're connecting to are slow or the
00:02:11.200 --> 00:02:12.560
databases you're talking to are slow.
00:02:12.560 --> 00:02:18.480
Or you can see something like, you made 600 requests to the database during this page load.
00:02:18.720 --> 00:02:23.020
You can really bet there's probably some sort of lazy loading problem going on, right?
00:02:23.020 --> 00:02:30.200
And so sometimes just a cursory glance at profiling stats will tell you, like, oh, I didn't realize I was
00:02:30.200 --> 00:02:30.860
doing that wrong.
00:02:30.860 --> 00:02:31.900
And you quickly fix it.
00:02:31.900 --> 00:02:33.220
So definitely check that out.
00:02:33.220 --> 00:02:41.800
So the built-in profile stuff and C-profile works great for a lot of the stuff I work on, but I'm not
00:02:41.800 --> 00:02:43.300
often working on web stuff.
00:02:43.560 --> 00:02:48.860
Are those the right tools for something like web applications or are there other things that you
00:02:48.860 --> 00:02:49.460
search for?
00:02:49.460 --> 00:02:54.140
One of the things that can be challenging about profiling web apps is there's a lot of startup
00:02:54.140 --> 00:02:55.560
code that runs.
00:02:55.560 --> 00:02:57.060
And that can be, like, computational.
00:02:57.060 --> 00:03:02.340
So you can, like, if you try to profile your app as it starts up, it could be swamped with
00:03:02.340 --> 00:03:07.560
actual, like, just getting the thing going traffic.
00:03:07.560 --> 00:03:10.960
And then you hit a request for a page and it's small enough it doesn't show up.
00:03:10.960 --> 00:03:14.100
So maybe you've got to hit it 100 times or, you know, something to get it to happen.
00:03:14.100 --> 00:03:17.340
So what I do, I don't know about the other frameworks.
00:03:17.340 --> 00:03:19.540
Pretty sure they must have something like this.
00:03:19.540 --> 00:03:26.260
But in Pyramid, by default, there's a little red box on the right side in development mode.
00:03:26.260 --> 00:03:27.640
And you can click on it.
00:03:27.640 --> 00:03:30.040
It'll take you to, it's, like, called the Pyramid Debug Toolbar.
00:03:30.040 --> 00:03:31.380
It takes you, you go to the back there.
00:03:31.380 --> 00:03:34.900
And one of the options is to turn on profiling per page request.
00:03:35.020 --> 00:03:39.080
So you just check a box and then request a page and you can, it'll tell you how many
00:03:39.080 --> 00:03:40.100
milliseconds it took.
00:03:40.100 --> 00:03:43.320
And if you click on it, it'll give you the output from this just for that page.
00:03:43.320 --> 00:03:44.480
Automatically.
00:03:44.480 --> 00:03:45.860
So you don't have to do anything.
00:03:45.860 --> 00:03:46.580
Yeah, it's super cool.
00:03:46.580 --> 00:03:46.960
All right.
00:03:46.960 --> 00:03:47.480
Well, thanks.
00:03:47.480 --> 00:03:48.060
Yeah, sure.
00:03:48.060 --> 00:03:49.540
Speaking of the web.
00:03:49.540 --> 00:03:54.780
So we have a new project coming out that I wanted to bring everyone's attention to.
00:03:54.780 --> 00:03:56.140
I don't know how old it is.
00:03:56.140 --> 00:03:58.600
It's like weeks, maybe months.
00:03:58.600 --> 00:03:59.000
I'm not sure.
00:03:59.060 --> 00:03:59.640
It's not very old.
00:03:59.640 --> 00:04:00.860
By Tom Christie.
00:04:00.860 --> 00:04:04.500
So you may know Tom Christie from the Django REST framework.
00:04:04.500 --> 00:04:07.740
And he came up with something called API Star.
00:04:07.740 --> 00:04:11.740
And this is an alternate REST framework.
00:04:11.740 --> 00:04:12.280
Okay.
00:04:12.280 --> 00:04:14.840
So Django REST framework's been around for, like, five years.
00:04:14.840 --> 00:04:16.940
And it's very popular.
00:04:16.940 --> 00:04:17.760
It's well-known.
00:04:17.760 --> 00:04:19.020
It's highly used.
00:04:19.020 --> 00:04:25.700
But it's also very much wedded with the Python 2 prior web world.
00:04:25.700 --> 00:04:26.580
Right?
00:04:26.580 --> 00:04:28.600
I mean, it's from five years ago, right?
00:04:28.660 --> 00:04:32.060
And it's based on stuff that was, you know, sort of put in a motion before then.
00:04:32.060 --> 00:04:33.560
So it's not...
00:04:33.560 --> 00:04:36.280
If you want to explore some new and interesting ideas, you can't really do it.
00:04:36.280 --> 00:04:37.360
And that's what Tom was saying.
00:04:37.360 --> 00:04:41.120
So he actually came up with this thing called API Star.
00:04:41.120 --> 00:04:46.680
And it has got some slick features that are really worth looking at.
00:04:46.680 --> 00:04:47.400
It's really new.
00:04:47.400 --> 00:04:49.380
So I don't know if it's quite ready for primetime.
00:04:49.380 --> 00:04:50.280
I just honestly don't know.
00:04:50.280 --> 00:04:51.060
I'm not saying it's not.
00:04:51.060 --> 00:04:56.280
But the idea is he calls it a smart web API framework designed specifically for Python 3.
00:04:57.480 --> 00:04:58.860
And it's super easy to get start.
00:04:58.860 --> 00:05:01.080
Just start to just pip install API Star.
00:05:01.080 --> 00:05:05.080
And you can say API Star-new and template-minimal or dash-template-minimal.
00:05:05.080 --> 00:05:05.300
Right?
00:05:05.300 --> 00:05:05.900
That'll get one.
00:05:05.900 --> 00:05:07.840
You can either run it or you can run the test straight away.
00:05:07.840 --> 00:05:10.220
So I thought you would like that little API Star space test.
00:05:10.220 --> 00:05:11.500
That's pretty cool.
00:05:11.500 --> 00:05:11.900
Yeah.
00:05:12.260 --> 00:05:13.820
And nice interface, too.
00:05:13.820 --> 00:05:15.300
It looks really clean.
00:05:15.300 --> 00:05:15.540
Yeah.
00:05:15.540 --> 00:05:17.420
So here's where the magic comes in.
00:05:17.420 --> 00:05:20.280
It's all about the type annotations.
00:05:20.280 --> 00:05:25.540
So in Python 3, you can say, like, I could define a function called, like, show query parameters.
00:05:25.540 --> 00:05:27.380
And I could have a thing called query parameters.
00:05:27.520 --> 00:05:34.740
If I wanted it to be of type HTTP.queryparams, I would say colon HTTP.queryparams.
00:05:34.740 --> 00:05:43.460
And that tells Python, not at runtime, but at design time or development time, hey, this thing's supposed to be a query params instance, right?
00:05:43.460 --> 00:05:43.800
Yeah.
00:05:43.800 --> 00:05:44.680
Okay.
00:05:44.680 --> 00:05:45.080
That's cool.
00:05:45.180 --> 00:05:45.360
Okay.
00:05:45.360 --> 00:05:46.520
So now here, check this out.
00:05:46.520 --> 00:05:57.860
If you put a parameter on that API method and you say it is one of those and it's available as part of the request, it will automatically come into your system regardless of what you call it and where you put it.
00:05:57.860 --> 00:05:58.480
Oh, nice.
00:05:58.480 --> 00:06:00.980
It looks at the type hints, the type parameters.
00:06:00.980 --> 00:06:04.900
So the thing you're saying, this thing called query params, you want the query params?
00:06:04.900 --> 00:06:06.080
I have one of those in the request.
00:06:06.080 --> 00:06:13.700
And similarly, if you return something from there, by default, you return dictionaries like all these web frameworks in Python do.
00:06:14.160 --> 00:06:19.220
But you can also use type annotations to say, no, this returns a response and then return something else.
00:06:19.220 --> 00:06:26.140
Like actually using the type annotation to control how the processing of the request is done.
00:06:26.140 --> 00:06:29.900
Similarly, you can put things in like your URL.
00:06:29.900 --> 00:06:34.320
So write like slash slash users slash seven, right?
00:06:34.320 --> 00:06:36.600
And normally that would all just come in as a string.
00:06:37.380 --> 00:06:48.660
But in this API, you can say like as a function on your REST method, you can say like user ID colon int and it will take that thing and convert it to an int out of the URL and pass it in.
00:06:48.660 --> 00:06:51.960
So there's all this really cool stuff around type hinting that I just type annotations.
00:06:51.960 --> 00:06:52.600
I really love.
00:06:53.060 --> 00:06:55.420
And not only that, it's faster than Sanic.
00:06:55.420 --> 00:06:56.340
Okay.
00:06:56.340 --> 00:06:58.300
So very, very cool.
00:06:58.300 --> 00:06:58.860
Good job, Tom.
00:06:58.860 --> 00:06:59.160
Yeah.
00:06:59.160 --> 00:07:05.680
And now that I know you said that already and I kind of went past me without me recognizing it.
00:07:05.680 --> 00:07:07.460
But the built in testing with pytest.
00:07:07.460 --> 00:07:07.740
Yay.
00:07:07.740 --> 00:07:08.560
Yay.
00:07:08.560 --> 00:07:09.260
It's awesome, right?
00:07:09.260 --> 00:07:10.180
Yeah, definitely.
00:07:10.180 --> 00:07:10.720
Cool.
00:07:10.920 --> 00:07:11.040
Yeah.
00:07:11.040 --> 00:07:12.380
So it's a really new framework.
00:07:12.380 --> 00:07:13.180
Check it out.
00:07:13.180 --> 00:07:15.160
It's already got quite a few stars on GitHub.
00:07:15.160 --> 00:07:16.520
But yeah, API star.
00:07:16.520 --> 00:07:17.480
There's a link in the notes.
00:07:17.480 --> 00:07:19.100
And there's a little example code as well.
00:07:19.100 --> 00:07:19.580
All right.
00:07:19.580 --> 00:07:22.100
But that's about fast web frameworks.
00:07:22.100 --> 00:07:23.920
But sometimes we don't care if things are fast, right?
00:07:23.920 --> 00:07:24.340
Yeah.
00:07:24.340 --> 00:07:28.640
So actually, we're kicking around the idea of talking about this last week and decided not to.
00:07:28.640 --> 00:07:29.900
But we're putting it in now.
00:07:29.900 --> 00:07:34.420
It's an article called, Yes, Python is slow and I don't care.
00:07:34.900 --> 00:07:39.720
And, you know, actually, I've never really noticed that being slow for what I have it for.
00:07:39.720 --> 00:07:46.800
But basically, that's kind of the point of the article is that fast is great.
00:07:46.800 --> 00:07:50.000
Having Sanic and API star be super fast.
00:07:50.000 --> 00:07:51.060
Of course, that's wonderful.
00:07:51.060 --> 00:07:59.600
But there's a lot of Python uses for Python and for other programming that the most expensive resource is not your CPU.
00:07:59.600 --> 00:08:02.460
Actually, it's very seldom your CPU anymore.
00:08:02.760 --> 00:08:07.660
So therefore, you usually don't really have to care about the speed of Python.
00:08:07.660 --> 00:08:09.080
And I'd have to agree.
00:08:09.080 --> 00:08:15.320
And a big chunk of this article is you should be optimizing for your most expensive resource.
00:08:15.320 --> 00:08:16.520
And that's your people.
00:08:16.520 --> 00:08:19.600
Your people are way more expensive than your computer time.
00:08:19.600 --> 00:08:20.460
So are bugs.
00:08:20.460 --> 00:08:22.500
Yes, and definitely.
00:08:22.500 --> 00:08:23.240
And so are bugs.
00:08:23.240 --> 00:08:29.060
I know that myself, we have at work, we use Python for testing.
00:08:29.060 --> 00:08:31.980
And it's because we can write smaller test code.
00:08:31.980 --> 00:08:36.080
And the time our tests run is all in IO time.
00:08:36.080 --> 00:08:37.980
It's communicating with instruments.
00:08:37.980 --> 00:08:40.240
It's not sitting in our computer.
00:08:40.240 --> 00:08:48.440
And so I can have small, elegant tests that I can read well is way more important than how fast Python is.
00:08:48.440 --> 00:08:48.720
Yeah.
00:08:48.720 --> 00:08:52.000
You want to, you know, you're talking about testing devices and hardware.
00:08:52.000 --> 00:08:53.380
Same thing applies to the web, right?
00:08:53.380 --> 00:08:56.620
Usually waiting on either a database, a web surface, or a socket somewhere.
00:08:57.260 --> 00:09:00.520
And the timing usually doesn't matter, right?
00:09:00.520 --> 00:09:00.800
Yeah.
00:09:00.800 --> 00:09:02.720
Well, I mean, of course you want it to be fast.
00:09:02.720 --> 00:09:05.320
But that's not the slow part isn't the Python.
00:09:05.320 --> 00:09:11.880
So actually, I guess that ties in with the other articles we've had so far.
00:09:12.440 --> 00:09:17.840
Developing an API quickly and elegantly is going to eliminate mistakes better.
00:09:17.840 --> 00:09:19.740
If you can do that with less code, great.
00:09:19.740 --> 00:09:20.340
Yeah, absolutely.
00:09:20.340 --> 00:09:22.020
Well, and if things are slow, right?
00:09:22.020 --> 00:09:23.060
There's always options, right?
00:09:23.060 --> 00:09:24.140
You could write it in C.
00:09:24.140 --> 00:09:25.240
You could write it in Rust.
00:09:25.240 --> 00:09:26.280
You could write it in Cython.
00:09:26.280 --> 00:09:28.660
Like, you could take that little bit and do something.
00:09:28.880 --> 00:09:32.460
Or just like you started at the beginning, profile it and change your algorithm.
00:09:32.460 --> 00:09:35.980
It very well may be that that makes a huge difference.
00:09:35.980 --> 00:09:36.320
Yeah.
00:09:36.320 --> 00:09:38.560
And it might be that you think it's Python.
00:09:38.560 --> 00:09:43.440
But like you said, it might be your database or you're accessing some resource or something.
00:09:43.440 --> 00:09:44.420
Figure that out.
00:09:44.420 --> 00:09:49.420
And then if it really is Python, which I think there's rare cases where it really is.
00:09:49.420 --> 00:09:53.420
But if it is, there's options with Cython and such.
00:09:53.420 --> 00:09:57.740
Or taking a look at Intel's offering or PyPy or something.
00:09:58.200 --> 00:09:58.780
Yeah, exactly.
00:09:58.780 --> 00:10:03.140
I just heard, saw some stuff that PyPy is supposed to be getting quite a bit faster still.
00:10:03.140 --> 00:10:06.560
And of course, they got that big grant from Mozilla to make Python 3 work much better.
00:10:06.560 --> 00:10:08.300
So all sorts of goodness there.
00:10:08.300 --> 00:10:09.060
Yeah, definitely.
00:10:09.060 --> 00:10:12.560
Now, before we get to the next item, let me tell you about Rollbar.
00:10:12.560 --> 00:10:16.660
You guys probably heard me talk about it before, but I've been using Rollbar for a long time.
00:10:16.660 --> 00:10:22.140
And the idea is you basically put a few lines of code into your web application.
00:10:22.140 --> 00:10:27.440
And if ever there's an error, it will automatically capture all the information that you need about it
00:10:27.440 --> 00:10:33.080
and ship that over to Rollbar and then send you a notification, all sorts of different ways you can get notifications.
00:10:33.080 --> 00:10:37.140
And it comes with almost all the context you need to actually solve the problem.
00:10:37.140 --> 00:10:46.000
So, for example, it might have the stack trace and the local variables and the URL and all those sorts of things that you might not even have to debug your code.
00:10:46.000 --> 00:10:51.180
You can just look at and go, oh, dear, I need to check for this or make sure that's not done or whatever, right?
00:10:51.540 --> 00:10:57.080
So if you want more reliable web apps, just be sure to check out rollbar.com slash pythonbytes.
00:10:57.180 --> 00:10:57.660
Wonderful.
00:10:57.660 --> 00:10:57.800
Wonderful.
00:10:57.800 --> 00:10:58.600
Thank you, Rollbar.
00:10:58.600 --> 00:11:03.780
And we have Rollbar to thank for why Python Bytes' website is always up.
00:11:03.780 --> 00:11:04.580
Yeah, that's right.
00:11:04.580 --> 00:11:05.200
Absolutely.
00:11:05.200 --> 00:11:07.640
It's integrated in all the sites.
00:11:07.640 --> 00:11:08.040
It's beautiful.
00:11:08.040 --> 00:11:12.680
So one of the things that I kind of want to take us back to the basics for a minute, okay?
00:11:13.520 --> 00:11:19.900
So one of the things that I think people, many people know about, but a lot of people don't, is hashing.
00:11:19.900 --> 00:11:23.320
When to use hashing, how to use hashing, and things like that.
00:11:23.320 --> 00:11:28.440
So there's a nice article called A Quick Introduction to Hashing by Gerald Nash.
00:11:28.440 --> 00:11:31.480
And this is specifically for Python developers.
00:11:31.480 --> 00:11:40.800
And has some nice examples of, like, if I want to hash a string, you know, using, say, SHA-256 or something like that for the hash, how do I do that?
00:11:40.800 --> 00:11:41.620
What does that look like?
00:11:41.700 --> 00:11:44.480
Can we back up a second in what is a hash?
00:11:44.480 --> 00:11:45.000
Sure.
00:11:45.000 --> 00:11:53.360
So a hash is a little bit like encryption in that you can look at the hash and you basically, it's obfuscated, right?
00:11:53.360 --> 00:11:54.300
You don't really know what it is.
00:11:54.300 --> 00:11:56.960
But unlike encryption, it doesn't, it can't be reversed.
00:11:56.960 --> 00:11:58.640
It can't be unhashed, right?
00:11:58.640 --> 00:12:06.480
You might take a 10 megabyte set of data and hash that into 256 characters or something like that, right?
00:12:06.500 --> 00:12:13.760
The idea is if you have the same input and you run the hash over and over again, you should get the same output.
00:12:13.760 --> 00:12:14.260
Okay.
00:12:14.260 --> 00:12:18.180
But even if it varies slightly, you'll get a totally different output.
00:12:18.180 --> 00:12:22.260
Not a little bit different, but dramatically, like unrelated sort of type of thing.
00:12:22.820 --> 00:12:27.960
And so it's used for verifying messages, verifying like download files are not tampered with.
00:12:27.960 --> 00:12:30.220
But most importantly, it's used for passwords, right?
00:12:30.220 --> 00:12:32.960
Storing raw passwords in a database, not the best.
00:12:33.360 --> 00:12:35.480
So we typically hash them.
00:12:35.480 --> 00:12:38.800
But there's all sorts of other interesting uses you can use for hashing.
00:12:38.800 --> 00:12:47.900
So like in my websites, I have the static files, JavaScript, CSS, images, et cetera, basically cached like super hard.
00:12:47.900 --> 00:12:52.760
So they're cached for a year at least, I think, maybe possibly longer.
00:12:52.760 --> 00:12:57.680
So if you go to the site and you like come back later, it's not going to go back and look again.
00:12:57.680 --> 00:13:11.220
And so what I do, the technique to make sure that nothing ever shows up stale on the site, right, you don't have to wait a year for it to like come back together, is I put a little hash of the raw files at the end of the URL of every bit of static content that I have.
00:13:11.220 --> 00:13:16.480
And so it caches it, but it caches it with the like the fingerprint of it embedded.
00:13:16.480 --> 00:13:21.500
So if the file ever changes, it instantly generates a new file and it pulls it out.
00:13:21.500 --> 00:13:23.680
So hashing is used for all sorts of good stuff.
00:13:23.680 --> 00:13:23.960
Okay.
00:13:23.960 --> 00:13:24.280
Yeah.
00:13:24.280 --> 00:13:25.720
So anyway, it's a great little article.
00:13:25.720 --> 00:13:26.680
I'll show you guys how to do that.
00:13:26.680 --> 00:13:30.280
So if you're not, if you're not taking advantage of hashes, they're super easy.
00:13:30.280 --> 00:13:31.640
Here's a nice way to see how to do it.
00:13:31.640 --> 00:13:32.040
Wonderful.
00:13:32.040 --> 00:13:34.320
This is a very fun article.
00:13:34.320 --> 00:13:42.780
I forgot to write this person's name, but there's an article called Wedding at Scale, How I Used Twilio, Python, and Google to Automate My Wedding.
00:13:42.780 --> 00:13:45.780
I feel like I missed this opportunity when I got married.
00:13:45.780 --> 00:13:46.120
Yeah.
00:13:46.120 --> 00:13:47.460
And this is just fun.
00:13:47.460 --> 00:13:52.800
And actually, the modern person's problem with like how to invite people.
00:13:52.800 --> 00:13:56.140
And I love this article.
00:13:56.140 --> 00:13:58.300
I'm just, you know, the nerd in me likes it.
00:13:58.300 --> 00:14:02.460
There's no way I would have had time to figure this out when I was trying to plan my wedding.
00:14:02.600 --> 00:14:04.740
But if you got the time, it's great.
00:14:04.740 --> 00:14:20.200
So through all of all the potential guests and their phone numbers into Google Spreadsheet and then used Python and a Python package called G Spread to access Google Spreadsheets and pull that out.
00:14:20.200 --> 00:14:25.380
And with Python used Twilio and SMS people and invitation to the wedding.
00:14:25.380 --> 00:14:30.740
And then not only that, left URLs for people to get back to him.
00:14:30.740 --> 00:14:41.240
I guess there's URLs and there's also like replies to have a set up a Flask app to collect everything of all the replies to that.
00:14:41.240 --> 00:14:48.380
And then even goes on to sending out reminder texts and having people select which food option they wanted.
00:14:49.180 --> 00:14:51.360
And it's pretty incredible, this story.
00:14:51.360 --> 00:14:53.760
Yeah, a real mashup of a bunch of cool technologies.
00:14:53.760 --> 00:14:54.440
That's awesome.
00:14:54.440 --> 00:14:55.980
Yeah, it's cool.
00:14:55.980 --> 00:14:56.280
Nice.
00:14:56.280 --> 00:14:59.560
I have another fun one for us for our last item here today.
00:14:59.560 --> 00:15:07.840
And I've got to be careful about how I speak about this device because my understanding is speaking of it causes it to do things.
00:15:07.840 --> 00:15:13.140
So let's call it the Amazon virtual assistant thing that sits on your desk.
00:15:13.140 --> 00:15:13.500
All right?
00:15:13.500 --> 00:15:13.780
Okay.
00:15:13.780 --> 00:15:14.080
Okay.
00:15:14.080 --> 00:15:21.040
So there's a guy who created a framework for creating what are called skills on this assistant.
00:15:21.040 --> 00:15:22.060
Right?
00:15:22.060 --> 00:15:23.920
So you can teach it to do new things.
00:15:23.920 --> 00:15:27.000
And the guy who wrote this article is Neil Stewart.
00:15:27.420 --> 00:15:31.560
And what I thought was really interesting was he was like visiting a friend or something like that.
00:15:31.560 --> 00:15:34.200
And they had one of these assistants.
00:15:34.200 --> 00:15:36.800
And he thought it was really cool.
00:15:36.800 --> 00:15:37.720
He's like, I'm ordering one.
00:15:37.720 --> 00:15:42.900
But he decided like, I'm going to challenge myself to build a new skill for it before it even arrives.
00:15:43.760 --> 00:15:49.700
So as developing for hardware, that's a pretty interesting idea, like to develop for it before it exists, you know, in your hands, right?
00:15:49.700 --> 00:15:50.800
Yeah, we do it all the time.
00:15:50.800 --> 00:15:51.320
Yeah, right.
00:15:51.320 --> 00:15:53.920
So the thing that he came up with is something called VoiceOps.
00:15:53.920 --> 00:15:56.480
So he has a bunch of AWS accounts and whatnot.
00:15:56.480 --> 00:16:01.520
And he can ask it things like, how's the status of his AWS servers and whatnot.
00:16:01.520 --> 00:16:08.100
And he'll tell him how many running and stopped instances there are, what RDS databases are on his account, and things like that.
00:16:08.820 --> 00:16:11.980
So that's a pretty fun skill to add to this assistant.
00:16:11.980 --> 00:16:14.360
Yeah, I didn't know you could do that, add skills to it.
00:16:14.360 --> 00:16:15.020
That's pretty cool.
00:16:15.020 --> 00:16:17.800
Yeah, and apparently you can do it in Python, which is even cooler.
00:16:17.800 --> 00:16:21.400
So he looked around and saw that there's a few things, but he wasn't really happy with it.
00:16:21.400 --> 00:16:26.040
So he decided to create a new framework called Python, the name of the thing.
00:16:26.040 --> 00:16:27.960
And it's open source on GitHub.
00:16:27.960 --> 00:16:34.460
The article here that we have linked, this one actually has a bunch of cool examples on how to affectionate.
00:16:34.460 --> 00:16:36.520
He has a hello world type of thing.
00:16:36.840 --> 00:16:39.540
And he also linked to something called Echo Shim.
00:16:39.540 --> 00:16:48.420
And Echo Shim allows you to create one of these skills, put it into AWS and run it on their Lambda system on Python,
00:16:48.420 --> 00:16:52.620
and then test it in the browser without even having hardware.
00:16:52.620 --> 00:16:53.160
Oh, cool.
00:16:53.160 --> 00:16:55.140
Yeah, so pretty fun project.
00:16:55.140 --> 00:16:59.480
So if people are into that assistant thing in Python, check it out.
00:16:59.480 --> 00:17:00.460
I will check it out.
00:17:00.460 --> 00:17:00.900
That's neat.
00:17:00.900 --> 00:17:01.740
Yeah, I haven't gotten more.
00:17:01.740 --> 00:17:02.980
Do you have one of those things?
00:17:02.980 --> 00:17:05.820
Any of those, like a Google Home or those types of things?
00:17:06.000 --> 00:17:11.480
No, actually that whole concept of like letting some other company just listen to my house.
00:17:11.480 --> 00:17:12.940
I don't like the idea.
00:17:12.940 --> 00:17:14.480
So anyway.
00:17:14.480 --> 00:17:15.620
Yeah, I'm not there yet either.
00:17:15.620 --> 00:17:19.700
I, I, I'm not super crazy about privacy and whatnot.
00:17:19.700 --> 00:17:20.800
Like, no, I'm not.
00:17:20.800 --> 00:17:22.420
Locations on my smartphone and stuff.
00:17:22.420 --> 00:17:25.400
But that somehow like crosses a little bit of a line to me.
00:17:25.400 --> 00:17:26.100
I don't know.
00:17:26.100 --> 00:17:27.460
I'm sure I'll be over it someday.
00:17:27.460 --> 00:17:28.640
Plus, I don't really.
00:17:28.640 --> 00:17:33.640
Yeah, I don't trust my kids to not just order a bunch of stuff all the time just by talking to it.
00:17:33.860 --> 00:17:34.120
Yeah.
00:17:34.120 --> 00:17:38.280
Like after what happened the first time I got an iPhone that had Siri on it.
00:17:38.280 --> 00:17:41.000
I know what the kids did to that thing.
00:17:41.000 --> 00:17:43.420
This is even more accessible to them.
00:17:43.420 --> 00:17:45.260
So I'm not sure I want that anywhere near my kids.
00:17:45.260 --> 00:17:47.100
Awesome.
00:17:47.100 --> 00:17:48.880
So that's it for the week.
00:17:48.880 --> 00:17:50.820
Brian, what do you got going on with you personally?
00:17:50.820 --> 00:18:01.700
I had an interview with Casey Rosenthal from Netflix on chaos engineering that I finally got edited and out last week on testing code.
00:18:01.700 --> 00:18:03.220
So that's out there.
00:18:03.220 --> 00:18:06.540
Oh, like chaos monkey, chaos gorilla, all that kind of stuff they do at Netflix.
00:18:06.720 --> 00:18:06.940
Yeah.
00:18:06.940 --> 00:18:22.220
And basically, we tried to talk about not just what they're doing there, but the concept of taking steady state measurements and doing experiments that might change the steady state on a system as opposed to traditional testing methods.
00:18:22.220 --> 00:18:23.120
It's pretty interesting.
00:18:23.120 --> 00:18:24.260
Yeah, nice.
00:18:24.260 --> 00:18:25.380
Oh, very cool.
00:18:25.380 --> 00:18:26.420
I'm definitely going to listen to that.
00:18:26.420 --> 00:18:26.780
That's great.
00:18:26.780 --> 00:18:27.240
How about you?
00:18:27.240 --> 00:18:34.680
So I spent the weekend reworking a bunch of my web stuff around the training course, training courses, training site, and so on.
00:18:34.680 --> 00:18:41.960
So I rebuilt a new player because I wanted to surface the closed captioning a little bit better for people, things like that.
00:18:41.960 --> 00:18:44.100
So I did a bunch of JavaScript and whatnot.
00:18:44.100 --> 00:18:48.480
And the other thing I did is I added full text search to the whole site.
00:18:48.480 --> 00:18:54.840
So you go there and you can search like into the videos even, into the text of the videos.
00:18:54.840 --> 00:18:56.160
So it's beautiful.
00:18:56.160 --> 00:18:56.860
Nice.
00:18:56.860 --> 00:19:01.440
This is what I was actually, yeah, this is actually what I was thinking about when we were talking about profiling.
00:19:01.440 --> 00:19:04.780
So when I first wrote this, I wrote it like what you might think of as like naively.
00:19:04.780 --> 00:19:09.460
I wrote it and it's all backed by like a bunch of text data in MongoDB.
00:19:09.460 --> 00:19:10.800
It's not using full text in Mongo.
00:19:10.800 --> 00:19:12.860
It's using something else that I've done.
00:19:12.860 --> 00:19:18.220
But basically, the backend is Mongo and there's a bunch of data in there, like 10 megs, 20 megs.
00:19:18.220 --> 00:19:21.440
I'm not sure exactly how much of text that I wanted to search.
00:19:21.440 --> 00:19:22.440
And I ran this.
00:19:22.440 --> 00:19:23.580
Oh, this would be nice and fast.
00:19:23.620 --> 00:19:29.060
And it was like 600 milliseconds a page, which like is acceptable maybe for other people.
00:19:29.060 --> 00:19:30.560
But for me, this is not acceptable.
00:19:30.560 --> 00:19:32.040
I'm like, oh, no way.
00:19:32.040 --> 00:19:33.080
This is not going to stand.
00:19:33.080 --> 00:19:34.080
Like, what is wrong with this?
00:19:34.080 --> 00:19:39.220
So I spent a lot of time in the profiler and I've gotten it down to 47 milliseconds.
00:19:39.220 --> 00:19:40.000
Oh, okay.
00:19:40.000 --> 00:19:40.340
Cool.
00:19:40.500 --> 00:19:43.220
So it's more than 10 times faster, right?
00:19:43.220 --> 00:19:45.860
That's like 10.5 times faster by using the profiler.
00:19:45.860 --> 00:19:47.880
And it was just, you know, this part's slow.
00:19:47.880 --> 00:19:48.780
How can I do this differently?
00:19:48.780 --> 00:19:49.480
This part's slow.
00:19:49.480 --> 00:19:50.420
How can I do this differently?
00:19:50.420 --> 00:19:52.000
So just, you know, very neat.
00:19:52.000 --> 00:19:56.240
If you want to see the fruits of that profiling, you can click the link at the bottom.
00:19:56.240 --> 00:19:56.660
Cool.
00:19:56.660 --> 00:19:59.900
Can we get a text search on Python Bytes?
00:20:00.080 --> 00:20:02.100
Yes, absolutely.
00:20:02.100 --> 00:20:04.200
We're getting full text search on Python Bytes soon.
00:20:04.200 --> 00:20:04.620
Okay.
00:20:04.620 --> 00:20:04.980
Yes.
00:20:04.980 --> 00:20:05.920
I think we need it though.
00:20:05.920 --> 00:20:08.840
I mean, we have a bunch of transcripts that we have interesting stuff in.
00:20:08.840 --> 00:20:11.760
We've got our pretty solid show notes for this podcast.
00:20:11.760 --> 00:20:13.380
I think we need a full text search.
00:20:13.380 --> 00:20:15.280
So yeah, we'll be sure to announce it shortly.
00:20:15.280 --> 00:20:16.100
Okay, great.
00:20:16.100 --> 00:20:16.780
Cool.
00:20:16.780 --> 00:20:18.040
I need one more weekend, I guess.
00:20:18.040 --> 00:20:20.660
Yeah, like adding work to you on air.
00:20:20.660 --> 00:20:21.480
Sorry about that.
00:20:21.480 --> 00:20:22.520
That's all right.
00:20:22.520 --> 00:20:22.840
It's good.
00:20:22.840 --> 00:20:23.200
No, no.
00:20:23.200 --> 00:20:23.840
It's on the roadmap.
00:20:23.840 --> 00:20:24.440
It's on the roadmap.
00:20:24.440 --> 00:20:25.220
All right.
00:20:25.220 --> 00:20:28.160
Well, Brian, thanks so much for finding these things and sharing them with everyone.
00:20:28.160 --> 00:20:28.860
Thank you.
00:20:28.860 --> 00:20:29.260
You bet.
00:20:29.260 --> 00:20:30.080
Catch you next time.
00:20:30.080 --> 00:20:33.860
Thank you for listening to Python Bytes.
00:20:33.860 --> 00:20:36.420
Follow the show on Twitter via at Python Bytes.
00:20:36.420 --> 00:20:39.300
That's Python Bytes as in B-Y-T-E-S.
00:20:39.300 --> 00:20:42.720
And get the full show notes at pythonbytes.fm.
00:20:42.720 --> 00:20:47.080
If you have a news item you want featured, just visit pythonbytes.fm and send it our way.
00:20:47.080 --> 00:20:49.800
We're always on the lookout for sharing something cool.
00:20:49.800 --> 00:20:53.160
On behalf of myself and Brian Okken, this is Michael Kennedy.
00:20:53.160 --> 00:20:56.780
Thank you for listening and sharing this podcast with your friends and colleagues.