WEBVTT

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

00:00:04.960 --> 00:00:09.800
This is episode 351, recorded September 5th, and I am Brian Okken.

00:00:09.800 --> 00:00:11.020
And I'm Michael Kennedy.

00:00:11.020 --> 00:00:14.920
And this episode is also sponsored by Sentry. Thank you, Sentry.

00:00:14.920 --> 00:00:19.420
And if you want to reach any of us or the show, either of us or the show,

00:00:19.420 --> 00:00:25.560
we're at mkennedy, at brianauken, and at pythonbytes, all at fostadon.org.

00:00:25.680 --> 00:00:31.220
And if you're listening later and you'd like to join the show live sometime,

00:00:31.220 --> 00:00:36.080
you can join us on YouTube at pythonbytes.fm/live.

00:00:36.080 --> 00:00:37.700
And we'd love to have you here.

00:00:37.700 --> 00:00:38.340
Indeed.

00:00:38.340 --> 00:00:39.820
What do you got for us first, Michael?

00:00:39.820 --> 00:00:42.600
Let's talk about multiprocessing.

00:00:42.600 --> 00:00:46.240
Empire, not pyre, but mpire, right?

00:00:46.240 --> 00:00:48.460
Pyre is the type checker from meta.

00:00:48.460 --> 00:00:53.220
Empire is something entirely different about multiprocessing.

00:00:53.220 --> 00:00:58.820
And so it's a Python package for easy multiprocessing that's faster than the built-in

00:00:58.820 --> 00:01:04.840
multiprocessing, but has a similar API, has really good error reporting and a bunch of

00:01:04.840 --> 00:01:07.840
other types of reporting, like how well did that session go?

00:01:07.840 --> 00:01:13.080
You know, like how well did you utilize the multiprocessing capabilities of your machine

00:01:13.080 --> 00:01:13.620
and so on?

00:01:13.620 --> 00:01:15.400
So yeah, let's dig into it.

00:01:15.400 --> 00:01:20.440
So the whole acronym for the name is multiprocessing is really easy,

00:01:20.440 --> 00:01:22.260
which is not what most people say, right?

00:01:22.600 --> 00:01:23.040
No.

00:01:23.040 --> 00:01:29.780
But it's a package that's faster than multiprocessing in most cases, has more features,

00:01:29.780 --> 00:01:34.020
and is generally more user-friendly than the default multiprocessing package.

00:01:34.020 --> 00:01:41.560
It has APIs like multiprocessing.pool, but it also has the benefits of things like copy,

00:01:41.560 --> 00:01:42.620
unwrite, shared objects.

00:01:42.620 --> 00:01:44.720
We're going to come back to that later as well.

00:01:45.200 --> 00:01:52.380
But also the ability to have like init and exit, set up teardown for your workers, some more

00:01:52.380 --> 00:01:53.960
state that you can use and so on.

00:01:53.960 --> 00:01:55.300
So pretty cool.

00:01:55.300 --> 00:01:56.920
It has a progress bar.

00:01:57.080 --> 00:02:02.660
It has TQDM progress built right into it across the multiple processes.

00:02:02.660 --> 00:02:05.720
So you can say things like, here is some work I want you to do.

00:02:05.720 --> 00:02:06.700
There's a hundred items.

00:02:06.700 --> 00:02:09.500
Split that across five cores.

00:02:10.020 --> 00:02:15.960
And as those different processes complete the work for individual elements, give me a unified

00:02:15.960 --> 00:02:18.260
progress bar, which is pretty awesome, right?

00:02:18.260 --> 00:02:18.820
Yeah.

00:02:18.820 --> 00:02:19.300
Yeah.

00:02:19.300 --> 00:02:19.760
Very cool.

00:02:19.880 --> 00:02:20.000
Yeah.

00:02:20.000 --> 00:02:20.540
Yeah.

00:02:20.540 --> 00:02:22.280
It's got a progress dashboard.

00:02:22.280 --> 00:02:23.580
Actually, I have no idea what that is.

00:02:23.580 --> 00:02:27.260
It has a worker insights that you can ask when it's done.

00:02:27.260 --> 00:02:31.020
Like how well did, you know, how efficient was that multiprocessing story?

00:02:31.020 --> 00:02:33.660
Graceful and user-friendly exception handling.

00:02:33.660 --> 00:02:34.680
It has timeouts.

00:02:34.680 --> 00:02:41.200
So you can say, I would like the execution of the work to not take more than three seconds.

00:02:41.200 --> 00:02:47.240
And actually you can even say things such as if the worker process itself takes 10 seconds

00:02:47.240 --> 00:02:50.860
or more to exit, maybe there's like some, something happening over there.

00:02:50.860 --> 00:02:55.140
That's like a hung connection on a database thing or who knows, right?

00:02:55.140 --> 00:02:55.780
Some network thing.

00:02:55.780 --> 00:02:59.320
You can actually set a different timeout for the process, which is pretty cool.

00:02:59.320 --> 00:03:01.680
It has automatic chunking.

00:03:01.680 --> 00:03:06.580
So instead of saying, I have a hundred things, let's go individually one at a time, hand them

00:03:06.580 --> 00:03:07.200
off to workers.

00:03:07.200 --> 00:03:13.460
It can break them up into bigger blocks, including numpy arrays, which is pretty cool.

00:03:13.740 --> 00:03:18.360
You can set the maximum number of tasks that are allowed to run at any given moment.

00:03:18.360 --> 00:03:21.780
I guess, you know, you can set the workers, but also like, if it does this chunking and

00:03:21.780 --> 00:03:24.620
you can say how many things can run to avoid memory problems.

00:03:24.620 --> 00:03:29.400
You could even say, four, I want to use five processes, but after.

00:03:29.400 --> 00:03:33.480
You know, 10, 10 bits of work on any given process.

00:03:33.660 --> 00:03:38.280
Give me a new worker and shut down the others in case there's like leaky memory or other

00:03:38.280 --> 00:03:39.480
things along those lines.

00:03:39.480 --> 00:03:42.880
you can create a pool of them through a daemon option.

00:03:42.880 --> 00:03:44.080
A whole bunch of stuff.

00:03:44.080 --> 00:03:51.000
It uses dill to serialize across, the multi-process processes, which is cool because it gives you

00:03:51.000 --> 00:04:00.000
more exotic, serialization options for say objects that are not pickleable lambdas functions and other

00:04:00.000 --> 00:04:01.980
things in IPython and Jupyter notebooks.

00:04:01.980 --> 00:04:03.420
So all that's pretty awesome.

00:04:03.420 --> 00:04:03.700
Right?

00:04:03.700 --> 00:04:04.260
Yeah.

00:04:04.260 --> 00:04:04.840
Yeah.

00:04:05.060 --> 00:04:11.180
So the API is super, super simple from empire import worker pool with worker pool jobs equal

00:04:11.180 --> 00:04:14.520
five, pull that map, some function, some data go.

00:04:14.520 --> 00:04:19.840
So this jobs here tells you how many processes to run basically for the progress bar.

00:04:19.840 --> 00:04:22.560
you just set progress bar equals true.

00:04:22.560 --> 00:04:23.620
That's not too bad.

00:04:23.620 --> 00:04:26.220
Another thing that's cool is you can have shared objects.

00:04:26.220 --> 00:04:33.500
So you can have, some shared data that's passed across without, basically using shared

00:04:33.500 --> 00:04:33.840
memory.

00:04:33.840 --> 00:04:37.860
I think is how that it works so that it's more efficient instead of trying to pickle it

00:04:37.860 --> 00:04:38.280
across.

00:04:38.280 --> 00:04:39.740
I think they have to be read only or something.

00:04:39.740 --> 00:04:40.720
And there's a whole bunch about it.

00:04:40.720 --> 00:04:41.240
Oh, interesting.

