WEBVTT

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

00:00:05.240 --> 00:00:09.940
This is episode 137, recorded June 26th, 2019.

00:00:09.940 --> 00:00:10.780
I'm Michael Kennedy.

00:00:10.780 --> 00:00:11.620
And I'm Brian Okken.

00:00:11.620 --> 00:00:13.940
And this episode is brought to you by Rollbar.

00:00:13.940 --> 00:00:15.620
I'll tell you all more about them later.

00:00:15.620 --> 00:00:18.860
For now, Brian, I always wonder about, you know,

00:00:18.860 --> 00:00:21.760
you hear that Python is an efficient and expressive language,

00:00:21.760 --> 00:00:24.160
and if you write code in C++, it'll be a lot longer.

00:00:24.160 --> 00:00:25.720
But, you know, how can you quantify that?

00:00:25.720 --> 00:00:29.240
Well, you can set up a whole bunch of people to write the same thing

00:00:29.240 --> 00:00:30.580
in a whole bunch of languages.

00:00:30.580 --> 00:00:33.720
Well, that's awesome that people did that.

00:00:33.720 --> 00:00:36.380
It seems like a lot of work, but yeah, I guess that's cool.

00:00:36.380 --> 00:00:37.300
Tell us about it.

00:00:37.300 --> 00:00:38.360
Like, this is your first item, right?

00:00:38.360 --> 00:00:46.000
So this is an article called Comparing the Same Project in Rust, Haskell, C++, Python, Scala, and

00:00:46.000 --> 00:00:47.420
how do you pronounce that?

00:00:47.420 --> 00:00:48.000
OCaml?

00:00:48.000 --> 00:00:49.200
O-C-A-M-L?

00:00:49.200 --> 00:00:50.080
OCaml, I think, yeah.

00:00:50.080 --> 00:00:53.160
So this was written up by Christian Hume,

00:00:53.160 --> 00:00:57.880
and this is about a university project, which is kind of a neat project.

00:00:58.480 --> 00:01:03.200
Basically, they had to implement a big chunk of Java.

00:01:03.200 --> 00:01:09.340
So it's a Java to x86 compiler as part of a compiler class.

00:01:09.340 --> 00:01:14.700
And they were basically had to set up, get up teams, teams of people to do it,

00:01:14.700 --> 00:01:16.620
and they could pick any language they wanted,

00:01:16.620 --> 00:01:20.680
which is kind of cool because, you know, people be better at different languages.

00:01:20.680 --> 00:01:21.440
Yeah.

00:01:21.440 --> 00:01:22.600
So let them use what they're good at.

00:01:22.660 --> 00:01:26.820
Yeah, let them use what they're good at because then they'll do it properly and not just try to cram it one.

00:01:26.820 --> 00:01:29.960
They'll have the most efficient use of that language for sure.

00:01:29.960 --> 00:01:33.620
Up to three people on a team, and it was a multi-month project.

00:01:33.620 --> 00:01:35.720
And then also tests were added.

00:01:35.920 --> 00:01:40.520
So this is kind of a neat part of the process, which I think is an awesome way to teach people,

00:01:40.520 --> 00:01:45.500
is have some published tests of, like, you're going to have to run these test cases and they have to pass,

00:01:45.500 --> 00:01:52.580
but then also have some secret ones where people don't, they don't know what tests are going to be tested against it,

00:01:52.960 --> 00:01:59.760
which is kind of nice because people will have to be able to make sure their implementation is robust without knowing,

00:01:59.760 --> 00:02:01.580
without the test cases.

00:02:01.580 --> 00:02:02.400
It's kind of neat.

00:02:02.400 --> 00:02:03.060
Yeah, that's cool.

00:02:03.060 --> 00:02:06.200
So I do love it that there's unknown tests.

00:02:06.200 --> 00:02:07.920
Like, these are the specifications.

00:02:07.920 --> 00:02:12.740
You can kind of get close with these tests, but to pass, you actually have to just work.

00:02:12.740 --> 00:02:14.680
That's totally like real life, you know.

00:02:14.680 --> 00:02:19.660
You'll write down some specifications, and there's some specifications that are not written down.

00:02:19.660 --> 00:02:21.340
They're just supposed to be known.

00:02:21.340 --> 00:02:24.820
And then there's other things that people, once they see the implementation, they go,

00:02:24.820 --> 00:02:26.720
oh, yeah, I wish it did this also.

00:02:26.720 --> 00:02:28.700
So I think that's a cool idea.

00:02:28.700 --> 00:02:33.280
And they weren't shooting for lines of code or anything complexity.

00:02:33.280 --> 00:02:35.540
They were just trying to finish the project.

00:02:35.540 --> 00:02:37.320
So this analysis was done after.

00:02:37.320 --> 00:02:43.180
They had a Rust, a baseline implementation written by two people that were familiar with Rust,

00:02:43.180 --> 00:02:45.580
and then they compared everything against that.

00:02:45.580 --> 00:02:50.020
So there was another Rust team that chose different design decisions,

00:02:50.020 --> 00:02:53.880
and it took, they had like three times the code.

00:02:53.880 --> 00:02:56.060
So these are all just comparing lines of code.

00:02:56.060 --> 00:03:01.740
The Haskell implementation was about equal, but depending on how you measure it,

00:03:01.740 --> 00:03:04.640
one to 1.6 times the code.

00:03:04.640 --> 00:03:06.280
Same for the OCaml.

00:03:06.280 --> 00:03:11.400
C++ was bigger, about 1.4 times the baseline.

00:03:11.400 --> 00:03:17.000
And Scala was a little bit less with about 70% of lines of code.

00:03:17.360 --> 00:03:22.600
The big outlier was Python, which had a lot of standouts.

00:03:22.600 --> 00:03:29.340
Python implementation was half the size, approximately, plus written by one person,

00:03:29.340 --> 00:03:35.160
and had extra features past all the secret tests, plus others.

00:03:35.220 --> 00:03:40.340
Somebody excellent at programming, of course, used some of the meta programming techniques.

00:03:40.340 --> 00:03:43.440
And anyway, kind of a fun article.

00:03:43.440 --> 00:03:49.320
One of the things I forgot to mention, one of the hindrances was they were only supposed to use standard libraries,

00:03:49.320 --> 00:03:54.720
no extra parsing, and then not any parsing libraries, even if they were part of the standard library.

00:03:55.080 --> 00:03:59.620
So even the parsing had to be kind of built up from scratch.

00:03:59.620 --> 00:04:00.360
Yeah, how interesting.

00:04:00.360 --> 00:04:04.280
I wonder if that would make things like Python even better possible.

00:04:04.280 --> 00:04:05.700
I don't know about Rust, maybe as well.

