WEBVTT

00:00:00.001 --> 00:00:05.100
Hello and welcome to Python Bytes, where we deliver Python news and headlines directly to your earbuds.

00:00:05.100 --> 00:00:09.720
This is episode 136, recorded June 19, 2019.

00:00:09.720 --> 00:00:10.640
I'm Michael Kennedy.

00:00:10.640 --> 00:00:11.400
And I'm Brian Okken.

00:00:11.400 --> 00:00:13.220
And this episode is brought to you by Datadog.

00:00:13.220 --> 00:00:15.700
Check them out at pythonbytes.fm/datadog.

00:00:15.700 --> 00:00:16.500
Get a cool shirt.

00:00:16.500 --> 00:00:17.380
More on that later.

00:00:17.380 --> 00:00:18.100
Brian, how you been?

00:00:18.100 --> 00:00:19.480
I am doing well.

00:00:19.480 --> 00:00:20.060
Good, good.

00:00:20.060 --> 00:00:21.000
Same here.

00:00:21.000 --> 00:00:22.420
Rolling into summer.

00:00:22.420 --> 00:00:23.420
Kids are home.

00:00:23.420 --> 00:00:26.280
Working from home is now chaos, but it's all right.

00:00:26.280 --> 00:00:26.680
Yeah.

00:00:26.680 --> 00:00:28.360
It's a little cooler today, too.

00:00:28.360 --> 00:00:28.760
It's nice.

00:00:28.760 --> 00:00:29.460
Yeah, it's beautiful.

00:00:30.040 --> 00:00:33.060
So you've got some kind of magic trick lined up for us for this first thing?

00:00:33.060 --> 00:00:33.900
What's going on here?

00:00:33.900 --> 00:00:39.220
Well, actually, I think it's just going to be me trying to pronounce a French word.

00:00:39.220 --> 00:00:42.640
So I think, is it, I know it's not voila.

00:00:42.640 --> 00:00:43.680
Voila?

00:00:43.680 --> 00:00:44.400
Voila?

00:00:44.400 --> 00:00:45.600
Do you pronounce the V?

00:00:45.600 --> 00:00:46.100
I don't know.

00:00:46.100 --> 00:00:46.400
Voila.

00:00:46.400 --> 00:00:47.380
I think so.

00:00:47.380 --> 00:00:47.680
Voila?

00:00:47.680 --> 00:00:48.320
Viola.

00:00:48.320 --> 00:00:48.780
No.

00:00:48.780 --> 00:00:49.780
No.

00:00:49.780 --> 00:00:53.060
Voila is a new project.

00:00:53.060 --> 00:00:56.760
It's a newly announced project from the Jupyter Notebook people.

00:00:56.760 --> 00:00:57.100
Cool.

00:00:57.100 --> 00:01:01.960
So the idea is Jupyter Notebooks in standalone applications or dashboards.

00:01:01.960 --> 00:01:16.500
So people that are used to working with notebooks and they want to share what they found with other people and you want to have people be able to interact with it and have it be a little bit interactive, but not allow people to change your code.

00:01:16.700 --> 00:01:17.720
How do you do that?

00:01:17.720 --> 00:01:20.160
That's where Voila steps in.

00:01:20.160 --> 00:01:22.120
It's a pretty cool project.

00:01:22.120 --> 00:01:24.320
I was playing around with it a little bit.

00:01:24.320 --> 00:01:32.180
You can have custom, or at least reading about it, custom widgets to set up your page and even like templates and grid layouts.

00:01:32.180 --> 00:01:33.800
But you don't have to be a web developer.

00:01:33.800 --> 00:01:35.140
It's like drag and drop stuff.

00:01:35.140 --> 00:01:35.580
This is cool.

00:01:35.580 --> 00:01:48.880
I like the idea of presenting the interactive plots and graphs and stuff and also being able to have people be able to run the code and do selectors and things, but not let people change the code.

00:01:48.880 --> 00:01:50.040
So that's pretty cool.

00:01:50.040 --> 00:01:50.280
Yeah.

00:01:50.280 --> 00:01:53.440
You just take your notebook and you just turn it into a web application.

00:01:53.440 --> 00:01:54.440
That's pretty awesome.

00:01:54.440 --> 00:02:01.860
And it has nice restrictions like does not permit execution of arbitrary code by consumers of the dashboard.

00:02:01.860 --> 00:02:03.140
It's language agnostic.

00:02:03.140 --> 00:02:07.960
So you could have C++ code up there in addition to Python or whatever, you know, Jupyter does.

00:02:07.960 --> 00:02:08.600
That's pretty sweet.

00:02:08.600 --> 00:02:08.840
Yeah.

00:02:08.840 --> 00:02:14.140
I could see a lot of people using this, even for dashboards for like peeking into databases and stuff.

00:02:14.140 --> 00:02:14.460
Nice.

00:02:14.460 --> 00:02:16.420
So Voila, and you have a website.

00:02:16.420 --> 00:02:16.820
Voila.

00:02:16.820 --> 00:02:20.680
I have a Jupyter notebook and here it is.

00:02:20.680 --> 00:02:20.900
Cool.

00:02:20.900 --> 00:02:21.720
Awesome.

00:02:22.720 --> 00:02:24.840
I don't think we covered this.

00:02:24.840 --> 00:02:38.960
I kind of tried to sort of intentionally didn't want to go too far into it because it didn't seem super productive, but there was a presentation back at the language summit called Python, something like cleaning up Python's dead batteries or something to that effect.

00:02:38.960 --> 00:02:39.960
Did you catch that?

00:02:39.960 --> 00:02:40.180
Yeah.

00:02:40.180 --> 00:02:45.520
So the idea was there are some modules and parts of Python that are outdated.

00:02:46.100 --> 00:02:53.780
Their existence puts pressure on the core developers in ways that doesn't let them focus on what they need to be doing.

00:02:53.780 --> 00:02:56.520
It also makes it super hard for people to contribute.

00:02:56.520 --> 00:03:01.460
Like, for example, there's a color sys module in Python in the standard library.

00:03:01.460 --> 00:03:04.260
I'm going to pick on this thing a lot during this little segment.

00:03:04.260 --> 00:03:11.480
And it has the very important purpose of converting CSS colors between coordinate systems.

00:03:12.320 --> 00:03:15.820
Super important to have that in the standard library, right?

00:03:15.820 --> 00:03:17.040
I don't know.

00:03:17.040 --> 00:03:18.700
Maybe, maybe not.

