WEBVTT

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

00:00:04.700 --> 00:00:10.240
This is episode 195, recorded August 12th, 2020.

00:00:10.240 --> 00:00:11.220
I'm Michael Kennedy.

00:00:11.220 --> 00:00:12.260
And I am Brian Okken.

00:00:12.260 --> 00:00:15.400
And this episode is brought to you by all the cool work that we're doing.

00:00:15.400 --> 00:00:16.520
Tell you more about this.

00:00:16.520 --> 00:00:20.420
Right now, I kind of just want to think about paying attention to stuff, Brian.

00:00:20.420 --> 00:00:22.700
Maybe watching things.

00:00:22.700 --> 00:00:24.060
I'll, like, look closer.

00:00:24.060 --> 00:00:25.260
Yes, watch carefully.

00:00:25.780 --> 00:00:32.360
So, actually, this thing sent over by Preyson Daniel, he sends us a bunch of good topics and links.

00:00:32.360 --> 00:00:34.000
And this one's called Watchdog.

00:00:34.000 --> 00:00:34.920
And maybe you've heard of it.

00:00:34.920 --> 00:00:42.260
It's the foundation of some web frameworks, for example, and things like that to know if, say, a file has changed that you're editing.

00:00:42.260 --> 00:00:44.260
Does it need to auto-restart the website?

00:00:44.260 --> 00:00:46.460
So when you refresh it, it actually reruns it.

00:00:46.460 --> 00:00:47.180
Things like that.

00:00:47.180 --> 00:00:54.600
But Watchdog is a cool little library that you can use just on your own to know if something has changed.

00:00:55.240 --> 00:00:57.420
So, basically, it's a simple little API.

00:00:57.420 --> 00:00:58.880
You create this thing called an observer.

00:00:58.880 --> 00:01:03.280
And you tell it to just start watching in some way.

00:01:03.280 --> 00:01:04.160
You give it a path.

00:01:04.160 --> 00:01:06.060
It can recursively look.

00:01:06.060 --> 00:01:07.740
You can give it, like, a pattern or whatnot.

00:01:07.740 --> 00:01:15.040
And it will say, just basically start firing events back on this observer thing when stuff happens.

00:01:15.040 --> 00:01:15.740
File is created.

00:01:15.740 --> 00:01:16.420
File is deleted.

00:01:16.420 --> 00:01:17.280
File is modified.

00:01:17.280 --> 00:01:18.060
And so on.

00:01:18.060 --> 00:01:18.500
Nice.

00:01:18.500 --> 00:01:19.500
This is cool.

00:01:19.500 --> 00:01:19.800
Yeah.

00:01:19.800 --> 00:01:20.680
Isn't that cool?

00:01:20.680 --> 00:01:25.800
It also comes with a CLI script called WatchMeDo.

00:01:25.800 --> 00:01:31.580
And what you can do with WatchMeDo is just type WatchMeDo, all one word, log.

00:01:31.580 --> 00:01:36.440
And wherever your current working directory is, when you type that, it will just start watching

00:01:36.440 --> 00:01:40.080
for files that change right there, just like on the command line.

00:01:40.080 --> 00:01:40.640
Oh, okay.

00:01:40.640 --> 00:01:40.860
Cool.

00:01:40.920 --> 00:01:44.780
So, if you're, you know, you don't want to write a program, but you just happen to be somewhere

00:01:44.780 --> 00:01:46.220
and you're like, what is happening?

00:01:46.220 --> 00:01:49.640
Like, what files are being modified or being touched or being changed here?

00:01:49.640 --> 00:01:51.900
And you can just type that and boom, there it goes.

00:01:51.900 --> 00:01:52.920
That's cool, right?

00:01:52.920 --> 00:01:54.040
That actually is really cool.

00:01:54.040 --> 00:01:54.320
Yeah.

00:01:54.400 --> 00:01:59.480
We have a build process that part of it is mucking up some directories and it'd be kind

00:01:59.480 --> 00:02:00.800
of cool to use something like this.

00:02:00.800 --> 00:02:01.080
Yeah.

00:02:01.080 --> 00:02:02.020
Absolutely.

00:02:02.020 --> 00:02:07.620
And so you could just pip install WatchDog and then just type WatchMeDo space log wherever

00:02:07.620 --> 00:02:08.700
you want it to know.

00:02:08.700 --> 00:02:13.700
There's a bunch of other things it does that you can pass commands and stuff, I suppose.

00:02:13.700 --> 00:02:18.640
Like, you could ask it to recursively watch or whatever, but yeah, I haven't had a use

00:02:18.640 --> 00:02:19.120
case for that.

00:02:19.120 --> 00:02:21.880
So, but yeah, this is a cool recommendation from Preycin.

00:02:21.880 --> 00:02:22.500
Yeah, nice.

00:02:22.500 --> 00:02:27.200
The example that I think I could possibly use it for is, you know, one of the things

00:02:27.200 --> 00:02:33.260
that we do that makes Python Bytes, .fm, as well as all the Talk Python, Talk Python training

00:02:33.260 --> 00:02:40.960
sites ridiculously fast as a user is we don't require you to re-download almost any of the

00:02:40.960 --> 00:02:46.900
static content, anything JavaScript, any image in the entire site, you know, CSS, all of those

00:02:46.900 --> 00:02:49.300
things, they're cached for a year, right?

00:02:50.000 --> 00:02:55.560
And so a problem with caching stuff for a long time is if you redeploy a new version,

00:02:55.560 --> 00:02:58.080
something's wacky, right?

00:02:58.080 --> 00:02:58.980
Something is really weird.

00:02:58.980 --> 00:03:01.040
Like, I have this problem with Twitter and Firefox.

00:03:01.040 --> 00:03:06.700
I'll go there and periodically it'll just say something went wrong, can't load it, and a command

00:03:06.700 --> 00:03:11.660
R, a hard refresh always fixes it because there's probably some JavaScript file that's like out of

00:03:11.660 --> 00:03:15.040
sync with some other part of some API or some random thing like that.

00:03:15.660 --> 00:03:20.780
And so what we do to make sure that never happens is we look at every one of those static

00:03:20.780 --> 00:03:24.760
files that we have a year-long cache on and we read it and we create the hash and we put

00:03:24.760 --> 00:03:29.320
question mark hash equals the hash of the file on the end of it.

00:03:29.320 --> 00:03:32.800
So that, you know, that's a separate file.

00:03:32.800 --> 00:03:38.220
If it ever changes one character, if it changes, the hash changes and it's now a totally separate

00:03:38.220 --> 00:03:39.880
thing in the web browser cache, right?

00:03:39.880 --> 00:03:41.280
All of this is perfect.

00:03:41.280 --> 00:03:45.920
The one drawback is to make things fast, you're not rehashing all the images on every

00:03:45.920 --> 00:03:46.440
request.

00:03:46.440 --> 00:03:49.540
Is it just says, have I seen this file before?

00:03:49.540 --> 00:03:51.240
Do I already compute the hash?

00:03:51.240 --> 00:03:52.200
Just use it, right?

00:03:52.200 --> 00:03:52.940
So that's fine.

00:03:52.940 --> 00:03:58.920
But that means that little hash refresh trick only really works if I restart the website.

00:03:58.920 --> 00:04:01.600
If like, say, only a CSS file changed.

00:04:01.600 --> 00:04:05.960
I could use this watchdog to watch all the static files that we're hashing.

