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.

