Transcript #95: Unleash the py-spy!
Return to episode page view on github00:00 Hello and welcome to Python Bytes, where we deliver Python news and headlines directly to your earbuds.
00:05 This is episode 95, recorded September 12th, 2018. I'm Michael Kennedy.
00:10 And I'm Brian Huckett.
00:11 Hey, Brian. How are you doing this fine, fine Wednesday?
00:13 I am excellent.
00:14 Nice. It's also excellent that Datadog is sponsoring a show.
00:17 So before getting further, tell them thank you. Pythonbytes.fm slash Datadog.
00:21 It's a cool shirt if you go there and follow along. We'll talk more about that later.
00:25 You know, I feel like summer's coming to an end, and I've been quite lazy all summer.
00:30 I'm not sure I'm ready to get back into the main swing of things, but it's upon us.
00:34 Yeah. And do you know who else is lazy? Programmers are lazy.
00:38 Productively lazy. They put lazy to good use.
00:41 Yes.
00:42 They make lazy a virtue.
00:43 And so this was our segue from nothing into the first item, which is Dataset.
00:51 And Dataset is a Python package that bills itself as databases for lazy people.
00:58 And this is actually something I totally want to try because it looks fun.
01:03 Their premise is programmers are lazy.
01:05 Oh, it says, first, I'll just read some of the top.
01:09 Although managing data in relational databases has plenty of benefits, they're rarely used in day-to-day work with small and medium-scale datasets.
01:17 But why is that?
01:19 It's because people are lazy, and they'll throw it in JSON or CSV instead.
01:22 Oh, they say the answer is programs are lazy.
01:25 They'll use the easy solution.
01:26 And I guess I can't disagree.
01:28 I've used JSON format as essentially a local database before.
01:33 But this is kind of cool.
01:35 This is what it is, is that it's built on top of Alchemy.
01:40 So it's built on top of SQLAlchemy, so it can work with any database or a SQL-style database.
01:46 And it's just really easy.
01:47 It looks kind of like a NoSQL.
01:51 It's kind of hard to describe, of course, over the air.
01:54 But it's pretty simple and worth checking out, I think.
01:57 Yeah, I like it.
01:57 It does automatic schema creation, upshirts.
02:01 It has query helpers, like distinct and stuff like that.
02:04 So if you were to say, I'm just going to use like an in-memory dictionary or other things like that, it's kind of nice that it helps with some of those things.
02:11 So you just said a couple terms that I don't even know what those are.
02:14 So upcert.
02:16 Upcert is I have a record, and I'm going to try to save it to the database.
02:21 If it does not exist in the database, an update would fail, right?
02:25 But if it already exists, an insert would fail because it would be a duplicate key.
02:29 And upcert says, hey, data access layer, take this thing and save it.
02:33 If it doesn't exist, put it in there as a new thing.
02:35 If it does, make an update and set the values to the new one.
02:38 Okay.
02:38 And it also deals with sparse stuff.
02:40 So one of their initial examples is, let's say you've got people or something.
02:45 And in the first person, you give them a name and an age, and you can insert that.
02:49 The second person comes along, and you give them a name and age and a gender.
02:53 And then you can search easily.
02:57 And yeah, like you said, it deals with the schema for you already, and you don't have to deal with that.
03:02 Yeah, and the example that you have in the show notes here uses SQLite as the back-end database,
03:07 but it uses the memory connection version.
03:11 So you can just load it up with data and then query it and work with it.
03:13 And then when your app shuts down, it just goes away.
03:15 Maybe you output stuff to a JSON file or whatever.
03:19 So you don't even have to store the database necessarily.
03:21 Yeah, to be able to use some queries on information.
03:24 That's interesting.
03:25 But you can also just play with it this way and then turn it into a file-stored fileback database as well,
03:32 even with SQLite or with something else.
03:34 Yeah, absolutely.
03:35 Yeah, it's a good find.
03:36 It's quite interesting.
03:37 I like it.
03:38 Yeah.
03:38 So I have a question for you, Brian.
03:39 Okay.
03:40 Why is NumPy, not this thing that we're going to talk about next, but NumPy itself, faster than regular Python?
03:46 Do you know?
03:47 I think because it's got stuff compiled in C.
03:49 Exactly.
03:50 Because it's written in C, and it can even do parallelism and stuff.
03:53 It could take advantage of cores.
03:54 Like, my new laptop is ridiculous.
03:56 It has 12 cores.
03:57 Nice.
03:57 That's a lot, right?
03:58 So maybe we could actually take advantage of that with NumPy.
04:01 Well, if you have NumPy code, this thing that I'm going to tell you about takes it to another level.
04:06 It's called Kupy.
04:09 I think it's how you say it, because I think it's based on CUDA.
04:11 So Kupy is what I'm going to go with.
04:13 And its full name is KupyGPUNumpy.
04:18 And the idea is it's an API-compatible library with NumPy.
04:23 So all the NumPy features that NumPy has, you can call the same functions on Kupy, I called it.
04:30 But instead of running on your, you know, 6, 4, whatever cores you have on your machine, it runs them on the GPU cores, which is insane.
04:41 Oh, wow.
04:42 Okay.
04:43 Isn't that cool?
04:44 And I looked, and I did a quick little search, just like, hey, what's like a modern machine learning or data science type GPU you might get?
04:52 So pretty standard one might be the GeForce GTX 1080 Ti.
04:58 Okay.
04:59 These things are getting super expensive because of all the Bitcoin miners and stuff.
05:03 But anyway, you get one of these things, and it has 3,584 cores.
05:09 3,000.
05:10 And you can run your code parallel on all of those.
05:14 Wow.
05:15 So instead of, you know, like having like, oh my gosh, I can't believe I have 12.
05:19 No, you have 3,500.
05:20 And all you have to do, the only line of code you have to change is instead of import NumPy as NP, which is the very common thing that people do, you would say import Kupy as NumPy.
05:33 That's it.
05:35 And now you're running on these CUDA cores doing GPU-backed data science.
05:39 Okay.
05:40 Do you remember what CUDA is?
05:41 I don't know what CUDA stands for.
05:42 I bet it's an acronym because it's all capitalized.
05:45 Yeah.
05:47 There's a lot.
05:48 There's like layers upon layers of acronyms here.
05:50 I don't actually know what CUDA cores are.
05:52 Okay.
05:53 Yeah.
05:53 It didn't mean to put you on this.
05:55 It's the mechanism of parallelism on the GPU, basically.
05:58 Okay.
05:59 Nice.
06:00 But I don't actually know more than that.
06:02 Yeah.
06:02 Isn't that cool?
06:03 I like it.
06:04 Yeah, yeah.
06:04 So it's really cool.
06:06 It has this compatible API.
06:07 I threw a little code sample in the show notes there.
06:11 And if for some reason you're like, you know, I actually need to customize how my code runs on the GPU, which is a thing sometimes people do.
06:19 You can like program against the CUDA cores and CUDA kernels and things like that.
06:23 You can actually embed in your Python code, C++ code, and CUDA pie will actually compile that down to a CUDA binary, which is even cooler.
06:33 Okay.
06:34 I was just curious.
06:35 So I'm really not a hardware guy.
06:37 So bear with me.
06:37 You said you have 12 cores.
06:39 Is it on a laptop that you're running?
06:41 Yeah.
06:41 It's a new MacBook Pro.
06:43 So it's an Intel Core i9 maxed out.
06:46 And it's really six cores that are each hyperthreaded is how it works.
06:51 But the OS sees them as 12.
06:52 So are there GPUs on a normal laptop or on your laptop?
06:56 Or is this GPUs just something that, okay.
06:58 No, no.
06:59 There's a pretty high end one on my MacBook.
07:02 It's not as high end as this.
07:05 Not even close.
07:05 But, you know, maybe half or something, I would guess, in terms of performance.
07:08 That's a pretty bad estimate because I don't really know.
07:11 But yeah, you could run this on a laptop.
07:13 Yeah.
07:13 I'm just curious if the Kupai would speed up things on just on a laptop or something or if
07:19 it would.
07:19 I would think so.
07:20 I mean, you got to have an algorithm that's like well adapted to GPUs.
07:25 But if you did, then I would think so.
07:26 Yeah.
07:26 Okay.
07:27 Well, this is neat.
07:28 For the people that really care about it, really care about it.
07:31 So this is cool.
07:32 Yeah, absolutely.
07:33 And I mean, you can go and get like GPU clusters on AWS or on DigitalOcean or things like that.
07:39 Yeah.
07:40 Okay.
07:41 And so you could actually ship your code up there even if you don't have one.
07:43 Final note on this one is there was a PyCon 2018 presentation on this.
07:49 And so I'm going to link to the presentation as well if people want to watch 30 more minutes
07:52 of this.
07:54 I think I would.
07:55 Yeah, I actually do too.
07:57 It looks really interesting.
07:57 Yeah.
07:58 All right.
07:58 I'm feeling a theme coming on.
08:00 In episode 84, we did touch on somebody called in or called in.
08:04 We actually don't have phone lines.
08:05 Somebody contacted us and said, hey, you should cover pre-commit.
08:09 And we have.
08:11 We did talk about pre-commit in episode 84, but we just sort of talked about what it was.
08:15 But today I ran across this fairly cool article called Automate Python Workflow using pre-commit.
08:23 I like this kind of an article actually of, okay, here's these cool tools using pre-commit
08:29 black and flake.
08:30 How do I put that in my day-to-day workflow?
08:32 And how does it really work?
08:34 And this is from LJ Miranda.
08:37 So good job, LJ.
08:38 It's got a great graphic at the start with telling you that you've got changes.
08:42 When you add something, you go to get add, you go to staging.
08:45 And then when you do a commit, what happens is the pre-commit will intercept that part and
08:50 it kicks off whatever pre-commit hooks you've got.
08:53 Set it up.
08:53 And if all of those pass, then it lets the commit happen.
08:58 And if it doesn't, it kicks it back.
09:00 And then it shows you how to deal with all of the different configuration that is available
09:06 with pre-commit.
09:07 I like this.
09:08 It's a good starter.
09:09 If you're still quite not on board with pre-commit, this is a good article to read.
09:13 Yeah.
09:13 Pre-commit's pretty cool.
09:15 And that's a Python package that you install that then manages all the rest, which I think
09:20 that's great.
09:20 Yeah.
09:21 This article, there's a little video.
09:22 And I think it's an animated GIF or something.
09:25 A little short demo video that runs.
09:27 I don't know how to do this.
09:29 This is neat.
09:29 So it shows it in action.
09:32 Yeah.
09:32 Yeah.
09:32 That's really cool.
09:33 I like those little autoplay GIFs that'll animate stuff.
09:36 Because sometimes it's like, you know, if you could just see it happening, it would be
09:40 so much more easy to grok with little pictures trying to tell me.
09:43 Yeah.
09:44 And I also don't mind.
09:45 Something like that is fine if it has like an actual video to play.
09:48 But don't give me a half hour video.
09:50 A little couple minute video at most is great.
09:53 Yeah.
09:53 A half hour GIF, probably not the way to go.
09:57 I don't even know if you can do that.
09:58 So the way, one way to go that is good though, is to check out Datadog.
10:04 So this episode is sponsored by Datadog, as I said, and I really appreciate them supporting
10:08 the podcast.
10:08 Datadog is a monitoring platform that brings metrics, logs, requests, traces, all that kind
10:14 of stuff into one place across different systems and computers and all sorts of stuff.
10:19 So you can use their trace search and analysis, which lets you break down Python application
10:24 performance using high cardinality attributes like show me what this customer has done across
10:29 my application or show me all the behaviors for this URL and really easy to troubleshoot
10:35 your app.
10:35 So start doing that with your Python apps today with a free trial and Datadog will send you
10:41 a free t-shirt, which has a cute little dog on it.
10:43 So visit them at pythonbytes.fm/Datadog to get started.
10:47 So you were talking earlier about that cool little GIF thing, and I think you can do it with
10:51 Camtasia.
10:52 Like you can record.
10:53 Okay.
10:53 So I think you can do it with Camtasia.
10:55 You can record basically a screencast and export it as a GIF, which is already pretty
11:00 cool.
11:00 Oh, okay.
11:00 But this next item has a really nice little animated GIF thing going on as well because
11:05 it's super good to see it in action.
11:07 So have you heard about PySpy?
11:10 I have not.
11:11 So PySpy is interesting for a couple of reasons.
11:15 It's interesting because it's a cool tool that people can use in some places that they
11:19 could not previously do so.
11:21 It's a Python profiler, so you can hook it up to your Python application and it'll tell
11:25 you where your Python app is spending its time, what functions and what it's doing and things
11:30 like that.
11:30 And it acts kind of like the Unix top command, which will take over your screen and it'll
11:35 show you a list that's kind of updating every couple of seconds what's happening.
11:38 Okay.
11:39 That's pretty cool.
11:39 So I can hook up this profiler and it'll live show me sort of the equivalent of like a process
11:46 report, like a CPU usage report.
11:48 But it'll say right now you have these various functions that have run recently and here
11:51 like we'll put the most expensive ones on top, things like that.
11:54 Oh, neat.
11:54 That's cool, right?
11:55 And so you can watch that little graph, that little GIF thing and see it going.
11:59 This is written by Ben Fredrickson and it's just taken off.
12:02 I think it was started in July or something like that.
12:05 It's already got 2000 GitHub stars.
12:06 So what's even cooler though is it'll let you visualize your Python's app's time without
12:12 restarting or modifying your code in any way.
12:14 And it can attach to running processes and then start to profile them.
12:19 Oh, nice.
12:19 So normally profiling happens by I run a profiler, which runs my code, which does a bunch of stuff.
12:26 Or maybe I reverse, I'll write some code, I'll import C profile and I'll call a function,
12:31 start profile, save profile, export, et cetera.
12:33 Right?
12:33 Like you, it's really invasive.
12:35 So if you do it from the outside, like the profiler runs your app, you can't do it in
12:39 production.
12:39 It makes it slow, all sorts of stuff.
12:41 If you do it the other way, you're doing all sorts of writing code to change it.
12:44 This, you just say, Hey, there's a random Python program.
12:47 I'm going to go profile that and it'll just attach to it.
12:50 Nice.
12:50 Yeah.
12:51 You can just give it a process ID.
12:52 Yeah, exactly.
12:53 Give it a PID.
12:54 And what's cool is because of that, that means you can use it in production.
12:59 I could log into my web server that's getting pounded on, not responding correctly or whatever.
13:04 And I could actually begin to profile it without like wrecking my thing or slowing it down or
13:10 restarting it or whatever, or any long running process.
13:13 Like while the problem is happening, you can just attach to it and figure out what's wrong.
13:17 That's the key thing.
13:18 Cause maybe restarting it, rerunning it, it takes like four hours to get into that weird state.
13:22 You never know, right?
13:23 Yeah.
13:23 Oh yeah.
13:24 This is cool.
13:25 Sweet.
13:25 That's pretty trick.
13:26 So it's written in Rust actually, but it's pip installable.
13:30 So all sorts of cool things.
13:32 And then he even goes into, Ben goes into how does it work?
13:35 So there's a section on how does PySpy work?
13:38 So I'll just read you this and tell me if this sounds like a program you would have written.
13:41 It's not what I would have.
13:43 PySpy works by directly reading the memory of the Python program using process VM Red V system
13:51 call Linux or VM read on OS 10 or read process memory on windows.
13:56 And then it just analyzes the memory over and over.
13:59 That's crazy, right?
14:01 But it knows enough about Python to go, well, that means X.
14:07 And it just, you know, off it goes.
14:08 So there's a bunch of more details on how he actually makes it work.
14:12 I'll link to that section as well.
14:14 It's a pretty cool profiler.
14:15 And I really like the attach to running processes without affecting them.
14:20 That's pretty unique, I think.
14:21 And so I wanted to highlight it.
14:22 Yeah.
14:23 Nice.
14:24 And it can do icicle graphs, which I don't know why that would be neat, but it looks neat.
14:29 Yeah.
14:29 Those are cool.
14:30 I get sometimes, you know, just visually some things are really out of whack.
14:34 You're like, what is that big bar from?
14:36 Oh, that's a radot sort.
14:38 Why are we calling that a thousand times?
14:39 Yeah.
14:40 Things like that.
14:41 Let's just sort it once.
14:42 All right.
14:43 What do you got for us next?
14:44 I've got SymPy, which is just sort of fun.
14:48 SymPy is a, it's a, well, I'm just going to read it, read the little bit here too.
14:53 Symbolic computation.
14:55 So like you're in math class or something.
14:57 We realized early on with programming that you can, if you punch things into the calculator
15:02 too fast, it just mucks things up because you have rounding and various things like that.
15:07 So symbolic computation deals with the computation of mathematical objects symbolically.
15:11 This means that mathematical objects are represented exactly, not approximately.
15:16 And math expressions are with unevaluated variables are left in symbolic form.
15:22 And SymPy allows you to do that with Python.
15:25 And it's sort of blasted cool.
15:29 I've got a little example of doing an integration of, of the sine of X squared over negative infinity
15:37 to positive infinity.
15:38 And it will tell you what the answer is.
15:41 And these sorts of symbolic math manipulations for a lot of people, boy, if I had to do this
15:48 by hand, I'd be in trouble.
15:50 I did not do that well in math.
15:51 And so being able to do this programmatically is cool.
15:55 And the introduction and the website is pretty awesome too.
15:58 It has a bunch of live, it's got engine in the back that runs it.
16:03 So you can try the examples out and pop up a little window and, and do it interactively.
16:09 So this is neat.
16:10 Yeah.
16:11 There's a ton of cool stuff that comes out of this.
16:13 So for example, you can say X comma Y equals symbols X and Y.
16:18 And then after that, you can do algebraic expressions, like truly algebraically.
16:23 So like expression equals X plus two Y, not in quotes or anything, just like as if it were
16:27 regular math.
16:28 And then you could like add one to that expression and it'll reform the equation and stuff like
16:35 that.
16:35 You can ask it to do integration.
16:37 Like the example you have in our show notes is to integrate sine of X squared from a minus
16:42 infinity to positive infinity.
16:43 Instead of giving you the answer of, oh my gosh, what is that?
16:46 Like 1.5 dot, dot, dot, dot.
16:49 You know, it just says that's square root of two pi over two.
16:52 Like the exact answer.
16:55 That is pretty awesome.
16:56 You know, we just wrecked the whole math experience for so many of our listeners who are students.
17:01 They're like, you know what?
17:01 That calculus class, I just solved that problem.
17:05 Well, I would have loved this while I was taking calculus.
17:08 Yeah, for sure.
17:09 Yeah.
17:10 You could totally check your work.
17:11 Like there's no answers in the book.
17:12 Oh yeah, really?
17:13 Hold on.
17:14 That's pretty awesome.
17:18 So if you can take your laptop to your tests, you're set.
17:22 Yeah.
17:22 Probably not likely.
17:23 All right.
17:25 So this next one that I found, Brian, it's pretty cool.
17:27 So something that I'm going to, I've been digging into lately behind the scenes, and I'm going
17:32 to be talking more and more about probably in the next few weeks is async programming in
17:36 Python.
17:36 Like I've really been doing a lot with that lately and we'll have some cool stuff to share
17:40 pretty soon.
17:41 But that means I'm running across all this cool async stuff.
17:45 So you've heard of WSGI, WSGI, which is the web service gateway interface.
17:50 That's like how Pyramid, Flask, Django, all those things work.
17:53 None of them do a great job of supporting async programming because fundamentally this WSGI
18:00 interface is synchronous.
18:01 It can't be made async.
18:02 Yeah.
18:04 So there's this other framework called ASGI for async gateway interface, I guess, that
18:10 allows these frameworks to be asynchronous.
18:13 So the thing I'm talking about this week is Starlet, which is an ASGI web framework.
18:19 And I like its little subtitle, the little ASGI framework that shines.
18:24 It's cute.
18:27 It is cute.
18:28 So it's basically intended to build high performance asyncio services.
18:35 So if you have anything that talks to a database, to caches, to file systems, things like that,
18:40 even calls other web services or microservices, super easy to build.
18:45 The API is basically Flask, like a Flask-ish API.
18:49 And you create like a web method.
18:52 You say async def regular view method.
18:54 And you go do a bunch of stuff.
18:56 And it has cool support for like response types.
18:59 So you can have a file response object that you just send back to the framework that's
19:03 based on async AIO files, which is an asyncio file based thing.
19:08 And there's a lot of nice integration like that.
19:10 Okay.
19:10 You're just interested in this or do you have an application that you're going to try to?
19:14 No, I'm building a course on it.
19:16 Oh, okay.
19:16 Trying to make a nice, well-rounded async concurrent programming Python course.
19:21 Oh, well, yeah.
19:22 So I've been building tons of little apps and stuff.
19:25 So here we go.
19:26 Here's one of them.
19:26 Cool.
19:27 If you want to build an app that is way more scalable, you know, 10 times more scalable
19:31 than regular web apps on the same hardware and whatnot, it's pretty easy to do if mostly
19:37 what that web app is doing is waiting, right?
19:40 You can just, you know, basically the asyncio web frameworks can just adapt to that more
19:46 easily because they're not blocking while they're waiting.
19:48 Also discovered a couple of cool things while looking into this.
19:52 One is they say you should install the ultra JSON package, which the pip install command
19:59 was ujson.
19:59 And that is a replace, basically a drop-in replacement for the JSON built-in that is like
20:06 between 50% and three times faster.
20:09 So if you're doing a lot of JSON, you can just use ultra JSON.
20:12 And that's pretty awesome.
20:13 Yeah.
20:14 Okay.
20:14 I have to check that out too.
20:16 Yeah.
20:16 So all you have to do is, you know, import a ujson as JSON.
20:21 And then that like makes your code faster.
20:23 Of course it has to be there, right?
20:25 But that's pretty sweet.
20:26 The other thing is you've maybe heard of G Unicorn for the traditional web frameworks.
20:31 There's a uveacorn, which is based on uvloop and gunicorn, which is also pretty awesome for
20:37 these async web frameworks.
20:38 Well, it's cool.
20:42 And I get the name, but eventually if we, if everybody starts using that, people forget
20:47 where that came from.
20:48 And it's just going to be a weird word, uveacorn.
20:50 I know.
20:51 Uveacorn.
20:53 No, it's uveacorn.
20:54 You got to understand where the name comes from.
20:55 Come on.
20:56 Get it together.
20:58 Well, that's it for our items.
21:00 I do have some extra stuff to share.
21:01 How about you?
21:02 Just one thing I wanted to point out if I remember it.
21:04 Okay, cool.
21:04 I'll go first.
21:06 You can think.
21:06 So really big news.
21:08 You and I, we had a good time at PyCon, right?
21:10 Oh, yeah.
21:10 I can tell you when we're going to have a good time again.
21:13 It's going to be, if we can go to a tutorial, it's May 1st and 2nd.
21:20 If you want to go to talks, it's May 3rd, 4th, and 5th.
21:23 And if you want to do the sprints, it's May 6th, 7th, 8th, and 9th.
21:27 So basically, the announcement is that the PyCon dates are out.
21:30 Yes, and it's not over.
21:32 I don't think it's over Mother's Day this year.
21:35 I hope it's not.
21:35 I hope it's not.
21:38 I also have a quick little follow-up.
21:40 You talked about the pre-commit package.
21:42 Also, another listener, Matthew Lehman, sent in some notes about how his team is using it
21:46 and basically talked about how they're using pre-commit, the Python package,
21:53 so that their Flake 8 and Black and other things that automatically run during continuous integration
22:00 also automatically run when people do Git commits.
22:03 So they have fewer failing builds, which is pretty awesome and has a couple of nice links.
22:08 So I threw that in there at the end.
22:09 And then, finally, you talked about the Gang of Four Patterns last week, right?
22:13 Yeah.
22:14 So John Tosher, I think he's right, sent us some messages pointing out another talk from PyCon AU
22:20 called You Don't Need That, which is pretty cool.
22:23 And it basically talks about how if you study the Gang of Four Patterns,
22:28 a lot of what they were doing was because they were using Smalltalk or Java or C++.
22:33 And in Python, here's a new way that you just basically don't need that pattern.
22:37 So pretty cool talk.
22:38 And that was a link to the video for that.
22:40 Yeah.
22:41 Yeah.
22:43 If you translated the Gang of Four book directly to Python, it would be like a pamphlet.
22:47 That's right.
22:48 Nice.
22:50 Do you remember your item?
22:51 I did not.
22:52 So...
22:53 Oh.
22:53 Save it for next week?
22:54 Yeah.
22:54 Yeah.
22:55 Save it for next week.
22:55 Yeah.
22:57 We'll do this again next week, right?
22:58 Yeah.
22:59 Maybe we should just do it every week.
23:00 Yeah.
23:00 All right.
23:01 Deal.
23:01 We'll do it every week.
23:02 Okay.
23:03 Cool.
23:03 Cool.
23:04 All right.
23:04 Well, thanks for doing the show this week.
23:05 Thank you.
23:06 You bet.
23:07 Bye.
23:07 Bye.
23:07 Thank you for listening to Python Bytes.
23:10 Follow the show on Twitter via at Python Bytes.
23:12 That's Python Bytes as in B-Y-T-E-S.
23:15 And get the full show notes at Pythonbytes.fm.
23:19 If you have a news item you want featured, just visit Pythonbytes.fm and send it our way.
23:23 We're always on the lookout for sharing something cool.
23:26 On behalf of myself and Brian Okken, this is Michael Kennedy.
23:30 Thank you for listening and sharing this podcast with your friends and colleagues.