00:04:05.960 --> 00:04:09.080
If any of them change, just instantly recompute the hash.

00:04:09.720 --> 00:04:10.300
That's it.

00:04:10.300 --> 00:04:16.020
So that would allow me to do like push deploys of just, you know, static content changes without

00:04:16.020 --> 00:04:17.920
kicking the website at all.

00:04:17.920 --> 00:04:20.860
And it would just magically like redetect those and start rolling.

00:04:20.860 --> 00:04:23.220
I think I might start using watchdog for that.

00:04:23.220 --> 00:04:25.260
Anyway, that's my use case that makes me excited.

00:04:25.260 --> 00:04:29.560
And I'm glad you pronounced watch me do because I looked at it and I went watch meadow.

00:04:29.560 --> 00:04:30.600
That's a weird name.

00:04:30.600 --> 00:04:31.520
That is a weird.

00:04:31.520 --> 00:04:33.140
I think it's a watch me do.

00:04:33.140 --> 00:04:34.560
Watch me do is better.

00:04:34.560 --> 00:04:34.940
Yeah.

00:04:34.940 --> 00:04:35.200
Yeah.

00:04:35.200 --> 00:04:36.520
You know what else is weird?

00:04:36.520 --> 00:04:39.560
Weird HTTP status codes.

00:04:39.560 --> 00:04:42.720
Like I'm very familiar with 400 bad requests.

00:04:42.720 --> 00:04:48.700
That's when somebody's created an API and I talked to it badly and they've created the API correctly.

00:04:48.700 --> 00:04:54.660
Or I get a 500 where there is their stuff has crashed because I sent them something bad and

00:04:54.660 --> 00:04:56.300
they've written their API badly.

00:04:56.300 --> 00:05:00.160
But somewhere in between there lives some odd thing.

00:05:00.160 --> 00:05:01.060
Right?

00:05:01.060 --> 00:05:01.520
Yes.

00:05:01.520 --> 00:05:04.340
Have you heard of error code 418 before?

00:05:04.340 --> 00:05:05.480
I'm a teapot.

00:05:07.000 --> 00:05:08.480
This is just great.

00:05:08.480 --> 00:05:09.980
So I love it.

00:05:09.980 --> 00:05:10.580
I love it.

00:05:10.580 --> 00:05:11.760
Status code 418.

00:05:11.760 --> 00:05:13.000
I'm a teapot.

00:05:13.000 --> 00:05:18.140
Any attempt to brew a coffee with a teapot should result in an error code 418.

00:05:18.140 --> 00:05:18.940
I'm a teapot.

00:05:18.940 --> 00:05:21.980
The resulting entity may be short and stout.

00:05:21.980 --> 00:05:25.760
So the resulting entity may be short and stout.

00:05:25.760 --> 00:05:26.180
I love it.

00:05:26.260 --> 00:05:29.620
This actually got brought up in a conversation I was having this morning.

00:05:29.620 --> 00:05:32.700
A colleague of mine, Andy Howe, suggested it.

00:05:32.700 --> 00:05:36.340
He said, so when is Python 3.9 going to come out?

00:05:36.340 --> 00:05:37.660
Because hasn't it been a while?

00:05:37.660 --> 00:05:43.580
And as a reminder to everybody, Python 3.9 candidate release or the release candidate one

00:05:43.580 --> 00:05:46.400
or RCCR or whatever is out now.

00:05:46.620 --> 00:05:47.840
So you can play with it.

00:05:47.840 --> 00:05:49.580
It's probably, I've been using it.

00:05:49.580 --> 00:05:50.440
It's safe to use.

00:05:50.440 --> 00:05:57.380
But the schedule for the release, final release is in October, I believe.

00:05:57.380 --> 00:06:02.800
And then after that, bug fixes, releases every month are planned, if there are any.

00:06:03.380 --> 00:06:10.640
Andy said, you know, my favorite enhancement for Python 3.9 is this 418.

00:06:10.640 --> 00:06:11.380
I'm a teapot.

00:06:11.380 --> 00:06:13.400
This is new in Python 3.9.

00:06:13.400 --> 00:06:18.480
HTTP library was missing the status code 418.

00:06:18.480 --> 00:06:19.200
I'm a teapot.

00:06:19.200 --> 00:06:20.940
And now it has it in there.

00:06:20.940 --> 00:06:23.120
But wow, I've got some links for you.

00:06:23.120 --> 00:06:32.180
Because in the show notes, this is referenced from HTCPCP, which is Hypertext Coffee Pot Control Protocol.

00:06:33.060 --> 00:06:37.560
And this came out in 1998 as an April Fool's joke.

00:06:37.560 --> 00:06:40.360
And then it's kind of part of it now.

00:06:40.360 --> 00:06:42.880
So it's part of HTTP, sort of.

00:06:42.880 --> 00:06:45.220
Another fun error code.

00:06:45.220 --> 00:06:54.500
So the document, the entire document for HTCPCP, says that most error codes share the same status codes as HTTP.

00:06:54.500 --> 00:06:57.340
However, 418 is separate.

00:06:57.340 --> 00:07:00.420
But also now HTTP can use that also.

00:07:00.620 --> 00:07:03.720
But also 406, not acceptable.

00:07:03.720 --> 00:07:12.920
So 406 is this response code may be returned if the operator of the coffee pot cannot comply with the accept addition request.

00:07:12.920 --> 00:07:14.800
Unless the request was in ahead.

00:07:14.800 --> 00:07:20.520
So, and it should return the list of possible coffee additions.

00:07:21.020 --> 00:07:23.160
This is bizarre that this is in the world.

00:07:23.160 --> 00:07:25.580
This is awesome.

00:07:25.580 --> 00:07:26.360
I really love it.

00:07:26.360 --> 00:07:29.620
I don't realize, I didn't realize it had been taken so far as this.

00:07:29.620 --> 00:07:30.240
This is great.

00:07:30.240 --> 00:07:39.080
And, you know, if you go and look at the thing you link to, the Hypertext Coffee Pot Control Protocol, HTCPCP slash 1.0.

00:07:39.400 --> 00:07:42.840
The whole memo describes so much of this thing.

00:07:43.040 --> 00:07:46.620
And it even talks about things like crossing firewalls.

00:07:46.620 --> 00:07:49.560
Like, modern coffee pots do not use fire.

00:07:49.560 --> 00:07:52.020
However, a firewall is useful in protecting it.

00:07:52.020 --> 00:07:55.340
It also addresses the security considerations.

00:07:55.340 --> 00:07:58.260
Anyone who gets between me and my morning coffee should be insecure.

00:07:58.260 --> 00:08:12.360
Filtration is not a good virus protection method.

00:08:12.360 --> 00:08:13.460
I mean, it just goes on and on.

00:08:13.460 --> 00:08:14.280
It's beautiful.

00:08:14.280 --> 00:08:14.960
Yes.

00:08:14.960 --> 00:08:21.500
And there's a security layer that I forgot about that's funny, too.

00:08:21.500 --> 00:08:22.400
That's part of this.

00:08:22.400 --> 00:08:23.920
But I can't find it right now.

00:08:23.920 --> 00:08:24.500
Yeah, no worries.

00:08:24.500 --> 00:08:36.240
I threw in a quick link also to this place called HTPstatuses.com, which this is a slightly more serious take, although it does, of course, include the coffee pot.