00:04:05.700 --> 00:04:08.680
But like C++ doesn't have parsing libraries built in that I know of.

00:04:08.680 --> 00:04:09.660
Things like that, right?

00:04:09.660 --> 00:04:13.320
There's a lot of mini-language parsing libraries around Python.

00:04:13.320 --> 00:04:18.720
So it'd be interesting to do that with, you know, go wild and use whatever's available.

00:04:18.720 --> 00:04:21.020
Right, like maybe take this project and then go,

00:04:21.020 --> 00:04:24.360
all right, well, what if we hit it with all the pip installable things?

00:04:24.360 --> 00:04:25.960
What happens then, right?

00:04:25.960 --> 00:04:26.660
Yeah, exactly.

00:04:26.660 --> 00:04:29.220
Yeah, it sounds like a super intense project, though, right?

00:04:29.220 --> 00:04:31.480
Like deep, deep into the language, right?

00:04:31.480 --> 00:04:33.340
I mean, on one, you're writing the compiler.

00:04:33.340 --> 00:04:35.400
You're understanding Java.

00:04:35.400 --> 00:04:36.960
You're compiling to x86.

00:04:36.960 --> 00:04:38.300
You're doing meta programming.

00:04:38.300 --> 00:04:39.800
Like there's a lot of stuff going on here.

00:04:39.800 --> 00:04:40.720
It's a pretty cool article.

00:04:40.720 --> 00:04:41.080
Cool.

00:04:41.080 --> 00:04:44.760
If that last one really connected with like your deep geek outlets,

00:04:44.760 --> 00:04:47.000
like go like really hard into the language,

00:04:47.000 --> 00:04:49.280
this next one is going to connect with your,

00:04:49.420 --> 00:04:51.020
I just want it to work really quick and easy.

00:04:51.020 --> 00:04:51.380
Yeah.

00:04:51.380 --> 00:04:52.380
So this one is really nice.

00:04:52.380 --> 00:04:53.780
So if I was a data scientist,

00:04:53.780 --> 00:04:57.960
I might use Matplotlib or just any kind of person who wanted some visualization of data.

00:04:57.960 --> 00:05:00.040
I might use Matplotlib for that.

00:05:00.040 --> 00:05:01.380
And that's great.

00:05:01.380 --> 00:05:05.960
Except for at least I personally can't make Matplotlib look super good, right?

00:05:05.960 --> 00:05:07.320
Like if I used Excel,

00:05:07.320 --> 00:05:09.800
like I put the data in there and I'd highlight the stuff and I would say,

00:05:09.800 --> 00:05:11.440
okay, insert chart.

00:05:11.440 --> 00:05:15.860
And I would pick the kind and then I would go and I would like right click and edit the chart.

00:05:15.940 --> 00:05:18.540
And I would like maybe drag it around to size it correctly,

00:05:18.540 --> 00:05:21.260
double click on the axes to change the axes.

00:05:21.260 --> 00:05:24.280
But in Matplotlib, you just write code and the picture comes out, right?

00:05:24.280 --> 00:05:24.560
Yeah.

00:05:24.560 --> 00:05:27.700
And I know you can do all this stuff, but it's not obvious.

00:05:27.700 --> 00:05:31.160
And you have to look at everything, every little thing up and tweak it.

00:05:31.160 --> 00:05:31.680
Yeah.

00:05:31.680 --> 00:05:36.640
So there's this project that we heard about from one of our listeners.

00:05:36.640 --> 00:05:37.720
And I can't remember.

00:05:37.720 --> 00:05:39.260
I'm trying to remember who it was.

00:05:39.260 --> 00:05:39.840
Oh, here it is.

00:05:40.260 --> 00:05:42.120
I've got this is from Lee Wagner.

00:05:42.120 --> 00:05:44.540
So thank you, Lee, for sending us in because this is killer.

00:05:44.540 --> 00:05:51.720
So there's this project called PyLustrator for styling your Matplotlib plot.

00:05:51.720 --> 00:05:58.360
So you just do your Matplotlib code, but you import PyLustrator and you say start at the beginning.

00:05:59.140 --> 00:06:04.640
And what it does is it pops up when you show your plot an interactive thing, much like Excel,

00:06:04.640 --> 00:06:08.400
where you can drag and drop and arrange your different plots.

00:06:08.400 --> 00:06:15.600
You can like go to the properties and edit like the axes and the colors and just all the kind of stuff that you might do.

00:06:15.740 --> 00:06:23.600
It even has like the cool design layout stuff where like it'll help you equally space stuff between each other.

00:06:23.600 --> 00:06:25.220
So put those little bars to say right there.

00:06:25.220 --> 00:06:28.860
If you drag and drop it, they'll be equally spaced or like align the tops and the sides.

00:06:28.860 --> 00:06:29.220
Yeah.

00:06:29.220 --> 00:06:34.700
And with that, the start thing, you can even fill it with some of your data to begin with.

00:06:34.700 --> 00:06:40.300
So if you, you kind of know the data you want to plot, because that's going to affect how you're going to design it.

00:06:40.300 --> 00:06:43.820
So you can pre-fill it and then drag it around and design it.

00:06:43.820 --> 00:06:45.100
It's just totally cool.

00:06:45.100 --> 00:06:45.840
It's totally cool.

00:06:45.840 --> 00:06:46.620
I'm glad they have.

00:06:46.620 --> 00:06:50.920
So the link we're going to show has a little embedded video.

00:06:50.920 --> 00:06:55.020
And that's where, I mean, talking about it, you're like, yeah, I think this might be useful.

00:06:55.020 --> 00:06:58.420
But you watch this video and you're like, oh, my God, I need to use this right away.

00:06:58.420 --> 00:06:59.060
Yes.

00:06:59.060 --> 00:07:00.800
I had the exact same experience.

00:07:00.800 --> 00:07:02.300
I'm like, kind of interesting.

00:07:02.300 --> 00:07:03.500
Oh, look at the video.

00:07:03.500 --> 00:07:04.060
Oh, my God.

00:07:04.060 --> 00:07:04.520
It's amazing.

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

00:07:04.800 --> 00:07:06.060
So this is super cool.

00:07:06.060 --> 00:07:10.900
And obviously, you don't save your changes to like an Excel workbook.

00:07:10.900 --> 00:07:12.760
What you do is you save your changes.

00:07:13.140 --> 00:07:15.140
And you can actually call save in PyListrator.

00:07:15.140 --> 00:07:20.260
And what it'll do is it'll put the configuration in Python back into the file that ran it.

00:07:20.260 --> 00:07:22.240
So that's pretty wild, actually.

00:07:22.240 --> 00:07:22.600
Yeah.

00:07:22.600 --> 00:07:24.280
And then you uncomment the PyListrator.