00:04:41.240 --> 00:04:43.640
But you pass it into the worker pool.

00:04:43.640 --> 00:04:44.140
Okay.

00:04:44.140 --> 00:04:44.740
Yeah.

00:04:44.740 --> 00:04:49.060
You say worker pool, these things, I want you to set them up in a way to be shared.

00:04:49.060 --> 00:04:54.740
And I think, like I said, in a read only way across, across all the processes instead

00:04:54.740 --> 00:04:55.900
of trying to copy them over.

00:04:55.900 --> 00:05:03.780
you have a setup and a teardown thing that you can do, to like prepare the worker,

00:05:03.780 --> 00:05:08.840
when it gets started, you can ask it for the insights, like I said, and then

00:05:08.840 --> 00:05:09.260
benchmarks.

00:05:09.260 --> 00:05:11.760
It shows it's significantly faster.

00:05:11.760 --> 00:05:16.080
Not just the compared, not just against multi-processing, but they say, here's how you do it.

00:05:16.080 --> 00:05:17.980
Here's what happens if you do it in a serial way.

00:05:17.980 --> 00:05:21.440
Here's what multi-processing and process pool executors look like.

00:05:21.520 --> 00:05:24.520
But it also compares against job lib, dask, and array.

00:05:24.520 --> 00:05:24.960
Mm.

00:05:24.960 --> 00:05:28.580
And it's, it's pretty much hanging there with the best of them, isn't it?

00:05:28.580 --> 00:05:29.000
Yeah.

00:05:29.000 --> 00:05:31.980
It does a titch faster than ray everywhere.

00:05:31.980 --> 00:05:32.460
Yeah.

00:05:32.460 --> 00:05:33.560
Just, yeah.

00:05:33.560 --> 00:05:34.560
Just, just a bit.

00:05:34.560 --> 00:05:35.840
One other thing.

00:05:35.960 --> 00:05:40.180
I don't remember where it was, in this huge, long list of things.

00:05:40.180 --> 00:05:47.500
but you can also pin the CPUs to CPU cores, which can be really valuable when you're thinking

00:05:47.500 --> 00:05:52.160
about, taking advantage of, you know, L1, L2 CPU caches.

00:05:52.300 --> 00:05:56.920
So if your processes are bouncing around back and forth, one's working with some data, then

00:05:56.920 --> 00:05:58.840
it switches to another core.

00:05:58.840 --> 00:06:05.340
And then it has to pull a new data into the, into the L2 cache, which is like hundreds

00:06:05.340 --> 00:06:06.800
of times slower than real memory.

00:06:06.800 --> 00:06:08.080
And that's how that slows it down.

00:06:08.080 --> 00:06:09.480
Then they switch back and they keep running.

00:06:09.480 --> 00:06:14.740
So you can say, you know, pin these workers to these CPUs and you know, you've got a better

00:06:14.740 --> 00:06:17.600
chance of them not redoing their cache all the time.

00:06:17.600 --> 00:06:18.260
So that's kind of cool.

00:06:18.260 --> 00:06:19.900
So there's just a bunch of neat little features in here.

00:06:19.900 --> 00:06:20.480
Yeah.

00:06:20.620 --> 00:06:23.400
If you're already using multiprocessing, you might check this out.

00:06:23.400 --> 00:06:26.800
Oh, if you care about performance for real, you know,

00:06:26.800 --> 00:06:30.740
why are you using multiprocessing if you don't care about performance?

00:06:30.740 --> 00:06:36.240
Well, I mean, you're, you're looking to pull out the final little bits of performance, I

00:06:36.240 --> 00:06:36.640
suppose.

00:06:36.640 --> 00:06:37.020
Yeah.

00:06:37.020 --> 00:06:37.220
Yeah.

00:06:37.220 --> 00:06:37.440
Yeah.

00:06:37.440 --> 00:06:38.100
Right.

00:06:38.100 --> 00:06:42.160
Like these benchmarks are cool, but they're doing, you know, computation on the workers.

00:06:42.160 --> 00:06:42.600
Right.

00:06:42.600 --> 00:06:47.380
Whereas a lot of what you're doing is like talking to queues and talking to networks and talking

00:06:47.380 --> 00:06:47.980
to databases.

00:06:47.980 --> 00:06:51.260
Like it doesn't matter what framework you used to do that long as you're doing something

00:06:51.260 --> 00:06:51.680
parallel.

00:06:51.680 --> 00:06:52.300
Right.

00:06:52.300 --> 00:06:52.820
Yeah.

00:06:52.820 --> 00:06:53.680
Well, yeah.

00:06:53.680 --> 00:06:54.320
Well, I don't know.

00:06:54.320 --> 00:06:55.760
That's why you have to do your own benchmarks.

00:06:55.760 --> 00:06:56.760
Yeah, for sure.

00:06:56.760 --> 00:07:00.740
And then there's that article over on medium by the creator as well.

00:07:01.160 --> 00:07:03.640
That gives you a whole lot of background on all this stuff.

00:07:03.640 --> 00:07:04.220
Oh, neat.

00:07:04.220 --> 00:07:04.800
Nice.

00:07:04.800 --> 00:07:05.140
Yeah.

00:07:05.140 --> 00:07:06.740
This is quite a long article.

00:07:06.740 --> 00:07:08.660
And I think it's actually more relevant.

00:07:08.660 --> 00:07:13.240
Like, for example, it's got screenshots where it shows, you know, if you use something like,

00:07:13.240 --> 00:07:14.760
let me read really quickly.

00:07:14.760 --> 00:07:19.000
Ray or job lib and you get some kind of exception.

00:07:19.000 --> 00:07:20.560
It just says exception occurred.

00:07:20.560 --> 00:07:21.160
Yikes.

00:07:21.540 --> 00:07:26.340
Whereas with this one, with empire, you get things like here's the call stack that goes

00:07:26.340 --> 00:07:28.520
back a little more correctly to the right function.

00:07:28.520 --> 00:07:30.900
And here's the arguments that were passed.

00:07:30.900 --> 00:07:31.960
Oh, interesting.

00:07:31.960 --> 00:07:32.620
Over.

00:07:32.620 --> 00:07:37.700
So when it crashes, you know, because you have like five processes, potentially all doing

00:07:37.700 --> 00:07:37.940
stuff.

00:07:37.940 --> 00:07:38.580
One of them crashed.

00:07:38.580 --> 00:07:39.780
Like what data did they have?

00:07:39.780 --> 00:07:40.480
I don't know.

00:07:40.480 --> 00:07:41.460
It's a parallel.

00:07:41.460 --> 00:07:41.960
It's hard.

00:07:41.960 --> 00:07:42.500
Right.

00:07:42.560 --> 00:07:46.600
So having the arguments like these are the ones that cause the error is pretty excellent.

00:07:46.600 --> 00:07:47.120
Yeah.

00:07:47.120 --> 00:07:47.580
Cool.

00:07:47.580 --> 00:07:49.400
Anyway, empire.

00:07:49.400 --> 00:07:50.560
That's what I got for number one.

00:07:50.560 --> 00:07:52.240
All right.

00:07:52.240 --> 00:07:52.500
Cool.

00:07:52.500 --> 00:07:56.740
I want to have, I have something else that starts with M.

00:07:56.740 --> 00:07:58.840
Mop up.

00:07:58.840 --> 00:08:05.240
So mop up is something that I learned about from an article by glyph.

00:08:05.240 --> 00:08:07.340
So I'll let me jump to the article first.

00:08:07.340 --> 00:08:12.040
So glyph wrote an article saying, get your Mac Python from python.org.

00:08:12.040 --> 00:08:13.440
That's what I already do.

00:08:13.440 --> 00:08:19.080
I've tried all the other stuff and I just like just the downloader from python.org.

00:08:19.080 --> 00:08:23.760
So this article talks about reasons why that's probably what you want.