00:03:18.700 --> 00:03:30.380
At one point, you know, Python standard library was really the goal of it was to come with everything you need because installing extra stuff like downloading it, getting it, like running the setup and all that was really tricky.

00:03:30.380 --> 00:03:31.240
Right?

00:03:31.300 --> 00:03:33.960
Now everything's pip install one away.

00:03:33.960 --> 00:03:36.580
So, like, it looks a little bit weird.

00:03:36.580 --> 00:03:43.080
And if, say, you wanted to fix or change the color sys module, it's not the same as if you want to go contribute to some random thing on GitHub.

00:03:43.080 --> 00:03:44.620
No, you've got to be a core developer.

00:03:44.620 --> 00:03:47.220
There's a lot of steps that go through this.

00:03:47.220 --> 00:03:53.140
It only ships every 16 months, or sorry, 18 months for new content and new things, changes.

00:03:53.780 --> 00:03:57.760
So, how much do you really care to make a contribution or change to color sys?

00:03:57.760 --> 00:03:58.180
Right?

00:03:58.180 --> 00:04:00.600
Probably not very much for all those reasons, right?

00:04:00.600 --> 00:04:01.620
It's slow on purpose.

00:04:01.620 --> 00:04:04.760
It's hard to make changes to and so on.

00:04:04.760 --> 00:04:10.300
But the problem is, like, it has things like color sys that probably don't make a lot of sense to be there anymore.

00:04:10.300 --> 00:04:17.920
So, Amber Brown and some other folks were making a case that maybe we should take some stuff away.

00:04:17.920 --> 00:04:19.180
And it was pretty controversial.

00:04:19.180 --> 00:04:23.340
There was some, like, heated disagreements at the actual presentation and stuff.

00:04:23.340 --> 00:04:24.440
And I don't care about that.

00:04:24.440 --> 00:04:25.180
I don't want to go into it.

00:04:25.180 --> 00:04:30.900
But that approach was, we have stuff in Python that maybe shouldn't be there.

00:04:30.900 --> 00:04:33.240
Let's talk about what we can take out.

00:04:33.240 --> 00:04:39.700
And Glyph wrote a cool article called Toward a Kernel Python.

00:04:40.040 --> 00:04:41.660
And I've talked about this before.

00:04:41.660 --> 00:04:44.680
I don't know if I talked about it on Python Bytes or on Talk Python.

00:04:44.680 --> 00:04:55.420
But I think there should be some kind of subset of Python that is defined to be, like, the minimum subset of Python that is guaranteed to be everywhere.

00:04:55.420 --> 00:05:01.740
So, for example, if you work with PyPy, you get one variant of mostly Python.

00:05:01.740 --> 00:05:07.860
If you work with CircuitPython or MicroPython, you get another variant of mostly Python, but not all of it, right?

00:05:07.860 --> 00:05:08.140
Yeah.

00:05:08.220 --> 00:05:16.860
If you work with Python or some of the JavaScript versions that run in the browsers, again, similar subset but not the same.

00:05:17.180 --> 00:05:31.840
So, if we had, like, a smaller sort of essential Python standard language definition and library that was, like, I don't know what's the right number, but a smaller amount that you could guarantee was identical across all those platforms.

00:05:32.220 --> 00:05:34.540
And then opt in to bringing the other stuff in.

00:05:34.540 --> 00:05:44.220
So, Glyph's main idea was, like, could we say, instead of, like, take what we have and hack away a few things that don't make sense, rather trim it down to this kernel, to this essence.

00:05:45.180 --> 00:05:51.260
And then, I don't know, pip install the rest of the libraries or something like that, the rest of the standard library.

00:05:51.260 --> 00:05:53.740
You want the networking stack, you pip install networking.

00:05:53.740 --> 00:05:54.160
I don't know.

00:05:54.160 --> 00:05:56.680
Like, I'm just making up parts that we would do that for.

00:05:57.500 --> 00:06:05.200
But that was his idea, that basically there's a PEP, PEP594, that's about removing, obviously, obsolete and dead stuff from the standard library.

00:06:05.200 --> 00:06:06.900
And that's all well and good.

00:06:07.240 --> 00:06:16.880
But it actually turns out that having things like ColorSys in the standard library mean that the core devs have to deal with a bunch of stuff.

00:06:16.880 --> 00:06:18.460
So, he runs Twisted.

00:06:18.460 --> 00:06:21.440
So, he talks about, like, how is Twisted doing on keeping up with PRs?

00:06:21.440 --> 00:06:23.700
And let's look at CPython over there.

00:06:23.700 --> 00:06:29.020
And they have 429 tickets currently awaiting review over on GitHub.

00:06:29.020 --> 00:06:30.200
I think it's in GitHub.

00:06:30.860 --> 00:06:36.820
It says the oldest PR awaiting review hasn't been touched since February 2nd, 2018.

00:06:36.820 --> 00:06:38.980
It's almost 500 days old.

00:06:38.980 --> 00:06:46.280
But when you look at it, the PRs, there's 25 PRs that are out on address or whatever.

00:06:46.280 --> 00:06:49.900
14 were about the standard library and 10 were about CPython.

00:06:49.900 --> 00:06:54.920
So, why are the core devs having to deal with this stuff when there's typically a replacement?

00:06:54.920 --> 00:06:59.920
Like, there is a built-in HTTP library, but people just use requests or AIOHTP or whatever, right?

00:07:00.320 --> 00:07:05.920
Like, there should be a way to maybe create this essence of it and then bring more in.

00:07:05.920 --> 00:07:06.620
What do you think?

00:07:06.620 --> 00:07:08.700
I definitely think there's an idea there.

00:07:08.700 --> 00:07:12.040
Like you said, there's kind of like a Venn diagram.

00:07:12.040 --> 00:07:17.900
There's a common set that most people need or you'll need for lots of different domains.

00:07:17.900 --> 00:07:28.360
But then for a web domain, for web stuff, you're going to need different stuff than for, like, working with audio files or working with text files.

00:07:28.560 --> 00:07:33.640
Or the different problem domains are going to use different bits and you don't need everything else.

00:07:33.640 --> 00:07:33.920
Yeah.

00:07:33.920 --> 00:07:34.840
Interesting idea.

00:07:34.840 --> 00:07:42.680
The install, the how do beginners install stuff is an interesting, how do you deal with that, though?

00:07:42.680 --> 00:07:43.520
Yeah, absolutely.

00:07:43.520 --> 00:07:44.700
And he does address that.

00:07:44.700 --> 00:07:46.660
And I do think it is a challenge.

00:07:47.020 --> 00:07:57.400
He says, look, probably the stuff you go get when you download off python.org or you brew install Python, that probably should just be everything, right?