00:07:24.280 --> 00:07:28.860
You don't have to import it later because it's not a dependency on your project afterwards.

00:07:28.860 --> 00:07:29.380
Right.

00:07:29.380 --> 00:07:30.640
It's just a little design tool.

00:07:30.700 --> 00:07:38.100
So it's super cool if anyone's doing Matplotlib and they want to have it styled, especially if you're doing more than one plot and you want to put them like side by side.

00:07:38.100 --> 00:07:39.100
Like, this is super cool.

00:07:39.100 --> 00:07:39.860
So check that out.

00:07:39.860 --> 00:07:40.880
I'm definitely a fan.

00:07:40.880 --> 00:07:43.100
Another thing I'm a fan of, Brian, MongoDB.

00:07:43.100 --> 00:07:44.180
Love it.

00:07:44.180 --> 00:07:49.140
Since you and I are paying attention to a lot of projects, there's a lot of different release cycles.

00:07:49.140 --> 00:07:55.900
And we kind of decided early on that we weren't going to try to track everybody's releases because that might get boring to people.

00:07:55.900 --> 00:08:00.860
However, we covered MongoDB 4 because it came out with...

00:08:00.860 --> 00:08:01.420
Transactions.

00:08:01.420 --> 00:08:02.320
Transactions.

00:08:02.320 --> 00:08:03.140
Among other things, yeah.

00:08:03.140 --> 00:08:04.080
Which was a big thing.

00:08:04.940 --> 00:08:10.120
But 4.2 is out and I'm kind of excited about a couple of features that it came out with.

00:08:10.120 --> 00:08:14.460
So the transactions are there, but now they're multi-doc.

00:08:14.460 --> 00:08:15.920
They're distributed transactions.

00:08:15.920 --> 00:08:21.200
So they're transactions that cross sharded clusters and replica sets.

00:08:21.200 --> 00:08:23.740
And that's just really cool.

00:08:23.740 --> 00:08:24.700
Yeah, that's super cool.

00:08:24.700 --> 00:08:28.860
I mean, you could use a cool transactional set before, but you're kind of limited, right?

00:08:28.940 --> 00:08:35.580
And now it's like, no matter what crazy cluster with scaling and sharding and replication you have set up, you just do a transaction and it's all good.

00:08:35.580 --> 00:08:36.100
Pretty cool.

00:08:36.100 --> 00:08:37.180
They're a good idea anyway.

00:08:37.180 --> 00:08:42.360
But with testing, you can set up a complex database full of stuff.

00:08:42.360 --> 00:08:46.140
And then at the beginning of your test, start a transaction.

00:08:46.140 --> 00:08:52.920
And then after your test, and you roll this into a fixture, you can just roll back and your next test has the same data.

00:08:52.920 --> 00:08:53.680
It saves time.

00:08:53.680 --> 00:08:54.760
So that's cool.

00:08:54.760 --> 00:08:58.420
Yeah, and it's probably got isolation if for some reason they ran in parallel or whatever.

00:08:58.580 --> 00:08:59.220
Yeah, it's really cool.

00:08:59.220 --> 00:08:59.520
Yeah.

00:08:59.520 --> 00:09:03.400
The other feature that's pretty amazing is the field level encryption.

00:09:03.400 --> 00:09:09.480
And this is encryption done on a per field basis on the client side.

00:09:09.480 --> 00:09:15.140
So the server doesn't even have, it doesn't do the, it's not doing it on the server.

00:09:15.140 --> 00:09:28.320
So there's like system administration can be done without having to make sure everybody signs NDAs and all that stuff that you can just, you can manage your database without even being exposed.

00:09:28.320 --> 00:09:29.320
Yeah, that's awesome.

00:09:29.320 --> 00:09:29.600
Yeah.

00:09:29.600 --> 00:09:30.040
Yeah, that's awesome.

00:09:30.040 --> 00:09:33.460
Like most databases, most of what's in them is not sensitive.

00:09:33.460 --> 00:09:39.100
But there's often like a little bit that is, that's really, you don't want, you don't want anyone to get access to.

00:09:39.100 --> 00:09:39.980
And yeah, this is really cool.

00:09:39.980 --> 00:09:44.800
Because like you said, it's done in the library that talks to MongoDB.

00:09:45.340 --> 00:09:48.200
So in PyMongo for the Python folks.

00:09:48.740 --> 00:09:55.400
And you just set the encryption key or decryption key over there and the server cannot decrypt it.

00:09:55.400 --> 00:10:01.780
So if somebody breaks into the server or you lose it, or it's like you set it up on the cloud for like testing, you forget that it's there.

00:10:01.860 --> 00:10:03.960
All the kind of random stuff that happens to databases.

00:10:03.960 --> 00:10:09.600
It doesn't matter in terms of this encrypted stuff because like literally the database doesn't know how to read it.

00:10:09.600 --> 00:10:13.080
It's the drivers that on the client side that have the keys.

00:10:13.420 --> 00:10:20.020
So with GDPR stuff, if the customer says, hey, delete my stuff, that's always been an issue with databases.

00:10:20.020 --> 00:10:22.300
It might be in a whole bunch of tables.

00:10:22.300 --> 00:10:28.840
But if you destroy the customer key, the data might still be there, but it's unreadable to anybody.

00:10:28.840 --> 00:10:30.940
So it may as well be garbage.

00:10:30.940 --> 00:10:31.440
Absolutely.

00:10:31.440 --> 00:10:42.500
And it gets to be really tricky because even if you set up the right code to delete all the customer data out of your database, what about the backup?

00:10:43.040 --> 00:10:50.360
That somebody made when an older admin was hired and they stored that in the S3 buckets so it was offsite, right?

00:10:50.360 --> 00:10:52.560
How do you delete the data out of there?

00:10:52.560 --> 00:10:53.940
You know what I mean?

00:10:53.940 --> 00:10:59.420
But if it's encrypted, then you can just throw away the encryption key and then it's just gobbledygook.

00:10:59.420 --> 00:10:59.740
Yeah.

00:10:59.740 --> 00:11:00.440
Cool.

00:11:00.440 --> 00:11:00.740
Pretty cool.

00:11:00.740 --> 00:11:01.540
I like it.

00:11:01.540 --> 00:11:05.860
Speaking of cool, Rollbar, happy to have them come along and sponsor the show.

00:11:05.860 --> 00:11:09.660
We use Rollbar on pythonbytes.fm, among other things.

00:11:09.780 --> 00:11:26.960
So if anything goes wrong and it's kind of fortuitous, I guess, I woke up this morning with a ton of Rollbar messages because there was a data center failure that caused some connectivity between MongoDB and pythonbytes.fm.

