Brought to you by Michael and Brian - take a Talk Python course or get Brian's pytest book


Transcript #84: Vibora web framework: It's fast, async, and means viper

Return to episode page view on github
Recorded on Wednesday, Jun 27, 2018.

00:00 Hello and welcome to Python Bytes where we deliver Python news and headlines directly to your earbuds. This is episode 84 Recorded June 27 2018. I'm Michael Kennedy and I'm Brian Okken and Brian You brought a special guest along for this one. I'm so excited that we have yet another perspective here. Yeah, welcome Nina Zakarenko Hi, it's great to be here Yeah, it's really great to have you on the show and it's gonna be fun to have your perspective on all these things So let's get started before we get into the topics just want to say thank you to DigitalOcean DigitalOcean is great.

00:30 If you want to try some of their cloud hosting, just go to pythonbytes.fm/digitalocean.

00:35 And for new users, you get $100 credit.

00:37 That's pretty sweet.

00:38 Hey, Brian, we've talked a lot about Python packaging, right?

00:41 - We have, and I'm going to talk about it more today.

00:44 - We were trying to talk about how to do it right, but sometimes it might go wrong, right?

00:48 - Yeah, so one of the fun things is, well, I've tried to, I'm working on switching packages to use Markdown versions of READMES, but a lot of them are in restructured text, And sometimes really either any one of them, sometimes you can get the documentation.

01:04 It can be kind of a little mucked up, but it might look fine on your computer, but you, you push everything up all the way up to PyPI and it doesn't look good.

01:14 Something's messed up.

01:15 And so somebody wrote a document called correct or a article called correcting documentation for a deployed Python package.

01:22 And, the answer there's a couple answers.

01:25 one of them is to try to prevent it first by checking your documentation first.

01:29 And there was a recommendation of a tool called RestView, which is a way to view your long description of your package before you push it up.

01:40 But even after then, if you don't do that or if it's still messed up, to use post version numbers, which I knew about these things, but I didn't know what they were for.

01:50 So let's say your package is on version 0.3.2.

01:54 And it's messed up.

01:56 Well, you can't just fix the documentation, push it back up again.

02:00 PyPI doesn't let you push up the same version again.

02:03 - Yeah, they're basically immutable once they're published, right?

02:06 - Yeah, so if you push up 0.3.3 with the fixed documentation, there's like nothing changed.

02:13 Nobody really has to download the new one.

02:16 But that's, I guess, what the post version numbers are.

02:19 So you can say 0.3.2.post1 and post2 and post3.

02:24 And these don't cause people to have to re-download if pip is, if it's a pip dependency or something like that.

02:31 But it allows you to push up new documentation.

02:34 And I thought that was cool.

02:35 That's interesting.

02:36 So the posts on the end means like if I do a dash U or dash dash upgrade in PIP, it's not going to do anything, but it'll still let you update it?

02:43 Yeah, it still pushes up a new version.

02:45 And I don't actually know if it prevents the pip install stuff, but at least in your version, your change log and stuff.

02:53 You can actually, I don't know all the details, but it's a cool trick.

02:57 Yeah, it's definitely a cool trick.

02:59 The other thing I wanted to bring up since we're talking about packaging is I was pushing up a different, going through the release process of pushing up a new package just the other day, and I was trying out the test.

03:10 For some reason, I was having trouble with the test PyPI.

03:13 So before you push it to the real one, you can test things out on the test server.

03:18 But for some reason, even though the packaging instructions are really pretty clear, I couldn't get it right.

03:26 So the Python Package Authority has a document called "Using Test API" that is a little more detailed and it helped me and it was nice.

03:34 So check that out also.

03:36 Yeah, that'll help all the package maintainers out there.

03:38 Nina, do you have any packages you have to maintain or take care of?

03:42 I'm very lucky I don't.

03:43 (laughing)

03:45 - I think it's probably a blessing and a curse to have a really popular project.

03:49 You just think of the people who create a Django or requests or something like that.

03:55 And on one hand, it's like sort of geek stardom in a sense, but on the other, all these people are asking you for changes and maintenance and all kinds of stuff that you're like, I've got another life to live.

04:07 This is the only thing I do, right?

04:09 So yeah, maybe it goes both ways.

04:11 - It's definitely a blessing and a curse.

04:12 - Yeah, for sure.

04:14 So, Nina, what's the item that you wanna talk about first?

04:17 - I wanna chat about something that's not particularly new.

04:20 It's been around for a long time, but it's gotten an update in the past year, and that's the Flask Mega Tutorial by Miguel Grinberg.

