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


Transcript #165: Ranges as dictionary keys - oh my!

Return to episode page view on github
Recorded on Thursday, Jan 16, 2020.

00:00 Hello and welcome to Python Bytes, where we deliver Python news and headlines directly to

00:04 your earbuds. This is episode 165, recorded January 16th, 2020. I'm Michael Kennedy.

00:12 And I'm Brian Ockin.

00:13 And this episode is brought to you by DigitalOcean. They're a great support of the show.

00:17 Check them out at pythonbytes.fm/digitalocean. Get $100 credit for new users.

00:21 More on that later. Brian, we've got a lot of stuff to get through and I want to just,

00:26 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,

00:31 whatever. Okay, so first off, let's talk 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

00:44 when I googled this relationship between coroutines and generators, apparently everybody else knows

00:50 this is a thing, but I missed out somehow. But this article is a really good introduction

00:55 to all of this concept and how they all work together.

00:58 So it starts, well, okay, I've got to start out with a beef. It starts out with like talking,

01:04 trying to do a gentle introduction to the iterator protocol with like the dunder iter and dunder next.

01:11 I just want people to stop doing that. Okay, muscle through it, but skip that part. It should be an

01:16 appendix, I think, because people don't do that anymore. Okay, next, it goes talks about generators,

01:22 which are the same thing as this iterator protocol, sort of, but using the yield function. I know there's

01:29 differences, but this is how I do it. I use yields 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

01:39 instead of like list append, or set.add, or whatever you're going to do to gather up the results. Just

01:44 replace that with yield, boom, you're done. It's usually less code. I love it. It's great. I'm a big fan.

01:49 Like, for instance, you just do throw things into a loop and put yield in there, or yield the things

01:55 you have, whatever it works. Unbound generators, it talks about, which means don't convert these to

02:00 lists because they don't stop. So there are, it is possible to write a for loop that doesn't stop,

02:05 and therefore there's a way to do a generator that doesn't stop. So.

02:09 Right, if you're working on infinite series, some kind of series that you use a generator for it,

02:14 it might not stop. Yeah, there's, I mean, there's legitimate reasons to do this, or maybe it does have

02:18 an end, but it doesn't fit in memory and stuff like that. So beware. Generator expressions, you know,

02:24 for some reason I just forget about. They're like list comprehensions, but you put parentheses instead

02:30 of brackets, and then it's a generator expression? They're smooth, right? I mean, they don't have those

02:35 sharp edges of those square braces. Smooth? Oh, wow. That was bad. Okay. The reason why I highlighted

02:42 this article really isn't for this stuff so far. It's a couple things. It talks about the generator

02:48 generators can use other generators or nesting generators with a yield from, and this is cool.

02:55 I didn't know this was a thing so that you can have, so let's say bar and baz are, are generators.

03:00 You can define a new function foo that yields from each of these, and it just goes through one.

03:07 And then when it's exhausted, it goes through the other really slick. Did you know this was a thing?

03:11 Yeah, this was added after the yield keyboard was added. So yield was there for a while.

03:17 And then what you would have to do before if you wanted one of these, you'd have to write a for loop

03:22 that goes through every item in the sub generator and then just yield that out. But now you can just

03:27 say yield from that thing. It's been a few versions that it came in. I can't remember exactly when,

03:31 but yeah, it's a bit of a new feature. Maybe three, five, maybe three, four. I can't remember,

03:36 but yeah, this is great. The place that I've used this most is recursive generators, right? You're

03:43 writing a generator and it's going through some data structure, but then you get to the point where

03:47 you're like, well, I need to call it again, but with a different node in a tree or something like

03:51 that. Instead of having to loop over that deal, you just say yield from basically the recursive call.

03:55 Oh, yield from with a recursive call. Nice. That hurts my head thinking.

04:00 Yeah, man. Think about, you know how painful it was to learn recursion and how funky it is to

04:05 learn about generators. You like mash them together and then the brain explodes. Yeah, it's great.

04:11 Okay. The article goes on and talks about the relationship between coroutines and generators

04:15 because yield usually just has, it's just a thing that it ends up being returning a value out of your

04:21 function, but you can equal your, to an assignment, a variable assignment from a yield. And that's one of