00:08:36.240 --> 00:08:41.480
But it's just, if you were like, what the heck should I be doing, you know, in this situation?

00:08:41.480 --> 00:08:42.860
Like, here's the error codes here.

00:08:42.860 --> 00:08:46.820
So, and if you just click on them, it gives you a, like, really nice summary.

00:08:46.820 --> 00:08:52.180
Like, if you click on 403, for example, it talks about when it's used and when it's, like, how it compares to 404.

00:08:52.380 --> 00:08:58.760
And then also how that reference code is set up as an enumeration in different languages.

00:08:58.760 --> 00:09:02.160
So, for example, in Go, it's HTTP.status forbidden.

00:09:02.160 --> 00:09:04.240
In Rails, it's colon forbidden.

00:09:04.240 --> 00:09:07.880
And then Python 3, it's HTTP.htpstatuses.forbidden.

00:09:07.880 --> 00:09:08.720
And things like that.

00:09:08.760 --> 00:09:15.980
So, it tells you, like, the language version instead of typing it all in yourself and having magic strings and numbers everywhere.

00:09:15.980 --> 00:09:16.560
Yeah.

00:09:16.560 --> 00:09:23.740
So, it does look like, I don't know what Symfony is, but Symfony and Go do also support 418.

00:09:23.740 --> 00:09:25.060
Status team.

00:09:25.060 --> 00:09:26.380
Beautiful.

00:09:26.380 --> 00:09:29.280
We're on par with Go in terms of the internet now.

00:09:29.280 --> 00:09:30.040
Very good.

00:09:30.040 --> 00:09:30.940
That was a good one.

00:09:30.940 --> 00:09:33.020
It almost could have been the joke, but I like it.

00:09:33.020 --> 00:09:33.500
All right.

00:09:33.500 --> 00:09:40.020
Also, things that I like is that we get a chance to create amazing stuff to help people get better with Python out there.

00:09:40.440 --> 00:09:45.080
So, over at Talk Python Training, we have three new courses coming very soon.

00:09:45.080 --> 00:09:46.780
We have Getting Started with Data Science.

00:09:46.780 --> 00:09:48.880
We have Moving from Excel to Python.

00:09:48.880 --> 00:09:54.880
And we have Diving into Python Memory Management and Optimizing Your Programs around that.

00:09:54.880 --> 00:09:57.860
All three of those are coming within probably a month or so.

00:09:57.860 --> 00:10:02.680
So, if you want to get notified about that, just visit training.talkpython.fm.

00:10:02.680 --> 00:10:07.160
And right at the front, there's a little email place you can enter your email address to get notified.

00:10:07.160 --> 00:10:08.240
How about you?

00:10:08.240 --> 00:10:10.700
I wanted to highlight Test and Code.

00:10:10.700 --> 00:10:13.220
So, pytest 6 is out.

00:10:13.220 --> 00:10:18.320
So, Test and Code is the other podcast I do at testandcode.com.

00:10:18.320 --> 00:10:23.700
And I had talked last week that there was going to be a pytest 6 episode.

00:10:23.700 --> 00:10:30.300
And instead of doing it just by myself, I contacted Anthony Sotilli and had him come on the show.

00:10:30.300 --> 00:10:33.360
And so, we BS about stuff for about an hour.

00:10:33.360 --> 00:10:35.160
Some of it's actual content.

00:10:35.160 --> 00:10:39.660
So, I'm really trying to get – I'd really like to have the shorter episodes on there.

00:10:39.660 --> 00:10:42.520
But, you know, I get to talking with somebody and it's just fun.

00:10:42.520 --> 00:10:44.500
Just keeps going.

00:10:44.500 --> 00:10:44.800
Awesome.

00:10:44.800 --> 00:10:45.200
Yeah.

00:10:45.200 --> 00:10:45.960
It's definitely a good one.

00:10:45.960 --> 00:10:46.760
People should check it out.

00:10:46.760 --> 00:10:48.000
What do we got next?

00:10:48.000 --> 00:10:49.380
We talked about Pydantic.

00:10:49.380 --> 00:10:50.280
Right?

00:10:50.280 --> 00:10:52.180
So, Pydantic is a cool library.

00:10:52.180 --> 00:10:54.520
You know, it's something I really just need to start using.

00:10:54.980 --> 00:10:59.140
Like, I haven't created any new projects that probably really deserve this.

00:10:59.140 --> 00:11:02.780
But I think it's definitely one of those things that I want to start using.

00:11:02.780 --> 00:11:04.080
Because it's just so slick.

00:11:04.080 --> 00:11:07.120
The ability to say, I have these models.

00:11:07.120 --> 00:11:08.220
They have these types.

00:11:08.220 --> 00:11:09.560
You can validate them.

00:11:09.560 --> 00:11:11.240
You can auto-convert between them.

00:11:11.240 --> 00:11:11.820
And so on.

00:11:11.820 --> 00:11:12.000
Right?

00:11:12.040 --> 00:11:14.060
So, we talked about that not too long ago, actually.

00:11:14.060 --> 00:11:22.540
However, Andy Shapiro sent over a heads up about a new feature that's in the beta version of Pydantic that's coming.

00:11:22.540 --> 00:11:25.400
That makes me pretty excited, actually.

00:11:25.400 --> 00:11:26.060
I don't know.

00:11:26.060 --> 00:11:27.260
We'll see how people feel about this.

00:11:27.260 --> 00:11:28.200
But I'm excited about it.

00:11:28.840 --> 00:11:31.300
I'm excited because I'm a fan of type hints.

00:11:31.300 --> 00:11:31.940
Yeah, me too.

00:11:31.940 --> 00:11:32.580
I love type hints.

00:11:32.580 --> 00:11:33.080
Yeah.

00:11:33.080 --> 00:11:39.400
I love them mostly because the way they make the editor help me write code.

00:11:39.400 --> 00:11:44.340
Instead of going and saying, oh, how do I do this thing with this library?

00:11:44.340 --> 00:11:45.200
Right?

00:11:45.200 --> 00:11:50.900
If I just say the type of this thing is one of the objects out of that library and I hit dot, boom.

00:11:50.900 --> 00:11:53.120
The editor shows me all the stuff I can do.

00:11:53.120 --> 00:11:55.760
It just keeps me in flow and working on what I need to.

00:11:55.760 --> 00:11:59.620
So, I love type hints mostly for that, but also for the validation.

00:11:59.620 --> 00:12:10.540
One of the things they are like, but they do not do, is they are not like static typing in other programming languages where somehow that verifies what's being passed.

00:12:10.540 --> 00:12:10.820
Right?

00:12:10.820 --> 00:12:11.180
Yeah.

00:12:11.180 --> 00:12:19.000
So, like, for example, if I have a function, it says it takes an integer, an age colon int, and that's what it says it takes.

00:12:19.000 --> 00:12:23.020
But then I go and I write code and I give it quote seven instead of the number seven.

00:12:23.020 --> 00:12:23.820
That's fine.

00:12:23.820 --> 00:12:24.940
Python's like, yeah, that's cool.

00:12:24.940 --> 00:12:27.140
You probably don't know what you're doing, but whatever.

00:12:27.140 --> 00:12:28.280
We're just going to let it fly, right?

00:12:28.280 --> 00:12:33.240
Well, with Pydantic, there's this new type annotation validator.