04:30 Have you guys heard of that?

04:30 - Yeah, that's a great one.

04:32 You're right, he had that around for a while, and he actually did a Kickstarter to revitalize it, which I thought was awesome.

04:38 - He used that Kickstarter money put out a great ebook format of the tutorial as well.

04:44 And for those of you who are listening and don't know about the Flask Mega tutorial, it's a, I have the page open right now, a 23 chapter Flask tutorial.

04:54 And it's come up for me several times in the past few weeks because I get a lot of questions with, from beginners about how to learn Python, how to really learn Python.

05:04 They maybe have a good grasp on the language, but they're stuck on what to do next or they want to learn about web apps and they kind of don't really know where to go.

05:14 And I always point them at the Flask Megatutorial.

05:17 - Oh yeah, that's really great.

05:18 It's so comprehensive.

05:20 I mean, you're right.

05:21 It has three chapters on deployment.

05:23 One for straight virtual machines, one for Heroku, and one for Docker.

05:27 Yeah, Miguel did a great job on this.

05:29 And I feel like, you know, you talked about new users or developers coming in and learning Python.

05:36 There's just so many layers to what you have to do as a developer, right?

05:39 Like, well, I learned Python really well.

05:41 Well, now you have to learn about databases.

05:42 Oh, okay, great, I'll go learn about that.

05:44 All right, now I know about databases.

05:45 All right, I want to put it on the web.

05:46 How do I do that?

05:47 Well, you got to go learn about Flask and HTML.

05:49 And okay, great, I did all that.

05:50 Like, now how do I get it on the web?

05:52 Like, well, now you got to learn about Linux or whatever, right?

05:55 Just like so many layers and having this is definitely helpful.

05:57 - Now you have to figure out how to maintain and deploy the thing.

06:01 Yeah, there's a chapter in this tutorial about databases, but there's also one about dates and times, which is super important and internationalization.

06:10 And then--

06:11 - So, I had one of the questions I had for you about this was I'm looking at a couple of different ones and Miguel does recommend some, as he's going through the different topics, some different extant flask extensions.

06:25 And have you found that his recommendations are fairly spot on for what you should be using?

06:31 - So, I actually did go through this tutorial back in the day when I was learning Flask, but it was the version that was four or five years old.

06:42 - Oh, okay.

06:43 - So I'm not fully up to date with what he recommends now.

06:47 What extensions does he mention?

06:48 - Oh, like for instance, Flask login for dealing with the user data or user login stuff, and Flask migrate for migrating databases, things like that.

07:01 - I haven't used either of those.

07:03 - Okay, Michael?

07:05 I haven't used a ton of them.

07:06 I know he's doing some interesting stuff with like some forms, extensions, and I've gone through his tutorial somewhat.

07:12 It's really nice.

07:13 But I mostly write in Pyramid, so I haven't been looking too closely, but I definitely do a little flask, and it's good to definitely experience all the frameworks.

07:22 And I have another one for you guys later, a pretty awesome one.

07:25 So there'll be more to learn.

07:26 There's always more to learn.

07:27 - Yeah. - Exciting.

07:29 - Yeah.

07:30 So one of the things I think is cool about Python is it's not like a compile, full on compiled language that lets you sort of work directly with memory.

07:39 And that means that there's no security vulnerabilities in Python, right?

07:42 - There's some, there's a few, they come up.

07:45 (laughing)

07:46 - So actually, so the thing that I wanna talk about is a show by, an article by Anthony Shaw.

07:52 Of course, it wouldn't be a show without mentioning Anthony Shaw doing something or other.

07:56 It called 10 Common Security Gotchas in Python and how to avoid them.

08:00 So he's done some really cool research here and talked about 10 things, maybe more than 10 things, 10 categories, let's say, of errors you can run into in Python that are super bad, can get your company in the headlines in the way you don't want it in the headlines.

08:16 So I'll run through these and you guys let me know if they're familiar or if you've seen examples or anything like that.

08:23 So the first one, probably the most common one, is some form of injection attack.

08:27 And when I think about injection attack, I think about Little Bobby Tables.

08:32 Have you seen Little Bobby Tables?

08:33 - Absolutely, it's a classic.

08:35 - Oh, he's a classic.

08:36 He's a trouble student.

08:38 So Little Bobby Tables is like a cartoon, XKCD about SQL injection attacks.

08:42 But there's also process injection attacks in Python that if you use process, P open and things like that, that you can actually do all sorts of badness by escaping or getting out of the various commands and sending multiple commands to the shell, which might also be super bad.

