Transcript #165: Ranges as dictionary keys - oh my!
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 165 recorded January 16th, 2020. I'm Michael Kennedy.
00:12 And I'm Brian Okken.
00:13 And this episode is brought to you by DigitalOcean. They're a great supporter of the show.
00:17 Check them out at pythonbytes.fm/digitalocean. Get $100 credit for new users. More on that later.
00:23 Brian, we've got a lot of stuff to get through and I want to just let's start iterating through it, man.
00:27 Okay, let's iterate through it. Also, I can't believe that it's halfway through January, whatever.
00:32 Okay, so first off, let's talk here about iterators, iterators, generators, and coroutines.
00:38 So I'm linking to an article that's pretty much what it's called by Mark McDonald. And when I googled this relationship between coroutines and generators, apparently everybody else knows this is a thing, but I missed out somehow. But this article is a really good introduction to all of of this concept and how they all work together.
00:59 So it start, well, okay, I've got to start out with a beef.
01:03 It starts out with like talking, trying to do a gentle introduction to the iterator protocol with like the dunder iter and dunder next.
01:12 I just want people to stop doing that.
01:14 Okay, muscle through it, but skip that part.
01:16 It should be an appendix, I think, because people don't do that anymore.
01:20 Okay, next, it goes, talks about generators, which are the same thing as this iterator protocol sort of, but using the yield function.
01:28 I know there's differences, but this is how I do it.
01:31 I use yield for generators.
01:33 - It's so beautiful because you take the code that's not generator style, and then you just throw in yield instead of like list append or set.add or whatever you're gonna do to gather up the results.
01:44 Just replace that with yield, boom, you're done.
01:46 It's usually less code.
01:48 I love it, it's great.
01:49 I'm a big fan.
01:50 - Like for instance, you just do throw things into a loop and put yield in there or yield the things you have, whatever it works.
01:56 Unbound generators, it talks about, which means don't convert these to lists because they don't stop.
02:02 So there are, it is possible to write a for loop that doesn't stop and therefore there's a way to do a generator that doesn't stop.
02:09 So.
02:10 - Right, if you're working on an infinite series, some kind of series that you use a generator for it, it might not stop.
02:15 - Yeah, I mean, there's legitimate reasons to do this or maybe it does have an end, but it doesn't fit in memory and stuff like that.
02:21 So beware.
02:22 Generator expressions, you know, for some reason I just forget about.
02:26 They're like list comprehensions, but you put parentheses instead of brackets and then it's a generator expression.
02:33 - They're smooth, right?
02:34 I mean, they don't have those sharp edges of those square braces.
02:37 - Smooth, oh wow, that was bad.
02:40 Okay, the reason why I highlighted this article really isn't for this stuff so far.
02:45 It's a couple things.
02:47 It talks about that generators can use other generators or nesting generators with a yield from, And this is cool, I didn't know this was a thing.
02:56 So that you can have, so let's say bar and baz are generators, you can define a new function foo that yields from each of these, and it just goes through one and then when it's exhausted, it goes through the other.
03:10 Really slick, did you know this was a thing?
03:12 - Yeah, this was added after the yield keyboard was added.
03:15 So yield was there for a while, and then what you would have to do before if you wanted one of these, you'd have to write a for loop that goes through every item in the sub generator and then just yield that out.
03:26 But now you can just say yield from that thing.
03:28 It's been a few versions that it came in.
03:30 I can't remember exactly when, but yeah, it's a bit of a new feature.
03:33 Maybe three, five, maybe three, four, I can't remember.
03:36 But yeah, this is great.
03:37 The place that I've used this most is recursive generators, right?
03:42 You're writing a generator and it's going through some data structure, but then you get to the point where you're like, well, I need to call it again, but with a different node in a tree or something like that.
03:51 Instead of having to loop over that to yield, you just say yield from, basically, the recursive call.
03:55 It's beautiful.
03:56 - Oh, yield from with a recursive call, nice.
03:59 That hurts my head thinking about it.
04:00 - Yeah, man, think about, you know how painful it was to learn recursion and how funky it is to learn about generators?
04:07 You like mash them together and then the brain explodes.
04:10 Yeah, it's great.
04:11 - Okay, the article goes on and talks about the relationship between coroutines and generators because yield, you usually just has, it's just a thing that it ends up returning a value out of your function.
04:23 But you can equal or do an assignment, a variable assignment from a yield, and that's one of the syntax things that works with coroutines.
04:34 And I got to admit, I got lost at this point.
04:36 So this is kind of a call to action to everybody.
04:39 I'd really like to have a coroutine tutorial that could show me how to use coroutines for stuff that I really actually might use that isn't async related and can we skip the iterator protocol?
04:52 - Or make it an appendix, like you said.
04:54 - Yeah, do you use coroutines?
04:55 I mean, they look neat, I just don't know how to use them.
04:57 - I use generators all the time, and I use async methods which ultimately are fancy wrappers around coroutines, but I don't use coroutines directly, not knowingly anyway.
05:10 - Okay, cool, I'll have to play with it a little bit.
05:12 - Yeah, nice, something that I use a lot is requests.
05:15 You probably use requests a lot as well.
05:17 - Yeah, lots of people do.
05:19 - Yeah, and requests is one of these things, you know, last time you spoke about PyPI stats, was it pypistats.org or something like that?
05:27 And requests was certainly right near the top.
05:29 It was not number one on the list of things being used, but it was near the top, and which that means it can't take too much change, right?
05:37 There can't be too many features or changes made to it.
05:40 So it would be nice to have something that makes working with requests nicer, that can change more quickly.
05:45 So there's this thing that I came across called Request Toolbelt.
05:49 Yeah, so Request Toolbelt is a, well, toolbelt of useful classes and functions to make working with requests easier.
05:57 And it really does, at the moment, four things.
06:00 But I think if people are out there and they're like, I always have to do this with requests, it's like these five lines, I gotta make sure I remember to do this right, it would be awesome to just extend this.
06:09 So this is a small project by someone I can't remember.
06:13 I don't think it says like really a meaningful name on it.
06:16 Yeah, now it's just under requests actually.
06:17 This is not the small project I think, you know, but I think it would be cool to like take those ideas if you see patterns that you're doing with the request library and fold them in here.
06:25 So let me give you the rundown on the four things it does.
06:28 First of all, if you're going to do multi-port form data encoding, like I have an image file and I want to upload it to the server, to the API.
06:38 That's annoying, right?
06:40 It's not super easy.
06:42 But with this thing, it's really easy to go and just basically say, "Here's a file stream. That is field two." It's, you know, whatever it is, right?
06:50 It's binary image data or it's text.
06:53 And then you just say, "Here's my data, this multi-part form and encoder." And boom, it's just uploading files and doing all the stuff it has to do.
07:01 That's incredible. Just a few lines of code.
07:03 Yeah, it's really, really nice.
07:04 And you don't have to think about like, "How do I do multi-part encoding again?" Just give it a file stream. You're good.
07:09 The next one is the user agent constructor.
07:11 So you have to set a header user dash agent, but then like, how do you construct that in a meaningful way?
07:16 There's a class that takes or a method.
07:18 It's just a method, take some arguments and it will generate the string that is a, I guess, compliance user agent for like your API app or whatever.
07:28 So that's cool.
07:29 User agent constructor.
07:30 Sometimes you have to, when you're working with other systems, conform to certain SSL protocols, right?
07:38 We have TLS version 1, 1.2, we have 2, I think, coming along.
07:43 But there's different versions of TLS, which is the foundation of SSL, right?
07:47 So they have an SSL adapter that lets you explicitly set, I want to use TLS 1.2 or 1.0 or something like that if you need to.
07:55 Oh, wow. Okay.
07:57 That's cool.
07:57 And then one thing that you can do with requests is you can create a session and then it'll start talking over it.
08:03 It probably reuses the connection.
08:05 I'm not entirely sure of all the things it does.
08:07 But one of the things the session does is it'll remember cookies and things like that.
08:11 Well, maybe you want to make a series of requests using a request session that doesn't actually carry the cookies from time from request 1 to 2 to 3 and so on.
08:21 So one of the classes in here is a forgetful cookie jar.
08:26 So if you set the request session cookies container to the forgetful cookie jar, it will, well, it implements the protocol, but it always forgets its cookies, obviously.
08:37 So it's a cool way to like clear out, still use sessions, but clear out cookie persistence across calls.
08:42 - Is there a reason to use sessions without cookies?
08:45 - Well, some websites behave differently if they think they've already seen you, or things like that, right? - Yeah, right.
08:51 - Right, like maybe I want to test the login function, both working and not working, and then I want to try it of, I forgot my password, but I don't want it to know that I've already actually logged in in that sequence.
09:03 Or something like-- it could be some series that you're testing for or playing with.
09:08 OK.
09:08 So if you've got to log in, your session login is still valid.
09:12 But you have to go--
09:13 Yeah, or maybe you're going to a place like some sort of paywalled ad place.
09:17 And it's like, well, you can come here three times.
09:19 But if you come here more than three times this month, we're going to show you the paywall.
09:23 You know what I mean?
09:24 You're like, well, you're using cookies for that.
09:26 And my cookie jar is forgetful.
09:28 I don't know.
09:28 I don't personally have a reason for it.
09:30 - I can imagine reasons that people might use that for automation and whatnot.
09:35 - I predict that we will hear other people telling us the reasons now.
09:39 - Yeah, absolutely.
09:40 They definitely might.
09:41 So people can visit pythonbyte.fm/165 and down at the bottom, they can tell us why why they're doing it.
09:47 It's a cool comment section.
09:48 All right, speaking of cool, let me tell you about DigitalOcean.
09:50 They're doing all sorts of good stuff.
09:52 They're offering $100 credit for new users.
09:55 So it was 50, it's back to 100, yay.
09:57 That's great.
09:58 And we, all of our infrastructure and stuff runs on DigitalOcean and it's been just perfect for years.
10:04 So that's great.
10:05 One of the things they recently released is memory heavy workload droplets.
10:10 So memory focused droplets.
10:12 So you can get up to eight gigs of RAM for each dedicated CPU.
10:17 And it goes from two CPUs all the way up to, is that 32, 256 gigs of RAM available on your VM, which is kind of ridiculous if you really need that.
10:27 but maybe you've got a workload that does.
10:29 So it's really good for high memory apps like high performance SQL or NoSQL databases and memory caches like Redis, maybe some data analysis of lots of data, stuff like that.
10:39 So check them out at pythonbytes.fm/digitalocean, get $100 credit from the users and support the show.
10:45 Speaking of data science, what do you got, Brian? What's next?
10:47 Yeah, speaking of data science, Pandas is used by lots of folks.
10:50 Not just data science, but I know the data analysis people use Pandas quite a bit.
10:55 And in episode 162, you weren't with us for that, but we covered a project called Bullwork.
11:02 Yeah, I listened into that episode as well, and you and Ollie did a great job, that was fun.
11:06 And we had a listener's suggestion about another package called Pandas Validation, and then I was just looking around to see if there's other projects.
11:16 One of the others I found was Pandera.
11:18 So I'll try to briefly talk about these, but Pandas Validation, Lance tells us that it lets you create a template for your data frame, how it should look, and then it validates your entire data frame against the template.
11:33 So if you have a data frame with the first column being string and second column being dates and then an address, and you can use a mixture of built-in validate types to ensure that your data conforms to that.
11:45 So that looks pretty cool.
11:46 - Yeah, this is really nice.
11:47 It's a little bit like, tiny bit like JSON schema or something.
11:51 So you've got these pandas data frames or time series that it's just full of whatever, and then you can throw on top of it, cool validation and just it's all at once against the whole collection, right?
12:00 - Yeah, and then Pandera is I think a similar sort of project that lets you set up types and properties for different columns of a data frame and perform validation to make sure sort of a schema validation sort of thing also.
12:15 So they're all kind of solving a similar problem, but I was looking at it and the API and how you use it between Bulwark, Pandas Validation, and Pandera are all very different.
12:25 - Yeah, they are.
12:25 - I'd really like to hear if there is a common approach or if Pandas Validation, DataFrame Validation is just not something that's catching on yet or what people are using.
12:36 I'd love to hear that.
12:37 - Yeah, and I just noticed at the bottom of Pandera, they have other data validation libraries and others Panda-specific ones like Opulent Pandas and Panda Schema and Pandas Validator and Table Enforcer and so on.
12:48 So apparently this is like a whole hole you can go down into that I was not even aware of.
12:52 But I got to say the Pandera API, where you basically define a column, a data type, and then a lambda function that you give it that does the validation, that's super cool.
13:04 I love that.
13:05 - Yeah, it looks pretty clean.
13:06 - Yeah, it looks incredibly flexible without getting like out of control.
13:10 Speaking of out of control, you know what's a little bit out of control?
13:13 GUIs for Python.
13:14 Yeah, they're a little bit.
13:16 And this way I don't mean, I'm not actually this time complaining about their absence or something like that.
13:21 But one of the best libraries for building GUIs in Python has got to be Qt, right?
13:31 Pranavski? - Yeah.
13:32 - And I was inspired at the Python meetup that you're running out in West Portland when we saw Augie Moore give a presentation on how he used FBS, FMAN build system, plus PyInstaller, plus Qt to build, you know, nice packaged apps that are GUI apps that he could distribute around.
13:52 And that was really cool.
13:53 So one of the things though that drives me crazy is like we've got PyCute 5, we've got PySide 2, PyCute 4, we have PySide, we have Python 4 Qt, we have all these different things, right?
14:05 I think Python 4 Qt might be the next version of PyCute 5 and so on.
14:10 And I just don't know where to start, right?
14:11 I'm looking at this going, oh my goodness, like you see different examples doing different things.
14:15 And so I ran across something called QtPy, Q-T-P-Y, QtPy.
14:20 - Yeah, or QtPy.
14:23 - I wanted to say QtPy, but I don't know, QtPy.
14:27 QtPy, so QtPy, no, QtPy, actually, one of the things about a lot of these libraries is they're like really cool little proof of concepts, but in practice, how real are they, how supported are they, and so on.
14:42 One thing that seems real and supported is Anaconda, the Anaconda distribution, and with that comes the Spyder IDE, like the whole Anaconda continuum data science IDE thing, right?
14:53 And this QtPy is the foundation of what they're doing to write that.
14:59 - Okay. - At least it's in their GitHub repo.
15:01 So it provides a uniform layer to support all those different libraries that I complained about with a single uniform API.
15:09 So it's like an adaptive layer on top of all those things, and it figures out what version you're actually running against.
15:14 and then it just adapts, so you write a code once, and then you can run it in all these different ways, or you can see these different examples.
15:20 - Yeah, it's nice.
15:21 - Yeah, it's cool, right?
15:22 So this is created by the Spyder development team, and there's not a whole lot to it.
15:25 Basically, it's like, well, here's a simpler way to work with these different libraries, because maybe you want a different license, or you want to go from PyQt 4 to PyQt 5, or something like that, 'cause there's all these different examples built with all these different libraries, and they're not exactly compatible.
15:42 So, quite cool, I think.
15:43 - Yeah, and also during the presentation at the meetup, the Ogi mentioned that just he uses that and then if there's a problem with one of these packages, just uninstall it and install one of the other ones and you don't have to change your code at all.
15:59 - Yeah, it's cool.
16:00 - That's how this one works.
16:01 One of the other things I thought was neat is at the bottom of the readme, they've got sponsors, like, you know, different sponsors at the bottom and become a sponsor.
16:10 I have not seen an open source project do that before.
16:12 - That's an interesting idea.
16:13 - Yeah, it is definitely an interesting idea.
16:15 I haven't seen that either.
16:17 - Yeah, so maybe I'll try that on my little open source project.
16:21 - Well, they also have the GitHub sponsor at the top.
16:23 Are you using the GitHub sponsor?
16:25 - No.
16:26 - That's something people can turn on.
16:27 I think that's really cool that GitHub did that, that people can now sponsor projects through GitHub instead of negotiating some deal separately with everyone.
16:35 - Yeah, I wonder if they're tied together.
16:37 I'll have to look into it.
16:38 Anyway.
16:39 - Yeah, yeah, check it out.
16:41 All right, so yeah, what's next?
16:42 - Well, I wanna shed some light on spreadsheets.
16:45 (laughing)
16:47 - They can be a dark place if you get sucked down into VBA or too far down there.
16:52 - Yeah, so actually we got an email from Victor Kiss.
16:55 I think it's Victor Kiss, K-I-S.
16:57 He said he's got his very first open source project, but it looks darn cool.
17:03 It's called PyLite XL, and it's an XLS spreadsheet thing that you can read and write spreadsheets with it.
17:12 So it's a lightweight, zero-dependency, minimal functionality read/writer.
17:17 It has, other than the standard library, there's no outside dependencies, and you can read and write modern XLSX and XLSM files, and with a very simple interface for getting access to the different sheets inside there, and rows and columns and stuff.
17:34 Actually, it looks pretty cool.
17:36 - Yeah, it looks totally useful if all you gotta do is get in there and get the data.
17:40 I don't know if it does things like lets you change, say, conditional formatting or other weirdness, but definitely if you just want to open up an Excel worksheet, not a CSV, but a full-on XLS, and get it the data or the rows or whatever it is you're after, it's quite neat.
17:57 If you go to the link that you're linking to and just scroll down a bit, there's a little animated GIF.
18:01 And I think it tells you pretty much all you need to know.
18:03 You just watch it for a second, and it's like, here's the few steps to go work with this Excel file.
18:08 It's cool.
18:08 He's already got documentation up with the API, but I found the most, on the docs, the best way also to get up to speed really quick is to look at his, he's got a handful of examples for how to do different things, and it's like, oh my gosh, I could just, if I needed to read Excel from Python, I could get started in a few minutes with this.
18:28 - Yeah, that's very cool.
18:32 Yep, and no dependencies, that's kind of nice as well.
18:35 - I never really thought about why that would be important, but he lists one of the reasons is that if you were going to a few things, if you're going to compile it into another installer or something using PyInstaller, not having any DLL or other dependencies makes this easier.
18:52 Then he even says that the library is just like a few source files.
18:56 So if you don't even want to install this as a package, if you just want to copy this stuff into your own source, that that's an option.
19:03 >> Right. Yeah, just vendor it and then you don't have dependencies either.
19:07 Yeah, you know, getting updates, but you know.
19:09 Yeah, wow. It's a trade-off.
19:11 I'm going to tell you about this other thing.
19:15 At first, it might not sound very exciting, but I'm actually pretty excited about it.
19:19 I think this is quite cool. It's a clever little library.
19:21 And this suggestion comes to us from Aiden Price.
19:25 And he told us about some project he's working on using something called Python-Ranges.
19:31 Okay.
19:32 So we have range, like the built-in range.
19:35 You can say start equals whatever, end equals whatever, and it goes from the start, integer-wise, up to, but not including the upper bound.
19:45 But you can't use that range in more meaningful ways.
19:49 So for example, if I had a range of 0 to 100, I can't easily ask, "Is x in there?" If x is a number.
19:57 Or if I have two ranges and I want to intersect them, how do I do that?
20:01 But this library takes that kind of basic idea, sort of like series, but with a lot of set operations.
20:08 You can ask for the intersection of ranges.
20:10 You can ask for whether or not they're mutually exclusive, things like that.
20:14 So all the set operations you can do on it.
20:17 But then it also extends that so you can have a range set, which is a bunch of different ranges, or even a range dictionary.
20:26 So why would you care about that?
20:27 So what you could do with a range dictionary you can use ranges as keys.
20:32 So if the example they give--
20:34 - It's crazy.
20:35 - I know, but here's the example they give.
20:37 It's probably abusing the concept of a dictionary, but it's really useful.
20:41 So if you had an if statement that said, if, they use tax or something like that.
20:46 Let's just say, if your income is zero to 10,000, you're in bracket A.
20:50 If you're in 10,001 to 20,000, you're in bracket B.
20:55 And so on, you had like a huge if, else if, else if, else if to test for that condition.
20:59 you can create a range dictionary where the key is a range, zero to 10,000, 10,001 to 20,000 and so on, and then some information about it is the value.
21:09 And then you could just take a number like 37,215 and get it from the dictionary, say I want to get that from the dictionary and it'll return.
21:18 So it'll basically do the test, like is this item in this range as part of the key match of a dictionary?
21:27 - That's brilliant, that's cool.
21:28 Isn't that cool?
21:29 It's got to be abusing the idea of the dictionary, really.
21:32 But it's pretty cool.
21:33 Yeah, so it's almost like a switch statement in a sense.
21:37 Like you could take those things and those that if else and replace it with this just flat statement of these ranges, and then it'll do the comparison kind of in the data structure.
21:45 Yeah.
21:47 Sweet.
21:48 So there's a bunch of stuff that you can do with these ideas.
21:51 They got some good examples.
21:52 But that little example I gave you, I think, is probably the simplest one to tell you about, Because it gives you a good sense of why you might actually use this.
22:00 A lot of times you look for these blocks or these ranges, and it's really cool to be able to test in here.
22:07 You could even do really interesting stuff.
22:10 I want to know, is this thing in any of these five ranges?
22:14 You could just create one of these range sets or these range dictionaries and just ask, is this number in this set?
22:20 If it is, it's in one of the five ranges that are in there.
22:23 There's really cool ways to layer these together.
22:25 - Yeah, and especially if you've got that all over the place.
22:27 Like for instance, I'm thinking hardware stuff.
22:30 - Yeah, it's gotta be in there, a bunch of numbers and frequencies and whatnot, right?
22:34 - Right, so if I've got different power levels, for instance, they'll have different attenuators that'll kick in at different power levels, but I don't want those power level numbers to be hard-coded all over my code.
22:45 So having some central place where I put those in place so that I can just throw in a number and it gets based on that, I know what the attenuation is or something, that'd be great.
22:55 - That's cool. - Yeah, that's cool.
22:56 It also occurs to me this might be useful for testing, right?
23:00 Because then your assert statement could have a little bit of ambiguity, right?
23:04 If there's like, well, as long as it's in this range, it's okay, but if it's not, then it's not.
23:08 And so maybe that's also an interesting way to simplify testing.
23:11 - Yeah, yeah, okay, cool.
23:13 - Cool, well, anyway, I think that's a much more interesting project than it just sort of sounds like.
23:17 It's like, well, Python has range built in, whatever.
23:19 But no, this is cool, yeah.
23:21 - Yeah, I like it. - Yeah, that's it for our main items.
23:22 What else do you want to tell folks about?
23:24 Well, I spent some time last night, I think I brought this up, I don't know, last time or the time before, that I have a few open source projects, not many, but one of them was lacking some work 'cause it had a bunch of like support requests or whatever you call them, issues.
23:41 So pytest check, I went in last night, I went and cleaned all those up and solved a couple of minor problems.
23:47 But one of the things that I ran into that was interesting and I don't, I mean, I just kind of wanted to highlight it, is plugin for pytest.
23:56 There are other plugins for pytest.
23:58 Some of them don't work together very well because of all the, the way they abuse and use pytest, I'm definitely abusing pytest hook functions with pytest check.
24:08 Intentionally, what it does is it allows you to check certain things within your test, but not fail right away so that you can continue on.
24:17 And then if any of the checks fail, it actually fails the entire test and tells you all of the failures.
24:23 - It fails them at the end, not as it hits the first one, right?
24:26 - Yes, but to get away with that, the only way I could figure out is to hook into the report function, which happens much later after the test completes.
24:36 Well, so there's a whole bunch of other plugins that allow you to rerun tests if they fail.
24:42 There's rerun failures, there's flaky, there's retry, and there's a handful of others.
24:47 Most of them are not compatible with pytest check because of the way, at the time that that they're checking to see if something fails and the time I'm checking.
24:55 So I guess I just want to point out that if you want that to happen, rerun failures works, flaky and retry don't.
25:02 - Nice.
25:03 Oh, that's really cool.
25:04 I wonder if you could like monkey patch flaky or retry to like force it to check later or something like that.
25:10 - Maybe, but also I actually commented in the defect report that it doesn't work with flaky.
25:16 And I said, well, I think it should try.
25:18 And I had a comment from somebody that said, you're just gonna kill yourself off if you think that you're gonna try to make it compatible with all the plugins out there.
25:26 So as long as there is a workaround, it's fine to say, if you need this to work with something like this, use this other plugin and not my problem.
25:35 - Yeah.
25:36 - It seems cold, but open source is a side project.
25:39 - Yeah, absolutely.
25:39 Cool, well, I've got a couple short ones here.
25:42 Jeremy Schendel sent in just a quick message that Pandas is now 1.0.
25:47 It had been living on the zero-ver branch for a long time, but it has migrated over to semantic versioning, and it has a couple of new cool features.
25:56 So we were already speaking about pandas earlier.
25:58 If you're using pandas or whatever, hey, pandas 1.0 is out, that's a big deal.
26:02 Probably also means a lot for the stability of the API.
26:04 - Yeah, it's good.
26:05 - For the PyCharm fans out there, myself included, friend of the show, Anthony Shaw, has created a PyCharm plugin called Python Security, so we'll link to that.
26:15 And basically what it does is it goes through Much like when you're working with PyCharm, it automatically tells you, oh, you're doing a type mismatch, you're passing an int and it expects a string, or you're calling this function and it takes two arguments but you're giving it three.
26:29 It does all that check-in in real time.
26:31 This one is for security, so it checks for unsafe loading the YAML files, remote code execution in Flask, man in the middle with a request for HTTPS, and debug configs in Flask and Django.
26:44 So that's kind of cool.
26:45 You want that?
26:46 Get that and install it.
26:46 - Nice.
26:47 - Yeah, and then finally, I have my Python for Decision Makers course that sort of talks about how to, whether or not you should, and how to position adopting Python at your organization.
26:58 So I did a webcast on that, and that's already passed.
27:00 That went really well, but the recording of it is out.
27:03 So I'll link to the recording if people want to sign up.
27:05 You gotta like register for the thing, but then you just watch the recording.
27:09 - Oh, I'll have to check that out.
27:10 Nice.
27:10 - Yeah, yeah, it was fun, a lot of fun.
27:11 A lot of good conversations there.
27:13 All right, I don't know about this joke, but I'm gonna do it anyway.
27:16 You ready? - Yeah.
27:17 - You've heard about optimists and pessimists and a glass, right?
27:21 A glass is either half full or half empty, depending on which side of that divide you land on, right?
27:27 - Yep.
27:27 - Well, there's a third angle here.
27:30 And for the engineer, you don't see the glass as half full or half empty.
27:35 No, the glass is twice as large as it needs to be.
27:37 - Exactly.
27:38 - It's all about capacity planning, come on.
27:42 - Yeah, okay, so I don't have a joke, but I came up with a little bit of a brain teaser this morning.
27:47 >> Okay, nice.
27:48 >> So, yeah, when is 90 greater than 100?
27:52 >> When is 90 greater than 100?
27:54 >> Yeah. Well, there's a couple of places.
27:57 One, which I was informed on Twitter, is when you're comparing a string literals.
28:01 >> True. Yeah, yeah. You're going to say, quote, 90 less than, quote, 100. It's false. Yeah, okay.
28:07 >> The other one is microwave times.
28:09 So, 100.
28:11 >> Nice.
28:13 Anyway, that's it.
28:14 All right.
28:15 Well, you've left people with something to think about.
28:18 And yeah, thanks for being here.
28:20 Thanks.
28:21 Bye.
28:22 Yeah.
28:23 Bye.
28:24 Thank you for listening to Python Bytes.
28:25 Follow the show on Twitter via @pythonbytes.
28:26 That's Python Bytes as in B-Y-T-E-S.
28:29 And get the full show notes at Python Bytes.FM.
28:32 If you have a news item you want featured, just visit Python Bytes.FM and send it our way.
28:36 We're always on the lookout for sharing something cool.
28:39 On behalf of myself and Brian Okken, this is Michael Kennedy.
28:42 Thank you for listening and sharing this podcast with your friends and colleagues.