WEBVTT 00:00:00.001 --> 00:00:06.000 Hello and welcome to Python Bytes, where we deliver Python news and headlines directly to your earbuds. 00:00:06.000 --> 00:00:12.200 This is episode 338, recorded May 30th, 2023. 00:00:12.200 --> 00:00:13.440 I'm Michael Kennedy. 00:00:13.440 --> 00:00:14.680 And I am Brian Okken. 00:00:14.680 --> 00:00:19.520 And this episode is brought to you by us, our courses and books and things like that. 00:00:19.520 --> 00:00:20.980 Talk to you more about that later. 00:00:20.980 --> 00:00:25.460 Also, connect with us on Mastodon or all over on Fosstodon, 00:00:25.460 --> 00:00:28.460 at mkennedy, @brianokken, and at Python Bytes. 00:00:28.600 --> 00:00:30.560 And we love it when people join the live show. 00:00:30.560 --> 00:00:36.540 If you want to be part of that, you can see the next scheduled upcoming one at pythonbytes.fm/live 00:00:36.540 --> 00:00:38.500 and click that notify me and YouTube. 00:00:38.500 --> 00:00:39.340 And guess what? 00:00:39.340 --> 00:00:40.500 It'll notify you when it's live. 00:00:40.500 --> 00:00:43.700 So that's the front matter, Brian. 00:00:43.700 --> 00:00:45.600 I think we should start it off with some basics. 00:00:45.600 --> 00:00:46.300 What do you think? 00:00:46.300 --> 00:00:47.840 Yeah, let's go back to the basics. 00:00:47.840 --> 00:00:49.920 Basics of Python packaging. 00:00:49.920 --> 00:00:57.040 So actually, this is something near and dear to what I've been paying a lot of attention to lately is packaging. 00:00:57.200 --> 00:00:59.200 And just how it's changed. 00:00:59.200 --> 00:01:03.740 And it's kind of in the most people have switched over to pyproject.toml now. 00:01:03.740 --> 00:01:06.500 And that's really what this is about. 00:01:06.500 --> 00:01:10.800 So when you're packaging, especially a pure Python package. 00:01:10.800 --> 00:01:13.920 Well, one of the things I like about this is it's not just for pure Python. 00:01:14.120 --> 00:01:15.440 But that's the easy part. 00:01:15.440 --> 00:01:20.720 If we're using pure Python packaging, you're probably using a pyproject.toml now. 00:01:20.720 --> 00:01:24.420 And there has been several write-ups of it. 00:01:24.420 --> 00:01:27.320 But some of them are kind of tool-centric. 00:01:27.320 --> 00:01:30.000 So I like about this write-up from JQui. 00:01:30.000 --> 00:01:31.300 Or JQui? 00:01:31.300 --> 00:01:31.880 Not sure. 00:01:32.780 --> 00:01:38.700 That talks about just sort of the easy, a fairly standard setup. 00:01:38.700 --> 00:01:43.640 So it does talk about the peps in this article. 00:01:43.640 --> 00:01:45.900 But you don't really need to know much about that. 00:01:45.900 --> 00:01:47.700 You can just kind of skip to how do I do it. 00:01:48.420 --> 00:01:58.840 So using the peps and using pyproject.toml, you do have to specify what your build backend is. 00:01:58.840 --> 00:02:04.620 So in the top example of this article, it talks about using a flit core. 00:02:04.620 --> 00:02:07.460 And that's one I've used a lot of that. 00:02:07.460 --> 00:02:10.460 But then what else do you put in there? 00:02:10.460 --> 00:02:15.800 So within the rest of the pyproject.toml is mostly metadata. 00:02:15.800 --> 00:02:18.000 You can have other stuff, too, like black and everything. 00:02:18.220 --> 00:02:23.120 But for your project building, the project metadata, there's not a lot that goes in it. 00:02:23.120 --> 00:02:25.300 I mean, it looks like a lot when you just glance. 00:02:25.300 --> 00:02:30.860 But it's really, you know, it's your name for the name of the project, the version, description of it. 00:02:30.860 --> 00:02:36.120 Your author, I will point out that this is not minimal because it includes the email. 00:02:36.120 --> 00:02:37.700 You don't have to include the email. 00:02:37.700 --> 00:02:39.380 If you don't want to, you can just put the name. 00:02:39.380 --> 00:02:42.900 And where your license and readme and classifiers are. 00:02:42.900 --> 00:02:47.340 One of the things I want to highlight is make sure you have the license. 00:02:47.460 --> 00:02:55.580 At the very least, have your license classifier listed because that's how the license shows up on the PyPI. 00:02:56.220 --> 00:02:59.520 So when PyPI is looking at projects, it looks at the classifier. 00:02:59.520 --> 00:03:05.840 And then try to throw in which Python is required and then any of your dependencies that you're using. 00:03:05.840 --> 00:03:07.080 And then some links. 00:03:07.080 --> 00:03:13.720 I mean, it's really, when you just talk about it as a stream of conscious, it seems like a lot, but it's really not that much. 00:03:13.940 --> 00:03:15.260 And you're pretty much done. 00:03:15.260 --> 00:03:17.600 You can do a build now with this. 00:03:17.600 --> 00:03:18.880 This is- 00:03:18.880 --> 00:03:22.180 I think, Brian, before you move on from that, that I just noticed that I really like. 00:03:22.180 --> 00:03:33.860 If you do a setup.py, what you've got to put is the readme and details and the descriptions and all those kinds of things, at least a long description. 00:03:33.860 --> 00:03:38.140 You've got to actually load the file and inject the content to the file. 00:03:38.140 --> 00:03:43.420 And here you just put the file names for the license and for the readme, and it'll just pull those in, right? 00:03:43.480 --> 00:03:43.800 That's cool. 00:03:43.800 --> 00:03:51.640 It is one of the things I've harassed people about before is it's weird that the readme and license are specified completely different. 00:03:51.640 --> 00:03:57.840 So the license has this, like, what, curly braces and then file equals license. 00:03:57.840 --> 00:03:58.580 Dictionary-ish. 00:03:58.580 --> 00:03:59.300 Yeah, it's a dictionary. 00:03:59.300 --> 00:04:03.080 Whereas the readme is just a text string with the name of the readme. 00:04:03.080 --> 00:04:05.040 It's odd. 00:04:05.040 --> 00:04:11.040 I think that maybe we could have it so the license could just be a string with the license file on it also. 00:04:11.300 --> 00:04:15.140 But anyway, there's probably reasons, I'm sure. 00:04:15.140 --> 00:04:20.280 The thing that I also want to point out is you can put as many URLs as you want in here. 00:04:20.280 --> 00:04:22.920 You can have, like, this example as homepage and bug tracker. 00:04:22.920 --> 00:04:27.620 A lot of people just list home that lists the GitHub link. 00:04:27.620 --> 00:04:30.800 But you can have your documentation and other stuff. 00:04:30.800 --> 00:04:34.840 And all these show up in PyPI also if you're published to PyPI. 00:04:34.840 --> 00:04:49.580 And if you don't want to publish to PyPI, one extra is to, that Kim reminds us of, is another classifier I learned about, is private do not upload, which tells PyPI to not upload it. 00:04:49.580 --> 00:04:51.900 So this is all great. 00:04:51.900 --> 00:04:58.500 And a lot of this also, if you want to watch it in video form, is covered in the sharing is carrying video. 00:04:58.500 --> 00:05:01.240 It's a talk I gave in PyCascades. 00:05:01.240 --> 00:05:02.840 The video is now online. 00:05:02.840 --> 00:05:04.180 We'll put a link in the show notes. 00:05:05.140 --> 00:05:15.140 But this document or this article goes through some of the different, make sure that you understand the build step of Python-M build is one way to do it. 00:05:15.140 --> 00:05:15.840 There's other ways. 00:05:15.840 --> 00:05:24.280 But then it talks about some of the discussion around why pyproduct.toml is there instead of setup.py. 00:05:24.280 --> 00:05:26.000 I think we're all convinced, hopefully. 00:05:26.620 --> 00:05:28.800 But then also some choices of backends. 00:05:28.800 --> 00:05:31.800 So this article used Flit Core to start with. 00:05:31.800 --> 00:05:36.520 But there's also Hatchling and setup tools and Poetry Core. 00:05:36.520 --> 00:05:39.480 So why would you choose different ones? 00:05:39.480 --> 00:05:42.960 And one of the, and it's because there's extra features. 00:05:42.960 --> 00:05:46.020 Some of them allow extra tags to go in there. 00:05:46.340 --> 00:06:00.700 And the example they're using, and that's one of the reasons why I use Hatch a lot, is you can have include and exclude things to say, you know, the normal stuff that you'd probably include in a source distribution. 00:06:00.700 --> 00:06:04.440 Also add the tests, for instance, or something else. 00:06:04.440 --> 00:06:12.900 The test is one that, like, distributors, redistributors, like Linux distros, like to have your tests in the source distribution. 00:06:12.900 --> 00:06:15.780 So throwing those in there is a good idea. 00:06:16.100 --> 00:06:18.020 I'm not sure why they're in there by default. 00:06:18.020 --> 00:06:21.680 But anyway, it's a cool discussion. 00:06:21.680 --> 00:06:27.240 One of the things I also love is it talks about what happens if you're not just Python. 00:06:27.240 --> 00:06:28.900 What if you have to include C? 00:06:28.900 --> 00:06:31.420 Well, it doesn't really discuss it too much. 00:06:31.420 --> 00:06:32.800 It just points you in the right direction. 00:06:32.800 --> 00:06:38.500 So if you have C or C++ extension, there's a Psykit build core that you can use. 00:06:38.500 --> 00:06:39.840 I haven't tried any of these. 00:06:39.840 --> 00:06:43.140 If you're into Mason, you can use Mason Python. 00:06:43.780 --> 00:06:46.180 And then also setup tool supports it. 00:06:46.180 --> 00:06:49.120 So there's a direction for that sort of stuff. 00:06:49.120 --> 00:06:49.640 Yeah. 00:06:49.640 --> 00:06:51.040 Straightforward. 00:06:51.040 --> 00:06:52.040 Back to the basics. 00:06:52.040 --> 00:06:52.560 I like it. 00:06:52.560 --> 00:06:52.940 Yeah. 00:06:52.940 --> 00:06:55.160 Definitely demystify some of that. 00:06:55.160 --> 00:07:01.640 Henry points out in the audience, the license key will likely change via PEP 649. 00:07:01.820 --> 00:07:04.260 And currently, Flit just ignores whatever you put there. 00:07:04.260 --> 00:07:08.420 The Trove classifiers are the canonical location for the license. 00:07:08.420 --> 00:07:10.520 So just FYI. 00:07:10.520 --> 00:07:11.780 Thanks for that, Henry. 00:07:11.780 --> 00:07:15.820 He always has such excellent extra information, background information. 00:07:15.820 --> 00:07:18.880 And we're so lucky to have some smart people show up on the chat. 00:07:18.880 --> 00:07:19.600 So thank you. 00:07:19.820 --> 00:07:20.400 Yes, absolutely. 00:07:20.400 --> 00:07:22.100 All right. 00:07:22.100 --> 00:07:23.580 Let's talk vectors. 00:07:23.580 --> 00:07:26.280 So I want to talk about VEX. 00:07:26.280 --> 00:07:31.540 And this project comes to us from Olly, who open sourced this, Olly Rice. 00:07:31.540 --> 00:07:36.660 Now, before I actually tell you about what VEX is and what it does, let's take a step back 00:07:36.660 --> 00:07:41.860 and talk about the PG vector extension for Postgres, the database. 00:07:41.860 --> 00:07:46.200 So this is an open source because VEX has to like build on top of this. 00:07:46.200 --> 00:07:52.700 So this is an open source vector similarity search extension for Postgres. 00:07:52.700 --> 00:07:58.180 So you can do things like given a bunch of points in different dimensions. 00:07:58.180 --> 00:08:03.820 This could be XY, could be XYZ, could be, you know, temperature and time. 00:08:03.820 --> 00:08:04.340 I don't know. 00:08:04.340 --> 00:08:04.720 Right. 00:08:04.720 --> 00:08:06.540 It could be whatever you come up with. 00:08:06.540 --> 00:08:11.600 It'll give you the exact and approximate nearest neighbors, allow you to query that, like 00:08:11.600 --> 00:08:16.440 given some measurement, what other measurement is closest or give me the five measurements 00:08:16.440 --> 00:08:18.520 or positions that are closest to this. 00:08:18.520 --> 00:08:20.560 Gives you L2 distance. 00:08:20.560 --> 00:08:22.800 It'll do the inner product and cosine distance. 00:08:22.800 --> 00:08:25.380 So different metrics, if that makes sense. 00:08:25.380 --> 00:08:29.320 And any language with a Postgres client can speak to it. 00:08:29.320 --> 00:08:30.280 It's pretty cool, right? 00:08:30.280 --> 00:08:30.840 Yeah. 00:08:30.840 --> 00:08:31.320 Yeah. 00:08:31.320 --> 00:08:32.940 So let me see if I can find some examples. 00:08:33.160 --> 00:08:37.960 So I can say, get me the nearest neighbor by L2 distance. 00:08:38.380 --> 00:08:51.600 And it says the way you would do that directly is you say, select star from items, order by embedding, whatever the value is, is closest to, in this case, the vector value 3, 1, 2. 00:08:51.760 --> 00:08:54.000 And then limit 5, just like you do in databases. 00:08:54.000 --> 00:08:55.200 You know, give me the first 5. 00:08:55.200 --> 00:08:57.360 So order by closest to farthest. 00:08:57.360 --> 00:08:58.400 And then just give me 5. 00:08:58.400 --> 00:09:00.160 That'll give you the 5 nearest, right? 00:09:00.160 --> 00:09:02.300 You could do things like sort by distance. 00:09:03.160 --> 00:09:04.660 You can find exact matches. 00:09:04.660 --> 00:09:06.700 And you can also do other database things. 00:09:06.700 --> 00:09:07.820 Let's see. 00:09:07.820 --> 00:09:12.980 Like, give me where the ID is or is not equal to some value, and so on. 00:09:12.980 --> 00:09:13.460 All right. 00:09:13.460 --> 00:09:14.820 So pretty neat. 00:09:14.820 --> 00:09:19.920 Now, that's the pg vector extension just for Postgres. 00:09:19.920 --> 00:09:23.940 So you're speaking to it in a special flavor of SQL, sort of. 00:09:24.140 --> 00:09:29.520 In Python, you can talk to this using this thing called VEX, okay? 00:09:29.520 --> 00:09:41.460 So with VEX, you just pip install it, and then you insert a bunch of vectors, and then you can write queries that are more API-based, I guess, not just direct SQL statements. 00:09:41.460 --> 00:09:47.160 So you give it the vector that you want to query against, and then, you know, like how many you want back. 00:09:47.660 --> 00:09:55.360 If there's a filter to say, I only want the ones for a certain year, right, filter it down, and then do that query based on distance or whatever. 00:09:55.360 --> 00:09:56.900 So pretty cool. 00:09:56.900 --> 00:10:01.120 If people are out there doing that kind of work, I think they might find this pretty helpful. 00:10:01.120 --> 00:10:02.260 Yeah. 00:10:02.260 --> 00:10:03.200 Very. 00:10:03.200 --> 00:10:04.020 Oops. 00:10:04.020 --> 00:10:13.900 It's not something that I have exact direct use for these days, but, you know, a lot of scientific or geospatial type of things seems relevant. 00:10:13.900 --> 00:10:14.760 Yeah. 00:10:14.860 --> 00:10:19.560 I've been spending more and more time in SQL queries lately, so anything to help with that is good. 00:10:19.560 --> 00:10:20.280 Yeah, absolutely. 00:10:20.280 --> 00:10:21.880 Now, one final thing. 00:10:21.880 --> 00:10:27.000 It says in here, it says you've got to have, I can't remember which one, talked about getting Postgres. 00:10:27.000 --> 00:10:31.940 One of them, yeah, this one says, if you don't have a Postgres database, see some hosting options. 00:10:31.940 --> 00:10:36.300 And if you're on Mac, I just want to throw out there really quick, postgresapp.com. 00:10:36.300 --> 00:10:45.820 All you do for this one is, it's super awesome, you download it, you unzip it or un-DMG, whatever its packaging format is, and it's just a postgres.app. 00:10:45.820 --> 00:10:47.440 You double-click it, Postgres is running. 00:10:47.440 --> 00:10:48.940 You close it, Postgres is not running. 00:10:48.940 --> 00:10:50.320 It auto-updates itself. 00:10:50.320 --> 00:10:50.820 Yeah. 00:10:50.820 --> 00:10:52.420 So pretty sweet. 00:10:52.420 --> 00:10:53.380 And it's open source, too. 00:10:53.380 --> 00:10:54.040 Cool. 00:10:54.040 --> 00:10:54.580 Neat. 00:10:54.820 --> 00:10:55.100 Yeah. 00:10:55.100 --> 00:10:56.240 Yeah, very neat. 00:10:56.240 --> 00:10:57.780 I'll be needing that very soon. 00:10:57.780 --> 00:10:58.720 Yeah. 00:10:58.720 --> 00:10:58.960 So. 00:10:58.960 --> 00:11:00.140 Yeah, cool. 00:11:00.140 --> 00:11:00.520 Check it out. 00:11:00.520 --> 00:11:01.760 Yeah, that one's, that's pretty nice. 00:11:01.760 --> 00:11:02.140 Okay. 00:11:02.140 --> 00:11:06.720 Now, before we move on, Brian, brought to you by us, this episode is. 00:11:06.720 --> 00:11:11.680 So I wanted to remind people to, you know, please check out the brand new Talk Python training apps. 00:11:11.680 --> 00:11:14.440 They're rebuilt for iOS and Android. 00:11:14.440 --> 00:11:17.000 I really think it's a cool experience for people to take it. 00:11:17.000 --> 00:11:22.560 It has offline playback and obviously way better on the mobile and tablet type of things. 00:11:22.700 --> 00:11:28.820 And it comes with six free courses that you can just tap on and join the free courses plus anything you might have gotten. 00:11:28.820 --> 00:11:30.020 So check that out. 00:11:30.020 --> 00:11:33.360 And I want to shout out your book or what do you want to shout out today? 00:11:33.360 --> 00:11:33.820 Yeah. 00:11:33.820 --> 00:11:40.480 Well, there's, there's, time is running out, but the, yeah, let's, the book is still on a promo. 00:11:40.480 --> 00:11:45.920 So Python testing with pytest, there is, what is the promo? 00:11:45.920 --> 00:11:48.680 It is spring 2023. 00:11:48.680 --> 00:11:50.940 All caps, all one word. 00:11:50.940 --> 00:11:52.540 And you get 50% off. 00:11:52.620 --> 00:11:54.540 And it's just for like today and tomorrow. 00:11:54.540 --> 00:11:56.580 I think it runs out at the end of May. 00:11:56.580 --> 00:12:01.640 But anytime you want it, there is a 25, that's 50% off. 00:12:01.640 --> 00:12:08.460 But if you want to sign up and get to their email list, you can get 50%, 25% off normally. 00:12:08.460 --> 00:12:11.040 So anyway, that's a good thing. 00:12:11.040 --> 00:12:11.740 Excellent. 00:12:11.740 --> 00:12:13.640 Also really quick follow up. 00:12:14.060 --> 00:12:18.820 Henry points out that it was actually PEP 639, not 649. 00:12:18.820 --> 00:12:19.700 Not a typo there. 00:12:19.700 --> 00:12:20.100 Yeah. 00:12:20.100 --> 00:12:24.900 So 639 is improved license clarity with better package metadata. 00:12:24.900 --> 00:12:29.560 It's in draft, but hopefully there'll be, it's in draft really? 00:12:29.900 --> 00:12:35.660 Anyway, some changes to how you specify the license, which would be good. 00:12:35.660 --> 00:12:37.140 All right. 00:12:37.140 --> 00:12:38.840 Let's talk about plagues next. 00:12:38.840 --> 00:12:40.300 Plagues? 00:12:40.300 --> 00:12:43.020 Like, you know, locusts and grasshoppers? 00:12:43.020 --> 00:12:44.480 Yes, exactly. 00:12:44.480 --> 00:12:45.560 Nice. 00:12:45.560 --> 00:12:47.680 No, I like these kind of plagues. 00:12:47.680 --> 00:12:48.540 These are awesome tools. 00:12:48.840 --> 00:12:51.300 So I've used locusts before. 00:12:51.300 --> 00:12:53.440 I think you've used locusts for- 00:12:53.440 --> 00:12:54.180 I love locusts. 00:12:54.180 --> 00:12:54.360 Yeah. 00:12:54.360 --> 00:12:55.160 For load testing. 00:12:55.160 --> 00:12:55.820 So good. 00:12:55.820 --> 00:13:01.140 So there's a company, AlterX, maybe? 00:13:01.140 --> 00:13:05.640 Anyway, they've introduced grasshoppers. 00:13:05.640 --> 00:13:07.540 So it's a locust grasshopper. 00:13:07.540 --> 00:13:12.860 It's an open source Python library for load testing, but it's built on locusts. 00:13:12.860 --> 00:13:14.640 So what's the difference? 00:13:15.020 --> 00:13:23.740 So we're linking to an article that discusses the introduction and discusses why they love locusts and everything, which is great. 00:13:23.740 --> 00:13:28.100 But they have a check, like grasshopper, what does it add? 00:13:28.100 --> 00:13:36.640 Well, it adds a whole bunch of really cool features that you might need if you're load testing and developing a package and keeping track of your load testing over time. 00:13:36.640 --> 00:13:39.120 So it has these extra checks in here. 00:13:39.520 --> 00:13:48.260 And checks, if I get this right, are things like special validation functions, Boolean functions that can run. 00:13:48.260 --> 00:13:54.240 And you can tell different checks whether or not they're passing or failing over time, which is based on your- 00:13:54.240 --> 00:13:54.240 I see. 00:13:54.240 --> 00:13:59.660 The document had this text in it to make sure it wasn't insane in the response or something. 00:13:59.960 --> 00:14:01.580 Yeah, actually, I'm not quite sure. 00:14:01.580 --> 00:14:03.020 So I'd have to dig into that more. 00:14:03.020 --> 00:14:13.040 But one of the things I really like is these custom trends, which custom trends and timing thresholds and integration with pytest. 00:14:13.040 --> 00:14:14.020 Of course, that's awesome. 00:14:14.020 --> 00:14:17.180 Time series database integration and reporting. 00:14:17.180 --> 00:14:18.580 This all sounds great. 00:14:18.720 --> 00:14:26.700 One of the things I really love that's talked about in the readme a little bit more is this idea of, like, tagging your test suite. 00:14:26.700 --> 00:14:28.140 So tag-based suites. 00:14:28.140 --> 00:14:34.500 So you can see your load test results based on different versions. 00:14:34.500 --> 00:14:45.080 So if you're tagging with using version tagging on your repo, you can see what the progression is and how well your application is doing based on different load requirements. 00:14:45.080 --> 00:14:46.960 And you can have thresholds. 00:14:46.960 --> 00:14:51.940 Like, with this load, you need to have, like, 90% of the speeds of things. 00:14:51.940 --> 00:14:54.320 The other thing is some speed thresholds. 00:14:54.320 --> 00:15:05.320 Like, you can have multiple timing little functions that have multiple time, multiple HTTP requests. 00:15:05.320 --> 00:15:11.320 So an action that really is like a user action often is several interactions. 00:15:11.320 --> 00:15:14.000 Like, how fast can somebody log in or something like that? 00:15:14.000 --> 00:15:15.480 Or go through the checkout. 00:15:15.480 --> 00:15:18.000 That's going to be a multiple sequence thing. 00:15:18.000 --> 00:15:21.200 You can time that under load and under stress. 00:15:21.200 --> 00:15:23.040 And that's a pretty cool addition. 00:15:23.040 --> 00:15:29.640 Or even to load this page, we're going to, it's probably some complicated JavaScript front end. 00:15:29.640 --> 00:15:34.400 So it's going to call this API and that API and that API just to load this HTML page. 00:15:34.400 --> 00:15:34.720 Yeah, sure. 00:15:34.720 --> 00:15:40.480 So you kind of want to treat that as, like, the page is loaded when these seven API calls finish, right? 00:15:40.480 --> 00:15:41.460 Something like that. 00:15:41.460 --> 00:15:41.900 Yeah. 00:15:41.900 --> 00:15:45.900 Because they're not using HTTPX like they should or HTMX like they should. 00:15:45.900 --> 00:15:50.640 Also, a nice shout out to a sponsor there, InfluxDB. 00:15:50.640 --> 00:15:52.880 So pythonbyes.fm slash InfluxDB. 00:15:52.880 --> 00:15:55.740 This is the time series database that it integrates into. 00:15:55.740 --> 00:15:59.360 When I looked at this, Brian, I'm like, yeah, but Locus is pretty awesome. 00:15:59.360 --> 00:16:04.500 Why would somebody go create another one of these for the Python world when Locus exists? 00:16:04.500 --> 00:16:05.520 And then I read it. 00:16:05.520 --> 00:16:07.220 It's like, oh, we've extended Locus. 00:16:07.220 --> 00:16:08.520 Oh, and here's why. 00:16:08.520 --> 00:16:09.660 And they give some pretty good reasons. 00:16:09.660 --> 00:16:11.880 Another trend that would be cool. 00:16:11.960 --> 00:16:17.100 I don't know if you can actually measure it here, but it talks about custom trends is one of the things you can track. 00:16:17.100 --> 00:16:23.100 Things like CPU load and memory load on the server would be really interesting. 00:16:23.100 --> 00:16:29.680 Or, you know, maybe CPU load on the database server while we're hammering the web server. 00:16:29.680 --> 00:16:33.160 If you could pull those kinds of things in, that would be really cool. 00:16:33.160 --> 00:16:34.240 Yeah, maybe you can. 00:16:34.240 --> 00:16:34.920 Yeah, maybe. 00:16:34.920 --> 00:16:38.520 I kind of get the sense that it might be possible, but let's see. 00:16:38.520 --> 00:16:39.700 Not sure. 00:16:39.700 --> 00:16:42.340 But very cool. 00:16:42.340 --> 00:16:43.800 Yeah, this looks nice. 00:16:43.800 --> 00:16:44.700 It's definitely worth checking out. 00:16:44.700 --> 00:16:49.440 Some of the check functions, you might be able to, like, abuse that for that purposes, too. 00:16:49.440 --> 00:16:56.160 While your load tester is running, check CPU levels and stuff like that. 00:16:56.160 --> 00:16:56.600 I don't know. 00:16:56.600 --> 00:16:57.260 Yeah, exactly. 00:16:57.260 --> 00:17:00.040 So anyway, neat project. 00:17:00.040 --> 00:17:01.880 Yeah, that's a good project. 00:17:01.880 --> 00:17:03.720 So Grasshopper, right? 00:17:03.720 --> 00:17:04.180 Yeah. 00:17:04.180 --> 00:17:08.260 Oh, one of the things that they talk about in the... 00:17:08.260 --> 00:17:13.680 I wasn't clear on it because I went and looked at PyPI and looked for Grasshopper, and I found the wrong one. 00:17:14.040 --> 00:17:16.740 So it's locust-grasshopper. 00:17:16.740 --> 00:17:22.760 So that's the GitHub repos under that, and that's what you pip install also is locust-grasshopper. 00:17:22.760 --> 00:17:23.800 So just to be clear. 00:17:23.800 --> 00:17:24.180 Got it. 00:17:24.180 --> 00:17:28.680 I wonder if it's like a superset, probably. 00:17:28.680 --> 00:17:29.060 Yeah. 00:17:29.060 --> 00:17:34.900 So if I have already written a bunch of locust tests, could I run them, or how easy is it to... 00:17:34.900 --> 00:17:38.540 I don't know, but I imagine it's not that bad to convert. 00:17:38.540 --> 00:17:38.860 Yeah. 00:17:38.860 --> 00:17:41.240 It looks like the code is super similar. 00:17:41.240 --> 00:17:50.300 So worst case, you maybe change the base class, but possibly the base class is derived from the locust base class that you use for your test cases or test suites. 00:17:50.300 --> 00:17:50.540 Yeah. 00:17:51.020 --> 00:17:53.140 Anyway, I haven't played with it yet, but it looks cool. 00:17:53.140 --> 00:17:55.080 The readme's got tons of information too. 00:17:55.080 --> 00:17:58.980 Good job on loading up the readme with lots of examples. 00:17:58.980 --> 00:17:59.680 Indeed. 00:18:01.000 --> 00:18:09.000 And before we move on, Kim says, it could possibly hook into telemetry tooling like Prometheus, which would enable metrics from other servers and stuff like that. 00:18:09.000 --> 00:18:14.460 Yeah, that's kind of what I was talking about, but not with actually concrete ways of doing it like Prometheus. 00:18:14.460 --> 00:18:15.000 So cool. 00:18:15.000 --> 00:18:15.500 Neat. 00:18:15.500 --> 00:18:16.460 Yeah. 00:18:16.460 --> 00:18:22.980 And I want to talk to you about something that is near and dear to this podcast. 00:18:23.480 --> 00:18:26.360 We talk about a lot of topics, right, Brian? 00:18:26.360 --> 00:18:27.400 Yeah. 00:18:27.400 --> 00:18:37.320 And if you go over to Python Bytes and you pick a particular episode and you scroll through here, you can see it is chock full of links. 00:18:37.960 --> 00:18:42.480 So one of the things you might want to do, you might want to say, oh, I'm listening to this. 00:18:42.480 --> 00:18:47.080 I want to remember not all of them, but just three things that I can come back to. 00:18:47.080 --> 00:18:59.020 And if you're on your iThing, your iPhone, iPad, et cetera, or even on your Mac, technically, if you've got an Apple Silicon Mac, you can use this thing called MemoCast. 00:18:59.020 --> 00:19:04.600 So MemoCast was created by Daniel Engvall. 00:19:05.600 --> 00:19:13.440 It's interesting on its own, but it's also interesting in a way to kind of script iOS with Python, which I hadn't really thought about doing. 00:19:13.440 --> 00:19:17.560 So first of all, let me tell you about MemoCast and then you can think how this might apply to you. 00:19:17.560 --> 00:19:23.940 So this is a small iOS app that allows you to add links heard about in a podcast as a reminder. 00:19:23.940 --> 00:19:28.840 So you can check them off your reminder list, you know, the at reminder app when you're done with them. 00:19:28.840 --> 00:19:30.040 So check this out. 00:19:30.040 --> 00:19:32.480 Imagine this is reading the website. 00:19:32.680 --> 00:19:40.160 Imagine you just as often as I do listen to a podcast such as Python Bytes, a fantastic one. 00:19:40.160 --> 00:19:40.840 Thank you. 00:19:40.840 --> 00:19:41.280 Thank you. 00:19:41.280 --> 00:19:48.040 Using Google Podcasts, walk around, you know, you're doing it while you're out and maybe busy, like mowing the lawn or something. 00:19:48.040 --> 00:19:48.420 Right. 00:19:48.420 --> 00:19:52.820 And then there's some thing talked about you wish you had more time to check out. 00:19:52.820 --> 00:19:58.280 Thankfully, the reference in the show notes, but you'd have to look it up and go through it and copy paste and all that. 00:19:58.280 --> 00:20:01.060 So there's a little video here. 00:20:01.060 --> 00:20:02.340 Notice this. 00:20:02.340 --> 00:20:03.000 Nice. 00:20:03.000 --> 00:20:03.900 On this page. 00:20:03.900 --> 00:20:06.600 And it shows all you got to do is say share. 00:20:06.600 --> 00:20:07.840 Go to the podcast player. 00:20:07.840 --> 00:20:08.480 Say share. 00:20:08.480 --> 00:20:09.740 Click MemoCast. 00:20:09.740 --> 00:20:11.420 And it gives it a second. 00:20:11.420 --> 00:20:14.860 Then it has a list of all the links that it's discovered in there. 00:20:14.860 --> 00:20:15.700 Isn't that cool, Brian? 00:20:15.700 --> 00:20:16.480 That is neat. 00:20:16.480 --> 00:20:16.820 Yeah. 00:20:16.820 --> 00:20:18.300 I can't really zoom that without the. 00:20:18.540 --> 00:20:22.440 I can't really zoom it without the responsive design only making it smaller. 00:20:22.440 --> 00:20:25.300 But so how is this possible? 00:20:25.300 --> 00:20:28.460 The thing you share it to is you don't share it directly to MemoCast. 00:20:28.460 --> 00:20:30.240 You say run in Pythonista. 00:20:30.240 --> 00:20:40.120 And so this is a Python script that that Daniel wrote that basically you run it through Pythonista Python 10 on iOS. 00:20:40.480 --> 00:20:49.100 It does a guessing request or something called over to our website and parses out all the links and then turns that into a UI that you can interact with. 00:20:49.100 --> 00:20:49.660 Cool, right? 00:20:49.660 --> 00:20:51.320 That's all done on the phone then? 00:20:51.320 --> 00:20:51.740 Yeah. 00:20:51.740 --> 00:20:52.120 That's pretty cool. 00:20:52.120 --> 00:20:52.640 Yeah. 00:20:52.640 --> 00:20:53.440 It's pretty cool. 00:20:54.100 --> 00:21:01.580 And so basically this is an example supports Python by Stock, Python, I mean, real Python as the three supportive podcasts. 00:21:01.580 --> 00:21:03.180 But you can integrate new ones if you wish. 00:21:03.180 --> 00:21:09.080 And you install it once you have Pythonista, which I think costs $10 US one time. 00:21:09.080 --> 00:21:14.960 But then you can install it scanning the QR code here with Pythonista and that will download it. 00:21:14.960 --> 00:21:16.740 Then you can just turn it into a thing that you can run. 00:21:16.740 --> 00:21:20.400 It also talks about how you add new podcasts if you want to add a different one. 00:21:20.400 --> 00:21:22.880 But that's somewhat interesting. 00:21:23.380 --> 00:21:33.340 I think what's more interesting is he took this Python code and the code is right here to build kind of a scriptable GUI for iOS, which I think is pretty cool. 00:21:33.340 --> 00:21:34.720 Yeah, that is nice. 00:21:34.720 --> 00:21:35.160 Cool. 00:21:35.160 --> 00:21:38.940 So talked about like I did try to do this with Kivy and other stuff. 00:21:38.940 --> 00:21:43.540 But let me tell you, the build chain and code signing and all of that is like a nightmare. 00:21:43.540 --> 00:21:48.200 And so here you just write a Python script and just run it inside of this app that already exists. 00:21:48.820 --> 00:21:52.320 And final bonus before I call all the time on this one. 00:21:52.320 --> 00:22:02.680 Daniel also discovered that if you're on a Mac with a Apple Silicon, then you can run Pythonista as an iOS app within macOS. 00:22:02.680 --> 00:22:06.280 So you go to the App Store, search for it on Mac and it doesn't come up. 00:22:06.320 --> 00:22:10.720 So then you click, say, show me tablet, you know, iPad apps, and then it'll come up. 00:22:10.720 --> 00:22:15.380 And then it integrates with your favorite IDE, such as PyCharm, and you can run it. 00:22:15.380 --> 00:22:20.780 So you can develop these little things on your Mac with a proper keyboard and everything. 00:22:20.960 --> 00:22:24.500 And then just deploy it to Pythonista on iOS. 00:22:24.500 --> 00:22:25.660 Yeah, that's pretty cool. 00:22:25.660 --> 00:22:28.780 So yeah, people can check that out, MemoCast. 00:22:28.780 --> 00:22:40.440 It's kind of cool that it's about our podcast in this way, but it's also more cool that it just kind of shows you how to take Python and leverage Pythonista a little bit more than maybe I realized you could, like an OS integration level. 00:22:40.440 --> 00:22:41.920 Yeah, I didn't know you could do that. 00:22:41.920 --> 00:22:42.560 That's cool. 00:22:42.560 --> 00:22:43.560 I did not either. 00:22:43.560 --> 00:22:44.780 Nice. 00:22:45.340 --> 00:22:57.040 And I guess before we jump out of here as well, Kim points out on Android, which I have some but not tons of experience with, you can run Python code with QPython should someone want to emulate this for Android. 00:22:57.040 --> 00:22:57.700 Thanks, Kim. 00:22:57.700 --> 00:22:58.220 Cool. 00:22:58.220 --> 00:22:59.080 All right. 00:22:59.080 --> 00:23:00.340 Is that all of our topics, Brian? 00:23:00.340 --> 00:23:02.060 That is all of our main topics. 00:23:02.060 --> 00:23:02.480 Yes. 00:23:02.480 --> 00:23:03.100 Yes. 00:23:03.100 --> 00:23:04.360 Of course, we always have extras. 00:23:04.360 --> 00:23:05.580 Yeah. 00:23:05.580 --> 00:23:05.940 I'm a joke. 00:23:05.940 --> 00:23:07.340 Any extras for you, though? 00:23:07.340 --> 00:23:08.080 Yeah. 00:23:08.080 --> 00:23:09.620 I can kick this off. 00:23:09.620 --> 00:23:11.860 So just a few. 00:23:13.220 --> 00:23:15.920 A shout out from, oh, who wrote this? 00:23:15.920 --> 00:23:16.680 I'm not sure. 00:23:16.680 --> 00:23:17.440 Hugo. 00:23:17.440 --> 00:23:19.200 Hugo Van Kimenad. 00:23:19.200 --> 00:23:23.800 Wrote, help test Python 3.12 beta. 00:23:23.800 --> 00:23:25.340 So 3.12 is in beta. 00:23:25.340 --> 00:23:32.840 If you are a package maintainer or just your own application, you may as well start testing to make sure that you don't have any surprises. 00:23:32.840 --> 00:23:42.020 So this article does talk through basically how to hook up your GitHub actions so that you're testing 3.12 also. 00:23:42.520 --> 00:23:49.780 And then whether it's the official Ubuntu latest or the Dead Snakes version, a couple ways to do it. 00:23:49.780 --> 00:23:52.840 And then even if you're using Travis CI still, bye. 00:23:52.840 --> 00:23:56.240 Anyway, you can do that with that as well. 00:23:56.240 --> 00:23:58.000 So that's the first. 00:23:58.000 --> 00:24:06.660 Secondly, I wanted to say that at the Python Software Foundation blog, there is a whole bunch of new articles. 00:24:06.980 --> 00:24:12.300 I basically wrote up, there's articles writing up all the different things that happened at the Python Language Summit. 00:24:12.300 --> 00:24:14.240 I haven't gone through these. 00:24:14.240 --> 00:24:15.040 They're just available. 00:24:15.040 --> 00:24:16.220 Wanted to shout that out. 00:24:16.220 --> 00:24:18.260 It's some interesting stuff, though. 00:24:18.500 --> 00:24:18.820 There is. 00:24:18.820 --> 00:24:22.360 I just interviewed Brett Cannon over on Talk Python about this. 00:24:22.360 --> 00:24:28.340 He gave us the walkthrough of all the presentations and thoughts at the Language Summit. 00:24:28.340 --> 00:24:28.820 Okay. 00:24:29.080 --> 00:24:36.560 And then from the news from the weird, I don't have much information about this other than on the Python Package Index blog. 00:24:36.560 --> 00:24:39.360 They say, hey, PyPI was subpoenaed. 00:24:39.360 --> 00:24:41.120 And, you know, this thing happened. 00:24:41.120 --> 00:24:43.240 And we complied and talked to lawyers. 00:24:43.240 --> 00:24:44.140 And it's weird. 00:24:44.140 --> 00:24:46.160 But, you know, it's just odd. 00:24:46.160 --> 00:24:47.240 Yeah. 00:24:47.480 --> 00:24:48.780 So how about you? 00:24:48.780 --> 00:24:49.340 Any extras? 00:24:49.340 --> 00:24:50.040 Yeah. 00:24:50.040 --> 00:24:52.840 I wonder if this has to do with some of the malware, crypto jacking. 00:24:52.840 --> 00:24:53.480 Maybe. 00:24:53.480 --> 00:24:55.200 Stuff that was uploaded to it. 00:24:55.200 --> 00:24:57.400 And they're like, all right, we're going to try to track down some of these people. 00:24:57.400 --> 00:25:03.620 There are certain places that are not allowed to say whether they received a request. 00:25:03.620 --> 00:25:04.980 And I think this is not a subpoena. 00:25:04.980 --> 00:25:07.160 This is more of a, what is it, FASA? 00:25:07.320 --> 00:25:11.720 Like the more international crime investigation laws. 00:25:11.720 --> 00:25:14.600 So we'll have a subpoena canaries. 00:25:14.600 --> 00:25:18.280 It'll be like the canary will be here unless we are subpoenaed. 00:25:18.280 --> 00:25:19.360 Then the canary is gone. 00:25:19.360 --> 00:25:20.220 We won't say anything. 00:25:20.220 --> 00:25:23.380 But we'll just, this bird won't be on the page or something anymore. 00:25:23.380 --> 00:25:24.280 So you can kind of know. 00:25:24.280 --> 00:25:26.260 But, yeah, it's kind of cool. 00:25:26.260 --> 00:25:28.340 They're being transparent about that. 00:25:28.340 --> 00:25:28.580 Yeah. 00:25:28.580 --> 00:25:36.160 One of the things that was interesting is that they got asked for addresses, including mailing and residential addresses. 00:25:36.160 --> 00:25:37.920 But they don't collect that. 00:25:37.920 --> 00:25:41.760 They just, I mean, that information isn't saved. 00:25:41.760 --> 00:25:42.680 So it's not there. 00:25:42.680 --> 00:25:42.860 Yeah. 00:25:42.860 --> 00:25:43.840 I'm sure it's a form. 00:25:43.840 --> 00:25:45.200 And like, we would like this information. 00:25:45.200 --> 00:25:46.420 Well, we don't have that. 00:25:46.420 --> 00:25:47.660 So we'll give you what we got. 00:25:47.660 --> 00:25:48.160 Yeah. 00:25:48.160 --> 00:25:49.020 Okay. 00:25:49.020 --> 00:25:49.880 Nice. 00:25:49.880 --> 00:25:50.120 All right. 00:25:50.120 --> 00:25:51.940 I got a couple of real quick ones here. 00:25:51.940 --> 00:25:53.100 Not Python. 00:25:53.100 --> 00:25:56.580 One, I wrote something called, you can ignore this post. 00:25:56.580 --> 00:25:58.300 Trying to get a lot of attention, of course. 00:25:58.300 --> 00:26:05.980 What it actually was is I just wrote about the github.com/github slash git ignore repo. 00:26:05.980 --> 00:26:12.020 Which has all, like when you go to github and you say create a new project and it says, do you want an ignore file? 00:26:12.020 --> 00:26:13.040 And it gives you a list. 00:26:13.400 --> 00:26:20.900 These are all the ignore files for every language supported there, including Python, which is in here somewhere right there. 00:26:20.900 --> 00:26:23.600 And so you can actually see what they all are. 00:26:23.600 --> 00:26:25.120 You could even do a PR. 00:26:25.120 --> 00:26:26.780 Like we really need to start ignoring. 00:26:27.200 --> 00:26:32.520 You know, if there's a new file format, that's like a build output of some new pyproject.tominal tooling. 00:26:32.520 --> 00:26:34.860 And it starts to, you know, needs to be ignored. 00:26:34.860 --> 00:26:36.780 You could say do a PR against this. 00:26:36.780 --> 00:26:39.420 So every repo on GitHub starts to adopt it. 00:26:39.460 --> 00:26:45.160 But also if you're doing, say, Python and front end stuff, you could go look for Node. 00:26:45.160 --> 00:26:51.440 And you could select one and then copy some stuff out of another to kind of create a combined one. 00:26:51.440 --> 00:26:51.780 Right. 00:26:51.780 --> 00:26:53.720 So you're not like, well, is it Node or is it Python? 00:26:53.720 --> 00:26:54.980 I really want to ignore for. 00:26:54.980 --> 00:26:59.300 So anyway, that article is just sort of about that. 00:26:59.300 --> 00:26:59.680 Really short. 00:26:59.680 --> 00:27:00.680 People can check that out. 00:27:00.840 --> 00:27:07.180 I use that all the time because I'm also on GitLab and GitLab doesn't fill those out for you. 00:27:07.180 --> 00:27:08.220 Oh, yeah. 00:27:08.220 --> 00:27:11.400 I hadn't really thought about it, but you could nab it for other purposes as well, right? 00:27:11.400 --> 00:27:11.600 Yeah. 00:27:11.600 --> 00:27:12.080 Yep. 00:27:12.080 --> 00:27:16.580 And then someone on Masset, I'll point out, you can do nox Python ignore. 00:27:16.580 --> 00:27:20.420 And I think it'll generate that file for you and uses that as the backend. 00:27:20.420 --> 00:27:21.420 I think. 00:27:21.420 --> 00:27:22.140 I think so. 00:27:22.140 --> 00:27:26.260 Some of the nox and some incantation will generate an ignore file for you. 00:27:26.260 --> 00:27:28.820 And if we have that wrong, somebody will correct us. 00:27:28.820 --> 00:27:29.800 They sure will. 00:27:29.800 --> 00:27:30.840 And we appreciate it. 00:27:30.840 --> 00:27:33.220 And speaking of incantations, are you ready for the joke? 00:27:33.220 --> 00:27:33.900 Yes. 00:27:33.900 --> 00:27:34.640 Okay. 00:27:34.640 --> 00:27:37.040 So here's the joke for developers. 00:27:37.040 --> 00:27:39.620 It says, careful where you might end up summoning a demon. 00:27:39.620 --> 00:27:45.680 And it has two categories, what you do in programming and what you do in demon summoning. 00:27:45.680 --> 00:27:49.780 So first one is you must know a language unspoken by mankind. 00:27:49.780 --> 00:27:50.920 Programming. 00:27:50.920 --> 00:27:51.220 Check. 00:27:51.220 --> 00:27:52.760 Demon summoning. 00:27:52.760 --> 00:27:53.060 Check. 00:27:53.060 --> 00:27:57.760 Requires that you be exact or suffer dire consequences. 00:27:57.760 --> 00:27:58.520 Programming. 00:27:58.520 --> 00:27:58.860 Check. 00:27:58.860 --> 00:27:59.780 Demon summoning. 00:27:59.780 --> 00:28:00.220 Check. 00:28:00.220 --> 00:28:05.700 Involves much cursing, swearing of oaths, and pleading with a higher power. 00:28:05.700 --> 00:28:06.360 Programming. 00:28:06.360 --> 00:28:06.720 Check. 00:28:06.720 --> 00:28:08.440 Demon summoning. 00:28:08.440 --> 00:28:08.700 Check. 00:28:08.700 --> 00:28:13.980 Another one is not understanding the true power you wield or the consequences of your actions. 00:28:13.980 --> 00:28:14.580 Programming. 00:28:14.580 --> 00:28:14.860 Check. 00:28:14.860 --> 00:28:15.980 Demon summoning. 00:28:15.980 --> 00:28:16.240 Check. 00:28:16.240 --> 00:28:20.900 The only differentiation, which I think is debatable, is candles. 00:28:20.900 --> 00:28:23.060 Do you use candles to accomplish this job? 00:28:23.060 --> 00:28:23.720 Programming? 00:28:23.720 --> 00:28:24.320 No. 00:28:24.320 --> 00:28:25.260 Demon summoning? 00:28:25.460 --> 00:28:25.820 Yes. 00:28:25.820 --> 00:28:25.820 Yes. 00:28:25.820 --> 00:28:27.360 And if you look over on Reddit. 00:28:27.360 --> 00:28:29.560 The comments are pretty glorious. 00:28:29.560 --> 00:28:31.400 That's funny. 00:28:31.400 --> 00:28:34.500 Let me see if I'm finding these good ones just here. 00:28:34.500 --> 00:28:42.980 Someone has said something like, I've been trying for hours to get this demon to run, and I just can't get it to work. 00:28:42.980 --> 00:28:43.920 That's what I'm writing on. 00:28:44.460 --> 00:28:46.100 Well, we're trying. 00:28:46.100 --> 00:28:47.660 Damon, not demon, right? 00:28:47.660 --> 00:28:48.160 Of course. 00:28:48.160 --> 00:28:48.660 Damon. 00:28:48.660 --> 00:28:56.720 And then someone else points out, you know, there actually is a candle app platform, which sounds truly demonic to me. 00:28:56.720 --> 00:28:57.500 So let me describe. 00:28:57.500 --> 00:28:58.560 This is like a real thing. 00:28:58.560 --> 00:28:59.160 This is not a joke. 00:28:59.160 --> 00:29:00.240 Candlescript.org. 00:29:00.240 --> 00:29:01.000 Somebody created this. 00:29:01.280 --> 00:29:05.220 Let me lay out the beautiful technologies that Candlescript combines. 00:29:05.220 --> 00:29:19.520 Are you ready to use the new open source platform that unifies core features of XSLT, XQuery, XML schema, RelaxNG, BNF, and XQuery update, and more into a single language called Candle? 00:29:19.520 --> 00:29:20.940 No, please, no. 00:29:20.940 --> 00:29:22.040 XSLT, no. 00:29:22.040 --> 00:29:24.720 Yeah, that sounds pretty demonic already. 00:29:24.720 --> 00:29:26.860 So I'm a little suspicious of that one. 00:29:27.300 --> 00:29:37.020 Yeah, and I think that actual demon summoning, they're probably worried about climate change and probably switching to low carbon lighting. 00:29:37.020 --> 00:29:37.340 Yes, yes. 00:29:37.340 --> 00:29:40.520 So probably LEDs now instead of actual candles. 00:29:40.520 --> 00:29:41.900 Yep, LEDs. 00:29:41.900 --> 00:29:43.860 Got to be careful about home automation. 00:29:43.860 --> 00:29:47.260 You might complete all the checkboxes. 00:29:47.260 --> 00:29:50.520 Yeah, I think sometimes you have to execute a child. 00:29:50.520 --> 00:29:51.420 That's funny. 00:29:51.420 --> 00:29:52.700 Child processes. 00:29:52.700 --> 00:29:54.240 Yeah, they both execute children, right? 00:29:54.240 --> 00:29:56.020 I mean, that's a pretty rough one. 00:29:56.900 --> 00:30:02.060 Kim, I believe, maybe has done enough XSLT as I have to know that it should never, ever be done. 00:30:02.060 --> 00:30:04.580 And says, Candlescript has just triggered my PTSD. 00:30:04.580 --> 00:30:07.760 Yeah, funny. 00:30:07.760 --> 00:30:09.160 Oh, the battle XML days. 00:30:09.160 --> 00:30:11.620 Well, that's it, Brian. 00:30:11.620 --> 00:30:13.100 Great show as always. 00:30:13.100 --> 00:30:13.840 Thank you for being here. 00:30:13.840 --> 00:30:14.720 Well, thank you. 00:30:14.720 --> 00:30:18.780 Thanks to you, everyone, for listening and those of you who joined live.