08:59 So there's that parsing XML, there's basically denial of surface attacks you can do by having a self referential XML entity that refers back to itself that refers to itself that'll just destroy your memory and a couple of things like that. But there's also ways to get around firewalls with linking in XML documents. So there's some interesting fixes, different libraries, you can drop in as replacements that get around those attacks, assert. So sometimes people might think assert that you are an admin before I let me, before I run the admin command, things like that.

09:34 But in production, you can turn off the assert statements in Python.

09:38 So that could be, well, you're error checking just left.

09:41 Right, that'd be bad.

09:42 Timing attack, some really interesting ones that we've sort of touched on a little bit, Brian, previously is with polluted site packages.

09:50 - Yeah. - Or things like that, right?

09:52 Like if I pip install requests and I like switch, I don't know, just misspell it somehow.

09:59 Somebody could publish an evil request, right?

10:02 We've covered a few examples of that actually happening on PyPI.

10:05 Let's see, temporary files, yaml.load, pickling, pickling is evil.

10:11 So I don't know, do you guys use pickle for anything?

10:13 - No, but it's still surprising to me that it shows up in a lot of tutorials on how to learn Python.

10:20 - I know, every time I see it, I'm just like, oh boy.

10:23 There's gotta be, couldn't we just do JSON?

10:25 - The short version of the pickle, go ahead Nina.

10:27 - I was gonna say, I have not come across any tutorial with pickle in it, so.

10:31 - That's good.

10:32 - I don't know where you get your material, Brian.

10:34 - Really old books.

10:37 - Yeah, it's like, oh, we can just save that.

10:38 We'll just pickle that.

10:39 There's so many things wrong with it, but security is one, because there's basically a step where arbitrary code is run on deserialization, and that's not amazing.

10:47 And then of course, patching your runtime and patching your dependencies.

10:50 So these are all just a handful of things to check your code for, to make sure you don't do to check your infrastructure for and so on.

10:57 Yeah, none of these were obvious to me.

10:58 I was expecting like the obvious one of don't use the eval statement on user data.

11:04 But maybe that's just too obvious.

11:06 Yeah, maybe.

11:07 I mean, that one definitely should be thrown in there, right?

11:09 That's definitely one that's sort of along the same thing as pickles, maybe even worse than pickles, to be honest.

11:16 But yeah, I think there's a lot of non obvious things here that people who have been doing Python for a long time, like I had no idea that yaml files could be evil, but they can be really evil.

11:25 And one of the things that I really liked was his fixes are pretty easy.

11:29 Just learn about these, use these fixes, and it's good.

11:31 I didn't know about the, that you can turn off assert statements in production.

11:36 I tend not to use them in code outside of testing, but that was a surprise to me and I've been doing Python for quite a long time.

11:44 It would be bad to, why is it not checking?

11:46 I know the check is here.

11:47 I could see it in the code.

11:48 Yeah, no, it just doesn't do anything.

11:50 Yeah, so if you're running any Python that is basically exposed to the world in any way, you probably wanna skim through Anthony's article.

11:58 It's a good one.

11:59 All right, before we move on, let me tell you all about DigitalOcean.

12:01 So DigitalOcean is a big supporter of the show.

12:04 Our infrastructure runs on DigitalOcean as well.

12:06 So we're both, they're sponsors, and we're both happy customers at the same time.

12:10 So you can go from zero to a server up and running in 60 seconds, probably more like 30, 35 seconds.

12:16 It's super easy.

12:17 You just go pick your Linux distribution.

12:20 If you want it pre-installed with something like Mongo or Ghost, you can check a box and it'll just do that.

12:26 Up and running, SSH in and you're off to the races.

12:29 Really super reliable, super bulletproof, lots of data centers, big fan.

12:35 If you go to pythonbytes.fm/digitalocean, you can get $100 to get started if you're a new user.

12:41 So check them out and tell them thanks for supporting the show.

12:44 - Once your server's up and running, go back and read Anthony's article to make sure that it's secure.

12:49 First thing you do is you patch your Python.

12:51 That's right.

12:51 So one thing that I don't use at all that I feel like I probably should learn more about are pre-commit hooks and get--

12:57 - I'm on the same boat.

12:58 I wanna try to, we're using some things like linters and other tools like PyLint and Flake 8, things like that at work now, but I wanna make sure that they're, wanna get into a use model where they're just used all the time before it gets committed.