00:11:27.420 --> 00:11:29.160
How about that for a funny thing?

00:11:29.160 --> 00:11:31.240
So some network card broke, right?

00:11:31.240 --> 00:11:34.200
And like the site couldn't talk to the server.

00:11:34.200 --> 00:11:35.000
So the database server.

00:11:35.000 --> 00:11:35.960
So it was freaking out.

00:11:35.960 --> 00:11:37.100
How do I know?

00:11:37.100 --> 00:11:38.260
And nobody complained to me.

00:11:38.260 --> 00:11:39.140
They probably should.

00:11:39.140 --> 00:11:40.300
Like, Michael, your site's down.

00:11:40.300 --> 00:11:40.920
What's going on?

00:11:40.920 --> 00:11:41.880
It's really messed up.

00:11:42.680 --> 00:11:44.360
But I just opened up my email.

00:11:44.360 --> 00:11:46.260
I'm like, whoa, there's a lot of Rollbar stuff going on here.

00:11:46.260 --> 00:11:51.480
So if you want to be notified right away, even when users don't tell you, check them out.

00:11:51.480 --> 00:11:52.300
They have a free tier.

00:11:52.300 --> 00:11:53.420
They have some great paid tiers.

00:11:53.420 --> 00:11:55.740
Visit pythonbytes.fm/Rollbar.

00:11:55.740 --> 00:11:59.000
Super easy to integrate into Python, into the web frameworks.

00:11:59.000 --> 00:12:02.840
They've just got like one or two lines you enter or maybe a little configuration.

00:12:02.840 --> 00:12:04.000
A few settings.

00:12:04.000 --> 00:12:04.740
Off you go.

00:12:04.740 --> 00:12:05.720
It's really, really nice.

00:12:05.800 --> 00:12:08.100
So check them out, pythonbytes.fm/Rollbar.

00:12:08.100 --> 00:12:08.480
Nice.

00:12:08.480 --> 00:12:12.960
So kind of like PyListrator, that sounds kind of useful and interesting.

00:12:12.960 --> 00:12:15.800
This next one also sounds useful and interesting.

00:12:15.800 --> 00:12:20.100
But like PyListrator, it's like, as you look into it, you're like, whoa, this thing does a lot, man.

00:12:20.100 --> 00:12:20.840
Look at it go.

00:12:20.840 --> 00:12:25.300
So there's this project that was recommended by Francois LeBlanc.

00:12:25.300 --> 00:12:27.120
Thank you for that, Francois.

00:12:27.120 --> 00:12:29.640
And it's called Deep Difference.

00:12:29.640 --> 00:12:31.640
It's just called Deep Dif.

00:12:31.640 --> 00:12:36.100
And so it does deep differences in search of any Python object graph.

00:12:36.100 --> 00:12:39.420
So I've got an object which holds a list.

00:12:39.420 --> 00:12:41.040
That list points to a bunch of objects.

00:12:41.040 --> 00:12:42.420
Those have other pointers.

00:12:42.420 --> 00:12:46.400
Like I want to know, is this thing somehow referenced by that?

00:12:46.400 --> 00:12:47.700
Let me do a search on it.

00:12:47.700 --> 00:12:48.960
Where is it?

00:12:48.960 --> 00:12:54.960
Is this giant crazy data structure same or different than other giant crazy data structure?

00:12:54.960 --> 00:12:56.660
And you could compare them.

00:12:56.660 --> 00:12:57.520
So that's pretty cool.

00:12:57.520 --> 00:12:58.360
So it has Deep Dif.

00:12:58.360 --> 00:12:59.620
It has Deep Search.

00:12:59.620 --> 00:13:01.200
And it also has Deep Hash.

00:13:01.720 --> 00:13:10.300
So if I've got some giant crazy data structure, you would like to know that if the data is the same across two of those, that the hash result is identical.

00:13:10.300 --> 00:13:14.320
And if any part of the data changes, that the hash then changes.

00:13:14.320 --> 00:13:15.360
Oh, yeah.

00:13:15.360 --> 00:13:16.000
Possibly, right?

00:13:16.000 --> 00:13:20.680
So it will do that on object graphs that are not even hashable themselves.

00:13:20.680 --> 00:13:21.180
Really?

00:13:21.180 --> 00:13:21.920
Yeah.

00:13:21.920 --> 00:13:24.000
So that's pretty wild.

00:13:24.200 --> 00:13:29.660
I have just a lot of nice touches in here that kind of made me realize like, wow, this is wild.

00:13:29.660 --> 00:13:36.300
So, for example, it'll give me the differences in a list, ignoring order and duplicates.

00:13:36.300 --> 00:13:37.200
Right?

00:13:37.200 --> 00:13:39.440
Just what is the essence of this data?

00:13:40.140 --> 00:13:46.660
Or you can say, is any data repeated in this list or in this, you know, dictionary or something like that?

00:13:46.660 --> 00:13:48.780
You can exclude certain types.

00:13:48.780 --> 00:13:49.700
Right?

00:13:49.780 --> 00:13:53.360
Like, maybe I want to know the data is the same, but they're both using like a thread object.

00:13:53.360 --> 00:13:54.640
And the thread object is different.

00:13:54.640 --> 00:13:55.780
So, of course, they're going to be different.

00:13:55.780 --> 00:13:58.040
But say, don't check on the thread object.

00:13:58.040 --> 00:13:59.140
Just check the other stuff.

00:13:59.140 --> 00:13:59.600
Right?

00:13:59.600 --> 00:14:04.200
So you can explicitly opt in or out data types that you might use.

00:14:04.200 --> 00:14:09.620
You can say, I'd like to compare these things, but only to like four significant digits because I computed them slightly differently.

00:14:09.620 --> 00:14:16.540
And maybe they're, you know, I can't get them like to the decimal accuracy to be exactly the same, just the way they're done.

00:14:16.540 --> 00:14:16.780
Right?

00:14:16.780 --> 00:14:20.880
You can exclude parts of your object tree that you're going for compared.

00:14:20.880 --> 00:14:21.740
I mean, isn't this insane?

00:14:21.740 --> 00:14:26.520
Being able to do like significant digits in a deep data structure.

00:14:26.520 --> 00:14:27.900
That's amazing.

00:14:27.900 --> 00:14:30.760
That's really cool for a lot of the stuff I work with.

00:14:30.760 --> 00:14:32.420
Yeah, I can imagine exactly.

00:14:32.420 --> 00:14:33.420
And you know what?

00:14:33.420 --> 00:14:35.540
I bet this would be really good to mix in with testing.

00:14:35.540 --> 00:14:38.860
Like you create your test data and then you deep diff it against the result.

00:14:39.160 --> 00:14:39.740
Yeah, exactly.