00:07:57.400 --> 00:08:04.380
But it doesn't mean that it can't be comprised of smaller things that potentially ship on a different schedule.

00:08:04.380 --> 00:08:11.240
If you're going to install, like, Visual Studio or something like that, you always have options of, do you want to install this stuff and this other stuff also?

00:08:11.240 --> 00:08:11.580
Yeah.

00:08:11.580 --> 00:08:12.600
You can opt out.

00:08:12.600 --> 00:08:18.080
And we could do something similar to that with Python of, like, do you want to install the web stuff?

00:08:18.080 --> 00:08:21.060
Do you want to install the audio stuff and whatever?

00:08:21.060 --> 00:08:21.460
Right.

00:08:21.700 --> 00:08:24.740
You could have these full distributions that you install.

00:08:24.740 --> 00:08:33.600
But if you look at, say, Linux, for example, if you go to an empty Ubuntu machine and you try to create a virtual environment, depending on the version you have, it may not work.

00:08:33.600 --> 00:08:39.640
You may get an error that says, you need to apt install Python 3-venv.

00:08:39.640 --> 00:08:42.160
It's like, wait, that part of Python wasn't shipped?

00:08:42.160 --> 00:08:43.220
Okay, well, we'll do that.

00:08:43.220 --> 00:08:49.520
Or if you try to even pip install something, it might say, you might have to apt install Python 3-pip, right?

00:08:49.520 --> 00:08:51.280
So they've already done this on Linux.

00:08:51.280 --> 00:08:53.380
There's other examples as well.

00:08:53.380 --> 00:08:59.640
For example, the .NET Core in the Microsoft space basically is like this, right?

00:08:59.640 --> 00:09:06.560
Like, you use their package management system to bring in, like, significant parts of what is their standard library.

00:09:06.560 --> 00:09:06.960
Yeah.

00:09:06.960 --> 00:09:08.480
I do think it's a problem for beginners.

00:09:08.480 --> 00:09:10.300
I think it makes it harder, right?

00:09:10.300 --> 00:09:14.620
It's like saying, well, we just run JavaScript over in Node and it's easy.

00:09:14.620 --> 00:09:17.720
But then you see all this require.js and all these, like, patterns.

00:09:17.720 --> 00:09:19.100
You're like, why is this so hard?

00:09:19.100 --> 00:09:20.680
What happened to print hello world?

00:09:20.680 --> 00:09:22.820
You know, like, I do think there's a danger.

00:09:22.820 --> 00:09:34.560
But if the standard way that people get Python is they get this big bundle, but maybe those bundles are not all maintained by the same team, which is the core developers, right?

00:09:34.620 --> 00:09:50.180
And then, like, what can we hack out of the system?

00:09:50.180 --> 00:09:52.040
Could we hack out ColorSys?

00:09:52.040 --> 00:09:52.780
Yes or no?

00:09:52.780 --> 00:09:53.540
Let's talk about that.

00:09:53.640 --> 00:09:53.900
Well, right.

00:09:53.900 --> 00:09:58.500
And also, just there's some stuff, like ColorSys, it's surprising that it needs to be there.

00:09:58.500 --> 00:10:03.900
And then there's stuff that's not in the core or in the standard library that, like, why is that not there?

00:10:03.900 --> 00:10:05.580
Like, set up tools and wheel.

00:10:05.580 --> 00:10:09.220
I'm always surprised that I have to pip install wheel to create a wheel.

00:10:09.320 --> 00:10:14.560
Yeah, and speaking of pip, Cliff did mention that when you get Python, it comes with pip.

00:10:14.560 --> 00:10:17.560
Like, installing Python lets you type pip install a thing.

00:10:17.560 --> 00:10:22.300
But pip is actually maintained by a different group and shipped on a different cycle, right?

00:10:22.300 --> 00:10:25.060
That's PyPA, not the core developers, for example.

00:10:25.180 --> 00:10:26.680
So, it's like that a little bit.

00:10:26.680 --> 00:10:29.540
But if it was more like that, you could make a change.

00:10:29.540 --> 00:10:40.120
You could join the team for, I don't know, the networking or ColorSys or whatever you want, work on that, and maybe push changes more rapidly than the core CPython runtime.

00:10:40.120 --> 00:10:40.640
Right.

00:10:40.640 --> 00:10:46.200
We could do something like the PyPA, but do, like, the Python standard library authority or something like that.

00:10:46.200 --> 00:10:46.800
Yeah, exactly.

00:10:46.800 --> 00:10:54.980
It's a pretty interesting idea, and it definitely seems better than, seems more like the outcome will be better than trying to just hack away at a few dead batteries.

00:10:54.980 --> 00:10:55.600
If you will.

00:10:55.600 --> 00:10:55.860
Yep.

00:10:55.860 --> 00:10:56.060
Cool.

00:10:56.060 --> 00:11:00.120
This next one that you're talking about, I recently ran into this as an error.

00:11:00.120 --> 00:11:01.420
I'm like, wait, what did I type wrong?

00:11:01.420 --> 00:11:03.860
And then I realized, this might be a cool feature.

00:11:03.860 --> 00:11:05.100
Why don't you tell people about this?

00:11:05.100 --> 00:11:09.680
Like, for instance, with pytest, it comes as a standalone script.

00:11:09.680 --> 00:11:12.520
You can say, you can just write pytest on the command line.

00:11:12.520 --> 00:11:16.140
But you can also say Python-M pytest.

00:11:16.140 --> 00:11:19.100
And a lot of pip installable things, you can do that.

00:11:19.100 --> 00:11:23.400
You can say –M, the thing name, and it works.

00:11:23.740 --> 00:11:25.680
I didn't know how to do this, actually.

00:11:25.680 --> 00:11:28.560
I never really thought, how do I do this, and how do I figure it out?

00:11:28.560 --> 00:11:32.920
And all it is to put a Dunder main file in your project.

00:11:32.920 --> 00:11:34.620
I didn't know it was that easy.

00:11:34.620 --> 00:11:44.220
So I'm linking to an article that pretty much says, we use the convention of if Dunder name equals Dunder main, then run the main program or something.

00:11:44.480 --> 00:11:49.460
But you can use the Dunder main.py file itself in your project.

00:11:49.460 --> 00:11:52.300
And that dash M thing just works.

00:11:52.300 --> 00:11:53.400
And that's pretty simple, right?

00:11:53.400 --> 00:11:55.140
I'm like, it can't really be that easy.

00:11:55.140 --> 00:11:59.660
So this morning, I did a little flip project, a flip-based project.