13:16 And so I came across this, I'm not sure who referenced it, but a project called pre-commit, which is built in Python, but it's not Python only.

13:25 It's a tool that can start easily hook up a lot of these Git pre-commit hooks for you so you can run things like Lint or Black or other things before you check in.

13:38 And it's got some nice features for it.

13:41 It's a YAML based, so it's really easy to read the setup.

13:45 does all the hooking up into Git for you. And I'm not sure, I'm guessing everybody individually has to do it once they check out a repo, but I'm not sure about that. I'm just getting into this.

13:55 But also one of the things I wanted to make sure I could do was to every step of my pre-commit, like if I wanted to run Black or Pylint or something, I could test that out. And it does, it has the ability to just run each individual hook by itself. So this is something fun that that I'm looking into.

14:12 - Oh yeah, that looks really fun.

14:14 - Pre-commit hooks are awesome.

14:15 - Oh yeah, are you using them?

14:16 - Yeah, I actually use them pretty heavily in my last project and they've saved my butt multiple times.

14:24 One of my favorite pre-commit hooks looks for debugger statements.

14:27 - Okay.

14:28 - Yeah, so if you have a PDB.

14:29 - Yeah, like triggering a breakpoint or something like that?

14:32 - Yeah, exactly.

14:33 - Oh, that's a really smart one, yeah.

14:35 I guess you could do all sorts of checks, right?

14:38 like check for to do or, you know, not implemented, all kinds of stuff that the people might put there, like actually, you probably shouldn't check that in.

14:46 - Yeah, and it's nice having kind of global, team-wide pre-commit hooks where everyone's on the same page with things like checking for debugger statements, linting, any other sort of, maybe you have a line length rule that you wanna follow, and then breaking that down and having individual pre-commit hooks.

15:04 So maybe checking for to do and your initials or whatever scratch code that you tend to put in and don't want to check into the greater project.

15:12 - Yeah, I see the real value of the pre-commit hooks being for team work.

15:17 Obviously, it's valuable for individuals as well, right?

15:20 Even individuals don't want to ship a web app that has a breakpoint in it.

15:24 But, you know, it seems like the value's amplified when you have a team and you can all agree upon the way it works and that just gets automated.

15:30 - Absolutely.

15:31 Yeah, I'm a big proponent of having a code style document where everyone's on the same page and where if a team is working on a code base as they commit code, it looks like one person is doing it and you can't just point in a chunk and say, oh, Michael wrote that, it's got his star on it.

15:50 - It's got that weird triple-list comprehension with an internal dictionary comprehension.

15:54 We don't do that.

15:55 - Right. - Yeah, yeah, no, that's awesome.

15:57 So we have kind of a big piece of news theoretically coming today, right?

16:02 - That's right.

16:03 Python 3.7 should be released today.

16:06 So by the time you're listening to this podcast, you'll have it.

16:11 - Fingers crossed.

16:12 So if you go check out PEP 5.3.7, this is the release schedule for Python 3.7.

16:17 It says expected on the schedule is 3.7.0 finals June 27th, 2018.

16:24 That's today.

16:25 So assuming everything lines up right, you should be able to go and download Python 3.7.

16:30 If not, just pause the show for a day or two and come check again.

16:35 Yeah, what are some of the features that you're finding really awesome there?

16:38 - So now there's a breakpoint function.

16:40 No more import PDB colon set trace.

16:45 There's just a breakpoint function that you can drop in.

16:48 - Yeah, that's cool.

16:48 When I first heard about that, I was like, well, okay, that's nice-er, right?

16:53 But how much does it really help?

16:55 And then the more I looked into it, I realized actually the PDB trick is tied to the PDB debugger.

17:03 But there are many other types of debuggers you may want to use in Python.

17:07 And this breakpoint thing lets you configure your environment to, when you say breakpoint, trigger a breakpoint in that debugger, which is kind of cool.

17:14 I personally use and love IPDB.

17:17 It's kind of more interactive version of PDB.

17:20 But the limitation in both that I maybe maybe there's a way but I never quite figured it out was you could only type in one line statements, you could put in semicolons and a few other things, but you were really kind of limited, you couldn't paste in functions or anything too complex.

17:38 Now with the new breakpoint function in Python 3.7, you can just open up an IPDB shell and do whatever you want.

17:45 That's so exciting.

17:46 Yeah, that's, yeah, that's really awesome.

17:48 I think that's great.

17:49 Certainly makes building better tools that plug in for that in place of PDB.

17:54 It's good.

17:55 Nice.

17:56 We also have some new board members, right?