00:14:39.740 --> 00:14:44.620
Because there may be noise in the system and you know some of the signals are noisy.

00:14:44.620 --> 00:14:46.420
So, yeah, this is awesome.

00:14:46.420 --> 00:14:46.760
Cool.

00:14:46.760 --> 00:14:47.600
It's super simple.

00:14:47.600 --> 00:14:49.380
But, yeah, it's pretty cool.

00:14:49.380 --> 00:14:52.740
So if that sounds like problems you're trying to solve, it sounds like you are, Brian.

00:14:52.740 --> 00:14:54.480
And I think it's definitely worth having a look at.

00:14:54.480 --> 00:14:55.300
Yeah, thanks.

00:14:55.300 --> 00:14:56.100
Yeah, you bet.

00:14:56.100 --> 00:14:58.600
See, we just do this podcast to help each other out.

00:14:58.600 --> 00:14:59.960
Like people can listen in.

00:14:59.960 --> 00:15:01.060
Yeah.

00:15:01.060 --> 00:15:01.900
Speaking of testing.

00:15:01.900 --> 00:15:08.980
Josh Peek is somebody that we, I'm sure we met him before at a previous PyCon, but he stopped by at PyCon.

00:15:08.980 --> 00:15:12.740
And this last year and met us and a really great guy.

00:15:12.740 --> 00:15:15.520
He wrote this great article called Advanced Python Testing.

00:15:16.280 --> 00:15:17.940
And it's kind of incredible.

00:15:17.940 --> 00:15:34.320
He goes through his, he got in a situation at work where he was asked to do complex tasks where he had to, he knew that testing and making sure that he was doing things properly would, and do good coding practices would, would help the entire process and make it go smoothly.

00:15:34.680 --> 00:15:39.340
So this is sort of a start to finish summary of it.

00:15:39.440 --> 00:15:46.080
But it's not that long of a read, but he talks about his learning journey, which he includes some great podcasts, including ours.

00:15:46.080 --> 00:15:48.520
Also an awesome book on testing.

00:15:48.520 --> 00:15:50.060
And I know the author for that one.

00:15:50.060 --> 00:15:52.360
Not just plugging our own stuff.

00:15:52.360 --> 00:15:53.900
He's got some great stuff in here.

00:15:53.980 --> 00:16:02.340
He talks about, he starts off with just a basic, for people new to testing, what a basic test function looks like and having good structure.

00:16:02.340 --> 00:16:09.820
But then he talks about, he wanted to ensure, you know, do static analysis and code style.

00:16:09.820 --> 00:16:12.400
So he uses black within his testing.

00:16:12.400 --> 00:16:17.880
And when he was talking about using PyLint, I don't use PyLint every day.

00:16:17.880 --> 00:16:25.200
So I didn't know that there was, it's a very comprehensive check, but it takes some time for large code bases.

00:16:25.200 --> 00:16:26.380
I didn't know that.

00:16:26.380 --> 00:16:34.880
But he has a cool hack that he puts in place to only, for like check-in tests, only lint modified files.

00:16:34.880 --> 00:16:35.660
Oh, that's cool.

00:16:35.660 --> 00:16:39.520
Yeah, because of course, if they're unmodified, then why would they have a different outcome?

00:16:39.520 --> 00:16:40.020
Yeah.

00:16:40.020 --> 00:16:40.320
Right.

00:16:40.320 --> 00:16:48.500
And then he uses incorporating flake 8 to do doc string testing to make sure that people are using consistent doc string styles.

00:16:48.500 --> 00:16:52.280
He covers all of his tox any configuration changes.

00:16:52.280 --> 00:16:55.980
He was trying to increase his code coverage.

00:16:55.980 --> 00:17:09.440
So he includes coverage.py, but then also has a cov fail under flag that he adds for testing to make sure that if code coverage drops below,

00:17:09.440 --> 00:17:11.640
a certain point, it fails the test.

00:17:11.640 --> 00:17:15.540
And then just generally gradually ratchet that up.

00:17:15.540 --> 00:17:18.240
So the increase, his target was 75%.

00:17:18.240 --> 00:17:22.840
So it even goes into fixtures and mocks and spies and stubs.

00:17:23.100 --> 00:17:32.680
And then even a cool tool called pytest VCR, which records your network interactions and then replays those for future test runs.

00:17:32.680 --> 00:17:35.020
And he saw a 10x speedup in that.

00:17:35.020 --> 00:17:35.700
That's really cool.

00:17:35.700 --> 00:17:37.120
There's so much cool stuff in here.

00:17:37.120 --> 00:17:37.900
pytest VCR.

00:17:37.900 --> 00:17:38.460
That's really cool.

00:17:38.540 --> 00:17:43.740
I think the only problem with it is like maybe a lot of folks using it have no idea what VCR means.

00:17:43.740 --> 00:17:44.620
Oh, yeah.

00:17:44.620 --> 00:17:46.300
That's true.

00:17:46.300 --> 00:17:47.720
I mean, even, yeah.

00:17:47.720 --> 00:17:48.100
So.

00:17:48.100 --> 00:17:48.400
Yeah.

00:17:48.400 --> 00:17:53.280
But no, it's awesome that you just record the network interactions and don't have to depend on anything at all.

00:17:53.280 --> 00:17:53.920
I love it.

00:17:53.920 --> 00:17:57.280
And the recordings are done based on a per test basis.

00:17:57.280 --> 00:18:04.240
So if you rerun an individual test, it only plays back the recording for that portion.

00:18:04.240 --> 00:18:07.880
It doesn't have order dependency built in, which is cool.

00:18:07.880 --> 00:18:08.120
Yeah.

00:18:08.120 --> 00:18:08.680
Super cool.

00:18:08.680 --> 00:18:09.500
I love it.

00:18:09.500 --> 00:18:10.200
Yeah.

00:18:10.200 --> 00:18:11.420
That's a really nice article, Josh.

00:18:11.420 --> 00:18:12.020
Well done.

00:18:12.020 --> 00:18:15.560
The last one I want to talk about was sent over by Kevin Books.

00:18:15.560 --> 00:18:21.600
Now, we've covered a few of the language, sort of language level learning things recently.

00:18:21.600 --> 00:18:27.140
We talked about the CPython byte compiler either last time or the time before that.

00:18:27.240 --> 00:18:28.880
How it doesn't really optimize stuff.

00:18:28.880 --> 00:18:33.300
And maybe there's some opportunities there, but more just to understand what's going on.

00:18:33.300 --> 00:18:38.300
So Kevin sent in a message, said, hey, I'm basically a C, C++ guy.

00:18:38.300 --> 00:18:41.580
And I saw the Dell keyword in Python.