00:12:33.240 --> 00:12:39.420
And so, what you can do is you can say, for this function, it has type annotations, and I want those to mean something.

00:12:39.420 --> 00:12:40.200
Oh, okay.

00:12:40.200 --> 00:12:40.480
Okay.

00:12:40.480 --> 00:12:44.140
So, it gives it basically that it's not runtime behavior in the static languages.

00:12:44.140 --> 00:12:45.680
It's a compile error, right?

00:12:45.680 --> 00:12:51.220
Your argument string cannot be converted to enter whatever the compilation error happens to be.

00:12:51.760 --> 00:12:53.400
But it would give you the runtime equivalent.

00:12:53.400 --> 00:13:03.640
So, all you have to do is you have a regular Python function, and it has regular types, just like it would, you know, s colon str, count colon int, that type of thing.

00:13:04.500 --> 00:13:06.460
And you can just work with it.

00:13:06.460 --> 00:13:15.400
It's a little bit smarter than the compiler, maybe of, say, like C++ or C#, though, in that what you do is you just say, at validate arguments.

00:13:15.400 --> 00:13:17.900
So, you give it a decorator that validates the arguments.

00:13:18.400 --> 00:13:21.160
And not only does it validate, but it will convert if it can.

00:13:21.160 --> 00:13:23.840
So, for example, I'll put an example in our show notes.

00:13:23.840 --> 00:13:25.120
There's a function called repeat.

00:13:25.120 --> 00:13:32.420
It takes a string and a number, and it's just going to echo out that string however many times that number exists, right?

00:13:32.420 --> 00:13:38.280
So, you can say repeat, quote, hello, comma, three, and it'll print hello three times.

00:13:38.280 --> 00:13:39.320
Super simple.

00:13:39.520 --> 00:13:43.480
That passes the validation precisely because it takes a string and an integer.

00:13:43.480 --> 00:13:52.360
But you can also say repeat, hello, comma, quote, four, and it'll still print out hello four times because it can take the string four and make it an integer four.

00:13:52.360 --> 00:13:53.740
Oh, that's cool.

00:13:53.740 --> 00:13:54.020
Right?

00:13:54.020 --> 00:14:07.720
But if I say repeat, hello, comma, goodbye, boom, exception, validation error, you know, the value is not a valid integer, type equals type error integer or whatever, like some message there, right?

00:14:07.920 --> 00:14:14.420
So, it says the count parameter is not and cannot be converted to the type specified by the type annotation.

00:14:14.420 --> 00:14:15.760
Oh, yeah, this is cool.

00:14:15.760 --> 00:14:16.560
How do you feel about this?

00:14:16.560 --> 00:14:22.300
I obviously don't want runtime typing for all of Python code.

00:14:22.300 --> 00:14:23.980
It's not, I don't want it.

00:14:23.980 --> 00:14:28.500
But for special places, like maybe around your API.

00:14:28.500 --> 00:14:29.200
Exactly.

00:14:29.200 --> 00:14:32.360
The boundary of libraries, like stuff going in there.

00:14:32.360 --> 00:14:32.600
Yeah.

00:14:32.600 --> 00:14:34.900
You're like, please don't send me the wrong data.

00:14:34.900 --> 00:14:37.420
Like, what is your other alternative, right?

00:14:37.420 --> 00:14:44.400
If you really want to validate that, you have to do is instance of an int or try to cast it to an int.

00:14:44.400 --> 00:14:47.480
And you've got to raise your own exception type and all that kind of stuff.

00:14:47.480 --> 00:14:50.260
You're already going to have to do that work if you're writing a good API.

00:14:50.800 --> 00:15:00.440
Or you're going to send out weird errors like int does not have, you know, type int does not have function split or some weird thing.

00:15:00.440 --> 00:15:07.420
And people have to realize like, oh, what that means is you type some kind of, you send a number where a string value is accepted, right?

00:15:07.500 --> 00:15:13.940
So this, if you really do depend on the types that you specify in your type annotation, this seems like a good idea to me.

00:15:13.940 --> 00:15:16.920
The one drawback is this cannot make your code faster.

00:15:16.920 --> 00:15:18.460
Right?

00:15:18.720 --> 00:15:25.660
If it's doing both validation and type conversion in front of your code, it can't be faster than just not doing that.

00:15:25.920 --> 00:15:27.040
But it might make your development faster.

00:15:27.040 --> 00:15:27.880
It's not always about speed.

00:15:27.880 --> 00:15:29.160
Exactly.

00:15:29.160 --> 00:15:30.600
And it may make your sanity.

00:15:30.600 --> 00:15:30.980
Yeah.

00:15:30.980 --> 00:15:42.940
So one of the ways people have gotten around this in the past is instead of, is like for an example, doing, instead of trying to validate parameters to a function at an API level,

00:15:42.940 --> 00:15:52.600
I have the parameters bundled into like an attrs object and have attrs validators written because attrs does a...

00:15:52.600 --> 00:15:53.120
Right, right.

00:15:53.120 --> 00:15:56.660
Put it into a validated object type and then pass that thing over.

00:15:56.660 --> 00:15:56.920
Yeah.

00:15:56.920 --> 00:15:57.220
Yeah.

00:15:57.220 --> 00:15:57.420
Gotcha.

00:15:57.420 --> 00:15:59.300
Which is kind of what this is.

00:15:59.300 --> 00:15:59.640
Yeah.

00:15:59.640 --> 00:16:00.580
But without doing it.

00:16:00.580 --> 00:16:01.100
This is cool.

00:16:01.100 --> 00:16:01.380
Yeah.

00:16:01.380 --> 00:16:01.880
I like it.

00:16:01.880 --> 00:16:02.120
Yeah.

00:16:02.120 --> 00:16:02.620
Very cool.

00:16:02.620 --> 00:16:03.320
I like it too.

00:16:03.320 --> 00:16:06.000
I was leaning Pydantically previously.

00:16:06.000 --> 00:16:07.500
This makes me lean more that way.

00:16:07.500 --> 00:16:07.880
I like it.

00:16:07.880 --> 00:16:08.300
All right.

00:16:08.300 --> 00:16:12.920
So one of the things that's really cool is, you know, we've had a lot of conversations about is Python fast.

00:16:12.920 --> 00:16:13.600
Is it slow?

00:16:13.600 --> 00:16:18.100
Is it fast for coming up with programs that work?

00:16:18.100 --> 00:16:19.620
Does it execute fast?

00:16:19.620 --> 00:16:23.780
Should you use libraries like Cython or rewrite some stuff in Rust?

00:16:23.780 --> 00:16:33.140
But Anthony Shaw, he took it to another level, like further down than even something like rewrite bits in C or compile Python to C or something.

00:16:33.140 --> 00:16:33.780
Yeah.

00:16:33.780 --> 00:16:38.860
I think this is maybe an example of Anthony just having too much time in his hands.

00:16:38.860 --> 00:16:39.820
I think maybe.

00:16:40.280 --> 00:16:48.120
So Anthony wrote a, I just tried it this morning, a project called PyMult, P-Y-M-U-L-T.

00:16:48.120 --> 00:16:49.660
You can pip install it.

00:16:49.660 --> 00:16:52.520
And it just multiplies numbers.

00:16:52.520 --> 00:16:56.020
And it only works for positive integers or negative integers.

00:16:56.020 --> 00:16:59.860
It just doesn't do, it doesn't ever display negative numbers.