00:08:23.760 --> 00:08:28.900
And that's probably what if you're writing a tutorial, it's probably what your users need

00:08:28.900 --> 00:08:29.440
to do, too.

00:08:29.440 --> 00:08:35.840
If they're if they're using a Mac and I won't go through all the details, but he he goes through

00:08:35.840 --> 00:08:42.020
reasons why you probably want this one and not things like what are the others?

00:08:42.020 --> 00:08:42.960
homebrew.

00:08:42.960 --> 00:08:46.580
You can brew install your Python, but he doesn't recommend it.

00:08:46.580 --> 00:08:48.200
And you can read all the pyenv.

00:08:48.200 --> 00:08:49.200
I've tried it.

00:08:49.200 --> 00:08:52.040
It like messes up other stuff for me.

00:08:52.040 --> 00:08:54.500
So I like the downloader from Python.

00:08:54.500 --> 00:09:01.720
But one of the things that I don't like is that if like if I had Python 311 4 installed and

00:09:01.720 --> 00:09:03.640
now Python 311 5 is out.

00:09:03.780 --> 00:09:05.480
How do I get that on my computer?

00:09:05.480 --> 00:09:06.660
Do I just reinstall it?

00:09:06.660 --> 00:09:07.620
Yes, you can.

00:09:07.620 --> 00:09:11.900
But Glyph made a new thing called mop up.

00:09:11.900 --> 00:09:16.720
So what mop up does is you you just pip install mop up.

00:09:16.840 --> 00:09:23.920
And it's like the only thing I install on my global my global Python versions like 311 pip install.

00:09:23.920 --> 00:09:26.980
I update pip and install this and that's it.

00:09:26.980 --> 00:09:28.820
Everything else goes into a virtual environment.

00:09:29.580 --> 00:09:32.000
Or pip x install this.

00:09:32.000 --> 00:09:32.560
Exactly.

00:09:32.560 --> 00:09:34.640
But mop up.

00:09:34.640 --> 00:09:35.360
What's the usage?

00:09:35.360 --> 00:09:36.680
So I just tried it this morning.

00:09:36.680 --> 00:09:38.780
I didn't pass it any flags.

00:09:38.780 --> 00:09:40.860
I just installed it and ran it.

00:09:40.860 --> 00:09:48.360
And it updated me from Python 311 4 to Python 311 5 without me having to re-download anything

00:09:48.360 --> 00:09:49.320
other than this.

00:09:49.580 --> 00:09:52.680
So I'm going to set up something that goes through.

00:09:52.680 --> 00:09:54.760
I've got a lot of versions on my computer.

00:09:54.760 --> 00:09:58.140
I've got I think well I've got 3.7 through 3.12 install.

00:09:58.140 --> 00:10:02.960
And and I want all of them to be on the latest bug fix release.

00:10:02.960 --> 00:10:12.760
So I'm just going to use probably use Brett Cannon's pi installer or Python installer pi on

00:10:12.760 --> 00:10:17.640
my Mac to go to each of the versions and run mop up on all of them to update it.

00:10:17.780 --> 00:10:19.920
So that's what I'd like to do.

00:10:19.920 --> 00:10:20.900
Anyway it's cool.

00:10:20.900 --> 00:10:25.940
I'm I'm really excited about this because this was like the one hole in using the install

00:10:25.940 --> 00:10:29.840
the the python.org installer is how they update it.

00:10:29.840 --> 00:10:31.260
So nice.

00:10:31.260 --> 00:10:31.520
Yep.

00:10:31.520 --> 00:10:32.260
Interesting.

00:10:32.260 --> 00:10:32.780
Interesting.

00:10:32.780 --> 00:10:37.460
I got to admit I'm still a brew install Python 3 sort of person.

00:10:37.460 --> 00:10:38.080
Okay.

00:10:38.080 --> 00:10:43.660
And the drawback the main drawback that glyph makes an argument for which is valid is you

00:10:43.660 --> 00:10:46.700
don't control necessarily the version of Python that you get.

00:10:46.820 --> 00:10:53.740
Because if you brew install I don't know some other you know YouTube downloader app or whatever

00:10:53.740 --> 00:10:59.880
rando thing it might say well I need a Python 3.12 and you only have 3.8 right.

00:10:59.880 --> 00:11:02.120
And it'll auto upgrade on you without you knowing.

00:11:02.120 --> 00:11:05.560
But I'm always running the absolute latest Python anyway.

00:11:05.560 --> 00:11:10.140
And so you know when it those other packages say greater than 3.10 like I don't care I already

00:11:10.140 --> 00:11:11.040
have greater than 3.10.

00:11:11.400 --> 00:11:15.600
So I don't know that's the world I'm living in now but that's okay for me.

00:11:15.600 --> 00:11:16.680
Oh okay.

00:11:16.680 --> 00:11:23.220
So yeah I'm I'm a package maintainer so I I have multiple versions on my box but it's

00:11:23.220 --> 00:11:28.100
but in a lot of people like pyenv for that reason but I yeah I don't.

00:11:28.320 --> 00:11:32.640
But anyway I've always I've had trouble with pyenv too especially around the Apple Silicon

00:11:32.640 --> 00:11:41.260
Rosetta compiler mismatch like there's just like it wouldn't install for me and so yeah I think the

00:11:41.260 --> 00:11:43.760
whole I think the python.org it's a good recommendation though.

00:11:43.760 --> 00:11:44.580
Okay cool.

00:11:44.580 --> 00:11:45.520
Yep yep.

00:11:45.520 --> 00:11:46.080
All right.

00:11:46.920 --> 00:11:49.740
before we move on to our next topic Brian.

00:11:49.740 --> 00:11:55.000
Well I'd like to thank Sentry for sponsoring this episode of Python Bytes.

00:11:55.000 --> 00:11:59.560
You know Sentry for their error tracking service but did you know that you can take take it all

00:11:59.560 --> 00:12:04.520
the way through your multi-tier and distributed app with their distributed tracing feature?

00:12:04.520 --> 00:12:05.400
How cool is that?

00:12:05.400 --> 00:12:10.720
Distributed tracing is a debugging technique that involves tracking your the request of your

00:12:10.720 --> 00:12:15.120
system starting from the very beginning like the user action all the way to the back end

00:12:15.120 --> 00:12:16.840
database and third-party services.

00:12:16.840 --> 00:12:24.180
This can help you identify if the cause of the an error is one project in one project is due to an

00:12:24.180 --> 00:12:25.920
error in the other another project.

00:12:25.920 --> 00:12:27.280
That's very useful.

00:12:27.280 --> 00:12:33.240
Every system can benefit from distributed tracing but they are useful for especially for microservices

00:12:33.240 --> 00:12:40.060
in microservice architecture logs won't give you the full picture so you can't debug every request

00:12:40.060 --> 00:12:45.000
in full by reading the logs but distributed tracing with a platform like Sentry

00:12:45.000 --> 00:12:50.060
can give you visual overview of which services were called during the execution of certain requests.

00:12:50.060 --> 00:12:56.060
Aside from debugging and visualizing architecture distributed tracing also helps you identify

00:12:56.060 --> 00:12:59.060
performance bottlenecks through a visual like Gantt chart.

00:12:59.060 --> 00:13:08.120
You can see if a particular span in your stack took longer than expected and how it could be causing slowdowns in other parts of your app.

00:13:08.120 --> 00:13:17.180
You can see if you can see the results of your app.

00:13:17.180 --> 00:13:17.180
You can see the results of your app.

00:13:17.180 --> 00:13:18.180
You can see the results of your app.

00:13:18.180 --> 00:13:19.180
You can see the results of your app.

00:13:19.180 --> 00:13:30.240
You can see the results of your app.

00:13:30.240 --> 00:13:41.300
You can see the results of your app.

00:13:41.300 --> 00:13:52.360
You can see the results of your app.