00:11:59.660 --> 00:12:06.440
And then threw a Dunder main in there with just a print statement and installed it and went somewhere else.

00:12:06.440 --> 00:12:08.540
And sure enough, it works just awesome.

00:12:08.540 --> 00:12:09.440
So neat.

00:12:09.440 --> 00:12:10.240
Yeah, that's super cool.

00:12:10.240 --> 00:12:17.780
Yeah, I ran across this by accidentally saying Python and saying run a directory instead of a file.

00:12:18.260 --> 00:12:21.100
I'm like, oh, it said it couldn't find Dunder main.

00:12:21.100 --> 00:12:22.240
I'm like, .py.

00:12:22.240 --> 00:12:24.820
I'm like, wait, it was looking for it?

00:12:24.820 --> 00:12:25.480
That's pretty cool.

00:12:25.480 --> 00:12:26.600
Maybe there's something to be done here.

00:12:26.600 --> 00:12:27.060
Yeah, that's great.

00:12:27.060 --> 00:12:27.860
I'm glad you pointed it out.

00:12:27.860 --> 00:12:33.840
If you have a Dunder main in there, you can just say Python and the directory name and it works?

00:12:33.840 --> 00:12:39.220
I have not verified that, but it seems like the error message would indicate that it might work.

00:12:39.220 --> 00:12:40.480
Yeah, I mean, it was like a full path.

00:12:40.480 --> 00:12:42.660
It wasn't just a standard directory either.

00:12:42.660 --> 00:12:43.260
Okay.

00:12:43.260 --> 00:12:44.600
Yeah, so pretty cool.

00:12:44.600 --> 00:12:44.880
Neat.

00:12:44.880 --> 00:12:46.540
I don't know how useful it is to people,

00:12:46.720 --> 00:12:48.920
but I'll run across it every once in a while.

00:12:48.920 --> 00:12:51.000
Yeah, that and entry points always really nice.

00:12:51.000 --> 00:12:55.040
Now, speaking of nice, Diddy Dog is supporting our show and they got some nice products.

00:12:55.040 --> 00:12:56.620
So let me tell you about them really quickly.

00:12:56.620 --> 00:13:03.740
And so they're a cloud scale monitoring platform that unifies metrics, logs, traces, all that kind of stuff.

00:13:03.740 --> 00:13:06.720
Monitors your Python apps in real time.

00:13:06.720 --> 00:13:13.860
Helps you find bottlenecks with detailed flame graphs, trace requests as they cross over service boundaries.

00:13:13.860 --> 00:13:14.600
All right.

00:13:14.600 --> 00:13:17.960
So if you have microservices, you're talking to database or queuing, things like that.

00:13:17.960 --> 00:13:25.280
Plus, it also does automatic instrumentation for popular frameworks like Django, AsyncIO, and Flask.

00:13:25.280 --> 00:13:27.540
So you can quickly get started without too much setup.

00:13:27.540 --> 00:13:29.600
So get started today.

00:13:29.600 --> 00:13:33.340
There's a 14-day free trial at pythonbytes.fm/datadog.

00:13:33.440 --> 00:13:36.180
And you get a cool Datadog t-shirt, which is always fun.

00:13:36.180 --> 00:13:37.060
Thanks for that, Dom.

00:13:37.060 --> 00:13:38.620
Mine's a nice purple color.

00:13:38.620 --> 00:13:40.560
And my kids always comment when I wear it.

00:13:40.560 --> 00:13:41.600
They like the shirt.

00:13:41.600 --> 00:13:42.140
Yeah, I love it.

00:13:42.140 --> 00:13:47.460
So this next one I want to talk about, the name might sound a little derogatory, but it's not really meant that way.

00:13:47.460 --> 00:13:50.240
So maybe simplistic sounds better.

00:13:50.340 --> 00:13:56.420
But the thing I want to talk about is this article by Chris Wellens entitled, The CPython Byte Compiler is Dumb.

00:13:56.420 --> 00:13:59.200
Simplistic is maybe better.

00:13:59.200 --> 00:14:11.140
But what you might not know, depending on how much you dig into it, is there's excruciatingly small amounts of optimization when CPython runs your code.

00:14:11.220 --> 00:14:14.120
So there's a compilation step, actually, right?

00:14:14.120 --> 00:14:16.480
The bytecode and compiler talks about some kind of compilation.

00:14:16.480 --> 00:14:20.860
So when you run your code, you probably see the __pycache__ folders.

00:14:20.860 --> 00:14:22.460
And in there you have the PYC files.

00:14:22.460 --> 00:14:25.760
So that's taking your source code, turn it into bytecode, and put it there.

00:14:25.760 --> 00:14:37.080
But then instead of, say, compiling that onto machine instructions, the interpreter takes that, feeds it through this ginormous switch statement that's like 3,000 lines long in the CPython runtime.

00:14:37.080 --> 00:14:39.620
And it just goes, well, what case is this?

00:14:39.620 --> 00:14:40.800
We're jumping to that, right?

00:14:40.800 --> 00:14:41.600
It's pretty wild.

00:14:41.600 --> 00:14:43.060
There's a file called cval.c.

00:14:43.060 --> 00:14:43.680
Check it out.

00:14:43.680 --> 00:14:48.060
However, there's very little optimization that happens here.

00:14:48.060 --> 00:14:53.300
So Chris decided to compare this against Lua and one other similar, maybe Ruby.

00:14:53.300 --> 00:14:55.820
I can't remember what the other one that he compared it against was.

00:14:55.820 --> 00:15:00.200
But he talked about, you know, like, if I write this code, what happens to it?

00:15:00.200 --> 00:15:07.360
So there are optimizations like what are called peephole optimizations and a few memory allocation optimizations in CPython.

00:15:07.360 --> 00:15:09.640
But they're pretty limited.

00:15:10.380 --> 00:15:16.440
So if you look at some examples, like let's take an example where we have a function.

00:15:16.440 --> 00:15:17.340
It's called foo.

00:15:17.340 --> 00:15:18.780
Defines two variables.

00:15:18.780 --> 00:15:19.840
X equals zero.

00:15:19.840 --> 00:15:21.180
Y equals one.

00:15:21.180 --> 00:15:22.480
Return X.

00:15:22.480 --> 00:15:23.720
That seems simple, right, Brian?

00:15:23.720 --> 00:15:24.040
Yeah.

00:15:24.040 --> 00:15:25.440
Except for Y is not needed.

00:15:25.440 --> 00:15:26.180
But yeah, sure.

00:15:26.300 --> 00:15:26.620
Exactly.

