WEBVTT 00:00:00.001 --> 00:00:05.040 Hello and welcome to Python Bytes, where we deliver news and headlines directly to your earbuds. 00:00:05.040 --> 00:00:09.240 This is episode 239, recorded June 23rd. 00:00:09.240 --> 00:00:10.880 It's almost the end of June. Wow. 00:00:10.880 --> 00:00:13.660 2021. I am Brian Okken. 00:00:13.660 --> 00:00:14.760 I'm Michael Kennedy. 00:00:14.760 --> 00:00:16.200 And I am Nick Moore. 00:00:16.200 --> 00:00:18.680 Welcome, Nick. Thanks for joining the show. 00:00:18.680 --> 00:00:21.400 Before we jump in, tell me a little bit about yourself. 00:00:21.400 --> 00:00:24.340 Yeah, sure. So as I said, Nick Moore. 00:00:24.340 --> 00:00:29.720 I'm based out of Ohio and I work as a data engineer, Trimble Transportation. 00:00:30.380 --> 00:00:38.960 It's a software company aiming to like revolutionize the way we supply the world and like simplify and connect like the world supply chain. 00:00:38.960 --> 00:00:43.300 Like it tries to make it easier to move goods and freight all around the world. 00:00:43.300 --> 00:00:49.740 I'm also the co-organizer of ClePy, which is Cleveland's Python meetup group. 00:00:49.740 --> 00:00:52.260 Thank you, Michael, for sharing it up on the screen. 00:00:52.260 --> 00:00:54.260 So, yeah, that's a bit about me. 00:00:54.260 --> 00:00:57.240 Nice. I enjoyed Cleveland when we were there for PyCon. 00:00:57.240 --> 00:00:59.460 Yeah, I think I met you guys there. 00:01:00.280 --> 00:01:00.480 Cool. 00:01:00.480 --> 00:01:02.520 I think you guys were in the JetBrains. 00:01:02.520 --> 00:01:04.500 That's right. We were. 00:01:04.500 --> 00:01:07.080 It was really great to be in Cleveland for a couple of years. 00:01:07.080 --> 00:01:09.220 And I guess we just completely missed Pittsburgh. 00:01:09.220 --> 00:01:14.200 But they're going to get another round out of here as a redo, which is cool from COVID. 00:01:14.540 --> 00:01:20.480 I got a chance to speak at the Cleveland Python meetup and talked about memory. 00:01:20.480 --> 00:01:21.020 Was that right? 00:01:21.020 --> 00:01:21.620 Yeah. 00:01:21.620 --> 00:01:24.160 You talked about how Python manages memory. 00:01:24.160 --> 00:01:26.300 It was like a really cool deep dive into that. 00:01:26.300 --> 00:01:26.720 Yeah. 00:01:26.720 --> 00:01:27.020 Thanks. 00:01:27.020 --> 00:01:28.200 That was super fun for having me. 00:01:28.200 --> 00:01:29.360 Now it's good to have you on our show. 00:01:29.360 --> 00:01:29.960 Yeah. 00:01:30.400 --> 00:01:31.580 So was that on purpose? 00:01:31.580 --> 00:01:34.180 Did you make a joke that you couldn't remember what the talk was about? 00:01:34.180 --> 00:01:34.700 No. 00:01:36.700 --> 00:01:44.060 I know how my brain might store the memory of what I spoke about, but I just, it could have been that or async and I wasn't 100% sure which one it was. 00:01:44.060 --> 00:01:47.320 We did talk about async too, though. 00:01:47.320 --> 00:01:48.200 Cool. 00:01:48.460 --> 00:01:48.640 Yeah. 00:01:48.640 --> 00:01:49.120 Yeah. 00:01:49.120 --> 00:01:49.540 For sure. 00:01:49.540 --> 00:01:52.840 Speaking of async, Brian, you see what databases tells us about it. 00:01:52.840 --> 00:01:57.620 Well, this is object relational mappers also. 00:01:57.620 --> 00:02:07.640 So we have ORMAR, which is an async mini ORM for Python, which supports Postgres, MySQL, and SQLite. 00:02:07.640 --> 00:02:13.120 This was a suggestion sent to us by John Hagen. 00:02:13.120 --> 00:02:14.780 So thanks, John, for sending this in. 00:02:14.780 --> 00:02:17.320 And I actually haven't played with this a lot. 00:02:17.320 --> 00:02:18.000 I was looking around. 00:02:18.060 --> 00:02:18.740 It looks pretty neat. 00:02:18.740 --> 00:02:20.840 But I'm going to quote John here. 00:02:20.840 --> 00:02:27.700 He says, it's a really cool ORM that combines Pydantic models and SQL models into a single definition. 00:02:27.700 --> 00:02:40.220 What is great about this is it can be used to reduce the repetitive duplication between the models for an ORM and the Pydantic models for that FastAPI needs to describe serialization. 00:02:40.220 --> 00:02:43.100 So I guess you do have to specify that twice normally. 00:02:43.940 --> 00:02:44.260 Yeah. 00:02:44.260 --> 00:02:51.580 Normally what you do is you would have the data model, the classes that do the exchange on the API level. 00:02:51.580 --> 00:02:53.080 So those would probably be Pydantic. 00:02:53.080 --> 00:02:56.240 But maybe then you have something like a SQLAlchemy model. 00:02:56.240 --> 00:03:03.820 And then somewhere in the middle, you've got to copy the SQLAlchemy data over to the Pydantic model, send out over FastAPI and you get it back. 00:03:03.820 --> 00:03:07.700 Then you've got to copy that from FastAPI and Pydantic back into SQLAlchemy. 00:03:08.260 --> 00:03:11.660 Because SQLAlchemy types are not really meant to be transferred on the wire. 00:03:11.660 --> 00:03:17.120 You don't get the open API documentation that you get from Pydantic integration and all those sorts of things. 00:03:17.120 --> 00:03:18.660 So that's normally what happens. 00:03:18.660 --> 00:03:24.440 But if your database model can also be a Pydantic model, then you don't do that back and forth. 00:03:24.440 --> 00:03:24.880 Yeah. 00:03:24.880 --> 00:03:30.120 And anytime you've got duplication, it's like that dry issue of just you're going to mess it up sometime. 00:03:30.120 --> 00:03:31.000 It's going to be wrong. 00:03:31.000 --> 00:03:49.500 And I think that's why SQLAlchemy, I think in version 1.4, they've been playing around with a lot of ideas on how to integrate data, not Pydantic, but data classes and the ORM style base models. 00:03:49.500 --> 00:03:54.240 Four different propositions of how that should be done, but it's not yet perfect. 00:03:54.240 --> 00:03:58.920 So I think that's something that it looks like they could learn from Omar here. 00:03:59.120 --> 00:04:07.720 Or at least it's good to have these sort of experiments going on for everybody to look around and see how do we move forward so that we can do this cleanly. 00:04:07.720 --> 00:04:08.240 Yeah. 00:04:08.240 --> 00:04:15.180 The one thing I will say is that with all of these ORMs, I don't know why they never give some love to SQL Server. 00:04:15.180 --> 00:04:18.060 I always see Postgres, MySQL, and SQLite. 00:04:18.060 --> 00:04:20.400 But like SQL Server is pretty cool too. 00:04:20.400 --> 00:04:23.120 Where is the support for that? 00:04:23.120 --> 00:04:24.540 What's SQL Server? 00:04:24.540 --> 00:04:27.800 So that's like Microsoft's, you know what? 00:04:28.000 --> 00:04:36.840 I think it really matters what audience you're addressing, Nick, right? 00:04:36.960 --> 00:04:42.760 So if you're talking startups and a lot of the open source crowd, yeah, it's all Postgres. 00:04:42.760 --> 00:04:45.580 Or, you know, if you're talking to Michael, it's all MongoDB, right? 00:04:45.920 --> 00:04:53.620 But if you're talking to enterprises, boy, oh, boy, do a big bunch of those enterprises run on the Microsoft stack. 00:04:53.620 --> 00:04:54.160 Yeah. 00:04:54.160 --> 00:04:57.960 Windows, Windows Servers, Microsoft SQL Server. 00:04:57.960 --> 00:05:02.320 And that's a non-trivial amount of the use cases for these things. 00:05:02.320 --> 00:05:09.920 So I agree that it should get some attention, even if it's not necessarily the one that the maintainers or many of the people are most keen to use. 00:05:10.260 --> 00:05:11.580 Yeah, and I agree. 00:05:11.580 --> 00:05:24.920 It was a joke, but one of the things I wanted to point out that John mentioned is that one of the benefits of Ormar is there's a quick start specifically for FastAPI. 00:05:25.080 --> 00:05:30.920 So you can look at the documentation and there's a FastAPI quick start on how to get this running with FastAPI. 00:05:30.920 --> 00:05:40.160 What an interesting combination of descriptors from the ORM class side and Pydantic models you get here. 00:05:40.280 --> 00:05:45.260 So for this, we have like the Pydantic model-based type of thing. 00:05:45.260 --> 00:05:56.500 We've got the columns specified with type information that Pydantic would use, but then you set them to things like an integer column that's a primary key or a string that has a max length setting and things like that. 00:05:56.500 --> 00:05:58.760 Yeah, it's like the worst of every world. 00:05:58.760 --> 00:06:03.180 But it's better than repeating stuff, right? 00:06:03.180 --> 00:06:04.640 So, yeah, interesting. 00:06:05.140 --> 00:06:06.940 Yeah, I think it's pretty good. 00:06:06.940 --> 00:06:11.260 And Nick, you mentioned SQL, Alchemy, and Data Classes. 00:06:11.260 --> 00:06:15.840 Pydantic also has some integration for working with Data Classes as well. 00:06:15.840 --> 00:06:21.540 So maybe there's a way to bridge those things across for like FastAPI and similar situations as well. 00:06:21.540 --> 00:06:23.280 I haven't tried that, but it's possible. 00:06:23.280 --> 00:06:24.180 Yeah, let's see. 00:06:24.180 --> 00:06:25.800 Out there in the live stream, we've got Sam Morley. 00:06:25.800 --> 00:06:26.160 Hey, Sam. 00:06:26.160 --> 00:06:28.080 Says, this looks a lot like a Django ORM. 00:06:28.080 --> 00:06:28.740 Yeah, absolutely. 00:06:28.740 --> 00:06:30.480 It really does. 00:06:30.480 --> 00:06:35.940 And then Dean is hoping that we'll get some support for a very important database, AccessDB. 00:06:35.940 --> 00:06:39.020 That and, oh gosh, what was it? 00:06:39.020 --> 00:06:40.600 DB2 and a couple of the others. 00:06:40.600 --> 00:06:44.680 Yeah, there's some really important ones that we might be forgetting, but I think it's going to be okay. 00:06:44.680 --> 00:06:47.960 Oh man, Access, that gives me PTSD from college. 00:06:47.960 --> 00:06:50.220 I can imagine. 00:06:50.220 --> 00:06:51.240 I can imagine. 00:06:51.240 --> 00:06:52.120 All right. 00:06:52.120 --> 00:07:01.260 Well, speaking of people who might be getting some trauma, let's talk about NoModuleNamed.com. 00:07:01.260 --> 00:07:03.220 In fact, it's now its own website. 00:07:03.220 --> 00:07:08.100 You used to think of it as like an error, and now it's actually a service. 00:07:08.100 --> 00:07:11.300 So error explanations of a service, I guess, is what you would call it. 00:07:11.300 --> 00:07:11.900 All right. 00:07:11.900 --> 00:07:16.880 So Garrett Dune pointed out that there's this website called NoModuleNamed. 00:07:17.180 --> 00:07:18.680 And it looks super plain. 00:07:18.680 --> 00:07:20.320 And I went to it like, what is this? 00:07:20.320 --> 00:07:24.680 It has 3,626 packages. 00:07:24.680 --> 00:07:28.520 And, oh my goodness, like 2 million modules or something like that. 00:07:28.520 --> 00:07:32.260 And it has 151,000 package install guidelines. 00:07:32.260 --> 00:07:34.960 So for example, what if I'm working with HTTPX? 00:07:34.960 --> 00:07:39.860 And I get the message that says, Python error, no module named HTTPX. 00:07:39.860 --> 00:07:40.160 Right? 00:07:40.160 --> 00:07:44.080 This is what you would have if you wrote import HTTPX and you went and tried to run it, 00:07:44.080 --> 00:07:49.880 but you were new and you didn't realize there were external dependencies or that HTTPX wasn't 00:07:49.880 --> 00:07:52.480 built into the standard library, you would get that error, right? 00:07:52.480 --> 00:07:53.020 Yeah. 00:07:53.020 --> 00:07:55.140 So this tells you how to fix it. 00:07:55.140 --> 00:07:58.760 It says, oh, this is probably because you don't have the package HTTPX. 00:07:58.760 --> 00:08:03.840 Let's see if I can go something like FastAPI.responses. 00:08:03.840 --> 00:08:04.620 Is that a thing? 00:08:04.620 --> 00:08:07.440 And what will it tell me if I try, oh, no such module. 00:08:07.440 --> 00:08:08.000 Yeah. 00:08:08.260 --> 00:08:13.680 But so NumPy, for example, it'll give you a lot of these and it'll tell you, this is 00:08:13.680 --> 00:08:19.300 probably because you don't have the package NumPy or NumPy MIPS64 installed. 00:08:19.300 --> 00:08:23.420 So that's what I was looking for is if it would sort of show like, well, the package name is 00:08:23.420 --> 00:08:25.840 not exactly what you're looking for. 00:08:25.840 --> 00:08:28.060 So maybe BS4, right? 00:08:28.060 --> 00:08:30.160 Sometimes there's these modules that, yeah. 00:08:30.260 --> 00:08:34.080 So for example, if I say BS4, it'll say, oh, it's because you don't have, if you have 00:08:34.080 --> 00:08:38.480 the error, no module name BS4, it's because you don't have beautiful Super 4 installed, 00:08:38.480 --> 00:08:38.940 right? 00:08:38.940 --> 00:08:42.760 So it's more than just like, duh, pip install the thing that there's no module of. 00:08:42.760 --> 00:08:47.160 It tries to help a little bit more with understanding that and it tells you how to get the latest 00:08:47.160 --> 00:08:47.600 version. 00:08:47.600 --> 00:08:48.800 It tells you how to install it. 00:08:48.800 --> 00:08:49.560 So yeah. 00:08:49.560 --> 00:08:51.160 And there's even a related article. 00:08:51.160 --> 00:08:57.900 Extremely beautiful like SEO on that with people just Googling error messages as well. 00:08:57.900 --> 00:08:58.380 Yeah. 00:08:58.720 --> 00:09:00.280 So pretty, pretty interesting. 00:09:00.280 --> 00:09:03.840 Garrett Dunn, thank you so much for sending that in. 00:09:03.840 --> 00:09:08.480 It's simple, but you know, these kinds of things can help people who are new and are getting 00:09:08.480 --> 00:09:08.740 in. 00:09:08.740 --> 00:09:13.140 And I think one of the powers of Python is we have people coming from all these different 00:09:13.140 --> 00:09:17.460 backgrounds and experiences, and they are not all computer science people that know about 00:09:17.460 --> 00:09:19.040 package managers and like love that. 00:09:19.040 --> 00:09:21.300 They're just like, oh, I know that I can do cool. 00:09:21.300 --> 00:09:24.560 I can like load this file and make a picture out of it that I need to work on. 00:09:24.560 --> 00:09:26.800 But I get this stupid no module named this. 00:09:26.800 --> 00:09:27.320 What is this? 00:09:27.320 --> 00:09:27.500 Right. 00:09:27.500 --> 00:09:29.640 And then they can, you know, these kinds of things can help. 00:09:29.640 --> 00:09:30.060 Yeah. 00:09:30.060 --> 00:09:34.280 Well, I'm trying to teach my 11 year old some programming and we started with packaging. 00:09:34.280 --> 00:09:34.840 Yeah. 00:09:34.840 --> 00:09:35.720 We didn't. 00:09:35.720 --> 00:09:39.500 I know you started with virtual environments and then packaging. 00:09:39.500 --> 00:09:40.240 Yeah. 00:09:41.200 --> 00:09:44.320 Brian, I thought you would have started with testing first. 00:09:44.320 --> 00:09:44.880 Yeah. 00:09:44.880 --> 00:09:45.760 I always test first. 00:09:45.760 --> 00:09:46.080 Yeah. 00:09:46.080 --> 00:09:50.600 I think this is like a really, this is like a really cool project. 00:09:50.820 --> 00:09:51.440 I find it's like a really cool thing. 00:09:51.440 --> 00:10:00.200 I find it super useful when I'm working on projects related to GUIs like Qt or Phoenix. 00:10:00.200 --> 00:10:00.780 No, no. 00:10:00.780 --> 00:10:01.780 WX Python. 00:10:01.780 --> 00:10:06.680 Because like those packages come with so many underlying dependencies. 00:10:06.680 --> 00:10:12.020 And sometimes you might miss one or might miss something that like is an OS dependency that you don't know. 00:10:12.020 --> 00:10:13.520 I feel like this could help you out. 00:10:13.900 --> 00:10:19.720 And I've run through this a few times where like I'm using like a package that is built on top of Qt. 00:10:19.720 --> 00:10:23.220 But then it tells me you don't have PyQt GT. 00:10:23.220 --> 00:10:24.320 PyQt 5. 00:10:24.320 --> 00:10:24.580 Right. 00:10:24.580 --> 00:10:25.140 Exactly. 00:10:25.900 --> 00:10:27.540 Well, I like that. 00:10:27.540 --> 00:10:33.360 I think you probably already mentioned this, but the error message is the module not found. 00:10:33.360 --> 00:10:35.360 That's often not the same. 00:10:35.360 --> 00:10:37.840 It's not the same name as the thing you pip install. 00:10:37.840 --> 00:10:39.760 Yeah. 00:10:39.760 --> 00:10:41.600 Like one that drives me crazy is DateUtil. 00:10:41.600 --> 00:10:42.680 I love DateUtil. 00:10:42.680 --> 00:10:45.820 I think it's like magic for the pain of parsing dates. 00:10:45.820 --> 00:10:47.180 But that's not what you install. 00:10:47.180 --> 00:10:49.500 You install Python underscore DateUtil. 00:10:49.500 --> 00:10:49.980 Right. 00:10:49.980 --> 00:10:53.740 And so there's just, it's those situations where you're like, why is there no DateUtil? 00:10:53.740 --> 00:10:55.020 I pip install DateUtil. 00:10:55.200 --> 00:10:56.600 And then it's not even the right thing. 00:10:56.600 --> 00:11:01.240 Or, you know, it's just, yeah, I think it's helpful to sort of put those things together for people. 00:11:01.240 --> 00:11:01.560 Yeah. 00:11:01.560 --> 00:11:04.780 And for people doing new packages, don't do this if you can. 00:11:04.780 --> 00:11:12.180 Even if you have the perfect name for your package, maybe come up with something else that you can actually, it's available on PyPI. 00:11:12.180 --> 00:11:13.000 Yeah. 00:11:13.000 --> 00:11:13.880 Yeah, for sure. 00:11:13.880 --> 00:11:14.480 All right. 00:11:14.480 --> 00:11:15.660 Nick, you got the next one, right? 00:11:15.660 --> 00:11:16.280 Yep. 00:11:16.280 --> 00:11:18.420 I got the next one. 00:11:18.420 --> 00:11:23.600 So I was looking through Jupyter. 00:11:23.600 --> 00:11:37.460 So I'm going to get, as I said, as a data engineer, I often use Jupyter for like data wrangling and just trying out how to like clean up some kind of data before I actually do the actual cleaning in our data pipeline. 00:11:37.460 --> 00:11:39.860 And so I stumbled, I got the new iPad. 00:11:39.860 --> 00:11:46.140 And I was, I went, I went to like tinkering around with like Python code and I was like researching into how to do that. 00:11:46.180 --> 00:11:49.740 And I stumbled across Jupyter light and I was like, okay, cool. 00:11:49.740 --> 00:11:50.340 Jupyter light. 00:11:50.340 --> 00:11:55.400 But sometimes I'm not going to always going to be connected to internet using my iPad. 00:11:55.400 --> 00:12:02.540 And then I looked deeper into it and it's a, Jupyter distribution that runs entirely in the browser. 00:12:02.540 --> 00:12:07.520 And it's like built from the ground up using Jupyter lab components and extensions. 00:12:07.520 --> 00:12:09.120 And that's cool. 00:12:09.120 --> 00:12:14.500 And the, and the kernels that are available are like in the browser. 00:12:14.500 --> 00:12:19.700 So like there's a Python kernel that is like in the browser and it's built using PyIodide. 00:12:19.700 --> 00:12:21.580 That was like really cool to see. 00:12:21.660 --> 00:12:31.520 and there's also like, I think there is a, where is it in the user guide, there are other kernels such as, yeah. 00:12:31.520 --> 00:12:42.280 JavaScript and P5 JS, which I think is like a graphics library to build like things on canvas, but it was really cool to see like it's supports Python 3.8. 00:12:42.280 --> 00:12:45.340 And, you get like start session. 00:12:45.340 --> 00:12:49.720 You can run Python code, Python completion, which is really cool. 00:12:50.220 --> 00:12:50.620 It's interesting. 00:12:50.620 --> 00:12:53.420 They call the kernel Pyolite. 00:12:53.420 --> 00:12:56.440 Pyolite based on PyIodide. 00:12:56.440 --> 00:12:57.020 Yeah. 00:12:57.020 --> 00:12:59.800 And this is, I pulled it on. 00:12:59.800 --> 00:13:00.680 This is how it looks like. 00:13:00.680 --> 00:13:02.160 And it looks pretty cool. 00:13:02.160 --> 00:13:04.340 So it also supports, right. 00:13:04.340 --> 00:13:10.420 I think for now it supports Altair and, I think Matplotlib as well. 00:13:10.420 --> 00:13:10.800 I think. 00:13:10.800 --> 00:13:11.080 Yeah. 00:13:11.080 --> 00:13:12.340 Matplotlib. 00:13:12.340 --> 00:13:17.240 And so like open up this Altair notebook. 00:13:17.240 --> 00:13:20.200 it even has something called Micropip. 00:13:20.200 --> 00:13:32.540 which is like, I don't know what this means, but if you're, it, I think it means that it's, like, is a package manager, but for the browser for Python, which is interesting. 00:13:32.600 --> 00:13:37.320 Oh, and it's, it's, it's, asynchronous because it's JavaScript basically. 00:13:37.320 --> 00:13:37.600 Right. 00:13:37.600 --> 00:13:42.160 So it's a wait micro pip installed like Jinja2, or Altair or something like that. 00:13:42.160 --> 00:13:42.660 How interesting. 00:13:42.660 --> 00:13:44.260 That's very cool. 00:13:44.500 --> 00:13:47.880 I think it also, everything that you download 00:13:47.880 --> 00:13:52.580 and everything that, all the data that you, like, load up, 00:13:52.580 --> 00:13:56.640 it's being stored in the browsers, like local storage 00:13:56.640 --> 00:13:59.800 or some other, I don't know, indexed DB. 00:13:59.800 --> 00:14:02.360 So it's, like, self-contained. 00:14:02.360 --> 00:14:04.520 The only thing I noticed is that right now, 00:14:04.520 --> 00:14:09.000 it's not, what was the word here? 00:14:09.000 --> 00:14:10.580 A PWA. 00:14:10.580 --> 00:14:13.920 Yes, I was just thinking it would be fantastic 00:14:13.920 --> 00:14:15.380 if that was a progressive web app 00:14:15.380 --> 00:14:18.940 and then you could just have it in mostly offline mode, yeah. 00:14:18.940 --> 00:14:21.840 Edge does a great job with PWAs 00:14:21.840 --> 00:14:25.040 and every time it detects, like, a manifest adjacent 00:14:25.040 --> 00:14:26.780 to show you, do you want to install this app? 00:14:26.780 --> 00:14:29.720 And I would just love to have, like, just click install 00:14:29.720 --> 00:14:32.300 and then have Jupyter Lite wherever I go 00:14:32.300 --> 00:14:34.720 or load it up on my iPad and then disconnect 00:14:34.720 --> 00:14:36.900 and still be tinkering around with what I want. 00:14:36.900 --> 00:14:38.500 So this is all browser-based. 00:14:38.500 --> 00:14:39.820 So that's really cool. 00:14:39.820 --> 00:14:41.520 I'm not going to run any of these, 00:14:41.520 --> 00:14:43.340 but I encourage everybody to check this out. 00:14:43.340 --> 00:14:44.340 It's pretty cool. 00:14:44.340 --> 00:14:45.680 Yeah, yeah, this is really cool. 00:14:45.680 --> 00:14:47.820 I do the same thing with, I use Brave. 00:14:47.820 --> 00:14:51.480 So I have, like, a YouTube app installed on my Mac 00:14:51.480 --> 00:14:54.440 and I've got a Twitter app installed. 00:14:54.440 --> 00:14:56.980 All is progressive web apps, so you can just launch them. 00:14:56.980 --> 00:14:58.700 I do wish Firefox supported that. 00:14:58.700 --> 00:14:59.800 Firefox, people, if you're listening, 00:14:59.800 --> 00:15:01.420 bring back the progressive web app. 00:15:01.420 --> 00:15:02.080 We all need this. 00:15:02.080 --> 00:15:02.620 Yep. 00:15:03.140 --> 00:15:03.800 Yeah, that's cool. 00:15:03.800 --> 00:15:05.820 What are some of the other notebooks in there that look cool? 00:15:05.820 --> 00:15:09.300 Are these, like, demo ones or did you create these? 00:15:09.300 --> 00:15:10.340 Yeah, there's a demo one. 00:15:10.340 --> 00:15:13.940 So there's a P5JS one. 00:15:13.940 --> 00:15:15.200 There's the Altair one. 00:15:15.200 --> 00:15:16.800 I don't know what Folium is. 00:15:16.800 --> 00:15:19.740 There's the interactive widgets, which is cool. 00:15:19.840 --> 00:15:24.940 So it still uses Jupyter's iPython notebook widgets, 00:15:24.940 --> 00:15:26.380 Matplotlib. 00:15:26.380 --> 00:15:28.780 Oh, Plotly as well. 00:15:28.780 --> 00:15:29.400 Nice. 00:15:29.400 --> 00:15:30.600 And Plotly, cool. 00:15:30.600 --> 00:15:33.400 And so this is a de facto, like, Pyolite one. 00:15:33.600 --> 00:15:36.760 So it supports Matplot, Pandas. 00:15:36.760 --> 00:15:37.600 That's cool. 00:15:37.600 --> 00:15:39.680 It supports LaTeX as well. 00:15:39.680 --> 00:15:40.660 Yeah, it's great. 00:15:40.660 --> 00:15:46.740 And so, like, as I was saying before, Pyolite is, what is it? 00:15:46.740 --> 00:15:51.980 It's, like, implementation of Python on the browser. 00:15:51.980 --> 00:15:56.540 Actually, implementation of Python is on the computing stack on the browser. 00:15:56.540 --> 00:16:02.820 So I think things like Pandas, NoobPy, SciPy, SciCutLearn are already, like, available. 00:16:02.820 --> 00:16:05.120 It's within the Pyolite ecosystem. 00:16:05.120 --> 00:16:05.820 So you don't have to... 00:16:05.820 --> 00:16:10.840 Yeah, I had the guys behind it, you know, Firefox and Mozilla were behind it originally, at least. 00:16:10.840 --> 00:16:12.760 And I had them on Talk Python. 00:16:12.760 --> 00:16:14.780 I believe it's WebAssembly based. 00:16:14.780 --> 00:16:20.000 I think what they did is they took all these major visualization libraries and things like Pandas and NumPy 00:16:20.000 --> 00:16:26.020 and compiled them all into a Python plus those WebAssembly thing that runs in the browser. 00:16:26.020 --> 00:16:28.400 instead of a JavaScript version, which is pretty awesome. 00:16:28.400 --> 00:16:29.420 Oh, even Symbol. 00:16:29.420 --> 00:16:35.940 Yeah, the symbolic output, like, got the math symbol integral of the square root of one over XDX. 00:16:35.940 --> 00:16:36.720 Beautiful. 00:16:36.720 --> 00:16:38.840 I wonder if you could get hand calcs on it. 00:16:38.840 --> 00:16:39.540 Oh, yeah. 00:16:39.540 --> 00:16:42.200 Awesome. 00:16:42.200 --> 00:16:43.060 Cool. 00:16:43.060 --> 00:16:43.300 All right. 00:16:43.300 --> 00:16:44.220 Well, that's a really good one. 00:16:44.220 --> 00:16:45.220 I love it. 00:16:45.220 --> 00:16:48.840 All the data scientists out there can definitely enjoy that. 00:16:48.840 --> 00:16:49.700 Yeah, cool. 00:16:49.700 --> 00:16:51.140 What do we got next? 00:16:51.140 --> 00:16:52.320 I think you're up next. 00:16:52.320 --> 00:16:53.340 Oh, right. 00:16:53.340 --> 00:16:53.800 Okay. 00:16:54.800 --> 00:16:56.580 So next, we've got... 00:16:56.580 --> 00:16:57.260 More plotting, maybe? 00:16:57.260 --> 00:16:58.340 Yeah, more plotting. 00:16:58.340 --> 00:17:02.420 So this is a long title. 00:17:02.420 --> 00:17:03.600 Basically, it's lots of plots. 00:17:03.600 --> 00:17:10.720 There's eight popular graphs made with Pandas, Map, Plotlib, Seaborn, and Plotly Express. 00:17:11.520 --> 00:17:19.020 And I've seen a lot of articles and stuff talking about how to do different plots in one or more of these. 00:17:19.020 --> 00:17:20.260 And a lot of them are... 00:17:20.260 --> 00:17:26.500 A lot of the articles, and rightly so, are focused on something cool you can do with one library that you can't do with others. 00:17:26.500 --> 00:17:29.660 And I've seen Seaborn ones like that. 00:17:29.660 --> 00:17:30.300 And that's great. 00:17:30.300 --> 00:17:42.660 What I like about this article is it's like, well, let's just take these different pandas plotting and Map, Plotlib, Seaborn, Plotly Express, and do the same plot. 00:17:42.660 --> 00:17:44.700 Let's do something they can all do. 00:17:44.700 --> 00:17:46.920 And so that's what this article does. 00:17:46.920 --> 00:17:49.220 It does a whole list. 00:17:49.300 --> 00:17:57.020 You've got normal line charts, grouped bar charts, stacked bars, pies, a whole bunch of things, and histograms. 00:17:57.020 --> 00:18:01.580 And then you can just compare to see what it looks like before you try. 00:18:01.580 --> 00:18:08.460 And for one, it's got the output, what do the graphs look like, which is important. 00:18:08.460 --> 00:18:11.780 But also, it's a fairly simple article. 00:18:11.780 --> 00:18:14.940 It's talking about what the plots look like, but also how do you make them? 00:18:14.940 --> 00:18:18.460 It's in a Jupyter Notebook Viewer. 00:18:18.460 --> 00:18:23.240 And it shows you what's the code look like to get these plots set up. 00:18:23.240 --> 00:18:30.240 And I think that's a big part of choosing your plotting library is looking at the API to see what kind of API looks comfortable to you. 00:18:30.240 --> 00:18:32.340 Yeah, I've got to write this code. 00:18:32.340 --> 00:18:33.800 Will I be able to remember this? 00:18:33.800 --> 00:18:34.160 Yeah. 00:18:34.160 --> 00:18:37.760 Or will it be like regular expressions and I learn it every time I use it? 00:18:37.760 --> 00:18:42.740 Yeah, or if you get stuck with one and you want to switch to other to sort of look at what the deltas are. 00:18:42.740 --> 00:18:46.600 I like these side-by-side apples-to-apples comparison sort of articles. 00:18:46.800 --> 00:18:50.860 So I think this is good for choosing the simple parts of plotting. 00:18:50.860 --> 00:18:55.740 But some of the comparisons are sort of funny because the bar charts just kind of all look the same. 00:18:55.740 --> 00:19:02.020 That one's orange versus orange and blue versus green and blue. 00:19:02.020 --> 00:19:02.780 It's not all the same. 00:19:03.420 --> 00:19:08.500 Yeah, but you get down into some of the fancy ones and they do look great. 00:19:08.500 --> 00:19:10.660 Some of the area charts. 00:19:10.660 --> 00:19:12.800 Yeah, that one looks great. 00:19:12.800 --> 00:19:13.280 What's that? 00:19:13.280 --> 00:19:15.780 Polly Express area charts look awesome. 00:19:15.780 --> 00:19:17.480 Yeah, the area charts look good. 00:19:17.760 --> 00:19:20.440 And I didn't know what a donut chart was. 00:19:20.440 --> 00:19:22.860 A donut chart looks like a pie chart with a hole in it. 00:19:22.860 --> 00:19:23.120 Yep. 00:19:23.120 --> 00:19:24.600 Why do people use that? 00:19:24.600 --> 00:19:35.660 I think it's because of like with the pie charts, the sectors are kind of, it's kind of, sometimes it can be hard to see like how much width. 00:19:35.820 --> 00:19:39.140 No, like, yeah, the circumference of like this sector. 00:19:39.140 --> 00:19:44.940 So maybe the donut chart kind of makes it easier to see like, okay, this takes like all of this. 00:19:44.940 --> 00:19:46.680 It's just a visual thing, to be honest. 00:19:46.680 --> 00:19:46.980 Yeah. 00:19:46.980 --> 00:19:48.100 Okay, good. 00:19:48.100 --> 00:19:49.100 Nick, this is your world. 00:19:49.100 --> 00:19:49.540 What do you think? 00:19:49.780 --> 00:19:57.120 I think this is really cool, but to be honest, all of these APIs don't compare to the grammar of graphics from R. 00:19:57.120 --> 00:20:07.800 And so I usually, if I am going to do graphics in Python, I would prefer to use something that like conforms to the grammar of graphics. 00:20:07.800 --> 00:20:16.040 Because to me, that's kind of, you know how like Python has the import this and it's all philosophy of how to write Python. 00:20:16.040 --> 00:20:18.080 The grammar of graphics like has that. 00:20:18.180 --> 00:20:23.520 So it has like, gives you these like sentences, so to speak, to build graphics. 00:20:23.520 --> 00:20:25.480 And I was like, that makes so much sense in my head. 00:20:25.480 --> 00:20:30.940 So like for graph, for graphing lab reads, it's either Altair or ggplot. 00:20:30.940 --> 00:20:36.120 And there is like a Python port of ggplot that's pretty good. 00:20:36.120 --> 00:20:40.900 But I think Altair is like the Pythonic de facto version that I've used. 00:20:40.900 --> 00:20:41.780 That's really nice. 00:20:42.300 --> 00:20:50.000 All the other ones that make me have to do like, like, like, like, do these method calls on objects. 00:20:50.000 --> 00:20:52.520 Just, I can't, I can't remember it. 00:20:52.520 --> 00:20:54.500 I have to come back to something like this. 00:20:54.500 --> 00:20:56.180 So how do you use gnm.lib? 00:20:56.180 --> 00:20:57.940 Are you using Seaborn? 00:20:57.940 --> 00:21:05.100 I really like the fact that like Seaborn has a lot of one liners to like do simple charts in one line, which is great. 00:21:05.640 --> 00:21:06.820 Like with the grammar graphics, right? 00:21:06.820 --> 00:21:08.860 It still makes you have to build everything out. 00:21:08.860 --> 00:21:18.200 But if I'm building something really custom or I am just building something that I have, I want to have complete control over. 00:21:18.400 --> 00:21:27.440 The grammar graphics just gives me a better way of like remembering what to do compared to having to remember all this API, all this API, all this method API calls. 00:21:27.440 --> 00:21:32.500 Well, I mean, the author, Dylan Castillo, says, let me know what you think. 00:21:32.500 --> 00:21:37.680 So maybe we can give him some feedback to add Altair and a couple others. 00:21:37.680 --> 00:21:38.800 Oh, yeah, that'd be cool. 00:21:38.800 --> 00:21:41.060 Dean also has some thoughts out there, right? 00:21:41.060 --> 00:21:44.740 Oh, Seaborn and Pandas use Matplotlib in the backend. 00:21:44.740 --> 00:21:47.020 So you can do everything they can do with Matplotlib. 00:21:47.020 --> 00:21:49.320 Okay, maybe harder, but not impossible. 00:21:49.320 --> 00:21:51.840 And also, that's probably why they look all the same. 00:21:51.840 --> 00:21:55.220 They are the same. 00:21:55.220 --> 00:21:56.580 Turtles all the way down. 00:21:56.580 --> 00:22:01.580 And he also says, remember, kids, almost every command in Matplotlib returns the object it charts. 00:22:01.580 --> 00:22:04.680 That's the start of OOP, object-oriented plotting. 00:22:04.680 --> 00:22:05.440 All right, right on. 00:22:05.440 --> 00:22:07.020 Oop, it'd be two Ps. 00:22:07.020 --> 00:22:08.960 Oop, oop, oop. 00:22:08.960 --> 00:22:10.480 I don't know how to pronounce that. 00:22:10.480 --> 00:22:14.640 All right, well, Brian, you got to talk about databases. 00:22:14.640 --> 00:22:16.440 So I'm going to talk about databases, too. 00:22:16.440 --> 00:22:22.460 But my databases are going to be smaller and in-memory and embedded, but also about MongoDB. 00:22:22.460 --> 00:22:28.680 So there's this really cool one created by David Latwi called MontyDB. 00:22:28.680 --> 00:22:31.140 So it's a Monty. 00:22:31.140 --> 00:22:34.340 It's a MongoDB tiny-ified. 00:22:34.680 --> 00:22:37.060 So it's MongoDB implemented in Python. 00:22:37.060 --> 00:22:41.100 And you can have it in process, kind of like SQLite, I believe. 00:22:41.100 --> 00:22:48.180 We've covered a couple of these libraries that are starting to show up that let you do sort of embedded MongoDB, which I think is really neat. 00:22:48.440 --> 00:22:52.700 So it's inspired by TinyDB and its extension TinyMongo. 00:22:52.700 --> 00:22:55.160 So the way you work with it, it's super simple. 00:22:55.160 --> 00:22:57.340 You just import the Monty client. 00:22:57.340 --> 00:23:01.380 And if you want to go crazy, you could say as Mongo client and make it basically the same. 00:23:01.380 --> 00:23:04.540 And then you can give it connection strings like colon memory colon. 00:23:04.540 --> 00:23:07.080 That should look familiar from something like SQLite. 00:23:07.080 --> 00:23:18.180 And then you can insert data to it, do all sorts of things, and do queries against it, run the MongoDB query syntax against it, and you get the responses back, which I think is pretty cool. 00:23:18.180 --> 00:23:20.720 It's certainly interesting for testing. 00:23:20.720 --> 00:23:27.140 If you told it to use a file storage, it could be an interesting little embedded database and things like that. 00:23:27.140 --> 00:23:28.100 So pretty cool. 00:23:28.100 --> 00:23:34.560 It supports many of the MongoDB versions up to 4.2 and 4.4 on the way with wave emoji. 00:23:34.680 --> 00:23:38.140 I'm not really sure about that, but also supports the... 00:23:38.140 --> 00:23:38.420 What's that? 00:23:38.420 --> 00:23:39.600 I think it's sweat. 00:23:39.600 --> 00:23:41.100 Oh, gotcha. 00:23:41.100 --> 00:23:42.460 Like the work is being done. 00:23:42.460 --> 00:23:42.760 Gotcha. 00:23:42.760 --> 00:23:49.380 So you can pip install MontyDB, and it will work in sort of its way. 00:23:49.380 --> 00:23:58.960 If you want to use the actual serialization library from MongoDB itself, you can say install MontyDB bracket BSON to install that as well. 00:23:59.320 --> 00:24:05.000 And it also has a lightning memory map DB, LMDB library. 00:24:05.000 --> 00:24:07.420 You can use that as the storage engine as well. 00:24:07.420 --> 00:24:10.500 So you can pip install, you know, add that on as well. 00:24:10.500 --> 00:24:13.520 So for the storage, you've got in memory, you've got a flat file. 00:24:13.520 --> 00:24:16.820 It'll actually use SQLite as a back-end store, which is pretty cool. 00:24:16.820 --> 00:24:20.140 And then that LMDB lightning memory mapped DB. 00:24:20.380 --> 00:24:32.680 So this looks pretty neat to me if you're going to do some kind of embedded thing or you're going to do some testing and you want something lightweight that's not a separate server you've got to set up and run and all those kinds of things. 00:24:32.680 --> 00:24:33.660 This is cool. 00:24:33.660 --> 00:24:34.640 I think it's awesome. 00:24:35.100 --> 00:24:41.660 Could you make this a pytest fixture, Brian, that just gives you, like, presets up your database and gives you access to the connection or something? 00:24:41.660 --> 00:24:42.520 Yeah. 00:24:42.520 --> 00:24:52.360 I mean, actually, I'm not really a fan of people switching their databases too much for testing because most modern databases have in-memory options or smaller version options. 00:24:52.360 --> 00:24:57.440 But, I mean, we use SQLite for tons of stuff that's not just for testing. 00:24:57.880 --> 00:25:02.920 And if you've got SQLite at the back-end, there's no reason why this couldn't be a production thing then. 00:25:02.920 --> 00:25:04.220 Yeah, absolutely. 00:25:04.220 --> 00:25:05.640 No, this is really cool. 00:25:05.640 --> 00:25:11.400 This could be really useful for, like, CLI apps that need to store your things. 00:25:11.400 --> 00:25:12.520 Yes, exactly. 00:25:12.520 --> 00:25:20.520 You want to have a little thing, but you don't want to say, oh, you want to run my little utility I packaged up with Py2 app or Py2.exe or something? 00:25:20.520 --> 00:25:20.920 Yeah. 00:25:20.920 --> 00:25:23.640 You're going to need to install MongoDB and become an admin of that. 00:25:23.860 --> 00:25:29.600 No, you just use, like, a SQLite file as the back-end store or the LMDB version. 00:25:29.600 --> 00:25:35.780 Another thing that's common from the MongoDB world is there's a set of CLI tools that allows you to manage it. 00:25:35.780 --> 00:25:37.980 So I can connect to it. 00:25:37.980 --> 00:25:51.020 I can import a bunch of exported files from some other or backed-up files from some other MongoDB instance and import that into my current server or whatever or create those exports, right? 00:25:51.020 --> 00:25:57.500 There's actually a bunch of utilities called Monty Import, Monty Export, Monty Restore, Monty Dump. 00:25:57.500 --> 00:26:04.660 All of these are the parallels of Mongo, Mongo Dump, Mongo Restore, and so on, right? 00:26:04.660 --> 00:26:11.060 So if you were used to working with MongoDB, it's not just explicitly that there's some API to talk to some file. 00:26:11.060 --> 00:26:13.760 There's also, like, the tools that are there as well. 00:26:13.760 --> 00:26:14.260 Yeah. 00:26:14.260 --> 00:26:15.360 Yeah, I don't know. 00:26:15.360 --> 00:26:17.380 I think that could be a cool project. 00:26:17.380 --> 00:26:26.940 So why don't I make this mostly for just fun and practicing on it, but also need it to run in this limited little environments for, like, render farms in the film industry. 00:26:26.940 --> 00:26:27.880 So that's pretty cool. 00:26:27.880 --> 00:26:31.480 It's a side project also with render farms. 00:26:33.560 --> 00:26:35.840 It's a side project for my supercomputer, yes. 00:26:35.840 --> 00:26:40.100 I love the name, by the way, Monty, Monty Python. 00:26:40.100 --> 00:26:40.980 I love it. 00:26:40.980 --> 00:26:47.040 Yeah, I mean, yeah, it really brings the MongoDB wordplay in with Monty Python, Python origin. 00:26:47.040 --> 00:26:48.460 Yeah, pretty cool. 00:26:48.460 --> 00:26:49.720 All right, Nick, you got the last one. 00:26:49.720 --> 00:26:50.720 Awesome. 00:26:52.480 --> 00:26:54.440 Exhaustiveness checking with mypy. 00:26:54.440 --> 00:27:06.940 So essentially what exhaustiveness checking is, is a feature of, like, a lot of type checkers where they guarantee that the programmer has covered all their cases. 00:27:06.940 --> 00:27:22.160 And so with mypy, you could essentially check things, like, whether you've covered all the, like, you have written all the if statements you're supposed to write at compile time rather than figuring that out at runtime. 00:27:22.160 --> 00:27:34.160 And, like, I really got into using mypy and trying to, like, have it save my bot a lot in the way I think about code by embracing types. 00:27:34.160 --> 00:27:46.400 So I stumbled across this, which was, like, really interesting, where this article written by Haki Benita went into how, like, exhaustive net checking actually works. 00:27:46.400 --> 00:27:51.620 So they start out with an enum that has order status. 00:27:51.620 --> 00:28:01.420 And you have a function that is called handle order that takes a status, which is an instance, which should be an instance of order status. 00:28:01.420 --> 00:28:07.320 And so in his function, he has this, like, if status is order ready, you do something. 00:28:07.320 --> 00:28:09.740 If status is order shipped, you do something. 00:28:09.740 --> 00:28:20.500 But then he gave this, like, added this, like, new, like, scenario where what if you wanted to check the status of something scheduled? 00:28:20.500 --> 00:28:23.040 And so he tried to run mypy right now. 00:28:23.040 --> 00:28:24.260 I didn't complain about it. 00:28:24.260 --> 00:28:25.440 So it was like, okay, cool. 00:28:25.440 --> 00:28:26.340 Yeah. 00:28:26.380 --> 00:28:32.960 Because one of the things that's very common is if you have something like a set of cases, in this case, it's put together in an enumeration. 00:28:32.960 --> 00:28:33.600 Yeah. 00:28:33.600 --> 00:28:35.120 You have more cases over time. 00:28:35.120 --> 00:28:44.500 But all these if, else if, else if, else if statements all over your code, have you exhaustively gone through and added that case check for all of them? 00:28:44.500 --> 00:28:45.260 Probably not. 00:28:45.260 --> 00:28:46.120 Yeah, probably not. 00:28:46.120 --> 00:28:46.420 Unless you've got good tests. 00:28:46.420 --> 00:28:47.560 A really good test. 00:28:47.560 --> 00:28:47.760 Yeah. 00:28:48.760 --> 00:28:49.320 Okay. 00:28:49.320 --> 00:29:01.800 And so he proposed, like, one quick way of checking that you handled all cases is by adding this assert false, comma, unhandled status. 00:29:01.800 --> 00:29:04.280 And you pass in the status using f-strings. 00:29:04.280 --> 00:29:12.220 And so then when you try to pass a state that you have not actually handled before, you actually get assertion error, right? 00:29:12.480 --> 00:29:26.220 Which is all right, but if you use mypy, there's this clever trick where you create a function called assert never that takes a value called no return and returns no return. 00:29:26.220 --> 00:29:29.520 And in it, it has the assert false unhandled value. 00:29:29.520 --> 00:29:41.260 And so then when you use that function in your handle order function, at the end case, you have this else assert never and you pass in the status. 00:29:41.860 --> 00:29:50.420 Now when you check with mypy, mypy will know, hey, argument one to assert never has incompatible type, literal, order status schedule, expected, no return. 00:29:50.420 --> 00:29:52.200 Oh, how interesting. 00:29:52.200 --> 00:29:52.600 Yeah. 00:29:52.600 --> 00:29:54.880 And this is a compile time and you can actually get this. 00:29:54.880 --> 00:29:55.360 Yeah, yeah. 00:29:55.360 --> 00:30:03.820 That's, I think that's the important thing because I was looking at that going, oh, I could just add the else statement and put the assert there and have nothing to do with mypy and it would catch that error. 00:30:03.820 --> 00:30:06.360 But that catches that error when that code runs. 00:30:06.360 --> 00:30:10.740 Like I said before, you know, hopefully there's tests, but oftentimes there's not tests for everything. 00:30:10.740 --> 00:30:11.240 Yeah. 00:30:11.240 --> 00:30:11.300 Yeah. 00:30:11.680 --> 00:30:16.040 And so especially there might not be a test for the new thing you've added. 00:30:16.240 --> 00:30:20.420 And so this is cool in that it checks all the possible types that could go in there. 00:30:20.420 --> 00:30:20.740 That's cool. 00:30:20.740 --> 00:30:21.180 Yeah. 00:30:21.180 --> 00:30:21.180 Yeah. 00:30:21.180 --> 00:30:21.620 Yeah. 00:30:21.620 --> 00:30:27.860 And the part that really got me was that it integrates with your IDE. 00:30:27.860 --> 00:30:37.780 So PyCharm, VS Code, or any editor that implements a language server can then like look at this and say, hey, you haven't handled all your cases. 00:30:37.780 --> 00:30:38.520 Right. 00:30:38.580 --> 00:30:45.660 And you get that immediate feedback rather than having to run your code and then find out, oh, dang it, I missed this case. 00:30:45.660 --> 00:30:46.600 Right. 00:30:46.600 --> 00:30:46.960 Yeah. 00:30:47.060 --> 00:30:52.400 So people who are not looking at the live stream YouTube stream, which is almost all the people listening. 00:30:52.400 --> 00:30:58.400 Nick is showing on the screen this assert function that's checking the numeration. 00:30:59.400 --> 00:31:05.760 And there's just a red squiggly line that literally says assert never has incompatible order status that's scheduled. 00:31:05.760 --> 00:31:08.080 That's the missed enumeration case. 00:31:08.080 --> 00:31:10.100 I think that's incredible that actually finds this. 00:31:10.100 --> 00:31:10.440 Yeah. 00:31:10.840 --> 00:31:18.400 And it works because mypy uses this technique called type narrowing. 00:31:18.400 --> 00:31:39.220 And essentially what that means is that it would, given a variable as it goes through like a control flow, like if statements, switch statements, my loop, mypy will like kind of confine or in other words, narrow down the types as it goes through those control flow. 00:31:39.220 --> 00:31:45.380 And so it works with enumeration types, unions, literals. 00:31:45.380 --> 00:31:57.340 So I have in the article, there are examples of how you could pass in a union of different types, strings, float, and you could still use this technique and to tell you, hey, you've missed a case. 00:31:57.340 --> 00:31:59.600 Or you could do this with literals. 00:31:59.600 --> 00:32:07.600 So you have like RGB and then you only implemented the, you only check for like two cases, which are R and G. 00:32:07.600 --> 00:32:11.840 And then to tell you, hey, you did not handle the B case. 00:32:11.840 --> 00:32:12.980 So yeah. 00:32:12.980 --> 00:32:18.440 And so like the article goes further into different ways in which you could set this up. 00:32:18.440 --> 00:32:23.960 Have mypy check all of the different cases for you, which is really cool. 00:32:23.960 --> 00:32:28.900 You've even got like the various sweets for cards, like clubs, diamonds, hearts. 00:32:29.000 --> 00:32:29.480 Yeah. 00:32:29.480 --> 00:32:45.080 It's interesting that like to mypy, when it sees an enum that has like clubs, diamonds, hearts, and spades, all it sees is like a union of literals, which are sweets, cards, sweet clubs, sweet hearts, which is actually interesting. 00:32:45.080 --> 00:32:46.220 That's how mypy sees it. 00:32:46.220 --> 00:32:46.700 Yeah. 00:32:46.700 --> 00:32:47.340 That's very interesting. 00:32:47.540 --> 00:32:49.160 I mean, basically it's emojis. 00:32:49.160 --> 00:32:49.760 Yeah. 00:32:49.760 --> 00:32:51.060 It's emojis. 00:32:51.060 --> 00:32:51.480 Right. 00:32:52.700 --> 00:33:00.820 The one other thing I wanted to mention here is that there was a specific, oh yeah. 00:33:00.820 --> 00:33:06.980 This feature is actually something that Guido actually thought was pretty cool. 00:33:07.160 --> 00:33:12.100 And so I think it's part of a PEP 622, a structural pattern matching already. 00:33:12.100 --> 00:33:27.920 So if you are matching against an enum or something that has like multiple different like states, the matching, hopefully Python 310 will give you a nice error saying, hey, you missed a particular case. 00:33:28.700 --> 00:33:45.200 And this could really, and if you're a Django developer or you just use Django or even, yeah, you just use any ORM and the ORM provides something like choices where like yes, no, or dollar, euro, like these kinds of choices in the field. 00:33:45.200 --> 00:33:46.700 This works pretty well. 00:33:46.700 --> 00:33:53.220 And so in your Django code, you could actually have mypy telling you, hey, you missed handling a particular case. 00:33:53.220 --> 00:33:54.220 Crazy. 00:33:54.220 --> 00:33:54.780 Yeah. 00:33:54.780 --> 00:33:55.320 That's awesome. 00:33:55.320 --> 00:33:55.780 Yeah. 00:33:55.780 --> 00:33:56.580 Which is really cool. 00:33:56.580 --> 00:33:57.080 Yeah. 00:33:57.220 --> 00:34:01.400 Sam out in the live stream was sort of on to the same thoughts you were talking about with Peter there. 00:34:01.400 --> 00:34:13.360 I wonder if one could hack on the match mechanism to deliver this functionality at runtime using by somehow getting all the variants of the enum and checking the branches, the AST or something. 00:34:13.360 --> 00:34:13.660 Yeah. 00:34:13.660 --> 00:34:24.260 That's interesting because I know that part of the structural pattern matching, like any object can implement the magic method match. 00:34:24.780 --> 00:34:28.960 And maybe that's like, yeah. 00:34:28.960 --> 00:34:31.580 And maybe that's your gate, like that's your entry point into providing that kind of checking at runtime. 00:34:31.580 --> 00:34:39.800 Of course, with Python, anything that is around runtime checking, there's like performance costs with that. 00:34:39.800 --> 00:34:40.580 So be careful. 00:34:40.580 --> 00:34:41.220 Yeah. 00:34:41.300 --> 00:34:44.520 But having this built into mypy already would be good. 00:34:44.520 --> 00:34:48.980 And Juergen is talking about it on the live stream. 00:34:48.980 --> 00:34:51.200 He says, I wonder whether you could rewrite the code 00:34:51.200 --> 00:34:52.960 to not use if statements at all, 00:34:52.960 --> 00:34:56.220 but be more polymorphic, which I agree. 00:34:56.220 --> 00:34:57.800 It's a really interesting idea 00:34:57.800 --> 00:35:00.020 with the method overloading and stuff. 00:35:00.020 --> 00:35:03.260 And it reminds me back a couple of weeks ago, 00:35:03.260 --> 00:35:05.020 Brian talked about function overloading 00:35:05.020 --> 00:35:06.940 with single dispatch and multiple dispatch. 00:35:06.940 --> 00:35:09.300 And yeah, you could kind of more or less 00:35:09.300 --> 00:35:10.460 make that happen there. 00:35:10.640 --> 00:35:11.340 So yeah, pretty neat. 00:35:11.340 --> 00:35:12.800 Although you still may miss a case. 00:35:12.800 --> 00:35:13.500 I'm not entirely sure. 00:35:13.500 --> 00:35:16.660 At least in the enumeration bit, that won't help you, right? 00:35:16.660 --> 00:35:18.360 Because the enum will still be the same type. 00:35:18.360 --> 00:35:20.100 It'll just have more values. 00:35:20.100 --> 00:35:20.620 Yeah. 00:35:20.620 --> 00:35:21.480 Awesome. 00:35:21.480 --> 00:35:22.240 Good one, Nick. 00:35:22.240 --> 00:35:23.260 Brian, what else we got? 00:35:23.260 --> 00:35:25.920 Well, I've got a couple of things. 00:35:25.920 --> 00:35:27.740 One of the things I wanted to note was that 00:35:27.740 --> 00:35:30.340 this is the second week in a row 00:35:30.340 --> 00:35:32.680 we've featured an article by Haki 00:35:32.680 --> 00:35:36.120 and the third in this year. 00:35:36.120 --> 00:35:38.740 So we should probably try to get him on the show or something. 00:35:38.740 --> 00:35:40.280 Yeah, absolutely. 00:35:40.460 --> 00:35:41.600 That sounds good. 00:35:41.600 --> 00:35:42.540 He's doing some good writing. 00:35:42.540 --> 00:35:43.020 So thanks. 00:35:43.020 --> 00:35:48.180 The other thing I wanted to mention is I've got... 00:35:48.180 --> 00:35:49.040 Oh, yeah. 00:35:49.040 --> 00:35:50.740 By the way, my book is out. 00:35:50.740 --> 00:35:52.060 Yay! 00:35:52.780 --> 00:35:54.040 This is the book, too. 00:35:54.040 --> 00:35:55.060 Yeah. 00:35:55.060 --> 00:35:57.700 Second edition of pytest is available for beta. 00:35:57.700 --> 00:36:00.500 So people can tell me everything that's... 00:36:00.500 --> 00:36:01.500 I already got it. 00:36:01.500 --> 00:36:03.640 Somebody said they have got an issue. 00:36:03.640 --> 00:36:06.860 It's a minor issue with it already. 00:36:06.860 --> 00:36:07.460 So thanks. 00:36:08.020 --> 00:36:11.440 But it's just been me and my editor so far working through it. 00:36:11.440 --> 00:36:16.920 So having more people, more eyes before we go to shipping the physical book would be great. 00:36:16.920 --> 00:36:19.840 So, of course, this is through Pragmatic. 00:36:19.840 --> 00:36:23.140 But if you go to pytestBook.com, it'll take you there. 00:36:23.400 --> 00:36:24.600 So that was my extra. 00:36:24.600 --> 00:36:25.340 Right on. 00:36:25.340 --> 00:36:25.760 Cool. 00:36:25.760 --> 00:36:26.920 I've got a couple as well. 00:36:26.920 --> 00:36:28.040 Yeah, I got some neat ones here. 00:36:28.040 --> 00:36:32.340 So how often do you maybe have like a blueprint floor plan? 00:36:32.340 --> 00:36:36.480 Maybe you're looking at a house and you're trying to decide whether you want to buy it. 00:36:36.480 --> 00:36:38.700 What would it be like to actually live there? 00:36:39.080 --> 00:36:43.320 Maybe you're trying to figure out, well, I'm planning out this apartment or I have this place. 00:36:43.320 --> 00:36:47.880 I want to remodel it like IKEA it all out or something along those lines. 00:36:47.880 --> 00:36:53.640 I ran across this thing that uses some interesting models called plan to scene. 00:36:53.640 --> 00:37:01.080 So the idea is it'll take what is literally a floor plan, like a blueprint floor plan that shows like swinging doors and bits. 00:37:01.080 --> 00:37:03.540 And then you tell it what kind of room it is. 00:37:03.540 --> 00:37:05.560 It's like a bedroom or a bathroom or whatever. 00:37:05.720 --> 00:37:16.140 And it will generate a 3D world that has things like sinks and toilets and couches that are three dimensional, not just somehow projected in there. 00:37:16.140 --> 00:37:19.280 So there's all of these interesting things you can see. 00:37:19.280 --> 00:37:21.720 If you pull up the site, there's all these like spinning worlds. 00:37:21.720 --> 00:37:27.700 And you can see that they've created these little environments just from floor plans, which I think is pretty insane. 00:37:27.700 --> 00:37:30.180 So anyway, you can go ahead, Nick. 00:37:30.180 --> 00:37:31.880 No, that's really cool. 00:37:32.400 --> 00:37:36.880 And I think I wonder if like, because like Trimble, we, we own like SketchUp. 00:37:36.880 --> 00:37:38.800 I wonder if they do this kind of stuff. 00:37:38.800 --> 00:37:42.900 They take floor plans and then they make it 3D. 00:37:42.900 --> 00:37:43.920 That's really cool. 00:37:43.920 --> 00:37:44.460 Yeah. 00:37:44.460 --> 00:37:53.760 There's a whole bunch of comparisons of how it used to be done, how you can pick like different, you know, different flooring and walls and source codes available on GitHub. 00:37:53.760 --> 00:37:54.700 People can run with that. 00:37:54.780 --> 00:37:55.720 So that's pretty cool. 00:37:55.720 --> 00:37:56.600 It's called Plan to Scene. 00:37:56.600 --> 00:38:02.380 And then just a quick shout out to this TCAS podcast I happen to be a guest of recently. 00:38:02.380 --> 00:38:09.280 And we got to talk about Python and data science and how Python and data are sort of changing the world and stuff. 00:38:09.280 --> 00:38:09.840 And it's really fun. 00:38:09.840 --> 00:38:11.040 So people can check that out. 00:38:11.040 --> 00:38:11.520 Yeah. 00:38:11.520 --> 00:38:12.680 And that's it for the things I got. 00:38:12.680 --> 00:38:14.240 Nick, anything else you want to throw out there? 00:38:14.440 --> 00:38:14.580 Yeah. 00:38:14.580 --> 00:38:16.720 Just a shameless plug. 00:38:16.720 --> 00:38:25.400 As I said earlier on the live stream, I co-host the Clipi, which is Cleveland's area Python meetup group. 00:38:26.100 --> 00:38:31.580 And so we have meetups every second Monday of the month. 00:38:31.580 --> 00:38:48.280 And one of the reasons why I would encourage anybody across the world or U.S. or everywhere to still come and present is because oftentimes meetups are a great place to present talks that you are planning on giving. 00:38:48.280 --> 00:38:56.120 And maybe like continental conferences or like other larger conferences, you know, smaller crowd. 00:38:56.120 --> 00:38:59.600 And, you know, we show you guys a good time. 00:38:59.600 --> 00:38:59.880 Right. 00:38:59.880 --> 00:39:06.300 So it's a great place to come, give your talk, get feedback from that, and then, you know, take and improve on it. 00:39:06.300 --> 00:39:07.400 So that's one. 00:39:07.920 --> 00:39:19.020 And then the other shameless plug is that Pye Ohio has its own conference coming up on July 31st. 00:39:19.020 --> 00:39:20.260 Registrations are open. 00:39:20.260 --> 00:39:21.800 We have pretty cool T-shirts. 00:39:21.800 --> 00:39:23.720 So, yeah, register. 00:39:23.720 --> 00:39:26.540 And that's a, is that live or streaming? 00:39:26.540 --> 00:39:29.000 Yes, that is being streamed. 00:39:29.000 --> 00:39:29.220 Okay. 00:39:29.220 --> 00:39:30.180 How about your meetups? 00:39:30.180 --> 00:39:32.380 Are those being, are those streamed or live? 00:39:32.380 --> 00:39:33.140 Those are virtual. 00:39:33.140 --> 00:39:35.720 We used to have them like in person. 00:39:35.720 --> 00:39:37.760 And that's, I really, that's when like. 00:39:37.760 --> 00:39:43.340 And then it really messed things up because you have stuff like pizza over and those have a good time talking about Python. 00:39:43.340 --> 00:39:48.480 But no, the virtual setting has given a lot more people access. 00:39:48.480 --> 00:39:51.180 You know, we're able to have more people on. 00:39:51.180 --> 00:39:51.500 So. 00:39:51.500 --> 00:39:52.180 Nice. 00:39:52.180 --> 00:39:53.520 Yeah, that's fantastic. 00:39:53.520 --> 00:39:59.880 And Pye Ohio is definitely one of those big regional conferences that a lot of people pay attention to, even if they're not in Ohio. 00:39:59.880 --> 00:40:00.380 Definitely. 00:40:00.380 --> 00:40:02.860 Are you going to go back to in-person only? 00:40:02.860 --> 00:40:09.860 Are you going to do like a hybrid stream and in-person or is it going to be, what's your plans for when the world returns to normal? 00:40:09.860 --> 00:40:11.720 That's if it ever returns to normal. 00:40:11.720 --> 00:40:13.500 I think we'll change forever. 00:40:14.580 --> 00:40:20.680 But to answer your question, I think my co-organizer and I have been thinking about them. 00:40:20.680 --> 00:40:22.380 We don't, we're not yet set yet. 00:40:22.380 --> 00:40:27.560 Like we see the benefits of the virtual, but we also see the benefits of the live. 00:40:27.560 --> 00:40:29.800 And there are things that have changed so much. 00:40:29.800 --> 00:40:32.560 We don't even know whether the live person is still available. 00:40:33.000 --> 00:40:34.900 But no, it's something we're thinking about. 00:40:34.900 --> 00:40:35.620 Yeah. 00:40:35.620 --> 00:40:36.140 Cool. 00:40:36.140 --> 00:40:37.420 Well, it's a challenge. 00:40:37.420 --> 00:40:44.140 I think all the meetups and other events are having, especially these smaller, like monthly, biweekly sort of things. 00:40:44.140 --> 00:40:44.360 Yeah. 00:40:44.360 --> 00:40:48.660 You know, it's one thing to say that there's going to be a big conference and we'll all go to it or not. 00:40:48.660 --> 00:40:52.960 But you're doing it every couple of weeks and it's mostly local, but not 100% local. 00:40:52.960 --> 00:40:53.860 Yeah, it's a challenge. 00:40:53.860 --> 00:40:54.340 Yeah. 00:40:54.340 --> 00:40:55.180 Fantastic. 00:40:55.180 --> 00:40:55.840 All right. 00:40:55.840 --> 00:40:57.400 Brian, you ready for a joke? 00:40:57.400 --> 00:40:58.200 Definitely. 00:40:58.740 --> 00:40:58.940 Okay. 00:40:58.940 --> 00:41:01.200 So I've got one and then Nick has one. 00:41:01.200 --> 00:41:04.860 So this one, the title of the joke is Root Beer Float. 00:41:04.860 --> 00:41:05.880 Okay. 00:41:05.880 --> 00:41:07.780 So a programmer walks into a bar. 00:41:07.780 --> 00:41:13.420 He orders 1.000000119 root beers. 00:41:13.420 --> 00:41:15.880 The bartender says, I'm going to have to charge you extra. 00:41:15.880 --> 00:41:17.220 That's a root beer float. 00:41:17.220 --> 00:41:20.280 The programmer says, well, in that case, make it a double. 00:41:20.280 --> 00:41:22.840 It's bad, right? 00:41:22.840 --> 00:41:24.080 That's bad. 00:41:24.080 --> 00:41:24.380 Yeah. 00:41:24.380 --> 00:41:25.140 All right. 00:41:25.140 --> 00:41:27.040 And Nick, you've got one as well. 00:41:27.040 --> 00:41:28.160 You want to do this one for us? 00:41:28.320 --> 00:41:28.720 Yeah. 00:41:28.720 --> 00:41:30.240 Would someone like to joke? 00:41:30.240 --> 00:41:32.840 You want me to be the bearded person? 00:41:32.840 --> 00:41:34.700 Yeah, I really have something going on there anyway. 00:41:34.700 --> 00:41:35.660 All right. 00:41:35.660 --> 00:41:39.400 So will refactoring the code improve the loading time? 00:41:39.400 --> 00:41:40.480 Not really. 00:41:40.480 --> 00:41:42.300 Will it improve the security then? 00:41:42.300 --> 00:41:42.920 No. 00:41:42.920 --> 00:41:45.040 So it's for browser compatibility? 00:41:45.040 --> 00:41:46.740 Yeah, no, not really. 00:41:46.740 --> 00:41:47.100 Nope. 00:41:47.100 --> 00:41:53.160 So tell me, why is it always the same old story with you guys wanting to refactor everything 00:41:53.160 --> 00:41:55.000 I need to know? 00:41:55.340 --> 00:42:01.160 Because as devs, if we know, excuse me, if we know we've left behind some messy code, 00:42:01.160 --> 00:42:02.500 we can't stop thinking about it. 00:42:02.500 --> 00:42:07.420 We wake up in the morning at lunchtime in the evening when we go home and when we're trying 00:42:07.420 --> 00:42:08.060 to go to sleep. 00:42:08.060 --> 00:42:09.280 It haunts us. 00:42:09.280 --> 00:42:11.460 You know, it haunts us. 00:42:11.460 --> 00:42:13.900 I love it. 00:42:14.360 --> 00:42:15.620 And it's true too. 00:42:15.620 --> 00:42:18.520 It's totally true. 00:42:18.520 --> 00:42:19.340 It's totally true. 00:42:19.340 --> 00:42:19.900 All right. 00:42:19.900 --> 00:42:21.580 I have one more joke for you guys. 00:42:21.580 --> 00:42:22.260 Oh yeah. 00:42:22.260 --> 00:42:22.700 Hit us. 00:42:22.700 --> 00:42:23.100 All right. 00:42:23.100 --> 00:42:25.000 How much does a chimney cost? 00:42:25.000 --> 00:42:26.460 No idea. 00:42:26.460 --> 00:42:27.140 Nothing. 00:42:27.140 --> 00:42:27.960 It's on the house. 00:42:27.960 --> 00:42:30.720 Very good. 00:42:31.640 --> 00:42:36.800 That's, I have a friend that is so, so into dad jokes, which is weird because it's only 00:42:36.800 --> 00:42:37.860 22. 00:42:37.860 --> 00:42:41.040 Practicing. 00:42:41.040 --> 00:42:42.380 Practicing for the future. 00:42:42.380 --> 00:42:43.640 Yeah. 00:42:43.640 --> 00:42:46.980 I don't think dads can be blamed for all bad jokes. 00:42:46.980 --> 00:42:48.940 Anyway. 00:42:50.240 --> 00:42:50.740 Yeah. 00:42:50.740 --> 00:42:55.760 I want to highlight, Juergen, says that they cost 2,500 euros. 00:42:55.760 --> 00:42:56.740 That's expensive. 00:42:56.740 --> 00:43:00.620 Well, thanks a lot for joining us today. 00:43:00.620 --> 00:43:05.860 this was a lot of fun and, thanks everybody in the stream for showing up and, we'll talk 00:43:05.860 --> 00:43:07.040 to everybody next week. 00:43:07.040 --> 00:43:07.520 Thanks. 00:43:07.520 --> 00:43:08.020 Bye everyone.