00:13:52.360 --> 00:14:03.420
You can see the results of your app.

00:14:03.420 --> 00:14:04.420
You can see the results of your app.

00:14:04.420 --> 00:14:16.480
You can see the results of your app.

00:14:16.480 --> 00:14:28.540
You can see the results of your app.

00:14:28.540 --> 00:14:29.540
You can see the results of your app.

00:14:29.540 --> 00:14:30.540
You can see the results of your app.

00:14:30.540 --> 00:14:31.540
You can see the results of your app.

00:14:31.540 --> 00:14:32.540
You can see the results of your app.

00:14:32.540 --> 00:14:33.540
You can see the results of your app.

00:14:33.540 --> 00:14:34.540
You can see the results of your app.

00:14:34.540 --> 00:14:35.540
You can see the results of your app.

00:14:35.540 --> 00:14:36.540
You can see the results of your app.

00:14:36.540 --> 00:14:37.540
You can see the results of your app.

00:14:37.540 --> 00:14:38.540
You can see the results of your app.

00:14:38.540 --> 00:14:39.540
You can see the results of your app.

00:14:39.540 --> 00:14:40.540
You can see the results of your app.

00:14:40.540 --> 00:14:41.540
You can see the results of your app.

00:14:41.540 --> 00:14:42.540
You can see the results of your app.

00:14:42.540 --> 00:14:43.540
You can see the results of your app.

00:14:43.540 --> 00:14:44.540
You can see the results of your app.

00:14:44.540 --> 00:14:45.540
You can see the results of your app.

00:14:45.540 --> 00:14:46.540
You can see the results of your app.

00:14:46.540 --> 00:14:47.540
You can see the results of your app.

00:14:47.540 --> 00:14:48.540
You can see the results of your app.

00:14:48.540 --> 00:14:49.540
You can see the results of your app.

00:14:49.540 --> 00:14:50.540
You can see the results of your app.

00:14:50.540 --> 00:14:51.540
You can see the results of your app.

00:14:51.540 --> 00:14:52.540
You can see the results of your app.

00:14:52.540 --> 00:14:53.540
You can see the results of your app.

00:14:53.540 --> 00:14:54.540
You can see the results of your app.

00:14:54.540 --> 00:14:55.540
You can see the results of your app.

00:14:55.540 --> 00:14:56.540
You can see the results of your app.

00:14:56.540 --> 00:14:57.540
You can see the results of your app.

00:14:57.540 --> 00:14:58.540
You can see the results of your app.

00:14:58.540 --> 00:14:59.540
You can see the results of your app.

00:14:59.540 --> 00:15:00.540
You can see the results of your app.

00:15:00.540 --> 00:15:01.540
You can see the results of your app.

00:15:01.540 --> 00:15:02.540
You can see the results of your app.

00:15:02.540 --> 00:15:03.540
You can see the results of your app.

00:15:03.540 --> 00:15:04.540
You can see the results of your app.

00:15:04.540 --> 00:15:05.540
You can see the results of your app.

00:15:05.540 --> 00:15:06.540
You can see the results of your app.

00:15:06.540 --> 00:15:07.540
You can see the results of your app.

00:15:07.540 --> 00:15:08.540
You can see the results of your app.

00:15:08.540 --> 00:15:09.540
You can see the results of your app.

00:15:09.540 --> 00:15:10.540
You can see the results of your app.

00:15:10.540 --> 00:15:11.540
You can see the results of your app.

00:15:11.540 --> 00:15:12.540
You can see the results of your app.

00:15:12.540 --> 00:15:13.540
You can see the results of your app.

00:15:13.540 --> 00:15:19.540
So if you have x equals a string, and then I say y equals x, it goes up to that thing

00:15:19.540 --> 00:15:22.540
and says plus plus, you know, plus equals one on the reference count.

00:15:22.540 --> 00:15:26.540
And when y goes away, then it minus minuses it, right?

00:15:26.540 --> 00:15:27.540
When that number hits zero, it gets cleaned up.

00:15:27.540 --> 00:15:31.540
There's also stuff on the object for cycles and garbage collection.

00:15:31.540 --> 00:15:33.540
So there's a lot of stuff that's happening there, right?

00:15:33.540 --> 00:15:34.540
Yeah.

00:15:34.540 --> 00:15:41.540
And so what they're doing is they're running a lot of Django for Instagram, which is pretty awesome.

00:15:41.540 --> 00:15:49.540
However, what they're trying to take advantage of is the fact that there's a lot of similar data, similar memory usage.

00:15:49.540 --> 00:15:58.540
When I load up Python, so if I write type Python on the terminal, and then I open up a new terminal type Python, it's gone through exactly the same startup process, right?

00:15:58.540 --> 00:16:01.540
So it's loaded the same shared libraries or DLLs.

00:16:01.540 --> 00:16:02.540
It's created.

00:16:02.540 --> 00:16:09.540
It's, it's, you know, negative 255 to 255 flywheel numbers.

00:16:09.540 --> 00:16:13.540
There's going to reuse instead of when you say the number seven, it doesn't always create a new seven.

00:16:13.540 --> 00:16:17.540
You always have the seven that was created at startup exceptions, those kinds of things, right?

00:16:17.540 --> 00:16:32.540
Well, if you have a web server that's got 10 or 20 or a hundred worker processes that all went through the same startup for a Python app, you would want to have things like that number seven or some exception type or whatever modules, right?

00:16:32.540 --> 00:16:33.540
Core modules that are loaded.

00:16:33.540 --> 00:16:40.540
You would like to have one copy of those in memory on Linux, and then have a copy on right thing for the stuff that actually changes.

00:16:40.540 --> 00:16:42.540
But those other pieces, you want them to stay the same.

00:16:42.540 --> 00:16:43.540
Yeah.

00:16:43.540 --> 00:16:44.540
Yeah.

00:16:44.540 --> 00:16:49.540
Like there's no point in having like a different representation of the number four for every process.

00:16:49.540 --> 00:16:52.540
If there's some way to share that memory that was created at startup.

00:16:52.540 --> 00:16:55.540
And we don't need reference counts updated and all that stuff.

00:16:55.540 --> 00:16:56.540
Because exactly exactly.

00:16:56.540 --> 00:17:07.540
So the, I, what they found was, while many of their Python objects are practically or effectively immutable, they didn't actually over time behave that way.

00:17:07.540 --> 00:17:10.540
So they have graphs of private memory and shared memory.

00:17:10.540 --> 00:17:16.540
And what you would hope is that the shared memory stays pretty stable over time, or maybe even grows.

00:17:16.540 --> 00:17:17.540
Maybe you're doing new stuff.

00:17:17.540 --> 00:17:20.540
That's like pulled in similar things, but that's not what happens in practice.

00:17:20.540 --> 00:17:22.540
I'm current Python.

00:17:22.540 --> 00:17:32.540
The shared memory goes down and down and down, because even though that object, or let's say that flywheel number that got created to be shared, it's still got his reference count number change.

00:17:32.540 --> 00:17:36.540
So throughout the behavior of one app, it might go, well, four was used for a long time.

00:17:36.540 --> 00:17:39.540
Four was used 300 times here and 280 over there.

00:17:39.540 --> 00:17:41.540
So those are not the same four.

00:17:41.540 --> 00:17:45.540
Cause on the reference count, they have 281 and 301 or whatever it is.

00:17:45.540 --> 00:17:46.540
Right.

00:17:46.540 --> 00:18:02.540
And so that, that shared memory is falling down because the garbage collector and, just the interacting with the ref count is very in very meaningless and small ways, changing pieces of the shared memory to make them fall out of the shared state.

00:18:02.540 --> 00:18:06.540
So this whole path, this whole idea is we're going to make those types of things.

00:18:06.540 --> 00:18:08.540
so that their reference count can't change.