00:15:26.620 --> 00:15:38.640
So when you see that, if Y is unused and this is not making any change, it's just literally creating a variable which is effectively an entry in, you know, like a module name lookup or a locals lookup, right?

00:15:38.700 --> 00:15:40.500
Like, why does that need to be done?

00:15:41.440 --> 00:15:43.060
Doesn't seem like a whole lot's happening.

00:15:43.060 --> 00:15:47.860
So for example, the CPython bytecode compiler could just go, well, forget that line.

00:15:48.000 --> 00:15:51.220
And it could say, well, X never changes its value.

00:15:51.220 --> 00:15:58.680
So why don't we just inline that to say, basically, the whole function is return zero, right?

00:15:58.680 --> 00:16:00.300
Inline the X, drop the Y.

00:16:00.300 --> 00:16:01.260
It's good to go.

00:16:01.660 --> 00:16:07.160
But if you go and throw that into the disassembler, you'll see that, no, that's not what happens.

00:16:07.160 --> 00:16:10.260
It literally just takes it step by step by step.

00:16:10.260 --> 00:16:10.540
Okay.

00:16:10.540 --> 00:16:11.100
Wild, right?

00:16:11.100 --> 00:16:12.500
So it loads the constant.

00:16:12.500 --> 00:16:14.200
It stores it into a field called X.

00:16:14.200 --> 00:16:15.100
It loads the constant.

00:16:15.100 --> 00:16:16.740
It stores into a field called Y.

00:16:16.740 --> 00:16:20.000
Then it loads the constant again, the value for X again.

00:16:20.000 --> 00:16:23.480
And then it calls return val as the bytecode instructions, right?

00:16:23.480 --> 00:16:26.860
Instead of just load constant zero, return value, right?

00:16:26.860 --> 00:16:28.060
Like, it could be a lot quicker.

00:16:28.680 --> 00:16:32.540
So I find that this is, it's honestly a little bit surprising.

00:16:32.540 --> 00:16:37.260
I mean, Python is 25 years old and it doesn't take steps like this.

00:16:37.260 --> 00:16:44.440
Now, Darius Beacon did point out that Guido himself said Python is about having the simplest,

00:16:44.440 --> 00:16:46.340
dumbest compiler imaginable.

00:16:46.340 --> 00:16:47.800
And there's some links to that.

00:16:47.800 --> 00:16:50.020
So some references there if you want to go check that out.

00:16:50.020 --> 00:16:53.960
So I think, you know, maybe it's by design to keep it simple.

00:16:53.960 --> 00:16:56.040
It's easy for people to contribute to.

00:16:56.340 --> 00:17:04.440
But it certainly seems like there could be a layer, like, between parsing the bytecode and executing the bytecode that says,

00:17:04.440 --> 00:17:07.480
we're not running into debugger or something like that.

00:17:07.480 --> 00:17:12.260
So let's go crazy and, like, just, you know, convert stuff like that to return zero.

00:17:12.260 --> 00:17:15.300
There's also a bunch of other interesting examples in there.

00:17:15.300 --> 00:17:18.620
This is just one that's really obvious that's good for talking that I pulled out.

00:17:18.680 --> 00:17:24.460
And optimization levels is something that CS people have been doing with compilers for a long time.

00:17:24.460 --> 00:17:26.980
So it's not like we'd have to invent it ourselves.

00:17:26.980 --> 00:17:27.480
Right.

00:17:27.480 --> 00:17:28.920
Yeah, yeah.

00:17:28.920 --> 00:17:30.160
C has had plenty of it.

00:17:30.160 --> 00:17:35.180
C#, the JIT compiled languages, their JIT compiler is a place where a lot of that happens.

00:17:35.180 --> 00:17:36.220
Things like this, right?

00:17:36.220 --> 00:17:39.500
Did you say that there was a comparison to other languages?

00:17:39.500 --> 00:17:42.280
Do other languages do more optimization?

00:17:42.600 --> 00:17:43.240
No, not really.

00:17:43.240 --> 00:17:46.560
They're all pretty much the same.

00:17:46.560 --> 00:17:49.540
For better or worse, they're all the same.

00:17:49.540 --> 00:17:53.020
So there's an interesting point that he makes that I do want to, like, just comment on real quick.

00:17:53.020 --> 00:18:00.040
It says, so the consensus seems to be that if you want or need better performance, don't use Python.

00:18:00.040 --> 00:18:01.980
Go use another language.

00:18:02.100 --> 00:18:04.480
I'm like, dude, no, you were, like, so close.

00:18:04.480 --> 00:18:05.860
You were so close as well.

00:18:05.860 --> 00:18:08.840
You could use, maybe don't use CPython, right?

00:18:08.840 --> 00:18:10.700
Maybe use PyPy, P-Y-P-Y.

00:18:10.700 --> 00:18:17.280
But the most obvious optimization to me that just can change the game is Cython.

00:18:17.280 --> 00:18:17.740
Yeah.

00:18:17.740 --> 00:18:24.920
You could write, like, one or two slow functions in Cython, and boom, it goes to machine instructions, and it's, you know, it nears the speed of C.

00:18:24.920 --> 00:18:26.720
So I like the article.

00:18:26.720 --> 00:18:30.180
I don't like that it says, oh, if things are a little bit slow, just run away.

00:18:30.180 --> 00:18:33.940
Like, no, there's probably a package that has a C extension that already works better.

00:18:33.940 --> 00:18:37.560
Or, you know, there's a data structure you should be using that would be better.

00:18:37.560 --> 00:18:40.200
Or there's Cython or, you know, on and on.

00:18:40.200 --> 00:18:43.200
There's a lot of improvements before Python's not the answer.

00:18:43.200 --> 00:18:47.360
Or be aware that this is doing this and do your own optimization.

00:18:47.360 --> 00:18:53.180
And for the most part, use a profiler and really tell where the optimization needs to be.

00:18:53.180 --> 00:18:53.560
Exactly.

00:18:53.560 --> 00:18:58.820
Like, only 10% of your code needs to be fast at all, if that much, most of the time, right?

00:18:58.820 --> 00:19:03.140
It's usually, like, one little bit, like, oh, if this were faster, it would change the game.

00:19:03.140 --> 00:19:03.460
Yeah.

00:19:03.460 --> 00:19:08.040
I mean, I learned assembly in college, and I'm glad I've never had to use it.

00:19:08.040 --> 00:19:10.320
For sure.

00:19:11.060 --> 00:19:13.180
So, final comment here.