17:58 That's right.

17:59 The PSF board member elections just finished two days ago and there are now four new board members.

18:06 I have not practiced saying their last names out loud, so if I butcher them, I fully apologize.

18:12 But we have four new members there, Anna Ossowiski, Christopher Nugabower, that's gonna be my final guess, Jeff Triplett, and then Katie McLoughlin.

18:27 - Oh, awesome, yeah, it's great to hear some of those folks in there.

18:30 Congratulations everybody on that.

18:31 And I know a number of us have voted and it's great to see the community sort of putting in place these structures to keep it vibrant.

18:40 - Yeah, I voted.

18:41 There was a 47% voter turnout for this election.

18:45 - That's pretty good, really.

18:46 - Yeah.

18:47 - I guess we could go for 100%, but 47, it seems like probably a lot of people don't check their mail and the announcements just go right by, right?

18:53 - Yeah, I'm super excited for them.

18:56 - Yeah, that's cool, awesome.

18:57 Congratulations and I'm really looking forward to installing Python 3.7.

19:00 That'll be fun.

19:01 So we talked about Flask and one of the big, I feel like one of the big blockades that's going to crack loose and really sort of change things in the Python web space is this async stuff.

19:14 And there've been a couple of attempts at it.

19:17 We've had Sanic, we've had Gepronto, we've got Quart, which is basically Flask directly converted to be a sync awaitable, which can give it really good performance benefits.

19:29 But there's a new framework that is just going like gangbusters called fibora fibora web framework.

19:36 Have either you heard of this?

19:37 I have not.

19:38 New.

19:39 It's shiny new.

19:40 So I went to the GitHub repository, and it's only 14 days old.

19:43 But it already has 21 contributors and over 2000 GitHub stars.

19:47 Whoa, that's pretty intense, right?

19:49 So it's basically flask like, right?

19:52 super inspired by flask but it's from scratch re-implementation or implementation of something like a asynchronous version of flask.

20:01 Alright, so if you want to create like a function that is asynchronous, you just say app.route, you know, decorate app.route, give it the URL, async def index and then return some kind of response.

20:12 So really, really nice to create these, you know, async await enabled functions and that has some interesting performance benefits.

20:21 So if you go look at vibora.io, they have some nice graphs.

20:27 So they've got like flask running around 30,000 requests per second pyramid running 35, Sanic 60, vibora 150,000 requests per second on the same, doing the same processing on the same infrastructure.

20:43 And I suspect the scalability is even better in terms of like, heavily IO bound things like I talked to a database, I talked to a web service, things like that.

20:51 - This is really impressive.

20:53 - Yeah.

20:53 - It looks like it's got WebSec that's built into it also.

20:56 - Yeah, and because of the async stuff, it's super easy for it to do without, you know, blocking and consuming threads and things like that.

21:03 I think this is great.

21:03 It's got a bunch of things that were written from scratch for performance considerations and to make sure that async is first class, like schema validation, the template engine, sessions, all sorts of cool stuff.

21:17 It takes advantage of multiple CPU cores.

21:20 It uses UV loop.

21:21 That's the same thing Sanic is based on and other C speed ups.

21:24 It also has a really interesting thing that I haven't seen in a lot of frameworks called virtual hosts.

21:29 So in like flask or pyramid, I can say the URL is forward slash, episode slash seven to get the episode seven or whatever.

21:37 But in here, you can actually have different domains.

21:39 So you can have like docs.pythonbytes.fm and episodes.pythonbytes.fm within the same web app.

21:47 Interesting.

21:48 Yeah, it's interesting, right?

21:49 And deployment is pretty easy.

21:50 It actually comes with its own server because WSGI is part of the problem.

21:54 WSGI, like the foundational server bits and most of these things are, is a synchronous interface.

22:00 And so there's no way to squeeze async in between it.

22:02 So it's pretty cool.

22:03 Anyway, the docs need a little help, but it's only 14 days old.

22:06 So I guess we should give them a little slack.

22:08 - Yeah, I just added a new start to their tally.

22:11 - Oh, awesome.

22:12 Yeah, they've just got a few more.

22:14 It's cool though, right?

22:15 I mean, it's very much like Flask, but it's kind of a modernized version.

22:18 I was gonna say, I was wondering about the name, Vybora, but they explain that on their GitHub page.

22:24 It means viper in Portuguese.

22:26 - Ah, viper, okay.

22:27 I guess vipers are fast, I don't know.

22:29 I mean, but they can strike fast.

22:31 I don't know about their actual motion.