00:16:59.860 --> 00:17:06.060
Anyway, regardless of that, it's an extension for Python written in assembly.

00:17:06.680 --> 00:17:08.240
Because, why not?

00:17:08.240 --> 00:17:09.200
And because of Anthony.

00:17:09.200 --> 00:17:14.040
As in like MV and, you know, add like the assembly language.

00:17:14.040 --> 00:17:18.600
That's the foundation of basically every other programming language?

00:17:18.600 --> 00:17:19.020
Yeah.

00:17:19.160 --> 00:17:27.920
In Anthony's Twitter announcement, he says, after a series of highly questionable life decisions, my Python extension written in pure assembly is now on PyPI.

00:17:28.400 --> 00:17:31.880
It required an assembly extension for disk utils.

00:17:31.880 --> 00:17:34.220
He also wrote a GitHub action support.

00:17:34.220 --> 00:17:39.880
So it's running CICD and testing with pytest above and beyond, over the top.

00:17:39.880 --> 00:17:41.780
But there is some coolness of it.

00:17:41.840 --> 00:17:48.140
So it's a proof of concept to demonstrate how to create a Python extension in 100% assembly.

00:17:48.140 --> 00:17:52.540
And then how to write a, you know, how to link those up.

00:17:52.540 --> 00:17:57.680
How to call a C API and create a PyObject and parse PyTubule and stuff like that.

00:17:57.680 --> 00:18:05.480
Basically all the stuff you have to do to get point parameters back and values out of an extension written in assembly.

00:18:06.200 --> 00:18:08.480
And yeah, it's interesting.

00:18:08.480 --> 00:18:10.260
So I like it actually.

00:18:10.260 --> 00:18:10.580
Yeah.

00:18:10.580 --> 00:18:13.460
And anyone wants to know what the code looks like.

00:18:13.460 --> 00:18:23.320
It's like move racks comma X, imol, qword of Y, move result to racks, move eddy to result.

00:18:23.320 --> 00:18:24.460
Like it's, yeah.

00:18:24.460 --> 00:18:28.580
But then you get a call pylong from long, which is kind of a cool thing.

00:18:28.580 --> 00:18:35.420
So there's this like interesting mix between the just pure assembly language and the C data types of CPython.

00:18:35.420 --> 00:18:44.400
On a serious note though, anybody wanting to learn a little bit of assembly or something, it's not like often you need some sort of environment to try it out in.

00:18:44.400 --> 00:18:48.940
Having some way to link Python and assembly is kind of neat actually.

00:18:48.940 --> 00:18:50.620
So I'm grateful for that.

00:18:50.620 --> 00:18:51.480
You're right.

00:18:51.480 --> 00:18:52.440
Some of these commands.

00:18:52.440 --> 00:18:55.140
I mean, I wrote some assembly in college.

00:18:55.140 --> 00:18:56.460
That was a long time ago.

00:18:56.460 --> 00:18:56.780
Yeah.

00:18:56.780 --> 00:18:59.700
Well, you had to, Anthony, because that's some impressive stuff.

00:18:59.700 --> 00:18:59.920
Yep.

00:18:59.920 --> 00:19:01.780
Would you say it's easy though?

00:19:01.780 --> 00:19:02.980
No.

00:19:02.980 --> 00:19:03.540
No.

00:19:03.540 --> 00:19:04.280
That's hard mode.

00:19:04.280 --> 00:19:04.680
Yeah.

00:19:04.680 --> 00:19:07.260
You know what actually is not as easy, I think, as it should be.

00:19:07.260 --> 00:19:08.660
And it's honestly just bizarre.

00:19:08.660 --> 00:19:19.400
Our properties in Python, as in at property, some function return some value converts what looks like a function call over to something that looks like field access.

00:19:19.400 --> 00:19:19.700
Right.

00:19:19.700 --> 00:19:19.920
Yeah.

00:19:19.980 --> 00:19:28.920
But why does it have to have this bizarre sequence of conventions where I have an at property and then a function that has a name?

00:19:28.920 --> 00:19:29.200
Okay.

00:19:29.200 --> 00:19:31.120
That defines the name of the property.

00:19:31.120 --> 00:19:31.780
That makes sense.

00:19:32.180 --> 00:19:43.680
But then the subsequent thing, if I want to be able to set that, I have to say, you know, if the property was a, then I have to say decorator a dot setter and also have a function that is called a.

00:19:44.160 --> 00:19:45.960
Like the a dot setter stuff is weird.

00:19:45.960 --> 00:19:50.100
And then the order of the setter varies as well.

00:19:50.100 --> 00:19:50.500
Right.

00:19:50.500 --> 00:19:52.600
It has to be, or is constrained.

00:19:52.600 --> 00:19:54.300
It has to be after the property a.

00:19:54.300 --> 00:19:58.860
And what I've found also is that you can run into issues with inheritance.

00:19:59.620 --> 00:20:06.640
I think if the property is defined in the base class, you try to create a setter on a drive class, things don't work right as well, which is all kinds of weird.

00:20:06.640 --> 00:20:06.820
Right.

00:20:06.820 --> 00:20:09.580
So there's just like, this is supposed to make life easy.

00:20:09.580 --> 00:20:10.880
Why is this so complicated?

00:20:10.880 --> 00:20:17.860
Like surely there was just another alternative that was like easier to do, to implement as well.

00:20:17.860 --> 00:20:21.980
Anyway, it's always kind of been one of the bizarro things of Python.

00:20:21.980 --> 00:20:23.640
That said, I love properties.

00:20:23.640 --> 00:20:27.580
I love that you can do like lazy calculation with them.

00:20:27.580 --> 00:20:28.820
You don't have to store them.

00:20:28.900 --> 00:20:29.840
It's part of the memory.

00:20:29.840 --> 00:20:33.640
If they can be recomputed from the values, there's a lot of good reasons to have them.

00:20:33.640 --> 00:20:39.780
So Rude Vanderham sent over this cool project, which he created called easy property.

00:20:39.780 --> 00:20:41.200
And do you know what?

00:20:41.200 --> 00:20:42.860
It's easier than regular properties.

00:20:42.860 --> 00:20:43.260
Okay.

00:20:43.260 --> 00:20:44.600
I think that's why he named it that.

00:20:44.600 --> 00:20:58.580
So the idea is, you know what you could do instead of have this property and then at a dot setter or a dot deleter is you could just say there's a at getter, at setter,

00:20:58.580 --> 00:21:00.860
at deleter on the thing.

00:21:01.100 --> 00:21:04.320
And it doesn't matter what order they are or if they're all defined.

00:21:04.320 --> 00:21:06.620
Like for example, you can't have a setter without a getter.

00:21:06.620 --> 00:21:09.420
Now conceptually, you should never really do that.

00:21:09.420 --> 00:21:14.200
But just, you know, syntactically, like those things have to be defined there.

00:21:14.320 --> 00:21:19.400
And like I said, the sort of base class, drive class type of thing, it gets wonky as well.

00:21:19.400 --> 00:21:21.800
So with this, you just create a function.

00:21:21.800 --> 00:21:24.460
The function name is the name of the property.

00:21:24.800 --> 00:21:26.820
And then you put at getter on it.

00:21:26.820 --> 00:21:30.820
And that makes it the kind that is, you know, the getter property.

00:21:30.820 --> 00:21:33.160
If you want to have one, you can set, you say at setter.