00:18:41.580 --> 00:18:48.660
And it threw me for a loop because Dell seems like delete in C++, which means free memory.

00:18:48.660 --> 00:18:51.840
But it doesn't necessarily mean that in Python.

00:18:51.840 --> 00:18:56.020
So it even seems like some of the books out there are kind of being a little misleading,

00:18:56.320 --> 00:18:58.120
at least according to Kevin's reading of them.

00:18:58.120 --> 00:19:05.120
So I thought I'd just pull up an article that he sent over and then talk a little bit over some of the uses for Dell.

00:19:05.120 --> 00:19:05.560
Great.

00:19:05.560 --> 00:19:06.320
I don't use it.

00:19:06.320 --> 00:19:07.220
So this would be good.

00:19:07.220 --> 00:19:07.480
Yeah.

00:19:07.600 --> 00:19:15.680
So the context where I know Dell is I want to get something out of a list or I want to get something out of a dictionary.

00:19:15.680 --> 00:19:16.500
Right.

00:19:16.500 --> 00:19:16.860
Okay.

00:19:16.860 --> 00:19:18.080
And it's a little bit weird.

00:19:18.080 --> 00:19:19.480
It's like in keyword.

00:19:19.480 --> 00:19:19.800
Right.

00:19:19.800 --> 00:19:25.160
A lot of times I would expect some operator to be on the object I'm modifying.

00:19:25.160 --> 00:19:25.880
Right.

00:19:25.880 --> 00:19:31.280
Like list or, you know, string dot in or something and you give it the value.

00:19:31.280 --> 00:19:31.460
Right.

00:19:31.460 --> 00:19:35.120
But you say string space in space, the variable.

00:19:35.120 --> 00:19:35.460
Right.

00:19:35.540 --> 00:19:40.500
So it's a little bit funky that you apply it not on the object, but as a keyword in the language.

00:19:40.500 --> 00:19:41.280
And Dell is like that.

00:19:41.280 --> 00:19:41.400
Right.

00:19:41.400 --> 00:19:46.900
So if I have a dictionary and I want to remove a key, not set it to nothing, but make it not be in the keys collection,

00:19:46.900 --> 00:19:53.360
you can say Dell dictionary of bracket, like as if you're accessing that value, but putting the Dell there takes it out.

00:19:53.520 --> 00:19:53.960
Oh, okay.

00:19:53.960 --> 00:19:54.240
Yeah.

00:19:54.240 --> 00:19:55.380
And you can also do that for lists.

00:19:55.380 --> 00:19:59.520
So I can go in and remove it, remove something from a list if I want.

00:19:59.520 --> 00:20:05.640
There's a remove function on the list, but somewhat confusingly, potentially it's by value.

00:20:05.640 --> 00:20:06.000
Right.

00:20:06.000 --> 00:20:11.860
So I could say remove Jeff from the list and Jeff will no longer be in that list wherever he appeared.

00:20:11.860 --> 00:20:17.120
But if I want to say remove the third thing, there's no remove at or anything like that.

00:20:17.120 --> 00:20:17.260
Right.

00:20:17.260 --> 00:20:19.760
I can't pass to that's not a value.

00:20:19.760 --> 00:20:20.020
Right.

00:20:20.020 --> 00:20:21.960
So Dell will let me remove that.

00:20:22.460 --> 00:20:26.680
You can also use pop for that, I believe on the list, but Dell is a little more general purpose.

00:20:26.680 --> 00:20:28.580
And you can also delete slices.

00:20:28.580 --> 00:20:34.920
So I could say, go to this list and take out everything from two to five, you know, two colon five like that.

00:20:34.920 --> 00:20:35.460
All right.

00:20:35.460 --> 00:20:37.280
So these are all pretty interesting.

00:20:37.280 --> 00:20:41.000
Now I'm linking over to the official docs that talk about it.

00:20:41.000 --> 00:20:44.640
And this article that kind of talks through some of these examples and shows you how to use it.

00:20:44.640 --> 00:20:48.740
You can also delete a variable out of like a local or a global namespace.

00:20:48.740 --> 00:20:52.200
So if there's a variable that's been defined and you want it to not be defined,

00:20:52.200 --> 00:20:53.920
I can say Dell space variable name.

00:20:53.920 --> 00:20:57.780
And now it's as if I didn't do that line that defined it, right?

00:20:57.780 --> 00:20:58.400
That created it.

00:20:58.400 --> 00:20:59.940
Does it remove it from the namespace?

00:20:59.940 --> 00:21:00.580
It removed.

00:21:00.580 --> 00:21:00.840
Yeah.

00:21:00.840 --> 00:21:06.180
It doesn't free the memory necessarily, but it takes it out as a global variable.

00:21:06.180 --> 00:21:06.800
Okay.

00:21:06.800 --> 00:21:08.520
Or a local one.

00:21:08.520 --> 00:21:08.720
Right.

00:21:08.720 --> 00:21:09.000
Yeah.

00:21:09.040 --> 00:21:10.740
So does it actually free any memory?

00:21:10.740 --> 00:21:11.460
Right.

00:21:11.460 --> 00:21:12.700
It depends.

00:21:12.700 --> 00:21:12.960
Right.

00:21:12.960 --> 00:21:17.160
So if I have it in the global names, let's say it's a global, right?

00:21:17.160 --> 00:21:21.560
It has obviously the thing that has a value at that variable.

00:21:21.820 --> 00:21:22.960
It's taking up some memory.

00:21:22.960 --> 00:21:26.040
If nothing else is pointing at it, right?

00:21:26.040 --> 00:21:28.120
It's still going to be around because that global variable is pointing at it.

00:21:28.120 --> 00:21:33.460
But if you call Dell that variable, you'll dereference that one reference to it, putting the reference

00:21:33.460 --> 00:21:35.160
count to zero and freeing it up.

00:21:35.160 --> 00:21:38.180
So theoretically, you could free up memory using Dell.

00:21:38.600 --> 00:21:43.280
Similarly, if it's in a list and the only place that points to it has a reference to it is that list itself.

00:21:43.280 --> 00:21:46.360
And you delete it out of there, out of the dictionary, it goes away, right?

00:21:46.360 --> 00:21:47.060
Memory wise.

00:21:47.060 --> 00:21:49.940
But if something else is pointing at it, then obviously it's not going to go away.

00:21:49.940 --> 00:21:50.280
Yeah.

00:21:50.280 --> 00:21:53.720
We also talked about how the CPython bytecode compiler is dumb.

00:21:53.720 --> 00:21:57.040
Dumb as in not super optimizing, maybe on purpose.

00:21:57.040 --> 00:22:02.720
And I think you could also, you know, if you're like really dealing with memory issues and you're like,