04:30 the syntax things that works with coroutines. And I got to admit, I got lost at this point. So this is

04:37 kind of a call to action to everybody. I'd really like to have a coroutine tutorial that could show

04:42 me how to use coroutines for stuff that I really actually might use that isn't async related. And

04:49 can we skip the iterator protocol or make it an appendix? Like you said. Yeah. Do you use coroutines?

04:55 I mean, they look neat. I just don't know how to use them. I use generators all the time and I use

05:00 async methods, which ultimately are fancy wrappers around coroutines, but I don't use coroutines

05:07 coroutines directly. Not knowingly anyway. Okay. Cool. Yeah. I'll have to play with it a little bit.

05:12 Yeah. Nice. Something that I use a lot is requests. You probably use requests a lot as well.

05:17 Yeah. Lots of people do. Yeah. And requests is one of these things, you know, last time you spoke about

05:23 PyPI stats, was it pypistats.org or something like that. 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's,

05:34 it can't take too much change, right? There can't be too many features or changes made to it. So it would

05:40 be nice to have something that makes working with requests nicer that can change more quickly. So

05:45 there's this thing that I came across called request tool belt. Yeah. So request tool belt is a,

05:51 well, tool belt of useful classes and functions to use, to like make working with requests easier.

05:57 And it really does at the moment for things. But I think if people are out there and they're like,

06:02 I always have to do this with requests, it's like these five lines. I got to make sure I remember to

06:06 do this right. It would be awesome to just, you know, extend this. So this is a small project by

06:11 someone I can't remember. I don't think it says like really a meaningful name on it. Yeah. No,

06:16 it's just under requests. Actually, this is not the small project I think, you know, but I think it

06:20 would be cool to like take those ideas. If you see patterns that you're doing with the request library and

06:24 fold them in here. So let me give you the rundown on the four things it does. First of all, if you're

06:29 going to do multi-port form data encoding, like I have an image file and I want to upload it to the

06:37 server, to the API, that's annoying, right? It's not, not super easy, but with this thing, it's really

06:43 easy to go and just basically say, here's a file stream that is field two. It's, you know, whatever

06:50 it is, right? It's binary image data or it's text. And then you just say, here's my data,

06:55 this multi-part form encoder and boom, it's just uploading files and doing all the stuff it has to

07:01 do. That's incredible. Just a few lines of code. Yeah. It's really, really nice. And you don't have

07:04 to think about like, how do I do multi-part encoding again? Just give it a file stream. You're good.

07:08 The next one is the user agent constructor. So you have to set a header user to ask agent,

07:14 but then like, how do you construct that in a meaningful way? There's a class that takes,

07:17 or a method, I think it's just a method, takes some arguments and it will generate the string

07:22 that is a, I guess, compliant user agent for like your API app or whatever. So that's cool. User

07:30 agent constructor. Sometimes you have to, when you're working with other systems, conform to certain

07:36 SSL protocols, right? We have TLS version one, 1.2. We have two, I think coming along,

07:43 but there's different versions of TLS, which is the foundation of SSL, right? So they have an SSL

07:48 adapter that lets you explicitly set, I want to use TLS 1.2 or 1.0 or something like that if you need

07:55 to. Oh, wow. Okay. That's cool. And then one thing that you can do with requests is you can create a

08:00 session and then it'll start talking over it. It probably reuses the connection. I'm not entirely sure

08:06 of all the things it does, but one of the things the session does is it'll remember cookies and things like

08:10 that. Well, maybe you want to make a series of requests using a request session that doesn't

08:17 actually carry the cookies from time from request one to two to three and so on. So one of the classes

08:23 in here is a forgetful cookie jar. So if you, if you set the request session cookies container to the

08:31 forgetful cookie jar, it will, well, it implements the protocol, but it always forgets its cookies,

08:36 obviously. So it's a cool way to like clear out still use sessions, but clear out cookie

08:41 persistence across calls. Is there a reason to use sessions without cookies? Well, some websites

08:47 behave differently if they think they've already seen you or things like that, right? Yeah. Like maybe I

08:52 want to test the login function, both working and not working. And then I want to try it of, I forgot my

08:58 password, but it, I don't want it to know that I've already actually logged in and that sequence or