22:33 Vybora, okay, cool.

22:34 - And you forgot to mention the best part.

22:36 On their page, the benchmark title has a rocket next to it.

22:40 I'm a fan of anything with rockets.

22:43 - I know, a testing rocket for sure.

22:48 - Nice, so people who are doing web stuff, this is a new one to keep your eye on in terms of the shiny new frameworks for Python.

22:55 Oh, another interesting thing is this is a Python, not just a Python 3 only framework, it's Python 3.6 or above.

23:02 None of that legacy stuff.

23:04 - I'm on board with that.

23:06 - Whoa. - That's crazy.

23:07 Yeah, that's bold, that's awesome.

23:08 All right, well, that's it for our items this week.

23:11 I did wanna give a quick shout out to one other thing because Brian, we kind of, have we talked about GUIs on this show yet?

23:17 - I think so.

23:17 I think we did maybe it was a while, a couple, a couple times.

23:21 So we've gone around and around.

23:22 So one of the major things coming for Python GUI space is Qt, the new version, the Qt for Python that's like PySide 2 reborn.

23:31 So they have a webinar coming up where they're introducing all the features and stuff as it launches.

23:36 I think that's in August.

23:38 And so I put the link to sign up for the webinar if you want.

23:41 Yeah, I'm already signed up.

23:42 Yeah, me too.

23:43 I'll see you there.

23:44 Nina.

23:45 Yeah, Nina, you got anything else going on you want to tell people about?

23:47 - Yeah, if you are gonna be doing the Flask mega tutorial and you're not super happy with your IDE and you haven't checked out VS Code yet, there's a Python extension for VS Code that makes working in Flask really easy.

24:03 And full disclosure, I work for Microsoft, but I also use it and enjoy it.

24:10 So if you wanna check it out, I can include a link in the show notes.

24:13 - Yeah, sure, drop it in there.

24:14 I use VS Code periodically when I'm working on like individual files.

24:18 And I know it does more than that, but I use PyCharm for some stuff, and then definitely VS Code, and it is getting much better.

24:24 It's getting like the auto-completion and all sorts of the linting.

24:28 It's getting quite nice.

24:29 - If you think that stuff is nice, we have some really exciting announcements coming up just before EuroPython.

24:36 - Okay, awesome.

24:37 You'll have to shoot us a note and we'll talk about 'em.

24:38 - It's something that no one else has, and that's about as much as I can say right now.

24:43 - Oh, that sounds exciting.

24:45 I think I can guess what it's going to be, but I won't speculate.

24:49 I'll let you do the announcement.

24:50 Awesome.

24:51 And then anything else?

24:52 That's it for me.

24:53 All right.

24:54 Well, that's good.

24:55 And Brian, you?

24:56 No.

24:57 It's good.

24:58 Although I do have a, it's a lot out.

24:59 I've got a whole bunch of interviews stacked up.

25:03 I'm finally getting some time to do some editing and pushing out for testing code.

25:08 And Nina's one of the people.

25:09 So I've got an interview with Nina that, who knows when it'll come out and maybe in a few Awesome.

25:16 Yeah.

25:17 Maybe if you all email and tweet it at Brian, he can be hired to chop the audio up a little sooner.

25:25 There you go.

25:27 Or better yet, write a bot that every 30 minutes just tweets at Brian.

25:31 Yeah.

25:32 Sorry, did I say that out loud?

25:39 It just tweets the number of days.

25:40 No, just kidding.

25:41 I'm going to stop right now.

25:42 - Days since last episode.

25:45 - That was what I was thinking, that's right.

25:47 I myself, I'm a little bit slow on this week, on mine as well, so I'm not gonna throw stones.

25:53 - Okay.

25:54 - All right, well, Nina, thank you so much for being on the show.

25:56 It's been a pleasure to talk with you, and Brian, thanks as always.

25:59 - Thank you.

26:00 - Thank you both so much.

26:01 - Yep, bye.

26:02 - Bye.

26:03 - Thank you for listening to Python Bytes.

26:05 Follow the show on Twitter via @PythonBytes.

26:08 That's Python Bytes as in B-Y-T-E-S.

26:11 and get the full show notes at pythonbytes.fm.

26:15 If you have a news item you want featured, just visit pythonbytes.fm and send it our way.

26:19 We're always on the lookout for sharing something cool.

26:22 On behalf of myself and Brian Aukin, this is Michael Kennedy.

26:25 Thank you for listening and sharing this podcast with your friends and colleagues.

Back to show page