00:18:08.540 --> 00:18:10.540
And their GC structures can't change.

00:18:10.540 --> 00:18:11.540
They cannot be changed.

00:18:11.540 --> 00:18:17.540
They're just always set to some magic number for like this thing's reference count is unchanged.

00:18:17.540 --> 00:18:18.540
Right.

00:18:18.540 --> 00:18:26.540
So if you look at like the object header, it's got a GC header reference count object type, and then the actual data for the ones that don't change.

00:18:26.540 --> 00:18:28.540
Now these new ones can be set.

00:18:28.540 --> 00:18:31.540
So even their GC header and the reference counts don't change.

00:18:31.540 --> 00:18:32.540
Cool.

00:18:32.540 --> 00:18:32.540
Right.

00:18:32.540 --> 00:18:33.540
Yeah.

00:18:33.540 --> 00:18:33.540
Yeah.

00:18:33.540 --> 00:18:38.540
And what that means is if you come down here, it says there's some challenges.

00:18:38.540 --> 00:18:41.540
First, they had to make sure that applications wouldn't crash.

00:18:41.540 --> 00:18:44.540
If some objects suddenly had different ref counts.

00:18:44.540 --> 00:18:55.540
Second, it changes the core memory representation of a Python object, which if you work in the C level, just directly with the memory, that's, you know, pointers to the object.

00:18:55.540 --> 00:18:56.540
That can be tricky.

00:18:56.540 --> 00:19:08.540
And finally, the core implementation relies on adding checks explicitly to the increment and decrement, the, you know, add ref, remove ref, decrement ref, which are two of the hottest bits of code in all of Python.

00:19:08.540 --> 00:19:09.540
Yeah.

00:19:09.540 --> 00:19:10.540
As in the most performance critical.

00:19:10.540 --> 00:19:15.540
So if you make a change to it, or you make all the Python slower for this, that's bad.

00:19:15.540 --> 00:19:18.540
And they did make Python slower, but only 2%.

00:19:18.540 --> 00:19:22.540
And they believe that the benefits they get is actually worth it.

00:19:22.540 --> 00:19:26.540
Cause you bring in, you know, for like heavy workloads, you get actually better performance.

00:19:26.540 --> 00:19:28.540
So it's a trade off, but there it is.

00:19:28.540 --> 00:19:30.540
One of the things that was reading this article.

00:19:30.540 --> 00:19:40.540
And one of the things that confused me was, is there, is this just something internal to Python that, that it's going to happen under the hood or do I need to change my syntax in any way?

00:19:40.540 --> 00:19:41.540
Yes.

00:19:41.540 --> 00:19:42.540
I was looking for that as well.

00:19:42.540 --> 00:19:53.540
And every single thing about, I went and read the PEP and everything I remember from reading the PEP and maybe I missed something, but everything I got from the PEP was it, the C layer.

00:19:53.540 --> 00:19:59.540
It was, you know, here's the pie immortal, you know, call that you make in the C API.

00:19:59.540 --> 00:20:04.540
So what I would like to see is something where you set a decorate, like kind of like a data class.

00:20:04.540 --> 00:20:06.540
Like this thing is outside of garbage collection.

00:20:06.540 --> 00:20:14.540
This class is out or this, I don't know, in some way to say in Python, this thing is a moral for now, at least.

00:20:14.540 --> 00:20:15.540
Yeah.

00:20:15.540 --> 00:20:16.540
But I didn't see it either.

00:20:16.540 --> 00:20:22.540
It also would be good even if we could just do like, like, that would be kind of like a constant then also.

00:20:22.540 --> 00:20:28.540
We could set up some, some constants in your system that, that are immortal or something.

00:20:28.540 --> 00:20:29.540
Yeah.

00:20:29.540 --> 00:20:30.540
Okay.

00:20:30.540 --> 00:20:31.540
Yeah.

00:20:31.540 --> 00:20:41.540
Like the dictionary of a module that loads up, if you're not dynamically changing it, which you almost never do, unless you're like mocking something out, like, let it, let it be, you know, it's just tell it it's the same.

00:20:41.540 --> 00:20:42.540
Don't, don't reference combat.

00:20:42.540 --> 00:20:43.540
Yeah.

00:20:43.540 --> 00:20:53.540
I'd be curious to see in this implement, as they're implementing it, it does seem like parts of the system are going to go a little bit slower, but also parts of it are going to go faster because you don't have to do all that work, but.

00:20:53.540 --> 00:20:54.540
Exactly.

00:20:54.540 --> 00:20:55.540
Right.

00:20:55.540 --> 00:20:56.540
Yeah.

00:20:56.540 --> 00:20:57.540
You don't have to, you don't have to do a lot of stuff.

00:20:57.540 --> 00:20:58.540
Okay.

00:20:58.540 --> 00:21:00.540
Like the garbage collection cycles that happen over time, right?

00:21:00.540 --> 00:21:01.540
Yeah.

00:21:01.540 --> 00:21:04.540
These things will just be excluded from garbage collection entirely.

00:21:04.540 --> 00:21:05.540
So that's cool.

00:21:05.540 --> 00:21:10.540
So they have some graphs of what happened afterwards and the before and after and on the after in the shared memory.

00:21:10.540 --> 00:21:13.540
Well, sorry, the before it went almost to zero.

00:21:13.540 --> 00:21:20.540
Like it went from, you know, Y axis with no numbers really high to Y axis low with no numbers.

00:21:20.540 --> 00:21:22.540
But I don't know exactly what this is.

00:21:22.540 --> 00:21:33.540
Maybe a percent, but like I said, it doesn't really, really say, but after processing as few as 300 requests, it was like a 10th of the original shared memory was left.

00:21:33.540 --> 00:21:39.540
And that was it now after it's down to it's 75, 80% still shared, which is pretty excellent.

00:21:39.540 --> 00:21:40.540
Okay, cool.

00:21:40.540 --> 00:21:46.540
But as you said, this is like one of the internal core things from what I can tell.

00:21:46.540 --> 00:21:47.540
Yeah.

00:21:47.540 --> 00:21:58.540
They do say that this is foundational work for the per interpreter Gil that six, eight, four, as well as making the global interpreter lock optional and see Python seven or three.

00:21:58.540 --> 00:21:59.540
So that's why I'm not going to be able to do that.

00:21:59.540 --> 00:22:00.540
And that's why I'm not going to be able to do that.

00:22:00.540 --> 00:22:01.540
And that's why I'm not going to be able to do that.

00:22:01.540 --> 00:22:02.540
And that's why I'm not going to be able to do that.

00:22:02.540 --> 00:22:03.540
And that's why I'm not going to be able to do that.

00:22:03.540 --> 00:22:04.540
And that's why I'm not going to be able to do that.

00:22:04.540 --> 00:22:05.540
Well, I'm not going to be able to do that.

00:22:05.540 --> 00:22:06.540
I'm not going to be able to do that.

00:22:06.540 --> 00:22:07.540
I'm not going to be able to do that.

00:22:07.540 --> 00:22:08.540
I'm not going to be able to do that.

00:22:08.540 --> 00:22:09.540
I'm not going to be able to do that.

00:22:09.540 --> 00:22:10.540
I'm not going to be able to do that.

00:22:10.540 --> 00:22:11.540
I'm not going to be able to do that.

00:22:11.540 --> 00:22:12.540
I'm not going to be able to do that.

00:22:12.540 --> 00:22:13.540
I'm not going to be able to do that.

00:22:13.540 --> 00:22:14.540
I'm not going to be able to do that.

00:22:14.540 --> 00:22:15.540
I'm not going to be able to do that.

00:22:15.540 --> 00:22:16.540
I'm not going to be able to do that.

00:22:16.540 --> 00:22:17.540
I'm not going to be able to do that.

00:22:17.540 --> 00:22:18.540
I'm not going to be able to do that.