00:19:13.180 --> 00:19:19.040
Brett Cannon, when I interviewed him recently, you know, he's on the steering council, core developer, and so on.

00:19:19.040 --> 00:19:24.800
He did talk about, you know, how would adoption of Python 3 change?

00:19:24.800 --> 00:19:30.560
How would adoption of Python in general change if we could make Python two or four times faster than it is today?

00:19:31.300 --> 00:19:32.600
Like, most of the time, it doesn't matter.

00:19:32.600 --> 00:19:37.200
But if it could be faster in some interesting ways, what would that mean, right?

00:19:37.200 --> 00:19:45.220
In terms of upgrading more quickly to the new versions and just general, like, people not saying, oh, I have to use Go because I need AsyncIO or something like this.

00:19:45.620 --> 00:20:00.440
So, it seems like if the compiler is this absent, if optimizations are this absent from the compiler, like, there's some low-hanging fruit to, like, do some simple CS compiler optimizations and make stuff faster, right?

00:20:00.440 --> 00:20:05.320
I mean, you could make this silly foo method, like, probably three times as fast, right?

00:20:05.320 --> 00:20:07.620
Because you could drop most of the bytecode operations.

00:20:07.620 --> 00:20:08.840
Yeah, definitely.

00:20:09.280 --> 00:20:10.280
It's worth looking at.

00:20:10.280 --> 00:20:14.900
It's interesting that there is some people thinking about performance.

00:20:14.900 --> 00:20:15.320
Yeah.

00:20:15.320 --> 00:20:22.620
I mean, we had that conversation around the idea of Rust and maybe what if we used Rust instead of C in certain situations.

00:20:22.620 --> 00:20:25.460
But, like, this seems like low-hanging fruit already right here.

00:20:25.460 --> 00:20:32.420
And regardless of whether it lands in Rust or C, when it's executed, not executing code is a lot faster than executing it.

00:20:32.420 --> 00:20:32.620
Yeah.

00:20:32.620 --> 00:20:32.840
Cool.

00:20:32.840 --> 00:20:33.380
What's the next one?

00:20:33.380 --> 00:20:37.980
EdgeDB is something that came up on my radar a couple years ago.

00:20:38.200 --> 00:20:48.240
I saw the EdgeDB people had a booth at one of the PyCons, and they were talking about it, but at the time, it wasn't around for people to actually play with.

00:20:48.240 --> 00:20:55.420
So the other day, I saw an article called A Path to a 10x Database put out by the EdgeDB people.

00:20:55.420 --> 00:20:59.560
One, there was a download link, which I was happy for.

00:20:59.560 --> 00:21:01.200
There's an alpha one available.

00:21:01.520 --> 00:21:10.280
And people that are following along and are kind of excited about what they're doing, they've published a roadmap of the features they have done, what they're working on.

00:21:10.280 --> 00:21:12.200
And it's kind of cool.

00:21:12.200 --> 00:21:14.460
I'm looking forward to being able to play with it more.

00:21:15.020 --> 00:21:19.900
So people that don't know what it is, they call it a next generation relational database.

00:21:19.900 --> 00:21:22.340
It's based on Postgres.

00:21:22.340 --> 00:21:28.120
I don't know what that means if they're using Postgres or if they're used the design of Postgres as a base.

00:21:28.120 --> 00:21:29.420
I haven't dug that far.

00:21:29.900 --> 00:21:35.020
But it features a different kind of data model and an advanced query language.

00:21:35.020 --> 00:21:40.200
And there are a whole bunch of features built into it already, and I'm pretty excited about a lot of it.

00:21:40.200 --> 00:21:45.300
But the thing that really excites me is that they completely replaced SQL, the query language.

00:21:45.300 --> 00:21:49.800
It's a different kind of language, and it looks more natural to me.

00:21:49.800 --> 00:21:59.580
I mean, people aren't really writing SQL a lot of times because they're using SQLAlchemy or something like that.

00:21:59.580 --> 00:22:03.580
And partly, those things exist because people don't want to write SQL.

00:22:03.580 --> 00:22:08.520
But maybe if we had a better query language, we wouldn't need the middle layer so much.

00:22:08.520 --> 00:22:09.780
Yeah, it definitely looks interesting.

00:22:09.780 --> 00:22:14.700
I don't have a real good sense of how it compares to both of those.

00:22:14.700 --> 00:22:16.920
The query syntax does look nice.

00:22:16.920 --> 00:22:23.300
The joins look super cool, or the subqueries possibly is more like an analogy.

00:22:23.300 --> 00:22:25.300
But yeah, it looks really neat.

00:22:25.520 --> 00:22:32.880
It sort of sells itself as a hybrid between document databases like Mongo and relational ones like Postgres.

00:22:32.880 --> 00:22:35.680
So yeah, it's cool to see innovation there for sure.

00:22:35.680 --> 00:22:41.720
Outside of Mongo, seeing some innovation on the SQL side or the relational side is nice.

00:22:41.720 --> 00:22:45.040
We'll see if it's really a 10x improvement.

00:22:45.040 --> 00:22:47.060
But yeah, we can't just stick around for nothing.

00:22:47.060 --> 00:22:51.460
I did actually try to play with it because I'm like, I want to play with this because it's got Python bindings.

00:22:51.900 --> 00:22:54.200
But I couldn't get it to install on my Mac.

00:22:54.200 --> 00:22:55.440
So yeah.

00:22:55.440 --> 00:22:59.100
Yeah, well, would you have to suffer for being out on the cutting edge, Brian?

00:22:59.100 --> 00:23:00.780
Price you pay.

00:23:00.780 --> 00:23:01.540
Yep.

00:23:01.540 --> 00:23:02.620
All right.

00:23:02.620 --> 00:23:05.460
So this last one is going to be just a quick roundup of some stuff.

00:23:05.460 --> 00:23:07.980
Then maybe this combo will help some folks.

00:23:07.980 --> 00:23:16.300
This guy, Wakwas Jonas, worked for a software, sorry, healthcare startup in the US.

00:23:16.760 --> 00:23:22.740
And he wrote this cool blog post called 16 Python Libraries that Helped a Healthcare Startup Grow.

00:23:22.740 --> 00:23:23.220
Oh, neat.

00:23:23.220 --> 00:23:23.440
Yeah.

00:23:23.440 --> 00:23:32.260
So it's just like a paragraph or two about different packages or even modules that they use to kind of solve some problem within their startup.

00:23:32.260 --> 00:23:39.060
So we have Paramiko, which lets you basically issue commands over SSH to other servers.

00:23:39.060 --> 00:23:48.660
So like on my computer, I could like use Python and talk over SSH to run processes or copy files, stuff between servers.

