« Return to show page
Transcript for Episode #202:
Jupyter is back in black!
00:00 Hello, and welcome to Python bytes where we deliver Python news and headlines directly to your earbuds. This is Episode 202. Recorded September 30 2020. I'm Brian knockin and i Michael Kennedy. Yeah. And this episode is brought to you by data dog. So Thanks, David. Oh, yeah, thank you data dog. Good to have you back where I need to be back. We missed you, and a little bit of mascara, but I'm all better now. So that's good to hear. We're recording this September 30. But but then this comes out, we might have a new Python. So did you know that I did not know that. But I'm very excited that you're covering that first. Yeah. So usually, there's about a week delay. And that's about when Python three nine. Yeah, so Python three, nine, there is a RC two or release candidate two was released September 17. The final is scheduled for release October 5, of course, you know, it's software, so things can come up. But we're looking forward to starting using three nine right away. We're linking to the change log, there's a lot of different lists for what is in three, nine. But I wanted to highlight a few features that I pulled out from the change log, the first couple I think I'm most excited about, there's a dictionary merge and update operators. So the merge operator is just the bar. So you can have two dictionaries and do bar to merge them together. And the bar equal for the update. The update kind of means it doesn't mean append, it means like if there's new stuff added to the older other dictionary, but if there's changes change it. So I think this is just when I first read about this, I thought why don't we already have this, this just seems obvious. So I'm glad to have a merge operator. Yeah, I thought this, there's already a way to accomplish this with the curly bracket, Star dictionary, Star Star dictionary, Star Star dictionary, which has the same effect. It's a little bit longer. I think this is for consistency with other container objects, like sets that have a pipe behavior. So it's like, oh, you can just do a dictionary? Yeah, I think it's nice. I had to read a little bit. The next one is remove prefix and remove suffix has been added to strings. And also added to bytes byte array and collections user string, which is cool. I'm most excited about this. Why are you? Yeah, because this actually, when you look at like the workarounds to do something, the workarounds are ugly. If you just want to, it's just I have like this string that might be at the beginning of my of another string, I want to remove it. Like just this prepended stuff that happens all the time. So like spaces or things like that, what would you use it for? Well, yeah, the same thing. There's a lot of times there's like, oh, there's this string that always starts at the beginning of this line. And I just don't want it, right. But the trim, trim, start trim and trim. If you give it characters, it doesn't mean remove that string, it remains remove, like, take each one of those characters and remove all of them until you don't run into any more of those characters. And so if one of the characters of your string happens to be the first character of the stuff that's left, it'll also get ripped. Yeah, you just want a specific string to hear removed a set of strings, right? If I'm like, I want this substring off the front, you know if it exists, but not if it doesn't, right, you don't do the test. And anyway, it's just it cleans it up and makes it a little more predictable. Okay, yeah. Next thing is a type annotations have a change that you can now use the built in collection types, such as lists and dict as generic types, instead of having to import typing or from typing import capital list or capital dict. I'm really excited about this. Wait, I didn't get back. I'm more excited about this than removed. Yes. Because I'm always annoyed when I have to like because I I'm starting to use type hinting for a, you know, for interfaces. And you don't need to import anything to do that. Except for if you have a list or a dictionary or set or something like that. And now you don't have to do that anymore. And I'm very happy. I'm still waiting for the optional operator. Question mark or something rather than capital O optional? Hmm. Yeah, that'd be good. Yeah, we've talked about the pig parser. Before but the three nine is where the the new pig parser comes in. I don't know if it'll affect anybody. But it's neat. Yeah, it's supposed to make extending the language with more complicated behaviors and more nuanced syntax. easier. But it won't affect you or me probably writing code day to day. I'm not gonna touch that thing. Yeah, I'm not. I was intrigued by this. Any valid expression can now be used as a decorator. This is Pep 614. I haven't quite wrapped my head around it. But I think this will change the way we use decorators. But I think we need a few tutorials to be written to people to figure out how to use this to maybe we should just make decorators like a lambda expression. Because I know you have later in the show some really cool uses of lambda expression. So we can come on guys. A huge lambda expression could be a decorator. Yeah, that'd be cool. Or really bad. Anyway, the other thing last thing I wanted to mention
05:00 zone info was a new module that comes in, which is cool has a in a timezone databases support. That's part of the standard library now. And there's a whole bunch of other stuff too. So we're going to link to the change log, and people should check that out. Very cool. Exciting. We're gonna have a new Python and Python comes faster now it does. I think they change the release cycle to 12 months. Oh, yeah. So your month 310 or whatever the next thing is, should be out soon. We'll just put our calendar first week in October, we should expect a new Python. That's right. What happens in October Halloween and Python? in black, black cats black. Yeah, because you want to go out into your costumes and your scary costumes. At night. When it's dark. It's no fun to do Halloween in the day because it looks fake. Or maybe you just have a Jupiter notebook. And you're a fan of black but you would like to format.
05:51 So Mary Hong sent over a cool recommendation based on some stuff we had over on talk by that so and talk Python I did a auto racing episode with Kane Replogle and his pick for pi package recommendation was black sail magic, which I think we covered on the show as well. I'm pretty sure she said you should check out Jupiter black. And Jupiter black is kind of like the same thing. But instead of having to type into the cells, you can just press it gives you a toolbar button you can press and off it goes. So that looks really cool. Because your toolbar button and a couple of hotkey shortcuts, keyboard shortcuts to format single cells and format all the cells. Okay, that was gonna be my question. Can you just have it do the whole, the whole shebang once. Exactly. And that's what was it also run, you can also just run instead of running black in your ci you can run j black or as a pre commit hook or something like that. Okay, so I believe with the one the black sell magic that I called, talked about previously, you had to like type it into the notebook. And it would would do it which is cool. But this is more of and I talked about there being an extension that would kind of do it for the whole notebook. But it was it had a huge message like this is no longer supported. So like I'm not so sure. So this gives you both a COI and hotkeys for the whole. The whole notebook, which is seems cool. Yeah, it does need definitely check that out. Yeah, absolutely. quick and simple. But to me, that's one of the huge shortcomings of Jupiter, a multiple levels. I think the auto formatting like Jupiter should format code as I type, I shouldn't have to like run command line things against it to get formatted code like, you know, Visual Studio code, pi charm. It gives you that support as you go. You're not like spacing around tabbing around the other. I really wish Jupiter did better was autocomplete. Yeah, yet, yes. If you hit dot, nothing happens. But if you hit tab, it will come up. And I think there's a lot of you know, compare that to the other modern editors. There's a lot of room to make improvements on those areas. But you know, this at least having a keyboard shortcut, like reformat document, you know, Command Shift B or whatever? Ctrl Shift B? That seems really like a good start. Do you know if Jupiter lab has any different supporters? I don't think so. I think Jupiter lab just has a more other UI elements like you have a ability to get to the terminal and do other stuff. It's not just the notebook, but I don't think in the fundamental editor experience change. I could be wrong. I don't compare them that often. But I mean, if they get to that point, it wouldn't be an it would be a JD right. Jupiter development. That's right at JD. Exactly. All right. Another cool thing is data dog. This episode of Python bites is brought to you by data dog. Let me ask you a question. You have an app in production that is slower than you like is its performance all over the place, sometimes fast, sometimes slow. Now, here's an important question. Do you know why? with data dog you will you can troubleshoot your app's performance with data dogs end to end tracing? Use the detailed flame graphs to identify bottlenecks and latency in that finicky app of yours. be the hero that got the app back on track for your company. Get started today with a free trial at Python bytes.fm slash data dog. Awesome. Thank you did it off? No, it's not awesome. DDoS denial of service against your web app. Yeah. So this is a couple of things. I've got our listeners suggestions. And unfortunately, since I kind of been out of commission for a week, I forgot who suggested this. So my apologies to the listener who brought this to their attention. There's an article written by Jacob Kaplan moss called understanding and preventing denial of service on web applications. I saw it but I kind of dismissed it right away because I thought it was just another like about all languages. But this one is focused on Python and has some specifics on Django. So I think it's, it starts off with a good discussion of what denial of service is, and then sort of kind of what to do about it and how to prevent it from happening and fix things on your with your application. But it kind of led me down around
10:00 Whole, and I kind of enjoyed it anyway, there's one example that it lists as a hidden, I think I've heard but I don't remember if we've talked about it on the show, which is called a ri DOS, which is a regular expression denial service. We talked about this, you know, I don't think so. But yeah, there's certain types of like computationally expensive things that are not going to match or useless or whatever you can send over regular expressions that all cause all sorts. And what's interesting, so that it says reduce bugs occur when certain types of strings can cause improperly crafted regular expressions to form extremely perform poorly. And I'm talking like, really poorly. What's interesting is they're not even complicated regular expressions. There's like, for instance, a match a set containing like a carrot, one or more characters, or zero more characters, followed by another zero or more characters, followed by a bee, or something like that. And there's like a little graphic on one of the links on this page that shows how slow this is, it has to match all these different things. And it's, it's bad. Anyway, some languages have stuff put in place to try to work this sort of thing, but Python does not. But we have a solution. So this article links to another article called finding Python reduce bugs at scale using D lint, which I was like de lint. What's that? So I went and looked there. D lint is a flake eight plugin. So you can check for denial of service vulnerabilities. When you're checking everything else with flake? Oh, that's interesting. I'd never never heard of that. Yeah. So this, I was thinking it's a security plugin. I sort of linter for Python. Man, I was thinking, is there a difference between that and bandit and the authors of D lint? Were expecting that. So the first FAQ is, what about bandit? So there's a discussion about whether or not to use bandit but the the TLDR is, it checks for different things than bandit so you can run both of them and they run perfectly fine on the same codebase. Yeah, super cool. DDoS is no fun, distributed DDoS. A whole lot less fun. So having to deal with as I've had to deal with that before, and managed to get ahead of it. But if there's thousands of computers, trying to do bad stuff to your website, all at the same time from different locations. Not easy. You've had to do that. But for maybe talk for talk by then training. Yeah, yeah. People, thousands of computers are trying to like do all sorts of stuff at the same time. So even things like let's just block this IP address, or let's put in checks that if this IP address does five bad actions, we're gonna block it for an hour or a day or permanently, none of that would work because it was so many different computers, or devices or whatever, anyway, not fun, it'll definitely get your attention.
12:58 Another thing that will get your attention is pictures, we love pictures. So show make child Do re sent over a project that he's working on that I think is pretty cool. So I decided to cover it, it reminds me of something that I'd worked on a long time ago, too, he works with computer vision. And now this is not just about I think this is useful beyond computer vision, which is why I'm covering it. But especially for computer vision. What he has to work with a lot is there's an image and you're trying to find all the people, and maybe the bicycle, or all the cars and things the car needs to worry about if it's a self driving car, right, crosswalks, lights, whatever, you want to put little pictures around and say the computer vision and the ML algorithm said this is a car. Where's that duck over there? That's not a car, right? So you want to label them visually. So often, what they do is they put boxes around them, and they put some text to say this is the person this is a car, this is a duck and drawing those boxes with the picture with the like the label lined up just right or affixed to the edge of the box or sort of an arrow pointing down to it and things like that, you know, kind of tedious. So he wrote a thing called beebox visualizer. which lets you just say here's a image file like a PNG. And here is the coordinates of this box. And the label I want you to put on it and boom, it draws like a nice fancy little box around the object that you talked about and puts a well oriented label on it. If you're doing any sort of science stuff, or image analysis where you want to put, like, here's what the computer thought is over here, and here's what we're calling it, you know, for all sorts of analysis. This is a handy little library. Yeah, this is cool. Yeah, you're not everyone's gonna need it. You don't need it for like a fancy web app or whatever. But I think if you're trying to do this kind of work, here's a super simple like two or three lines of code. Put a nice bunch of bounding boxes on top of things and pictures with nice labels. That seemed cool. Yeah, I can also see like lots of different, like student projects where they're using working with the
15:00 The images and algorithms around it to be able to highlight particular that they're working on or something like that, I think uses for sure. I see a lot of science that are doing it. Like we just we detected this as a star here, this is a star, here's the name of the star or whatever. Yeah. And to just sort of lump all of the drawing the box stuff into a library, this is cool. Like it. Yeah, for sure. You've got some nice fancy code examples, like taking your Python code to the next level that tells about it. Next level, I was debating as to I've got like a devilish streak in me, I think as to why I'm bringing this in. This also was another listener suggestion, my apologies to ever sent it, I forget, I think it's a just GitHub Gist, I'm pretty sure. And it's how to never use lambdas.
15:47 So I'm like just chuckling even at the name. It starts off with a brief example showing you how to how to rewrite a power function as a lambda. And, you know, anybody sort of familiar with lambdas, that's kind of a common use cases, I've got a little like, single one or two argument function that I need to pass in as an expression instead, and I can't pass in functions. So I pass in and lambda says it's kind of a bound function sort of thing, right? I want to do a sort on a list. And I want to sort by its all users, I want to sort by their login date. So yeah, lambda, you go say u dot login date, or something super simple like that. Right? That seems good. Anybody scared of lambdas? If you look at the initial example, that's a good simple thing. It's a they're not scary. They're just basically functions without names. But they have to be expressions. So first one, no problem. But then he jumped right into some crazy code and saying he I don't know that, who wrote it. But the crazy code right away is some code with import statements. So how do you get around import statements? Will you somehow it's a using Dunder import in referencing the library you want to import with as an expression passed as an the value of that passed as an argument to another lambda. And these are nested lambdas. So right off the bat, first bad example is horrible. So don't do that. This is almost like a decorator lambda.
17:15 things. It's Yes. Oh, it starts off frightening. And then shows an example of a class definition. And then how to lambda phi class definition as Yes. So you can have a lambda expression be in the entire class definition. Weird. And then the last example, which is my favorite, is an entire working flask application as a single lambda expression. It's truly horrible stuff. You should not do this. But it's amusing to read about, well, if your goal is have fewer lines of code, like one line for an entire flask application. That's impressive. I think it has to it has two routes, not just one. Impressive. Yeah. Yeah, that's great. Cool. The some sometimes have these like, let's see, these ideas taken to extreme are pretty interesting. And definitely, that's the lambda. Cool. Now, one good use case of this, I think, maybe I'm might get struck by lightning by suggesting this. But if you're in, if you got a CS student, and you're doing really good, you got like 110% in the class, maybe turn in a homework assignment. That's just entirely lambda expressions.
18:25 Or if you just feel really devious, and you get some homework assignment, you're super frustrated with, you're like, you know what, you can ask me to do something silly. And you said long as it works, it counts. You're getting this back.
18:41 Anyway, yeah, I'll probably get Yeah, maybe I'll do that. That's a meal for that. Sorry, what's not mean is contributing to open source generally? Yeah. That's not mean. That's nice. Yeah. So Alexandra, wouldn't listeners sent over an article or blog post by Vincent wunderman. And it's called uncommon contributions, making an impact without touching the core of a library. I think this is one of the challenges paradoxes that you might run into is like, you find these libraries that are very popular, and you love them, and you want to contribute to them, like I love Django, I want to contribute, I love flask, I'm gonna contribute to it. I love requests, I want to contribute to it. Well, guess what? All of those things are highly polished. And they have a lot of different use cases, it's very hard to make changes to them, because any little change will have a potentially huge effect on a lot of software. Right. And it's also just intimidating to touch the code for a large project too. So yeah, exactly. So here are a bunch of ideas of things that are low danger, low stress, probably a lot of people haven't taken advantage of them. I'll just go through a couple that Vincent works through. One of them is just providing better information. So he contributed to this project called rasa. And I don't know what rasa does, I forgot to check out so it's, it has SLI se rasa Se Ra.
20:00 dash dash version. And what it would say would be like one dot two dot seven. Okay, that seems totally legit like that features implemented, right? But then and by the way, if you look at this article, if you open up the actual article, Brian, you'll see like, each one of these has like a beautiful, like XKCD style picture, talking about the story. So for like the info one, it says, to debug this, like somebody says, Hey, Ross is not working. All right? Well, what in order for me to debug this, you got to give me your Python version, your operating system, all the versions of the packages that you have, like, are you running out of a virtual environment, etc, etc. So what he did was that, alright, when you say dash dash version, now, you're going to get the version of Python, the path, your virtual environment, the version of related packages, that rasa depends upon things like that. Nice, that's easy to do. That's not a challenging, you know, too difficult sort of implementation there. The next one is to set up a cron job to run tests, checking the dependencies having affected a package. So I know you know about continuous integration, right? Check in changes come in to run some rerun your unit tests. That's great, right. But what happens if an underlying package as an underlying dependency, so the dependency of the dependency, is that a grant dependency? I don't know, underlying dependency has a change that potentially makes something operate differently. What is going to trigger your ci if you don't make any changes to your code there? Yeah. Right. So
21:39 he actually ran into this psychic Dasha Lego is a package that ends at works on and he discovered that it wasn't working for some reason, because scikit learn introduced a minor but breaking change. So what he set up was a cron job with GitHub actions, to just run that once a day to say, hey, just in case something which we don't know about, or, you know, directly affects our repo, we still want to run those tests again, just to make sure like, yeah, things are still good. Yeah. What do you think is good? And I also wonder, if the breaking change? Was that the change with the version output? produced? Yeah, I did think about that. Actually. If somewhere in there, there's like a test, you know, someone has something to just test that calling that on the command line. Alright, spellcheck spellcheck is easy. Yeah. There's always spelling. Yeah, lighten. could always Yeah, because a lot of times the symbols we use are not proper words. But I do really appreciate things like pi charm that will find misspellings inside of various things. Right? Like if you've got a function, check, login, and I enter switch, it'll say login is a mess. Yeah. But you know, it's still hurt grammar, checks, grammar, checking people's doc strings, or Yes, and code and stuff like that. Exactly. So there's a nice example in there about looking for a country, I think, where it was Spain, but Spain was misspelled, or you know, as a doc string example. So that's definitely something easy to do just run a spell checker on the doctrine. One, I'm a real big proponent of is having better error messages. Oh, yeah. So it's so frustrated, like just today. Yesterday, I was asleep. I'm not sure exactly when I got this. But I got a message from student taking the Excel course says, Hey, I tried to run cookie cutter. Because during the Excel course, we talked about setting up like a cookie cutter template that gets everyone started. It says I tried to run cookie cutter, and it didn't work. Here's the message. And it just says something about the git clone that cookie cutter internally tries to use failed, and it doesn't say anything about you know, is Git not installed to get what was the error from get? Like it just Nope, it failed, right? You're just like a random like this command failed. Great. So if there was a better error message, like we tried to do that, but you don't have permission to write where you tried to clone this thing to or get is not installed or something like that. They could have been, oh, I need to install git, right? They would have been much better off. So error messages. So they work on means it works on something called what Lee's and it allows for optional dependencies like it has some of its functionality, but you might have to pip install what leaves bracket something else like here's TF hub, right? And in order to use a certain part of that, that depends on that optional dependency, you have to have that installed, but you don't have to install it to use library, right. So you could run into this problem where you try to use a feature that doesn't have a dependency. Yeah. So instead of just going none object has no attribute, whatever, right or whatever is gonna happen. There are no libraries such and such. It says now the air is in order to use convert, convert language, you'll need to install pip install what leaves bracket TF hub, see installation guide here. And there's the
21:39 Like that is a proper error message telling people how to fix their Yeah, yeah. And you know, it's just it's not that much work. But just finding these problems, like how many times just appear on Stack Overflow, rather than just like, let him go find it on Stack Overflow, and give it a message. So I recently added something like this to fluid check. Remember, when we talked, I think you brought this up talked about using raise from on exception. So you could say raise an exception. But if you do that in a catch block, you get weird. Other issues, right. So by default, it would say something like, during the handling of the above exception, another exception occurred. And that sounds like one thing broke another. But like in this library, it's supposed to find errors and then report them to so if you use race from it'll say the above exception was a direct cause of the following exception, which makes it sound like okay, this is this is the source of the error, right. So just simple changes like that are really nice, get better error messages, failing unit tests. And I'm not talking about going around and finding projects that have failing unit tests. But rather, if you want to make a contribution, or you'd rather you find a bug, rather than just submitting a bug on a GitHub issue tracker saying, this doesn't work. I tried it, and then having a long conversation about it, submit along with it a failing, create a PR that has a failing unit test for that issue. That's awesome. Yeah, right. To go, look, it's supposed to do this, that's failed. If you make this fast, I'm happy, right? And then they can fold that into the unit test suite, and so on. And then also, finally, there are some packages that might have names that result in import statements that are very confusing. So for example, if you've got a package, and in the package, there's a file.pi, lowercase F, and within file.py, there's a capital file class that those would be totally reasonable that what you call the files, file, pi greeter class in it. Depending on how the package is set up, you could set up with end up with something like from package import lowercase file, and from package import uppercase file would both work but obviously don't mean the same thing. So in that case, they recommend like renaming certain files that are really meant to be used internally as an option. Yeah. Like in the example, I don't even think it was different. I know I just stared at for a while as well. Okay, that's it for all those recommendations. But I think there's definitely some good ones in there. I like the error messages a lot. I like the failing unit tests as well. Those are my two faves. Yeah, I just even thinking about all this stuff that talk about documentation, not about creating documentation just about the spell checking within documentation. Okay, well, I probably well, I guess that's docstrings, I was pretty limited. I had documentation to this because yeah, projects always are liking it, or sometimes behind. So the documentation might be great. Somebody was really gung ho about it for a while. And then there's been improvements. But the new features just haven't made it into the documentation all over the place yet. Yeah. Or tutorials. There's no good tutorials showing like this part of code. Like there's maybe a quickstart. But then like the advanced hard stuff, there's no examples. Definitely.
21:39 What extra, you got, well, I just learned about this this morning. So I was gonna just not give a whole big thing. But just to let people know, I saw somebody on Twitter, of course, obviously, being really bad about referencing people, but sorry, a new thing. There's a as of September, early in September, there was a collaboration between the people in Wonder Woman, and the Smithsonian Learning Lab and NASA and Microsoft. So now there's a we're linking to an article that's learned to code with Wonder Woman, Smith, Smithsonian and NASA. And so there's a whole bunch of ideas that there's, there's one there's a lot of schools that don't offer computer science, education. And also with COVID, and everything, some people have kind of that's kind of dropped off a little bit. And people are focusing on core classes, which is probably fair, but if you still want to have your kid learn programming, this might be a way to do it. And this is pretty cool. And and looks pretty neat. There's some Wonder Woman adventure stuff and, and NASA exploration, and there's even a little bit of Minecraft in there. It looks really fun. And at least some of the tutorials are in Python. I haven't checked out to see if all of them are Python or not. But there's a lot of Python in there. Some of them use blocky, but some of them like the super quiz from Wonder Woman uses Python and then some of the NASA ones which sets will actually call that the NASA Microsoft partner ones last time, but not this the Wonder Woman one. So yeah, it's a mixed vehicle. It's neat. I got it. Yeah, I can't wait to see what see 94 I'm looking forward to it.
21:39 Yeah, definitely. I have a quick thing as well. I'm going to be doing a presentation at Indy pi. So virtual online.
21:39 Line, obviously, when is this this is coming up on October 13. So they're going to be doing a Python memory deep dive, both like understanding some of the internals of Python memory as well as some optimizations that you can make to go faster and use less memory. So you guys can sign up for that. And and check it out. If you like a memory talk and you forgot the date. That's funny. Yeah, I know.
21:39 Maybe we just haven't finished it off. You know, I think we actually may have covered this a long time ago when it came up. I'm not sure. But I don't remember Cabernet. So it was suggested by Tim Jacobson, Kelsey high towers project, no code. This is a hilarious repo. But you kind of have to go look at it. So the tagline is no code is the best way to write secure and reliable applications, right, nothing deployed nowhere. And you highlighted that the style guide was good. So I went and looked at that says no code style guide. All no code programs are the same regardless of use case, any code you write is a liability. So as to how beautiful the style guide a guide talks about file extensions, says, no code is store is not stored in files. But if you must use the dot node file extension, like example, main dot know, there are linters built right into your POSIX based system here Linux systems. So for example, you can check by saying d u dash H space main.no. And if it outputs zero, then you have no code, which is D, you know, it's like a line count the number of lines of text file.
21:39 And then they have code reviews. The no code community has adopted the following conventions before reviewing code changes, when the code changes contains no code additions or modifications. Lgt looks good to me. When the code changes include code additions, or modifications, ci al code is a liability.
21:39 They should be that code change should be rejected immediately. And then the final kicker for me on this one is that there's 43,000 stars Yeah, 4000 forks of it, which are funny, but the thing that made me laugh is there's 360 people watching for changes in the note
21:39 story where there seems to be no changes.
21:39 That's funny. And there's three 3.0 to add Docker support.
21:39 Issues filing is oh my god there are what are they here for?
21:39 Oh, yeah. suspended Arctic code vault controversial reconstruction aviator chain generator keys. All right. No water in the water cooler is one of the issues.
21:39 And then the contributing at the other README says contributing? You don't.
21:39 Sweet. All right. Well, that's a good one. Tim and Kelsey, nice job with that project. Well, thanks a lot again for lovely podcast. Thank you for listening to Python bytes. Follow the show on twitter at Python bytes. That's Python bytes as in V yts. And get the full show notes at Python bytes at FM. If you have a news item you want featured just visit Python bytes.fm and send it our way. We're always on the lookout for sharing something cool. This is Brian Aachen and on behalf of myself and Michael Kennedy, thank you for listening and sharing this podcast with your friends and colleagues.