09:04 something like it could be some like series that you're testing for playing with. Okay. So like,

09:08 if you got a login, your session login is still valid, but you have to go. Yeah. Yeah. Or maybe

09:13 you're going to a place like some sort of paywalled ad place and it's like, well, you can come here

09:18 three times, 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? You're like, well, you're using cookies for that. And my cookie jar is forgetful.

09:27 I don't know. There's, I don't personally have a reason for it, but I can imagine reasons that that

09:32 might, people might use that for like automation and whatnot. I predict that we will hear other

09:36 people telling us the reasons now. Yeah, absolutely. They definitely might. So people can visit

09:42 Pythonbytes.fm slash 165 and down at the bottom, they can tell us why, why they're doing some cool

09:47 comment section. Yeah. All right. Speaking of cool, let me tell you about DigitalOcean. They're doing all

09:51 sorts of good stuff. They're offering a hundred dollars credit for new users. So it was 50,

09:56 it's back to a hundred. Yay. That's great. And we, all of our infrastructure and stuff runs on DigitalOcean

10:02 and it's been just perfect for years. So that's great. One of the things they recently released is

10:07 memory heavy workload droplets. So memory focused droplets. So you can get up to eight gigs of RAM for

10:14 each dedicated CPU and it goes from two CPUs all the way up to, is that 32, 256 gigs of RAM available

10:24 on your VM, which is kind of ridiculous if you really need that, but you know, maybe you've got

10:28 a workload that does. So it's really good for high memory apps, like a high performance SQL or no SQL

10:33 databases and memory caches like Redis, maybe some data analysis of lots of data, stuff like that. So

10:39 check them out at pythonbytes.fm/DigitalOcean, get a hundred dollars credit from new users and

10:44 support the show. Speaking of data science, what do you got, Brian? What's next? Yeah. Speaking of data

10:48 science, pandas is used by lots of folks, not just data science, but I know the data analysis people use

10:54 pandas quite a bit. And in episode 162, you weren't with us for that, but we covered a project called

11:01 Bulwark. 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 suggestion about another package called pandas validation. And then I was

11:13 just looking around to see if there's other projects. One of the others I've found was Pandera. So I'll

11:20 try to briefly talk about these, but pandas validation, Lance tells us that it lets you create a template

11:26 for your data frame, how it should look, and then it validates your entire data frame against a template.

11:33 So if you have a data frame with the first column being string and second column being dates and then

11:38 an address, and you can use a mixture of built-in validate types to ensure that your data conforms

11:44 to that. So that looks pretty cool. Yeah, this is really nice. It's a little bit like tiny bit like

11:49 JSON schema or something. So you've got these pandas data frames or time series that it's just full of

11:54 whatever. And then you can throw on top of it a cool validation and just it's all at once against the

11:59 whole collection, right? Yeah. And then Pandera is, I think, a similar sort of project that lets

12:05 you set up types and properties for different columns of a data frame and perform validation

12:11 to make sure sort of a schema validation sort of thing also. So they're all kind of solving a similar

12:17 problem, but I was looking at it and the API and how you use it between Bulwark, Pandas validation,

12:23 Pandera are all very different. Yeah, they are. I'd really like to hear if there is a common approach

12:28 or if Pandas validation, data frame validation is just not something that's catching on yet or,

12:34 you know, what people are using. I'd love to hear that. Yeah. And I just noticed at the bottom of

12:38 Pandera, they have other data validation libraries and others, Panda specific ones like opulent Pandas

12:45 and Panda schema and Pandas validator and table enforcer and so on. So apparently this is like a whole

12:49 hole you can go down into that I was not even aware of, but I got to say the Pandera API where

12:55 you basically define a column, a data type, and then a Lambda function that you give it that does

13:02 the validation. That's super cool. I love that. Yeah. It looks pretty clean. Yeah. It looks incredibly

13:07 flexible without getting like out of control. Yeah. Speaking of out of control, you know, it's a

13:11 little bit out of control. GUIs for Python. Yeah. And this way, I don't mean it. I'm not actually this time

13:18 complaining about their absence or something like that. But one of the best libraries for building GUIs

13:27 in Python has got to be Qt, right? Yeah. And I was inspired at the Python meetup that you're running out in