00:23:48.660 --> 00:23:49.940
Anything I can SSH to.

00:23:49.940 --> 00:23:50.620
That's pretty cool.

00:23:50.620 --> 00:23:52.460
The built-in CSV module.

00:23:52.460 --> 00:23:56.780
You know, that's always good for parsing CSV files.

00:23:56.780 --> 00:23:57.320
Really nice.

00:23:57.320 --> 00:23:58.340
You mentioned SQLAlchemy.

00:23:58.500 --> 00:24:04.340
So they use SQLAlchemy as well, requests and beautiful soup for APIs and web scraping.

00:24:04.340 --> 00:24:09.100
I like to say that every website is an API, even if it doesn't know it.

00:24:09.100 --> 00:24:14.140
So if it doesn't have an API, it has data and you just have to do the right request to it.

00:24:14.140 --> 00:24:15.360
Now it's an API.

00:24:15.360 --> 00:24:16.720
Here's one for you, Brian.

00:24:16.720 --> 00:24:21.420
Test scenarios, which is a PyUnit extension for dependency injection.

00:24:21.420 --> 00:24:23.040
So that's kind of cool.

00:24:23.620 --> 00:24:30.040
Dependency injection is not that huge of a thing that people make use of in Python, but, you know, it has its place, I guess.

00:24:30.040 --> 00:24:30.240
Yeah.

00:24:30.240 --> 00:24:30.940
HL7.

00:24:30.940 --> 00:24:37.740
So a simple library for parsing health level 7 files into Python objects.

00:24:37.740 --> 00:24:38.520
That's cool.

00:24:38.520 --> 00:24:41.100
I suppose like doing that yourself probably is not fun.

00:24:41.100 --> 00:24:43.280
So having a library that does it is great.

00:24:43.280 --> 00:24:49.360
Python phone numbers, which is a library for parsing, formatting, and validating international phone numbers.

00:24:49.360 --> 00:24:50.620
That's pretty sweet.

00:24:50.620 --> 00:24:51.820
It's based on a Google library.

00:24:51.960 --> 00:24:53.000
It's like a Python port of it.

00:24:53.000 --> 00:24:56.900
G event for networking and asynchronous code.

00:24:56.900 --> 00:25:00.780
Python dash date util for parsing date times.

00:25:00.780 --> 00:25:09.460
Like anytime I have to work with date times, I'm like, okay, this project now requires Python dash date util because parsing date time sucks without it, right?

00:25:09.460 --> 00:25:13.840
But this one you just say pars and like that right answer just seems to always come out as great.

00:25:13.840 --> 00:25:15.300
So Matt Plotlev for graphs.

00:25:15.300 --> 00:25:16.760
Python magic.

00:25:16.760 --> 00:25:18.000
Have you heard of Python magic?

00:25:18.000 --> 00:25:19.540
I don't know.

00:25:19.540 --> 00:25:20.260
I hadn't.

00:25:20.360 --> 00:25:27.480
And so what you can do is you can give it a file, some random binary file or even text file, and it'll tell you what file type it is.

00:25:27.480 --> 00:25:27.840
Oh, neat.

00:25:27.900 --> 00:25:32.820
So like suppose somebody gives you an image and they've named it .jpg, but it's really a PNG.

00:25:32.820 --> 00:25:36.140
Like you could feed it something to something like Python magic.

00:25:36.140 --> 00:25:36.840
It would say PNG.

00:25:36.840 --> 00:25:42.820
So you can give it like PDFs or zip files, and it'll tell you like what file it is.

00:25:42.820 --> 00:25:43.800
Okay.

00:25:43.800 --> 00:25:44.940
But magic?

00:25:44.940 --> 00:25:46.660
That seems like a bad name for it.

00:25:46.660 --> 00:25:47.400
But yeah.

00:25:47.400 --> 00:25:48.260
It's Python magic.

00:25:48.380 --> 00:25:51.580
Well, I mean, the reason is it's based on a thing called lib magic.

00:25:51.580 --> 00:25:52.280
But yeah.

00:25:52.280 --> 00:25:56.720
It's just like the criticism just transitively follows to lib magic, I guess.

00:25:56.720 --> 00:25:58.620
All right.

00:25:58.620 --> 00:25:59.260
Another one.

00:25:59.260 --> 00:25:59.660
Django.

00:25:59.860 --> 00:26:02.920
Obviously, that doesn't need a lot of introduction, but yeah, they must use Django.

00:26:02.920 --> 00:26:06.300
Bodo, which is the API for interacting with all things AWS.

00:26:06.300 --> 00:26:09.020
So if you're doing anything with that, that's super cool.

00:26:09.720 --> 00:26:21.100
Like I use Bodo for automatic transcoding, like re-encoding in different formats, videos for my courses, or downloading, say, MP3s to a caching server, stuff like that.

00:26:21.100 --> 00:26:28.940
And then finally, Mailgun for sending email, and Twilio's Python API for sending, both of those were sending reminders, one over email, one over text.

00:26:28.940 --> 00:26:31.960
But it's kind of a cool combo of things, right?

00:26:31.960 --> 00:26:33.400
Mailgun's just a great name.

00:26:33.400 --> 00:26:38.500
We've been starting to use Paramount at work, too, but for the SSH features.

00:26:38.500 --> 00:26:39.220
It's good.

00:26:39.220 --> 00:26:39.620
Oh, yeah.

00:26:39.800 --> 00:26:40.020
Nice.

00:26:40.020 --> 00:26:50.920
Yeah, I feel like this, you know, you don't necessarily have to pick what he picked, but it's cool to see how those all fit together and think of like, well, what packages run this company, basically.

00:26:50.920 --> 00:26:54.340
Articles like this are neat of different people solving different problems.

00:26:54.340 --> 00:26:56.380
What are they using from Python?

00:26:56.380 --> 00:26:57.380
Yeah, exactly.

00:26:57.380 --> 00:26:57.920
Like it.

00:26:57.920 --> 00:26:58.240
All right.

00:26:58.240 --> 00:26:59.940
So that's it for our main items.

00:26:59.940 --> 00:27:01.480
Got any extras you want to share with us?

00:27:01.480 --> 00:27:02.560
No.

00:27:02.560 --> 00:27:03.420
Do you?

00:27:03.420 --> 00:27:05.700
I thought I didn't, but I'm going to share one thing with you all.

00:27:05.700 --> 00:27:11.840
I just recorded an episode with the United States Digital Service for Talk Python.

00:27:11.840 --> 00:27:12.360
Okay.