00:21:33.160 --> 00:21:36.120
The order doesn't matter or anything like that.

00:21:36.120 --> 00:21:36.480
Nice.

00:21:36.480 --> 00:21:37.060
Isn't that nice?

00:21:37.060 --> 00:21:37.400
Yeah.

00:21:37.540 --> 00:21:41.800
So there's a cool little example that he wrote.

00:21:41.800 --> 00:21:45.600
You know, you can do them separately, which is probably what I would recommend and do.

00:21:45.600 --> 00:21:47.700
But you can also have an at getter setter.

00:21:48.440 --> 00:21:55.460
So you can have one function whose job is to both be the getter and the setter operation of the property.

00:21:55.460 --> 00:22:03.880
And then the way it works is just the value is set to be like some default value, which is what happens in the, you know, in the get version.

00:22:03.880 --> 00:22:06.040
You can have an at documenter.

00:22:06.040 --> 00:22:07.400
You can have an at documenter.

00:22:07.400 --> 00:22:13.280
So you can also have documentation for your property.

00:22:13.280 --> 00:22:16.220
And there's a little function that will come up and do that.

00:22:16.440 --> 00:22:19.000
So anyway, it's, it looks pretty nice to me.

00:22:19.000 --> 00:22:23.700
It's not one of those things that's going to be, you're taking a heavy dependency upon to give it a try.

00:22:23.700 --> 00:22:24.120
Right.

00:22:24.120 --> 00:22:25.860
It's not like a, a runtime thing.

00:22:25.860 --> 00:22:31.660
Like for example, that validate arguments, that's in between every time you call a function all the time, all the time.

00:22:31.660 --> 00:22:31.800
Right.

00:22:31.800 --> 00:22:36.260
So like this is the type of thing, like if it's going to work, it's going to work clearly, or it's just not going to work at all.

00:22:36.260 --> 00:22:38.220
So give it a try and see if it makes you happy.

00:22:38.220 --> 00:22:42.200
And if it sparks joy, you can have an at getter.

00:22:42.200 --> 00:22:44.280
And I like the syntax better than properties.

00:22:44.280 --> 00:22:45.460
Just more sense.

00:22:45.460 --> 00:22:45.680
Yeah.

00:22:45.800 --> 00:22:47.980
And you know, I think at property is just fine.

00:22:47.980 --> 00:22:49.300
Like, okay, that totally.

00:22:49.300 --> 00:22:54.800
But you know, at property name dot setter, like that just drives me.

00:22:54.800 --> 00:23:00.580
It's just so bizarre and weird in the ordering and the dependencies of it existing in the same class hierarchy level.

00:23:00.580 --> 00:23:01.620
Yeah.

00:23:01.620 --> 00:23:02.240
Don't get me started.

00:23:02.240 --> 00:23:03.120
So this is cool.

00:23:03.120 --> 00:23:03.780
I like it.

00:23:03.780 --> 00:23:06.960
Thanks for developing that and sending that over.

00:23:07.160 --> 00:23:11.600
So we talked about assembly and properties and decorators and stuff.

00:23:11.720 --> 00:23:16.540
So if anybody's left listening to this podcast, we do have more to talk about.

00:23:16.540 --> 00:23:17.660
Let's talk about recursion.

00:23:17.660 --> 00:23:18.500
No, just kidding.

00:23:18.500 --> 00:23:22.140
I couldn't resist highlighting the last topic.

00:23:22.140 --> 00:23:31.160
So there was an article by Ryan Howard that was on the test project.io blog called non-blocking assertion failures with pytestCheck.

00:23:31.220 --> 00:23:36.860
And I had to highlight it because it's really the first time anybody's ever written an article about something I wrote.

00:23:36.860 --> 00:23:38.320
So that's neat.

00:23:38.320 --> 00:23:38.660
Yeah, very cool.

00:23:38.780 --> 00:23:50.540
So pytestCheck is a library that allows you to do multiple failures within a test, mostly because assert normally uses asserts, but asserts stop after the first failure.

00:23:50.540 --> 00:23:52.120
And sometimes you want more.

00:23:52.120 --> 00:23:55.000
And I never really thought about the different use cases.

00:23:55.000 --> 00:24:04.640
But so Ryan has the use case of using it with Selenium because sometimes when you're testing a page coming back, you might have to test multiple aspects of it.

00:24:04.980 --> 00:24:12.780
His example was what's the content of some field and also if the URL is correct or something.

00:24:12.780 --> 00:24:28.340
And I think with like a Selenium or some sort of web test, that totally makes sense because you'd have things like you want to check the error code and content and whether somebody's name shows up, then a whole bunch of stuff you could check and having multiple things.

00:24:28.340 --> 00:24:28.600
Right.

00:24:28.600 --> 00:24:35.440
You don't necessarily have just one assertion that captures all of the essence of what you're trying to determine, right?

00:24:35.440 --> 00:24:35.700
Yeah.

00:24:35.700 --> 00:24:41.160
And so I also linked to the pytestCheck library and then or plugin.

00:24:41.720 --> 00:24:48.640
And then also an article that I wrote back and way back in 2015 where I started thinking about this and thinking how to solve it.

00:24:48.640 --> 00:24:49.160
Okay.

00:24:49.160 --> 00:24:49.560
Yeah.

00:24:49.560 --> 00:24:50.580
Yeah.

00:24:50.580 --> 00:24:51.000
Very cool.

00:24:51.000 --> 00:24:51.940
Nice article, right?

00:24:51.940 --> 00:25:01.280
And then I also wanted to do a public service announcement that because both Ryan and Anthony got this wrong, there are no capital letters in pytest.

00:25:01.280 --> 00:25:01.740
So.

00:25:01.740 --> 00:25:02.200
Hold on.

00:25:02.200 --> 00:25:02.460
Hold on.

00:25:02.460 --> 00:25:02.580
Hold on.

00:25:02.580 --> 00:25:03.140
Let me try this.

00:25:03.140 --> 00:25:03.800
Let me just.

00:25:03.800 --> 00:25:04.400
Yeah.

00:25:04.400 --> 00:25:04.800
Okay.

00:25:04.800 --> 00:25:05.500
On this one.

00:25:05.500 --> 00:25:11.920
But if I go over to Word and I type pytest is a testing framework, I'll bet you that Word makes it capital.

00:25:11.920 --> 00:25:12.380
Yeah.

00:25:12.380 --> 00:25:14.100
Doesn't that make it real?

00:25:14.100 --> 00:25:14.760
No.

00:25:14.760 --> 00:25:17.640
I know PowerPoint well.

00:25:17.640 --> 00:25:17.960
So.

00:25:17.960 --> 00:25:18.400
No.

00:25:18.400 --> 00:25:18.660
Yeah.

00:25:18.660 --> 00:25:19.640
That's always tricky, right?

00:25:19.640 --> 00:25:24.620
When you have sort of a formal name, but the formal name doesn't have spaces or a slower case.

00:25:24.620 --> 00:25:25.520
But I'm fine with it.

00:25:25.520 --> 00:25:26.860
We got used to it with iPhone.

00:25:26.860 --> 00:25:28.400
So there's no capital.

00:25:28.400 --> 00:25:31.240
I mean, the P is capitalized in iPhone.

00:25:31.600 --> 00:25:32.040
Yeah.

00:25:32.040 --> 00:25:35.540
Will Word correct you, I wonder, if you try to type iPhone?