13:37 West Portland when we saw Augie Moore give a presentation and how he used FBS, Fman build

13:43 system, plus PyInstaller, plus Qt to build, you know, nice packaged apps that are GUI apps that he

13:51 could distribute around. And that was really cool. So one of the things though that drives me crazy is

13:55 like we've got PyQt 5, we've got PySide 2, PyQt 4, we have PySide, we have Python 4 Qt. We have all

14:02 these different, different things, right? I think Python 4 Qt might be the next version of PyQt 5 and so on.

14:09 And I just don't know where to start, right? And look at it, that's going, oh my goodness. Like you see

14:13 different examples doing different things. And so I ran across something called QtPy. QtPy.

14:20 QtPy. Yeah. Or QtPy.

14:22 I wanted to say QtPy, but I don't know. QtPy. QtPy. So QtPy, actually, you know, one of the things

14:32 about a lot of these libraries is they're like really cool little proof of concepts, but in practice,

14:36 how real are they? How supported are they? And so on. One thing that seems real and supported is

14:44 Anaconda, the Anaconda distribution. And with that comes the spider IDE, like the whole Anaconda

14:49 Continuum data science IDE thing, right? And this QtPy is the foundation of what they're doing to

14:58 write that. Okay. At least it's in their GitHub repo. So it provides a uniform layer to support all

15:04 those different libraries that I complained about with a single uniform API. So it's like an adaptive

15:10 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

15:18 ways or against these different examples. Yeah, it's nice. Yeah, it's cool, right? So this is

15:22 created by the spider development team. And there's not a whole lot to it. Basically, it's like,

15:26 well, here's a simple simpler way to work with these different libraries, because maybe you want a

15:31 different license or you want to go from PyQt4 to PyQt5 or something like that. Because there's

15:38 all these different examples built with all these different libraries, and they're not exactly

15:41 compatible. So quite cool, I think. Yeah. And also during the presentation at the meetup,

15:46 Is it Ogie? Yeah. Mentioned that just he uses that. And then if there's a problem with one of

15:53 these packages, just uninstall it and install one of the other ones. And you don't have to change your

15:58 code at all. Yeah, it's cool. It just works. One of the other things I thought was neat is at the

16:03 bottom of the readme, they've got sponsors like, you know, different sponsors at the bottom and become

16:09 a sponsor. I have not seen an open source project do that before. It's an interesting idea.

16:13 Yeah, it is definitely an interesting idea. I haven't seen that either.

16:16 Yeah. So maybe I'll try that on my little open source project.

16:20 Well, they also have the GitHub sponsor at the top. Are you using the GitHub sponsor?

16:24 No.

16:25 That's something people can turn on. I think that's really cool that GitHub did that,

16:28 that people can now sponsor projects like through GitHub instead of negotiating some

16:34 deals separately with everyone.

16:35 Yeah. I wonder if they're tied together. Oh, I did look into it. Anyway.

16:39 Yeah. Check it out. All right. So yeah, what's next?

16:42 Well, I want to shed some light on spreadsheets.

16:45 They can be a dark place if you get sucked down into VBA or too far down there.

16:51 Yeah. So actually we got an email from Victor Kiss. I think it's Victor Kiss.

16:56 K-I-S. He said he's got his, 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:11 So it's a lightweight, zero dependency, minimal functionality, read writer has other than the standard library.

17:19 There's no outside dependencies and you can read and write modern XLSX and XLSM files.

17:26 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's pretty, looks pretty cool.

17:36 Yeah. It looks totally useful if all you got to do is like get in there and get the data.

17:40 I don't know if it like does things like lets you change say like conditional formatting or other weirdness, but it definitely, if you just get, want to open up an Excel worksheet, not a CSV, but like a full on XLS and get at the data or the rows or whatever it is you're after.

17:56 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 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.

18:20 And it's like, oh my gosh, I could just, if I needed to get read Excel from Python, I could get started in a few minutes with this.

18:28 So yeah, it looks pretty cool.

18:31 Yep.

18:32 And no dependencies.

18:32 That's kind of nice as well.

18:34 So I never really thought about why that would be important, but he lists one of the reasons is that if you are going to a few things, if you're going to compile it into another installer or something using pi installer, not having any DLL or other dependencies makes this easier.