00:22:18.540 --> 00:22:19.540
I'm not going to be able to do that.

00:22:19.540 --> 00:22:20.540
I'm not going to be able to do that.

00:22:20.540 --> 00:22:22.540
So that's why it's there to support.

00:22:22.540 --> 00:22:26.540
And that's why it's relevant for some of these parallelism peps.

00:22:26.540 --> 00:22:28.540
So anyway, pretty cool.

00:22:28.540 --> 00:22:31.540
This is coming in 3.12, I guess.

00:22:31.540 --> 00:22:32.540
Nice. Cool.

00:22:32.540 --> 00:22:37.540
Well, I'd like to talk about something that I don't really think about that much in that

00:22:37.540 --> 00:22:40.540
that is doc strings for doc string formats.

00:22:40.540 --> 00:22:47.540
And I just ran across this article and I'm covering it partly just as a question to the audience.

00:22:47.540 --> 00:22:54.540
So the article is from Scott Robinson and it's called Common Doc String Formats in Python.

00:22:54.540 --> 00:22:58.540
And doc strings, people forget what they are.

00:22:58.540 --> 00:23:01.540
Like, let's say you have a function called add numbers or something.

00:23:01.540 --> 00:23:06.540
You can do, you can really do any kind of quote, but the first string in a function,

00:23:06.540 --> 00:23:09.540
if it's not assigned to a variable, is the doc string.

00:23:09.540 --> 00:23:11.540
And it's the first element.

00:23:11.540 --> 00:23:16.540
Anyway, the first line is a little, it's usually one line.

00:23:16.540 --> 00:23:19.540
one line and then maybe a space and then some other stuff.

00:23:19.540 --> 00:23:24.540
And there apparently there's several format, common formats of this.

00:23:24.540 --> 00:23:29.540
You can also, you can get access to it by the underscore doc attribute of something.

00:23:29.540 --> 00:23:37.540
So if you have a, a, a reference to a function, you can say dot dunder doc, and you can see the doc string.

00:23:37.540 --> 00:23:42.540
And a lot of like ID is use this to pop up hints and stuff.

00:23:42.540 --> 00:23:51.540
That's one of the reasons why you want to have like the first, at least the first line be an explanation that is good for somebody to see if it pops up on them and stuff.

00:23:51.540 --> 00:23:54.540
So anyway, which formats should this be?

00:23:54.540 --> 00:23:57.540
So it covers a handful of different formats.

00:23:57.540 --> 00:24:02.540
There's a restructured, restructured text doc stream format.

00:24:02.540 --> 00:24:08.540
So you've got all this like descriptions of parameters and the types and stuff.

00:24:08.540 --> 00:24:10.540
this is scary looking to me.

00:24:10.540 --> 00:24:15.540
there's the, the, let's go through next, Google doc stream format.

00:24:15.540 --> 00:24:18.540
This one makes a little more sense, but again, I don't know.

00:24:18.540 --> 00:24:21.540
it says, and it talks about the different parameters.

00:24:21.540 --> 00:24:26.540
And if, if you really have to describe them, this is probably one of my favorites is what looks pretty good.

00:24:26.540 --> 00:24:27.540
return.

00:24:27.540 --> 00:24:30.540
What, what, what, what, what is the information that it returns?

00:24:30.540 --> 00:24:36.540
what are the arguments and why some like one liner explanations, not too bad.

00:24:36.540 --> 00:24:39.540
There's a numpy scipy doc format.

00:24:39.540 --> 00:24:40.540
This is also pretty clear.

00:24:40.540 --> 00:24:44.540
maybe a little, let's compare the two.

00:24:44.540 --> 00:24:50.540
I guess this is it got an extra line because you're doing the underscore line, which is, I guess.

00:24:50.540 --> 00:24:51.540
Okay.

00:24:51.540 --> 00:24:53.540
It looks sort of, I don't know.

00:24:53.540 --> 00:24:58.540
This is a lot of space, but I would, I'm just curious if people are really using this.

00:24:58.540 --> 00:25:08.540
Looking at this, I can see the benefit of describing if it's not clear, from the name of your function, describing stuff.

00:25:08.540 --> 00:25:09.540
And I also like type hints.

00:25:09.540 --> 00:25:13.540
So this seems like a great argument for type hints because the types we,

00:25:13.540 --> 00:25:14.540
the types would be great.

00:25:14.540 --> 00:25:15.540
Just right in the right.

00:25:15.540 --> 00:25:16.540
Right.

00:25:16.540 --> 00:25:16.540
Right.

00:25:16.540 --> 00:25:17.540
Exactly.

00:25:17.540 --> 00:25:18.540
The parameters.

00:25:18.540 --> 00:25:25.540
and then if you don't have to describe the type, maybe just have variable names that are more clear.

00:25:25.540 --> 00:25:34.540
So, I, my personal preference really is, use type hints and then also, have a description.

00:25:34.540 --> 00:25:40.540
If you're going to do a doc string and it's not obvious from the name of the function, then have a description of what the function does.

00:25:40.540 --> 00:25:41.540
And that's it.

00:25:41.540 --> 00:25:48.540
and then if it's unclear to about what really what the stuff is, the behavior of different parameters, then add that.

00:25:48.540 --> 00:25:57.540
But, I, again, I'd love to hear back from people, go ahead and, send me a message on, @brianokken at faucet.org.

00:25:57.540 --> 00:25:59.540
This worked great last week.

00:25:59.540 --> 00:26:00.540
I got some great feedback.

00:26:00.540 --> 00:26:04.540
and so I'd love to hear what people are doing for their doc string formats.

00:26:04.540 --> 00:26:06.540
Do you, do you use doc string formats, Michael?

00:26:06.540 --> 00:26:09.540
I'm familiar with doc string formats and I've played with them.

00:26:09.540 --> 00:26:12.540
I like the Google one best, I think, but I'm with you.

00:26:12.540 --> 00:26:16.540
Like if you have good variable names, do you need the parameter information?

00:26:16.540 --> 00:26:19.540
If you use type hints, do you need the parameter information to say the type?

00:26:19.540 --> 00:26:23.540
If you have a return declaration with a type, do you need to have the returns?

00:26:23.540 --> 00:26:31.540
The function has a good name, like get user, you know, area angle bracket, optional user, like, oh, well, it returns a user or it returns none.

00:26:31.540 --> 00:26:33.540
How much more do you need to say about what it returns?

00:26:33.540 --> 00:26:34.540
You know?

00:26:34.540 --> 00:26:34.540
Right.

00:26:34.540 --> 00:26:49.540
Like there's a lot of it's, it's a little bit of a, a case study and yes, you want to be very thorough, but also good naming goes a really long way to like limit the amount of comments and docs you got to put onto a thing.

00:26:49.540 --> 00:26:50.540
There are times when it makes sense though.

00:26:50.540 --> 00:26:55.540
Like if, you're talking about, range or.

00:26:55.540 --> 00:26:56.540
something like that.

00:26:56.540 --> 00:27:00.540
is it inclusive of both, both numbers?

00:27:00.540 --> 00:27:05.540
and if I say one to 10, do I get one, two, three, four up to 10 or I get one, two, three, four up to nine.

00:27:05.540 --> 00:27:05.540
Right.

00:27:05.540 --> 00:27:12.540
Like those, those situations where you might need to say the non-inclusive upper bound of the rain.

00:27:12.540 --> 00:27:13.540
I don't know, whatever.

00:27:13.540 --> 00:27:14.540
Something like that.

00:27:14.540 --> 00:27:14.540
Right.

00:27:14.540 --> 00:27:15.540
Yeah.

00:27:15.540 --> 00:27:15.540
Yeah.

00:27:15.540 --> 00:27:19.540
I do like, an explanation of what's returned though.

00:27:19.540 --> 00:27:20.540
often it's not obvious.