00:25:35.540 --> 00:25:36.360
I would doubt it.

00:25:36.360 --> 00:25:38.960
I mean, but that's Apple and they think differently.

00:25:38.960 --> 00:25:40.000
That's what they tell me.

00:25:40.000 --> 00:25:41.880
But there's others.

00:25:41.880 --> 00:25:46.000
I mean, so there's some, I guess it's a weird thing with tools and stuff.

00:25:46.000 --> 00:25:50.380
Some tools don't care whether you capitalize or not.

00:25:50.380 --> 00:25:53.800
The people in pytest like it not capitalized.

00:25:53.800 --> 00:25:54.620
So anyway.

00:25:54.620 --> 00:25:54.880
Yeah.

00:25:54.880 --> 00:25:58.820
Let's respect their lowercase p's.

00:25:58.820 --> 00:25:59.800
Yeah.

00:25:59.800 --> 00:26:00.160
All right.

00:26:00.400 --> 00:26:02.600
So I have three really quick things.

00:26:02.600 --> 00:26:03.520
They're all kind of fun.

00:26:03.520 --> 00:26:11.740
So PyMC is a cool library for Bayesian analysis and probabilistic programming in Python.

00:26:11.740 --> 00:26:21.000
So Alex, one of the core developers there, sent me a message, said, hey, we're planning the first ever PyMC on.

00:26:21.000 --> 00:26:21.440
Okay.

00:26:21.440 --> 00:26:25.060
I pronounce PyMC on because it's so on, they say.

00:26:25.500 --> 00:26:30.080
And it's the first Bayesian community online conference around PyMC.

00:26:30.080 --> 00:26:34.420
So if you are into probabilistic programming in Python, check it out.

00:26:34.420 --> 00:26:36.960
There's a bunch of cool stuff they got going on.

00:26:36.960 --> 00:26:40.140
They're also, I think, have a call for paper.

00:26:40.140 --> 00:26:44.580
So if you want to do a presentation, shoot them a note.

00:26:44.580 --> 00:26:46.940
And yeah, I'll link to that in the show notes.

00:26:47.320 --> 00:26:51.140
Second, a while ago, we talked about Rumps quite a while ago.

00:26:51.140 --> 00:26:59.920
Rumps is ridiculously uncomplicated Mac, I don't know, something, menu programs or something like that.

00:27:00.480 --> 00:27:15.080
And so I ended up, I was sitting around, I have this little library that I run because so many things in my life require taking a title or taking some words and turning them into a file name or a URL name.

00:27:15.080 --> 00:27:15.820
All right.

00:27:15.820 --> 00:27:21.660
So suppose I've got the title of a video and I want to name an MP4 file that.

00:27:22.040 --> 00:27:27.100
And it's got like a colon in it or like a forward slash or some random thing that shouldn't be in there.

00:27:27.100 --> 00:27:28.480
I don't want spaces.

00:27:28.480 --> 00:27:28.980
I want it.

00:27:28.980 --> 00:27:32.940
So I wrote this little command line utility called URLify that I would just run.

00:27:32.940 --> 00:27:38.960
It would take whatever's in the clipboard and replace it with that canonicalized version that would work well as a file name.

00:27:38.960 --> 00:27:39.400
Oh, cool.

00:27:39.400 --> 00:27:39.720
Yeah.

00:27:39.720 --> 00:27:40.460
And that was cool.

00:27:40.460 --> 00:27:44.760
But then I got tired of like always firing up the command line, the terminal.

00:27:44.760 --> 00:27:46.340
Maybe it's busy doing something else.

00:27:46.340 --> 00:27:48.940
So I got to do a new window, run that thing and then close it down.

00:27:48.940 --> 00:27:52.040
And I was like, I just want to click something once.

00:27:52.040 --> 00:27:52.720
All right.

00:27:52.720 --> 00:27:55.520
I don't want to click the terminal and then start a new terminal.

00:27:55.520 --> 00:28:01.340
And it was like not that much work, but you can imagine the way I'm going on and on about this.

00:28:01.340 --> 00:28:03.120
I must be doing it more than is reasonable.

00:28:03.120 --> 00:28:13.740
So what I did is in like 45 minutes, I converted that command line app to a Mac dot app file, like a full on dot app file that I could just ship to any Mac user.

00:28:13.740 --> 00:28:14.620
They have no idea.

00:28:14.800 --> 00:28:24.400
It uses multiple Python packages, a code that I wrote, and it runs as a GUI auto starting with my macOS when I log in in my menu bar.

00:28:24.400 --> 00:28:24.980
Oh, wow.

00:28:24.980 --> 00:28:25.480
Is that cool?

00:28:25.480 --> 00:28:25.820
Yeah.

00:28:25.820 --> 00:28:30.000
And so I linked to a little tweet that has a screenshot just says convert text.

00:28:30.000 --> 00:28:33.440
But actually, I changed it to URL fi text, trim text.

00:28:33.520 --> 00:28:40.020
So now I can just click up there and any text that I have, you know, if you copy something and you want to like paste an email or like, but maybe it's got a bunch of white space.

00:28:40.020 --> 00:28:41.400
You're like, why is this all here?

00:28:41.400 --> 00:28:41.560
Right.

00:28:41.560 --> 00:28:43.860
Instead of putting in text editor and just getting the little bit out.

00:28:43.860 --> 00:28:47.080
I just hit that and then I'll trim it or like a good lowercase text.

00:28:47.080 --> 00:28:56.000
So I have these like little cool like clipboard text transforms and it all took like 45 minutes to turn it into a Mac app with pi to app and rumps.

00:28:56.000 --> 00:28:56.520
Oh, wow.

00:28:56.520 --> 00:28:58.680
So are you sharing this somewhere?

00:28:58.680 --> 00:29:01.700
I will happily share it.

00:29:01.700 --> 00:29:02.160
Okay.

00:29:02.260 --> 00:29:04.580
But I don't have the GitHub repo public yet.

00:29:04.580 --> 00:29:09.560
So let me just like put like a screenshot and what the heck it is and then I can make it public.

00:29:09.560 --> 00:29:11.220
But yeah, so I'll put it in the show notes.

00:29:11.220 --> 00:29:11.600
Neat.

00:29:11.600 --> 00:29:11.880
Yeah.

00:29:11.880 --> 00:29:12.080
Yeah.

00:29:12.080 --> 00:29:12.560
It's super cool.

00:29:12.560 --> 00:29:17.960
And finally, I just want to let people know who are taking courses over at Talk Python.

00:29:17.960 --> 00:29:30.320
I was sitting around and I decided I want as you hover over the scrubber, I want it to show show a little thumbnail of where you would go in the video if you were to click the scrubber in that location.

00:29:30.320 --> 00:29:30.960
What's the scrubber?

00:29:30.960 --> 00:29:35.960
We're not like the little like time thing where you can click around and like zoom ahead and whatever.

00:29:35.960 --> 00:29:41.680
And we're not like reusing Vimeo or YouTube or something that might potentially do that.

00:29:41.680 --> 00:29:42.800
I think YouTube does it.

00:29:42.800 --> 00:29:43.940
I don't know that Vimeo does.

00:29:43.940 --> 00:29:48.120
Anyway, I recently figured out how to do that.

00:29:48.120 --> 00:29:52.100
So if people are interested, they can check it out.