00:22:02.720 --> 00:22:07.680
I really wish this thing would just go away sooner in this one little edge case,

00:22:07.780 --> 00:22:14.080
you could probably use Dell to put in some of the optimizations that you might hope that the compiler itself might do,

00:22:14.080 --> 00:22:21.320
but it doesn't like dereference a thing as soon as it's used within a function before you can get to the end or things like this.

00:22:21.320 --> 00:22:21.780
Yeah.

00:22:21.780 --> 00:22:22.380
Okay.

00:22:22.380 --> 00:22:23.680
So is it for memory?

00:22:23.680 --> 00:22:24.420
Sort of.

00:22:24.420 --> 00:22:25.020
Not really.

00:22:25.020 --> 00:22:27.280
But maybe as a side effect.

00:22:27.280 --> 00:22:28.060
Yeah.

00:22:28.060 --> 00:22:32.160
This has been a long time, but I do remember it tripping me up because I was like,

00:22:32.160 --> 00:22:37.100
it seems a lot like delete, which should have a matching new to it.

00:22:37.360 --> 00:22:37.840
Exactly.

00:22:37.840 --> 00:22:38.660
Exactly.

00:22:38.660 --> 00:22:40.480
We both done the C++ thing, right?

00:22:40.480 --> 00:22:41.920
Like where's the new that goes with Dell?

00:22:41.920 --> 00:22:43.280
I've never seen a new.

00:22:43.280 --> 00:22:44.740
Anyway, it's pretty cool.

00:22:44.740 --> 00:22:45.960
There's a couple of links here.

00:22:45.960 --> 00:22:47.040
There's a visual documentation.

00:22:47.040 --> 00:22:49.600
There's the article understanding Python's Dell.

00:22:49.600 --> 00:22:53.380
And then there's the reference to that bytecode compiler people can check out.

00:22:53.380 --> 00:22:53.700
Yeah.

00:22:53.700 --> 00:22:58.180
In C++, I don't think there's a way to remove a name from a namespace.

00:22:58.380 --> 00:22:58.540
Yeah.

00:22:58.540 --> 00:22:59.860
I don't think so either, right?

00:22:59.860 --> 00:23:00.160
Yeah.

00:23:00.160 --> 00:23:04.340
You can like make it point at null, but that's about it, right?

00:23:04.340 --> 00:23:04.740
Yeah.

00:23:04.740 --> 00:23:06.140
But I mean, you got to think about it, right?

00:23:06.140 --> 00:23:09.160
Like classes, you could delete a field out of a class, right?

00:23:09.160 --> 00:23:11.200
Because it's just a dictionary, right?

00:23:11.200 --> 00:23:13.760
So much of Python is built on like dictionaries, right?

00:23:13.760 --> 00:23:17.960
Like the variables are their variable names or the keys in the dictionary and their values

00:23:17.960 --> 00:23:18.660
are their value.

00:23:19.040 --> 00:23:21.780
So you just take it out of the global dictionary effectively, right?

00:23:21.780 --> 00:23:22.000
Yeah.

00:23:22.000 --> 00:23:22.440
Okay.

00:23:22.440 --> 00:23:22.880
Cool.

00:23:22.880 --> 00:23:23.360
Pretty sweet.

00:23:23.360 --> 00:23:25.880
So those are our main items for today.

00:23:25.880 --> 00:23:27.740
You got anything else you want to chat about, Brian?

00:23:27.740 --> 00:23:29.700
I'm just, I'm glad it's summer.

00:23:29.700 --> 00:23:30.940
It's starting to feel nice.

00:23:30.940 --> 00:23:31.700
It feels like summer.

00:23:31.700 --> 00:23:33.940
But other than that, not much.

00:23:33.940 --> 00:23:34.420
How about you?

00:23:34.420 --> 00:23:35.180
Summer is awesome.

00:23:35.180 --> 00:23:38.200
It makes programming hard because programming is indoors.

00:23:38.200 --> 00:23:42.760
Although some of my friends and I who work from home, we try to get out and program

00:23:42.760 --> 00:23:45.580
in like a coffee shop or a cafe by lake or something.

00:23:46.080 --> 00:23:50.320
And periodically we have the weird experience of getting a sunburn while writing code.

00:23:50.320 --> 00:23:54.420
And yeah, we've dubbed it a code burn and it's kind of a badge of honor.

00:23:54.420 --> 00:23:55.920
That's funny.

00:23:55.920 --> 00:23:56.320
Cool.

00:23:56.320 --> 00:23:56.620
Yeah.

00:23:56.620 --> 00:23:59.120
So there's actually a couple of things I want to throw out here.

00:23:59.120 --> 00:24:02.280
We recently had Max Sklar from the local Maximum podcast.

00:24:02.280 --> 00:24:05.620
And afterwards he had me onto his podcast.

00:24:05.620 --> 00:24:09.320
So I'll be on episode 73, which should be out.

00:24:09.320 --> 00:24:13.640
Not yet, but thanks to time shifting when this episode comes out, it should already be out.

00:24:13.640 --> 00:24:14.400
I'll put a link to that.

00:24:14.860 --> 00:24:23.020
Josh Thurston sent over a cool video of the popularity of languages on Stack Overflow over

00:24:23.020 --> 00:24:25.520
time as a bar chart race.

00:24:25.520 --> 00:24:29.820
I didn't know about bar chart races, but these are basically animated bar charts over time.

00:24:29.820 --> 00:24:32.000
And you just watch the bars grow and shrink.

00:24:32.000 --> 00:24:33.100
And it's really cool.

00:24:33.100 --> 00:24:36.100
Python is kind of like a little tiny consideration at the bottom.

00:24:36.100 --> 00:24:40.980
And obviously we know that Python is crushing it on popularity and Stack Overflow and all those

00:24:40.980 --> 00:24:41.160
things.

00:24:41.260 --> 00:24:43.000
So it's like a minute and a half video.

00:24:43.000 --> 00:24:45.940
I think everyone will appreciate watching it if they just got a minute to kill.

00:24:45.940 --> 00:24:47.020
No, it's a fun video.

00:24:47.020 --> 00:24:54.080
And one of the things I enjoy about it is early on, you see the Java bar going up and down based

00:24:54.080 --> 00:24:58.780
on the time of the year because it was used in education a lot.

00:24:58.780 --> 00:24:59.880
That totally made sense.

00:24:59.880 --> 00:25:00.380
Exactly.

00:25:00.380 --> 00:25:02.740
You're like, oh, there's a huge spike in September.

00:25:02.900 --> 00:25:03.740
I wonder why.

00:25:03.740 --> 00:25:06.120
Maybe a bunch of people got a job.

00:25:06.120 --> 00:25:06.680
No.