00:27:20.540 --> 00:27:31.540
and it's, even if you are doing a type hint and you can get the type of what's returned, what's the meaning of what's returned is if that's not obvious, please put that in a doc string.

00:27:31.540 --> 00:27:32.540
But yeah, anyway, cool.

00:27:32.540 --> 00:27:35.540
I wonder, I don't, I, this is an honest question.

00:27:35.540 --> 00:27:41.540
I have no idea if you express it in any of this documentation or if the editors consume it.

00:27:41.540 --> 00:27:48.540
But what would be really awesome is if there was a way to express all possible exception types and the entire call stack, right?

00:27:48.540 --> 00:27:57.540
Like you could get a value error, you could get a database connection error, or you could get a uniqueness constraint exception with any of those three.

00:27:57.540 --> 00:28:00.540
Then you could have editors where you just hit like alt enter, right?

00:28:00.540 --> 00:28:02.540
The error handling goes, bam, bam, bam.

00:28:02.540 --> 00:28:05.540
Here's the three types of things you might catch.

00:28:05.540 --> 00:28:05.540
Right.

00:28:05.540 --> 00:28:06.540
That would be awesome.

00:28:06.540 --> 00:28:11.540
But I don't know if you can express the possible range of exceptions in there or not.

00:28:11.540 --> 00:28:13.540
Or unless you've, yeah.

00:28:13.540 --> 00:28:17.540
And especially if you're calling any extra functions within, within a function.

00:28:17.540 --> 00:28:18.540
Yeah.

00:28:18.540 --> 00:28:21.540
You don't know if it's going to raise an exception possibly, but.

00:28:21.540 --> 00:28:22.540
Possibly.

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

00:28:23.540 --> 00:28:28.540
Anyway, that's something I would see actually really useful there that you don't express in like the type information or the name or any of those things.

00:28:28.540 --> 00:28:29.540
Yeah.

00:28:29.540 --> 00:28:30.540
Cool.

00:28:30.540 --> 00:28:31.540
Yeah.

00:28:31.540 --> 00:28:32.540
Cool.

00:28:32.540 --> 00:28:33.540
Well, those are our items.

00:28:33.540 --> 00:28:34.540
Michael, do you have any extras for us?

00:28:34.540 --> 00:28:37.540
I have an extra for you in particular.

00:28:37.540 --> 00:28:38.540
How about that?

00:28:38.540 --> 00:28:39.540
Okay.

00:28:39.540 --> 00:28:40.540
Let's start with that one then.

00:28:40.540 --> 00:28:44.540
So last week you asked about GitHub releases.

00:28:44.540 --> 00:28:45.540
Who uses these?

00:28:45.540 --> 00:28:46.540
Should I be bothered?

00:28:46.540 --> 00:28:47.540
Yeah.

00:28:47.540 --> 00:28:49.540
There's this person that seems to be telling everyone on GitHub.

00:28:49.540 --> 00:28:51.540
They should use releases if they're not.

00:28:51.540 --> 00:28:52.540
Do I care?

00:28:52.540 --> 00:28:58.540
And Rhett Turnbull, who's been on talk Python to talk about building Mac apps or with Python.

00:28:58.540 --> 00:29:01.540
GitHub said there said GitHub releases questions.

00:29:01.540 --> 00:29:06.540
I use them and I like them so people can subscribe to be notified of new releases.

00:29:06.540 --> 00:29:10.540
I use GH, the GitHub command line.

00:29:10.540 --> 00:29:14.540
GitHub release create to create one of the command line every time I pushed up IPI.

00:29:14.540 --> 00:29:18.540
I'm sure this can be done as an action, but I don't push that often.

00:29:18.540 --> 00:29:19.540
So it's fine with me.

00:29:19.540 --> 00:29:21.540
Anyway, there's some feedback for you.

00:29:21.540 --> 00:29:22.540
Thanks.

00:29:22.540 --> 00:29:27.540
Yeah, I actually got quite a few people reaching out and I really appreciate it.

00:29:27.540 --> 00:29:38.540
And it did convince me that I'm going to start trying to figure it out using GitHub releases, but I also want to make sure that it's automated as much as possible.

00:29:38.540 --> 00:29:40.540
I don't want to add redundant work just for the heck of it.

00:29:40.540 --> 00:29:45.540
So you're going to set up some automation to go around and tell everyone on GitHub who doesn't have releases going yet?

00:29:45.540 --> 00:29:46.540
No.

00:29:46.540 --> 00:29:47.540
They should do releases.

00:29:47.540 --> 00:29:50.540
Think of all the contributor badges you're going to get.

00:29:50.540 --> 00:29:52.540
Yeah.

00:29:52.540 --> 00:29:53.540
I'm just kidding.

00:29:53.540 --> 00:29:57.540
All right.

00:29:57.540 --> 00:29:58.540
Let's talk about one more thing.

00:29:58.540 --> 00:30:09.540
We've heard about IPI issues where people are uploading malicious packages and a lot of times it's crypto kitties and other idiots who are doing that or researchers to like just prove a concept that it's not going to be.

00:30:09.540 --> 00:30:10.540
Prove of concept that it can be done.

00:30:10.540 --> 00:30:14.540
But Lazarus hackers who are I'm pretty sure.

00:30:14.540 --> 00:30:14.540
Yeah.

00:30:14.540 --> 00:30:25.540
North Korean state sponsored hacking group is uploaded a fake VMware VM connect library targeting it professionals.

00:30:25.540 --> 00:30:29.540
So it only had 237 downloads.

00:30:29.540 --> 00:30:38.540
But when you start to think about state actor hacking level of stuff getting installed onto your machine, that's like a at minimum format.

00:30:38.540 --> 00:30:41.540
The OS maybe just throw it in the trash.

00:30:41.540 --> 00:30:42.540
I don't know.

00:30:42.540 --> 00:30:44.540
It's like pretty bad level of being infected.

00:30:44.540 --> 00:30:45.540
So I don't know.

00:30:45.540 --> 00:30:47.540
That's I have no action or further thoughts.

00:30:47.540 --> 00:30:49.540
Just like a, Hey, that's worth checking out.

00:30:49.540 --> 00:30:50.540
Yeah.

00:30:50.540 --> 00:30:54.540
And maybe we do need to care about our, our, you know, pipeline and whatever.

00:30:54.540 --> 00:31:01.540
But yeah, the supply supply chain, but we do have the new security person, Mike, that was hired.

00:31:01.540 --> 00:31:02.540
Right.

00:31:02.540 --> 00:31:03.540
So that's excellent.

00:31:03.540 --> 00:31:04.540
Yes.

00:31:04.540 --> 00:31:05.540
Yeah.

00:31:05.540 --> 00:31:06.540
He was in the audience.

00:31:06.540 --> 00:31:07.540
So that was great.

00:31:07.540 --> 00:31:08.540
I believe it was Mike.

00:31:08.540 --> 00:31:09.540
Right.

00:31:09.540 --> 00:31:10.540
Hopefully I got the name, right?

00:31:10.540 --> 00:31:11.540
Yeah.

00:31:11.540 --> 00:31:12.540
Over to you.

00:31:12.540 --> 00:31:13.540
That's what I got.

00:31:13.540 --> 00:31:20.540
It's actually this, the, I don't know how to pronounce that J and Y J and Y, on PI, the PI bytes slack.

00:31:20.540 --> 00:31:26.540
we were, talking about using, talking about using TRS 80 computers.

00:31:26.540 --> 00:31:35.540
And I said, Hey, I remember typing in lunar lander on my TRS 80 way back when, copied it out of the back of a magazine.

00:31:35.540 --> 00:31:41.540
And he's, he said, Oh, I've got a copy, copy of, of, lunar lander that works on Python.

00:31:41.540 --> 00:31:42.540
I'm like, Oh, I want to try it.