00:27:12.360 --> 00:27:13.400
What is that?

00:27:13.400 --> 00:27:14.300
I hadn't heard of that either.

00:27:14.720 --> 00:27:18.900
But this is like a little stealth startup type thing inside the government.

00:27:18.900 --> 00:27:29.040
President Obama set it up and it was basically the tech team brought in to solve the healthcare.gov crashing problems like that whole big fail to launch for the Obamacare stuff.

00:27:29.600 --> 00:27:32.200
There was a group of people brought in to fix it and then they did.

00:27:32.200 --> 00:27:35.900
They're like, well, why can't we just apply this to all the other broken things in the government?

00:27:35.900 --> 00:27:45.020
So it's a really cool service where like you can go do like a three month tour of duty at the U.S. Digital Service and like not even have to leave your job.

00:27:45.020 --> 00:27:48.900
Just take a like unpaid leave to go fix something in the government or whatever.

00:27:48.900 --> 00:27:49.680
It's pretty cool.

00:27:49.680 --> 00:27:52.700
I have an episode coming out, but I hadn't heard of it and I thought that was kind of cool.

00:27:52.700 --> 00:27:53.660
So I thought I'd throw it out there.

00:27:53.660 --> 00:27:54.840
Yeah, this is neat.

00:27:54.840 --> 00:27:55.440
It is for sure.

00:27:56.060 --> 00:27:58.240
I have a, it's almost a joke.

00:27:58.240 --> 00:27:59.720
It's not exactly a joke.

00:27:59.720 --> 00:28:06.720
It's more maybe mocking, but how can you tell the difference between machine learning and AI, Brian?

00:28:06.720 --> 00:28:07.900
I don't know.

00:28:07.900 --> 00:28:11.020
If it's written in Python, it's probably machine learning.

00:28:11.020 --> 00:28:13.840
If it's written in PowerPoint, it's probably AI.

00:28:13.840 --> 00:28:14.580
What?

00:28:14.580 --> 00:28:17.280
Written in PowerPoint?

00:28:17.280 --> 00:28:22.520
Like as in it's just like a presentation with ideas, but no code and no implementation yet.

00:28:22.520 --> 00:28:23.540
Oh, okay.

00:28:23.540 --> 00:28:23.900
Yeah.

00:28:23.900 --> 00:28:24.300
Okay.

00:28:24.300 --> 00:28:24.980
Got it.

00:28:24.980 --> 00:28:27.120
So basically if it's real, it's machine learning.

00:28:27.120 --> 00:28:34.160
If it's, if it's like, we're going to use magic, computer magic to solve this problem, it's AI and it's in PowerPoint.

00:28:34.160 --> 00:28:34.860
That's funny.

00:28:34.860 --> 00:28:43.260
I have a question for you when I, it's not a joke, but way back in the dark ages when I was going to college, all the AI work was done in like Lisp.

00:28:43.260 --> 00:28:44.240
Yes, it was.

00:28:44.240 --> 00:28:47.900
Are there still people doing AI in Lisp or is that not a thing anymore?

00:28:47.900 --> 00:28:48.480
Do you know?

00:28:48.640 --> 00:28:50.780
I think people are still doing it.

00:28:50.780 --> 00:28:55.600
I think people are still doing it, but I don't think the neural network people have stayed there.

00:28:55.600 --> 00:28:55.800
Right.

00:28:55.800 --> 00:29:02.580
I think the neural network people mostly have moved to Python and things like TensorFlow and the other GP based things.

00:29:02.580 --> 00:29:07.340
But I'm sure that there's like different kinds of AI.

00:29:07.340 --> 00:29:07.460
Yeah.

00:29:07.460 --> 00:29:07.540
Yeah.

00:29:07.540 --> 00:29:08.060
Because you're right.

00:29:08.060 --> 00:29:12.160
It was all, you had to be a Lisp programmer if you wanted to do anything with AI.

00:29:12.160 --> 00:29:15.380
And AI was always this like amorphous, weird thing.

00:29:15.380 --> 00:29:24.040
Like you don't really know what it is, but probably if we can like set up a blind chat with it over IRC, then it might seem like it's alive and then it'll be AI.

00:29:24.040 --> 00:29:24.420
Right.

00:29:24.420 --> 00:29:28.000
Like that, you know, the whole Turing test and all that, that stuff.

00:29:28.000 --> 00:29:30.220
And now it's like, that's cute.

00:29:30.220 --> 00:29:32.520
Car, drive here.

00:29:32.520 --> 00:29:34.820
The car will go out.

00:29:34.820 --> 00:29:41.960
You know, like that's with Python and like TensorFlow and the Lisp one that's doing the chat.

00:29:41.960 --> 00:29:42.640
Right.

00:29:42.640 --> 00:29:48.760
Like I feel like that's kind of where it is, but I'm sure people are still doing cool stuff with Lisp that I don't know or really want to read the code for.

00:29:48.760 --> 00:29:49.360
Okay.

00:29:49.360 --> 00:29:52.420
I'm glad there's probably not any Lisp programmers that listen to this.

00:29:52.420 --> 00:29:55.780
No, but we're probably going to be posted in a negative way on some Lisp forum.

00:29:55.780 --> 00:29:56.440
Sorry about that.

00:29:56.440 --> 00:29:57.120
Sorry.

00:29:57.120 --> 00:29:58.820
All right.

00:29:58.820 --> 00:30:00.120
Well, thanks for being here, Brian.

00:30:00.120 --> 00:30:01.460
And thanks for sharing everything.

00:30:01.460 --> 00:30:01.940
Thank you.

00:30:01.940 --> 00:30:02.260
You bet.

00:30:02.260 --> 00:30:02.720
Bye, everyone.

00:30:02.720 --> 00:30:03.000
Bye.

00:30:03.000 --> 00:30:04.900
Thank you for listening to Python Bytes.

00:30:04.900 --> 00:30:07.440
Follow the show on Twitter via at Python Bytes.

00:30:07.440 --> 00:30:10.300
That's Python Bytes as in B-Y-T-E-S.

00:30:10.560 --> 00:30:13.540
And get the full show notes at pythonbytes.fm.

00:30:13.540 --> 00:30:17.740
If you have a news item you want featured, just visit pythonbytes.fm and send it our way.

00:30:17.740 --> 00:30:20.440
We're always on the lookout for sharing something cool.

00:30:20.440 --> 00:30:23.560
On behalf of myself and Brian Okken, this is Michael Kennedy.

00:30:23.560 --> 00:30:26.980
Thank you for listening and sharing this podcast with your friends and colleagues.