00:29:52.100 --> 00:30:01.540
But there's a cool little trick where you can take a second hidden video player and point it at either the same video or a smaller version of the video.

00:30:01.540 --> 00:30:07.800
And then as the mouse moves, just seek it to that time and show it above where the mouse is.

00:30:07.800 --> 00:30:08.680
Isn't that crazy?

00:30:08.680 --> 00:30:08.980
Yeah.

00:30:09.100 --> 00:30:12.900
So if people need something like that, yeah, a little cool trick you might consider.

00:30:12.900 --> 00:30:18.400
Not that often in Python, but if you happen to make your way to the JavaScript side of things, you'll do a lot of that, I guess.

00:30:18.400 --> 00:30:20.260
So is that in your training site?

00:30:20.260 --> 00:30:21.160
Has it been updated then?

00:30:21.200 --> 00:30:21.800
Yeah, exactly.

00:30:21.800 --> 00:30:31.720
It's not updated as we speak because I'm still busy transcoding 200 hours of video to 500 by 200 size.

00:30:31.720 --> 00:30:34.620
So I'm about halfway through that.

00:30:34.620 --> 00:30:38.840
I've had yesterday I uploaded 200 gigs of data.

00:30:38.840 --> 00:30:42.300
I'm so going over my data limit this month.

00:30:42.300 --> 00:30:47.340
That was 20% of my data limit in one day.

00:30:47.340 --> 00:30:48.640
I got more to send.

00:30:48.640 --> 00:30:50.740
So, but yeah, it'll be there as soon as the videos are done.

00:30:50.840 --> 00:30:51.520
It'll turn it on.

00:30:51.520 --> 00:30:52.700
I'm going to back up a little bit.

00:30:52.700 --> 00:30:53.860
This IMC.

00:30:53.860 --> 00:30:54.180
Yeah.

00:30:54.180 --> 00:30:55.460
Probabilistic programming.

00:30:55.460 --> 00:30:58.520
Can I use this to make a probability drive?

00:30:58.520 --> 00:30:59.740
A probability drive?

00:30:59.740 --> 00:30:59.980
Yeah.

00:30:59.980 --> 00:31:01.040
Is this from science fiction?

00:31:01.040 --> 00:31:01.600
I don't know it.

00:31:01.600 --> 00:31:03.120
Like Hitchhiker's Guide to the Galaxy.

00:31:03.120 --> 00:31:03.940
Oh, no.

00:31:03.940 --> 00:31:04.960
Yeah, I would think so.

00:31:04.960 --> 00:31:08.940
I would begin by feeding it the number 42 and see what comes out.

00:31:08.940 --> 00:31:09.240
Maybe.

00:31:09.240 --> 00:31:09.640
Yeah.

00:31:09.640 --> 00:31:11.420
That's probably the natural first step.

00:31:11.420 --> 00:31:11.580
Yeah.

00:31:11.580 --> 00:31:12.300
All right.

00:31:12.300 --> 00:31:14.540
Speaking of jokes, we've got two.

00:31:14.540 --> 00:31:15.340
You want to go first?

00:31:15.340 --> 00:31:15.900
Yes.

00:31:15.900 --> 00:31:19.560
This was submitted by Reuven Lerner, inspired by Anthony Shaw.

00:31:20.100 --> 00:31:21.740
I used to do low-level programming.

00:31:21.740 --> 00:31:25.160
Then a product I bought told me no assembly required.

00:31:25.160 --> 00:31:27.200
Since then, I've been coding in Python.

00:31:27.200 --> 00:31:28.680
Nice.

00:31:28.680 --> 00:31:30.060
Except for Anthony.

00:31:30.060 --> 00:31:31.500
Anthony's coding in assembly.

00:31:31.500 --> 00:31:32.320
He codes in both.

00:31:32.320 --> 00:31:32.540
Yeah.

00:31:33.340 --> 00:31:36.820
His Python is assembly code or something like that.

00:31:36.820 --> 00:31:42.260
So this one, like last week, we talked about little Bobby Tables, who's beautiful, over at XKCD.

00:31:42.260 --> 00:31:44.720
And I've got another XKCD for us.

00:31:44.720 --> 00:31:46.360
But this one is not about databases.

00:31:46.360 --> 00:31:48.500
No, it's about source control and Git.

00:31:48.500 --> 00:31:48.780
Okay.

00:31:48.780 --> 00:31:49.140
All right.

00:31:49.140 --> 00:31:52.300
You want to be the woman developer that asks the question?

00:31:52.300 --> 00:31:52.960
Yes.

00:31:52.960 --> 00:31:54.020
I'll start us off.

00:31:54.020 --> 00:31:54.620
All right.

00:31:54.620 --> 00:31:56.560
So there's a couple developers speaking.

00:31:56.560 --> 00:31:59.480
First one is talking about this new source control.

00:31:59.480 --> 00:32:00.500
This is Git.

00:32:00.500 --> 00:32:05.660
It tracks collaborative work on projects through a beautiful distributed graph theory tree model.

00:32:05.660 --> 00:32:05.920
Cool.

00:32:05.920 --> 00:32:06.640
How do we use it?

00:32:06.640 --> 00:32:07.280
No idea.

00:32:07.280 --> 00:32:09.700
Just memorize these shell commands and type them to sync up.

00:32:09.700 --> 00:32:13.740
If you get errors, save your work elsewhere, delete the project, and download a fresh copy.

00:32:13.740 --> 00:32:21.300
It's funny because it happens too often, I think.

00:32:21.300 --> 00:32:22.540
Yeah.

00:32:22.540 --> 00:32:29.660
I think most people have like the four or five or six Git commands that they use all the time and everything else they have to look up if they need it.

00:32:29.660 --> 00:32:29.980
Yeah.

00:32:29.980 --> 00:32:31.140
Merge conflict.

00:32:31.140 --> 00:32:31.460
All right.

00:32:31.460 --> 00:32:32.060
I'm deleting it.

00:32:32.060 --> 00:32:33.280
I'm going to copy this back over.

00:32:33.280 --> 00:32:35.400
Yep.

00:32:35.400 --> 00:32:36.640
All right.

00:32:36.640 --> 00:32:38.020
Funny indeed.

00:32:38.020 --> 00:32:39.920
Well, thanks for being here as always.

00:32:39.920 --> 00:32:41.000
And thanks to everyone for listening.

00:32:41.000 --> 00:32:41.400
Thank you.

00:32:41.400 --> 00:32:41.860
Bye.

00:32:41.860 --> 00:32:42.140
Bye.

00:32:42.140 --> 00:32:42.300
Bye.

00:32:42.700 --> 00:32:44.320
Thank you for listening to Python Bytes.

00:32:44.320 --> 00:32:46.840
Follow the show on Twitter via at Python Bytes.

00:32:46.840 --> 00:32:49.680
That's Python Bytes as in B-Y-T-E-S.

00:32:49.680 --> 00:32:52.920
And get the full show notes at pythonbytes.fm.

00:32:52.920 --> 00:32:57.140
If you have a news item you want featured, just visit pythonbytes.fm and send it our way.

00:32:57.140 --> 00:32:59.840
We're always on the lookout for sharing something cool.

00:32:59.840 --> 00:33:02.940
On behalf of myself and Brian Okken, this is Michael Kennedy.

00:33:02.940 --> 00:33:06.380
Thank you for listening and sharing this podcast with your friends and colleagues.