00:25:06.680 --> 00:25:09.500
Like CS 101 is now back in session.

00:25:09.500 --> 00:25:10.120
Yeah.

00:25:10.120 --> 00:25:10.860
Exactly.

00:25:10.860 --> 00:25:14.580
Then the last one I want to throw out is this thing called Pine Source.

00:25:14.580 --> 00:25:17.940
So what this does, this comes to us from Anders Klint.

00:25:18.860 --> 00:25:24.820
It's basically a UML diagram creation tool for Python code.

00:25:24.820 --> 00:25:29.520
So you give it some Python files, it will generate a UML diagram that shows the relationship of

00:25:29.520 --> 00:25:30.840
all the classes in there.

00:25:30.840 --> 00:25:31.860
Oh, that's cool.

00:25:31.860 --> 00:25:32.180
Yeah.

00:25:32.180 --> 00:25:32.680
It's pretty cool.

00:25:32.680 --> 00:25:35.740
There's a free, maybe even open source version.

00:25:35.740 --> 00:25:37.460
And then there's also a paid version.

00:25:37.700 --> 00:25:44.420
So you can buy it and, you know, I'm actually not a huge fan of UML, but if you have Python

00:25:44.420 --> 00:25:49.500
code and you think a UML diagram would help describing it, this thing's pretty cool actually.

00:25:49.500 --> 00:25:50.880
And it's a little GUI app.

00:25:50.880 --> 00:25:51.800
There's a bunch of screenshots.

00:25:51.800 --> 00:25:53.400
You can check it out and see if it'll help you.

00:25:53.400 --> 00:25:54.800
But it looks pretty neat.

00:25:54.800 --> 00:25:59.080
And it does, you know, proper UML, not just like sort of visualization of classes.

00:25:59.080 --> 00:26:00.540
So that's kind of nice.

00:26:00.540 --> 00:26:05.240
My favorite use of these kinds of diagrams is to print them out and pin them to your wall,

00:26:05.420 --> 00:26:09.600
your cubicle wall so that other programmers think that you're smarter than they are.

00:26:09.600 --> 00:26:11.140
Absolutely.

00:26:11.140 --> 00:26:16.080
Put some little cryptic notes on them, like as if, you know, you're marking them up.

00:26:16.080 --> 00:26:16.680
Yeah, absolutely.

00:26:16.680 --> 00:26:17.160
Love it.

00:26:17.160 --> 00:26:18.700
Yeah, so you can do this with your project.

00:26:18.700 --> 00:26:20.600
Yes, this huge thing is our project.

00:26:20.600 --> 00:26:22.080
Anyway, it's pretty cool.

00:26:22.080 --> 00:26:24.900
And there's a free version, like I said, so maybe I'll help some folks out there.

00:26:24.900 --> 00:26:25.580
All right.

00:26:25.580 --> 00:26:26.860
You ready for some jokes, Brian?

00:26:26.860 --> 00:26:27.740
Yes, definitely.

00:26:27.740 --> 00:26:28.280
All right.

00:26:28.280 --> 00:26:32.340
I have a, you've heard about the glass being half full and half empty and like, oh, I'm a

00:26:32.340 --> 00:26:33.440
half empty sort of person.

00:26:33.440 --> 00:26:35.260
I kind of see the world as slightly negative.

00:26:35.260 --> 00:26:35.620
Yes.

00:26:35.620 --> 00:26:37.500
So here's the developer version.

00:26:37.500 --> 00:26:40.160
So we have an optimist who says the glass is half full.

00:26:40.160 --> 00:26:43.280
We have the pessimist who says the glass is half empty.

00:26:43.280 --> 00:26:47.260
And we have the programmer who says the glass is twice as large as necessary.

00:26:47.260 --> 00:26:48.900
Yes, definitely.

00:26:48.900 --> 00:26:51.700
So I wanted to extend that.

00:26:51.700 --> 00:26:52.000
Okay.

00:26:52.000 --> 00:26:56.860
With the pragmatist that says that I'm just allowing enough room for requirements, oversight,

00:26:56.860 --> 00:26:58.740
scope creep, and schedule overrun.

00:26:58.740 --> 00:26:59.840
That's right.

00:26:59.840 --> 00:27:00.300
It's perfect.

00:27:00.300 --> 00:27:01.560
I love it.

00:27:01.560 --> 00:27:04.400
And then you have this other one about software startups.

00:27:04.400 --> 00:27:05.220
Yeah, man.

00:27:05.220 --> 00:27:11.260
It's not really any startup, but I watched the upside with Kevin Hart last night and it

00:27:11.260 --> 00:27:13.080
was a joke that I couldn't help but sharing.

00:27:13.080 --> 00:27:18.560
I can't remember the characters, but Kevin's character said, would you invest in my business

00:27:18.560 --> 00:27:18.980
idea?

00:27:19.640 --> 00:27:23.260
And the other guy says, that seems too niche.

00:27:23.260 --> 00:27:25.760
Kevin, what's niche mean?

00:27:25.760 --> 00:27:28.280
Oh, it's the girl version of nephew.

00:27:30.500 --> 00:27:31.320
I love it.

00:27:31.320 --> 00:27:31.340
I love it.

00:27:31.340 --> 00:27:31.880
That's bad.

00:27:31.880 --> 00:27:34.900
If you got to ask, that's a pretty good answer.

00:27:34.900 --> 00:27:35.260
Yeah.

00:27:35.260 --> 00:27:35.780
Yeah.

00:27:35.780 --> 00:27:36.000
Cool.

00:27:36.000 --> 00:27:36.180
Cool.

00:27:36.180 --> 00:27:36.640
All right.

00:27:36.640 --> 00:27:40.240
Well, thanks for putting all the cool topics together as always and being here.

00:27:40.240 --> 00:27:40.540
Yeah.

00:27:40.540 --> 00:27:40.960
Thank you.

00:27:40.960 --> 00:27:41.340
Bye.

00:27:41.580 --> 00:27:43.180
Thank you for listening to Python Bytes.

00:27:43.180 --> 00:27:45.720
Follow the show on Twitter via at Python Bytes.

00:27:45.720 --> 00:27:48.580
That's Python Bytes as in B-Y-T-E-S.

00:27:48.580 --> 00:27:51.820
And get the full show notes at pythonbytes.fm.

00:27:51.820 --> 00:27:56.020
If you have a news item you want featured, just visit pythonbytes.fm and send it our way.

00:27:56.020 --> 00:27:58.720
We're always on the lookout for sharing something cool.

00:27:58.720 --> 00:28:01.840
On behalf of myself and Brian Okken, this is Michael Kennedy.

00:28:01.840 --> 00:28:05.260
Thank you for listening and sharing this podcast with your friends and colleagues.