18:52 And then he even says that he's a, 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.

19:04 Yeah.

19:04 Just vendor it.

19:05 And then you, you don't have dependencies either.

19:06 Yeah.

19:07 You know, getting updates, but you know.

19:09 Yeah.

19:09 Wow.

19:10 It's a trade-off.

19:11 I'm going to tell you about this other thing.

19:14 And at first it might not sound very exciting, but I'm actually pretty excited about it.

19:18 I think this is, this is quite cool.

19:20 It's a clever little library.

19:22 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 dash ranges.

19:31 Okay.

19:31 Okay.

19:32 So we have range, like the built-in range.

19:35 You can say, you know, start equals whatever, end equals whatever.

19:38 And it goes from the start integer wise up to, but not including the upper bound.

19:44 But you can't use that range in like more meaningful ways.

19:48 So for example, if I had a range of zero to a hundred, I can't easily ask, is X in there,

19:55 right?

19:55 If X is a number 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

20:07 operations, 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, but then it also extends that.

20:18 So you can have a range set, which is a bunch of different ranges or even a range dictionary.

20:25 So like, why would you care about that?

20:27 So what you could do with a range dictionary is you can use ranges as keys.

20:32 So if the example they give is if you have...

20:34 That'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, let's just

20:46 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 and so on.

20:55 And you had like a huge if, else 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

21:06 and so on.

21:07 And then like 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.

21:15 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

21:25 of a dictionary?

21:26 That's brilliant.

21:27 That's cool.

21:28 Isn't that 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.

21:33 Yeah.

21:33 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

21:40 flat statement of these ranges, and then it'll do the comparison kind of in the data structure.

21:45 Yeah.

21:46 Sweet.

21:48 So there's a bunch of stuff that you can do with these ideas.

21:51 They got some good examples, but that little example I gave you, I think is probably the

21:55 simplest one to tell you about because it gives you a good sense of like why you might actually

21:59 use this, right?

22:00 Like a lot of times you look for these blocks or these ranges and it's really cool to figure

22:05 out, to be able to sort of test in here.

22:07 Like you could even do really interesting stuff.

22:10 Like I want to know is this thing in any of these five ranges, you could just create one

22:15 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 like cool ways to layer these together.

22:25 Yeah.

22:25 And especially if you've got that all over the place.

22:27 Like for instance, I'm thinking hardware stuff.

22:31 Yeah.

22:31 It's got to be in there.

22:32 There's a bunch of numbers and frequencies and whatnot, right?

22:34 Right.

22:34 So if I've got different power levels, for instance, they'll have different attenuators that'll

22:39 kick in at different power levels, but I don't want those power level numbers to be hard

22:43 coded all over my code.

22:44 So having some central place where I put those in place so that I can just throw in a number

22:50 and it gets based on that.

22:52 I know what the attenuation is or something.

22:53 That'd be great.

22:54 It's cool.

22:55 Yeah.

22:55 That's cool.

22:56 It also, it occurs to me, this might be useful for testing, right?

22:59 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.

23:06 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.

23:11 Yeah.

23:12 Okay.

23:12 Cool.

23:12 Cool.

23:13 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.

23:20 Yeah.

23:21 Yeah, that's it for our main item.

23:22 So what else do you want to tell folks about?

23:24 Well, I spent some time last night.

23:26 I think I brought this up, I don't know, last time or the time before, that I have a few

23:31 open source projects, not many, but one of them was lacking some work because it had a

23:37 bunch of support requests or whatever you call them, issues.

23:40 So pytestCheck, I went in last night, I went and cleaned all those up and solved a couple

23:46 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

23:52 kind of wanted to highlight it, is plugin for pytest.

23:55 There are other plugins for pytest.

23:57 Some of them don't work together very well because of all the, the way they abuse and use

24:03 pytest.

24:03 I'm definitely abusing pytest hook functions with pytestCheck.

24:08 intentionally what it does is it allows you to check certain things within your test,

24:13 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

24:23 failures.

24:23 It fails them at the end, not as it hits the first one, right?

24:26 Yes.

24:27 But to get away with that, the only way I could figure out is to hook into the report