00:31:42.540 --> 00:31:48.540
And, and I still can't, I'm going to get back to him, but, I can't get his to work.

00:31:48.540 --> 00:31:51.540
And then I looked around and there was this other cool one.

00:31:51.540 --> 00:31:54.540
lunar lander Python.

00:31:54.540 --> 00:32:01.540
I found that's a four years old and apparently it was done as part of a fundamentals of computing course.

00:32:01.540 --> 00:32:03.540
which is, which is pretty impressive.

00:32:03.540 --> 00:32:06.540
I couldn't get it to work, but their website looks great.

00:32:06.540 --> 00:32:08.540
So they have a website with it.

00:32:08.540 --> 00:32:13.540
You got attached to it with, with like a screenshots and it shows good fonts too.

00:32:13.540 --> 00:32:14.540
Yeah.

00:32:14.540 --> 00:32:15.540
Yeah.

00:32:15.540 --> 00:32:18.540
And it looks exactly like the lunar lander that I typed into my TRS 80.

00:32:18.540 --> 00:32:20.540
So I'm pretty excited about that.

00:32:20.540 --> 00:32:22.540
anyway, but I can't get that to work either.

00:32:22.540 --> 00:32:32.540
So if anybody's got like a lunar lander, copy or something that works on, works with modern Python, I would love to, to play with it.

00:32:32.540 --> 00:32:35.540
I also want to like hack with it with my daughter and stuff.

00:32:35.540 --> 00:32:40.540
So anyway, that's the only extra thing I got is, bring on the lunar lander.

00:32:40.540 --> 00:32:41.540
That's really cool.

00:32:41.540 --> 00:32:42.540
I like it.

00:32:42.540 --> 00:32:43.540
Yeah.

00:32:43.540 --> 00:32:44.540
Mike, Mike Felder is here.

00:32:44.540 --> 00:32:45.540
Fidel is here.

00:32:45.540 --> 00:32:50.540
the security guy and people are thinking him and stuff for all the security work.

00:32:50.540 --> 00:32:53.540
So just getting started, but yeah, it's, it's not an easy job.

00:32:53.540 --> 00:32:54.540
I'm sure.

00:32:54.540 --> 00:32:55.540
Yeah.

00:32:55.540 --> 00:32:56.540
And we're pretty excited.

00:32:56.540 --> 00:32:58.540
I can't think of a better person to do this job.

00:32:58.540 --> 00:32:59.540
So indeed.

00:32:59.540 --> 00:33:01.540
So shall we play some bingo?

00:33:01.540 --> 00:33:02.540
Sure.

00:33:02.540 --> 00:33:03.540
All right.

00:33:03.540 --> 00:33:04.540
This is our joke.

00:33:04.540 --> 00:33:05.540
Program or bingo.

00:33:05.540 --> 00:33:06.540
I love it.

00:33:06.540 --> 00:33:07.540
So, you know, bingo works.

00:33:07.540 --> 00:33:10.540
Everybody gets a different card with different options.

00:33:10.540 --> 00:33:16.540
Typically it's numbers, but in this case it's program or actions or statements you call out or have happened.

00:33:16.540 --> 00:33:23.540
And as they get called out, you mark them off and whoever completes a row or column or I dunno, something diagonal.

00:33:23.540 --> 00:33:25.540
I don't play that much bingo, but you win.

00:33:25.540 --> 00:33:26.540
Right.

00:33:26.540 --> 00:33:29.540
And so this is, this is a possible program or bingo card.

00:33:29.540 --> 00:33:32.540
We should come up with one, a whole bunch of them.

00:33:32.540 --> 00:33:34.540
So I'll just read you some of the options out of this card.

00:33:34.540 --> 00:33:35.540
Okay.

00:33:35.540 --> 00:33:36.540
Ryan.

00:33:36.540 --> 00:33:39.540
So we've got number one written code without comments.

00:33:39.540 --> 00:33:43.540
Everybody could check that one off for all of the C inspired language.

00:33:43.540 --> 00:33:46.540
People forgot a semi-colon at the end of a line.

00:33:46.540 --> 00:33:47.540
That's good.

00:33:47.540 --> 00:33:51.540
I can certainly relate with number three, close 12 tabs after fixing an issue.

00:33:51.540 --> 00:33:52.540
Oh yeah.

00:33:52.540 --> 00:33:53.540
Oh yeah.

00:33:53.540 --> 00:33:54.540
Also related.

00:33:54.540 --> 00:33:57.540
Number four, 20 warnings, zero errors.

00:33:57.540 --> 00:33:59.540
Works on my machine, man.

00:33:59.540 --> 00:34:00.540
Yeah, exactly.

00:34:00.540 --> 00:34:02.540
The number five is program.

00:34:02.540 --> 00:34:04.540
Didn't run on someone else's computer.

00:34:04.540 --> 00:34:05.540
Yeah.

00:34:05.540 --> 00:34:08.540
And instantiation of the works on my machine problem.

00:34:08.540 --> 00:34:11.540
And then this number six to do list greater than completed tasks.

00:34:11.540 --> 00:34:13.540
Number seven copied code from stack overflow.

00:34:13.540 --> 00:34:15.540
I'm pretty sure we can all check that one off.

00:34:15.540 --> 00:34:17.540
Close program without saving it.

00:34:17.540 --> 00:34:18.540
Okay.

00:34:18.540 --> 00:34:21.540
Number nine, ask to fix a laptop because you're a programmer.

00:34:21.540 --> 00:34:22.540
I have a problem with my computer.

00:34:22.540 --> 00:34:24.540
Like, please don't, please don't.

00:34:24.540 --> 00:34:26.540
Number 10 turned your bug into a feature.

00:34:26.540 --> 00:34:29.540
11 deleted block of code and regretted it later.

00:34:29.540 --> 00:34:32.540
Finally learned a new programming language, but never used it.

00:34:32.540 --> 00:34:33.540
Hello TypeScript.

00:34:33.540 --> 00:34:35.540
We could come up with so many of these.

00:34:35.540 --> 00:34:36.540
We should, we should totally do.

00:34:36.540 --> 00:34:37.540
We should do more.

00:34:37.540 --> 00:34:38.540
So good.

00:34:38.540 --> 00:34:39.540
Aren't they?

00:34:39.540 --> 00:34:40.540
You can just go on and on.

00:34:40.540 --> 00:34:41.540
Yeah.

00:34:41.540 --> 00:34:42.540
Yeah.

00:34:42.540 --> 00:34:47.540
You can do a backup copy of your code repository, even though it's like a hub.

00:34:47.540 --> 00:34:48.540
Yeah.

00:34:48.540 --> 00:34:50.540
Zip is my source control.

00:34:50.540 --> 00:34:51.540
Yeah.

00:34:51.540 --> 00:34:57.540
And then the, the, the, there's usually a free one in the middle that could just be a need

00:34:57.540 --> 00:34:59.540
to need to update pip.

00:34:59.540 --> 00:35:01.540
That's exactly.

00:35:01.540 --> 00:35:02.540
Pip is out of date.

00:35:02.540 --> 00:35:03.540
Yeah.

00:35:03.540 --> 00:35:04.540
Awesome.

00:35:04.540 --> 00:35:11.540
Well, as usual, pleasure to talk with you, Michael, and thank you so much Sentry for sponsoring

00:35:11.540 --> 00:35:12.540
this episode.

00:35:12.540 --> 00:35:16.540
Again, everybody check out Sentry and go to, what was that link again?

00:35:16.540 --> 00:35:17.540
Pythonbytes.fm/sentry.

00:35:17.540 --> 00:35:18.540
Thanks Brian.

00:35:18.540 --> 00:35:19.540
Thank you.

00:35:19.540 --> 00:35:20.540
Bye.

00:35:20.540 --> 00:35:21.540
See y'all.

00:35:21.540 --> 00:35:22.240
Thank you. Bye.