24:31 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:41 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 pytestCheck because of the way, at the time that they're

24:52 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,

25:00 flaky and retry don't.

25:02 Nice.

25:02 Oh, that's really cool.

25:03 I wonder if you could like monkey patch flaky or retry to like force it to check later or

25:09 something like that.

25:10 Maybe.

25:10 But also I actually commented in the defect report that it doesn't work with flaky.

25:15 And I said, well, I think it should try.

25:17 And I had a comment from somebody that said, you're just going to kill yourself off if you

25:22 think that you're going to 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

25:32 like this, use this other plugin and not my problem.

25:34 Yeah.

25:35 It seems cold, but open source is a side project.

25:38 So yeah, absolutely.

25:39 Cool.

25:40 Well, I've got a couple of 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

25:53 versioning.

25:54 It has a couple of new cool features.

25:55 So we're already speaking about Pandas earlier.

25:58 If you're using Pandas or whatever, you know, hey, Pandas 1.0 is out.

26:01 That's a big deal.

26:01 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

26:10 a PyCharm plugin called Python Security.

26:13 So we'll link to that.

26:14 And basically what it does is it goes through, much like when you're working with PyCharm,

26:19 it automatically tells you, oh, you're doing a type mismatch.

26:23 You're passing an int and it expects a string, or you're calling this function and it takes

26:27 two arguments, but you're giving it three.

26:29 It does all that checking in real time.

26:31 This one is for security.

26:32 So it checks for unsafe loading the YAML files, remote code execution in Flask, man in the

26:38 middle with requests or HTTPX, and debug configs in like Flask and Django stuff.

26:43 So that's kind of cool.

26:44 You want that?

26:45 Get that and install it.

26:46 Nice.

26:47 Yeah.

26:47 And then finally, I have my Python for Decision Makers course that sort of talks about whether

26:52 or not you should and how to position adopting Python at your organization.

26:57 So I did a webcast on that and that's already passed.

27:00 That went really well.

27:00 But the recording of it is out.

27:02 So I'll link to the recording if people want to sign up.

27:05 You got to like register for the thing, but then you just watch the recording.

27:08 Oh, I'll have to check that out.

27:10 Nice.

27:10 Yeah.

27:10 Yeah.

27:10 It was fun.

27:11 A lot of fun.

27:11 A lot of good conversations there.

27:13 All right.

27:13 I don't know about this joke, but I'm going to do it anyway.

27:16 You ready?

27:16 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

27:26 on, right?

27:26 Yep.

27:27 Well, there's a third angle here.

27:29 And for the engineer, you don't see the glass is half full or half empty.

27:34 No, the glass is twice as large as it needs to be.

27:37 Exactly.

27:40 It's all about capacity planning.

27:41 Come on.

27:42 Yeah.

27:42 Okay.

27:43 So I don't have a joke, but I came up with a little bit of a brain teaser this morning.

27:47 Okay.

27:48 Nice.

27:48 Let's have it.

27:49 Yeah.

27:50 When is 90 greater than 100?

27:52 When is 90 greater than 100?

27:53 Yeah.

27:54 Well, there's a couple places.

27:56 One, which I was informed on Twitter, is when you're comparing a string literals.

28:01 True.

28:02 Yeah.

28:02 Yeah.

28:02 If you're going to say quote 90 less than quote 100, it's false.

28:06 Yeah.

28:06 Okay.

28:06 The other one is microwave times.

28:08 So 100.

28:11 Nice.

28:13 Anyway.

28:14 Very good.

28:14 That's it.

28:15 All right.

28:16 Well, you've left people with something to think about.

28:18 And yeah, thanks for being here.

28:19 Thanks.

28:20 Bye.

28:20 Yeah.

28:21 Bye.

28:21 Thank you for listening to Python Bytes.

28:23 Follow the show on Twitter via at Python Bytes.

28:25 That's Python Bytes as in B-Y-T-E-S.

28:28 And get the full show notes at pythonbytes.fm.

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

28:36 We're always on the lookout for sharing something cool.

28:38 On behalf of myself and Brian Okken, this is Michael Kennedy.

28:41 Thank you for listening and sharing this podcast with your friends and colleagues.

Back to show page